/*******************************************************************************
* Actel Corportation
* Fusion's Context Saving and Reload Application Note's Design Example
*
* Target Device:    AFS600 256 FBGA
* File Name:    CONTEXT_CNTRL.v
* Date:         June 2006
* Language:     Verilog
*
* Description: CONTEXT_CNTRL contains a simple 2-bit (4 state) state
* machine that controls the context saving and reload interactions
* amongst the Flash memory and its dependant peripherals i.e. Sram
* and the Analog System's RTC. The state machine also controls the
* switching between the two clock domains (100MHz and 10MHz) and supplies
* the shutdown input to the voltage regulator for an auto-shudown (if 
* enabled) after the completion of a save command.  
********************************************************************************
* IMPORTANT-READ THESE TERMS CAREFULLY BEFORE UTILIZING THE INFORMATION
* CONTAINED IN THIS APPLICATION NOTE. 
*
* NO SUPPORT/NO WARRANTY. THE DESIGN FILES AND DOCUMENTATION ARE PROVIDED
* WITHOUT SUPPORT OR WARRANTY OF ANY KIND. ACTEL IS NOT OBLIGATED TO 
* PROVIDE UPDATES, BUG FIXES, OR TECHNICAL SUPPORT AND DISCLAIMS ALL 
* WARRANTIES INCLUDING, WITHOUT LIMITATION, THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, AND WARRANTIES OF NON-INFRINGEMENT OF THE
* RIGHTS OF THIRD PARTIES (INCLUDING, WITHOUT LIMITATION, RIGHTS UNDER PATENT,
* COPYRIGHT, TRADE SECRET, OR OTHER INTELLECTUAL PROPERTY RIGHTS).  RECIPIENT
* ACCEPTS THE APPLICATION NOTE DESIGN FILES AND DOCUMENTATION IN "AS-IS"
* CONDITION.
*******************************************************************************/


