/*******************************************************************************
* Actel Corportation
* Fusion's Context Saving and Reload Application Note's Design Example
*
* Target Device:    AFS600 256 FBGA
* File Name:    TEST_PM_CONTEXT_SAVING.v
* Date:         June 2006
* Language:     Verilog
*
* Description: Testbench verilog stimulus for the PM_CONTEXT_SAVING_TOP
* module. Two other modules also reside in the file and are used to 
* mimic the external crytal (EXT_XTAL) and reset generator circuits
* (RSTGEN).
* 
* Module List: TEST_PM_CONTEXT_SAVING, RSTGEN, EXT_XTAL 
********************************************************************************
* 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 TEST_PM_CONTEXT_SAVING();

/* Register and interconnect definitions */
reg     SAVE_SRAM_TO_FLASH, SAVE_SRAM_TO_FLASH_d;
reg     UPDATE_SRAM_FROM_FLASH, UPDATE_SRAM_FROM_FLASH_d;
reg     PUB, VRPU_IN;
reg 	VRPU_AUTO_SHDN_EN, VRPU_AUTO_SHDN_EN_d;
reg     WENn, WENn_d;
reg     RENn, RENn_d;
reg     [5:0]   WADDR, WADDR_d;
reg     [5:0]   RADDR, RADDR_d;
reg     [15:0]  golden_data, golden_data_d;
reg     [15:0]  WD, WD_d;

wire    [15:0]  RD;
wire	XTL;
wire	SYS_RESETn;
wire    SYS_CLOCK, CONTEXT_DONE, FPGAGOOD;


/* Module Instances and Interconnects */

// Reset generator instance
RSTGEN U_RESET( .FPGAGOOD(FPGAGOOD), .SYS_RESETn(SYS_RESETn));


// External crystal instance
EXT_XTAL U_EXT_XTAL(.XTL(XTL));


// Context saving and reload top instance
PM_CONTEXT_SAVING_TOP U_PMCS_TOP( .SYS_RESETn(SYS_RESETn)
    , .SYS_CLOCK(SYS_CLOCK)
    , .XTL(XTL)
    , .PUB(PUB)
    , .VRPU_IN(VRPU_IN)
    , .VAREF()
    , .SAVE_SRAM_TO_FLASH(SAVE_SRAM_TO_FLASH)
    , .UPDATE_SRAM_FROM_FLASH(UPDATE_SRAM_FROM_FLASH)
    , .VRPU_AUTO_SHDN_EN(VRPU_AUTO_SHDN_EN)
    , .WENn(WENn)
    , .RENn(RENn)
    , .WADDR(WADDR)
    , .RADDR(RADDR)
    , .WD(WD)
    , .RD(RD)
    , .CONTEXT_DONE(CONTEXT_DONE)
    , .FPGAGOOD(FPGAGOOD)
);


/* Control signal input generation for the PM_CONTEXT_SAVING_TOP module */

// Synchronous control registers to be connected to PM_CONTEXT_SAVING_TOP.
always @(posedge SYS_CLOCK or negedge SYS_RESETn)
begin
   if (!SYS_RESETn)
   begin
        SAVE_SRAM_TO_FLASH <= 1'b0;
        UPDATE_SRAM_FROM_FLASH <= 1'b0;
        VRPU_AUTO_SHDN_EN <= 1'b0;

        WENn <= 1'b1;
        RENn <= 1'b1;
        WADDR <= 6'h00;
        RADDR <= 6'h00;
        WD <= 16'h0000;
   end
   else
   begin
        SAVE_SRAM_TO_FLASH <= #0.1 SAVE_SRAM_TO_FLASH_d;
        UPDATE_SRAM_FROM_FLASH <= #0.1 UPDATE_SRAM_FROM_FLASH_d;
        VRPU_AUTO_SHDN_EN <= #0.1 VRPU_AUTO_SHDN_EN_d;

        WENn <= #0.1 WENn_d;
        RENn <= #0.1 RENn_d;
        WADDR <= #0.1 WADDR_d;
        RADDR <= #0.1 RADDR_d;
        WD <= #0.1 WD_d;
   end

end


// Write to Sram task which perform all write operations.
// All possible Sram locations are written using data values
// generated from the supplied start_data value.
task write_sram;
input   [15:0]  start_data;
begin
    @(negedge SYS_CLOCK)
    begin
        WENn_d = 1'b0;
        WADDR_d = 6'h00;
        WD_d = start_data;
    end
    repeat(63)
    begin
        @(negedge SYS_CLOCK)
        begin
            WADDR_d = WADDR_d + 6'h01;
            WD_d = WD_d + 16'h0001;
        end
    end
    @(negedge SYS_CLOCK)
        WENn_d = 1'b1;
end
endtask


// The set of data values used to verify the Sram data read.
always @(posedge SYS_CLOCK or negedge SYS_RESETn)
begin
   if (!SYS_RESETn)
        golden_data <= 16'h0000;
   else
        golden_data <= #0.1 golden_data_d;
end


// Read from Sram task which performs all read operations.
// All possible Sram locations are read and verified against the
// generated values (golden_data) from the supplied start_data value.
task read_sram;
input   [15:0]  start_data;
integer i;

