在学习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 don`t 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 / 10ps
`define 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
//`protect
`define tCLHI_TIME 11.5
`define tCLLO_TIME 11.5
`define tCLHI2_TIME 14 // READ(03h)
`define tCLLO2_TIME 14 // READ(03h)
`define tCSS_TIME 10
`define tCSH_TIME 10
`define tDS_TIME 5
`define tDH_TIME 5
`define tCPH_TIME 25
`define tCHZ_TIME 15
`define tV_TIME 11
`define tHO_TIME 1
`define tHS_TIME 5
`define tHH_TIME 5
`define tHLZ_TIME 12
`define tHHZ_TIME 9
`define tWPS_TIME 20
`define tWPH_TIME 20
`define tDP_TIME 5_000
`define tPRB_TIME 500_000
`ifdef shortsim
`define tPP_TIME 15_000
`define tSSE_TIME 60_000
`define tSE_TIME 60_000
`define tCHE_TIME 60_000
`define 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 (" ");
end
`else
`define tPP_TIME 1_000_000
`define tSSE_TIME 150_000_000
`define tSE_TIME 250_000_000
`define tCHE_TIME 34'd6_000_000_000
`define tSRW_TIME 10_000_000
`endif
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_MODE
`else
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
end
`ifdef 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 代码了