在学习spi 协议时,我们会经常使用flash 作为参考例子, 在调试verilog 代码时,经常会使用示波器, 或者quarts, vivado 的工具自带的调试工具,但这些方法都需要编译verilog 代码,下载到开发板上,再进行调试。 本文介绍一种方法,直接使用仿真工具,将自己所写的 spi controller 进行验证, 如果仿真ok, 再进行编译,在线调试,会大大提高开发周期
在对spi flash controller 进行spi flash 仿真时, 遇到的问题没有spi flash (device)的情况下,不好仿真,没有设备应答。 但实际中,我们会发现,绝大多数的spi flash 厂家,都会提供verilog 的源码,这样就极大的方便了 controller 的开发了。我们这里以SST25WF080B 为例, 做一个spi flash controller 的仿真工程。
首先,我们先找到spi flash 的源码, 大多数厂家都会提供。
举例: https://www.microchip.com/wwwproducts/en/SST25WF080B

其他的flash ,用户也能在各自的网站上找到verilog。
接下来我们在vivado 下创建仿真工程:
module tb_sim(
);
reg sys_clk = 0;
always sys_clk = #10 ~sys_clk;
reg flash_clk = 0;
reg flash_cs = 1;
reg flash_mosi = 0;
wire flash_miso;
reg [7:0] cnt = 0;
wire [7:0] RDID = 8'h9f;
reg [31:0] DEV_ID = 0;
initial
begin
flash_clk = 0;
flash_cs = 1;
flash_mosi = 0;
#2000;
flash_cs = 0;
@(posedge sys_clk);
flash_mosi = RDID[7];
@(posedge sys_clk);
flash_clk = 1;
@(posedge sys_clk);
flash_clk = 0;
flash_mosi = RDID[6];
@(posedge sys_clk);
flash_clk = 1;
@(posedge sys_clk);
flash_clk = 0;
flash_mosi = RDID[5];
@(posedge sys_clk);
flash_clk = 1;
@(posedge sys_clk);
flash_clk = 0;
flash_mosi = RDID[4];
@(posedge sys_clk);
flash_clk = 1;
@(posedge sys_clk);
flash_clk = 0;
flash_mosi = RDID[3];
@(posedge sys_clk);
flash_clk = 1;
@(posedge sys_clk);
flash_clk = 0;
flash_mosi = RDID[2];
@(posedge sys_clk);
flash_clk = 1;
@(posedge sys_clk);
flash_clk = 0;
flash_mosi = RDID[1];
@(posedge sys_clk);
flash_clk = 1;
@(posedge sys_clk);
flash_clk = 0;
flash_mosi = RDID[0];
@(posedge sys_clk);
flash_clk = 1;
@(posedge sys_clk);
flash_clk = 0;
for(cnt = 0; cnt < 32; cnt = cnt + 1)
begin
@(posedge sys_clk);
flash_clk = 1;
DEV_ID[31 - cnt] = flash_miso;
@(posedge sys_clk);
flash_clk = 0;
end
@(posedge sys_clk);
flash_cs = 1;
end
reg [7:0] cs_cnt = 0;
always @ (posedge flash_clk )
if(flash_cs) cs_cnt <= 0;
else cs_cnt <= cs_cnt + 1;
SST25WF080B SST25WF080B_inst
(
.SCK (flash_clk),
.CEB (flash_cs),
.SI (flash_mosi),
.SO (flash_miso),
.WPB (1),
.HOLDB (1)
);
首先我们创建一个系统时钟:
reg sys_clk = 0;
always sys_clk = #10 ~sys_clk;
sys_clk 为50M 的时钟。
接下来是flash 的连接线:
reg flash_clk = 0; // 提供给flash 芯片的时钟
reg flash_cs = 0; // falsh 芯片 的片选
reg flash_mosi = 0; // 发送给flash 芯片的数据线
wire flash_miso; // falsh 芯片 发送给controller 的数据线
wire [7:0] RDID = 8’h9f; // 根据手册为RDID 命令
sst25wf080b 的手册 : https://ww1.microchip.com/downloads/en/DeviceDoc/SST25WF080B-8-Mbit-1.8V-SPI-Serial-Flash-Data-Sheet-DS20005164E.pdf
reg [31:0] DEV_ID = 0; // 定义为从flash 芯片中读取的相关信息。
接下来就是initial 的 仿真逻辑了:
1)发送8’h9f 命令, 同时根据上图发送相应的flash_clk, flash_cs, 和 flash_mosi
2)连续输出(flash_clk) 32个clk
3) 将flash_cs 置高。
cs_cnt 用来记录 在flash_cs 为低期间 一共产生了多少flash_clk
仿真的结果为:
分析上图,我们会发现:
cs_cnt 记录为8个clk
在 falsh_cs 为低 的 8-16 个clock 之间。得到8’h62
接下来以此类推, 得到 flash 返回的所有信息: 32’h6216_1400
在仿真程序设计时,我们发现 从网上下载的sst25wf080b 的verilog 代码中:
SST25WF080B SST25WF080B_inst
(
.SCK (flash_clk),
.CEB (flash_cs),
.SI (flash_mosi),
.SO (flash_miso),
.WPB (1),
.HOLDB (1)
);
SI, SO 为 inout的,原因是芯片 支持 双线读写, 我们的仿真例子中使用的是spix1 模式, 单线读写。
这个信号在vivado 仿真时,比较麻烦,所以在这里我们修改了sst25wf080b的verilog文件。 将SI 设置为input
SO 设置为output (适合我们仿真中的spix1 模式)
//********************************************************************** // // Microchip 8M Serial Flash : SST25WF080B(Dual-mode) // // --- Verilog-HDL MODEL --- // //---------------------------------------------------------------------- // Ver Date Comment // 1.0 7/17/13 Initial release //---------------------------------------------------------------------- // Note: The following is the way to excute this model. // 1. Reading the external file of the Flash memory data // When the verilog simulation is executed with "+define+datain", // the Flash memory data is loaded from the external file named // "from8m.dat". // This file need to be placed in the current directory that // executes simulation. // The format of the files is the following. // @00000 // +- 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 // | 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 // | 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 // +-----> 01 // MSB LSB // IN this example, the data of "00000h" address is "01h" and // "00001h" address is "02h". // Thus, the data is arranged at address order. All data that // is not set in this file are "XXh". // // 2. Reading the external file of the Status register non-volatile information // When the verilog simulation is executed with "+define+statusin", // the Flash memory status register non-volatile information is loaded // from the external file named "from8mstat.dat". // This file also need to be placed in the current directory that // executes simulation. // The format of the files is the following. // +- BC // +-----> BC // MSB LSB // IN this example, the non-volatile information of "SRWP(Bit7)" is "1", // "TB(Bit5)" is "1", "BP2(Bit4)" is "1", "BP1(Bit3)" is "1" and // "BP0(Bit2)" is "1". // The data of "WEN(Bit1)" and "RDY#(Bit0)" are dont care. // // 3. SHORT MODE simulation // When the verilog simulation is executed with "+define+shortsim", // The WRITE TIME(PAGE PROGRAM, SECTOR ERASE, BLOCK ERASE, // CHIP ERASE and STATUS REGISTER WRITE) is reduced. // tPP = 15us, tSE = 60us, tBE = 60us, tCE = 60us, tWRSR = 60us. // //**************************************************************timescale 1ns / 10psdefine DBG_MODE module SST25WF080B ( SCK, SI, SO, CEB, WPB, HOLDB ); input SCK, CEB, WPB, HOLDB;ifdef DBG_MODE input SI; output SO;else inout SI, SO;endif //define datain //define statusin //define shortsim //protectdefine tCLHI_TIME 11.5define tCLLO_TIME 11.5define tCLHI2_TIME 14 // READ(03h)define tCLLO2_TIME 14 // READ(03h)define tCSS_TIME 10define tCSH_TIME 10define tDS_TIME 5define tDH_TIME 5define tCPH_TIME 25define tCHZ_TIME 15define tV_TIME 11define tHO_TIME 1define tHS_TIME 5define tHH_TIME 5define tHLZ_TIME 12define tHHZ_TIME 9define tWPS_TIME 20define tWPH_TIME 20define tDP_TIME 5_000define tPRB_TIME 500_000ifdef shortsimdefine tPP_TIME 15_000define tSSE_TIME 60_000define tSE_TIME 60_000define tCHE_TIME 60_000define tSRW_TIME 60_000 initial begin $display ("NOTICE!!"); $display (" This Flash memory simulation is SHORT MODE."); $display (" WRITE TIME was changed for fast simulation."); $display (" tPP = 15us, tSSE = 60us, tSE = 60us, tCHE = 60us, tSRW = 60us."); $display (" "); endelsedefine tPP_TIME 1_000_000define tSSE_TIME 150_000_000define tSE_TIME 250_000_000define tCHE_TIME 34'd6_000_000_000define tSRW_TIME 10_000_000endif parameter COMMAND_WIDTH = 8; parameter DATA_CODE = 8; parameter ADDRESS_SIZE = 20; // 8Mbit parameter SSEC_ADDRESS_SIZE = 8; // 8Mbit parameter SEC_ADDRESS_SIZE = 4; // 8Mbit parameter PAGE_ADDRESS_SIZE = 12; // 8Mbit parameter MEMORY_SIZE = 1048576; // 8Mbit(One memory register is One Byte) parameter PAGE_SIZE = 2048; parameter SCLK_SIZE = 12; parameter CMD_STORE_SIZE = 40; parameter tPP =tPP_TIME; parameter tSSE =tSSE_TIME; parameter tSE =tSE_TIME; parameter tCHE =tCHE_TIME; parameter tSRW =tSRW_TIME; parameter tV =tV_TIME; parameter tHO =tHO_TIME; parameter tCHZ =tCHZ_TIME; parameter tHHZ =tHHZ_TIME; parameter tHLZ =tHLZ_TIME; parameter tWPH_STORE =tWPH_TIME; parameter tDP_STORE =tDP_TIME; parameter tPRB_STORE =tPRB_TIME; parameter tDH_STORE =tDH_TIME;ifdef DBG_MODE parameter SO_OUT_P = 1'b0;else parameter SO_OUT_P = 1'bx;endif reg [COMMAND_WIDTH-1:0] CMD_CD; reg [DATA_CODE-1:0] DT_CD; reg [ADDRESS_SIZE-1:0] ADDRESS; reg [ADDRESS_SIZE-1:0] PG_PROG_STORE_ADD; reg [7:0] fmemory[MEMORY_SIZE-1:0]; reg [7:0] fmemorystat[0:0]; reg [7:0] fstat_info; reg [PAGE_SIZE-1:0] fmpage; reg [SCLK_SIZE-1:0] clk_count; reg [SCLK_SIZE-1:0] DT_count; reg clk_parity; reg [CMD_STORE_SIZE-1:0] cmd_store_reg; reg [ADDRESS_SIZE-1:0] dualio_store_reg; reg PG_data_entry_complete; reg [3:0] prot_level; reg READ4_CMD; reg READ5_CMD; reg DUAL_READ_CMD; reg DUAL_IO_READ_CMD; reg STATUS_READ_CMD; reg PDOWN_CMD; reg PDOWN_RELEASE_CMD; reg WRT_DSB_CMD; reg WRT_ENB_CMD; reg STATUS_WRT_CMD; reg DUAL_READ_ENT; reg DUAL_IO_READ_ENT; reg WRT_DSB; reg WRT_ENB; reg STATUS_WRT; reg write_flag; reg single_bus_l; reg two_bus_l; reg four_bus_l; reg POWER_DOWN; reg PDOWN_ENTRY; reg PDOWN_RELEASE; reg WPB_store; reg HOLD_EVENT; reg hold_flag; reg no_erase_dat_fg; reg no_erase_fg; reg SRWP; reg TB; reg BP2; reg BP1; reg BP0; reg WEN; integer p, x, y; reg [7:0] tmp; reg [7:0] ADDRESS_inc; reg [7:0] page[255:0]; reg spi_mode0; reg spi_mode3; reg every8bit; reg IDREAD_9F_CMD; reg IDREAD_AB_CMD; reg SSERASE_CMD; reg SERASE_CMD; reg CERASE_CMD; reg SSERASE_preset; reg SERASE_preset; reg [SSEC_ADDRESS_SIZE-1:0] ADDRESS_ssers; reg [SEC_ADDRESS_SIZE-1:0] ADDRESS_sers; reg [PAGE_ADDRESS_SIZE-1:0] ADDRESS_page; reg [ADDRESS_SIZE-1:0] SSERS_START_ADD; reg [ADDRESS_SIZE-1:0] SSERS_END_ADD; reg [ADDRESS_SIZE-1:0] SERS_START_ADD; reg [ADDRESS_SIZE-1:0] SERS_END_ADD; reg PROG_CMD; reg PROG_preset; reg [ADDRESS_SIZE-1:0] ADDRESS_prg; reg READ; reg DUAL_READ; reg DUAL_IO_READ; reg IDREAD_9F; reg IDREAD_AB; reg STATUS_READ; reg SSERASE; reg SERASE; reg CERASE; reg PROG; reg [7:0] so_reg; reg [7:0] so_reg_upper; reg [7:0] so_reg_lower; reg si_out; reg so_out; reg OE_SI; reg OE_SO; reg datain; reg statusin; reg [7:0] befor_data; reg [7:0] after_data; /* for timing check */ reg error_tCLHI, error_tCLLO; reg error_tCLHI2, error_tCLLO2; reg error_tCSS, error_tCSH; reg error_tDS, error_tDH; reg error_tCPH; reg error_tHS, error_tHH; reg error_tWPS, error_tWPH; reg error_tDP, error_tPRB; reg ac_err_com_fg; reg error_tHS_fg, error_tHH_fg; wire WRT; integer n,i,j,k,l,m; buf (_SCK, SCK); buf (_SI, SI);ifdef DBG_MODEelse buf (_SO, SO);endif buf (_CEB, CEB); buf (_WPB, WPB); buf (_HOLDB, HOLDB);ifdef DBG_MODE assign SO = OE_SO ? so_out : 1'bz;else bufif1 ( SI, si_out, OE_SI ); bufif1 ( SO, so_out, OE_SO );endif ///////////////////////////////////// // Initial data set // /////////////////////////////////////ifdef datain initial datain = 1;else initial datain = 0;endif initial begin if( datain ) begin $readmemh ("from8m.dat",fmemory); end else if( !datain ) begin for ( n = 0; n < MEMORY_SIZE; n = n + 1 ) begin fmemory[n] = 8'hXX; end end $display (" Initial Data in"); for ( n = 0; n <= 7; n = n + 1 ) begin $display ("Flashmemory Address=%h : Data=%h", n, fmemory[n]); end $display (" : "); $display (" : "); for ( n = MEMORY_SIZE-2; n <= MEMORY_SIZE-1; n = n + 1 ) begin $display ("Flashmemory Address=%h : Data=%h", n, fmemory[n]); end endifdef statusin initial statusin = 1;else initial statusin = 0;endif initial begin if( statusin ) begin $readmemh ("from8mstat.dat",fmemorystat); fstat_info = fmemorystat[0]; SRWP = fstat_info[7]; TB = fstat_info[5]; BP2 = fstat_info[4]; BP1 = fstat_info[3]; BP0 = fstat_info[2]; end else if( !statusin ) begin SRWP = 1'h0; TB = 1'h0; BP2 = 1'h0; BP1 = 1'h0; BP0 = 1'h0; end $display (" "); $display (" Initial STATUS REGISTER Non-Volatile information in"); $display ("Bit7(SRWP)=%h" , SRWP); $display ("Bit5(TB)=%h" , TB); $display ("Bit4(BP2)=%h" , BP2); $display ("Bit3(BP1)=%h" , BP1); $display ("Bit2(BP0)=%h" , BP0); $display (" "); end ///////////////////////////////////// // SPI MODE detect // ///////////////////////////////////// always @( _CEB ) begin if( _CEB ) begin spi_mode0 <= #2 0; spi_mode3 <= #2 0; end else if( !_SCK && !_CEB ) spi_mode0 <= 1; else if( _SCK && !_CEB ) spi_mode3 <= 1; end ///////////////////////////////////// // CLK counter // ///////////////////////////////////// always @( posedge _SCK or posedge _CEB ) begin if( _CEB ) begin if( ( clk_count > 12'h000 && clk_count < 12'h008 ) && !clk_parity ) begin $display (" Warning : Command instruction less than a byte unit. (Time=%.3f, %m)",$realtime); $display (" "); end clk_count <= 0; end else if( !hold_flag ) begin clk_count <= clk_count + 1; end end always @( posedge _CEB or posedge OE_SO ) begin clk_parity <= 0; end always @( posedge _SCK ) begin if( clk_count == 12'hFFF ) begin clk_parity <= 1; end end ///////////////////////////////////// // COMMAND store // ///////////////////////////////////// always @( posedge _CEB ) begin cmd_store_reg <= 0; dualio_store_reg <= 0; end always @( posedge _SCK ) begin if( !_CEB && !OE_SO && !hold_flag ) begin cmd_store_reg <= cmd_store_reg << 1; cmd_store_reg[0] <= _SI; end if( !_CEB && !OE_SO && !hold_flag && DUAL_IO_READ_CMD ) begin dualio_store_reg <= dualio_store_reg << 2; dualio_store_reg[0] <= _SI;ifdef DBG_MODE dualio_store_reg[1] <= 1;else dualio_store_reg[1] <= _SO;endif end end ///////////////////////////////////// // COMMAND code entry // ///////////////////////////////////// always @( negedge _SCK or posedge _CEB && _SCK ) begin if( clk_count == 12'h08 && !clk_parity && !hold_flag && !WRT && !POWER_DOWN ) begin case(cmd_store_reg[7:0]) 8'h03: READ4_CMD <= 1; 8'h0B: READ5_CMD <= 1; 8'h3B: DUAL_READ_CMD <= 1; 8'hBB: DUAL_IO_READ_CMD <= 1; 8'hD7: SSERASE_CMD <= 1; 8'h20: SSERASE_CMD <= 1; 8'hD8: SERASE_CMD <= 1; 8'hC7: CERASE_CMD <= 1; 8'h60: CERASE_CMD <= 1; 8'h02: PROG_CMD <= 1; 8'h06: WRT_ENB_CMD <= 1; 8'h04: WRT_DSB_CMD <= 1; 8'h05: STATUS_READ_CMD <= 1; 8'h01: STATUS_WRT_CMD <= 1; 8'h9F: IDREAD_9F_CMD <= 1; 8'hAB: begin IDREAD_AB_CMD <= 1; PDOWN_RELEASE_CMD <= 1; end 8'hB9: PDOWN_CMD <= 1; default: begin $display (" Error : undefined command instruction entry. (Time=%.3f, %m)",$realtime); $display (" "); end endcase end else if( clk_count == 12'h08 && !clk_parity && !hold_flag && WRT && !POWER_DOWN ) begin if (cmd_store_reg[7:0] == 8'h05) begin STATUS_READ_CMD <= 1; end else begin $display (" Warning : During write, all operations except STATUS READ are ignored. (Time=%.3f, %m)",$realtime); $display (" "); end end else if( clk_count == 12'h08 && !clk_parity && !hold_flag && POWER_DOWN ) begin if (cmd_store_reg[7:0] == 8'hAB) begin IDREAD_AB_CMD <= 1; PDOWN_RELEASE_CMD <= 1; end else begin $display (" Warning : POWER DOWN state has ignored all commands except IDREAD_AB and POWER DOWN RELEASE command. (Time=%.3f, %m)",$realtime); $display (" "); end end end always @( posedge _CEB ) begin if( _CEB ) begin READ4_CMD <= 0; READ5_CMD <= 0; DUAL_READ_CMD <= 0; DUAL_IO_READ_CMD <= 0; STATUS_READ_CMD <= 0; IDREAD_9F_CMD <= 0; IDREAD_AB_CMD <= 0; i <= #tCHZ 0; m <= #tCHZ 0; end end always @( negedge _CEB ) begin if( !_CEB ) begin WRT_ENB_CMD <= 0; WRT_DSB_CMD <= 0; SSERASE_CMD <= 0; SERASE_CMD <= 0; CERASE_CMD <= 0; PROG_CMD <= 0; STATUS_WRT_CMD <= 0; PDOWN_CMD <= 0; PDOWN_RELEASE_CMD <= 0; end end ///////////////////////////////////// // ADDRESS entry // ///////////////////////////////////// always @( negedge _SCK or posedge _CEB ) begin if( _CEB ) ADDRESS <= 0; else if( clk_count == 12'h20 && !clk_parity && !WRT && !DUAL_IO_READ_CMD ) /* 32 cycles */ ADDRESS[ADDRESS_SIZE-1:0] <= cmd_store_reg[ADDRESS_SIZE-1:0]; else if( clk_count == 12'h14 && !clk_parity && DUAL_IO_READ_CMD ) /* 20 cycles */ ADDRESS[ADDRESS_SIZE-1:0] <= dualio_store_reg[ADDRESS_SIZE-1:0]; else if( clk_count == 12'h14 && !clk_parity && SSERASE_CMD ) /* 20 cycles */ ADDRESS_ssers <= cmd_store_reg[SSEC_ADDRESS_SIZE-1:0]; else if( clk_count == 12'h10 && !clk_parity && SERASE_CMD ) /* 16 cycles */ ADDRESS_sers <= cmd_store_reg[SEC_ADDRESS_SIZE-1:0]; end //////////////////////////////// // PROGRAM / DATA entry // //////////////////////////////// always @( posedge _SCK ) begin if( ( clk_count > 12'h20 || clk_parity ) && PROG_CMD ) begin #1 if( clk_count == DT_count ) begin fmpage = fmpage << 8; fmpage[7:0] = cmd_store_reg[7:0]; DT_count = DT_count + 8; if( j > 255 ) l = l + 1; j = j + 1; PG_data_entry_complete <= 1; end else PG_data_entry_complete <= 0; end else if( STATUS_WRT_CMD ) begin #1 if( clk_count == 12'h10 && !clk_parity ) begin DT_CD[7:0] = cmd_store_reg[7:0]; PG_data_entry_complete <= 1; end else PG_data_entry_complete <= 0; end end always @( negedge WRT or negedge _CEB ) begin if( !WRT ) begin DT_count <=12'h28; PG_data_entry_complete <= 0; j = 0; l = 0; end end ///////////////////////////////////// // READ mode // ///////////////////////////////////// initial begin OE_SI <= 0; OE_SO <= 0; end always @( negedge _SCK or posedge _CEB ) begin if( _CEB ) begin OE_SO <= #tCHZ 0; READ <= 0; end else if( READ4_CMD && clk_count == 12'h20 && !clk_parity && !WRT && !hold_flag ) begin if( !ac_err_com_fg ) begin OE_SO <= 1; READ <= 1; end else begin $display (" Error : AC violation occured during 4bus READ command instruction and hence"); $display (" that command input was ignored. (Time=%.3f, %m)",$realtime); $display (" "); ac_err_com_fg <= 0; end end else if( READ5_CMD && clk_count == 12'h28 && !clk_parity && !WRT && !hold_flag ) begin if( !ac_err_com_fg ) begin OE_SO <= 1; READ <= 1; end else begin $display (" Error : AC violation occured during 5bus READ command instruction and hence"); $display (" that command input was ignored. (Time=%.3f, %m)",$realtime); $display (" "); ac_err_com_fg <= 0; end end end always @( negedge _SCK or posedge _CEB or posedge READ ) begin if( _CEB ) begin i = #tCHZ 0; so_out = #tCHZ SO_OUT_P; end else if( READ && !hold_flag && !ac_err_com_fg ) begin if( i == 8 ) begin ADDRESS = ADDRESS + 1; i = 0; end #tHO so_out = SO_OUT_P; so_reg = fmemory[ADDRESS]; #(tV-tHO) so_out = so_reg[7-i]; if( !_CEB ) i = i + 1; end else if( READ && ac_err_com_fg ) begin $display (" Error : AC violation occured during READ and hence the corresponding output goes to "); $display (" indefinite momentarily. (Time=%.3f, %m)",$realtime); $display (" "); ac_err_com_fg <= 0; if( !_CEB ) begin #tHO so_out = SO_OUT_P; i = i + 1; end end end always @( posedge _CEB or posedge READ4_CMD or posedge READ5_CMD ) begin if( READ4_CMD && _CEB && clk_count < 12'h20 && !clk_parity ) begin READ4_CMD <= 0; $display (" Error : 4bus READ command ignored due to the transmitted data length is less than 4bus cycles."); $display (" (Time=%.3f, %m)",$realtime); end else if( READ5_CMD && _CEB && clk_count < 12'h28 && !clk_parity ) begin READ5_CMD <= 0; $display (" Error : 5bus READ command ignored due to the transmitted data length is less than 5bus cycles."); $display (" (Time=%.3f, %m)",$realtime); end end always @( posedge _CEB ) begin if( READ4_CMD && clk_count == 12'h20 && !clk_parity && _SCK ) begin READ4_CMD <= 0; $display (" Warning : For 4bus READ command, there is no clk availabale for output data transmission. (Time=%.3f, %m)",$realtime); $display (" "); end else if( READ5_CMD && clk_count == 12'h28 && !clk_parity && _SCK ) begin READ5_CMD <= 0; $display (" Warning : For 5bus READ command, there is no clk availabale for output data transmission. (Time=%.3f, %m)",$realtime); $display (" "); end end ///////////////////////////////////// // DUAL READ mode // ///////////////////////////////////// initial begin DUAL_READ <= 0; DUAL_READ_ENT <= 0; end always @( _SCK or _CEB ) begin if( _CEB ) begin DUAL_READ_ENT <= 0; end else if( cmd_store_reg[7:0] == 8'h3B && !_CEB && clk_count == 12'h08 && !clk_parity ) begin DUAL_READ_ENT <= 1; end else if( clk_count == 12'h20 && !_SCK && !clk_parity ) begin DUAL_READ_ENT <= 0; end end always @( negedge _SCK or posedge _CEB ) begin if( _CEB ) begin OE_SI <= #tCHZ 0; OE_SO <= #tCHZ 0; DUAL_READ <= 0; end else if( DUAL_READ_CMD && clk_count == 12'h28 && !clk_parity && !WRT && !hold_flag ) begin if( !ac_err_com_fg ) begin OE_SI <= 1; OE_SO <= 1; DUAL_READ <= 1; end else begin $display (" Error : AC violation occured during DUAL READ command instruction and hence"); $display (" that command input was ignored. (Time=%.3f, %m)",$realtime); $display (" "); ac_err_com_fg <= 0; end end end always @( negedge _SCK or posedge _CEB or posedge DUAL_READ ) begin if( _CEB ) begin i = #tCHZ 0; so_out <= #tCHZ SO_OUT_P; si_out <= #tCHZ 1'bX; end else if( DUAL_READ && !hold_flag && !ac_err_com_fg ) begin if( i == 8 ) begin ADDRESS = ADDRESS + 1; i = 0; end #tHO so_out = SO_OUT_P; si_out = 1'bX; so_reg = fmemory[ADDRESS]; #(tV-tHO) so_out = so_reg[7-i]; si_out = so_reg[6-i]; if( !_CEB ) i = i + 2; end else if( DUAL_READ && ac_err_com_fg ) begin $display (" Error : AC violation occured during DUAL READ and hence the corresponding output goes to "); $display (" indefinite momentarily. (Time=%.3f, %m)",$realtime); $display (" "); ac_err_com_fg <= 0; if( !_CEB ) begin #tHO so_out = SO_OUT_P; si_out = 1'bX; i = i + 2; end end end always @( posedge _CEB ) begin if( DUAL_READ_CMD && clk_count < 12'h28 && !clk_parity ) begin $display (" Error : DUAL READ command ignored due to the transmitted data length is less than 5bus cycles."); $display (" (Time=%.3f, %m)",$realtime); end end always @( posedge _CEB ) begin if( DUAL_READ_CMD && clk_count == 12'h28 && !clk_parity && _SCK ) begin DUAL_READ_CMD <= 0; $display (" Warning : For DUAL READ command, there is no clk availabale for output data transmission. (Time=%.3f, %m)",$realtime); $display (" "); end end ///////////////////////////////////// // DUAL IO READ mode // ///////////////////////////////////// initial begin DUAL_IO_READ <= 0; DUAL_IO_READ_ENT <= 0; end always @( _SCK or _CEB ) begin if( _CEB ) begin DUAL_IO_READ_ENT <= 0; end else if( cmd_store_reg[7:0] == 8'hBB && !_CEB && clk_count == 12'h08 && !clk_parity ) begin DUAL_IO_READ_ENT <= 1; end else if( clk_count == 12'h14 && !_SCK && !clk_parity ) begin DUAL_IO_READ_ENT <= 0; end end always @( negedge _SCK or posedge _CEB ) begin if( _CEB ) begin OE_SI <= #tCHZ 0; OE_SO <= #tCHZ 0; DUAL_IO_READ <= 0; end else if( DUAL_IO_READ_CMD && clk_count == 12'h18 && !clk_parity && !WRT && !hold_flag ) begin if( !ac_err_com_fg ) begin OE_SI <= 1; OE_SO <= 1; DUAL_IO_READ <= 1; end else begin $display (" Error : AC violation occured during DUAL-I/O READ command instruction and hence"); $display (" that command input was ignored. (Time=%.3f, %m)",$realtime); $display (" "); ac_err_com_fg <= 0; end end end always @( negedge _SCK or posedge _CEB or posedge DUAL_IO_READ ) begin if( _CEB ) begin i = #tCHZ 0; so_out <= #tCHZ SO_OUT_P; si_out <= #tCHZ 1'bX; end else if( DUAL_IO_READ && !hold_flag && !ac_err_com_fg ) begin if( i == 8 ) begin ADDRESS = ADDRESS + 1; i = 0; end #tHO so_out = SO_OUT_P; si_out = 1'bX; so_reg = fmemory[ADDRESS]; #(tV-tHO) so_out = so_reg[7-i]; si_out = so_reg[6-i]; if( !_CEB ) i = i + 2; end else if( DUAL_IO_READ && ac_err_com_fg ) begin $display (" Error : AC violation occured during DUAL-I/O READ and hence the corresponding output goes to "); $display (" indefinite momentarily. (Time=%.3f, %m)",$realtime); $display (" "); ac_err_com_fg <= 0; if( !_CEB ) begin #tHO so_out = SO_OUT_P; si_out = 1'bX; i = i + 2; end end end always @( posedge _CEB ) begin if( DUAL_IO_READ_CMD && clk_count < 12'h18 && !clk_parity ) begin $display (" Error : DUAL-I/O READ command ignored due to the transmitted data length is less than 3bus cycles."); $display (" (Time=%.3f, %m)",$realtime); end end always @( posedge _CEB ) begin if( DUAL_IO_READ_CMD && clk_count == 12'h18 && !clk_parity && _SCK ) begin DUAL_IO_READ_CMD <= 0; $display (" Warning : For DUAL-I/O READ command, there is no clk availabale for output data transmission. (Time=%.3f, %m)",$realtime); $display (" "); end end ///////////////////////////////////// // STATUS REGISTER mode // ///////////////////////////////////// // STATUS REGISTER READ initial STATUS_READ <= 0; always @( posedge _CEB or posedge STATUS_READ_CMD ) begin if( _CEB ) begin OE_SO <= #tCHZ 0; STATUS_READ <= 0; STATUS_READ_CMD <= 0; end else if( STATUS_READ_CMD && clk_count == 12'h08 && !clk_parity && !hold_flag ) begin if( !ac_err_com_fg ) begin OE_SO <= 1; STATUS_READ <= 1; end else begin $display (" Error : AC violation occured during STATUS READ command instruction and hence"); $display (" that command input was ignored. (Time=%.3f, %m)",$realtime); $display (" "); ac_err_com_fg <= 0; end end end always @( negedge _SCK or posedge _CEB or posedge STATUS_READ ) begin if( _CEB ) begin i = #tCHZ 0; so_out = #tCHZ SO_OUT_P; end else if( STATUS_READ && !hold_flag && !ac_err_com_fg ) begin if( i == 8 ) begin i = 0; end so_reg[7] = SRWP; so_reg[6] = 1'b0; so_reg[5] = TB; so_reg[4] = BP2; so_reg[3] = BP1; so_reg[2] = BP0; so_reg[1] = WEN; so_reg[0] = WRT; #tHO so_out = SO_OUT_P; #(tV-tHO) so_out = so_reg[7-i]; if( !_CEB ) i = i + 1; end else if( STATUS_READ && ac_err_com_fg ) begin $display (" Error : AC violation occured during STATUS READ and hence the corresponding output"); $display (" goes to indefinite momentarily. (Time=%.3f, %m)",$realtime); $display (" "); ac_err_com_fg <= 0; if( !_CEB ) begin #tHO so_out = SO_OUT_P; i = i + 1; end end end always @( posedge _CEB ) begin if( STATUS_READ_CMD && clk_count == 12'h08 && !clk_parity && _SCK ) begin $display (" Warning : For STATUS READ command, there is no clk availabale for output data transmission. (Time=%.3f, %m)",$realtime); $display (" "); end end // STATUS REGISTER WRITE initial begin WPB_store <= 0; STATUS_WRT <= 0; STATUS_WRT_CMD <= 0; end always @( posedge _CEB or posedge STATUS_WRT_CMD ) begin if( STATUS_WRT_CMD && PG_data_entry_complete && WEN && _CEB ) begin WPB_store = _WPB; STATUS_WRT_CMD = 0; #tWPH_STORE if( SRWP === 1'hX ) begin TB = 1'hX; BP2 = 1'hX; BP1 = 1'hX; BP0 = 1'hX; $display (" Error : STATUS REGISTER Non-Volatile information (SRWP) is not defined. (Time=%.3f, %m)",$realtime - tWPH_STORE ); $display (" STATUS REGISTER WRITE is not executed."); $display (" "); end else if( ( !SRWP || WPB_store ) && !ac_err_com_fg ) begin STATUS_WRT = 1; $display (" STATUS REGISTER WRITE started. (Time= %.3f, %m)", $realtime-tSRW); #(tSRW-tWPH_STORE) STATUS_WRT <= 0; SRWP = DT_CD[7]; TB = DT_CD[5]; BP2 = DT_CD[4]; BP1 = DT_CD[3]; BP0 = DT_CD[2]; $display (" STATUS REGISTER WRITE completed. (Time= %.3f, %m)", $realtime); $display (" STATUS REGISTER Non-Volatile information : Bit7(SRWP)=%h" , SRWP); $display (" : Bit5(TB)=%h" , TB); $display (" : Bit4(BP2)=%h" , BP2); $display (" : Bit3(BP1)=%h" , BP1); $display (" : Bit2(BP0)=%h" , BP0); $display (" "); end else if( SRWP == 1 && WPB_store == 0 && !ac_err_com_fg ) begin $display (" Warning : STATUS REGISTER is write protected because SRWP is Hi and WP# pin is Lo."); $display (" (Time=%.3f, %m)",$realtime); $display (" STATUS REGISTER WRITE is not executed."); $display (" STATUS REGISTER Non-Volatile information : Bit7(SRWP)=%h" , SRWP); $display (" : Bit5(TB)=%h" , TB); $display (" : Bit4(BP2)=%h" , BP2); $display (" : Bit3(BP1)=%h" , BP1); $display (" : Bit2(BP0)=%h" , BP0); $display (" "); end else if( ac_err_com_fg ) begin SRWP = 1'hX; TB = 1'hX; BP2 = 1'hX; BP1 = 1'hX; BP0 = 1'hX; $display (" Error : STATUS REGISTER WRITE failed due to AC violation in the input command sequence."); $display (" (Time=%.3f, %m)",$realtime - tWPH_STORE ); $display (" STATUS REGISTER Non-Volatile information : Bit7(SRWP)=%h" , SRWP); $display (" : Bit5(TB)=%h" , TB); $display (" : Bit4(BP2)=%h" , BP2); $display (" : Bit3(BP1)=%h" , BP1); $display (" : Bit2(BP0)=%h" , BP0); $display (" "); ac_err_com_fg <= 0; end end else if( STATUS_WRT_CMD && PG_data_entry_complete && !WEN && _CEB ) begin $display (" Warning : WEN bit is not set to 1 and hence STATUS REGISTER WRITE command was ignored. (Time=%.3f, %m)",$realtime); $display (" "); STATUS_WRT_CMD <= 0; end else if( STATUS_WRT_CMD && !single_bus_l && WEN && _CEB ) begin $display (" Error : No register data supplied and hence STATUS REGISTER WRITE command was ignored. (Time=%.3f, %m)",$realtime); $display (" "); STATUS_WRT_CMD <= 0; end else if( STATUS_WRT_CMD && two_bus_l && WEN && _CEB ) begin $display (" Error : STATUS REGISTER WRITE command ignored due to the transmitted data length is"); $display (" more than 2 bus cycles. (Time=%.3f, %m)",$realtime); $display (" "); STATUS_WRT_CMD <= 0; end else if( STATUS_WRT_CMD && !PG_data_entry_complete && WEN && _CEB ) begin $display (" Error : STATUS REGISTER WRITE command ignored due to the transmitted data length is"); $display (" less than 2 bus cycles. (Time=%.3f, %m)",$realtime); $display (" "); STATUS_WRT_CMD <= 0; end end ///////////////////////////////////// // WRITE ENABLE / DISABLE // ///////////////////////////////////// always @( posedge _CEB or posedge WRT_ENB_CMD ) begin if( WRT_ENB_CMD && !single_bus_l && _CEB ) begin if( ac_err_com_fg ) begin $display (" Error : AC violation occured and hence WRITE ENABLE command was ignored. (Time=%.3f, %m)",$realtime); $display (" "); WRT_ENB_CMD <= 0; ac_err_com_fg <= 0; end else begin WRT_ENB <= 1; WRT_ENB_CMD <= 0; end end else if( WRT_ENB_CMD && single_bus_l && _CEB ) begin $display (" Error : WRITE ENABLE command ignored due to the transmitted data length is more than 1 bus cycle . (Time=%.3f, %m)",$realtime); $display (" "); WRT_ENB_CMD <= 0; end end always @( posedge _CEB or posedge WRT_DSB_CMD ) begin if( WRT_DSB_CMD && !single_bus_l && _CEB ) begin if( ac_err_com_fg ) begin $display (" Error : AC violation occured and hence WRITE DISABLE command was ignored. (Time=%.3f, %m)",$realtime); $display (" "); WRT_DSB_CMD <= 0; ac_err_com_fg <= 0; end else begin WRT_DSB <= 1; WRT_DSB_CMD <= 0; end end else if( WRT_DSB_CMD && single_bus_l && _CEB ) begin $display (" Error : WRITE DISABLE command ignored due to the transmitted data length is more than 1 bus cycle . (Time=%.3f, %m)",$realtime); $display (" "); WRT_DSB_CMD <= 0; end end initial begin WEN <= 0; WRT_ENB <= 0; WRT_ENB_CMD <= 0; WRT_DSB <= 0; WRT_DSB_CMD <= 0; end always @( negedge WRT or posedge WRT_DSB ) begin if( WRT_DSB && !WEN ) begin $display (" Warning : WRITE DISABLE was requested while WEN bit is not set to 1. (Time=%.3f, %m)",$realtime); $display (" "); WRT_DSB <= 0; end else begin WEN <= 0; WRT_DSB <= 0; end end always @( posedge WRT_ENB ) begin if( WEN ) begin $display (" Warning : WRITE EABLE was requested while WEN bit is set to 1. (Time=%.3f, %m)",$realtime); $display (" "); WRT_ENB <= 0; end else begin WEN <= 1; WRT_ENB <= 0; end end ////////////////////////////////////////////////// // Protection level setting conditions // ///////////////////////////////////////////////// always @( negedge _CEB ) begin if( ( TB === 1'hX ) || ( BP2 === 1'hX ) || ( BP1 === 1'hX ) || ( BP0 === 1'hX ) ) prot_level = 4'hX; else if( {BP2,BP1,BP0} === 3'h0 ) prot_level = 4'h0; //no protect else if( {TB,BP2,BP1,BP0} === 4'h1 ) prot_level = 4'h1; else if( {TB,BP2,BP1,BP0} === 4'h2 ) prot_level = 4'h2; else if( {TB,BP2,BP1,BP0} === 4'h3 ) prot_level = 4'h3; else if( {TB,BP2,BP1,BP0} === 4'h4 ) prot_level = 4'h4; else if( {TB,BP2,BP1,BP0} === 4'h9 ) prot_level = 4'h9; else if( {TB,BP2,BP1,BP0} === 4'hA ) prot_level = 4'hA; else if( {TB,BP2,BP1,BP0} === 4'hB ) prot_level = 4'hB; else if( {TB,BP2,BP1,BP0} === 4'hC ) prot_level = 4'hC; else prot_level = 4'hF; //all protect //$display (" Set prot_level=%h",prot_level); end ///////////////////////////////////// // POWER DOWN mode // ///////////////////////////////////// // POWER DOWN always @( posedge _CEB or posedge PDOWN_CMD ) begin if( PDOWN_CMD && !single_bus_l && _CEB ) begin if( !ac_err_com_fg ) begin PDOWN_ENTRY <= 1; PDOWN_CMD <= 0; $display (" POWER DOWN command executed. (Time=%.3f, %m)",$realtime ); $display (" POWER DOWN state will be entered from Time=%.3f.",$realtime + tDP_STORE ); $display (" "); POWER_DOWN <= #tDP_STORE 1; PDOWN_ENTRY <= #tDP_STORE 0; end else begin $display (" Error : AC violation occured during POWER DOWN command instruction and hence that command input was ignored. (Time=%.3f, %m)",$realtime); $display (" "); PDOWN_CMD <= 0; ac_err_com_fg <= 0; end end else if( PDOWN_CMD && single_bus_l ) begin if( _CEB ) begin $display (" Error : POWER DOWN command ignored due to the transmitted data length is more than 1 bus cycle. (Time=%.3f, %m)",$realtime); $display (" "); PDOWN_CMD <= 0; end end end // POWER DOWN RELEASE always @( posedge _CEB or posedge PDOWN_RELEASE_CMD ) begin if( PDOWN_RELEASE_CMD && _CEB ) begin if( POWER_DOWN ) begin if( !ac_err_com_fg ) begin PDOWN_RELEASE <= 1; PDOWN_RELEASE_CMD <= 0; $display (" POWER DOWN RELEASE command executed. (Time=%.3f, %m)",$realtime ); $display (" POWER DOWN state will be exited from Time=%.3f.",$realtime + tPRB_STORE ); $display (" "); POWER_DOWN <= #tPRB_STORE 0; PDOWN_RELEASE <= #tPRB_STORE 0; end else begin $display (" Error : AC violation occured during POWER DOWN RELEASE command instruction and hence that command input was ignored. (Time=%.3f, %m)",$realtime); $display (" "); PDOWN_RELEASE_CMD <= 0; ac_err_com_fg <= 0; end end else if( !POWER_DOWN && clk_count < 12'h20 && !clk_parity ) begin $display (" Warning : POWER DOWN RELEASE was requested while POWER DOWN state is not entered. (Time=%.3f, %m)",$realtime); $display (" "); PDOWN_RELEASE_CMD <= 0; end end end initial begin PDOWN_CMD <= 0; PDOWN_RELEASE_CMD <= 0; POWER_DOWN <= 0; PDOWN_ENTRY <= 0; PDOWN_RELEASE <= 0; end always @( negedge _CEB ) begin if( PDOWN_ENTRY ) begin PDOWN_ENTRY <= 0; $display (" Error : POWER DOWN failed due to insufficient power down time, tDP. (Time=%.3f, %m)",$realtime); $display (" "); end else if( PDOWN_RELEASE ) begin PDOWN_RELEASE <= 0; $display (" Error : POWER DOWN RELEASE failed due to insufficient power down recovery time, tPRB. (Time=%.3f, %m)",$realtime); $display (" "); end end //////////////////////////////////// // READID mode /r //////////////////////////////////// // IDREAD_9F initial begin IDREAD_9F_CMD <= 0; IDREAD_9F <= 0; end always @( posedge _CEB or posedge IDREAD_9F_CMD ) begin if( _CEB ) begin OE_SO <= #tCHZ 0; IDREAD_9F_CMD <= 0; IDREAD_9F <= 0; end else if( clk_count == 12'h08 && !clk_parity && IDREAD_9F_CMD && !hold_flag ) begin if( !ac_err_com_fg ) begin OE_SO <= 1; IDREAD_9F <= 1; end else begin $display (" Error : AC violation occured during IDREAD_9F command instruction and hence"); $display (" that command input was ignored. (Time=%.3f, %m)",$realtime); $display (" "); ac_err_com_fg <= 0; end end end always @( negedge _SCK or posedge _CEB or posedge IDREAD_9F ) begin if( _CEB ) begin i = #tCHZ 0; m = #tCHZ 0; so_out = #tCHZ SO_OUT_P; end else if( IDREAD_9F && !hold_flag && !ac_err_com_fg ) begin if( m == 0 ) begin if( i == 8) i = 0; so_reg = 8'h62; /* SANYO */ #tHO so_out = SO_OUT_P; #(tV-tHO) so_out = so_reg[7-i]; i = i + 1; if( i == 8) m = 1; end else if( m == 1 ) begin if( i == 8) i = 0; so_reg = 8'h16; /* MEMORY TYPE */ #tHO so_out = SO_OUT_P; #(tV-tHO) so_out = so_reg[7-i]; i = i + 1; if( i == 8) m = 2; end else if( m == 2 ) begin if( i == 8) i = 0; so_reg = 8'h14; /* MEMORY CAPACITY */ #tHO so_out = SO_OUT_P; #(tV-tHO) so_out = so_reg[7-i]; i = i + 1; if( i == 8) m = 3; end else if( m == 3 ) begin if( i == 8) i = 0; so_reg = 8'h00; /* Reserved */ #tHO so_out = SO_OUT_P; #(tV-tHO) so_out = so_reg[7-i]; i = i + 1; if( i == 8) m = 0; end end else if( IDREAD_9F && ac_err_com_fg ) begin $display (" Error : AC violation occured during IDREAD_9F and hence the corresponding output"); $display (" goes to indefinite momentarily. (Time=%.3f, %m)",$realtime); $display (" "); ac_err_com_fg <= 0; if( !_CEB ) begin #tHO so_out = SO_OUT_P; i = i + 1; end end end always @( posedge _CEB ) begin if( IDREAD_9F_CMD && clk_count == 12'h08 && !clk_parity && _SCK ) begin IDREAD_9F_CMD <= 0; IDREAD_9F <= 0; $display (" Warning : For IDREAD_9F command, there is no clk availabale for output data transmission. (Time=%.3f, %m)",$realtime); $display (" "); end end // IDREAD_AB initial begin IDREAD_AB_CMD <= 0; IDREAD_AB <= 0; end always @( negedge _SCK or posedge _CEB ) begin if( _CEB ) begin OE_SO <= #tCHZ 0; IDREAD_AB_CMD <= 0; IDREAD_AB <= 0; end else if( clk_count == 12'h20 && !clk_parity && IDREAD_AB_CMD && !hold_flag ) begin if( !ac_err_com_fg ) begin OE_SO <= 1; IDREAD_AB <= 1; end else begin if( !POWER_DOWN ) begin $display (" Error : AC violation occured during IDREAD_AB command instruction and hence"); $display (" that command input was ignored. (Time=%.3f, %m)",$realtime); $display (" "); ac_err_com_fg <= 0; end end end end always @( negedge _SCK or posedge _CEB or posedge IDREAD_AB ) begin if( _CEB ) begin i = #tCHZ 0; so_out = #tCHZ SO_OUT_P; end else if( IDREAD_AB && !hold_flag && !ac_err_com_fg ) begin if( i == 8 ) begin i = 0; end so_reg = 8'h86; /* LE25S80 */ #tHO so_out = SO_OUT_P; #(tV-tHO) so_out = so_reg[7-i]; if( !_CEB ) i = i + 1; if( i == 8 ) ADDRESS[0] = 0; end else if( IDREAD_AB && ac_err_com_fg ) begin $display (" Error : AC violation occured during IDREAD_AB and hence the corresponding output"); $display (" goes to indefinite momentarily. (Time=%.3f, %m)",$realtime); $display (" "); ac_err_com_fg <= 0; if( !_CEB ) begin #tHO so_out = SO_OUT_P; i = i + 1; end end end always @( posedge _CEB ) begin if( IDREAD_AB_CMD && ( clk_count > 12'h08 && clk_count < 12'h20 ) && !clk_parity && !POWER_DOWN ) begin IDREAD_AB_CMD <= 0; $display (" Error : IDREAD_AB command ignored due to the transmitted data length is less than 4 bus cycles. (Time=%.3f, %m)",$realtime); $display (" "); end else if( IDREAD_AB_CMD && clk_count == 12'h20 && !clk_parity && _SCK && !POWER_DOWN ) begin IDREAD_AB_CMD <= 0; $display (" Warning : For IDREAD_AB command, there is no clk availabale for output data transmission. (Time=%.3f, %m)",$realtime); $display (" "); end end ///////////////////////////////////// // HOLD Function // ///////////////////////////////////// initial begin HOLD_EVENT <= 0; hold_flag <= 0; end always @( posedge _CEB or _HOLDB ) begin if( _CEB ) begin hold_flag <= 0; OE_SI <= #tCHZ 0; OE_SO <= #tCHZ 0; HOLD_EVENT <= 0; end else begin HOLD_EVENT <= 1; end end always @( posedge HOLD_EVENT ) begin if( !_CEB && !_SCK && !_HOLDB ) begin if( error_tHH_fg ) begin $display (" Error : HOLD entry function fails due to hold time violation, tHH. (Time=%.3f, %m)",$realtime); $display (" "); OE_SO <= 1'bX; OE_SI <= 1'bX; hold_flag <= 1'bX; HOLD_EVENT <= 0; error_tHH_fg <= 0; end else begin hold_flag <= 1; HOLD_EVENT <= 0; #tHHZ if ( error_tHS !== 1 && error_tHH !== 1 ) begin OE_SO <= 0; OE_SI <= 0; end end end else if( !_CEB && _HOLDB && !_SCK ) begin if( error_tHH_fg ) begin $display (" Error : HOLD release function fails due to violation in Hold time, tHH. (Time=%.3f, %m)",$realtime); $display (" "); OE_SO <= 1'bX; OE_SI <= 1'bX; hold_flag <= 1'bX; HOLD_EVENT <= 0; error_tHH_fg <= 0; end else begin hold_flag <= 0; HOLD_EVENT <= 0; if( READ || STATUS_READ || IDREAD_9F || IDREAD_AB ) begin #tHLZ if ( error_tHS !== 1 && error_tHH !== 1 ) begin OE_SO <= 1; end end else if( DUAL_READ || DUAL_IO_READ ) begin #tHLZ if ( error_tHS !== 1 && error_tHH !== 1 ) begin OE_SO <= 1; OE_SI <= 1; end end end end else if( !_CEB && !_HOLDB && _SCK ) begin $display (" Warning : HOLD entry function cannot accept during EXSCK=1. (Time=%.3f, %m)",$realtime); $display (" "); HOLD_EVENT <= 0; end else if( !_CEB && _HOLDB && _SCK ) begin $display (" Warning : HOLD release function cannot accept during EXSCK=1. (Time=%.3f, %m)",$realtime); $display (" "); HOLD_EVENT <= 0; end end always @( posedge error_tHS_fg ) begin if( !_CEB && !_HOLDB && _SCK ) begin $display (" Error : HOLD entry function fails due to setup time violation, tHS. (Time=%.3f, %m)",$realtime); $display (" "); OE_SO <= 1'bX; OE_SI <= 1'bX; hold_flag <= 1'bX; error_tHS_fg <= 0; end else if( !_CEB && _HOLDB && _SCK ) begin $display (" Error : HOLD release function fails due to violation in Hold time, tHS. (Time=%.3f, %m)",$realtime); $display (" "); OE_SO <= 1'bX; OE_SI <= 1'bX; hold_flag <= 1'bX; error_tHS_fg <= 0; end end always @( negedge _CEB ) begin if( !_CEB && !_HOLDB ) begin hold_flag <= 1; end end always @( SCK ) begin if( !_CEB & _HOLDB === 1'bX ) begin $display (" Error : HOLD pin is not certain. (Time=%.3f, %m)",$realtime); $display (" "); hold_flag <= 1'bX; end end ///////////////////////////////////// // WRITE status // ///////////////////////////////////// assign WRT = SSERASE | SERASE | PROG | CERASE | STATUS_WRT; ///////////////////////////////////// // WRITE setup // ///////////////////////////////////// always @( posedge _SCK ) begin if( clk_count[2:0] == 3'h7 && !_CEB) every8bit <= 1; if( clk_count[2:0] == 3'h0 && !_CEB) every8bit <= 0; end always @(_SCK ) begin //check only for 1 bus cycle if( clk_count == 12'h8 && !clk_parity && !_CEB && _SCK) single_bus_l <= 1; //check only for 2 bus cycles if( clk_count == 12'h10 && !clk_parity && !_CEB && _SCK) two_bus_l <= 1; //check only for 4 bus cycles if( clk_count == 12'h20 && !clk_parity && !_CEB && _SCK) four_bus_l <= 1; end always @( negedge _CEB ) begin if( !_CEB ) begin every8bit <= 0; single_bus_l <= 0; two_bus_l <= 0; four_bus_l <= 0; end end ///////////////////////////////////// // ERASE mode // ///////////////////////////////////// /* SMALL SECTOR ERASE */ initial begin SSERASE <= 0; SSERASE_preset <= 0; SSERASE_CMD <= 0; write_flag <= 0; end always @( posedge _CEB ) begin if( clk_count < 12'h20 && !clk_parity && SSERASE_CMD && _CEB ) begin SSERASE_CMD <= 0; $display (" Error : SMALL SECTOR ERASE command ignored due to the transmitted data length is less than 4 bus cycles. (Time=%.3f, %m)",$realtime); $display (" "); end else if( clk_count == 12'h20 && !clk_parity && SSERASE_CMD && _CEB ) begin SSERASE_preset <= 1; end else if( ( clk_count > 12'h20 || clk_parity ) && SSERASE_CMD && _CEB ) begin $display (" Error : SMALL SECTOR ERASE command ignored due to the transmitted data length is"); $display (" more than 4 bus cycles. (Time=%.3f, %m)",$realtime); $display (" "); SSERASE_CMD <= 0; end end always @( negedge WRT ) begin if( !WRT ) begin write_flag <= 0; j = 0; l = 0; end end always @( posedge SSERASE_preset ) begin if( SSERASE_CMD && SSERASE_preset && !four_bus_l && WEN ) begin if( _CEB ) begin SSERASE_preset = 0; SSERASE_CMD = 0; case( prot_level ) 4'hX : write_flag = 0; 4'hF : write_flag = 0; 4'hC : begin if( ADDRESS_ssers > 8'h7F ) write_flag = 1; else write_flag = 0; end 4'hB : begin if( ADDRESS_ssers > 8'h3F ) write_flag = 1; else write_flag = 0; end 4'hA : begin if( ADDRESS_ssers > 8'h1F ) write_flag = 1; else write_flag = 0; end 4'h9 : begin if( ADDRESS_ssers > 8'h0F ) write_flag = 1; else write_flag = 0; end 4'h4 : begin if( ADDRESS_ssers < 8'h80 ) write_flag = 1; else write_flag = 0; end 4'h3 : begin if( ADDRESS_ssers < 8'hC0 ) write_flag = 1; else write_flag = 0; end 4'h2 : begin if( ADDRESS_ssers < 8'hE0 ) write_flag = 1; else write_flag = 0; end 4'h1 : begin if( ADDRESS_ssers < 8'hF0 ) write_flag = 1; else write_flag = 0; end 4'h0 : write_flag = 1; default write_flag = 0; endcase SSERS_START_ADD = { ADDRESS_ssers, 12'h000 }; SSERS_END_ADD = { ADDRESS_ssers, 12'hFFF }; if( ac_err_com_fg ) begin for ( j = SSERS_START_ADD; j <= SSERS_END_ADD; j = j + 1 ) begin fmemory[j] = 8'hXX; end $display (" Error : SMALL SECTOR ERASE failed due to AC violation in the input command sequence."); $display (" (Time=%.3f, %m)",$realtime); for ( j = SSERS_START_ADD; j <= SSERS_START_ADD + 7; j = j + 1 ) begin $display ("Flashmemory Address=%h : Data=%h", j, fmemory[j]); end $display (" :"); $display (" :"); $display (" :"); $display ("Flashmemory Address=%h : Data=%h", SSERS_END_ADD-1, fmemory[SSERS_END_ADD-1]); $display ("Flashmemory Address=%h : Data=%h", SSERS_END_ADD-0, fmemory[SSERS_END_ADD]); $display (" "); ac_err_com_fg <= 0; end else if( !write_flag ) begin if( prot_level === 4'hX ) $display (" Error : STATUS REGISTER Non-Volatile information is not defined. (Time=%.3f, %m)",$realtime); else if( prot_level == 4'hF ) $display (" Warning : Entire chip area is write protected. (Time=%.3f, %m)",$realtime); else if( prot_level == 4'hC ) $display (" Warning : Address=7ffff~00000 is write protected. (Time=%.3f, %m)",$realtime); else if( prot_level == 4'hB ) $display (" Warning : Address=3ffff~00000 is write protected. (Time=%.3f, %m)",$realtime); else if( prot_level == 4'hA ) $display (" Warning : Address=1ffff~00000 is write protected. (Time=%.3f, %m)",$realtime); else if( prot_level == 4'h9 ) $display (" Warning : Address=0ffff~00000 is write protected. (Time=%.3f, %m)",$realtime); else if( prot_level == 4'h4 ) $display (" Warning : Address=fffff~80000 is write protected. (Time=%.3f, %m)",$realtime); else if( prot_level == 4'h3 ) $display (" Warning : Address=fffff~c0000 is write protected. (Time=%.3f, %m)",$realtime); else if( prot_level == 4'h2 ) $display (" Warning : Address=fffff~e0000 is write protected. (Time=%.3f, %m)",$realtime); else if( prot_level == 4'h1 ) $display (" Warning : Address=fffff~f0000 is write protected. (Time=%.3f, %m)",$realtime); $display (" SMALL SECTOR ERASE is not executed."); for ( j = SSERS_START_ADD; j <= SSERS_START_ADD + 7; j = j + 1 ) begin $display ("Flashmemory Address=%h : Data=%h", j, fmemory[j]); end $display (" :"); $display (" :"); $display (" :"); $display ("Flashmemory Address=%h : Data=%h", SSERS_END_ADD-1, fmemory[SSERS_END_ADD-1]); $display ("Flashmemory Address=%h : Data=%h", SSERS_END_ADD-0, fmemory[SSERS_END_ADD]); $display (" "); end else if( write_flag ) begin SSERASE = 1; $display (" SMALL SECTOR ERASE started ...... (Time= %.3f, %m)", $realtime); #tSSE SSERASE <= 0; for ( j = SSERS_START_ADD; j <= SSERS_END_ADD; j = j + 1 ) begin fmemory[j] = 8'hFF; end $display (" SMALL SECTOR ERASE completed. (Time= %.3f, %m)", $realtime ); for ( j = SSERS_START_ADD; j <= SSERS_START_ADD + 7; j = j + 1 ) begin $display ("Flashmemory Address=%h : Data=%h", j, fmemory[j]); end $display (" :"); $display (" :"); $display (" :"); $display ("Flashmemory Address=%h : Data=%h", SSERS_END_ADD-1, fmemory[SSERS_END_ADD-1]); $display ("Flashmemory Address=%h : Data=%h", SSERS_END_ADD-0, fmemory[SSERS_END_ADD]); $display (" "); end end end else if( SSERASE_CMD && SSERASE_preset && !four_bus_l && !WEN ) begin $display (" Warning : WEN bit is not set to 1 and hence SMALL SECTOR ERASE command was ignored. (Time=%.3f, %m)",$realtime); $display (" "); SSERASE_CMD <= 0; SSERASE_preset <= 0; end end /* SECTOR ERASE */ initial begin SERASE <= 0; SERASE_preset <= 0; SERASE_CMD <= 0; write_flag <= 0; end always @( posedge _CEB ) begin if( clk_count < 12'h20 && !clk_parity && SERASE_CMD && _CEB ) begin SERASE_CMD <= 0; $display (" Error : SECTOR ERASE command ignored due to the transmitted data length is less than 4 bus cycles. (Time=%.3f, %m)",$realtime); $display (" "); end else if( clk_count == 12'h20 && !clk_parity && SERASE_CMD && _CEB ) begin SERASE_preset <= 1; end else if( ( clk_count > 12'h20 || clk_parity ) && SERASE_CMD && _CEB ) begin $display (" Error : SECTOR ERASE command ignored due to the transmitted data length is"); $display (" more than 4 bus cycles. (Time=%.3f, %m)",$realtime); $display (" "); SERASE_CMD <= 0; end end always @( negedge WRT ) begin if( !WRT ) begin write_flag <= 0; j = 0; l = 0; end end always @( posedge SERASE_preset ) begin if( SERASE_CMD && SERASE_preset && !four_bus_l && WEN ) begin if( _CEB ) begin SERASE_preset = 0; SERASE_CMD = 0; case( prot_level ) 4'hX : write_flag = 0; 4'hF : write_flag = 0; 4'hC : begin if( ADDRESS_sers > 4'h7 ) write_flag = 1; else write_flag = 0; end 4'hB : begin if( ADDRESS_sers > 4'h3 ) write_flag = 1; else write_flag = 0; end 4'hA : begin if( ADDRESS_sers > 4'h1 ) write_flag = 1; else write_flag = 0; end 4'h9 : begin if( ADDRESS_sers > 4'h0 ) write_flag = 1; else write_flag = 0; end 4'h4 : begin if( ADDRESS_sers < 4'h8 ) write_flag = 1; else write_flag = 0; end 4'h3 : begin if( ADDRESS_sers < 4'hC ) write_flag = 1; else write_flag = 0; end 4'h2 : begin if( ADDRESS_sers < 4'hE ) write_flag = 1; else write_flag = 0; end 4'h1 : begin if( ADDRESS_sers < 4'hF ) write_flag = 1; else write_flag = 0; end 4'h0 : write_flag = 1; default write_flag = 0; endcase SERS_START_ADD = { ADDRESS_sers, 16'h0000 }; SERS_END_ADD = { ADDRESS_sers, 16'hFFFF }; if( ac_err_com_fg ) begin for ( j = SERS_START_ADD; j <= SERS_END_ADD; j = j + 1 ) begin fmemory[j] = 8'hXX; end $display (" Error : SECTOR ERASE failed due to AC violation in the input command sequence."); $display (" (Time=%.3f, %m)",$realtime); for ( j = SERS_START_ADD; j <= SERS_START_ADD + 7; j = j + 1 ) begin $display ("Flashmemory Address=%h : Data=%h", j, fmemory[j]); end $display (" :"); $display (" :"); $display (" :"); $display ("Flashmemory Address=%h : Data=%h", SERS_END_ADD-1, fmemory[SERS_END_ADD-1]); $display ("Flashmemory Address=%h : Data=%h", SERS_END_ADD-0, fmemory[SERS_END_ADD]); $display (" "); ac_err_com_fg <= 0; end else if( !write_flag ) begin if( prot_level === 4'hX ) $display (" Error : STATUS REGISTER Non-Volatile information is not defined. (Time=%.3f, %m)",$realtime); else if( prot_level == 4'hF ) $display (" Warning : Entire chip area is write protected. (Time=%.3f, %m)",$realtime); else if( prot_level == 4'hC ) $display (" Warning : Address=7ffff~00000 is write protected. (Time=%.3f, %m)",$realtime); else if( prot_level == 4'hB ) $display (" Warning : Address=3ffff~00000 is write protected. (Time=%.3f, %m)",$realtime); else if( prot_level == 4'hA ) $display (" Warning : Address=1ffff~00000 is write protected. (Time=%.3f, %m)",$realtime); else if( prot_level == 4'h9 ) $display (" Warning : Address=0ffff~00000 is write protected. (Time=%.3f, %m)",$realtime); else if( prot_level == 4'h4 ) $display (" Warning : Address=fffff~80000 is write protected. (Time=%.3f, %m)",$realtime); else if( prot_level == 4'h3 ) $display (" Warning : Address=fffff~c0000 is write protected. (Time=%.3f, %m)",$realtime); else if( prot_level == 4'h2 ) $display (" Warning : Address=fffff~e0000 is write protected. (Time=%.3f, %m)",$realtime); else if( prot_level == 4'h1 ) $display (" Warning : Address=fffff~f0000 is write protected. (Time=%.3f, %m)",$realtime); $display (" SECTOR ERASE is not executed."); for ( j = SERS_START_ADD; j <= SERS_START_ADD + 7; j = j + 1 ) begin $display ("Flashmemory Address=%h : Data=%h", j, fmemory[j]); end $display (" :"); $display (" :"); $display (" :"); $display ("Flashmemory Address=%h : Data=%h", SERS_END_ADD-1, fmemory[SERS_END_ADD-1]); $display ("Flashmemory Address=%h : Data=%h", SERS_END_ADD-0, fmemory[SERS_END_ADD]); $display (" "); end else if( write_flag ) begin SERASE = 1; $display (" SECTOR ERASE started ...... (Time= %.3f, %m)", $realtime); #tSE SERASE <= 0; for ( j = SERS_START_ADD; j <= SERS_END_ADD; j = j + 1 ) begin fmemory[j] = 8'hFF; end $display (" SECTOR ERASE completed. (Time= %.3f, %m)", $realtime ); for ( j = SERS_START_ADD; j <= SERS_START_ADD + 7; j = j + 1 ) begin $display ("Flashmemory Address=%h : Data=%h", j, fmemory[j]); end $display (" :"); $display (" :"); $display (" :"); $display ("Flashmemory Address=%h : Data=%h", SERS_END_ADD-1, fmemory[SERS_END_ADD-1]); $display ("Flashmemory Address=%h : Data=%h", SERS_END_ADD-0, fmemory[SERS_END_ADD]); $display (" "); end end end else if( SERASE_CMD && SERASE_preset && !four_bus_l && !WEN ) begin $display (" Warning : WEN bit is not set to 1 and hence SECTOR ERASE command was ignored. (Time=%.3f, %m)",$realtime); $display (" "); SERASE_CMD <= 0; SERASE_preset <= 0; end end /* CHIP ERASE */ initial begin CERASE <= 0; CERASE_CMD <= 0; end always @( negedge WRT ) begin if( !WRT ) begin k = 0; end end always @( posedge _CEB or posedge CERASE_CMD ) begin if( CERASE_CMD && !single_bus_l && _CEB && WEN ) begin CERASE_CMD = 0; case( prot_level ) 4'hX : write_flag = 0; 4'hF : write_flag = 0; 4'hC : write_flag = 0; 4'hB : write_flag = 0; 4'hA : write_flag = 0; 4'h9 : write_flag = 0; 4'h4 : write_flag = 0; 4'h3 : write_flag = 0; 4'h2 : write_flag = 0; 4'h1 : write_flag = 0; 4'h0 : write_flag = 1; default write_flag = 0; endcase if( ac_err_com_fg ) begin for ( k = 0; k < MEMORY_SIZE; k = k + 1 ) begin fmemory[k] = 8'hXX; end $display (" Error : CHIP ERASE failed due to AC violation in the input command sequence."); $display (" (Time=%.3f, %m)",$realtime); for ( j = 0; j <= 7; j = j + 1 ) begin $display ("Flashmemory Address=%h : Data=%h", j, fmemory[j]); end $display (" :"); $display (" :"); $display (" :"); $display ("Flashmemory Address=%h : Data=%h", MEMORY_SIZE-2, fmemory[MEMORY_SIZE-2]); $display ("Flashmemory Address=%h : Data=%h", MEMORY_SIZE-1, fmemory[MEMORY_SIZE-1]); $display (" "); ac_err_com_fg <= 0; end else if( !write_flag ) begin if( prot_level === 4'hX ) $display (" Error : STATUS REGISTER Non-Volatile information is not defined. (Time=%.3f, %m)",$realtime); else if( prot_level == 4'hF ) $display (" Warning : Entire chip area is write protected. (Time=%.3f, %m)",$realtime); else if( prot_level == 4'hC ) $display (" Warning : Address=7ffff~00000 is write protected. (Time=%.3f, %m)",$realtime); else if( prot_level == 4'hB ) $display (" Warning : Address=3ffff~00000 is write protected. (Time=%.3f, %m)",$realtime); else if( prot_level == 4'hA ) $display (" Warning : Address=1ffff~00000 is write protected. (Time=%.3f, %m)",$realtime); else if( prot_level == 4'h9 ) $display (" Warning : Address=0ffff~00000 is write protected. (Time=%.3f, %m)",$realtime); else if( prot_level == 4'h4 ) $display (" Warning : Address=fffff~80000 is write protected. (Time=%.3f, %m)",$realtime); else if( prot_level == 4'h3 ) $display (" Warning : Address=fffff~c0000 is write protected. (Time=%.3f, %m)",$realtime); else if( prot_level == 4'h2 ) $display (" Warning : Address=fffff~e0000 is write protected. (Time=%.3f, %m)",$realtime); else if( prot_level == 4'h1 ) $display (" Warning : Address=fffff~f0000 is write protected. (Time=%.3f, %m)",$realtime); $display (" CHIP ERASE is not executed."); for ( j = 0; j <= 7; j = j + 1 ) begin $display ("Flashmemory Address=%h : Data=%h", j, fmemory[j]); end $display (" :"); $display (" :"); $display (" :"); $display ("Flashmemory Address=%h : Data=%h", MEMORY_SIZE-2, fmemory[MEMORY_SIZE-2]); $display ("Flashmemory Address=%h : Data=%h", MEMORY_SIZE-1, fmemory[MEMORY_SIZE-1]); $display (" "); end else if( write_flag ) begin CERASE = 1; $display (" CHIP ERASE started...... (Time= %.3f, %m)", $realtime); #tCHE CERASE <= 0; for ( k = 0; k < MEMORY_SIZE; k = k + 1 ) begin fmemory[k] = 8'hFF; end $display (" CHIP ERASE completed. (Time= %.3f, %m)", $realtime ); for ( j = 0; j <= 7; j = j + 1 ) begin $display ("Flashmemory Address=%h : Data=%h", j, fmemory[j]); end $display (" :"); $display (" :"); $display (" :"); $display ("Flashmemory Address=%h : Data=%h", MEMORY_SIZE-2, fmemory[MEMORY_SIZE-2]); $display ("Flashmemory Address=%h : Data=%h", MEMORY_SIZE-1, fmemory[MEMORY_SIZE-1]); $display (" "); end end else if( CERASE_CMD && !single_bus_l && _CEB && !WEN ) begin $display (" Warning : WEN bit is not set to 1 and hence CHIP ERASE command was ignored. (Time=%.3f, %m)",$realtime); $display (" "); CERASE_CMD <= 0; end else if( CERASE_CMD && single_bus_l && _CEB && WEN ) begin $display (" Error : CHIP ERASE command ignored due to the transmitted data length is"); $display (" more than 1 bus cycle. (Time=%.3f, %m)",$realtime); $display (" "); CERASE_CMD <= 0; end end ///////////////////////////////////// // PROG mode // ///////////////////////////////////// /* Prog Address latch */ always @( posedge _CEB ) begin if( clk_count < 12'h20 && !clk_parity && PROG_CMD && _CEB ) begin $display (" Error : Input command sequence less than 4 bus cycles and hence PAGE PROGRAM command was ignored. (Time=%.3f, %m)",$realtime); $display (" "); PROG_CMD <= 0; end else if( clk_count == 12'h20 && !clk_parity && PROG_CMD &_CEB ) begin $display (" Error : No program data supplied and hence PAGE PROGRAM command was ignored. (Time=%.3f, %m)",$realtime); $display (" "); PROG_CMD <= 0; end else if( ( clk_count > 12'h20 || clk_parity ) && every8bit && PROG_CMD && _CEB ) begin PROG_preset <= 1; end else if( ( clk_count > 12'h20 || clk_parity ) && !every8bit && PROG_CMD && _CEB ) begin PROG_CMD = 0; $display (" Error : PAGE PROGRAM command ignored due to the last transmitted data before _CEB going high is"); $display (" less or more than a byte unit. (Time=%.3f, %m)",$realtime); $display (" "); end end always @( posedge _SCK ) begin if( clk_count == 12'h20 && !clk_parity && PROG_CMD && !_CEB ) begin ADDRESS_prg <= ADDRESS; end end /* PAGE PROG */ initial begin PROG <= 0; PROG_preset <= 0; PROG_CMD <= 0; end always @( posedge PROG_preset ) begin if( PROG_CMD && PROG_preset && PG_data_entry_complete && WEN ) begin PROG_preset = 0; PROG_CMD = 0; no_erase_dat_fg = 0; no_erase_fg = 0; ADDRESS_page = ADDRESS_prg[ADDRESS_SIZE-1:8]; ADDRESS_inc = ADDRESS_prg[7:0]; case( prot_level ) 4'hX : write_flag = 0; 4'hF : write_flag = 0; 4'hC : begin if( ADDRESS_page > 12'h7FF ) write_flag = 1; else write_flag = 0; end 4'hB : begin if( ADDRESS_page > 12'h3FF ) write_flag = 1; else write_flag = 0; end 4'hA : begin if( ADDRESS_page > 12'h1FF ) write_flag = 1; else write_flag = 0; end 4'h9 : begin if( ADDRESS_page > 12'h0FF ) write_flag = 1; else write_flag = 0; end 4'h4 : begin if( ADDRESS_page < 12'h800 ) write_flag = 1; else write_flag = 0; end 4'h3 : begin if( ADDRESS_page < 12'hC00 ) write_flag = 1; else write_flag = 0; end 4'h2 : begin if( ADDRESS_page < 12'hE00 ) write_flag = 1; else write_flag = 0; end 4'h1 : begin if( ADDRESS_page < 12'hF00 ) write_flag = 1; else write_flag = 0; end 4'h0 : write_flag = 1; endcase if( ac_err_com_fg ) begin PROG <= 0; $display (" Error : PAGE PROGRAM failed due to AC violation in the input command sequence."); $display (" (Time= %.3f, %m)", $realtime); ADDRESS_inc = ADDRESS_inc + l; for ( n = j; n > l; n = n - 1 ) begin PG_PROG_STORE_ADD = { ADDRESS_page, ADDRESS_inc }; fmemory[PG_PROG_STORE_ADD] = 8'hXX; $display ("Flashmemory Address=%h : Data=%h", PG_PROG_STORE_ADD, fmemory[PG_PROG_STORE_ADD]); ADDRESS_inc = ADDRESS_inc + 1; end $display (" "); ac_err_com_fg <= 0; end else if( !write_flag ) begin if( prot_level === 4'hX ) $display (" Error : STATUS REGISTER Non-Volatile information is not defined. (Time=%.3f, %m)",$realtime); else if( prot_level == 4'hF ) $display (" Warning : Entire chip area is write protected. (Time=%.3f, %m)",$realtime); else if( prot_level == 4'hC ) $display (" Warning : Address=7ffff~00000 is write protected. (Time=%.3f, %m)",$realtime); else if( prot_level == 4'hB ) $display (" Warning : Address=3ffff~00000 is write protected. (Time=%.3f, %m)",$realtime); else if( prot_level == 4'hA ) $display (" Warning : Address=1ffff~00000 is write protected. (Time=%.3f, %m)",$realtime); else if( prot_level == 4'h9 ) $display (" Warning : Address=0ffff~00000 is write protected. (Time=%.3f, %m)",$realtime); else if( prot_level == 4'h4 ) $display (" Warning : Address=fffff~80000 is write protected. (Time=%.3f, %m)",$realtime); else if( prot_level == 4'h3 ) $display (" Warning : Address=fffff~c0000 is write protected. (Time=%.3f, %m)",$realtime); else if( prot_level == 4'h2 ) $display (" Warning : Address=fffff~e0000 is write protected. (Time=%.3f, %m)",$realtime); else if( prot_level == 4'h1 ) $display (" Warning : Address=fffff~f0000 is write protected. (Time=%.3f, %m)",$realtime); $display (" PAGE PROGRAM is not executed."); ADDRESS_inc = ADDRESS_inc + l; for ( n = j; n > l; n = n - 1 ) begin PG_PROG_STORE_ADD = { ADDRESS_page, ADDRESS_inc }; $display ("Flashmemory Address=%h : Data=%h", PG_PROG_STORE_ADD, fmemory[PG_PROG_STORE_ADD]); ADDRESS_inc = ADDRESS_inc + 1; end $display (" "); end else if( write_flag ) begin PROG = 1; for(y = 0; y < j; y = y + 1 ) begin for(x = 0; x < 8; x = x + 1) tmp[x] = fmpage[8*y+x]; page[y] = tmp; end ADDRESS_inc = ADDRESS_inc + l; for ( n = j; n > l; n = n - 1 ) begin PG_PROG_STORE_ADD = { ADDRESS_page, ADDRESS_inc }; befor_data = fmemory[PG_PROG_STORE_ADD]; if( befor_data === 8'hXX ) begin no_erase_dat_fg = 1; n = 0; end else if( befor_data !== 8'hFF ) begin no_erase_fg = 1; n = 0; end ADDRESS_inc = ADDRESS_inc + 1; end ADDRESS_page = ADDRESS_prg[ADDRESS_SIZE-1:8]; ADDRESS_inc = ADDRESS_prg[7:0]; if( no_erase_dat_fg ) begin PROG <= 0; $display (" Error : You have to execute ERASE at the requested addresses before PAGE PROGRAM command execute. (Time= %.3f, %m)", $realtime); ADDRESS_inc = ADDRESS_inc + l; for ( n = j; n > l; n = n - 1 ) begin PG_PROG_STORE_ADD = { ADDRESS_page, ADDRESS_inc }; fmemory[PG_PROG_STORE_ADD] = 8'hXX; $display ("Flashmemory Address=%h : Data=%h", PG_PROG_STORE_ADD, fmemory[PG_PROG_STORE_ADD]); ADDRESS_inc = ADDRESS_inc + 1; end $display (" "); end else if( no_erase_fg ) begin PROG <= 0; $display (" Error : PAGE PROGRAM failed because there is some data other than FFh at the requested addresses."); $display (" (Time= %.3f, %m)", $realtime); ADDRESS_inc = ADDRESS_inc + l; for ( n = j; n > l; n = n - 1 ) begin PG_PROG_STORE_ADD = { ADDRESS_page, ADDRESS_inc }; fmemory[PG_PROG_STORE_ADD] = 8'hXX; $display ("Flashmemory Address=%h : Data=%h", PG_PROG_STORE_ADD, fmemory[PG_PROG_STORE_ADD]); ADDRESS_inc = ADDRESS_inc + 1; end $display (" "); end else begin $display(" PAGE PROGRAM started ...... (Time=%.3f, %m)",$realtime) ; #tPP PROG <= 0; ADDRESS_inc = ADDRESS_inc + l; $display (" PAGE PROGRAM completed. (Time= %.3f, %m)", $realtime ); for ( n = j; n > l; n = n - 1 ) begin PG_PROG_STORE_ADD = { ADDRESS_page, ADDRESS_inc }; fmemory[PG_PROG_STORE_ADD] = page[n-l-1]; $display ("Flashmemory Address=%h : Data=%h", PG_PROG_STORE_ADD, fmemory[PG_PROG_STORE_ADD]); ADDRESS_inc = ADDRESS_inc + 1; end $display (" "); end end end else if( PROG_CMD && PROG_preset && PG_data_entry_complete && !WEN ) begin $display (" Warning : WEN bit is not set to 1 and hence PAGE PROGRAM command was ignored. (Time=%.3f, %m)",$realtime); $display (" "); PROG_CMD <= 0; PROG_preset <= 0; end end ///////////////////////////////////// // Timing check // ///////////////////////////////////// not I0 ( cs, CEB ); buf I1 ( pdown_entry, PDOWN_ENTRY ); buf I2 ( pdown_release, PDOWN_RELEASE ); buf I3 ( dual_read_entry, DUAL_READ_ENT ); buf I4 ( dual_io_read_entry, DUAL_IO_READ_ENT ); or I5 ( read_output, READ, DUAL_READ, DUAL_IO_READ, STATUS_READ, IDREAD_9F, IDREAD_AB ); and I6 ( command_entry, cs, ~read_output, ~DUAL_READ_CMD, ~DUAL_IO_READ_CMD ); buf I7 ( read_03h, READ4_CMD ); initial begin ac_err_com_fg <= 0; error_tHS_fg <= 0; error_tHH_fg <= 0; error_tCLHI <= 0; error_tCLLO <= 0; error_tCLHI2 <= 0; error_tCLLO2 <= 0; error_tCSS <= 0; error_tCSH <= 0; error_tDS <= 0; error_tDH <= 0; error_tCPH <= 0; error_tHS <= 0; error_tHH <= 0; error_tWPS <= 0; error_tWPH <= 0; error_tDP <= 0; error_tPRB <= 0; end always @( error_tCLHI or error_tCLLO or error_tCLHI2 or error_tCLLO2 or error_tCSS or error_tCSH or error_tDS or error_tDH or error_tCPH or error_tHS or error_tHH or error_tWPS or error_tWPH or error_tDP or error_tPRB ) begin if ( error_tCLHI || error_tCLLO || error_tCLHI2 || error_tCLLO2 || error_tCSS || error_tCSH || error_tDS || error_tDH || error_tCPH || error_tHS || error_tHH || error_tWPS || error_tWPH || error_tDP || error_tPRB ) begin ac_err_com_fg <= 1; end end always @( error_tHS or posedge _CEB ) begin if( _CEB ) error_tHS_fg <= 0; else error_tHS_fg <= 1; end always @( error_tHH or posedge _CEB ) begin if( _CEB ) error_tHH_fg <= 0; else error_tHH_fg <= 1; end specify specparam tCLHI =tCLHI_TIME; specparam tCLLO =tCLLO_TIME; specparam tCLHI2 =tCLHI2_TIME; specparam tCLLO2 =tCLLO2_TIME; specparam tCSS =tCSS_TIME; specparam tCSH =tCSH_TIME; specparam tDS =tDS_TIME; specparam tDH =tDH_TIME; specparam tCPH =tCPH_TIME; specparam tHS =tHS_TIME; specparam tHH =tHH_TIME; specparam tWPS =tWPS_TIME; specparam tWPH =tWPH_TIME; specparam tDP =tDP_TIME; specparam tPRB =tPRB_TIME; $width ( posedge SCK, tCLHI, 0, error_tCLHI ); $width ( negedge SCK, tCLLO, 0, error_tCLLO ); $width ( posedge SCK &&& read_03h, tCLHI2, 0, error_tCLHI2 ); $width ( negedge SCK &&& read_03h, tCLLO2, 0, error_tCLLO2 ); $setup ( CEB, posedge SCK, tCSS, error_tCSS ); $hold ( posedge SCK, CEB, tCSH, error_tCSH ); $setup ( SI &&& command_entry, posedge SCK, tDS, error_tDS ); $hold ( posedge SCK, SI &&& command_entry, tDH, error_tDH ); $setup ( SI &&& dual_read_entry, posedge SCK, tDS, error_tDS ); $hold ( posedge SCK, SI &&& dual_read_entry, tDH, error_tDH ); $setup ( SO &&& dual_read_entry, posedge SCK, tDS, error_tDS ); $hold ( posedge SCK, SO &&& dual_read_entry, tDH, error_tDH ); $setup ( SI &&& dual_io_read_entry, posedge SCK, tDS, error_tDS ); $hold ( posedge SCK, SI &&& dual_io_read_entry, tDH, error_tDH ); $setup ( SO &&& dual_io_read_entry, posedge SCK, tDS, error_tDS ); $hold ( posedge SCK, SO &&& dual_io_read_entry, tDH, error_tDH ); $width ( posedge CEB, tCPH, 0, error_tCPH ); $setup ( HOLDB, posedge SCK, tHS, error_tHS ); $hold ( negedge SCK, HOLDB, tHH, error_tHH ); $setup ( WPB, negedge CEB, tWPS, error_tWPS ); $hold ( posedge CEB, WPB, tWPH, error_tWPH ); $width ( posedge pdown_entry, tDP, 0, error_tDP ); $width ( posedge pdown_release, tPRB, 0, error_tPRB ); endspecify //endprotect endmodule
这里,我们增加了一个宏:
define DBG_MODE
如果定义这个宏, 就是我们的测试模式spix1, si 为input, so 为 output 如果没有定义, 则是厂家的标准模式 si,so 都是inout 。 到此,我们就有了一个标准的flash 芯片, 在仿真工程中就可以专心致志的编译controller 代码了