begin
    i=0;
    $display ("* Read and Verify Data:");
    @(posedge SYS_CLOCK)
    begin
        RENn_d = 1'b0;
        RADDR_d = 6'h00;
    end
    for(i=0; i<66; i=i+1)
    begin
        @(posedge SYS_CLOCK)
        begin
            case(i)
            0: begin
                RADDR_d = RADDR_d + 6'h01;
                golden_data_d = start_data;
            end
            63: begin
                if (RD == golden_data)
                    $display ("Good Data @ RADDR=%2h, RD=%4h", RADDR, RD);
                else
                    $display ("Bad Data @ RADDR=%2h, RD=%4h", RADDR, RD);
                golden_data_d = golden_data_d + 16'h0001;
                RENn_d = 1'b1;
            end
            64: begin
                if (RD == golden_data)
                    $display ("Good Data @ RADDR=%2h, RD=%4h", RADDR, RD);
                else
                    $display ("Bad Data @ RADDR=%2h, RD=%4h", RADDR, RD);
                golden_data_d = golden_data_d + 16'h0001;
                RENn_d = 1'b1;
            end
            65: begin
                if (RD == golden_data)
                    $display ("Good Data @ RADDR=%2h, RD=%4h", RADDR, RD);
                else
                    $display ("Bad Data @ RADDR=%2h, RD=%4h", RADDR, RD);
            end
            default: begin
                if (RD == golden_data)
                    $display ("Good Data @ RADDR=%2h, RD=%4h", RADDR, RD);
                else
                    $display ("Bad Data @ RADDR=%2h, RD=%4h", RADDR, RD);
                RADDR_d = RADDR_d + 6'h01;
                golden_data_d = golden_data_d + 16'h0001;
            end
            endcase
        end
    end
end
endtask


/* Initial block with all time dependant testbench activities */
initial
begin
    // Time 0 initial values
    SAVE_SRAM_TO_FLASH_d = 1'b0;
    UPDATE_SRAM_FROM_FLASH_d = 1'b0;
    VRPU_AUTO_SHDN_EN_d = 1'b0;

    WENn_d = 1'b1;
    RENn_d = 1'b1;
    WADDR_d = 6'h00;
    RADDR_d = 6'h00;
    WD_d = 16'h0000;
    golden_data_d = 16'h0000;

    PUB = 1'b1;
    VRPU_IN = 1'b0;

    
    @(posedge SYS_RESETn)       // Wait for reset to complete
    ;
    
    @(posedge CONTEXT_DONE)     // Wait for CONTEXT_DONE to become active
    ;

    #100  write_sram(16'hA500); // Write values starting at 0xA500 to Sram
    #100  read_sram(16'hA500);  // Read and verify values starting at 0xA500 from Sram

    repeat(2)                   // Issue a context save command
        @(negedge SYS_CLOCK) SAVE_SRAM_TO_FLASH_d = !SAVE_SRAM_TO_FLASH_d;

    @(posedge CONTEXT_DONE)     // Wait for CONTEXT_DONE to become active
    ;

    repeat(2)                   // Issue a context reload command
        @(negedge SYS_CLOCK) UPDATE_SRAM_FROM_FLASH_d = !UPDATE_SRAM_FROM_FLASH_d;

    @(posedge CONTEXT_DONE)     // Wait for CONTEXT_DONE to become active
    ;
 
     repeat(2)                   // Issue a context save command
        @(negedge SYS_CLOCK) SAVE_SRAM_TO_FLASH_d = !SAVE_SRAM_TO_FLASH_d;

    @(posedge CONTEXT_DONE)     // Wait for CONTEXT_DONE to become active
    ;
    #100  read_sram(16'hA500);  // Read and verify values starting at 0xA500 from Sram

    repeat(2)                   // Issue a voltage regulator shutdown command
        #100 VRPU_IN = !VRPU_IN;

    @(posedge SYS_RESETn)       // Wait for reset to complete
    ;

    #100 VRPU_AUTO_SHDN_EN_d = 1'b1;    // Enable the auto-shutdown feature

    @(posedge CONTEXT_DONE)     // Wait for CONTEXT_DONE to become active
    ;

    #100  read_sram(16'hA500);  // Read and verify values starting at 0xA500 from Sram

    repeat(2)                   // Issue a context save command
        @(negedge SYS_CLOCK) SAVE_SRAM_TO_FLASH_d = !SAVE_SRAM_TO_FLASH_d;

    @(posedge SYS_RESETn)       // Wait for reset to complete
    ;

    @(posedge CONTEXT_DONE)     // Wait for CONTEXT_DONE to become active
    ;

    #100  read_sram(16'hA500);  // Read and verify values starting at 0xA500 from Sram

    #1000   $stop;
end


/* Initial block used to stop the simulation if the above initial block 
activity never ends */
initial
begin
    #5000000   $stop;
end

endmodule   // TEST_PM_CONTEXT_SAVING




/* External XTAL component */
module EXT_XTAL(XTL);
output	XTL;

reg	XTL;

parameter XTLCLK_PERIOD = 100;       // Clock period variable (10MHz)

always
begin
    #(XTLCLK_PERIOD/2) XTL = !XTL;
end

initial
begin
    XTL = 1'b1;
end
endmodule


/* External RESET generator */
module RSTGEN( FPGAGOOD, SYS_RESETn);
input	FPGAGOOD;
output	SYS_RESETn;

reg	SYS_RESETn;

always @(FPGAGOOD)
begin
     #5 SYS_RESETn = FPGAGOOD;
end

initial
begin
    SYS_RESETn = 1'b0;
end
endmodule