`timescale 1 ns/100 ps


module CONTEXT_CNTRL( SYS_RESETn
    , PLL_LOCK
    , NGMUX_SEL
    , CONTEXT_CLK
    , SAVE_SRAM_TO_FLASH
    , UPDATE_SRAM_FROM_FLASH
    , CONTEXT_DONE
    , FLASH_RESETn
    , INIT_POWER_UP
    , CLIENT_UPDATE
    , INIT_WEN_MASK
    , INIT_DONE
    , SAVE_COMPLETE
    , VRPU_AUTO_SHDN
);


/* CONTEXT_CNTRL Port Declarations */
input   SYS_RESETn;             // External active-low reset input
input   PLL_LOCK;               // Lock input from the PLL
output  NGMUX_SEL;              // Control output signal to the NGMUX select port input
input   CONTEXT_CLK;            // CONTEXT_CNTRL module clock input
input   SAVE_SRAM_TO_FLASH;     // Sram to Flash save command input
input   UPDATE_SRAM_FROM_FLASH; // Update Sram from Flash command input
output  CONTEXT_DONE;           // Context initialization interface done output
output  FLASH_RESETn;           // Active-low reset output to the Flash macro
output  INIT_POWER_UP;          // Active-high context reload control output 
output  CLIENT_UPDATE;          // Active-high context save control output 
output	INIT_WEN_MASK;          // Active-low mask output to the INIT_*_WEN signals
input   INIT_DONE;              // Active-high context reload complete input from Flash
input   SAVE_COMPLETE;          // Active-high context save complete input from Flash
output  VRPU_AUTO_SHDN;         // Auto-shutdown after a save command to the voltage regulator


/* CONTEXT_CNTRL Register Definitions */

// All *_d registers are signals controlled within the state machine's
// combinational always block. They are essentially the D inputs to the 
// defined DFF.
reg     [1:0]   CNTRL_CURRENT_STATE, CNTRL_NEXT_STATE;
reg     NGMUX_CYCLE_DLY;
reg     NGMUX_SEL, NGMUX_SEL_d;
reg     INIT_POWER_UP;
reg     FLASH_RESETn, FLASH_RESETn_d;
reg     CLIENT_UPDATE, CLIENT_UPDATE_d;
reg     CONTEXT_DONE, CONTEXT_DONE_d;
reg     INIT_WEN_MASK, INIT_WEN_MASK_d;
reg     VRPU_AUTO_SHDN, VRPU_AUTO_SHDN_d;


// State machine state definitions
parameter
    IDLE = 2'b00,
    UPDATE = 2'b01,
    SAVE = 2'b10,
    WAIT_SAVE_COMPLETE = 2'b11;


/* CONTEXT_CNTRL register always blocks */

////////////////////////////////////////////////////////////////////////
// INIT_POWER_UP controls the update (reload) activital
// from the flash memory to Sram and RTC.
//
// Will not transition high unless PLL is locked (inherant
// through NGMUX_CYCLE_DLY), the mux has switched clock domains
// and settled to its new frequency, and INIT_DONE is low.
//
// It will hold high until FLASH_RESETn is pulsed low. At this
// time INIT_DONE will also clear.  
////////////////////////////////////////////////////////////////////////
always @(posedge CONTEXT_CLK or negedge FLASH_RESETn)
begin
    if (!FLASH_RESETn)
        INIT_POWER_UP <= 1'b0;
    else
        INIT_POWER_UP <= NGMUX_CYCLE_DLY & !INIT_DONE;
end


////////////////////////////////////////////////////////////////////////
// NGMUX_CYCLE_DLY controls transitions between states. It is used
// to statisfy the NGMUX requirement of a 2 cycle settling time between
// frequency transitions.
//
// Cycle 1: NGMUX_SEL is captured by NGMUX_CYCLE_DLY
// Cycle 2: NGMUX_CYCLE_DLY is captured by the state machine controls
////////////////////////////////////////////////////////////////////////
always @(posedge CONTEXT_CLK or negedge SYS_RESETn)
begin
    if (!SYS_RESETn)
        NGMUX_CYCLE_DLY <= 1'b0;
    else
        NGMUX_CYCLE_DLY <= NGMUX_SEL;
end


////////////////////////////////////////////////////////////////////////
// Context control state registers. CNTRL_CURRENT_STATE registers 
// transition from one state to the next base on the CNTRL_NEXT_STATE 
// combinational logic.
////////////////////////////////////////////////////////////////////////
always @(posedge CONTEXT_CLK or negedge SYS_RESETn)
begin
    if (!SYS_RESETn)
        CNTRL_CURRENT_STATE <= IDLE;
    else
        CNTRL_CURRENT_STATE <= CNTRL_NEXT_STATE;
end


////////////////////////////////////////////////////////////////////////
// The below always block contains multiple DFF registers, all unique,
// whose outputs are also outputs of the CONTEXT_CNTRL module.
//
// NGMUX_SEL - Switches between clock domains. If '0': 100MHz clock, 
// then '1': 10MHz clock. 
//
// FLASH_RESETn - Active-low pulsed reset made specifically to reset the
// Flash to allow for an on-demand context reload action.
//
// CLIENT_UPDATE - Active-high level driven signal that controls the 
// context reload activity. If '1', a context reload is active, 
// otherwise in-active.
//
// CONTEXT_DONE - Active-high level driven signal used to indicate when
// the context save or context reload activity is complete. Its secondary
// function is to indicate the clock domain status. If '1' the context
// activity has completed and the clock domain is 100MHz. if '0' the 
// context activity is in progress and the clock domain is 10MHz.
//
// VRPU_AUTO_SHDN - Active-high pulse driven shutdown output. It can be
// used to auto-shutdown the voltage regulator is enabled. VRPU_AUTO_SHDN
// pulses on after a context save operation has completed.
//
// INIT_WEN_MASK - Active-low mask output, which should be ANDed together
// with the INIT_*_WEN signals connections from Flash to all configuration
// registers that should only be updated at power-up and not from
// an on-demand update command.
////////////////////////////////////////////////////////////////////////
always @(posedge CONTEXT_CLK or negedge SYS_RESETn)
begin
    if (!SYS_RESETn)
    begin
        NGMUX_SEL <= 1'b0;
        FLASH_RESETn <= 1'b0;
        CLIENT_UPDATE <= 1'b0;
        CONTEXT_DONE <= 1'b1;
        VRPU_AUTO_SHDN <= 1'b0;
        INIT_WEN_MASK <= 1'b1;
    end
    else
    begin
        NGMUX_SEL <= NGMUX_SEL_d;
        FLASH_RESETn <= FLASH_RESETn_d;
        CLIENT_UPDATE <= CLIENT_UPDATE_d;
        CONTEXT_DONE <= CONTEXT_DONE_d;
        VRPU_AUTO_SHDN <= VRPU_AUTO_SHDN_d;
        INIT_WEN_MASK <= INIT_WEN_MASK_d;
    end
end


/* CONTEXT_CNTRL state machine combinational logic always blocks */

////////////////////////////////////////////////////////////////////////
// State machine combinational logic always block: Controls the state 
// transitions and all output register inputs.
////////////////////////////////////////////////////////////////////////
always @(CNTRL_CURRENT_STATE or UPDATE_SRAM_FROM_FLASH or SAVE_SRAM_TO_FLASH
or CONTEXT_DONE or NGMUX_SEL or NGMUX_CYCLE_DLY or PLL_LOCK or CLIENT_UPDATE
or INIT_DONE or SAVE_COMPLETE or INIT_WEN_MASK)
begin
    // Output signal default state definitions
    CNTRL_NEXT_STATE = CNTRL_CURRENT_STATE; // hold
    VRPU_AUTO_SHDN_d = 1'b0;                // low
    FLASH_RESETn_d = 1'b1;                  // high
    NGMUX_SEL_d = NGMUX_SEL;                // hold 
    CLIENT_UPDATE_d = 1'b0;                 // low
    INIT_WEN_MASK_d = INIT_WEN_MASK;        // hold
    CONTEXT_DONE_d = CONTEXT_DONE;          // hold

    // Main state machine case switch
    case(CNTRL_CURRENT_STATE)
    IDLE:   // Idle or context reload wait state
    begin
        if (INIT_DONE)
        // Initialization (context reload) is complete       
        begin
            if (!NGMUX_CYCLE_DLY)
            begin
                // Waits for update or save commands. Previous activities have completed.
                // Update and save commands can not execute unless the PLL is locked.
                if (UPDATE_SRAM_FROM_FLASH & PLL_LOCK)
                    CNTRL_NEXT_STATE = UPDATE;
                else if (SAVE_SRAM_TO_FLASH & PLL_LOCK)
                    CNTRL_NEXT_STATE = SAVE;
                else
                    CNTRL_NEXT_STATE = IDLE;
                CONTEXT_DONE_d = 1'b1;
            end
            else
                NGMUX_SEL_d = 1'b0;     // Context reload has completed. Switch NGMUX.

          	INIT_WEN_MASK_d = 1'b1;     // Context save complete, bring back to high state.
        end
        else
        // Initialization (context reload) is not complete
        begin   
            NGMUX_SEL_d = PLL_LOCK;     // Switches clock domains once PLL is locked
            CONTEXT_DONE_d = 1'b0;      // Context activity is in progress
            CNTRL_NEXT_STATE = IDLE;    // IDLE loop
        end
    end
    UPDATE: // Context reload operation state
    begin
        if (NGMUX_CYCLE_DLY)
        // 2-cycle NGMUX requirement met, initiate context update activity
        begin
            FLASH_RESETn_d = 1'b0;      // issue flash a reset which triggers INIT_POWER_UP
	        INIT_WEN_MASK_d = 1'b0;     // enable mask
            CNTRL_NEXT_STATE = IDLE;    // wait for INIT_DONE in IDLE state
        end
        else
        // 2-cycle NGMUX requirement not met, UPDATE state loop 
            CNTRL_NEXT_STATE = UPDATE;

        NGMUX_SEL_d = 1'b1;             // switch clock domains
        CONTEXT_DONE_d = 1'b0;          // context reload activitly in progress
    end
    SAVE: // Context save operation state
    begin
        if (NGMUX_CYCLE_DLY)
        // 2-cycle NGMUX requirement met, initiate context save activity
        begin
            CLIENT_UPDATE_d = 1'b1;     // issue context save control 
            CNTRL_NEXT_STATE = WAIT_SAVE_COMPLETE;  // jump states to wait for SAVE_COMPLETE
        end
        else
        // 2-cycle NGMUX requirement not met, SAVE state loop
            CNTRL_NEXT_STATE = SAVE;

        NGMUX_SEL_d = 1'b1;             // switch clock domains
        CONTEXT_DONE_d = 1'b0;          // context save activitly in progress
    end
    WAIT_SAVE_COMPLETE: // Context save wait state
    begin
        if (CLIENT_UPDATE)
        // Context save activity is still active
        begin
            CLIENT_UPDATE_d = !SAVE_COMPLETE;       // transitions low when SAVE_COMPLETE pulses high
            CONTEXT_DONE_d = 1'b0;                  // context save activitly in progress
            CNTRL_NEXT_STATE = WAIT_SAVE_COMPLETE;  // WAIT_SAVE_COMPLETE loop
        end
        else if (SAVE_COMPLETE)
        // Context save activity is now complete, must still wait for SAVE_COMPLETE to fall low
        begin
            CONTEXT_DONE_d = 1'b0;      // context save activitly in progress
            VRPU_AUTO_SHDN_d = 1'b1;	// auto-shutdown of the system after a save
            CNTRL_NEXT_STATE = WAIT_SAVE_COMPLETE;  // WAIT_SAVE_COMPLETE loop
        end
        else
        // Context save activity is now complete
        begin
            // Wait for the 2-cycle NGMUX requirement to be met.
            CNTRL_NEXT_STATE = NGMUX_CYCLE_DLY ? WAIT_SAVE_COMPLETE : IDLE;
            CONTEXT_DONE_d = !NGMUX_CYCLE_DLY;
            NGMUX_SEL_d = 1'b0;         // switch clock domains
        end
    end
    endcase
end


endmodule