blob: b731310b9cd4da68cdd82ff48a32e368492b467f [file] [log] [blame]
// *==============================================================================================
// *
// * MX25U3235F.v - 32M-BIT CMOS Serial Flash Memory
// *
// * COPYRIGHT 2018 Macronix International Co., Ltd.
// *
// * Security Level: Macronix Proprietary
// *----------------------------------------------------------------------------------------------
// * Environment : Cadence NC-Verilog
// * Reference Doc: MX25U3235F REV.1.6,JUL.12,2017
// * Creation Date: @(#)$Date: 2017/07/17 08:43:16 $
// * Version : @(#)$Revision: 1.21 $
// * Description : There is only one module in this file
// * module MX25U3235F->behavior model for the 32M-Bit flash
// *----------------------------------------------------------------------------------------------
// * Note 1:model can load initial flash data from file when parameter Init_File = "xxx" was defined;
// * xxx: initial flash data file name;default value xxx = "none", initial flash data is "FF".
// * Note 2:power setup time is tVSL = 800_000 ns, so after power up, chip can be enable.
// * Note 3:because it is not checked during the Board system simulation the tCLQX timing is not
// * inserted to the read function flow temporarily.
// * Note 4:more than one values (min. typ. max. value) are defined for some AC parameters in the
// * datasheet, but only one of them is selected in the behavior model, e.g. program and
// * erase cycle time is typical value. For the detailed information of the parameters,
// * please refer to datasheet and contact with Macronix.
// * Note 5:If you have any question and suggestion, please send your mail to following email address :
// * flash_model@mxic.com.tw
// *==============================================================================================
// * timescale define
// *==============================================================================================
`timescale 1ns / 100ps
// *==============================================================================================
// * product parameter define
// *==============================================================================================
/*----------------------------------------------------------------------*/
/* all the parameters users may need to change */
/*----------------------------------------------------------------------*/
`define Vtclqv 6 //30pf:8ns, 15pf:6ns
`define File_Name "none" // Flash data file name for normal array
`define File_Name_Secu "none" // Flash data file name for security region
`define File_Name_SFDP "none" // Flash data file name for SFDP region
`define VSEC_Pro_Reg ~1'b0 // for protect
`define VSEC_Pro_Reg_TOP 16'hffff // for top protect
`define VSEC_Pro_Reg_BOT 16'hffff // for bottom protect
`define VSecur_Reg1_0 2'b00 // security register[1:0]
`define VSecur_Reg7 1'b0 // security register[7]
`define VStatus_Reg7_2 6'b0 // status register[7:2] are non-volatile bits
/*----------------------------------------------------------------------*/
/* Define controller STATE */
/*----------------------------------------------------------------------*/
`define STANDBY_STATE 0
`define CMD_STATE 1
`define BAD_CMD_STATE 2
module MX25U3235F( SCLK,
CS,
SI,
SO,
WP,
SIO3 );
// *==============================================================================================
// * Declaration of ports (input, output, inout)
// *==============================================================================================
input SCLK; // Signal of Clock Input
input CS; // Chip select (Low active)
inout SI; // Serial Input/Output SIO0
inout SO; // Serial Input/Output SIO1
inout WP; // Hardware write protection or Serial Input/Output SIO2
inout SIO3; // Serial Input/Output SIO3
// *==============================================================================================
// * Declaration of parameter (parameter)
// *==============================================================================================
parameter VERBOSE = 0;
/*----------------------------------------------------------------------*/
/* Density STATE parameter */
/*----------------------------------------------------------------------*/
parameter A_MSB = 21,
TOP_Add = 22'h3fffff,
A_MSB_OTP = 8,
Secur_TOP_Add = 9'h1ff,
Sector_MSB = 9,
A_MSB_SFDP = 6,
SFDP_TOP_Add = 7'h7f,
Buffer_Num = 256,
Block_MSB = 5,
Block_NUM = 64;
/*----------------------------------------------------------------------*/
/* Define ID Parameter */
/*----------------------------------------------------------------------*/
parameter ID_MXIC = 8'hc2,
ID_Device = 8'h36,
Memory_Type = 8'h25,
Memory_Density = 8'h36;
/*----------------------------------------------------------------------*/
/* Define Initial Memory File Name */
/*----------------------------------------------------------------------*/
parameter Init_File = `File_Name; // initial flash data
parameter Init_File_Secu = `File_Name_Secu; // initial flash data for security
parameter Init_File_SFDP = `File_Name_SFDP; // initial flash data for SFDP
/*----------------------------------------------------------------------*/
/* AC Characters Parameter */
/*----------------------------------------------------------------------*/
parameter tSHQZ = 8, // CS High to SO Float Time [ns]
tCLQV = `Vtclqv, // Clock Low to Output Valid
tCLQX = 0, // Output hold time
tBP = 12_000, // Byte program time
tSE = 35_000_000, // Sector erase time
tBE = 350_000_000, // Block erase time
tBE32 = 200_000_000, // Block 32KB erase time
tCE = 25_000, // unit is ms instead of ns
tPP = 500_000, // Program time
tW = 40_000_000, // Write Status time
tWPS = 12_000, // Write Protection Select time
tWP_SRAM = 1_000, // Write protection sram time
tRCR = 20_000, // reset time from read
tRCP = 20_000, // reset time from program
tRCE = 12_000_000, // reset time from erase
tRHRL_E = 12_000_000, // hardware reset recovery time for ers
// in operation phase
tRHRL_RP = 20_000, // hardware reset recovery time for
// read/pgm phase or instruction coding phase
`ifdef SPEEDSIM
tVSL = 10_000; // Time delay to chip select allowed
`else
tVSL = 800_000; // Time delay to chip select allowed
`endif
parameter tPGM_CHK = 2_000, // 2 us
tERS_CHK = 100_000; // 100 us
parameter tESL = 20_000, // delay after erase suspend command
tPSL = 20_000, // delay after program suspend command
tPRS = 100_000, // latency between program resume and next suspend
tERS = 400_000; // latency between erase resume and next suspend
/*----------------------------------------------------------------------*/
/* Internal counter parameter */
/*----------------------------------------------------------------------*/
parameter Clock = 50, // Internal clock cycle = 100ns
ERS_Count_BE32K = tBE32 / (Clock*2) / 500, // Internal clock cycle = 50us
ERS_Count_SE = tSE / (Clock*2) / 500, // Internal clock cycle = 50us
ERS_Count_BE = tBE / (Clock*2) / 500, // Internal clock cycle = 50us
Echip_Count = tCE / (Clock*2) * 2000;
specify
specparam tSCLK = 9.6, // Clock Cycle Time [ns]
fSCLK = 104, // Clock Frequence except READ instruction
tTSCLK = 11.9, // Clock Cycle Time for 2XI/O READ instruction
fTSCLK = 84, // Clock Frequence for 2XI/O READ instruction
tTSCLK2 = 9.6, // Clock Cycle Time for DREAD instruction
fTSCLK2 = 104, // Clock Frequence for DREAD instruction
tQSCLK = 9.6, // Clock Cycle Time for 4XI/O READ instruction
fQSCLK = 104, // Clock Frequence for 4XI/O READ instruction
tQSCLK2 = 11.9, // Clock Cycle Time for 4XI/O READ instruction
fQSCLK2 = 84, // Clock Frequence for 4XI/O READ instruction
tQSCLK3 = 9.6, // Clock Cycle Time for QREAD instruction
fQSCLK3 = 104, // Clock Frequence for QREAD instruction
tRSCLK = 18.5, // Clock Cycle Time for READ instruction
fRSCLK = 54, // Clock Frequence for READ instruction
tCH = 4.5, // Clock High Time (min) [ns]
tCL = 4.5, // Clock Low Time (min) [ns]
tCH_R = 9, // Clock High Time (min) [ns]
tCL_R = 9, // Clock Low Time (min) [ns]
tSLCH = 5, // CS# Active Setup Time (relative to SCLK) (min) [ns]
tCHSL = 5, // CS# Not Active Hold Time (relative to SCLK)(min) [ns]
tSHSL_R = 5, // CS High Time for read instruction (min) [ns]
tSHSL_W = 30, // CS High Time for write instruction (min) [ns]
tDVCH = 2, // SI Setup Time (min) [ns]
tCHDX = 3, // SI Hold Time (min) [ns]
tCHSH = 2, // CS# Active Hold Time (relative to SCLK) (min) [ns]
tSHCH = 3, // CS# Not Active Setup Time (relative to SCLK) (min) [ns]
tWHSL = 10, // Write Protection Setup Time
tSHWL = 10, // Write Protection Hold Time
tRLRH = 1_000, // hardware reset pulse
tRS = 15, // reset setup time
tRH = 15, // reset hold time
tDP = 10_000,
tRES1 = 30_000,
tRES2 = 30_000;
endspecify
/*----------------------------------------------------------------------*/
/* Define Command Parameter */
/*----------------------------------------------------------------------*/
parameter WREN = 8'h06, // WriteEnable
WRDI = 8'h04, // WriteDisable
RDID = 8'h9F, // ReadID
RDSR = 8'h05, // ReadStatus
WRSR = 8'h01, // WriteStatus
READ1X = 8'h03, // ReadData
FASTREAD1X = 8'h0b, // FastReadData
SE = 8'h20, // SectorErase
BE2 = 8'h52, // 32k block erase
CE1 = 8'h60, // ChipErase
CE2 = 8'hc7, // ChipErase
PP = 8'h02, // PageProgram
DP = 8'hb9, // DeepPowerDown
RDP = 8'hab, // ReleaseFromDeepPowerDown
RES = 8'hab, // ReadElectricID
REMS = 8'h90, // ReadElectricManufacturerDeviceID
BE = 8'hd8, // BlockErase
READ2X = 8'hbb, // 2X Read
ENSO = 8'hb1, // Enter secured OTP;
EXSO = 8'hc1, // Exit secured OTP;
RDSCUR = 8'h2b, // Read security register;
WRSCUR = 8'h2f, // Write security register;
READ4X = 8'heb, // 4XI/O Read;
FIOPGM0 = 8'h38, // 4I Page Pgm load address and data all 4io
SFDP_READ = 8'h5a, // enter SFDP read mode
DREAD = 8'h3b, // Fastread dual output;
QREAD = 8'h6b, // Fastread quad output 1I/4O
WPSEL = 8'h68, // write protection selection
SBLK = 8'h36, // single block lock
SBULK = 8'h39, // single block unlock
RDBLOCK = 8'h3c, // block protect read
GBLK = 8'h7e, // gang block lock
GBULK = 8'h98; // gang block unlock
parameter EQIO = 8'h35, // enable quad I/O
RSTQIO = 8'hf5, // reset quad I/O
QPIID = 8'haf, // QPI ID read
W4READ = 8'he7, // enable wrap quad read
NOP = 8'h00, // no operation
RSTEN = 8'h66, // reset enable
RST = 8'h99, // reset memory
SUSP = 8'hb0,
RESU = 8'h30,
SBL = 8'hc0; // set burst length
/*----------------------------------------------------------------------*/
/* Declaration of internal-signal */
/*----------------------------------------------------------------------*/
reg [7:0] ARRAY[0:TOP_Add]; // memory array
reg [7:0] Status_Reg; // Status Register
reg [7:0] CMD_BUS;
reg [23:0] SI_Reg; // temp reg to store serial in
reg [7:0] Dummy_A[0:255]; // page size
reg [A_MSB:0] Address;
reg [Sector_MSB:0] Sector;
reg [Block_MSB:0] Block;
reg [Block_MSB+1:0] Block2;
reg [2:0] STATE;
reg [7:0] SFDP_ARRAY[0:SFDP_TOP_Add];
reg [15:0] SEC_Pro_Reg_TOP;
reg [15:0] SEC_Pro_Reg_BOT;
reg [Block_NUM - 2:1] SEC_Pro_Reg;
reg SIO0_Reg;
reg SIO1_Reg;
reg SIO2_Reg;
reg SIO3_Reg;
reg SIO0_Out_Reg;
reg SIO1_Out_Reg;
reg SIO2_Out_Reg;
reg SIO3_Out_Reg;
reg Chip_EN;
reg DP_Mode; // deep power down mode
reg Read_Mode;
reg Read_1XIO_Mode;
reg Read_1XIO_Chk;
reg tDP_Chk;
reg tRES1_Chk;
reg tRES2_Chk;
reg RDID_Mode;
reg RDSR_Mode;
reg RDSCUR_Mode;
reg FastRD_1XIO_Mode;
reg PP_1XIO_Mode;
reg SE_4K_Mode;
reg BE_Mode;
reg BE32K_Mode;
reg BE64K_Mode;
reg CE_Mode;
reg WRSR_Mode;
reg RES_Mode;
reg REMS_Mode;
reg SCLK_EN;
reg SO_OUT_EN; // for SO
reg SI_IN_EN; // for SI
reg SFDP_Mode;
reg SEC_PROVFY_Mode;
reg RST_CMD_EN;
reg WRSCUR_Mode;
reg WR_WPSEL_Mode;
reg EN_Burst;
reg W4Read_Mode;
reg During_Susp_Wait;
reg Susp_Ready;
reg Susp_Trig;
reg Resume_Trig;
reg ERS_CLK; // internal clock register for erase timer
reg PGM_CLK; // internal clock register for program timer
reg WR2Susp;
wire CS_INT;
wire WP_B_INT;
wire RESETB_INT;
wire SCLK;
wire WIP;
wire ESB;
wire PSB;
wire EPSUSP;
wire WEL;
wire SRWD;
wire Dis_CE, Dis_WRSR;
wire WPSEL_Mode;
wire Norm_Array_Mode;
wire Pgm_Mode;
wire Ers_Mode;
event Resume_Event;
event Susp_Event;
event WRSR_Event;
event BE_Event;
event SE_4K_Event;
event CE_Event;
event PP_Event;
event BE32K_Event;
event WPSEL_Event;
event SBLK_Event;
event SBULK_Event;
event GBLK_Event;
event GBULK_Event;
event RST_Event;
event RST_EN_Event;
event HDRST_Event;
integer i;
integer j;
integer Bit;
integer Bit_Tmp;
integer Start_Add;
integer End_Add;
integer tWRSR;
integer Burst_Length;
// time tRES;
time ERS_Time;
time tPP_Real; //program time according to programmed byte number
reg Read_SHSL;
wire Write_SHSL;
reg [7:0] Secur_ARRAY[0:Secur_TOP_Add]; // Secured OTP
reg [7:0] Secur_Reg; // security register
reg Secur_Mode; // enter secured mode
reg Read_2XIO_Mode;
reg Read_2XIO_Chk;
reg Byte_PGM_Mode;
reg SI_OUT_EN; // for SI
reg SO_IN_EN; // for SO
event WRSCUR_Event;
reg Read_4XIO_Mode;
reg READ4X_Mode;
reg FREAD4X_Mode;
reg Read_4XIO_Chk;
reg FastRD_2XIO_Mode;
reg FastRD_2XIO_Chk;
reg FastRD_4XIO_Mode;
reg FastRD_4XIO_Chk;
reg PP_4XIO_Mode;
reg PP_4XIO_Load;
reg PP_4XIO_Chk;
reg EN4XIO_Read_Mode;
reg Set_4XIO_Enhance_Mode;
reg WP_OUT_EN; // for WP pin
reg SIO3_OUT_EN; // for SIO3 pin
reg WP_IN_EN; // for WP pin
reg SIO3_IN_EN; // for SIO3 pin
reg ENQUAD;
reg During_RST_REC;
wire HPM_RD;
wire SIO3;
wire fQ_84M;
wire fQ_104M;
assign fQ_84M = ((CMD_BUS == FASTREAD1X & ENQUAD ) | (CMD_BUS == W4READ) )& Read_4XIO_Chk;
assign fQ_104M = !fQ_84M && Read_4XIO_Chk;
/*----------------------------------------------------------------------*/
/* initial variable value */
/*----------------------------------------------------------------------*/
initial begin
Chip_EN = 1'b0;
Secur_Reg = {`VSecur_Reg7,5'b0_0000,`VSecur_Reg1_0};
Status_Reg = {`VStatus_Reg7_2,2'b00};
READ4X_Mode = 1'b0;
reset_sm;
end
task reset_sm;
begin
SEC_Pro_Reg[Block_NUM - 2:1] = `VSEC_Pro_Reg;
SEC_Pro_Reg_TOP[15:0] = `VSEC_Pro_Reg_TOP;
SEC_Pro_Reg_BOT[15:0] = `VSEC_Pro_Reg_BOT;
During_RST_REC = 1'b0;
WRSCUR_Mode = 1'b0;
WR_WPSEL_Mode = 1'b0;
SIO0_Reg = 1'b1;
SIO1_Reg = 1'b1;
SIO2_Reg = 1'b1;
SIO3_Reg = 1'b1;
SIO0_Out_Reg = 1'b1;
SIO1_Out_Reg = 1'b1;
SIO2_Out_Reg = 1'b1;
SIO3_Out_Reg = 1'b1;
RST_CMD_EN = 1'b0;
ENQUAD = 1'b0;
SO_OUT_EN = 1'b0; // SO output enable
SI_IN_EN = 1'b0; // SI input enable
CMD_BUS = 8'b0000_0000;
Address = 0;
i = 0;
j = 0;
Bit = 0;
Bit_Tmp = 0;
Start_Add = 0;
End_Add = 0;
DP_Mode = 1'b0;
SCLK_EN = 1'b1;
Read_Mode = 1'b0;
Read_1XIO_Mode = 1'b0;
Read_1XIO_Chk = 1'b0;
tDP_Chk = 1'b0;
tRES1_Chk = 1'b0;
tRES2_Chk = 1'b0;
RDID_Mode = 1'b0;
RDSR_Mode = 1'b0;
RDSCUR_Mode = 1'b0;
PP_1XIO_Mode = 1'b0;
SE_4K_Mode = 1'b0;
BE_Mode = 1'b0;
BE32K_Mode = 1'b0;
BE64K_Mode = 1'b0;
CE_Mode = 1'b0;
WRSR_Mode = 1'b0;
RES_Mode = 1'b0;
REMS_Mode = 1'b0;
Read_SHSL = 1'b0;
FastRD_1XIO_Mode = 1'b0;
FastRD_2XIO_Mode = 1'b0;
FastRD_2XIO_Chk = 1'b0;
FastRD_4XIO_Mode = 1'b0;
FastRD_4XIO_Chk = 1'b0;
SI_OUT_EN = 1'b0; // SI output enable
SO_IN_EN = 1'b0; // SO input enable
Secur_Mode = 1'b0;
Read_2XIO_Mode = 1'b0;
Read_2XIO_Chk = 1'b0;
Byte_PGM_Mode = 1'b0;
WP_OUT_EN = 1'b0; // for WP pin output enable
SIO3_OUT_EN = 1'b0; // for SIO3 pin output enable
WP_IN_EN = 1'b0; // for WP pin input enable
SIO3_IN_EN = 1'b0; // for SIO3 pin input enable
Read_4XIO_Mode = 1'b0;
W4Read_Mode = 1'b0;
FREAD4X_Mode = 1'b0;
Read_4XIO_Chk = 1'b0;
PP_4XIO_Mode = 1'b0;
PP_4XIO_Load = 1'b0;
PP_4XIO_Chk = 1'b0;
EN4XIO_Read_Mode = 1'b0;
Set_4XIO_Enhance_Mode = 1'b0;
SFDP_Mode = 1'b0;
SEC_PROVFY_Mode = 1'b0;
EN_Burst = 1'b0;
Burst_Length = 8;
During_Susp_Wait = 0;
Susp_Ready = 1'b1;
Susp_Trig = 1'b0;
Resume_Trig = 1'b0;
ERS_CLK = 1'b0;
PGM_CLK = 1'b0;
WR2Susp = 1'b0;
end
endtask // reset_sm
/*----------------------------------------------------------------------*/
/* initial flash data */
/*----------------------------------------------------------------------*/
initial
begin : memory_initialize
for ( i = 0; i <= TOP_Add; i = i + 1 )
ARRAY[i] = 8'hff;
if ( Init_File != "none" )
$readmemh(Init_File,ARRAY) ;
for( i = 0; i <= Secur_TOP_Add; i = i + 1 ) begin
Secur_ARRAY[i]=8'hff;
end
if ( Init_File_Secu != "none" )
$readmemh(Init_File_Secu,Secur_ARRAY) ;
for( i = 0; i <= SFDP_TOP_Add; i = i + 1 ) begin
SFDP_ARRAY[i] = 8'hff;
end
if ( Init_File_SFDP != "none" )
$readmemh(Init_File_SFDP,SFDP_ARRAY) ;
// define SFDP code
SFDP_ARRAY[8'h0] = 8'h53;
SFDP_ARRAY[8'h1] = 8'h46;
SFDP_ARRAY[8'h2] = 8'h44;
SFDP_ARRAY[8'h3] = 8'h50;
SFDP_ARRAY[8'h4] = 8'h00;
SFDP_ARRAY[8'h5] = 8'h01;
SFDP_ARRAY[8'h6] = 8'h01;
SFDP_ARRAY[8'h7] = 8'hff;
SFDP_ARRAY[8'h8] = 8'h00;
SFDP_ARRAY[8'h9] = 8'h00;
SFDP_ARRAY[8'ha] = 8'h01;
SFDP_ARRAY[8'hb] = 8'h09;
SFDP_ARRAY[8'hc] = 8'h30;
SFDP_ARRAY[8'hd] = 8'h00;
SFDP_ARRAY[8'he] = 8'h00;
SFDP_ARRAY[8'hf] = 8'hff;
SFDP_ARRAY[8'h10] = 8'hc2;
SFDP_ARRAY[8'h11] = 8'h00;
SFDP_ARRAY[8'h12] = 8'h01;
SFDP_ARRAY[8'h13] = 8'h04;
SFDP_ARRAY[8'h14] = 8'h60;
SFDP_ARRAY[8'h15] = 8'h00;
SFDP_ARRAY[8'h16] = 8'h00;
SFDP_ARRAY[8'h17] = 8'hff;
SFDP_ARRAY[8'h18] = 8'hff;
SFDP_ARRAY[8'h19] = 8'hff;
SFDP_ARRAY[8'h1a] = 8'hff;
SFDP_ARRAY[8'h1b] = 8'hff;
SFDP_ARRAY[8'h1c] = 8'hff;
SFDP_ARRAY[8'h1d] = 8'hff;
SFDP_ARRAY[8'h1e] = 8'hff;
SFDP_ARRAY[8'h1f] = 8'hff;
SFDP_ARRAY[8'h20] = 8'hff;
SFDP_ARRAY[8'h21] = 8'hff;
SFDP_ARRAY[8'h22] = 8'hff;
SFDP_ARRAY[8'h23] = 8'hff;
SFDP_ARRAY[8'h24] = 8'hff;
SFDP_ARRAY[8'h25] = 8'hff;
SFDP_ARRAY[8'h26] = 8'hff;
SFDP_ARRAY[8'h27] = 8'hff;
SFDP_ARRAY[8'h28] = 8'hff;
SFDP_ARRAY[8'h29] = 8'hff;
SFDP_ARRAY[8'h2a] = 8'hff;
SFDP_ARRAY[8'h2b] = 8'hff;
SFDP_ARRAY[8'h2c] = 8'hff;
SFDP_ARRAY[8'h2d] = 8'hff;
SFDP_ARRAY[8'h2e] = 8'hff;
SFDP_ARRAY[8'h2f] = 8'hff;
SFDP_ARRAY[8'h30] = 8'he5;
SFDP_ARRAY[8'h31] = 8'h20;
SFDP_ARRAY[8'h32] = 8'hf1;
SFDP_ARRAY[8'h33] = 8'hff;
SFDP_ARRAY[8'h34] = 8'hff;
SFDP_ARRAY[8'h35] = 8'hff;
SFDP_ARRAY[8'h36] = 8'hff;
SFDP_ARRAY[8'h37] = 8'h01;
SFDP_ARRAY[8'h38] = 8'h44;
SFDP_ARRAY[8'h39] = 8'heb;
SFDP_ARRAY[8'h3a] = 8'h08;
SFDP_ARRAY[8'h3b] = 8'h6b;
SFDP_ARRAY[8'h3c] = 8'h08;
SFDP_ARRAY[8'h3d] = 8'h3b;
SFDP_ARRAY[8'h3e] = 8'h04;
SFDP_ARRAY[8'h3f] = 8'hbb;
SFDP_ARRAY[8'h40] = 8'hfe;
SFDP_ARRAY[8'h41] = 8'hff;
SFDP_ARRAY[8'h42] = 8'hff;
SFDP_ARRAY[8'h43] = 8'hff;
SFDP_ARRAY[8'h44] = 8'hff;
SFDP_ARRAY[8'h45] = 8'hff;
SFDP_ARRAY[8'h46] = 8'h00;
SFDP_ARRAY[8'h47] = 8'hff;
SFDP_ARRAY[8'h48] = 8'hff;
SFDP_ARRAY[8'h49] = 8'hff;
SFDP_ARRAY[8'h4a] = 8'h44;
SFDP_ARRAY[8'h4b] = 8'heb;
SFDP_ARRAY[8'h4c] = 8'h0c;
SFDP_ARRAY[8'h4d] = 8'h20;
SFDP_ARRAY[8'h4e] = 8'h0f;
SFDP_ARRAY[8'h4f] = 8'h52;
SFDP_ARRAY[8'h50] = 8'h10;
SFDP_ARRAY[8'h51] = 8'hd8;
SFDP_ARRAY[8'h52] = 8'h00;
SFDP_ARRAY[8'h53] = 8'hff;
SFDP_ARRAY[8'h54] = 8'hff;
SFDP_ARRAY[8'h55] = 8'hff;
SFDP_ARRAY[8'h56] = 8'hff;
SFDP_ARRAY[8'h57] = 8'hff;
SFDP_ARRAY[8'h58] = 8'hff;
SFDP_ARRAY[8'h59] = 8'hff;
SFDP_ARRAY[8'h5a] = 8'hff;
SFDP_ARRAY[8'h5b] = 8'hff;
SFDP_ARRAY[8'h5c] = 8'hff;
SFDP_ARRAY[8'h5d] = 8'hff;
SFDP_ARRAY[8'h5e] = 8'hff;
SFDP_ARRAY[8'h5f] = 8'hff;
SFDP_ARRAY[8'h60] = 8'h00;
SFDP_ARRAY[8'h61] = 8'h20;
SFDP_ARRAY[8'h62] = 8'h50;
SFDP_ARRAY[8'h63] = 8'h16;
SFDP_ARRAY[8'h64] = 8'h9d;
SFDP_ARRAY[8'h65] = 8'hf9;
SFDP_ARRAY[8'h66] = 8'hc0;
SFDP_ARRAY[8'h67] = 8'h64;
SFDP_ARRAY[8'h68] = 8'hd9;
SFDP_ARRAY[8'h69] = 8'hc8;
SFDP_ARRAY[8'h6a] = 8'hff;
SFDP_ARRAY[8'h6b] = 8'hff;
SFDP_ARRAY[8'h6c] = 8'hff;
SFDP_ARRAY[8'h6d] = 8'hff;
SFDP_ARRAY[8'h6e] = 8'hff;
SFDP_ARRAY[8'h6f] = 8'hff;
end
// *==============================================================================================
// * Input/Output bus operation
// *==============================================================================================
assign CS_INT = ( During_RST_REC == 1'b0 && RESETB_INT == 1'b1 && Chip_EN ) ? CS : 1'b1;
assign WP_B_INT = (Status_Reg[6] == 1'b0 && !ENQUAD) ? WP : 1'b1;
assign SO = SO_OUT_EN ? SIO1_Out_Reg : 1'bz ;
assign SI = SI_OUT_EN ? SIO0_Out_Reg : 1'bz ;
assign WP = WP_OUT_EN ? SIO2_Out_Reg : 1'bz ;
assign SIO3 = SIO3_OUT_EN ? SIO3_Out_Reg : 1'bz ;
assign RESETB_INT = (Status_Reg[6] == 1'b0 && ENQUAD == 1'b0)? ((SIO3 === 1'b1 || SIO3 === 1'b0) ? SIO3 : 1'b1): 1'b1;
/*----------------------------------------------------------------------*/
/* output buffer */
/*----------------------------------------------------------------------*/
always @( SIO3_Reg or SIO2_Reg or SIO1_Reg or SIO0_Reg ) begin
if ( SIO3_OUT_EN && WP_OUT_EN && SO_OUT_EN && SI_OUT_EN ) begin
SIO3_Out_Reg <= #tCLQV SIO3_Reg;
SIO2_Out_Reg <= #tCLQV SIO2_Reg;
SIO1_Out_Reg <= #tCLQV SIO1_Reg;
SIO0_Out_Reg <= #tCLQV SIO0_Reg;
end
else if ( SO_OUT_EN && SI_OUT_EN ) begin
SIO1_Out_Reg <= #tCLQV SIO1_Reg;
SIO0_Out_Reg <= #tCLQV SIO0_Reg;
end
else if ( SO_OUT_EN ) begin
SIO1_Out_Reg <= #tCLQV SIO1_Reg;
end
end
// *==============================================================================================
// * Finite State machine to control Flash operation
// *==============================================================================================
/*----------------------------------------------------------------------*/
/* power on */
/*----------------------------------------------------------------------*/
initial begin
Chip_EN <= #tVSL 1'b1;// Time delay to chip select allowed
end
/*----------------------------------------------------------------------*/
/* Command Decode */
/*----------------------------------------------------------------------*/
assign ESB = Secur_Reg[3] ;
assign PSB = Secur_Reg[2] ;
assign EPSUSP = ESB | PSB ;
assign WIP = Status_Reg[0] ;
assign WEL = Status_Reg[1] ;
assign SRWD = Status_Reg[7] ;
assign Dis_CE = Status_Reg[5] == 1'b1 || Status_Reg[4] == 1'b1 ||
Status_Reg[3] == 1'b1 || Status_Reg[2] == 1'b1;
assign HPM_RD = EN4XIO_Read_Mode == 1'b1 ;
assign Norm_Array_Mode = ~Secur_Mode;
assign Dis_WRSR = (WP_B_INT == 1'b0 && Status_Reg[7] == 1'b1) || (!Norm_Array_Mode);
assign Pgm_Mode = PP_1XIO_Mode || PP_4XIO_Mode;
assign Ers_Mode = SE_4K_Mode || BE_Mode;
assign WPSEL_Mode = Secur_Reg[7];
always @ ( negedge CS_INT ) begin
SI_IN_EN = 1'b1;
if ( ENQUAD ) begin
SO_IN_EN = 1'b1;
SI_IN_EN = 1'b1;
WP_IN_EN = 1'b1;
SIO3_IN_EN = 1'b1;
end
if ( EN4XIO_Read_Mode == 1'b1 ) begin
if (VERBOSE) $display( $time, " Enter READX4 Function ..." );
Read_SHSL = 1'b1;
STATE <= `CMD_STATE;
Read_4XIO_Mode = 1'b1;
end
if ( HPM_RD == 1'b0 ) begin
Read_SHSL <= #1 1'b0;
end
#1;
tDP_Chk = 1'b0;
tRES1_Chk = 1'b0;
tRES2_Chk = 1'b0;
end
always @ ( posedge SCLK or posedge CS_INT ) begin
#0;
if ( CS_INT == 1'b0 ) begin
if ( ENQUAD ) begin
Bit_Tmp = Bit_Tmp + 4;
Bit = Bit_Tmp - 1;
end
else begin
Bit_Tmp = Bit_Tmp + 1;
Bit = Bit_Tmp - 1;
end
if ( SI_IN_EN == 1'b1 && SO_IN_EN == 1'b1 && WP_IN_EN == 1'b1 && SIO3_IN_EN == 1'b1 ) begin
SI_Reg[23:0] = {SI_Reg[19:0], SIO3, WP, SO, SI};
end
else if ( SI_IN_EN == 1'b1 && SO_IN_EN == 1'b1 ) begin
SI_Reg[23:0] = {SI_Reg[21:0], SO, SI};
end
else begin
SI_Reg[23:0] = {SI_Reg[22:0], SI};
end
if ( (EN4XIO_Read_Mode == 1'b1 && ((Bit == 5 && !ENQUAD) || (Bit == 23 && ENQUAD))) ) begin
Address = SI_Reg[A_MSB:0];
load_address(Address);
end
end
if ( Bit == 7 && CS_INT == 1'b0 && ~HPM_RD ) begin
STATE = `CMD_STATE;
CMD_BUS = SI_Reg[7:0];
if (VERBOSE) $display( $time," SI_Reg[7:0]= %h ", SI_Reg[7:0] );
if ( During_RST_REC )
$display ($time," During reset recovery time, there is command. \n");
end
if ( (EN4XIO_Read_Mode && (Bit == 1 || ENQUAD && Bit==7)) && CS_INT == 1'b0
&& HPM_RD && (SI_Reg[7:0]== RSTEN || SI_Reg[7:0]== RST)) begin
CMD_BUS = SI_Reg[7:0];
if (VERBOSE) $display( $time," SI_Reg[7:0]= %h ", SI_Reg[7:0] );
end
if ( CS == 1'b1 && RST_CMD_EN &&
( (Bit+1)%8 == 0 || (EN4XIO_Read_Mode && !ENQUAD && (Bit+1)%2 == 0) ) ) begin
RST_CMD_EN <= #1 1'b0;
end
case ( STATE )
`STANDBY_STATE:
begin
end
`CMD_STATE:
begin
case ( CMD_BUS )
WREN:
begin
if ( !DP_Mode && !WIP && Chip_EN && ~HPM_RD && !PSB ) begin
if ( CS_INT == 1'b1 && Bit == 7 ) begin
// $display( $time, " Enter Write Enable Function ..." );
write_enable;
end
else if ( Bit > 7 )
STATE <= `BAD_CMD_STATE;
end
else if ( Bit == 7 )
STATE <= `BAD_CMD_STATE;
end
WRDI:
begin
if ( !DP_Mode && ( !WIP || During_Susp_Wait ) && Chip_EN && ~HPM_RD ) begin
if ( CS_INT == 1'b1 && Bit == 7 ) begin
// $display( $time, " Enter Write Disable Function ..." );
write_disable;
end
else if ( Bit > 7 )
STATE <= `BAD_CMD_STATE;
end
else if ( Bit == 7 )
STATE <= `BAD_CMD_STATE;
end
RDID:
begin
if ( !DP_Mode && !WIP && Chip_EN && ~HPM_RD && !ENQUAD ) begin
if (VERBOSE) $display( $time, " Enter Read ID Function ..." );
Read_SHSL = 1'b1;
RDID_Mode = 1'b1;
end
else if ( Bit == 7 )
STATE <= `BAD_CMD_STATE;
end
QPIID:
begin
if ( !DP_Mode && !WIP && Chip_EN && ~HPM_RD && ENQUAD ) begin
if (VERBOSE) $display( $time, " Enter Read ID Function ..." );
Read_SHSL = 1'b1;
RDID_Mode = 1'b1;
end
else if ( Bit == 7 )
STATE <= `BAD_CMD_STATE;
end
RDSR:
begin
if ( !DP_Mode && Chip_EN && ~HPM_RD) begin
if (VERBOSE) $display( $time, " Enter Read Status Function ..." );
Read_SHSL = 1'b1;
RDSR_Mode = 1'b1 ;
end
else if ( Bit == 7 )
STATE <= `BAD_CMD_STATE;
end
WRSR:
begin
if ( !DP_Mode && !WIP && WEL && Chip_EN && ~HPM_RD && !EPSUSP ) begin
if ( CS_INT == 1'b1 && Bit == 15 ) begin
if ( Dis_WRSR ) begin
Status_Reg[1] = 1'b0;
end
else begin
if (VERBOSE) $display( $time, " Enter Write Status Function ..." );
->WRSR_Event;
WRSR_Mode = 1'b1;
end
end
else if ( CS_INT == 1'b1 && Bit < 15 || Bit > 15 )
STATE <= `BAD_CMD_STATE;
end
else if ( Bit == 7 )
STATE <= `BAD_CMD_STATE;
end
SBL:
begin
if ( !DP_Mode && !WIP && Chip_EN && ~HPM_RD ) begin // no WEL
if ( CS_INT == 1'b1 && Bit == 15 ) begin
if (VERBOSE) $display( $time, " Enter Set Burst Length Function ..." );
EN_Burst = !SI_Reg[4];
if ( SI_Reg[7:5]==3'b000 && SI_Reg[3:2]==2'b00 ) begin
if ( SI_Reg[1:0]==2'b00 )
Burst_Length = 8;
else if ( SI_Reg[1:0]==2'b01 )
Burst_Length = 16;
else if ( SI_Reg[1:0]==2'b10 )
Burst_Length = 32;
else if ( SI_Reg[1:0]==2'b11 )
Burst_Length = 64;
end
else begin
Burst_Length = 8;
end
end
else if ( CS_INT == 1'b1 && Bit < 15 || Bit > 15 )
STATE <= `BAD_CMD_STATE;
end
else if ( Bit == 7 )
STATE <= `BAD_CMD_STATE;
end
READ1X:
begin
if ( !DP_Mode && !WIP && Chip_EN && ~HPM_RD && !ENQUAD ) begin
if (VERBOSE) $display( $time, " Enter Read Data Function ..." );
Read_SHSL = 1'b1;
if ( Bit == 31 ) begin
Address = SI_Reg [A_MSB:0];
load_address(Address);
end
Read_1XIO_Mode = 1'b1;
end
else if ( Bit == 7 )
STATE <= `BAD_CMD_STATE;
end
W4READ:
begin
if ( !DP_Mode && !WIP && Status_Reg[6] && Chip_EN && ~HPM_RD && !ENQUAD ) begin
if (VERBOSE) $display( $time, " Enter Quad I/O Read Data Function ..." );
Read_SHSL = 1'b1;
if ( Bit == 13 ) begin
Address = SI_Reg [A_MSB:0];
load_address(Address);
end
Read_4XIO_Mode = 1'b1;
W4Read_Mode = 1'b1;
end
else if ( Bit == 7 )
STATE <= `BAD_CMD_STATE;
end
FASTREAD1X:
begin
if ( !DP_Mode && !WIP && Chip_EN && ~HPM_RD ) begin
if (VERBOSE) $display( $time, " Enter Fast Read Data Function ..." );
Read_SHSL = 1'b1;
if ( Bit == 31 ) begin
Address = SI_Reg [A_MSB:0];
load_address(Address);
end
if (ENQUAD) begin
Read_4XIO_Mode = 1'b1;
FREAD4X_Mode = 1'b1;
end
else begin
FastRD_1XIO_Mode = 1'b1;
end
end
else if ( Bit == 7 )
STATE <= `BAD_CMD_STATE;
end
SE:
begin
if ( !DP_Mode && !WIP && WEL && !Secur_Mode && Chip_EN && ~HPM_RD && !EPSUSP ) begin
if ( Bit == 31 ) begin
Address = SI_Reg [A_MSB:0];
end
if ( CS_INT == 1'b1 && Bit == 31 ) begin
if (VERBOSE) $display( $time, " Enter Sector Erase Function ..." );
->SE_4K_Event;
SE_4K_Mode = 1'b1;
end
else if ( CS_INT == 1'b1 && Bit < 31 || Bit > 31 )
STATE <= `BAD_CMD_STATE;
end
else if ( Bit == 7 )
STATE <= `BAD_CMD_STATE;
end
BE:
begin
if ( !DP_Mode && !WIP && WEL && !Secur_Mode && Chip_EN && ~HPM_RD && !EPSUSP ) begin
if ( Bit == 31 ) begin
Address = SI_Reg [A_MSB:0];
end
if ( CS_INT == 1'b1 && Bit == 31 ) begin
if (VERBOSE) $display( $time, " Enter Block Erase Function ..." );
->BE_Event;
BE_Mode = 1'b1;
BE64K_Mode = 1'b1;
end
else if ( CS_INT == 1'b1 && Bit < 31 || Bit > 31 )
STATE <= `BAD_CMD_STATE;
end
else if ( Bit == 7 )
STATE <= `BAD_CMD_STATE;
end
BE2:
begin
if ( !DP_Mode && !WIP && WEL && !Secur_Mode && Chip_EN && ~HPM_RD && !EPSUSP ) begin
if ( Bit == 31 ) begin
Address = SI_Reg [A_MSB:0];
end
if ( CS_INT == 1'b1 && Bit == 31 ) begin
if (VERBOSE) $display( $time, " Enter Block 32K Erase Function ..." );
->BE32K_Event;
BE_Mode = 1'b1;
BE32K_Mode = 1'b1;
end
else if ( CS_INT == 1'b1 && Bit < 31 || Bit > 31 )
STATE <= `BAD_CMD_STATE;
end
else if ( Bit == 7 )
STATE <= `BAD_CMD_STATE;
end
SUSP:
begin
if ( !DP_Mode && !Secur_Mode && Chip_EN && ~HPM_RD && !EPSUSP ) begin
if ( CS_INT == 1'b1 && Bit == 7 ) begin
if (VERBOSE) $display( $time, " Enter Suspend Function ..." );
->Susp_Event;
end
else if ( Bit > 7 )
STATE <= `BAD_CMD_STATE;
end
else if ( Bit == 7 )
STATE <= `BAD_CMD_STATE;
end
RESU:
begin
if ( !DP_Mode && !WIP && Chip_EN && ~HPM_RD && EPSUSP ) begin
if ( CS_INT == 1'b1 && Bit == 7 ) begin
if (VERBOSE) $display( $time, " Enter Resume Function ..." );
Secur_Mode = 1'b0;
->Resume_Event;
end
else if ( Bit > 7 )
STATE <= `BAD_CMD_STATE;
end
else if ( Bit == 7 )
STATE <= `BAD_CMD_STATE;
end
CE1, CE2:
begin
if ( !DP_Mode && !WIP && WEL && !Secur_Mode && Chip_EN && ~HPM_RD && !EPSUSP) begin
if ( CS_INT == 1'b1 && Bit == 7 ) begin
if (VERBOSE) $display( $time, " Enter Chip Erase Function ..." );
->CE_Event;
CE_Mode = 1'b1 ;
end
else if ( Bit > 7 )
STATE <= `BAD_CMD_STATE;
end
else if ( Bit == 7 )
STATE <= `BAD_CMD_STATE;
end
PP:
begin
if ( !DP_Mode && !WIP && WEL && Chip_EN && ~HPM_RD && !PSB) begin
if ( Bit == 31 ) begin
Address = SI_Reg [A_MSB:0];
load_address(Address);
end
if ( Bit == 31 ) begin
if (VERBOSE) $display( $time, " Enter Page Program Function ..." );
if ( CS_INT == 1'b0 ) begin
->PP_Event;
PP_1XIO_Mode = 1'b1;
end
end
else if ( CS_INT == 1 && (Bit < 31 || ((Bit + 1) % 8 !== 0)))
STATE <= `BAD_CMD_STATE;
end
else if ( Bit == 7 )
STATE <= `BAD_CMD_STATE;
end
SFDP_READ:
begin
if ( !DP_Mode && !Secur_Mode && !WIP && Chip_EN ) begin
if (VERBOSE) $display( $time, " Enter SFDP read mode ..." );
if ( Bit == 31 ) begin
Address = SI_Reg [A_MSB:0];
load_address(Address);
end
if ( Bit == 7 ) begin
SFDP_Mode = 1;
if (ENQUAD) begin
Read_4XIO_Mode = 1'b1;
end
else begin
FastRD_1XIO_Mode = 1'b1;
end
Read_SHSL = 1'b1;
end
end
else if ( Bit == 7 )
STATE <= `BAD_CMD_STATE;
end
WPSEL:
begin
if ( !DP_Mode && !WIP && WEL && Norm_Array_Mode && Chip_EN && !EPSUSP ) begin
if ( CS_INT == 1'b1 && Bit == 7 ) begin
if (VERBOSE) $display( $time, " Enter Write Protection Selection Function ..." );
->WPSEL_Event;
end
else if ( Bit > 7 )
STATE <= `BAD_CMD_STATE;
end
else if ( Bit == 7 )
STATE <= `BAD_CMD_STATE;
end
SBLK:
begin
if ( !DP_Mode && !WIP && WEL && Norm_Array_Mode && WPSEL_Mode && Chip_EN && !EPSUSP ) begin
if ( Bit == 31 ) begin
Address = SI_Reg[A_MSB:0] ;
end
if ( CS_INT == 1'b1 && Bit == 31 ) begin
if (VERBOSE) $display( $time, " Enter Sector Protection Function ..." );
->SBLK_Event;
end
else if ( CS_INT == 1'b1 && Bit < 31 || Bit > 31 )
STATE <= `BAD_CMD_STATE;
end
else if ( Bit == 7 )
STATE <= `BAD_CMD_STATE;
end
SBULK:
begin
if ( !DP_Mode && !WIP && WEL && Norm_Array_Mode && WPSEL_Mode && Chip_EN && !EPSUSP ) begin
if ( Bit == 31 ) begin
Address = SI_Reg[A_MSB:0] ;
end
if ( CS_INT == 1'b1 && Bit == 31 ) begin
if (VERBOSE) $display( $time, " Enter Sector Unprotection Function ..." );
->SBULK_Event;
end
else if ( CS_INT == 1'b1 && Bit < 31 || Bit > 31 )
STATE <= `BAD_CMD_STATE;
end
else if ( Bit == 7 )
STATE <= `BAD_CMD_STATE;
end
RDBLOCK:
begin
if ( !DP_Mode && !WIP && WPSEL_Mode && Chip_EN ) begin
if (VERBOSE) $display( $time, " Enter Sector protection Read Function ..." );
if ( Bit == 31 ) begin
Address = SI_Reg[A_MSB:0];
end
if ( Bit == 7 ) begin
SEC_PROVFY_Mode = 1'b1;
Read_SHSL = 1'b1;
end
end
else if ( Bit == 7 )
STATE <= `BAD_CMD_STATE;
end
GBLK:
begin
if ( !DP_Mode && !WIP && WEL && Norm_Array_Mode && WPSEL_Mode && Chip_EN && !EPSUSP ) begin
if ( CS_INT == 1'b1 && Bit == 7 ) begin
if (VERBOSE) $display( $time, " Enter Chip Protection Function ..." );
->GBLK_Event;
end
else if ( CS_INT == 1'b1 && Bit > 7 )
STATE <= `BAD_CMD_STATE;
end
else if ( Bit == 7 )
STATE <= `BAD_CMD_STATE;
end
GBULK:
begin
if ( !DP_Mode && !WIP && WEL && Norm_Array_Mode && WPSEL_Mode && Chip_EN && !EPSUSP ) begin
if ( CS_INT == 1'b1 && Bit == 7 ) begin
if (VERBOSE) $display( $time, " Enter Chip Unprotection Function ..." );
->GBULK_Event;
end
else if ( CS_INT == 1'b1 && Bit > 7 )
STATE <= `BAD_CMD_STATE;
end
else if ( Bit == 7 )
STATE <= `BAD_CMD_STATE;
end
DP:
begin
if ( !WIP && Chip_EN && ~HPM_RD && !EPSUSP ) begin
if ( CS_INT == 1'b1 && Bit == 7 && DP_Mode == 1'b0 ) begin
if (VERBOSE) $display( $time, " Enter Deep Power Down Function ..." );
tDP_Chk = 1'b1;
DP_Mode = 1'b1;
end
else if ( Bit > 7 )
STATE <= `BAD_CMD_STATE;
end
else if ( Bit == 7 )
STATE <= `BAD_CMD_STATE;
end
RDP, RES:
begin
if ( ( !WIP || During_Susp_Wait ) && Chip_EN && ~HPM_RD ) begin
// $display( $time, " Enter Release from Deep Power Down Function ..." );
RES_Mode = 1'b1;
Read_SHSL = 1'b1;
if ( CS_INT == 1'b1 && SCLK == 1'b0 && tRES1_Chk &&
((Bit >= 38 && !ENQUAD) || (Bit >=38 && ENQUAD)) ) begin
tRES1_Chk = 1'b0;
tRES2_Chk = 1'b1;
DP_Mode = 1'b0;
end
else if ( CS_INT == 1'b1 && SCLK == 1'b1 && tRES1_Chk &&
((Bit >= 39 && !ENQUAD) || (Bit >=39 && ENQUAD)) ) begin
tRES1_Chk = 1'b0;
tRES2_Chk = 1'b1;
DP_Mode = 1'b0;
end
else if ( CS_INT == 1'b1 && Bit > 0 && DP_Mode ) begin
tRES1_Chk = 1'b1;
DP_Mode = 1'b0;
end
end
else if ( Bit == 7 )
STATE <= `BAD_CMD_STATE;
end
REMS:
begin
if ( !DP_Mode && !WIP && Chip_EN && ~HPM_RD && !ENQUAD) begin
if ( Bit == 31 ) begin
Address = SI_Reg[A_MSB:0] ;
end
if (VERBOSE) $display( $time, " Enter Read Electronic Manufacturer & ID Function ..." );
Read_SHSL = 1'b1;
REMS_Mode = 1'b1;
end
else if ( Bit == 7 )
STATE <= `BAD_CMD_STATE;
end
READ2X:
begin
if ( !DP_Mode && !WIP && Chip_EN && ~HPM_RD && !ENQUAD ) begin
if (VERBOSE) $display( $time, " Enter READX2 Function ..." );
Read_SHSL = 1'b1;
if ( Bit == 19 ) begin
Address = SI_Reg [A_MSB:0];
load_address(Address);
end
Read_2XIO_Mode = 1'b1;
end
else if ( Bit == 7 )
STATE <= `BAD_CMD_STATE;
end
ENSO:
begin
if ( !DP_Mode && !WIP && Chip_EN && ~HPM_RD ) begin
if ( CS_INT == 1'b1 && Bit == 7 ) begin
if (VERBOSE) $display( $time, " Enter ENSO Function ..." );
enter_secured_otp;
end
else if ( Bit > 7 )
STATE <= `BAD_CMD_STATE;
end
else if ( Bit == 7 )
STATE <= `BAD_CMD_STATE;
end
EXSO:
begin
if ( !DP_Mode && !WIP && Chip_EN && ~HPM_RD ) begin
if ( CS_INT == 1'b1 && Bit == 7 ) begin
if (VERBOSE) $display( $time, " Enter EXSO Function ..." );
exit_secured_otp;
end
else if ( Bit > 7 )
STATE <= `BAD_CMD_STATE;
end
else if ( Bit == 7 )
STATE <= `BAD_CMD_STATE;
end
RDSCUR:
begin
if ( !DP_Mode && Chip_EN && ~HPM_RD) begin
// $display( $time, " Enter Read Secur_Register Function ..." );
Read_SHSL = 1'b1;
RDSCUR_Mode = 1'b1;
end
else if ( Bit == 7 )
STATE <= `BAD_CMD_STATE;
end
WRSCUR:
begin
if ( !DP_Mode && !WIP && WEL && !Secur_Mode && Chip_EN && ~HPM_RD && !EPSUSP ) begin
if ( CS_INT == 1'b1 && Bit == 7 ) begin
if (VERBOSE) $display( $time, " Enter WRSCUR Secur_Register Function ..." );
->WRSCUR_Event;
end
else if ( Bit > 7 )
STATE <= `BAD_CMD_STATE;
end
else if ( Bit == 7 )
STATE <= `BAD_CMD_STATE;
end
READ4X:
begin
if ( !DP_Mode && !WIP && (Status_Reg[6]|ENQUAD) && Chip_EN && ~HPM_RD ) begin
if (VERBOSE) $display( $time, " Enter READX4 Function ..." );
Read_SHSL = 1'b1;
if ( (Bit == 13 && !ENQUAD) || (Bit == 31 && ENQUAD) ) begin
Address = SI_Reg [A_MSB:0];
load_address(Address);
end
Read_4XIO_Mode = 1'b1;
READ4X_Mode = 1'b1;
end
else if ( Bit == 7 )
STATE <= `BAD_CMD_STATE;
end
DREAD:
begin
if ( !DP_Mode && !WIP && Chip_EN && ~HPM_RD && !ENQUAD ) begin
if (VERBOSE) $display( $time, " Enter Fast Read dual output Function ..." );
Read_SHSL = 1'b1;
if ( Bit == 31 ) begin
Address = SI_Reg [A_MSB:0];
load_address(Address);
end
FastRD_2XIO_Mode =1'b1;
end
else if ( Bit == 7 )
STATE <= `BAD_CMD_STATE;
end
QREAD:
begin
if ( !DP_Mode && !WIP && Status_Reg[6] && Chip_EN && ~HPM_RD && !ENQUAD ) begin
if (VERBOSE) $display( $time, " Enter Fast Read quad output Function ..." );
Read_SHSL = 1'b1;
if ( Bit == 31 ) begin
Address = SI_Reg[A_MSB:0] ;
load_address(Address);
end
FastRD_4XIO_Mode =1'b1;
end
else if ( Bit == 7 )
STATE <= `BAD_CMD_STATE;
end
FIOPGM0:
begin
if ( !DP_Mode && !WIP && WEL && Status_Reg[6] && Chip_EN && ~HPM_RD && !ENQUAD && !PSB) begin
if ( Bit == 13 ) begin
Address = SI_Reg [A_MSB:0];
load_address(Address);
end
PP_4XIO_Load= 1'b1;
SO_IN_EN = 1'b1;
SI_IN_EN = 1'b1;
WP_IN_EN = 1'b1;
SIO3_IN_EN = 1'b1;
if ( Bit == 13 ) begin
if (VERBOSE) $display( $time, " Enter 4io Page Program Function ..." );
->PP_Event;
PP_4XIO_Mode= 1'b1;
end
else if ( CS_INT == 1 && (Bit < 15 || (Bit + 1)%2 !== 0 ))begin
STATE <= `BAD_CMD_STATE;
end
end
else if ( Bit == 7 )
STATE <= `BAD_CMD_STATE;
end
EQIO:
begin
if ( !DP_Mode && !WIP && Chip_EN && ~HPM_RD && !ENQUAD ) begin
if ( CS_INT == 1'b1 && Bit == 7 ) begin
if (VERBOSE) $display( $time, " Enable Quad I/O Function ..." );
ENQUAD = 1'b1;
end
else if ( Bit > 7 )
STATE <= `BAD_CMD_STATE;
end
else if ( Bit == 7 )
STATE <= `BAD_CMD_STATE;
end
RSTQIO:
begin
if ( !DP_Mode && !WIP && Chip_EN && ~HPM_RD && ENQUAD ) begin
if ( CS_INT == 1'b1 && Bit == 7 ) begin
if (VERBOSE) $display( $time, " Exiting QPI mode ..." );
ENQUAD = 1'b0;
end
else if ( Bit > 7 )
STATE <= `BAD_CMD_STATE;
end
else if ( Bit == 7 )
STATE <= `BAD_CMD_STATE;
end
RSTEN:
begin
if ( Chip_EN ) begin
if ( CS_INT == 1'b1 && (Bit == 7 || (EN4XIO_Read_Mode && Bit == 1)) ) begin
if (VERBOSE) $display( $time, " Reset enable ..." );
->RST_EN_Event;
end
else if ( Bit > 7 )
STATE <= `BAD_CMD_STATE;
end
else if ( Bit == 7 )
STATE <= `BAD_CMD_STATE;
end
RST:
begin
if ( Chip_EN && RST_CMD_EN ) begin
if ( CS_INT == 1'b1 && (Bit == 7 || (EN4XIO_Read_Mode && Bit == 1)) ) begin
if (VERBOSE) $display( $time, " Reset memory ..." );
->RST_Event;
end
else if ( Bit > 7 )
STATE <= `BAD_CMD_STATE;
end
else if ( Bit == 7 )
STATE <= `BAD_CMD_STATE;
end
NOP:
begin
end
default:
begin
STATE <= `BAD_CMD_STATE;
end
endcase
end
`BAD_CMD_STATE:
begin
end
default:
begin
STATE = `STANDBY_STATE;
end
endcase
if ( CS_INT == 1'b1 ) begin
end
end
always @ (posedge CS_INT) begin
SIO0_Reg <= #tSHQZ 1'bx;
SIO1_Reg <= #tSHQZ 1'bx;
SIO2_Reg <= #tSHQZ 1'bx;
SIO3_Reg <= #tSHQZ 1'bx;
SIO0_Out_Reg <= #tSHQZ 1'bx;
SIO1_Out_Reg <= #tSHQZ 1'bx;
SIO2_Out_Reg <= #tSHQZ 1'bx;
SIO3_Out_Reg <= #tSHQZ 1'bx;
SO_OUT_EN <= #tSHQZ 1'b0;
SI_OUT_EN <= #tSHQZ 1'b0;
WP_OUT_EN <= #tSHQZ 1'b0;
SIO3_OUT_EN <= #tSHQZ 1'b0;
#1;
Bit = 1'b0;
Bit_Tmp = 1'b0;
SO_IN_EN = 1'b0;
SI_IN_EN = 1'b0;
WP_IN_EN = 1'b0;
SIO3_IN_EN = 1'b0;
RDID_Mode = 1'b0;
RDSR_Mode = 1'b0;
RDSCUR_Mode = 1'b0;
Read_Mode = 1'b0;
RES_Mode = 1'b0;
REMS_Mode = 1'b0;
SFDP_Mode = 1'b0;
Read_1XIO_Mode = 1'b0;
Read_2XIO_Mode = 1'b0;
Read_4XIO_Mode = 1'b0;
Read_1XIO_Chk = 1'b0;
Read_2XIO_Chk = 1'b0;
Read_4XIO_Chk = 1'b0;
FastRD_1XIO_Mode= 1'b0;
FastRD_2XIO_Mode= 1'b0;
FastRD_2XIO_Chk= 1'b0;
FastRD_4XIO_Mode= 1'b0;
FastRD_4XIO_Chk= 1'b0;
PP_4XIO_Load = 1'b0;
PP_4XIO_Chk = 1'b0;
STATE <= `STANDBY_STATE;
SEC_PROVFY_Mode = 1'b0;
disable read_id;
disable read_status;
disable read_Secur_Register;
disable read_1xio;
disable read_2xio;
disable read_4xio;
disable fastread_1xio;
disable fastread_2xio;
disable fastread_4xio;
disable read_electronic_id;
disable read_electronic_manufacturer_device_id;
disable read_function;
disable dummy_cycle;
end
always @ (posedge CS_INT) begin
if ( Set_4XIO_Enhance_Mode) begin
EN4XIO_Read_Mode = 1'b1;
end
else begin
EN4XIO_Read_Mode = 1'b0;
W4Read_Mode = 1'b0;
FREAD4X_Mode = 1'b0;
end
end
/*----------------------------------------------------------------------*/
/* ALL function trig action */
/*----------------------------------------------------------------------*/
always @ ( posedge Read_1XIO_Mode
or posedge FastRD_1XIO_Mode
or posedge REMS_Mode
or posedge RES_Mode
or posedge Read_2XIO_Mode
or posedge Read_4XIO_Mode
or posedge PP_4XIO_Load
or posedge FastRD_2XIO_Mode
or posedge FastRD_4XIO_Mode
) begin:read_function
wait ( SCLK == 1'b0 );
if ( Read_1XIO_Mode == 1'b1 ) begin
Read_1XIO_Chk = 1'b1;
read_1xio;
end
else if ( FastRD_1XIO_Mode == 1'b1 ) begin
fastread_1xio;
end
else if ( FastRD_2XIO_Mode == 1'b1 ) begin
FastRD_2XIO_Chk = 1'b1;
fastread_2xio;
end
else if ( FastRD_4XIO_Mode == 1'b1 ) begin
FastRD_4XIO_Chk = 1'b1;
fastread_4xio;
end
else if ( REMS_Mode == 1'b1 ) begin
read_electronic_manufacturer_device_id;
end
else if ( RES_Mode == 1'b1 ) begin
read_electronic_id;
end
else if ( Read_2XIO_Mode == 1'b1 ) begin
Read_2XIO_Chk = 1'b1;
read_2xio;
end
else if ( Read_4XIO_Mode == 1'b1 ) begin
Read_4XIO_Chk = 1'b1;
read_4xio;
end
else if ( PP_4XIO_Load == 1'b1 ) begin
PP_4XIO_Chk = 1'b1;
end
end
always @ ( RST_EN_Event ) begin
RST_CMD_EN = #2 1'b1;
end
always @ ( RST_Event ) begin
During_RST_REC = 1;
if ( BE_Mode || SE_4K_Mode || CE_Mode ) begin
#tRCE;
end
else if ( WRSR_Mode || WRSCUR_Mode || WR_WPSEL_Mode || PP_4XIO_Mode || PP_1XIO_Mode ) begin
#tRCP;
end
else if ( DP_Mode == 1'b1 ) begin
#tRES2;
end
else begin
#tRCR;
end
disable write_status;
disable write_protection_select;
disable block_erase_32k;
disable single_block_lock;
disable single_block_unlock;
disable chip_lock;
disable chip_unlock;
disable sector_protection_read;
disable block_erase;
disable sector_erase_4k;
disable chip_erase;
disable page_program; // can deleted
disable update_array;
disable read_Secur_Register;
disable write_secur_register;
disable read_id;
disable read_status;
disable suspend_write;
disable resume_write;
disable er_timer;
disable pg_timer;
disable stimeout_cnt;
disable rtimeout_cnt;
disable read_1xio;
disable read_2xio;
disable read_4xio;
disable fastread_1xio;
disable fastread_2xio;
disable fastread_4xio;
disable read_electronic_id;
disable read_electronic_manufacturer_device_id;
disable read_function;
disable dummy_cycle;
reset_sm;
READ4X_Mode = 1'b0;
Secur_Reg[6:2] = 5'b0;
Status_Reg[1:0] = 2'b0;
end
// *==============================================================================================
// * Hardware Reset Function description
// * =============================================================================================
always @ ( negedge RESETB_INT ) begin
if (RESETB_INT == 1'b0) begin
disable hd_reset;
#0;
-> HDRST_Event;
end
end
always @ ( HDRST_Event ) begin: hd_reset
if (RESETB_INT == 1'b0) begin
During_RST_REC = 1;
wait ( RESETB_INT == 1'b1 );
if (WRSR_Mode && tWRSR==tW) begin
#(tRHRL_RP);
end
else if (WRSR_Mode && tWRSR==tBP) begin
#(tRHRL_RP);
end
else if ( WR_WPSEL_Mode || WRSCUR_Mode || PP_4XIO_Mode || PP_1XIO_Mode ) begin
#(tRHRL_RP);
end
else if (SE_4K_Mode || BE32K_Mode || BE64K_Mode || CE_Mode ) begin
#(tRHRL_E);
end
else if ( DP_Mode == 1'b1 ) begin
#(tRES2);
end
else begin
#(tRHRL_RP);
end
disable write_status;
disable write_protection_select;
disable block_erase_32k;
disable single_block_lock;
disable single_block_unlock;
disable chip_lock;
disable chip_unlock;
disable sector_protection_read;
disable block_erase;
disable sector_erase_4k;
disable chip_erase;
disable page_program; // can deleted
disable update_array;
disable read_Secur_Register;
disable write_secur_register;
disable read_id;
disable read_status;
disable suspend_write;
disable resume_write;
disable er_timer;
disable pg_timer;
disable stimeout_cnt;
disable rtimeout_cnt;
disable read_1xio;
disable read_2xio;
disable read_4xio;
disable fastread_1xio;
disable fastread_2xio;
disable fastread_4xio;
disable read_electronic_id;
disable read_electronic_manufacturer_device_id;
disable read_function;
disable dummy_cycle;
reset_sm;
READ4X_Mode = 1'b0;
FREAD4X_Mode = 1'b0;
Secur_Reg[6:2] = 5'b0;
Status_Reg[1:0] = 2'b0;
end
end
always @ ( posedge Susp_Trig ) begin:stimeout_cnt
Susp_Trig <= #1 1'b0;
end
always @ ( posedge Resume_Trig ) begin:rtimeout_cnt
Resume_Trig <= #1 1'b0;
end
always @ ( posedge W4Read_Mode or posedge FREAD4X_Mode ) begin
READ4X_Mode = 1'b0;
end
always @ ( WRSR_Event ) begin
write_status;
end
always @ ( BE_Event ) begin
block_erase;
end
always @ ( CE_Event ) begin
chip_erase;
end
always @ ( PP_Event ) begin:page_program_mode
page_program( Address );
end
always @ ( SE_4K_Event ) begin
sector_erase_4k;
end
always @ ( posedge RDID_Mode ) begin
read_id;
end
always @ ( posedge RDSR_Mode ) begin
read_status;
end
always @ ( posedge RDSCUR_Mode ) begin
read_Secur_Register;
end
always @ ( WRSCUR_Event ) begin
write_secur_register;
end
always @ ( Susp_Event ) begin
suspend_write;
end
always @ ( Resume_Event ) begin
resume_write;
end
always @ ( BE32K_Event ) begin
block_erase_32k;
end
always @ ( SBLK_Event ) begin
single_block_lock;
end
always @ ( SBULK_Event ) begin
single_block_unlock;
end
always @ ( GBLK_Event ) begin
chip_lock;
end
always @ ( GBULK_Event ) begin
chip_unlock;
end
always @ ( WPSEL_Event ) begin
write_protection_select;
end
always @ ( posedge SEC_PROVFY_Mode ) begin
sector_protection_read;
end
// *==========================================================================================
// * Module Task Declaration
// *==========================================================================================
/*----------------------------------------------------------------------*/
/* Description: define a wait dummy cycle task */
/* INPUT */
/* Cnum: cycle number */
/*----------------------------------------------------------------------*/
task dummy_cycle;
input [31:0] Cnum;
begin
repeat( Cnum ) begin
@ ( posedge SCLK );
end
end
endtask // dummy_cycle
/*----------------------------------------------------------------------*/
/* Description: define a write enable task */
/*----------------------------------------------------------------------*/
task write_enable;
begin
if (VERBOSE) $display( $time, " Old Status Register = %b", Status_Reg );
Status_Reg[1] = 1'b1;
// $display( $time, " New Status Register = %b", Status_Reg );
end
endtask // write_enable
/*----------------------------------------------------------------------*/
/* Description: define a write disable task (WRDI) */
/*----------------------------------------------------------------------*/
task write_disable;
begin
if (VERBOSE) $display( $time, " Old Status Register = %b", Status_Reg );
Status_Reg[1] = 1'b0;
if (VERBOSE) $display( $time, " New Status Register = %b", Status_Reg );
end
endtask // write_disable
/*----------------------------------------------------------------------*/
/* Description: define a read id task (RDID) */
/*----------------------------------------------------------------------*/
task read_id;
reg [23:0] Dummy_ID;
integer Dummy_Count;
begin
Dummy_ID = {ID_MXIC, Memory_Type, Memory_Density};
Dummy_Count = 0;
forever begin
@ ( negedge SCLK or posedge CS_INT );
if ( CS_INT == 1'b1 ) begin
disable read_id;
end
else begin
if (ENQUAD) begin
SI_OUT_EN = 1'b1;
WP_OUT_EN = 1'b1;
SIO3_OUT_EN = 1'b1;
end
SO_OUT_EN = 1'b1;
SO_IN_EN = 1'b0;
SI_IN_EN = 1'b0;
WP_IN_EN = 1'b0;
SIO3_IN_EN= 1'b0;
if (ENQUAD)
{SIO3_Reg, SIO2_Reg, SIO1_Reg, SIO0_Reg, Dummy_ID} <= {Dummy_ID, Dummy_ID[23:20]};
else
{SIO1_Reg, Dummy_ID} <= {Dummy_ID, Dummy_ID[23]};
end
end // end forever
end
endtask // read_id
/*----------------------------------------------------------------------*/
/* Description: define a read status task (RDSR) */
/*----------------------------------------------------------------------*/
task read_status;
reg [7:0] Status_Reg_Int;
integer Dummy_Count;
begin
Status_Reg_Int = Status_Reg;
if (ENQUAD) begin
Dummy_Count = 2;
end
else begin
Dummy_Count = 8;
end
forever begin
@ ( negedge SCLK or posedge CS_INT );
if ( CS_INT == 1'b1 ) begin
disable read_status;
end
else begin
if (ENQUAD) begin
SI_OUT_EN = 1'b1;
WP_OUT_EN = 1'b1;
SIO3_OUT_EN = 1'b1;
end
SO_OUT_EN = 1'b1;
SO_IN_EN = 1'b0;
SI_IN_EN = 1'b0;
WP_IN_EN = 1'b0;
SIO3_IN_EN= 1'b0;
if ( Dummy_Count ) begin
Dummy_Count = Dummy_Count - 1;
if (ENQUAD) begin
{SIO3_Reg, SIO2_Reg, SIO1_Reg, SIO0_Reg} <= Dummy_Count ?
Status_Reg_Int[7:4] : Status_Reg_Int[3:0];
end
else begin
SIO1_Reg <= Status_Reg_Int[Dummy_Count];
end
end
else begin
if (ENQUAD) begin
Dummy_Count = 1;
Status_Reg_Int = Status_Reg;
{SIO3_Reg, SIO2_Reg, SIO1_Reg, SIO0_Reg} <= Status_Reg_Int[7:4];
end
else begin
Dummy_Count = 7;
Status_Reg_Int = Status_Reg;
SIO1_Reg <= Status_Reg_Int[Dummy_Count];
end
end
end
end // end forever
end
endtask // read_status
/*----------------------------------------------------------------------*/
/* Description: define a write status task */
/*----------------------------------------------------------------------*/
task write_status;
reg [7:0] Status_Reg_Up;
begin
if (VERBOSE) $display( $time, " Old Status Register = %b", Status_Reg );
Status_Reg_Up = SI_Reg[7:0] ;
tWRSR = tW;
Secur_Reg[5] = 1'b0;
if ( (Status_Reg[7] == 1'b1 && Status_Reg_Up[7] == 1'b0 ) ||
(Status_Reg[6] == 1'b1 && Status_Reg_Up[6] == 1'b0 ) ||
(Status_Reg[5] == 1'b1 && Status_Reg_Up[5] == 1'b0 ) ||
(Status_Reg[4] == 1'b1 && Status_Reg_Up[4] == 1'b0 ) ||
(Status_Reg[3] == 1'b1 && Status_Reg_Up[3] == 1'b0 ) ||
(Status_Reg[2] == 1'b1 && Status_Reg_Up[2] == 1'b0 ))
begin
Secur_Reg[6] = 1'b0;
end
//SRWD:Status Register Write Protect
Status_Reg[0] = 1'b1;
#tWRSR;
Status_Reg[7] = Status_Reg_Up[7];
Status_Reg[6:2] = Status_Reg_Up[6:2];
//WIP : write in process Bit
Status_Reg[0] = 1'b0;
//WEL:Write Enable Latch
Status_Reg[1] = 1'b0;
WRSR_Mode = 1'b0;
end
endtask // write_status
/*----------------------------------------------------------------------*/
/* Description: define a read data task */
/* 03 AD1 AD2 AD3 X */
/*----------------------------------------------------------------------*/
task read_1xio;
integer Dummy_Count, Tmp_Int;
reg [7:0] OUT_Buf;
begin
Dummy_Count = 8;
dummy_cycle(24);
#1;
read_array(Address, OUT_Buf);
forever begin
@ ( negedge SCLK or posedge CS_INT );
if ( CS_INT == 1'b1 ) begin
disable read_1xio;
end
else begin
Read_Mode = 1'b1;
SO_OUT_EN = 1'b1;
SI_IN_EN = 1'b0;
if ( Dummy_Count ) begin
{SIO1_Reg, OUT_Buf} <= {OUT_Buf, OUT_Buf[7]};
Dummy_Count = Dummy_Count - 1;
end
else begin
Address = Address + 1;
load_address(Address);
read_array(Address, OUT_Buf);
{SIO1_Reg, OUT_Buf} <= {OUT_Buf, OUT_Buf[7]};
Dummy_Count = 7 ;
end
end
end // end forever
end
endtask // read_1xio
/*----------------------------------------------------------------------*/
/* Description: define a fast read data task */
/* 0B AD1 AD2 AD3 X */
/*----------------------------------------------------------------------*/
task fastread_1xio;
integer Dummy_Count, Tmp_Int;
reg [7:0] OUT_Buf;
begin
Dummy_Count = 8;
dummy_cycle(32);
read_array(Address, OUT_Buf);
forever begin
@ ( negedge SCLK or posedge CS_INT );
if ( CS_INT == 1'b1 ) begin
disable fastread_1xio;
end
else begin
Read_Mode = 1'b1;
SO_OUT_EN = 1'b1;
SI_IN_EN = 1'b0;
if ( Dummy_Count ) begin
{SIO1_Reg, OUT_Buf} <= {OUT_Buf, OUT_Buf[7]};
Dummy_Count = Dummy_Count - 1;
end
else begin
Address = Address + 1;
load_address(Address);
read_array(Address, OUT_Buf);
{SIO1_Reg, OUT_Buf} <= {OUT_Buf, OUT_Buf[7]};
Dummy_Count = 7 ;
end
end
end // end forever
end
endtask // fastread_1xio
/*----------------------------------------------------------------------*/
/* Description: Execute Write protection select */
/*----------------------------------------------------------------------*/
task write_protection_select;
begin
Secur_Reg [5] = 1'b0;
WR_WPSEL_Mode = 1'b1;
Status_Reg[0] = 1'b1;
#tWPS;
WR_WPSEL_Mode = 1'b0;
Secur_Reg [7] = 1'b1;
Status_Reg[0] = 1'b0;
Status_Reg[1] = 1'b0;
Status_Reg[7] = 1'b0;
end
endtask // write_protection_select
/*----------------------------------------------------------------------*/
/* Description: define a block erase task */
/* 52 AD1 AD2 AD3 */
/*----------------------------------------------------------------------*/
task block_erase_32k;
integer i, i_tmp;
//time ERS_Time;
integer Start_Add;
integer End_Add;
begin
Block = Address[A_MSB:16];
Block2 = Address[A_MSB:15];
Start_Add = (Address[A_MSB:15]<<15) + 16'h0;
End_Add = (Address[A_MSB:15]<<15) + 16'h7fff;
//WIP : write in process Bit
Status_Reg[0] = 1'b1;
Secur_Reg[6] = 1'b0;
if ( write_protect(Address) == 1'b0 &&
!(WPSEL_Mode == 1'b1 && Block[Block_MSB:0] == 0 && ((Address[15]&&SEC_Pro_Reg_BOT[15:8]) || (!Address[15]&&SEC_Pro_Reg_BOT[7:0]))) &&
!(WPSEL_Mode == 1'b1 && Block[Block_MSB:0] == Block_NUM-1 && ((Address[15]&&SEC_Pro_Reg_TOP[15:8]) || (!Address[15]&&SEC_Pro_Reg_TOP[7:0]))) ) begin
for( i = Start_Add; i <= End_Add; i = i + 1 )
begin
ARRAY[i] = 8'hxx;
end
ERS_Time = ERS_Count_BE32K;
fork
er_timer;
begin
for( i = 0; i < ERS_Time; i = i + 1 ) begin
@ ( negedge ERS_CLK or posedge Susp_Trig );
if ( Susp_Trig == 1'b1 ) begin
if( Susp_Ready == 0 ) i = i_tmp;
i_tmp = i;
wait( Resume_Trig );
$display ( $time, " Resume BE32K Erase ..." );
end
end
//#tBE32 ;
for( i = Start_Add; i <= End_Add; i = i + 1 )
begin
ARRAY[i] = 8'hff;
end
disable er_timer;
disable resume_write;
Susp_Ready = 1'b1;
end
join
//WIP : write in process Bit
Status_Reg[0] = 1'b0;//WIP
//WEL : write enable latch
Status_Reg[1] = 1'b0;//WEL
BE_Mode = 1'b0;
BE32K_Mode = 1'b0;
end
else begin
#tERS_CHK;
Secur_Reg[6] = 1'b1;
Status_Reg[0] = 1'b0;//WIP
Status_Reg[1] = 1'b0;//WEL
BE_Mode = 1'b0;
BE32K_Mode = 1'b0;
end
end
endtask // block_erase_32k
/*----------------------------------------------------------------------*/
/* Description: define an suspend task */
/*----------------------------------------------------------------------*/
task suspend_write;
begin
disable resume_write;
Susp_Ready = 1'b1;
if ( Pgm_Mode ) begin
Susp_Trig = 1;
During_Susp_Wait = 1'b1;
#tPSL;
$display ( $time, " Suspend Program ..." );
Secur_Reg[2] = 1'b1;//PSB
Status_Reg[0] = 1'b0;//WIP
Status_Reg[1] = 1'b0;//WEL
WR2Susp = 0;
During_Susp_Wait = 1'b0;
end
else if ( Ers_Mode ) begin
Susp_Trig = 1;
During_Susp_Wait = 1'b1;
#tESL;
$display ( $time, " Suspend Erase ..." );
Secur_Reg[3] = 1'b1;//ESB
Status_Reg[0] = 1'b0;//WIP
Status_Reg[1] = 1'b0;//WEL
WR2Susp = 0;
During_Susp_Wait = 1'b0;
end
end
endtask // suspend_write
/*----------------------------------------------------------------------*/
/* Description: define an resume task */
/*----------------------------------------------------------------------*/
task resume_write;
begin
if ( Pgm_Mode ) begin
Susp_Ready = 1'b0;
Status_Reg[0] = 1'b1;//WIP
Status_Reg[1] = 1'b1;//WEL
Secur_Reg[2] = 1'b0;//PSB
Resume_Trig = 1;
#tPRS;
Susp_Ready = 1'b1;
end
else if ( Ers_Mode ) begin
Susp_Ready = 1'b0;
Status_Reg[0] = 1'b1;//WIP
Status_Reg[1] = 1'b1;//WEL
Secur_Reg[3] = 1'b0;//ESB
Resume_Trig = 1;
#tERS;
Susp_Ready = 1'b1;
end
end
endtask // resume_write
/*----------------------------------------------------------------------*/
/* Description: define a timer to count erase time */
/*----------------------------------------------------------------------*/
task er_timer;
begin
ERS_CLK = 1'b0;
forever
begin
#(Clock*500) ERS_CLK = ~ERS_CLK; // erase timer period is 50us
end
end
endtask // er_timer
/*----------------------------------------------------------------------*/
/* Description: Execute Single Block Lock */
/*----------------------------------------------------------------------*/
task single_block_lock;
reg [A_MSB:0] Address_Int;
reg [Block_MSB:0] Block;
begin
Address_Int = Address;
Block = Address_Int [A_MSB:16];
Status_Reg[0] = 1'b1;
#tWP_SRAM;
if (Block[Block_MSB:0] == 0) begin
SEC_Pro_Reg_BOT[Address_Int[15:12]] = 1'b1;
end
else if (Block[Block_MSB:0] == (Block_NUM-1)) begin
SEC_Pro_Reg_TOP[Address_Int[15:12]] = 1'b1;
end
else
SEC_Pro_Reg[Block] = 1'b1;
Status_Reg[0] = 1'b0;
Status_Reg[1] = 1'b0;
end
endtask // single_block_lock
/*----------------------------------------------------------------------*/
/* Description: Execute Single Block Unlock */
/*----------------------------------------------------------------------*/
task single_block_unlock;
reg [A_MSB:0] Address_Int;
reg [Block_MSB:0] Block;
begin
Address_Int = Address;
Block = Address_Int [A_MSB:16];
Status_Reg[0] = 1'b1;
#tWP_SRAM;
if (Block[Block_MSB:0] == 0) begin
SEC_Pro_Reg_BOT[Address_Int[15:12]] = 1'b0;
end
else if (Block[Block_MSB:0] == (Block_NUM-1)) begin
SEC_Pro_Reg_TOP[Address_Int[15:12]] = 1'b0;
end
else
SEC_Pro_Reg[Block] = 1'b0;
Status_Reg[0] = 1'b0;
Status_Reg[1] = 1'b0;
end
endtask // single_block_unlock
/*----------------------------------------------------------------------*/
/* Description: Execute Chip Lock */
/*----------------------------------------------------------------------*/
task chip_lock;
begin
Status_Reg[0] = 1'b1;
//#(tWP_SRAM*Block_NUM);
#(tWP_SRAM);
SEC_Pro_Reg = ~1'b0;
SEC_Pro_Reg_BOT = ~1'b0;
SEC_Pro_Reg_TOP = ~1'b0;
Status_Reg[0] = 1'b0;
Status_Reg[1] = 1'b0;
end
endtask // chip_lock
/*----------------------------------------------------------------------*/
/* Description: Execute Chip Block Unlock */
/*----------------------------------------------------------------------*/
task chip_unlock;
begin
Status_Reg[0] = 1'b1;
#(tWP_SRAM);
SEC_Pro_Reg = 1'b0;
SEC_Pro_Reg_BOT = 1'b0;
SEC_Pro_Reg_TOP = 1'b0;
Status_Reg[0] = 1'b0;
Status_Reg[1] = 1'b0;
end
endtask // chip_unlock
/*----------------------------------------------------------------------*/
/* Description: Execute Block Lock Protection Read */
/*----------------------------------------------------------------------*/
task sector_protection_read;
reg [Block_MSB:0] Block;
begin
if (ENQUAD) begin
dummy_cycle(6);
end
else begin
dummy_cycle(24);
end
#1;
Block = Address[A_MSB:16];
forever begin
@ ( negedge SCLK or posedge CS_INT );
if ( CS_INT == 1'b1 ) begin
disable sector_protection_read;
end
else begin
if (ENQUAD) begin
SI_OUT_EN = 1'b1;
WP_OUT_EN = 1'b1;
SIO3_OUT_EN = 1'b1;
end
SO_OUT_EN = 1'b1;
SO_IN_EN = 1'b0;
SI_IN_EN = 1'b0;
WP_IN_EN = 1'b0;
SIO3_IN_EN = 1'b0;
if (Block[Block_MSB:0] == 0) begin
{SIO3_Reg,SIO2_Reg,SIO1_Reg,SIO0_Reg} <= {4{SEC_Pro_Reg_BOT[Address[15:12]]}} ;
end
else if (Block[Block_MSB:0] == (Block_NUM-1)) begin
{SIO3_Reg,SIO2_Reg,SIO1_Reg,SIO0_Reg} <= {4{SEC_Pro_Reg_TOP[Address[15:12]]}} ;
end
else
{SIO3_Reg,SIO2_Reg,SIO1_Reg,SIO0_Reg} <= {4{SEC_Pro_Reg[Block]}} ;
end
end // end forever
end
endtask // sector_protection_read
/*----------------------------------------------------------------------*/
/* Description: define a block erase task */
/* D8 AD1 AD2 AD3 */
/*----------------------------------------------------------------------*/
task block_erase;
integer i, i_tmp;
//time ERS_Time;
integer Start_Add;
integer End_Add;
begin
Block = Address[A_MSB:16];
Block2 = Address[A_MSB:15];
Start_Add = (Address[A_MSB:16]<<16) + 16'h0;
End_Add = (Address[A_MSB:16]<<16) + 16'hffff;
//WIP : write in process Bit
Status_Reg[0] = 1'b1;
Secur_Reg[6] = 1'b0;
if ( write_protect(Address) == 1'b0 &&
!(WPSEL_Mode == 1'b1 && Block[Block_MSB:0] == 0 && SEC_Pro_Reg_BOT) &&
!(WPSEL_Mode == 1'b1 && Block[Block_MSB:0] == Block_NUM-1 && SEC_Pro_Reg_TOP) ) begin
for( i = Start_Add; i <= End_Add; i = i + 1 )
begin
ARRAY[i] = 8'hxx;
end
ERS_Time = ERS_Count_BE;
fork
er_timer;
begin
for( i = 0; i < ERS_Time; i = i + 1 ) begin
@ ( negedge ERS_CLK or posedge Susp_Trig );
if ( Susp_Trig == 1'b1 ) begin
if( Susp_Ready == 0 ) i = i_tmp;
i_tmp = i;
wait( Resume_Trig );
$display ( $time, " Resume BE Erase ..." );
end
end
//#tBE ;
for( i = Start_Add; i <= End_Add; i = i + 1 )
begin
ARRAY[i] = 8'hff;
end
disable er_timer;
disable resume_write;
Susp_Ready = 1'b1;
end
join
end
else begin
#tERS_CHK;
Secur_Reg[6] = 1'b1;
end
//WIP : write in process Bit
Status_Reg[0] = 1'b0;//WIP
//WEL : write enable latch
Status_Reg[1] = 1'b0;//WEL
BE_Mode = 1'b0;
BE64K_Mode = 1'b0;
end
endtask // block_erase
/*----------------------------------------------------------------------*/
/* Description: define a sector 4k erase task */
/* 20 AD1 AD2 AD3 */
/*----------------------------------------------------------------------*/
task sector_erase_4k;
integer i, i_tmp;
//time ERS_Time;
integer Start_Add;
integer End_Add;
begin
Sector = Address[A_MSB:12];
Start_Add = (Address[A_MSB:12]<<12) + 12'h000;
End_Add = (Address[A_MSB:12]<<12) + 12'hfff;
//WIP : write in process Bit
Status_Reg[0] = 1'b1;
Secur_Reg[6] = 1'b0;
if ( write_protect(Address) == 1'b0 ) begin
for( i = Start_Add; i <= End_Add; i = i + 1 )
begin
ARRAY[i] = 8'hxx;
end
ERS_Time = ERS_Count_SE;
fork
er_timer;
begin
for( i = 0; i < ERS_Time; i = i + 1 ) begin
@ ( negedge ERS_CLK or posedge Susp_Trig );
if ( Susp_Trig == 1'b1 ) begin
if( Susp_Ready == 0 ) i = i_tmp;
i_tmp = i;
wait( Resume_Trig );
$display ( $time, " Resume SE Erase ..." );
end
end
for( i = Start_Add; i <= End_Add; i = i + 1 )
begin
ARRAY[i] = 8'hff;
end
disable er_timer;
disable resume_write;
Susp_Ready = 1'b1;
end
join
end
else begin
#tERS_CHK;
Secur_Reg[6] = 1'b1;
end
//WIP : write in process Bit
Status_Reg[0] = 1'b0;//WIP
//WEL : write enable latch
Status_Reg[1] = 1'b0;//WEL
SE_4K_Mode = 1'b0;
end
endtask // sector_erase_4k
/*----------------------------------------------------------------------*/
/* Description: define a chip erase task */
/* 60(C7) */
/*----------------------------------------------------------------------*/
task chip_erase;
reg [A_MSB:0] Address_Int;
integer i;
begin
Address_Int = Address;
Status_Reg[0] = 1'b1;
Secur_Reg[6] = 1'b0;
if ( (Dis_CE == 1'b1 && WPSEL_Mode == 1'b0) ||
((SEC_Pro_Reg || SEC_Pro_Reg_BOT || SEC_Pro_Reg_TOP || (WP_B_INT == 1'b0)) && WPSEL_Mode == 1'b1)) begin
#tERS_CHK;
Secur_Reg[6] = 1'b1;
end
else begin
for ( i = 0;i<tCE/100;i = i + 1) begin
#100_000_000;
end
for( i = 0; i <Block_NUM; i = i+1 ) begin
Address_Int = (i<<16) + 16'h0;
Start_Add = (i<<16) + 16'h0;
End_Add = (i<<16) + 16'hffff;
for( j = Start_Add; j <=End_Add; j = j + 1 )
begin
ARRAY[j] = 8'hff;
end
end
end
//WIP : write in process Bit
Status_Reg[0] = 1'b0;//WIP
//WEL : write enable latch
Status_Reg[1] = 1'b0;//WEL
CE_Mode = 1'b0;
end
endtask // chip_erase
/*----------------------------------------------------------------------*/
/* Description: define a page program task */
/* 02 AD1 AD2 AD3 */
/*----------------------------------------------------------------------*/
task page_program;
input [A_MSB:0] Address;
reg [7:0] Offset;
integer Dummy_Count, Tmp_Int, i;
begin
Dummy_Count = Buffer_Num; // page size
Tmp_Int = 0;
Offset = Address[7:0];
/*------------------------------------------------*/
/* Store 256 bytes into a temp buffer - Dummy_A */
/*------------------------------------------------*/
for (i = 0; i < Dummy_Count ; i = i + 1 ) begin
Dummy_A[i] = 8'hff;
end
forever begin
@ ( posedge SCLK or posedge CS_INT );
if ( CS_INT == 1'b1 ) begin
if ( (Tmp_Int % 8 !== 0) || (Tmp_Int == 1'b0) ) begin
PP_4XIO_Mode = 0;
PP_1XIO_Mode = 0;
disable page_program;
end
else begin
tPP_Real = pgm_time_cal(Tmp_Int/8);
if ( Tmp_Int > 8 )
Byte_PGM_Mode = 1'b0;
else
Byte_PGM_Mode = 1'b1;
update_array ( Address );
end
disable page_program;
end
else begin // count how many Bits been shifted
Tmp_Int = ( PP_4XIO_Mode | ENQUAD ) ? Tmp_Int + 4 : Tmp_Int + 1;
if ( Tmp_Int % 8 == 0) begin
#1;
Dummy_A[Offset] = SI_Reg [7:0];
Offset = Offset + 1;
Offset = Offset[7:0];
end
end
end // end forever
end
endtask // page_program
/*----------------------------------------------------------------------*/
/* Description: define a program time calculation function */
/* INPUT: program number */
/*----------------------------------------------------------------------*/
function time pgm_time_cal;
input pgm_num;
integer pgm_num;
time pgm_time_tmp;
begin
pgm_time_tmp = ( 8 + pgm_num * 4 ) * 1000;
if ( pgm_num == 1 ) begin
pgm_time_cal = tBP;
end
else if ( pgm_num >= Buffer_Num || pgm_time_tmp > tPP ) begin
pgm_time_cal = tPP;
end
else begin
pgm_time_cal = pgm_time_tmp;
end
end
endfunction
/*----------------------------------------------------------------------*/
/* Description: define a read electronic ID (RES) */
/* AB X X X */
/*----------------------------------------------------------------------*/
task read_electronic_id;
reg [7:0] Dummy_ID;
begin
if (VERBOSE) $display( $time, " Old DP Mode Register = %b", DP_Mode );
if (ENQUAD) begin
dummy_cycle(5);
end
else begin
dummy_cycle(23);
end
Dummy_ID = ID_Device;
dummy_cycle(1);
forever begin
@ ( negedge SCLK or posedge CS_INT );
if ( CS_INT == 1'b1 ) begin
disable read_electronic_id;
end
else begin
if (ENQUAD) begin
SI_OUT_EN = 1'b1;
WP_OUT_EN = 1'b1;
SIO3_OUT_EN = 1'b1;
end
SO_OUT_EN = 1'b1;
SO_IN_EN = 1'b0;
SI_IN_EN = 1'b0;
WP_IN_EN = 1'b0;
SIO3_IN_EN= 1'b0;
if (ENQUAD) begin
{SIO3_Reg, SIO2_Reg, SIO1_Reg, SIO0_Reg, Dummy_ID} <= {Dummy_ID, Dummy_ID[7:4]};
end
else begin
{SIO1_Reg, Dummy_ID} <= {Dummy_ID, Dummy_ID[7]};
end
end
end // end forever
end
endtask // read_electronic_id
/*----------------------------------------------------------------------*/
/* Description: define a read electronic manufacturer & device ID */
/*----------------------------------------------------------------------*/
task read_electronic_manufacturer_device_id;
reg [15:0] Dummy_ID;
integer Dummy_Count;
begin
dummy_cycle(24);
#1;
if ( Address[0] == 1'b0 ) begin
Dummy_ID = {ID_MXIC,ID_Device};
end
else begin
Dummy_ID = {ID_Device,ID_MXIC};
end
Dummy_Count = 0;
forever begin
@ ( negedge SCLK or posedge CS_INT );
if ( CS_INT == 1'b1 ) begin
disable read_electronic_manufacturer_device_id;
end
else begin
SO_OUT_EN = 1'b1;
SI_IN_EN = 1'b0;
{SIO1_Reg, Dummy_ID} <= {Dummy_ID, Dummy_ID[15]};
end
end // end forever
end
endtask // read_electronic_manufacturer_device_id
/*----------------------------------------------------------------------*/
/* Description: define a program chip task */
/* INPUT:address */
/*----------------------------------------------------------------------*/
task update_array;
input [A_MSB:0] Address;
integer Dummy_Count, i, i_tmp;
integer program_time;
reg [7:0] ori [0:Buffer_Num-1];
begin
Dummy_Count = Buffer_Num;
Address = { Address [A_MSB:8], 8'h0 };
program_time = tPP_Real;
Status_Reg[0]= 1'b1;
Secur_Reg[5] = 1'b0;
if ( write_protect(Address) == 1'b0 && add_in_erase(Address) == 1'b0 ) begin
for ( i = 0; i < Dummy_Count; i = i + 1 ) begin
if ( Secur_Mode == 1'b1) begin
ori[i] = Secur_ARRAY[Address + i];
Secur_ARRAY[Address + i] = Secur_ARRAY[Address + i] & 8'bx;
end
else begin
ori[i] = ARRAY[Address + i];
ARRAY[Address+ i] = ARRAY[Address + i] & 8'bx;
end
end
fork
pg_timer;
begin
for( i = 0; i*2 < program_time; i = i + 1 ) begin
@ ( negedge PGM_CLK or posedge Susp_Trig );
if ( Susp_Trig == 1'b1 ) begin
if( Susp_Ready == 0 ) i = i_tmp;
i_tmp = i;
wait( Resume_Trig );
$display ( $time, " Resume program ..." );
end
end
//#program_time ;
for ( i = 0; i < Dummy_Count; i = i + 1 ) begin
if ( Secur_Mode == 1'b1)
Secur_ARRAY[Address + i] = ori[i] & Dummy_A[i];
else
ARRAY[Address+ i] = ori[i] & Dummy_A[i];
end
disable pg_timer;
disable resume_write;
Susp_Ready = 1'b1;
end
join
end
else begin
#tPGM_CHK ;
Secur_Reg[5] = 1'b1;
end
Status_Reg[0] = 1'b0;
Status_Reg[1] = 1'b0;
PP_4XIO_Mode = 1'b0;
PP_1XIO_Mode = 1'b0;
Byte_PGM_Mode = 1'b0;
end
endtask // update_array
/*----------------------------------------------------------------------*/
/*Description: find out whether the address is selected for erase */
/*----------------------------------------------------------------------*/
function add_in_erase;
input [A_MSB:0] Address;
begin
if( Secur_Mode == 1'b0 ) begin
if (( ERS_Time == ERS_Count_BE32K && Address[A_MSB:15] == Block2 && ESB ) ||
( ERS_Time == ERS_Count_BE && Address[A_MSB:16] == Block && ESB ) ||
( ERS_Time == ERS_Count_SE && Address[A_MSB:12] == Sector && ESB ) ) begin
add_in_erase = 1'b1;
$display ( $time," Failed programing,address is in erase" );
end
else begin
add_in_erase = 1'b0;
end
end
else if( Secur_Mode == 1'b1 ) begin
add_in_erase = 1'b0;
end
end
endfunction // add_in_erase
/*----------------------------------------------------------------------*/
/* Description: define a timer to count program time */
/*----------------------------------------------------------------------*/
task pg_timer;
begin
PGM_CLK = 1'b0;
forever
begin
#1 PGM_CLK = ~PGM_CLK; // program timer period is 2ns
end
end
endtask // pg_timer
/*----------------------------------------------------------------------*/
/* Description: define a enter secured OTP task */
/*----------------------------------------------------------------------*/
task enter_secured_otp;
begin
if (VERBOSE) $display( $time, " Enter secured OTP mode = %b", Secur_Mode );
Secur_Mode= 1;
if (VERBOSE) $display( $time, " New Enter secured OTP mode = %b", Secur_Mode );
end
endtask // enter_secured_otp
/*----------------------------------------------------------------------*/
/* Description: define a exit secured OTP task */
/*----------------------------------------------------------------------*/
task exit_secured_otp;
begin
if (VERBOSE) $display( $time, " Enter secured OTP mode = %b", Secur_Mode );
Secur_Mode = 0;
if (VERBOSE) $display( $time, " New Enter secured OTP mode = %b", Secur_Mode );
end
endtask
/*----------------------------------------------------------------------*/
/* Description: Execute Reading Security Register */
/*----------------------------------------------------------------------*/
task read_Secur_Register;
integer Dummy_Count;
begin
if (ENQUAD) begin
Dummy_Count = 2;
end
else begin
Dummy_Count = 8;
end
forever @ ( negedge SCLK or posedge CS_INT ) begin // output security register info
if ( CS_INT == 1 ) begin
disable read_Secur_Register;
end
else begin
if (ENQUAD) begin
SI_OUT_EN = 1'b1;
WP_OUT_EN = 1'b1;
SIO3_OUT_EN = 1'b1;
end
SO_OUT_EN = 1'b1;
SO_IN_EN = 1'b0;
SI_IN_EN = 1'b0;
WP_IN_EN = 1'b0;
SIO3_IN_EN= 1'b0;
if ( Dummy_Count ) begin
Dummy_Count = Dummy_Count - 1;
if (ENQUAD) begin
{SIO3_Reg, SIO2_Reg, SIO1_Reg, SIO0_Reg} <= Dummy_Count ?
Secur_Reg[7:4] : Secur_Reg[3:0];
end
else begin
SIO1_Reg <= Secur_Reg[Dummy_Count];
end
end
else begin
if (ENQUAD) begin
Dummy_Count = 1;
{SIO3_Reg, SIO2_Reg, SIO1_Reg, SIO0_Reg} <= Secur_Reg[7:4];
end
else begin
Dummy_Count = 7;
SIO1_Reg <= Secur_Reg[Dummy_Count];
end
end
end
end
end
endtask // read_Secur_Register
/*----------------------------------------------------------------------*/
/* Description: Execute Write Security Register */
/*----------------------------------------------------------------------*/
task write_secur_register;
begin
WRSCUR_Mode = 1'b1;
Status_Reg[0] = 1'b1;
#tBP;
WRSCUR_Mode = 1'b0;
Secur_Reg [1] = 1'b1;
Status_Reg[0] = 1'b0;
Status_Reg[1] = 1'b0;
end
endtask // write_secur_register
/*----------------------------------------------------------------------*/
/* Description: Execute 2X IO Read Mode */
/*----------------------------------------------------------------------*/
task read_2xio;
reg [7:0] OUT_Buf;
integer Dummy_Count;
begin
Dummy_Count=4;
SI_IN_EN = 1'b1;
SO_IN_EN = 1'b1;
SI_OUT_EN = 1'b0;
SO_OUT_EN = 1'b0;
dummy_cycle(12);
dummy_cycle(2);
#1;
dummy_cycle(2);
read_array(Address, OUT_Buf);
forever @ ( negedge SCLK or posedge CS_INT ) begin
if ( CS_INT == 1'b1 ) begin
disable read_2xio;
end
else begin
Read_Mode = 1'b1;
SO_OUT_EN = 1'b1;
SI_OUT_EN = 1'b1;
SI_IN_EN = 1'b0;
SO_IN_EN = 1'b0;
if ( Dummy_Count ) begin
{SIO1_Reg, SIO0_Reg, OUT_Buf} <= {OUT_Buf, OUT_Buf[1:0]};
Dummy_Count = Dummy_Count - 1;
end
else begin
Address = Address + 1;
load_address(Address);
read_array(Address, OUT_Buf);
{SIO1_Reg, SIO0_Reg, OUT_Buf} <= {OUT_Buf, OUT_Buf[1:0]};
Dummy_Count = 3 ;
end
end
end//forever
end
endtask // read_2xio
/*----------------------------------------------------------------------*/
/* Description: Execute 4X IO Read Mode */
/*----------------------------------------------------------------------*/
task read_4xio;
//reg [A_MSB:0] Address;
reg [7:0] OUT_Buf ;
integer Dummy_Count;
begin
Dummy_Count = 2;
SI_OUT_EN = 1'b0;
SO_OUT_EN = 1'b0;
WP_OUT_EN = 1'b0;
SIO3_OUT_EN = 1'b0;
SI_IN_EN = 1'b1;
SO_IN_EN = 1'b1;
WP_IN_EN = 1'b1;
SIO3_IN_EN = 1'b1;
dummy_cycle(6); // for address
dummy_cycle(2);
#1;
if ( ((SI_Reg[0] === 1'hz) ||
(SI_Reg[1] === 1'hz) ||
(SI_Reg[2] === 1'hz) ||
(SI_Reg[3] === 1'hz) ||
(SI_Reg[4] === 1'hz) ||
(SI_Reg[5] === 1'hz) ||
(SI_Reg[6] === 1'hz) ||
(SI_Reg[7] === 1'hz) ) &&
(SFDP_Mode !== 1) ) begin
$display("Warning: Hi-impedance is inhibited for the two clock cycles.");
STATE = `BAD_CMD_STATE;
disable read_4xio;
end
else if ((SI_Reg[0] !== SI_Reg[4]) &&
(SI_Reg[1]!= SI_Reg[5]) &&
(SI_Reg[2]!= SI_Reg[6]) &&
(SI_Reg[3]!= SI_Reg[7]) ) begin
Set_4XIO_Enhance_Mode = 1'b1;
end
else begin
Set_4XIO_Enhance_Mode = 1'b0;
end
if ( CMD_BUS == FASTREAD1X || CMD_BUS == W4READ || (!READ4X_Mode && (CMD_BUS == RSTEN || CMD_BUS == RST) && EN4XIO_Read_Mode == 1'b1) )
dummy_cycle(2);
else if ( SFDP_Mode == 1 )
dummy_cycle(6);
else
dummy_cycle(4);
read_array(Address, OUT_Buf);
forever @ ( negedge SCLK or posedge CS_INT ) begin
if ( CS_INT == 1'b1 ) begin
disable read_4xio;
end
else begin
SO_OUT_EN = 1'b1;
SI_OUT_EN = 1'b1;
WP_OUT_EN = 1'b1;
SIO3_OUT_EN = 1'b1;
SO_IN_EN = 1'b0;
SI_IN_EN = 1'b0;
WP_IN_EN = 1'b0;
SIO3_IN_EN = 1'b0;
Read_Mode = 1'b1;
if ( Dummy_Count ) begin
{SIO3_Reg, SIO2_Reg, SIO1_Reg, SIO0_Reg, OUT_Buf} <= {OUT_Buf, OUT_Buf[3:0]};
Dummy_Count = Dummy_Count - 1;
end
else begin
if ( EN_Burst && Burst_Length==8 && Address[2:0]==3'b111 )
Address = {Address[A_MSB:3], 3'b000};
else if ( EN_Burst && Burst_Length==16 && Address[3:0]==4'b1111 )
Address = {Address[A_MSB:4], 4'b0000};
else if ( EN_Burst && Burst_Length==32 && Address[4:0]==5'b1_1111 )
Address = {Address[A_MSB:5], 5'b0_0000};
else if ( EN_Burst && Burst_Length==64 && Address[5:0]==6'b11_1111 )
Address = {Address[A_MSB:6], 6'b00_0000};
else
Address = Address + 1;
load_address(Address);
read_array(Address, OUT_Buf);
{SIO3_Reg, SIO2_Reg, SIO1_Reg, SIO0_Reg, OUT_Buf} <= {OUT_Buf, OUT_Buf[3:0]};
Dummy_Count = 1 ;
end
end
end//forever
end
endtask // read_4xio
/*----------------------------------------------------------------------*/
/* Description: define a fast read dual output data task */
/* 3B AD1 AD2 AD3 X */
/*----------------------------------------------------------------------*/
task fastread_2xio;
integer Dummy_Count;
reg [7:0] OUT_Buf;
begin
Dummy_Count = 4 ;
dummy_cycle(32);
read_array(Address, OUT_Buf);
forever @ ( negedge SCLK or posedge CS_INT ) begin
if ( CS_INT == 1'b1 ) begin
disable fastread_2xio;
end
else begin
Read_Mode= 1'b1;
SO_OUT_EN = 1'b1;
SI_OUT_EN = 1'b1;
SI_IN_EN = 1'b0;
SO_IN_EN = 1'b0;
if ( Dummy_Count ) begin
{SIO1_Reg, SIO0_Reg, OUT_Buf} <= {OUT_Buf, OUT_Buf[1:0]};
Dummy_Count = Dummy_Count - 1;
end
else begin
Address = Address + 1;
load_address(Address);
read_array(Address, OUT_Buf);
{SIO1_Reg, SIO0_Reg, OUT_Buf} <= {OUT_Buf, OUT_Buf[1:0]};
Dummy_Count = 3 ;
end
end
end//forever
end
endtask // fastread_2xio
/*----------------------------------------------------------------------*/
/* Description: define a fast read quad output data task */
/* 6B AD1 AD2 AD3 X */
/*----------------------------------------------------------------------*/
task fastread_4xio;
integer Dummy_Count;
reg [7:0] OUT_Buf;
begin
Dummy_Count = 2 ;
dummy_cycle(32);
read_array(Address, OUT_Buf);
forever @ ( negedge SCLK or posedge CS ) begin
if ( CS == 1'b1 ) begin
disable fastread_4xio;
end
else begin
SI_IN_EN = 1'b0;
SI_OUT_EN = 1'b1;
SO_OUT_EN = 1'b1;
WP_OUT_EN = 1'b1;
SIO3_OUT_EN = 1'b1;
if ( Dummy_Count ) begin
{SIO3_Reg, SIO2_Reg, SIO1_Reg, SIO0_Reg, OUT_Buf} <= {OUT_Buf, OUT_Buf[3:0]};
Dummy_Count = Dummy_Count - 1;
end
else begin
Address = Address + 1;
load_address(Address);
read_array(Address, OUT_Buf);
{SIO3_Reg, SIO2_Reg, SIO1_Reg, SIO0_Reg, OUT_Buf} <= {OUT_Buf, OUT_Buf[3:0]};
Dummy_Count = 1 ;
end
end
end//forever
end
endtask // fastread_4xio
/*----------------------------------------------------------------------*/
/* Description: define read array output task */
/*----------------------------------------------------------------------*/
task read_array;
input [A_MSB:0] Address;
output [7:0] OUT_Buf;
begin
if ( Secur_Mode == 1 ) begin
OUT_Buf = Secur_ARRAY[Address];
end
else if ( SFDP_Mode == 1 ) begin
OUT_Buf = SFDP_ARRAY[Address];
end
else begin
OUT_Buf = ARRAY[Address] ;
end
end
endtask // read_array
/*----------------------------------------------------------------------*/
/* Description: define read array output task */
/*----------------------------------------------------------------------*/
task load_address;
inout [A_MSB:0] Address;
begin
if ( Secur_Mode == 1 ) begin
Address = Address[A_MSB_OTP:0] ;
end
else if ( SFDP_Mode == 1 ) begin
Address = Address[A_MSB_SFDP:0] ;
end
end
endtask // load_address
/*----------------------------------------------------------------------*/
/* Description: define a write_protect area function */
/* INPUT: address */
/*----------------------------------------------------------------------*/
function write_protect;
input [A_MSB:0] Address;
reg [Block_MSB:0] Block;
begin
//protect_define
if( Secur_Mode == 1'b0 ) begin
Block = Address [A_MSB:16];
if ( WPSEL_Mode == 1'b0 ) begin
if (Status_Reg[5:2] == 4'b0000) begin
write_protect = 1'b0;
end
else if (Status_Reg[5:2] == 4'b0001) begin
if (Block[Block_MSB:0] == 63) begin
write_protect = 1'b1;
end
else begin
write_protect = 1'b0;
end
end
else if (Status_Reg[5:2] == 4'b0010) begin
if (Block[Block_MSB:0] >= 62 && Block[Block_MSB:0] <= 63) begin
write_protect = 1'b1;
end
else begin
write_protect = 1'b0;
end
end
else if (Status_Reg[5:2] == 4'b0011) begin
if (Block[Block_MSB:0] >= 60 && Block[Block_MSB:0] <= 63) begin
write_protect = 1'b1;
end
else begin
write_protect = 1'b0;
end
end
else if (Status_Reg[5:2] == 4'b0100) begin
if (Block[Block_MSB:0] >= 56 && Block[Block_MSB:0] <= 63) begin
write_protect = 1'b1;
end
else begin
write_protect = 1'b0;
end
end
else if (Status_Reg[5:2] == 4'b0101) begin
if (Block[Block_MSB:0] >= 48 && Block[Block_MSB:0] <= 63) begin
write_protect = 1'b1;
end
else begin
write_protect = 1'b0;
end
end
else if (Status_Reg[5:2] == 4'b0110) begin
if (Block[Block_MSB:0] >= 32 && Block[Block_MSB:0] <= 63) begin
write_protect = 1'b1;
end
else begin
write_protect = 1'b0;
end
end
else if (Status_Reg[5:2] == 4'b0111) begin
write_protect = 1'b1;
end
else if (Status_Reg[5:2] == 4'b1000) begin
write_protect = 1'b1;
end
else if (Status_Reg[5:2] == 4'b1001) begin
if (Block[Block_MSB:0] >= 0 && Block[Block_MSB:0] <= 31) begin
write_protect = 1'b1;
end
else begin
write_protect = 1'b0;
end
end
else if (Status_Reg[5:2] == 4'b1010) begin
if (Block[Block_MSB:0] >= 0 && Block[Block_MSB:0] <= 47) begin
write_protect = 1'b1;
end
else begin
write_protect = 1'b0;
end
end
else if (Status_Reg[5:2] == 4'b1011) begin
if (Block[Block_MSB:0] >= 0 && Block[Block_MSB:0] <= 55) begin
write_protect = 1'b1;
end
else begin
write_protect = 1'b0;
end
end
else if (Status_Reg[5:2] == 4'b1100) begin
if (Block[Block_MSB:0] >= 0 && Block[Block_MSB:0] <= 59) begin
write_protect = 1'b1;
end
else begin
write_protect = 1'b0;
end
end
else if (Status_Reg[5:2] == 4'b1101) begin
if (Block[Block_MSB:0] >= 0 && Block[Block_MSB:0] <= 61) begin
write_protect = 1'b1;
end
else begin
write_protect = 1'b0;
end
end
else if (Status_Reg[5:2] == 4'b1110) begin
if (Block[Block_MSB:0] >= 0 && Block[Block_MSB:0] <= 62) begin
write_protect = 1'b1;
end
else begin
write_protect = 1'b0;
end
end
else if (Status_Reg[5:2] == 4'b1111) begin
write_protect = 1'b1;
end
end
else begin
if (Block[Block_MSB:0] == 0) begin
if ( SEC_Pro_Reg_BOT[Address[15:12]] == 1'b0 ) begin
write_protect = 1'b0;
end
else begin
write_protect = 1'b1;
end
end
else if (Block[Block_MSB:0] == 63) begin
if ( SEC_Pro_Reg_TOP[Address[15:12]] == 1'b0 ) begin
write_protect = 1'b0;
end
else begin
write_protect = 1'b1;
end
end
else begin
if ( SEC_Pro_Reg[Address[A_MSB:16]] == 1'b0 ) begin
write_protect = 1'b0;
end
else begin
write_protect = 1'b1;
end
end
if( WP_B_INT == 1'b0 )
write_protect = 1'b1;
end
end
else if( Secur_Mode == 1'b1 ) begin
if ( Secur_Reg [1] == 1'b0 && Secur_Reg [0] == 1'b0 ) begin
write_protect = 1'b0;
end
else begin
write_protect = 1'b1;
end
end
end
endfunction // write_protect
// *==============================================================================================
// * AC Timing Check Section
// *==============================================================================================
wire SIO3_EN;
wire WP_EN;
assign SIO3_EN = !Status_Reg[6];
assign WP_EN = !Status_Reg[6] && !ENQUAD && SRWD;
assign Write_SHSL = !Read_SHSL;
wire Read_1XIO_Chk_W;
assign Read_1XIO_Chk_W = Read_1XIO_Chk;
wire Read_2XIO_Chk_W;
assign Read_2XIO_Chk_W = Read_2XIO_Chk;
wire Read_2XIO_Chk_W2;
assign Read_2XIO_Chk_W2 = FastRD_2XIO_Chk;
wire Read_4XIO_Chk_W2;
assign Read_4XIO_Chk_W2 = FastRD_4XIO_Chk;
wire tDP_Chk_W;
assign tDP_Chk_W = tDP_Chk;
wire tRES1_Chk_W;
assign tRES1_Chk_W = tRES1_Chk;
wire tRES2_Chk_W;
assign tRES2_Chk_W = tRES2_Chk;
wire PP_4XIO_Chk_W;
assign PP_4XIO_Chk_W = PP_4XIO_Chk;
wire Read_SHSL_W;
assign Read_SHSL_W = Read_SHSL;
wire SI_IN_EN_W;
assign SI_IN_EN_W = SI_IN_EN;
wire SO_IN_EN_W;
assign SO_IN_EN_W = SO_IN_EN;
wire WP_IN_EN_W;
assign WP_IN_EN_W = WP_IN_EN;
wire SIO3_IN_EN_W;
assign SIO3_IN_EN_W = SIO3_IN_EN;
specify
/*----------------------------------------------------------------------*/
/* Timing Check */
/*----------------------------------------------------------------------*/
$period( posedge SCLK &&& ~CS, tSCLK ); // SCLK _/~ ->_/~
$period( negedge SCLK &&& ~CS, tSCLK ); // SCLK ~\_ ->~\_
$period( posedge SCLK &&& Read_1XIO_Chk_W , tRSCLK ); // SCLK _/~ ->_/~
$period( posedge SCLK &&& Read_2XIO_Chk_W , tTSCLK ); // SCLK _/~ ->_/~
$period( posedge SCLK &&& Read_2XIO_Chk_W2 , tTSCLK2 ); // SCLK _/~ ->_/~
$period( posedge SCLK &&& fQ_104M , tQSCLK ); // SCLK _/~ ->_/~
$period( posedge SCLK &&& fQ_84M , tQSCLK2 ); // SCLK _/~ ->_/~
$period( posedge SCLK &&& Read_4XIO_Chk_W2 , tQSCLK3 ); // SCLK _/~ ->_/~
$width ( posedge CS &&& tDP_Chk_W, tDP ); // CS _/~\_
$width ( posedge CS &&& tRES1_Chk_W, tRES1 ); // CS _/~\_
$width ( posedge CS &&& tRES2_Chk_W, tRES2 ); // CS _/~\_
$width ( posedge SCLK &&& ~CS, tCH ); // SCLK _/~~\_
$width ( negedge SCLK &&& ~CS, tCL ); // SCLK ~\__/~
$width ( posedge SCLK &&& Read_1XIO_Chk_W, tCH_R ); // SCLK _/~~\_
$width ( negedge SCLK &&& Read_1XIO_Chk_W, tCL_R ); // SCLK ~\__/~
$width ( posedge SCLK &&& PP_4XIO_Chk_W, tCH ); // SCLK _/~~\_
$width ( negedge SCLK &&& PP_4XIO_Chk_W, tCL ); // SCLK ~\__/~
$width ( posedge CS &&& Read_SHSL_W, tSHSL_R ); // CS _/~\_
$width ( posedge CS &&& Write_SHSL, tSHSL_W );// CS _/~\_
$setup ( SI &&& ~CS, posedge SCLK &&& SI_IN_EN_W, tDVCH );
$hold ( posedge SCLK &&& SI_IN_EN_W, SI &&& ~CS, tCHDX );
$setup ( SO &&& ~CS, posedge SCLK &&& SO_IN_EN_W, tDVCH );
$hold ( posedge SCLK &&& SO_IN_EN_W, SO &&& ~CS, tCHDX );
$setup ( WP &&& ~CS, posedge SCLK &&& WP_IN_EN_W, tDVCH );
$hold ( posedge SCLK &&& WP_IN_EN_W, WP &&& ~CS, tCHDX );
$setup ( SIO3 &&& ~CS, posedge SCLK &&& SIO3_IN_EN_W, tDVCH );
$hold ( posedge SCLK &&& SIO3_IN_EN_W, SIO3 &&& ~CS, tCHDX );
$setup ( negedge CS, posedge SCLK &&& ~CS, tSLCH );
$hold ( posedge SCLK &&& ~CS, posedge CS, tCHSH );
$setup ( posedge CS, posedge SCLK &&& CS, tSHCH );
$hold ( posedge SCLK &&& CS, negedge CS, tCHSL );
$setup ( posedge WP &&& WP_EN, negedge CS, tWHSL );
$hold ( posedge CS, negedge WP &&& WP_EN, tSHWL );
$width ( negedge RESETB_INT, tRLRH ); // RESET ~\__/~
$setup ( posedge CS, negedge RESETB_INT , tRS );
$hold ( negedge RESETB_INT, posedge CS , tRH );
endspecify
integer AC_Check_File;
// timing check module
initial
begin
AC_Check_File= $fopen ("ac_check.err" );
end
realtime T_CS_P , T_CS_N;
realtime T_WP_P , T_WP_N;
realtime T_SCLK_P , T_SCLK_N;
realtime T_SIO3_P , T_SIO3_N;
realtime T_SI;
realtime T_SO;
realtime T_WP;
realtime T_SIO3;
realtime T_RESET_N, T_RESET_P;
initial
begin
T_CS_P = 0;
T_CS_N = 0;
T_WP_P = 0;
T_WP_N = 0;
T_SCLK_P = 0;
T_SCLK_N = 0;
T_SIO3_P = 0;
T_SIO3_N = 0;
T_SI = 0;
T_SO = 0;
T_WP = 0;
T_SIO3 = 0;
T_RESET_N = 0;
T_RESET_P = 0;
end
always @ ( posedge SCLK ) begin
//tSCLK
if ( $realtime - T_SCLK_P < tSCLK && $realtime > 0 && ~CS )
$fwrite (AC_Check_File, "Clock Frequence for except READ instruction fSCLK =%f Mhz, fSCLK timing violation at %f \n", fSCLK, $realtime );
//fRSCLK
if ( $realtime - T_SCLK_P < tRSCLK && Read_1XIO_Chk && $realtime > 0 && ~CS )
$fwrite (AC_Check_File, "Clock Frequence for READ instruction fRSCLK =%f Mhz, fRSCLK timing violation at %f \n", fRSCLK, $realtime );
//fTSCLK
if ( $realtime - T_SCLK_P < tTSCLK && Read_2XIO_Chk && $realtime > 0 && ~CS )
$fwrite (AC_Check_File, "Clock Frequence for 2XI/O instruction fTSCLK =%f Mhz, fTSCLK timing violation at %f \n", fTSCLK, $realtime );
//fTSCLK2
if ( $realtime - T_SCLK_P < tTSCLK2 && FastRD_2XIO_Chk && $realtime > 0 && ~CS )
$fwrite (AC_Check_File, "Clock Frequence for 2XI/O instruction fTSCLK2 =%f Mhz, fTSCLK2 timing violation at %f \n", fTSCLK2, $realtime );
//fQSCLK
if ( $realtime - T_SCLK_P < tQSCLK && Read_4XIO_Chk && fQ_104M && $realtime > 0 && ~CS )
$fwrite (AC_Check_File, "Clock Frequence for 4XI/O instruction fQSCLK =%f Mhz, fQSCLK timing violation at %f \n", fQSCLK, $realtime );
//fQSCLK2
if ( $realtime - T_SCLK_P < tQSCLK2 && Read_4XIO_Chk && fQ_84M && $realtime > 0 && ~CS )
$fwrite (AC_Check_File, "Clock Frequence for 4XI/O instruction fQSCLK2 =%f Mhz, fQSCLK2 timing violation at %f \n", fQSCLK2, $realtime );
//fQSCLK3
if ( $realtime - T_SCLK_P < tQSCLK3 && FastRD_4XIO_Chk && $realtime > 0 && ~CS )
$fwrite (AC_Check_File, "Clock Frequence for 4XI/O instruction fQSCLK3 =%f Mhz, fQSCLK3 timing violation at %f \n", fQSCLK3, $realtime );
T_SCLK_P = $realtime;
#0;
//tDVCH
if ( T_SCLK_P - T_SI < tDVCH && SI_IN_EN && T_SCLK_P > 0 )
$fwrite (AC_Check_File, "minimum Data SI setup time tDVCH=%f ns, tDVCH timing violation at %f \n", tDVCH, $realtime );
if ( T_SCLK_P - T_SO < tDVCH && SO_IN_EN && T_SCLK_P > 0 )
$fwrite (AC_Check_File, "minimum Data SO setup time tDVCH=%f ns, tDVCH timing violation at %f \n", tDVCH, $realtime );
if ( T_SCLK_P - T_WP < tDVCH && WP_IN_EN && T_SCLK_P > 0 )
$fwrite (AC_Check_File, "minimum Data WP setup time tDVCH=%f ns, tDVCH timing violation at %f \n", tDVCH, $realtime );
if ( T_SCLK_P - T_SIO3 < tDVCH && SIO3_IN_EN && T_SCLK_P > 0 )
$fwrite (AC_Check_File, "minimum Data SIO3 setup time tDVCH=%f ns, tDVCH timing violation at %f \n", tDVCH, $realtime );
//tCL
if ( T_SCLK_P - T_SCLK_N < tCL && ~CS && T_SCLK_P > 0 )
$fwrite (AC_Check_File, "minimum SCLK Low time tCL=%f ns, tCL timing violation at %f \n", tCL, $realtime );
//tCL_R
if ( T_SCLK_P - T_SCLK_N < tCL_R && Read_1XIO_Chk && T_SCLK_P > 0 )
$fwrite (AC_Check_File, "minimum SCLK Low time tCL=%f ns, tCL timing violation at %f \n", tCL_R, $realtime );
if ( T_SCLK_P - T_SCLK_N < tCL && PP_4XIO_Chk && T_SCLK_P > 0 )
$fwrite (AC_Check_File, "minimum SCLK Low time tCL=%f ns, tCL timing violation at %f \n", tCL, $realtime );
#0;
// tSLCH
if ( T_SCLK_P - T_CS_N < tSLCH && T_SCLK_P > 0 )
$fwrite (AC_Check_File, "minimum CS# active setup time tSLCH=%f ns, tSLCH timing violation at %f \n", tSLCH, $realtime );
// tSHCH
if ( T_SCLK_P - T_CS_P < tSHCH && T_SCLK_P > 0 )
$fwrite (AC_Check_File, "minimum CS# not active setup time tSHCH=%f ns, tSHCH timing violation at %f \n", tSHCH, $realtime );
end
always @ ( negedge SCLK ) begin
T_SCLK_N = $realtime;
#0;
//tCH
if ( T_SCLK_N - T_SCLK_P < tCH && ~CS && T_SCLK_N > 0 )
$fwrite (AC_Check_File, "minimum SCLK High time tCH=%f ns, tCH timing violation at %f \n", tCH, $realtime );
//tCH_R
if ( T_SCLK_N - T_SCLK_P < tCH_R && Read_1XIO_Chk && T_SCLK_N > 0 )
$fwrite (AC_Check_File, "minimum SCLK High time tCH=%f ns, tCH timing violation at %f \n", tCH_R, $realtime );
if ( T_SCLK_N - T_SCLK_P < tCH && PP_4XIO_Chk && T_SCLK_N > 0 )
$fwrite (AC_Check_File, "minimum SCLK High time tCH=%f ns, tCH timing violation at %f \n", tCH, $realtime );
end
always @ ( SI ) begin
T_SI = $realtime;
#0;
//tCHDX
if ( T_SI - T_SCLK_P < tCHDX && SI_IN_EN && T_SI > 0 )
$fwrite (AC_Check_File, "minimum Data SI hold time tCHDX=%f ns, tCHDX timing violation at %f \n", tCHDX, $realtime );
end
always @ ( SO ) begin
T_SO = $realtime;
#0;
//tCHDX
if ( T_SO - T_SCLK_P < tCHDX && SO_IN_EN && T_SO > 0 )
$fwrite (AC_Check_File, "minimum Data SO hold time tCHDX=%f ns, tCHDX timing violation at %f \n", tCHDX, $realtime );
end
always @ ( WP ) begin
T_WP = $realtime;
#0;
//tCHDX
if ( T_WP - T_SCLK_P < tCHDX && WP_IN_EN && T_WP > 0 )
$fwrite (AC_Check_File, "minimum Data WP hold time tCHDX=%f ns, tCHDX timing violation at %f \n", tCHDX, $realtime );
end
always @ ( SIO3 ) begin
T_SIO3 = $realtime;
#0;
//tCHDX
if ( T_SIO3 - T_SCLK_P < tCHDX && SIO3_IN_EN && T_SIO3 > 0 )
$fwrite (AC_Check_File, "minimum Data SIO3 hold time tCHDX=%f ns, tCHDX timing violation at %f \n", tCHDX, $realtime );
end
always @ ( posedge CS ) begin
T_CS_P = $realtime;
#0;
// tCHSH
if ( T_CS_P - T_SCLK_P < tCHSH && T_CS_P > 0 )
$fwrite (AC_Check_File, "minimum CS# active hold time tCHSH=%f ns, tCHSH timing violation at %f \n", tCHSH, $realtime );
// tRH
if ( T_CS_P - T_RESET_N < tRH && T_CS_P > 0 )
$fwrite (AC_Check_File, "minimum hold time tRH=%f ns, tRH timing violation at %f \n", tRH, $realtime );
end
always @ ( negedge CS ) begin
T_CS_N = $realtime;
#0;
//tCHSL
if ( T_CS_N - T_SCLK_P < tCHSL && T_CS_N > 0 )
$fwrite (AC_Check_File, "minimum CS# not active hold time tCHSL=%f ns, tCHSL timing violation at %f \n", tCHSL, $realtime );
//tSHSL
if ( T_CS_N - T_CS_P < tSHSL_R && T_CS_N > 0 && Read_SHSL)
$fwrite (AC_Check_File, "minimum CS# deselect time tSHSL_R=%f ns, tSHSL timing violation at %f \n", tSHSL_R, $realtime );
if ( T_CS_N - T_CS_P < tSHSL_W && T_CS_N > 0 && Write_SHSL)
$fwrite (AC_Check_File, "minimum CS# deselect time tSHSL_W=%f ns, tSHSL timing violation at %f \n", tSHSL_W, $realtime );
//tWHSL
if ( T_CS_N - T_WP_P < tWHSL && WP_EN && T_CS_N > 0 )
$fwrite (AC_Check_File, "minimum WP setup time tWHSL=%f ns, tWHSL timing violation at %f \n", tWHSL, $realtime );
//tDP
if ( T_CS_N - T_CS_P < tDP && T_CS_N > 0 && tDP_Chk)
$fwrite (AC_Check_File, "when transit from Standby Mode to Deep-Power Mode, CS# must remain high for at least tDP =%f ns, tDP timing violation at %f \n", tDP, $realtime );
//tRES1/2
if ( T_CS_N - T_CS_P < tRES1 && T_CS_N > 0 && tRES1_Chk)
$fwrite (AC_Check_File, "when transit from Deep-Power Mode to Standby Mode, CS# must remain high for at least tRES1 =%f ns, tRES1 timing violation at %f \n", tRES1, $realtime );
if ( T_CS_N - T_CS_P < tRES2 && T_CS_N > 0 && tRES2_Chk)
$fwrite (AC_Check_File, "when transit from Deep-Power Mode to Standby Mode, CS# must remain high for at least tRES2 =%f ns, tRES2 timing violation at %f \n", tRES2, $realtime );
end
always @ ( posedge WP ) begin
T_WP_P = $realtime;
#0;
end
always @ ( negedge WP ) begin
T_WP_N = $realtime;
#0;
//tSHWL
if ( ((T_WP_N - T_CS_P < tSHWL) || ~CS) && WP_EN && T_WP_N > 0 )
$fwrite (AC_Check_File, "minimum WP hold time tSHWL=%f ns, tSHWL timing violation at %f \n", tSHWL, $realtime );
end
always @ ( negedge RESETB_INT ) begin
T_RESET_N = $realtime;
#0;
//tRS
if ( (T_RESET_N - T_CS_P < tRS) && T_RESET_N > 0 )
$fwrite (AC_Check_File, "minimum setup time tRS=%f ns, tRS timing violation at %f \n", tRS, $realtime );
end
always @ ( posedge RESETB_INT ) begin
T_RESET_P = $realtime;
#0;
//tRLRH
if ( (T_RESET_P - T_RESET_N < tRLRH) && T_RESET_P > 0 )
$fwrite (AC_Check_File, "minimum reset pulse width tRLRH=%f ns, tRLRH timing violation at %f \n", tRLRH, $realtime );
end
endmodule