MIPS/resources/system_top/testbench/MX25L6405D.v
2021-08-23 21:46:36 +08:00

2155 lines
75 KiB
Verilog

// *==============================================================================================
// *
// * MX25L6405D.v - 64M-BIT CMOS Serial Flash Memory
// *
// * COPYRIGHT 2008 Macronix International Co., Ltd.
// *----------------------------------------------------------------------------------------------
// * Environment : Cadence NC-Verilog
// * Reference Doc: MX25L1605D-3205D-6405D REV.1.1,MAY.12, 2008
// * Creation Date: @(#)$Date: 2008/06/13 05:24:15 $
// * Version : @(#)$Revision: 1.4 $
// * Description : There is only one module in this file
// * module MX25L6405D->behavior model for the 64M-Bit flash
// *----------------------------------------------------------------------------------------------
// * Note 1:model can load initial flash data from file when model define parameter Init_File = "xxx";
// * xxx: initial flash data file name;default value xxx = "none", initial flash data is "FF".
// * Note 2:power setup time is tVSL = 200_000 ns, so after power up, chip can be enable.
// * Note 3:time delay to write instruction is tPUW = 10_000_000 ns.
// * Note 4:If define KGD product, Model support good ID read (Addr 0x3f Data 55h).
// * Note 5:If you have any question and suggestion, please send your mail to follow email address :
// * flash_model@mxic.com.tw
// *----------------------------------------------------------------------------------------------
// * History
// * Date | Version Description
// * $Log: MX25L6405D.v,v $
// * Revision 1.4 2008/06/13 05:24:15 simmodel
// * update fTSCLK=50MHz.
// *
// * Revision 1.3 2008/06/12 02:06:42 simmodel
// * disable KGD product define
// *
// * Revision 1.2 2008/03/04 16:32:05 simmodel
// * update DISWRSR
// *
// *==============================================================================================
// *==============================================================================================
// * timescale define
// *==============================================================================================
`timescale 1ns / 100ps
// *==============================================================================================
// * product parameter define
// *==============================================================================================
/*----------------------------------------------------------------------*/
/* Define controller STATE */
/*----------------------------------------------------------------------*/
`define STANDBY_STATE 0
`define ACTION_STATE 1
`define CMD_STATE 2
`define BAD_CMD_STATE 3
`define MX25L6405D
// `define MX25L6405D
// `define MX25L6415D
`ifdef MX25L6405D
`define PADOP1 1'b0
`endif
`ifdef MX25L6415D
`define PADOP1 1'b1
`endif
`define KGD_PRODUCT 1'b0
module MX25L6405D( SCLK,
CS,
SI,
SO,
WP,
HOLD );
// *==============================================================================================
// * 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
input WP; // Hardware write protection
input HOLD; // Pause the chip without diselecting the chip
// *==============================================================================================
// * Declaration of parameter (parameter)
// *==============================================================================================
/*----------------------------------------------------------------------*/
/* Density STATE parameter */
/*----------------------------------------------------------------------*/
parameter A_MSB = 22,
TOP_Add = 23'h7fffff,
Secur_TOP_Add = 7'h7f,
Sector_MSB = 10,
Block_MSB = 6,
Block_NUM = 128,
PRO_128K_Beg = 23'h7d0000,
PRO_128K_End = 23'h7effff;
/*----------------------------------------------------------------------*/
/* Define ID Parameter */
/*----------------------------------------------------------------------*/
parameter ID_MXIC = 8'hc2,
ID_Device = `PADOP1? 8'h1e : 8'h16,
Memory_Type = `PADOP1? 8'h22 : 8'h20,
Memory_Density = 8'h17;
/*----------------------------------------------------------------------*/
/* Define Initial Memory File Name */
/*----------------------------------------------------------------------*/
parameter Init_File = "none"; // initial flash data
/*----------------------------------------------------------------------*/
/* AC Charicters Parameter */
/*----------------------------------------------------------------------*/
parameter tSHQZ = 8, // CS High to SO Float Time [ns]
tCLQV = 8, // Clock Low to Output Valid
tHHQX = 8, // HOLD to Output Low-z
tHLQZ = 8, // HOLD to Output High-z
tDP = 10_000,
tRES1 = 8_800,
tRES2 = 8_800;
parameter tREP0 = 100, // 100ns Reset# recovery time (during read algorithm)
// to read or write
tREP1 = 50_000; // 50us Reset# recovery time (during program/erase algorithm)
// to read or write
//tOHZ = 10, // 10ns PR# goes high and SCLK falling to data out
//tRD = 10; // 10ns PR# goes high and SCLK falling to data out
parameter tAA = 50; // 50ns Parallel mode read time
parameter tBP = 9_000; // Byte program time
parameter tSE = 90_000_000, // Sector erase time
tBE = 700_000_000, // Block erase time
tCE = 50_000, // unit is ms instead of ns
tPP = 1_400_000, // Program time
tW = 40_000_000, // Write Status time
tPUW = 10_000_000, // Time delay to write instruction
tVSL = 20; // Time delay to chip select allowed
//smh tVSL = 200_000; // Time delay to chip select allowed
specify
specparam tSCLK = 12, // Clock Cycle Time [ns]
fSCLK = 86, // Clock Frequence except READ instruction[ns] 15pF
tRSCLK = 30, // Clock Cycle Time for READ instruction[ns] 15pF
fRSCLK = 33, // Clock Frequence for READ instruction[ns] 15pF
tCH = 5.5, // Clock High Time (min) [ns]
tCL = 5.5, // 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 = 100, // CS High Time (min) [ns]
tDVCH = 2, // SI Setup Time (min) [ns]
tCHDX = 5, // SI Hold Time (min) [ns]
tCHSH = 5, // CS# Active Hold Time (relative to SCLK) (min) [ns]
tSHCH = 5, // CS# Not Active Setup Time (relative to SCLK) (min) [ns]
tHLCH = 5, // HOLD# Setup Time (relative to SCLK) (min) [ns]
tCHHH = 5, // HOLD# Hold Time (relative to SCLK) (min) [ns]
tHHCH = 5, // HOLD Setup Time (relative to SCLK) (min) [ns]
tCHHL = 5, // HOLD Hold Time (relative to SCLK) (min) [ns]
tWHSL = 20, // Write Protection Setup Time
tSHWL = 100, // Write Protection Hold Time
tCLHS = 3, // Clock Low to HOLD# setup time
tCLHH = 3; // Clock Low to HOLD# hold time
specparam tTSCLK = 20, // Clock Cycle Time for 2XI/O READ instruction[ns] 15pF
fTSCLK = 50; // Clock Frequence for 2XI/O READ instruction[ns] 15pF
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
CE1 = 8'h60, // ChipErase
CE2 = 8'hc7, // ChipErase
PP = 8'h02, // PageProgram
DP = 8'hb9, // DeepPowerDown
RDP = 8'hab, // ReleaseFromDeepPowerDwon
RES = 8'hab, // ReadElectricID
REMS = 8'h90; // ReadElectricManufacturerDeviceID
parameter RDPR = 8'ha1, // Read parameter register
WRPR = 8'hf1; // Write parameter register
parameter BE = 8'hd8, // BlockErase
READ2X = 8'hbb, // 2X Read
CP = 8'had, // Continuously program mode;
REMS2 = 8'hef, // ReadElectricManufacturerDeviceID
ENSO = 8'hb1, // Enter secured OTP;
EXSO = 8'hc1, // Exit secured OTP;
RDSCUR = 8'h2b, // Read security register;
WDSCUR = 8'h2f, // Write security register;
WRLB = 8'h21, // Write read-lock register;
ESRY = 8'h70, // Enable SO to output RY/BY;
DSRY = 8'h80; // Disable SO to output RY/BY;
/*----------------------------------------------------------------------*/
/* Declaration of internal-register (reg) */
/*----------------------------------------------------------------------*/
reg [7:0] ARRAY[0:TOP_Add]; // memory array
reg [7:0] Status_Reg; // Status Register
reg [7:0] CMD_BUS;
reg [6:0] PO_Reg;
reg [6:0] Latch_PO;
reg Latch_SO;
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 [2:0] STATE;
reg EN_S0; //EN_S0 fSCLK Serial AC Characteristics;
reg EN_P0; //EN_P0 fSCLK parallel AC Characteristics;
reg EN_S1; //EN_S1 fRSCLK Serial AC Characteristics;
reg EN_P1; //EN_P1 fRSCLK parallel AC Characteristics;
reg SIO1_Reg;
reg Write_EN;
reg Read_EN;
reg P_Mode; // parallel mode
reg DP_Mode; // deep power down mode
reg Read_Mode;
reg Read_1XIO_Mode;
reg Read_1XIO_Chk;
reg FastRD_1XIO_Mode;
reg PP_1XIO_Mode;
reg SE_4K_Mode;
reg BE_Mode;
reg CE_Mode;
reg WRSR_Mode;
reg RES_Mode;
reg REMS_Mode;
reg SCLK_EN;
reg HOLD_OUT_B;
reg SO_OUT_EN; // for SO
reg SI_IN_EN; // for SI
wire HOLD_B_INT;
wire WP_B_INT;
wire ISCLK;
wire WIP;
wire WEL;
wire SRWD;
wire Dis_CE, Dis_WRSR;
event WRSR_Event;
event BE_Event;
event SE_4K_Event;
event CE_Event;
event PP_Event;
event RDP_Event;
event DP_Event;
integer i;
integer j;
integer Bit;
integer Bit_Tmp;
integer Start_Add;
integer End_Add;
integer Page_Size;
time tRES;
reg [7:0] Param_Reg; // Parameter register
wire RESET_B;
reg [7:0] Secur_ARRAY[0:Secur_TOP_Add]; // Secured OTP
reg [7:0] Secur_Reg; // security register
reg [15:0] CP_Data;
reg Secur_Mode; // enter secured mode
reg CP_ESRY_Mode;
reg EN_CP_Mode;
reg CP_Mode;
reg Read_2XIO_Mode;
reg Read_2XIO_Chk;
reg SE_1K_Mode;
reg Byte_PGM_Mode; //Program one byte is 7us
reg SI_OUT_EN; // for SI
reg SO_IN_EN; // for SO
reg SIO0_Reg;
wire CP_Busy;
event CP_Event;
event WRSCUR_Event;
event SE_1K_Event;
/*----------------------------------------------------------------------*/
/* initial variable value */
/*----------------------------------------------------------------------*/
initial begin
reset_sm;
Secur_Reg = 8'b0000_0000;
end
task reset_sm;
begin
Status_Reg = 8'b0000_0000;
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;
Page_Size = 256;
DP_Mode = 1'b0;
P_Mode = 1'b0;
Write_EN = 1'b0;
Read_EN = 1'b0;
SCLK_EN = 1'b1;
Read_Mode = 1'b0;
Read_1XIO_Mode = 1'b0;
Read_1XIO_Chk = 1'b0;
PP_1XIO_Mode = 1'b0;
SE_4K_Mode = 1'b0;
BE_Mode = 1'b0;
CE_Mode = 1'b0;
WRSR_Mode = 1'b0;
RES_Mode = 1'b0;
REMS_Mode = 1'b0;
FastRD_1XIO_Mode = 1'b0;
HOLD_OUT_B = 1'b1;
{EN_S0, EN_P0, EN_S1, EN_P1} = {1'b1, 1'b0, 1'b0, 1'b0};
Param_Reg = 8'b0000_0000;
SI_OUT_EN = 1'b0; // SI output enable
SO_IN_EN = 1'b0; // SO input enable
CP_Data = 8'b0000_0000;
Secur_Mode = 1'b0;
CP_ESRY_Mode = 1'b0;
EN_CP_Mode = 1'b0;
CP_Mode = 1'b0;
Read_2XIO_Mode = 1'b0;
Read_2XIO_Chk = 1'b0;
SE_1K_Mode = 1'b0;
Byte_PGM_Mode = 1'b0;
Secur_Reg[3:2] = 2'b00;
end
endtask // reset_sm
/*----------------------------------------------------------------------*/
/* initial flash data */
/*----------------------------------------------------------------------*/
//MX25L6405D #(.Init_File(`APP_FLASH))
initial
begin : memory_initialize
for ( i = 0; i <= TOP_Add; i = i + 1 )
ARRAY[i] = 8'hff;
if ( Init_File != "none" ) begin
$readmemh(Init_File,ARRAY) ;
$display("load Init_File %s, array[0..3]=%h %h %h %h", Init_File,
ARRAY[0],ARRAY[1],ARRAY[2],ARRAY[3]);
end
for( i = 0; i <= Secur_TOP_Add; i = i + 1 ) begin
Secur_ARRAY[i]=8'hff;
end
if ( `KGD_PRODUCT == 1'b1 ) begin
Secur_ARRAY[8'h3f]=8'h55;
end
end
// *==============================================================================================
// * Input/Output bus opearation
// *==============================================================================================
assign ISCLK = (SCLK_EN == 1'b1) ? SCLK:1'b0;
assign HOLD_B_INT = (CS == 1'b0 && `PADOP1 == 1'b0 ) ? HOLD : 1'b1;
assign RESET_B = `PADOP1 == 1'b1 ? HOLD : 1'b1;
assign WP_B_INT = (CS == 1'b0 ) ? WP : 1'b1;
assign SO = (SO_OUT_EN && HOLD_OUT_B) ? SIO1_Reg : 1'bz ;
assign SI = (SI_OUT_EN && HOLD_OUT_B) ? SIO0_Reg : 1'bz ;
/*----------------------------------------------------------------------*/
/* When CP_mode, Enable SO to output RY/BY; */
/*----------------------------------------------------------------------*/
assign CP_Busy = !(EN_CP_Mode && Status_Reg[0]);
always @ ( negedge CS or CP_Busy or ISCLK ) begin
if ( (EN_CP_Mode == 1) && (CS == 0) && (CP_ESRY_Mode == 1'b1) ) begin
SIO1_Reg <= #tCLQV CP_Busy;
SO_OUT_EN = 1'b1;
end
end
/*----------------------------------------------------------------------*/
/* When Hold Condtion Operation; */
/*----------------------------------------------------------------------*/
always @ ( HOLD_B_INT or negedge SCLK) begin
if ( HOLD_B_INT == 1'b0 && SCLK == 1'b0) begin
SCLK_EN =1'b0;
HOLD_OUT_B<= #tHLQZ 1'b0;
end
else if ( HOLD_B_INT == 1'b1 && SCLK == 1'b0) begin
SCLK_EN =1'b1;
HOLD_OUT_B<= #tHHQX 1'b1;
end
end
/*----------------------------------------------------------------------*/
/* When Reset Condtion Operation; */
/*----------------------------------------------------------------------*/
always @ ( RESET_B ) begin
if ( RESET_B == 1'b0 ) begin
disable write_status;
disable block_erase;
disable sector_erase_4k;
disable sector_erase_1k;
disable chip_erase;
disable page_program_mode;
disable cp_program;
disable write_secur_register;
disable deep_power_down;
disable release_from_deep_power_down;
disable read_1xio;
disable read_2xio;
disable fastread_1xio;
disable read_electronic_id;
disable read_electronic_manufacturer_device_id;
disable read_function;
disable dummy_cycle;
SO_OUT_EN <=#tSHQZ 1'b0;
SI_OUT_EN <=#tSHQZ 1'b0;
end
else begin
if ( Status_Reg[0] == 1'b1 )
STATE <= #tREP1 `STANDBY_STATE;
else
STATE <= #tREP0 `STANDBY_STATE;
reset_sm;
end
end
/*----------------------------------------------------------------------*/
/* When Secur_Mode, Page_Size 256-->64 */
/*----------------------------------------------------------------------*/
always @ ( Secur_Mode ) begin
Page_Size = (Secur_Mode == 1) ? 64 : 256;
end
// *==============================================================================================
// * Finite State machine to control Flash operation
// *==============================================================================================
/*----------------------------------------------------------------------*/
/* power on */
/*----------------------------------------------------------------------*/
initial begin
Write_EN <= #tPUW 1'b1;// Time delay to write instruction
Read_EN <= #tVSL 1'b1;// Time delay to chip select allowed
end
/*----------------------------------------------------------------------*/
/* Command Decode */
/*----------------------------------------------------------------------*/
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 Dis_WRSR = (WP_B_INT == 1'b0 && Status_Reg[7] == 1'b1) || (Secur_Reg[3] == 1'b1) || Secur_Mode;
always @ ( negedge CS ) begin
SI_IN_EN = 1'b1;
end
always @ ( posedge ISCLK or posedge CS ) begin
#0;
if ( CS == 1'b0 ) begin
Bit_Tmp = Bit_Tmp + 1;
Bit = Bit_Tmp - 1;
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
end
if ( Bit == 7 && CS == 1'b0 ) begin
STATE = `CMD_STATE;
CMD_BUS = SI_Reg[7:0];
//$display( $time,"SI_Reg[7:0]= %h ", SI_Reg[7:0] );
end
case ( STATE )
`STANDBY_STATE:
begin
end
`CMD_STATE:
begin
case ( CMD_BUS )
WREN:
begin
if ( !DP_Mode && !EN_CP_Mode && !WIP && Write_EN ) begin
if ( CS == 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 && Read_EN ) begin
if ( CS == 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 && !EN_CP_Mode && !WIP && Read_EN) begin
//$display( $time, " Enter Read ID Function ..." );
read_id;
end
else if ( Bit == 7 )
STATE <= `BAD_CMD_STATE;
end
RDSR:
begin
if ( !DP_Mode && (EN_CP_Mode && CP_ESRY_Mode) == 1'b0 && Read_EN) begin
//$display( $time, " Enter Read Status Function ..." );
read_status ;
end
else if ( Bit == 7 )
STATE <= `BAD_CMD_STATE;
end
WRSR:
begin
if ( !DP_Mode && !EN_CP_Mode && !WIP && WEL && Write_EN ) begin
if ( CS == 1'b1 && Bit == 15 && !Dis_WRSR ) begin
//$display( $time, " Enter Write Status Function ..." );
->WRSR_Event;
WRSR_Mode = 1'b1;
end
else if ( CS == 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 && !EN_CP_Mode && !WIP && Read_EN ) begin
//$display( $time, " Enter Read Data Function ..." );
if ( Bit == 31 ) begin
Address = (Secur_Mode == 1) ? SI_Reg[5:0] : SI_Reg[A_MSB:0];
end
Read_1XIO_Mode = 1'b1;
end
else if ( Bit == 7 )
STATE <= `BAD_CMD_STATE;
end
FASTREAD1X:
begin
if ( !DP_Mode && !EN_CP_Mode && !WIP && Read_EN ) begin
//$display( $time, " Enter Fast Read Data Function ..." );
if ( Bit == 31 ) begin
Address = (Secur_Mode == 1) ? SI_Reg[5:0] : SI_Reg[A_MSB:0];
end
FastRD_1XIO_Mode = 1'b1;
end
else if ( Bit == 7 )
STATE <= `BAD_CMD_STATE;
end
SE:
begin
if ( !DP_Mode && !EN_CP_Mode && !WIP && WEL && !Secur_Mode && Write_EN ) begin
if ( Bit == 31 ) begin
Address = SI_Reg[A_MSB:0];
end
if ( CS == 1'b1 && Bit == 31 && write_protect(Address) == 1'b0 ) begin
//$display( $time, " Enter Sector Erase Function ..." );
if ( (Param_Reg[0] == 1) && (Address[A_MSB:12] == 0) ) begin
->SE_1K_Event;
SE_1K_Mode = 1'b1;
end
else begin
->SE_4K_Event;
SE_4K_Mode = 1'b1;
end
end
else if ( CS == 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 && !EN_CP_Mode && !WIP && WEL && !Secur_Mode && Write_EN ) begin
if ( Bit == 31 ) begin
Address = SI_Reg[A_MSB:0] ;
end
if ( CS == 1'b1 && Bit == 31 && write_protect(Address) == 1'b0 ) begin
//$display( $time, " Enter Block Erase Function ..." );
->BE_Event;
BE_Mode = 1'b1;
end
else if ( CS == 1'b1 && Bit < 31 || Bit > 31 )
STATE <= `BAD_CMD_STATE;
end
else if ( Bit == 7 )
STATE <= `BAD_CMD_STATE;
end
CE1, CE2:
begin
if ( !DP_Mode && !EN_CP_Mode && !WIP && WEL && !Secur_Mode && Write_EN ) begin
if ( CS == 1'b1 && Bit == 7 && Dis_CE == 0 ) begin
//$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 && !EN_CP_Mode && !WIP && WEL && Write_EN ) begin
if ( Bit == 31 ) begin
Address = (Secur_Mode == 1) ? SI_Reg[5:0] : SI_Reg[A_MSB:0];
end
if ( Bit == 31 && (((write_protect(Address) == 1'b0) && (!Secur_Mode)) ||
(Secur_Mode && (!(Secur_Reg[1] || Secur_Reg[0])))) ) begin
//$display( $time, " Enter Page Program Function ..." );
->PP_Event;
PP_1XIO_Mode = 1'b1;
end
else if ( CS == 1 && (Bit < 31 || ((Bit + 1) % 8 !== 0)))
STATE <= `BAD_CMD_STATE;
end
else if ( Bit == 7 )
STATE <= `BAD_CMD_STATE;
end
DP:
begin
if ( !WIP && !EN_CP_Mode && Read_EN ) begin
if ( CS == 1'b1 && Bit == 7 ) begin
//$display( $time, " Enter Deep Power Dwon Function ..." );
->DP_Event;
end
else if ( Bit > 7 )
STATE <= `BAD_CMD_STATE;
end
else if ( Bit == 7 )
STATE <= `BAD_CMD_STATE;
end
RDP, RES:
begin
if ( !WIP && !EN_CP_Mode && Read_EN ) begin
// $display( $time, " Enter Release from Deep Power Dwon Function ..." );
RES_Mode = 1'b1;
if ( CS == 1'b1 ) begin
if ( Bit >= 38 ) begin
tRES = tRES2;
end
else begin
tRES = tRES1;
end
->RDP_Event;
end
end
else if ( Bit == 7 )
STATE <= `BAD_CMD_STATE;
end
REMS, REMS2:
begin
if ( !DP_Mode && !EN_CP_Mode && !WIP && Read_EN ) begin
if ( Bit == 31 ) begin
Address = SI_Reg[A_MSB:0] ;
end
//$display( $time, " Enter Read Electronic Manufacturer & ID Function ..." );
REMS_Mode = 1'b1;
end
else if ( Bit == 7 )
STATE <= `BAD_CMD_STATE;
end
WRPR:
begin
if ( !DP_Mode && !EN_CP_Mode && !WIP && WEL && Write_EN ) begin
if ( CS == 1'b1 && Bit == 15 ) begin
//$display( $time, " Enter Write Parameter Register Function ..." );
write_parameter;
end
else if ( CS == 1'b1 && Bit < 15 || Bit > 15 )
STATE <= `BAD_CMD_STATE;
end
else if ( Bit == 7 )
STATE <= `BAD_CMD_STATE;
end
RDPR:
begin
if ( !DP_Mode && (EN_CP_Mode && CP_ESRY_Mode) == 1'b0 && Read_EN) begin
//$display( $time, " Enter READ Parameter Register Function ..." );
read_parameter;
end
else if ( Bit == 7 )
STATE <= `BAD_CMD_STATE;
end
READ2X:
begin
if ( !DP_Mode && !EN_CP_Mode && !WIP && Read_EN ) begin
//$display( $time, " Enter READX2 Function ..." );
if ( Bit == 19 ) begin
Address = (Secur_Mode == 1) ? SI_Reg[5:0] : SI_Reg[A_MSB:0];
end
Read_2XIO_Mode = 1'b1;
end
else if ( Bit == 7 )
STATE <= `BAD_CMD_STATE;
end
CP:
begin
if ( !DP_Mode && !WIP && WEL && Write_EN ) begin
if ( EN_CP_Mode == 1'b0 && Bit == 31 ) begin
Address = (Secur_Mode == 1) ? SI_Reg[5:0] : SI_Reg[A_MSB:0];
Address = {Address [A_MSB:1], 1'b0} ;
end
if ( ((EN_CP_Mode == 1'b0 && Bit == 47) || (EN_CP_Mode == 1'b1 && Bit == 23)) &&
(( (write_protect(Address) == 1'b0 && (!Secur_Mode)) ||
(Secur_Mode && (!(Secur_Reg[1] || Secur_Reg[0]))))) ) begin
//$display( $time, " Enter CP Mode Function ..." );
->CP_Event;
end
else if ( CS == 1'b1 && ((EN_CP_Mode == 1'b0 && Bit < 47) ||
(EN_CP_Mode == 1'b1 && Bit < 23) || ((Bit + 1) % 8 !== 0)))
STATE <= `BAD_CMD_STATE;
end
else if ( Bit == 7 )
STATE <= `BAD_CMD_STATE;
end
WRLB:
begin
if ( !DP_Mode && !EN_CP_Mode && !WIP && WEL && `PADOP1 && Read_EN ) begin
if ( CS == 1'b1 && Bit == 15 ) begin
//$display( $time, " Enter WRLB Function ..." );
write_lkbit;
end
else if ( CS == 1'b1 && Bit < 15 || Bit >15)
STATE <= `BAD_CMD_STATE;
end
else if ( Bit == 7 )
STATE <= `BAD_CMD_STATE;
end
ENSO:
begin
if ( !DP_Mode && !EN_CP_Mode && !WIP && Read_EN ) begin
if ( CS == 1'b1 && Bit == 7 ) begin
//$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 && !EN_CP_Mode && !WIP && Read_EN ) begin
if ( CS == 1'b1 && Bit == 7 ) begin
//$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 && (EN_CP_Mode && CP_ESRY_Mode) == 1'b0 && Read_EN) begin
// $display( $time, " Enter Read Secur_Register Function ..." );
read_Secur_Register;
end
else if ( Bit == 7 )
STATE <= `BAD_CMD_STATE;
end
WDSCUR:
begin
if ( !DP_Mode && !EN_CP_Mode && !WIP && !Secur_Mode && Write_EN ) begin
if ( CS == 1'b1 && Bit == 7 ) begin
//$display( $time, " Enter WDSCUR Secur_Register Function ..." );
->WRSCUR_Event;
end
else if ( Bit > 7 )
STATE <= `BAD_CMD_STATE;
end
else if ( Bit == 7 )
STATE <= `BAD_CMD_STATE;
end
ESRY:
begin
if ( !DP_Mode && !EN_CP_Mode && !WIP && Read_EN ) begin
if ( CS == 1'b1 && Bit == 7 ) begin
//$display( $time, " Enter ESRY Function ..." );
read_ryby;
end
else if ( Bit > 7 )
STATE <= `BAD_CMD_STATE;
end
else if ( Bit == 7 )
STATE <= `BAD_CMD_STATE;
end
DSRY:
begin
if ( !DP_Mode && !EN_CP_Mode && !WIP && Read_EN ) begin
if ( CS == 1'b1 && Bit == 7 ) begin
//$display( $time, " Enter DSRY Function ..." );
disread_ryby;
end
else if ( Bit > 7 )
STATE <= `BAD_CMD_STATE;
end
else if ( Bit == 7 )
STATE <= `BAD_CMD_STATE;
end
default:
begin
STATE <= `BAD_CMD_STATE;
end
endcase
end
`BAD_CMD_STATE:
begin
end
default:
begin
STATE = `STANDBY_STATE;
end
endcase
if ( CS == 1'b1 ) begin
Bit = 1'b0;
Bit_Tmp = 1'b0;
SO_IN_EN = 1'b0;
SI_IN_EN = 1'b0;
SO_OUT_EN <= #tSHQZ 1'b0;
SI_OUT_EN <= #tSHQZ 1'b0;
Read_Mode = 1'b0;
RES_Mode = 1'b0;
REMS_Mode = 1'b0;
Read_1XIO_Mode = 1'b0;
Read_2XIO_Mode = 1'b0;
Read_1XIO_Chk = 1'b0;
Read_2XIO_Chk = 1'b0;
FastRD_1XIO_Mode = 1'b0;
STATE <= #1 `STANDBY_STATE;
SIO0_Reg <= #tSHQZ 1'bx;
SIO1_Reg <= #tSHQZ 1'bx;
PO_Reg[6:0] <= #tSHQZ 7'bx;
#1;
disable read_1xio;
disable read_2xio;
disable fastread_1xio;
disable read_electronic_id;
disable read_electronic_manufacturer_device_id;
disable read_function;
disable dummy_cycle;
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
) begin:read_function
wait ( ISCLK == 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 ( 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
end
always @ ( WRSR_Event ) begin
write_status;
end
always @ ( RDP_Event ) begin
disable deep_power_down;
release_from_deep_power_down;
end
always @ ( DP_Event ) begin
deep_power_down;
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 @ ( CP_Event ) begin
cp_program;
end
always @ ( WRSCUR_Event ) begin
write_secur_register;
end
always @ ( SE_1K_Event ) begin
sector_erase_1k;
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 ISCLK );
end
end
endtask // dummy_cycle
/*----------------------------------------------------------------------*/
/* Description: define a write enable task */
/*----------------------------------------------------------------------*/
task write_enable;
begin
//$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
//$display( $time, " Old Status Register = %b", Status_Reg );
Status_Reg[1] = 1'b0;
EN_CP_Mode = 1'b0;
Status_Reg[6] = 1'b0;
//$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 ISCLK or posedge CS );
if ( CS == 1'b1 ) begin
disable read_id;
end
else begin
SO_OUT_EN = 1'b1;
if ( P_Mode == 1'b0 ) begin // check parallel mode (2)
{SIO1_Reg, Dummy_ID} <= #tCLQV {Dummy_ID, Dummy_ID[23]};
end
else begin
if ( Dummy_Count == 0 ) begin
{SIO1_Reg,PO_Reg} <= #tAA ID_MXIC;
Dummy_Count = 1;
end
else if ( Dummy_Count == 1 ) begin
{SIO1_Reg,PO_Reg} <= #tAA Memory_Type;
Dummy_Count = 2;
end
else if ( Dummy_Count == 2 ) begin
{SIO1_Reg,PO_Reg} <= #tAA Memory_Density;
Dummy_Count = 0;
end
end
end
end // end forever
end
endtask // read_id
/*----------------------------------------------------------------------*/
/* Description: define a read status task (RDSR) */
/*----------------------------------------------------------------------*/
task read_status;
integer Dummy_Count;
begin
Dummy_Count = 8;
forever begin
@ ( negedge ISCLK or posedge CS );
if ( CS == 1'b1 ) begin
disable read_status;
end
else begin
SO_OUT_EN = 1'b1;
if ( P_Mode == 1'b0 ) begin
if ( Dummy_Count ) begin
Dummy_Count = Dummy_Count - 1;
SIO1_Reg <= #tCLQV Status_Reg[Dummy_Count];
end
else begin
Dummy_Count = 7;
SIO1_Reg <= #tCLQV Status_Reg[Dummy_Count];
end
end
else begin
{SIO1_Reg,PO_Reg} <= #tAA Status_Reg;
end
end
end // end forever
end
endtask // read_status
/*----------------------------------------------------------------------*/
/* Description: define a write status task */
/*----------------------------------------------------------------------*/
task write_status;
integer tWRSR;
reg [7:0] Status_Reg_Up;
begin
//$display( $time, " Old Status Register = %b", Status_Reg );
Status_Reg_Up = SI_Reg[7:0] ;
if ( (Status_Reg[7] == Status_Reg_Up[7] )
&& (Status_Reg[5:2] == Status_Reg_Up[5:2] ) ) begin
Status_Reg[1] = 1'b0;
WRSR_Mode = 1'b0;
end
else begin
if ( (Status_Reg[7] == 1'b1 && Status_Reg_Up[7] == 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 ))
tWRSR = tW;
else
tWRSR = tBP;
//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 Enable Latch
Status_Reg[0] = 1'b0;
//WEL:Write Enable Latch
Status_Reg[1] = 1'b0;
WRSR_Mode = 1'b0;
end
if ( Status_Reg[4] == 0 || Status_Reg[3] == 0 || Status_Reg [2] == 0 ) begin//BP2~0 not all 1
Param_Reg = 8'h00;
end
end
endtask // write_status
/*----------------------------------------------------------------------*/
/* Description: define a read data task */
/*----------------------------------------------------------------------*/
task read_1xio;
integer Dummy_Count, Tmp_Int;
reg [7:0] OUT_Buf;
begin
Dummy_Count = 8;
dummy_cycle(24);
#1;
OUT_Buf = (Secur_Mode == 1) ? Secur_ARRAY[Address] :
((read_protect(Address) == 1'b1) ? 8'b0 : ARRAY[Address] );
forever begin
@ ( negedge ISCLK or posedge CS );
if ( CS == 1'b1 ) begin
if ( P_Mode == 0 ) begin
{EN_S0, EN_P0, EN_S1, EN_P1} = {1'b1, 1'b0, 1'b0, 1'b0};
end
else begin
{EN_S0, EN_P0, EN_S1, EN_P1} = {1'b0, 1'b1, 1'b0, 1'b0};
end
disable read_1xio;
end
else begin //do work on non deep power down mode
Read_Mode = 1'b1;
SO_OUT_EN = 1'b1;
if ( P_Mode == 1'b0 ) begin
{EN_S0, EN_P0, EN_S1, EN_P1} = {1'b0, 1'b0, 1'b1, 1'b0};
if ( Dummy_Count ) begin
{SIO1_Reg, OUT_Buf} <= #tCLQV {OUT_Buf, OUT_Buf[7]};
Dummy_Count = Dummy_Count - 1;
end
else begin
Address = Address + 1;
Address = (Secur_Mode == 1) ? Address[5:0] : Address;
OUT_Buf = (Secur_Mode == 1) ? Secur_ARRAY[Address]
:((read_protect(Address) == 1'b1) ? 8'b0 : ARRAY[Address] );
{SIO1_Reg, OUT_Buf} <= #tCLQV {OUT_Buf, OUT_Buf[7]};
Dummy_Count = 7 ;
end
end
else begin
{EN_S0, EN_P0, EN_S1, EN_P1} = {1'b0, 1'b0, 1'b0, 1'b1};
OUT_Buf = (Secur_Mode == 1) ? Secur_ARRAY[Address]
:((read_protect(Address) == 1'b1) ? 8'b0 : ARRAY[Address] );
{SIO1_Reg,PO_Reg} <= #tCLQV {OUT_Buf};
Address = Address + 1;
Address = (Secur_Mode == 1) ? Address[5:0] : Address;
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(24);
dummy_cycle(8);
OUT_Buf = (Secur_Mode == 1) ? Secur_ARRAY[Address]:
((read_protect(Address) == 1'b1) ? 8'b0 : ARRAY[Address] );
forever begin
@ ( negedge ISCLK or posedge CS );
if ( CS == 1'b1 ) begin
disable fastread_1xio;
end
else begin //do work on non deep power down mode
Read_Mode = 1'b1;
SO_OUT_EN = 1'b1;
if ( Dummy_Count ) begin
{SIO1_Reg, OUT_Buf} <= #tCLQV {OUT_Buf, OUT_Buf[7]};
Dummy_Count = Dummy_Count - 1;
end
else begin
Address = Address + 1;
Address = (Secur_Mode == 1) ? Address[5:0] : Address;
OUT_Buf = (Secur_Mode == 1) ? Secur_ARRAY[Address]
:((read_protect(Address) == 1'b1) ? 8'b0 : ARRAY[Address] );
{SIO1_Reg, OUT_Buf} <= #tCLQV {OUT_Buf, OUT_Buf[7]};
Dummy_Count = 7 ;
end
end
end // end forever
end
endtask // fastread_1xio
/*----------------------------------------------------------------------*/
/* Description: define a block erase task */
/* D8 AD1 AD2 AD3 */
/*----------------------------------------------------------------------*/
task block_erase;
reg [Block_MSB:0] Block;
integer i;
begin
Block = Address[A_MSB:16];
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;
#tBE ;
for( i = Start_Add; i <= End_Add; i = i + 1 )
begin
ARRAY[i] = 8'hff;
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;
end
endtask // block_erase
/*----------------------------------------------------------------------*/
/* Description: define a sector 4k erase task */
/* 20(D8) AD1 AD2 AD3 */
/*----------------------------------------------------------------------*/
task sector_erase_4k;
integer i;
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;
#tSE;
for( i = Start_Add; i <= End_Add; i = i + 1 )
begin
ARRAY[i] = 8'hff;
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 sector 1k erase task */
/* 20(D8) AD1 AD2 AD3 */
/*----------------------------------------------------------------------*/
task sector_erase_1k;
reg [1:0] SEC_1K;
integer i;
begin
SEC_1K = Address[11:10];
Start_Add = (Address[A_MSB:10]<<10) + 12'h000;
End_Add = (Address[A_MSB:10]<<10) + 12'h3ff;
//WIP : write in process Bit
Status_Reg[0] = 1'b1;
#tSE
for( i = Start_Add; i <= End_Add; i = i + 1 )
begin
ARRAY[i] = 8'hff;
end
//WIP : write in process Bit
Status_Reg[0] = 1'b0;//WIP
//WEL : write enable latch
Status_Reg[1] = 1'b0;//WEL
SE_1K_Mode = 1'b0;
end
endtask // sector_erase_1k
/*----------------------------------------------------------------------*/
/* Description: define a chip erase task */
/* 60(C7) */
/*----------------------------------------------------------------------*/
task chip_erase;
begin
Status_Reg[0] = 1'b1;
for ( i = 0;i<tCE/1000;i = i + 1)
begin
#1000_000_000;
end
for( i = 0; i <Block_NUM; i = i+1 )
begin
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
i = 0;
//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 = Page_Size; // 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 ISCLK or posedge CS );
if ( CS == 1'b1 ) begin
if ( Tmp_Int % 8 !== 0 ) begin
PP_1XIO_Mode = 0;
disable page_program;
end
else begin
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
if ( P_Mode == 1'b0 ) begin
Tmp_Int = Tmp_Int + 1;
if ( Tmp_Int % 8 == 0) begin
#1;
Dummy_A[Offset] = SI_Reg [7:0];
Offset = Offset + 1;
Offset = (Secur_Mode == 1) ? Offset[5:0] : Offset[7:0];
end
end
else begin
Tmp_Int = Tmp_Int + 8;
if ( Tmp_Int % 8 == 0) begin
#1;
Dummy_A[Offset] = {Latch_SO, Latch_PO};
Offset = Offset + 1;
Offset = (Secur_Mode == 1) ? Offset[5:0] : Offset[7:0];
end
end
end
end // end forever
end
endtask // page_program
/*----------------------------------------------------------------------*/
/* Description: define a deep power down (DP) */
/*----------------------------------------------------------------------*/
task deep_power_down;
begin
//$display( $time, " Old DP Mode Register = %b", DP_Mode );
if ( DP_Mode == 1'b0)
DP_Mode = #tDP 1'b1;
//$display( $time, " New DP Mode Register = %b", DP_Mode );
end
endtask // deep_power_down
/*----------------------------------------------------------------------*/
/* Description: define a release from deep power dwon task (RDP) */
/*----------------------------------------------------------------------*/
task release_from_deep_power_down;
begin
//$display( $time, " Old DP Mode Register = %b", DP_Mode );
if ( DP_Mode == 1'b1)
DP_Mode = #tRES 1'b0;
//$display( $time, " New DP Mode Register = %b", DP_Mode );
end
endtask // release_from_deep_power_down
/*----------------------------------------------------------------------*/
/* Description: define a read electronic ID (RES) */
/* AB X X X */
/*----------------------------------------------------------------------*/
task read_electronic_id;
reg [7:0] Dummy_ID;
begin
//$display( $time, " Old DP Mode Register = %b", DP_Mode );
dummy_cycle(23);
Dummy_ID = ID_Device;
dummy_cycle(1);
forever begin
@ ( negedge ISCLK or posedge CS );
if ( CS == 1'b1 ) begin
disable read_electronic_id;
end
else begin
SO_OUT_EN = 1'b1;
if ( P_Mode == 1'b0 ) begin
{SIO1_Reg, Dummy_ID} <= #tCLQV {Dummy_ID, Dummy_ID[7]};
end
else begin
{SIO1_Reg,PO_Reg} <= #tAA ID_Device;
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 ISCLK or posedge CS );
if ( CS == 1'b1 ) begin
disable read_electronic_manufacturer_device_id;
end
else begin
SO_OUT_EN = 1'b1;
if ( P_Mode == 1'b0 ) begin // check parallel mode (2)
{SIO1_Reg, Dummy_ID} <= #tCLQV {Dummy_ID, Dummy_ID[15]};
end
else if ( P_Mode == 1'b1 ) begin
if ( Dummy_Count == 0 ) begin
{SIO1_Reg,PO_Reg} <= #tAA Dummy_ID[15:8];
Dummy_Count = 1;
end
else begin
{SIO1_Reg,PO_Reg} <= #tAA Dummy_ID[7:0];
Dummy_Count = 0;
end
end
end
end // end forever
end
endtask // read_electronic_manufacturer_device_id
/*----------------------------------------------------------------------*/
/* Description: define a program chip task */
/* INPUT program_time */
/* segment: segment address */
/* offset : offset address */
/*----------------------------------------------------------------------*/
task update_array;
input [A_MSB:0] Address;
integer Dummy_Count;
integer program_time;
begin
Dummy_Count = Page_Size;
Address = { Address [A_MSB:8], 8'h0 };
program_time = (Byte_PGM_Mode) ? tBP : tPP;
Status_Reg[0]= 1'b1;
#program_time ;
for ( i = 0; i < Dummy_Count; i = i + 1 ) begin
if ( Secur_Mode == 1'b1)
Secur_ARRAY[Address + i] = Secur_ARRAY[Address + i] & Dummy_A[i];
else
ARRAY[Address+ i] = ARRAY[Address + i] & Dummy_A[i];
end
Status_Reg[0] = 1'b0;
Status_Reg[1] = 1'b0;
PP_1XIO_Mode = 1'b0;
Byte_PGM_Mode = 1'b0;
end
endtask // update_array
/*----------------------------------------------------------------------*/
/* Description: define a write read-lock register task */
/*----------------------------------------------------------------------*/
task write_lkbit;
begin
if ( SI_Reg[2] == 1 ) begin
Secur_Reg[2] <= SI_Reg[2];
end
if ( SI_Reg[3] == 1 ) begin
Secur_Reg[3] <= SI_Reg[3];
end
Status_Reg[1]<=1'b0;
end
endtask // write_lkbit
/*----------------------------------------------------------------------*/
/* Description: define a enter secured OTP task */
/*----------------------------------------------------------------------*/
task enter_secured_otp;
begin
//$display( $time, " Enter secured OTP mode = %b", enter_Secur_Mode );
Secur_Mode= 1;
//$display( $time, " New Enter secured OTP mode = %b", enter_Secur_Mode );
end
endtask // enter_secured_otp
/*----------------------------------------------------------------------*/
/* Description: define a exit 512 secured OTP task */
/*----------------------------------------------------------------------*/
task exit_secured_otp;
begin
//$display( $time, " Enter 512 secured OTP mode = %b", enter_Secur_Mode );
Secur_Mode = 0;
//$display( $time, " New Enter 512 secured OTP mode = %b", enter_Secur_Mode );
end
endtask
/*----------------------------------------------------------------------*/
/* Description: Execute Reading Security Register */
/*----------------------------------------------------------------------*/
task read_Secur_Register;
integer Dummy_Count;
begin
Dummy_Count = 8;
forever @ ( negedge ISCLK or posedge CS ) begin // output security register info
if ( CS == 1 ) begin
disable read_Secur_Register;
end
else begin //do work on non deep power down mode and not in CP_Mode with hardware detection
SO_OUT_EN = 1'b1;
if ( P_Mode == 1'b0 ) begin
if ( Dummy_Count ) begin
Dummy_Count = Dummy_Count - 1;
SIO1_Reg <= #tCLQV Secur_Reg[Dummy_Count];
end
else begin
Dummy_Count = 7;
SIO1_Reg <= #tCLQV Secur_Reg[Dummy_Count];
end
end
else begin
{SIO1_Reg,PO_Reg} <= #tAA Secur_Reg;
end
end
end
end
endtask // read_Secur_Register
/*----------------------------------------------------------------------*/
/* Description: Execute Write Security Register */
/*----------------------------------------------------------------------*/
task write_secur_register;
begin
Status_Reg[0] = 1'b1;
#tBP;
Secur_Reg [1] = 1'b1;
Status_Reg[0] = 1'b0;
end
endtask // write_secur_register
/*----------------------------------------------------------------------*/
/* Description: define a continuously program task */
/* 02 AD1 AD2 AD3 */
/*----------------------------------------------------------------------*/
task cp_program;
integer Tmp_Int;
begin
CP_Data = SI_Reg[15:0] ;
Tmp_Int = 0;
forever begin
@ ( posedge ISCLK or posedge CS );
if ( CS == 1'b1 ) begin
if ( P_Mode == 1'b0 && Tmp_Int % 8 !== 0 ) begin
disable cp_program;
end
else begin
EN_CP_Mode = 1'b1;
CP_Mode = 1'b1;
Status_Reg[6] = EN_CP_Mode;
Status_Reg[0] = 1'b1;
#tBP;
Status_Reg[0]= 1'b0;
CP_Mode = 1'b0;
if ( Secur_Mode == 1)
begin
Secur_ARRAY[Address + 1] = Secur_ARRAY[Address + 1] & CP_Data [7:0];
Secur_ARRAY[Address] = Secur_ARRAY[Address] & CP_Data [15:8];
end
else
begin
ARRAY[Address + 1] = ARRAY[Address + 1] & CP_Data [7:0];
ARRAY[Address] = ARRAY[Address] & CP_Data [15:8];
end
if ( Address == (Secur_Mode ? (Secur_TOP_Add - 1) : (TOP_Add - 1)))
begin
Status_Reg[6] = 1'b0;
Status_Reg[1] = 1'b0;
EN_CP_Mode = 1'b0;
end
else
begin
Address = Address + 2;
end
if ( write_protect(Address) == 1'b1 && (!Secur_Mode) )
begin
Status_Reg[6] = 1'b0;
Status_Reg[1] = 1'b0;
EN_CP_Mode = 1'b0;
end
end
disable cp_program;
end
else begin // count how many Bits been shifted
if ( P_Mode == 1'b0 ) begin
Tmp_Int = Tmp_Int + 1;
end
else begin
Tmp_Int = Tmp_Int + 8;
end
end
end // end forever
end
endtask // cp_program
/*----------------------------------------------------------------------*/
/* Description: define a ESRY task */
/*----------------------------------------------------------------------*/
task read_ryby;
begin
//$display( $time, " Enter CP ESRY mode = %b", CP_ESRY_Mode );
CP_ESRY_Mode= 1;
//$display( $time, " New Enter CP ESRY mode = %b", CP_ESRY_Mode );
end
endtask // read_ryby
/*----------------------------------------------------------------------*/
/* Description: define a DSRY task */
/*----------------------------------------------------------------------*/
task disread_ryby;
begin
//$display( $time, " Enter CP ESRY mode = %b", CP_ESRY_Mode );
CP_ESRY_Mode = 0;
//$display( $time, " New Enter CP ESRY mode = %b", CP_ESRY_Mode );
end
endtask // disread_ryby
/*----------------------------------------------------------------------*/
/* 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(4);
OUT_Buf = (Secur_Mode == 1) ? Secur_ARRAY[Address] :
((read_protect(Address) == 1'b1) ? 8'b0 : ARRAY[Address] );
forever @ ( negedge ISCLK or posedge CS ) begin
if ( CS == 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} <= #tCLQV {OUT_Buf, OUT_Buf[1:0]};
Dummy_Count = Dummy_Count - 1;
end
else begin
Address = Address + 1;
Address = (Secur_Mode == 1) ? Address[5:0] : Address;
OUT_Buf = (Secur_Mode == 1) ? Secur_ARRAY[Address] :
((read_protect(Address) == 1'b1) ? 8'b0 : ARRAY[Address] );
{SIO1_Reg, SIO0_Reg, OUT_Buf} <= #tCLQV {OUT_Buf, OUT_Buf[1:0]};
Dummy_Count = 3 ;
end
end
end//forever
end
endtask // read_2xio
/*----------------------------------------------------------------------*/
/* Description: define Reading Parameter */
/*----------------------------------------------------------------------*/
task read_parameter;
integer Dummy_Count;
begin
Dummy_Count = 8;
forever begin
@ ( negedge ISCLK or posedge CS );
if ( CS == 1'b1 ) begin
disable read_parameter;
end
else begin
SO_OUT_EN = 1'b1;
if ( Dummy_Count ) begin
Dummy_Count = Dummy_Count - 1;
SIO1_Reg <= #tCLQV Param_Reg[Dummy_Count];
end
else begin
Dummy_Count = 7;
SIO1_Reg <= #tCLQV Param_Reg[Dummy_Count];
end
end
end // end forever
end
endtask // read_parameter
/*----------------------------------------------------------------------*/
/* Description: Execute Writing Parameter */
/*----------------------------------------------------------------------*/
task write_parameter;
begin
//$display( $time, " Old Parameter Register = %b", Param_Reg );
if ( Status_Reg[4] == 0 || Status_Reg[3] == 0 || Status_Reg[2] == 0 ) begin//BP2~0 not all 1
Param_Reg = 8'h00;
end
else begin //allow to change parameter register
Param_Reg = {3'b000,SI_Reg[4:0]};
end
end
endtask // write_parameter
/*----------------------------------------------------------------------*/
/* Description: define a write_protect area function */
/* INPUT */
/* sector : sector address */
/*----------------------------------------------------------------------*/
function write_protect;
input [A_MSB:0] Address;
begin
//protect_define
Block = Address [A_MSB:16];
if((Param_Reg[0] == 1) &&(Address[A_MSB:12] == 0)) begin
write_protect = Param_Reg[1]&&(Address[11:10] == 2'b00) ||
Param_Reg[2]&&(Address[11:10] == 2'b01) ||
Param_Reg[3]&&(Address[11:10] == 2'b10) ||
Param_Reg[4]&&(Address[11:10] == 2'b11) ;
end
else 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] >= 126 && Block[Block_MSB:0] <= 127) 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] >= 124 && Block[Block_MSB:0] <= 127) 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] >= 120 && Block[Block_MSB:0] <= 127) 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] >= 112 && Block[Block_MSB:0] <= 127) 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] >= 96 && Block[Block_MSB:0] <= 127) 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] >= 64 && Block[Block_MSB:0] <= 127) 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] <= 63) 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] <= 95) 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] <= 111) 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] <= 119) 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] <= 123) 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] <= 125) 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
else begin
write_protect = 1'b1;
end
end
endfunction // write_protect
/*----------------------------------------------------------------------*/
/* When WRLB Condtion Operation; */
/*----------------------------------------------------------------------*/
function read_protect;
input [A_MSB : 0] Address ;
begin
if ( (Secur_Reg[2] == 1'b1) && (Address >= PRO_128K_Beg) && (Address <= PRO_128K_End) ) begin
read_protect = 1'b1;
end
else begin
read_protect = 1'b0;
end
end
endfunction // read_protect
// *==============================================================================================
// * AC Timing Check Section
// *==============================================================================================
wire Read_1XIO_Chk_w = Read_1XIO_Chk;
wire Read_2XIO_Chk_w = Read_2XIO_Chk;
wire SI_IN_EN_w = SI_IN_EN;
wire SO_IN_EN_w = SO_IN_EN;
specify
/*----------------------------------------------------------------------*/
/* Timing Check */
/*----------------------------------------------------------------------*/
$period( posedge ISCLK &&& ~CS, tSCLK ); // SCLK _/~ ->_/~
$period( negedge ISCLK &&& ~CS, tSCLK ); // SCLK ~\_ ->~\_
$period( posedge ISCLK &&& Read_1XIO_Chk_w , tRSCLK ); // SCLK ~\_ ->~\_
$period( posedge ISCLK &&& Read_2XIO_Chk_w , tTSCLK ); // SCLK ~\_ ->~\_
$width ( posedge ISCLK &&& ~CS, tCH ); // SCLK _/~~\_
$width ( negedge ISCLK &&& ~CS, tCL ); // SCLK ~\__/~
$width ( posedge CS , tSHSL ); // CS _/~\_
$setup ( SI &&& ~CS, posedge ISCLK &&& SI_IN_EN_w, tDVCH );
$hold ( posedge ISCLK &&& SI_IN_EN_w, SI &&& ~CS, tCHDX );
$setup ( SO &&& ~CS, posedge ISCLK &&& SO_IN_EN_w, tDVCH );
$hold ( posedge ISCLK &&& SO_IN_EN_w, SO &&& ~CS, tCHDX );
$setup ( negedge CS, posedge ISCLK &&& ~CS, tSLCH );
$hold ( posedge ISCLK &&& ~CS, posedge CS, tCHSH );
$setup ( posedge CS, posedge ISCLK &&& CS, tSHCH );
$hold ( posedge ISCLK &&& CS, negedge CS, tCHSL );
$setup ( negedge HOLD , posedge SCLK &&& ~CS, tHLCH );
$hold ( posedge SCLK &&& ~CS, posedge HOLD , tCHHH );
$setup ( posedge HOLD , posedge SCLK &&& ~CS, tHHCH );
$hold ( posedge SCLK &&& ~CS, negedge HOLD , tCHHL );
$setup ( posedge WP &&& SRWD, negedge CS, tWHSL );
$hold ( posedge CS, negedge WP &&& SRWD, tSHWL );
$setup ( negedge SCLK &&& ~CS, negedge HOLD , tCLHS );
$hold ( negedge SCLK &&& ~CS, posedge HOLD , tCLHH );
endspecify
integer AC_Check_File;
// timing check module
initial
begin
AC_Check_File= $fopen ("ac_check.err" );
end
time T_CS_P , T_CS_N;
time T_WP_P , T_WP_N;
time T_SCLK_P , T_SCLK_N;
time T_ISCLK_P , T_ISCLK_N;
time T_HOLD_P , T_HOLD_N;
time T_SI;
time T_SO;
time T_WP;
time T_HOLD;
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_ISCLK_P = 0;
T_ISCLK_N = 0;
T_HOLD_P = 0;
T_HOLD_N = 0;
T_SI = 0;
T_SO = 0;
T_WP = 0;
T_HOLD = 0;
end
always @ ( posedge ISCLK ) begin
//tSCLK
if ( $time - T_ISCLK_P < tSCLK && $time > 0 && ~CS )
$fwrite (AC_Check_File, "Clock Frequence for except READ struction fSCLK =%d Mhz, fSCLK timing violation at %d \n", fSCLK, $time );
//fRSCLK
if ( $time - T_ISCLK_P < tRSCLK && Read_1XIO_Chk && $time > 0 && ~CS )
$fwrite (AC_Check_File, "Clock Frequence for READ instruction fRSCLK =%d Mhz, fRSCLK timing violation at %d \n", fRSCLK, $time );
//fTSCLK
if ( $time - T_ISCLK_P < tTSCLK && Read_2XIO_Chk && $time > 0 && ~CS )
$fwrite (AC_Check_File, "Clock Frequence for 2/4XI/O instruction fTSCLK =%d Mhz, fRSCLK timing violation at %d \n", fTSCLK, $time );
T_ISCLK_P = $time;
#0;
//tDVCH
if ( T_ISCLK_P - T_SI < tDVCH && SI_IN_EN && T_ISCLK_P > 0 )
$fwrite (AC_Check_File, "minimun Data SI setup time tDVCH=%d ns, tDVCH timing violation at %d \n", tDVCH, $time );
if ( T_ISCLK_P - T_SO < tDVCH && SO_IN_EN && T_ISCLK_P > 0 )
$fwrite (AC_Check_File, "minimun Data SO setup time tDVCH=%d ns, tDVCH timing violation at %d \n", tDVCH, $time );
//tCL
if ( T_ISCLK_P - T_ISCLK_N < tCL && ~CS && T_ISCLK_P > 0 )
$fwrite (AC_Check_File, "minimun SCLK Low time tCL=%f ns, tCL timing violation at %d \n", tCL, $time );
end
always @ ( negedge ISCLK ) begin
T_ISCLK_N = $time;
#0;
//tCH
if ( T_ISCLK_N - T_ISCLK_P < tCH && ~CS && T_ISCLK_N > 0 )
$fwrite (AC_Check_File, "minimun SCLK High time tCH=%f ns, tCH timing violation at %d \n", tCH, $time );
end
always @ ( SI ) begin
T_SI = $time;
#0;
//tCHDX
if ( T_SI - T_ISCLK_P < tCHDX && SI_IN_EN && T_SI > 0 )
$fwrite (AC_Check_File, "minimun Data SI hold time tCHDX=%d ns, tCHDX timing violation at %d \n", tCHDX, $time );
end
always @ ( SO ) begin
T_SO = $time;
#0;
//tCHDX
if ( T_SO - T_ISCLK_P < tCHDX && SO_IN_EN && T_SO > 0 )
$fwrite (AC_Check_File, "minimun Data SO hold time tCHDX=%d ns, tCHDX timing violation at %d \n", tCHDX, $time );
end
always @ ( posedge SCLK ) begin
T_SCLK_P = $time;
#0;
// tSLCH
if ( T_SCLK_P - T_CS_N < tSLCH && T_SCLK_P > 0 )
$fwrite (AC_Check_File, "minimun CS# active setup time tSLCH=%d ns, tSLCH timing violation at %d \n", tSLCH, $time );
// tSHCH
if ( T_SCLK_P - T_CS_P < tSHCH && T_SCLK_P > 0 )
$fwrite (AC_Check_File, "minimun CS# not active setup time tSHCH=%d ns, tSHCH timing violation at %d \n", tSHCH, $time );
//tHLCH
if ( T_SCLK_P - T_HOLD_N < tHLCH && ~CS && T_SCLK_P > 0 )
$fwrite (AC_Check_File, "minimun HOLD# setup time tHLCH=%d ns, tHLCH timing violation at %d \n", tHLCH, $time );
//tHHCH
if ( T_SCLK_P - T_HOLD_P < tHHCH && ~CS && T_SCLK_P > 0 )
$fwrite (AC_Check_File, "minimun HOLD setup time tHHCH=%d ns, tHHCH timing violation at %d \n", tHHCH, $time );
end
always @ ( negedge SCLK ) begin
T_SCLK_N = $time;
end
always @ ( posedge CS ) begin
T_CS_P = $time;
#0;
// tCHSH
if ( T_CS_P - T_SCLK_P < tCHSH && T_CS_P > 0 )
$fwrite (AC_Check_File, "minimun CS# active hold time tCHSH=%d ns, tCHSH timing violation at %d \n", tCHSH, $time );
end
always @ ( negedge CS ) begin
T_CS_N = $time;
#0;
//tCHSL
if ( T_CS_N - T_SCLK_P < tCHSL && T_CS_N > 0 )
$fwrite (AC_Check_File, "minimun CS# not active hold time tCHSL=%d ns, tCHSL timing violation at %d \n", tCHSL, $time );
//tSHSL
if ( T_CS_N - T_CS_P < tSHSL && T_CS_N > 0 )
$fwrite (AC_Check_File, "minimun CS# deslect time tSHSL=%d ns, tSHSL timing violation at %d \n", tSHSL, $time );
//tWHSL
if ( T_CS_N - T_WP_P < tWHSL && SRWD && T_CS_N > 0 )
$fwrite (AC_Check_File, "minimun WP setup time tWHSL=%d ns, tWHSL timing violation at %d \n", tWHSL, $time );
end
always @ ( posedge WP ) begin
T_WP_P = $time;
#0;
end
always @ ( negedge WP ) begin
T_WP_N = $time;
#0;
//tSHWL
if ( ((T_WP_N - T_CS_P < tSHWL) || ~CS) && SRWD && T_WP_N > 0 )
$fwrite (AC_Check_File, "minimun WP hold time tSHWL=%d ns, tSHWL timing violation at %d \n", tSHWL, $time );
end
always @ ( posedge HOLD ) begin
T_HOLD_P = $time;
#0;
//tCHHH
if ( T_HOLD_P - T_SCLK_P < tCHHH && ~CS && T_HOLD_P > 0 )
$fwrite (AC_Check_File, "minimun HOLD# hold time tCHHH=%d ns, tCHHH timing violation at %d \n", tCHHH, $time );
//tCLHH
if ( T_HOLD_P - T_SCLK_N < tCLHH && ~CS && T_HOLD_P > 0 )
$fwrite (AC_Check_File, "Clock Low to HOLD# hold time tCLHH=%d ns, tCLHH timing violation at %d \n", tCLHH, $time );
end
always @ ( negedge HOLD ) begin
T_HOLD_N = $time;
#0;
//tCHHL
if ( T_HOLD_N - T_SCLK_P < tCHHL && ~CS && T_HOLD_N > 0 )
$fwrite (AC_Check_File, "minimun HOLD hold time tCHHL=%d ns, tCHHL timing violation at %d \n", tCHHL, $time );
//tCLHS
if ( T_HOLD_N - T_SCLK_N < tCLHS && ~CS && T_HOLD_N > 0 )
$fwrite (AC_Check_File, "Clock Low to HOLD# setup time tCLHS=%d ns, tCLHS timing violation at %d \n", tCLHS, $time );
end
endmodule