OpenCores
URL https://opencores.org/ocsvn/cfi_ctrl/cfi_ctrl/trunk

Subversion Repositories cfi_ctrl

Compare Revisions

  • This comparison shows the changes necessary to convert path
    /
    from Rev 1 to Rev 2
    Reverse comparison

Rev 1 → Rev 2

/cfi_ctrl/trunk/bench/verilog/cfi_ctrl_wb_bench.v
0,0 → 1,444
/* Testbench of Wishbone classic-slave wrapped basic CFI controller */
 
`include "def.h"
`include "data.h"
 
`timescale 1ns/1ps
 
module cfi_ctrl_wb_bench();
 
 
// Signal Bus
wire [`ADDRBUS_dim - 1:0] A; // Address Bus
wire [`DATABUS_dim - 1:0] DQ; // Data I/0 Bus
// Control Signal
wire WE_N; // Write Enable
wire OE_N; // Output Enable
wire CE_N; // Chip Enable
wire RST_N; // Reset
wire WP_N; // Write Protect
wire ADV_N; // Latch Enable
wire CLK; // Clock
wire WAIT; // Wait
 
// Voltage signal rappresentad by integer Vector which correspond to millivolts
wire [`Voltage_range] VCC; // Supply Voltage
wire [`Voltage_range] VCCQ; // Supply Voltage for I/O Buffers
wire [`Voltage_range] VPP; // Optional Supply Voltage for Fast Program & Erase
 
//wire STS;
wire Info; // Activate/Deactivate info device operation
assign Info = 1;
assign VCC = 36'd1700;
assign VCCQ = 36'd1700;
assign VPP = 36'd2000;
 
parameter sys_clk_half_period = 15.15/2; /* 66MHz */
parameter sys_clk_period = sys_clk_half_period*2;
reg sys_clk;
reg sys_rst;
 
initial begin
sys_clk = 0;
forever
#sys_clk_half_period sys_clk = ~sys_clk;
end
initial begin
sys_rst = 1;
#sys_clk_period;
#sys_clk_period;
sys_rst = 0;
end
 
reg [31:0] wb_adr_i;
reg [31:0] wb_dat_i;
reg wb_stb_i;
reg wb_cyc_i;
reg [3:0] wb_sel_i;
reg wb_we_i;
wire [31:0] wb_dat_o;
wire wb_ack_o;
task wb_wait_for_ack;
begin
while (!wb_ack_o)
#sys_clk_period;
 
wb_stb_i = 0;
wb_cyc_i = 0;
/* Leave these deasserted for a cycle */
#sys_clk_period;
end
endtask // wb_wait_for_ack
 
task wb_write_16bits;
input [31:0] address;
input [15:0] dat;
begin
wb_adr_i = {address[31:1],1'b0};
wb_dat_i = {dat,dat};
wb_sel_i = address[1] ? 4'h3 : 4'hc;
wb_we_i = 1;
wb_stb_i = 1;
wb_cyc_i = 1;
#sys_clk_period;
wb_wait_for_ack();
end
endtask // wb_write_16bits
 
task wb_write_32bits;
input [31:0] address;
input [31:0] dat;
begin
wb_adr_i = address;
wb_dat_i = dat;
wb_sel_i = 4'hf;
wb_we_i = 1;
wb_stb_i = 1;
wb_cyc_i = 1;
#sys_clk_period;
wb_wait_for_ack();
end
endtask // wb_write_32bits
 
task wb_read_8bits;
input [31:0] address;
output [7:0] dat;
begin
wb_adr_i = address[31:0];
wb_sel_i = address[1:0] == 2'b00 ? 4'h8 :
address[1:0] == 2'b01 ? 4'h4 :
address[1:0] == 2'b10 ? 4'h2 : 4'h1;
wb_we_i = 0;
wb_stb_i = 1;
wb_cyc_i = 1;
#sys_clk_period;
wb_wait_for_ack();
dat = address[1:0] == 2'b00 ? wb_dat_o[31:24] :
address[1:0] == 2'b01 ? wb_dat_o[23:16] :
address[1:0] == 2'b10 ? wb_dat_o[15:8] : wb_dat_o[7:0];
end
endtask // wb_read_16bits
task wb_read_16bits;
input [31:0] address;
output [15:0] dat;
begin
wb_adr_i = {address[31:1],1'b0};
wb_sel_i = address[1] ? 4'h3 : 4'hc;
wb_we_i = 0;
wb_stb_i = 1;
wb_cyc_i = 1;
#sys_clk_period;
wb_wait_for_ack();
dat = address[1] ? wb_dat_o[15:0] : wb_dat_o[31:16];
end
endtask // wb_read_16bits
task wb_read_32bits;
input [31:0] address;
output [31:0] dat;
begin
wb_adr_i = address;
wb_sel_i = 4'hf;
wb_we_i = 0;
wb_stb_i = 1;
wb_cyc_i = 1;
#sys_clk_period;
wb_wait_for_ack();
dat = wb_dat_o;
end
endtask // wb_read_32bits
 
reg [31:0] temp_data;
reg [7:0] status_reg;
 
task wb_cfi_read_status_reg;
output [7:0] stat;
begin
wb_write_16bits(32'h0, 16'h0070);
wb_read_16bits(32'h0, stat);
end
endtask // wb_cfi_read_status_reg
 
task wb_cfi_wait_for_status_ready;
begin
wb_cfi_read_status_reg(status_reg);
while (!status_reg[7])
wb_cfi_read_status_reg(status_reg);
end
endtask // wb_cfi_wait_for_status_ready
task wb_cfi_write_16bits;
input [31:0] address;
input [15:0] dat;
begin
wb_write_16bits(address, 16'h0040);
wb_write_16bits(address, dat);
wb_cfi_wait_for_status_ready();
end
endtask // wb_cfi_write_16bits
task wb_cfi_write_32bits;
input [31:0] address;
input [31:0] dat;
begin
wb_cfi_write_16bits(address, dat[31:16]);
wb_cfi_write_16bits(address+2, dat[15:0]);
end
endtask // wb_cfi_write_32bits
 
task wb_cfi_read_8bits;
input [31:0] address;
output [7:0] dat;
begin
wb_write_16bits(address, 16'h00ff);
wb_read_8bits(address, dat);
end
endtask // wb_read_8bits
task wb_cfi_read_16bits;
input [31:0] address;
output [15:0] dat;
begin
wb_write_16bits(address, 16'h00ff);
wb_read_16bits(address, dat);
end
endtask // wb_cfi_read_16bits
task wb_cfi_read_32bits;
input [31:0] address;
output [31:0] dat;
begin
wb_cfi_read_16bits(address, dat[31:16]);
wb_cfi_read_16bits(address+2, dat[15:0]);
end
endtask // wb_cfi_write_32bits
 
task wb_cfi_unlock_and_erase_block;
input [31:0] address;
begin
/* Unlock block */
wb_write_16bits(address, 16'h0060);
wb_write_16bits(address, 16'h00D0);
/* Erase block */
wb_write_16bits(address, 16'h0020);
wb_write_16bits(address, 16'h00D0);
wb_cfi_wait_for_status_ready();
end
endtask
 
task wb_cfi_read_device_ident;
input [31:0] address;
output [15:0] data;
begin
wb_write_16bits(32'd0, 16'h0090);
wb_read_16bits((address<<1), data);
end
endtask // wb_cfi_read_device_ident
 
task wb_cfi_query;
input [31:0] address;
output [15:0] data;
begin
wb_write_16bits(32'd0, 16'h0098);
wb_read_16bits((address<<1), data);
end
endtask // wb_cfi_query
 
task wb_cfi_read_all_device_ident;
begin
$display("%t Reading device identifier information", $time);
wb_cfi_read_device_ident(0,temp_data[15:0]);
$display("%t Manufacturer code: %04h",$time,temp_data[15:0]);
wb_cfi_read_device_ident(31'h1,temp_data[15:0]);
$display("%t Device ID code: %04h",$time,temp_data[15:0]);
wb_cfi_read_device_ident(31'h5,temp_data[15:0]);
$display("%t RCR: %04h",$time,temp_data[15:0]);
wb_cfi_read_device_ident(31'h2 + ((128*1024)>>1),temp_data[15:0]);
$display("%t Block 0 locked?: %04h",$time,temp_data[15:0]);
end
endtask // wb_cfi_read_all_device_ident
 
task wb_cfi_queries;
begin
$display("%t Querying CFI device", $time);
wb_cfi_query(31'h10,temp_data[15:0]);
$display("%t Query ID string: %04h",$time,temp_data[15:0]);
wb_cfi_query(31'h13,temp_data[15:0]);
$display("%t Vendor command set and control interface ID: %04h",$time,temp_data[15:0]);
wb_cfi_query(31'h27,temp_data[15:0]);
$display("%t size 2^n: %04h",$time,temp_data[15:0]);
wb_cfi_query(31'h28,temp_data[15:0]);
$display("%t device interface code: %04h",$time,temp_data[15:0]);
wb_cfi_query(31'h2c,temp_data[15:0]);
$display("%t number of erase block regions: %04h",$time,temp_data[15:0]);
end
endtask
integer i;
 
parameter test_length = 16;
reg [31:0] temp_result;
/* Main test stimulus block */
initial begin
 
wb_adr_i = 0;
wb_dat_i = 0;
wb_stb_i = 0;
wb_cyc_i = 0;
wb_sel_i = 0;
wb_we_i = 0;
$dumpfile("../out/cfi_ctrl_wb_bench.vcd");
$dumpvars(0);
$display("Starting CFI Wishbone controller test");
#550; // Wait for the part to power up
 
wb_cfi_read_all_device_ident();
#500;
wb_cfi_queries();
#500;
/* Ready first block for play*/
wb_cfi_unlock_and_erase_block(0);
/* Clear status register */
wb_write_16bits(32'd0, 16'h0050);
/* Write a 32-bit word */
wb_cfi_write_32bits(32'h0000_0000, 32'hdeadbeef);
 
/* read it back */
wb_cfi_read_32bits(32'h0000_0000, temp_data);
/* works because we're already in read array mode */
wb_read_32bits(32'h0000_0000, temp_data);
/* Write data */
for (i = 0; i< ((4*test_length)/4); i=i+1) begin
temp_result[31:16] = 16'hdead-i;
temp_result[15:0] = 16'hbeef+i;
wb_cfi_write_32bits(32'h0000_0000+i*4, temp_result);
end
 
/* Read it back 16-bits at a time and check it */
for (i = 0; i< ((4*test_length)/4); i=i+1) begin
wb_cfi_read_16bits(32'h0000_0000+i*4, temp_data[31:16]);
wb_cfi_read_16bits(32'h0000_0000+i*4+2, temp_data[15:0]);
temp_result[31:16] = 16'hdead-i;
temp_result[15:0] = 16'hbeef+i;
if (temp_data != temp_result) begin
$display("Read verify error at %h",(i*4));
$finish;
end
end
/* Read it back 8-bits at a time and check it */
for (i = 0; i< ((4*test_length)/4); i=i+1) begin
wb_read_8bits(32'h0000_0000+i*4, temp_data[31:24]);
wb_read_8bits(32'h0000_0000+i*4+1, temp_data[23:16]);
wb_read_8bits(32'h0000_0000+i*4+2, temp_data[15:8]);
wb_read_8bits(32'h0000_0000+i*4+3, temp_data[7:0]);
temp_result[31:16] = 16'hdead-i;
temp_result[15:0] = 16'hbeef+i;
if (temp_data != temp_result) begin
$display("Read verify error at %h",(i*4));
$finish;
end
end
/* Read it back and check it */
for (i = 0; i< ((4*test_length)/4); i=i+1) begin
wb_read_32bits(32'h0000_0000+i*4, temp_data);
temp_result[31:16] = 16'hdead-i;
temp_result[15:0] = 16'hbeef+i;
if (temp_data != temp_result) begin
$display("Read verify error at %h",(i*4));
$finish;
end
end
 
/* Test doing things on next block */
wb_cfi_unlock_and_erase_block(32'h20000);
 
/* Write 4k of data */
for (i = 0; i< ((4*test_length)/4); i=i+1) begin
temp_result[31:16] = 16'hdead-i;
temp_result[15:0] = 16'hbeef+i;
wb_cfi_write_32bits(32'h0002_0000+i*4, temp_result);
end
/* Read it back and check it */
/* Do one read to get it into the read array mode */
wb_cfi_read_16bits(32'h0002_0000, temp_data[15:0]);
for (i = 0; i< ((4*test_length)/4); i=i+1) begin
wb_read_32bits(32'h0002_0000+i*4, temp_data);
temp_result[31:16] = 16'hdead-i;
temp_result[15:0] = 16'hbeef+i;
if (temp_data != temp_result) begin
$display("Read verify error at %h",(i*4));
$finish;
end
end
 
/* Read it back 16-bits at a time and check it */
for (i = 0; i< ((4*test_length)/4); i=i+1) begin
wb_read_16bits(32'h0002_0000+i*4, temp_data[31:16]);
wb_read_16bits(32'h0002_0000+i*4+2, temp_data[15:0]);
temp_result[31:16] = 16'hdead-i;
temp_result[15:0] = 16'hbeef+i;
if (temp_data != temp_result) begin
$display("Read verify error at %h",(i*4));
$finish;
end
end
$display("Finishing CFI Wishbone controller test");
$finish;
end
 
/* timeout function - sim shouldn't run much longer than this */
/*
initial begin
#55000;
$display("Simulation finish due to timeout");
$finish;
end
*/
cfi_ctrl
#(.cfi_engine("DISABLED")) /* Simpler controller */
dut
(
.wb_clk_i(sys_clk),
.wb_rst_i(sys_rst),
 
.wb_adr_i(wb_adr_i),
.wb_dat_i(wb_dat_i),
.wb_stb_i(wb_stb_i),
.wb_cyc_i(wb_cyc_i),
.wb_we_i (wb_we_i ),
.wb_sel_i(wb_sel_i),
.wb_dat_o(wb_dat_o),
.wb_ack_o(wb_ack_o),
.flash_dq_io(DQ),
.flash_adr_o(A),
.flash_adv_n_o(ADV_N),
.flash_ce_n_o(CE_N),
.flash_clk_o(CLK),
.flash_oe_n_o(OE_N),
.flash_rst_n_o(RST_N),
.flash_wait_i(WAIT),
.flash_we_n_o(WE_N),
.flash_wp_n_o(WP_N)
);
 
x28fxxxp30 part(A, DQ, WE_N, OE_N, CE_N, ADV_N, CLK,
WAIT, WP_N, RST_N, VCC, VCCQ, VPP, Info);
 
 
endmodule
/cfi_ctrl/trunk/bench/verilog/include/data.h
0,0 → 1,214
// _/ _/_/
// _/_/ _/_/_/
// _/_/_/_/ _/_/_/
// _/_/_/_/_/ _/_/_/ ____________________________________________
// _/_/_/_/_/ _/_/_/ / /
// _/_/_/_/_/ _/_/_/ / 28F256P30 /
// _/_/_/_/_/ _/_/_/ / /
// _/_/_/_/_/_/ _/_/_/ / 256Mbit /
// _/_/_/_/_/_/ _/_/_/ / single die /
// _/_/_/ _/_/_/ _/_/_/ / /
// _/_/_/ _/_/_/ _/_/_/ / Verilog Behavioral Model /
// _/_/_/ _/_/_/ _/_/_/ / Version 1.3 /
// _/_/_/ _/_/_/ _/_/_/ / /
// _/_/_/ _/_/_/_/_/_/ / Copyright (c) 2010 Numonyx B.V. /
// _/_/_/ _/_/_/_/_/ /___________________________________________/
// _/_/_/ _/_/_/_/
// _/_/ _/_/_/
//
//
// NUMONYX
 
// ******
//
// data.h
//
// ******
 
// ********************
//
// Main Characteristics
//
// ********************
 
`define ADDRBUS_dim 24 // - Address Bus pin numbers
`define DATABUS_dim 16 // - Data Bus pin numbers
`define MEMORY_dim 1 << `ADDRBUS_dim // - Memory Dimension
`define LAST_ADDR (`MEMORY_dim) - 1 // - Last Address
 
// ********************
//
// Address & Data range
//
// ********************
 
`define ADDRBUS_range `ADDRBUS_dim - 1 : 0
`define DATABUS_range `DATABUS_dim - 1 : 0
 
// *****************
//
// Init Memory Files
//
// *****************
 
`define CFI_dim 9'h157
`define CFI_range `CFI_dim - 1:9'h10
// *******************
//
// Protection Register
//
// *******************
 
 
`define REG_addrStart 16'h0
`define REG_addrEnd 16'h15
 
`define REGSTART_addr 9'h80 // Protection Register Start Address
`define REGEND_addr 9'h109 // Protection Register End Address
`define REG_dim `REGEND_addr - `REGSTART_addr + 1
 
`define REG_addrRange `REG_addrEnd:`REG_addrStart
 
`define REG_addrbitStart 8'd0
`define REG_addrbitEnd 8'd8
`define REG_addrbitRange `REG_addrbitEnd:`REG_addrbitStart
 
`define PROTECTREGLOCK_addr 9'h80 // Protection Register Lock Address
 
 
`define UDNREGSTART_addr 9'h81
`define UDNREGEND_addr 9'h84
`define UDNprotect_bit 8'hFE
 
`define UPREGSTART_addr 9'h85
`define UPREGEND_addr 9'h88
`define UPprotect_bit 8'hFD // serve ad indentificare quale bit deve essere 0 nel lock regi
`define PRL_default 16'h0002 // Protection Register Lock default definito anche in def
 
// *****************************
//
// Extended User OTP
//
// *****************************
 
`define ExtREG_dim 8'h20
 
 
`define ExtREG_regiondim 8'h8
`define ExtREGSTART_regionaddr 9'h8A // Ext Protection Register Start Address
`define ExtREGEND_regionaddr 9'h109 // Ext Protection Register End Address
 
`define ExtPROTECTREGLOCK_addr 9'h89 // Ext Protection Register Lock Address
`define ExtPRL_default 16'hFFFF // Protection Register Lock default
 
 
 
// ***********************
//
// Voltage Characteristics
//
// ***********************
`define Voltage_range 35:0
`define VDDmin 36'd01700
`define VDDmax 36'd02000
`define VDDQmin 36'd01700
`define VDDQmax 36'd03600
`define VPPmin 36'd00900
`define VPPmax 36'd03600
`define VPPHmin 36'd08500
`define VPPHmax 36'd09500
 
// **********************
//
// Configuration Register
//
// **********************
 
`define ConfigurationReg_dim 16
`define ConfigReg_default 16'hF94F
 
// ********************
//
// Electronic Signature
//
// ********************
 
`define ManufacturerCode 8'h89
`define TopDeviceCode 8'h19
`define BottomDeviceCode 8'h1C
`define SignAddress_dim 9
`define SignAddress_range `SignAddress_dim - 1 : 0
 
 
 
// *********************
//
// Write Buffer constant
//
// *********************
 
 
`define ProgramBuffer_addrDim 9 // Program Buffer address dimension
`define ProgramBuffer_addrRange `ProgramBuffer_addrDim - 1:0
`define ProgramBuffer_dim 512 // Buffer Size= 2 ^ ProgramBuffer_addrDim
`define ProgramBuffer_range `ProgramBuffer_dim - 1:0
 
// *********************
//
// Buffer Enhanced Program constant
//
// *********************
 
`define BuffEnhProgramBuffer_dim 512
`define BuffEnhProgramBuffer_range `BuffEnhProgramBuffer_dim - 1 : 0
`define BuffEnhProgramBuffer_addrDim 9
`define BuffEnhProgramBuffer_addrRange `BuffEnhProgramBuffer_addrDim - 1:0
 
// Warning and Error Messages
 
`define NoError_msg 0 // No Error Found
`define CmdSeq_msg 1 // Sequence Command Unknown
`define SuspCmd_msg 2 // Cannot execute this command during suspend
`define SuspAcc_msg 3 // Cannot access this address due to suspend
`define AddrRange_msg 4 // Address out of range
`define AddrTog_msg 5 // Cannot change block address during command sequence
`define SuspAccWarn_msg 6 // It isn't possible access this address due to suspend
`define InvVDD_msg 7 // Voltage Supply must be: VDD>VDDmin or VDD<VDDmax
`define InvVPP_msg 8 // Voltage Supply must be: VDD>VDDmin or VDD<VDDmax
`define BlockLock_msg 9 // Cannot complete operation when the block is locked
`define ByteToggle_msg 10 // Cannot toggle BYTE_N while busy
`define NoUnLock_msg 11 // Invalid UnLock Block command in Locked-Down Block
`define AddrCFI_msg 12 // CFI Address out of range
`define PreProg_msg 13 // Program Failure due to cell failure
`define NoBusy_msg 14 // Device is not Busy
`define NoSusp_msg 15 // Nothing previus suspend command
`define Suspend_msg 16 // Device is Suspend mode
`define UDNlock_msg 17 // Unique Device Number Register is locked
`define UPlock_msg 18 // User Programmable Register is locked
`define ExitPHASE_BEFP_msg 19
`define WrongEraseConfirm_msg 20 // Wrong Erase Confirm code
`define SignAddrRange_msg 21 // Signature Address out of range
`define CFIAddrRange_msg 22 // CFI Address out of range
`define WrongBlankCheckConfirm_msg 23 // Wrong Blank Check Confirm code command
`define BlankCheckFailed_msg 24 // Blank Check Failed
`define ProgramPHASE_BEFP_msg 25 // End of Program or Verify Phase on Enhanced Factory Program
`define BlkBuffer_msg 26 // Program Buffer cannot cross block boundary
`define ExtREGLock_msg 27 // Extended User Programmable Register is locked
`define LeastAddr0 28 // Significative bit [%d,0] of Start Address must be 0
`define ProtRegAddrRange_msg 29 // Protect Register Address out of range
`define BuffSize_msg 30 // Buffer size is too large
`define WrongBlankCheckBlock 31 // No main block
 
// ******************
//
// Valid Access Times
//
// ******************
 
`define tAccess_1 100
`define tAccess_2 110
 
 
 
 
/cfi_ctrl/trunk/bench/verilog/include/CUIcommandData.h
0,0 → 1,106
// _/ _/_/
// _/_/ _/_/_/
// _/_/_/_/ _/_/_/
// _/_/_/_/_/ _/_/_/ ____________________________________________
// _/_/_/_/_/ _/_/_/ / /
// _/_/_/_/_/ _/_/_/ / 28F256P30 /
// _/_/_/_/_/ _/_/_/ / /
// _/_/_/_/_/_/ _/_/_/ / 256Mbit /
// _/_/_/_/_/_/ _/_/_/ / single die /
// _/_/_/ _/_/_/ _/_/_/ / /
// _/_/_/ _/_/_/ _/_/_/ / Verilog Behavioral Model /
// _/_/_/ _/_/_/ _/_/_/ / Version 1.3 /
// _/_/_/ _/_/_/ _/_/_/ / /
// _/_/_/ _/_/_/_/_/_/ / Copyright (c) 2010 Numonyx B.V. /
// _/_/_/ _/_/_/_/_/ /___________________________________________/
// _/_/_/ _/_/_/_/
// _/_/ _/_/_/
//
//
// NUMONYX
 
// **********************
//
// COMMAND USER INTERFACE
//
// **********************
 
// Read Commands
 
`define RD_cmd 8'hFF // Read Memory Array
`define RSR_cmd 8'h70 // Read Status Register
`define RSIG_cmd 8'h90 // Read Electronic Signature
`define RCFI_cmd 8'h98 // Read CFI
 
 
// Program/Erase Commands
 
`define PG_cmd 8'h40 // Program
`define PES_cmd 8'hB0 // Program/Erase Suspend
`define PER_cmd 8'hD0 // Program/Erase Resume
`define BLKEE_cmd 8'h20 // Block Erase
`define BLKEEconfirm_cmd 8'hD0 // Block Erase Confirm
`define CLRSR_cmd 8'h50 // Clear Status Register
`define PRREG_cmd 8'hC0 // Protection Register Program //verificare se va bene x OTP register program setup
 
 
// Protect Commands
 
`define BL_cmd 8'h60 // Block Lock //setup??
`define BUL_cmd 8'h60 // Block UnLock
`define BLD_cmd 8'h60 // Block lock-down
`define BLDconfirm_cmd 8'h2F // Block Lock-down confirm
`define BLconfirm_cmd 8'h01 // Block Lock Confirm
`define BULconfirm_cmd 8'hD0 // Block unLock Confirm
 
 
// Additional Features Commands
 
`define PB_cmd 8'hE8 // Program Buffer
`define PBcfm_cmd 8'hD0 // Close Sequence of Program Buffer Command
 
 
// Configuration Register
 
`define SCR_cmd 8'h60 // Set Configuration Register
`define SCRconfirm_cmd 8'h03 // Set Configuration Register confirm
 
// Additional Features Commands //aggiunto
`define BLNKCHK_cmd 8'hBC // Blank Check Command
`define BLNKCHKconfirm_cmd 8'hD0 // Blank Check Confirm
 
 
// Factory Program Commands
`define BuffEnhProgram_cmd 8'h80 // Enhanced Setup Command
`define BuffEnhProgramCfrm_cmd 8'hD0 // Enhanced Setup confirm
 
`define EnhSetup_cmd 8'h80 // Enhanced Setup Command
`define EnhSetup_cfrm 8'hD0 // Enhanced Setup confirm
 
 
// CUI Status
 
// Read Bus Status Operation
 
`define ReadArray_bus 2'b00 // Read Memory Array
`define ReadSignature_bus 2'b01 // Read Electronic Signature
`define ReadStatusReg_bus 2'b10 // Read Status Register
`define ReadCFI_bus 2'b11 // Read CFI
 
 
// Program/Erase Controller Status
 
`define Free_pes 0 // No Operation
`define Program_pes 1 // Programming
`define ProgramBuff_pes 7 // Programming
 
 
`define BlockErase_pes 2 // Erasing Block
`define ChipErase_pes 3 // Chip Erasing
`define BlockEraseSuspend_pes 4 // Block Erase Suspend
`define ProgramEraseSuspend_pes 5 // Program/Erase Resume
`define ProgramEraseWait_pes 6 // Program/Erase Wait
`define Reset_pes 10 // Reset status
 
 
 
/cfi_ctrl/trunk/bench/verilog/include/def.h
0,0 → 1,49
// _/ _/_/
// _/_/ _/_/_/
// _/_/_/_/ _/_/_/
// _/_/_/_/_/ _/_/_/ ____________________________________________
// _/_/_/_/_/ _/_/_/ / /
// _/_/_/_/_/ _/_/_/ / 28F256P30 /
// _/_/_/_/_/ _/_/_/ / /
// _/_/_/_/_/_/ _/_/_/ / 256Mbit /
// _/_/_/_/_/_/ _/_/_/ / single die /
// _/_/_/ _/_/_/ _/_/_/ / /
// _/_/_/ _/_/_/ _/_/_/ / Verilog Behavioral Model /
// _/_/_/ _/_/_/ _/_/_/ / Version 1.3 /
// _/_/_/ _/_/_/ _/_/_/ / /
// _/_/_/ _/_/_/_/_/_/ / Copyright (c) 2010 Numonyx B.V. /
// _/_/_/ _/_/_/_/_/ /___________________________________________/
// _/_/_/ _/_/_/_/
// _/_/ _/_/_/
//
//
// NUMONYX
// *****************************************
// Glogal Definition for Device : M58WR128F
// *****************************************
 
// TimeScale Directive
`timescale 1 ns / 1 ns
 
`define HIGH 1'b1
`define LOW 1'b0
`define Z 1'bZ
`define X 1'bX
`define FALSE 1'b0
`define TRUE 1'b1
`define UNLOCK 1'b0 // Unlocked Block Lock Status
`define LOCK 1'b1 // Locked Block Lock Status
`define UNLOCKDOWN 1'b0 // UnLocked-down Status
`define LOCKDOWN 1'b1 // Locked-down Status
`define BUSY 1'b0
`define READY 1'b1
`define BYTE_range 7:0
`define WORD_range 15:0
`define LOW_range 7:0
`define HIGH_range 15:8
`define WORDNP 16'hFFFF // Memory not programmed
`define Kbyte 1024
`define Kword 1024
`define INTEGER 15:0
 
/cfi_ctrl/trunk/bench/verilog/include/TimingData.h
0,0 → 1,314
// _/ _/_/
// _/_/ _/_/_/
// _/_/_/_/ _/_/_/
// _/_/_/_/_/ _/_/_/ ____________________________________________
// _/_/_/_/_/ _/_/_/ / /
// _/_/_/_/_/ _/_/_/ / 28F256P30 /
// _/_/_/_/_/ _/_/_/ / /
// _/_/_/_/_/_/ _/_/_/ / 256Mbit /
// _/_/_/_/_/_/ _/_/_/ / single die /
// _/_/_/ _/_/_/ _/_/_/ / /
// _/_/_/ _/_/_/ _/_/_/ / Verilog Behavioral Model /
// _/_/_/ _/_/_/ _/_/_/ / Version 1.3 /
// _/_/_/ _/_/_/ _/_/_/ / /
// _/_/_/ _/_/_/_/_/_/ / Copyright (c) 2010 Numonyx B.V. /
// _/_/_/ _/_/_/_/_/ /___________________________________________/
// _/_/_/ _/_/_/_/
// _/_/ _/_/_/
//
//
// NUMONYX
`include "data.h"
`include "UserData.h"
 
`define Reset_time 300000
 
// *********************************************
//
// Table 29
// Program/Erase Characteristics
//
// *********************************************
 
// Vpp = VppL
 
/*
// Too long!
`define ParameterBlockErase_time 800000000// 0.8 sec
`define MainBlockErase_time 800000000
*/
 
/* erase times much reduced for simulation - Julius */
`define ParameterBlockErase_time 8000// 800ns sec
`define MainBlockErase_time 8000
 
/*
`define WordProgram_time 150000 // 150 us
`define ParameterBlockProgram_time 272000 // 32000 us = 32 ms???????verificare
`define MainBlockProgram_time 700000 // 256000 us = 256 ms???????verificare
*/
 
`define WordProgram_time 1500 // 150 us
`define ParameterBlockProgram_time 2720 // 32000 us = 32 ms???????verificare
`define MainBlockProgram_time 7000 // 256000 us = 256 ms???????verificare
 
`define ProgramSuspendLatency_time 20000 // 20 us
`define EraseSuspendLatency_time 20000 // 20 us
`define MainBlankCheck_time 3200000
// Vpp = VppH
 
`define FastParameterBlockErase_time 800000000 // 0.8 sec
`define FastMainBlockErase_time 800000000 // 0.8 sec
`define FastWordProgram_time 150000 // 8 us
`define FastParameterBlockProgram_time 272000 // 32 ms
`define FastMainBlockProgram_time 700000 // 256000 us = 256 ms
 
`define BlockProtect_time 1800
`define BlockUnProtect_time 5000000
 
`define ProgramBuffer_time 700000
 
 
`define EnhBuffProgram_time 512000 //
`define EnhBuffProgramSetupPhase_time 5000
 
 
 
// **********************
//
// Timing Data Module :
// set timing values
//
// **********************
 
module TimingDataModule;
 
// ************************************
//
// AC Read Specifications
//
// Table 27
//
// ************************************
 
integer tAVAV; // Address Valid to Next Address Valid
integer tAVQV; // Address Valid to Output Valid (Random)
integer tAVQV1; // Address Valid to Output Valid (Page)
integer tELTV; // Chip Enable Low to Wait Valid
integer tELQV; // Chip Enable Low to Output Valid
integer tELQX; // Chip Enable Low to Output Transition
integer tEHTZ; // Chip Enable High to Wait Hi-Z
integer tEHQX;//tOH // Chip Enable High to Output Transition
integer tEHQZ; // Chip Enable High to Output Hi-Z
integer tGLQV; // Output Enable Low to Output Valid
integer tGLQX; // Output Enable Low to Output Transition
integer tGHQZ; // Output Enable High to Output Hi-Z
integer tAVLH;//tAVVH // Address Valid to (ADV#) Latch Enable High
integer tELLH; //tELVH // Chip Enable Low to Latch Enable High
integer tLHAX; //tVHAX // Latch Enable High to Address Transition
integer tLLLH; //tVLVH // Latch Enable Low to Latch Enable High
integer tLLQV; //tVLQV // Latch Enable Low to Output Valid
 
integer tGLTV; //// Output Enable Low to Wait Valid
integer tGLTX; //// Output Enable Low to Wait Transition
integer tGHTZ; //// Output Enable high to Wait Hi-Z
 
 
 
 
 
integer tAVKH; //tAVCH/L // Address Valid to Clock High
integer tELKH; //tELCH // Chip Enable Low to Clock High
integer tEHEL;// tEHEL // Chip Enable High to Chip Enable Low (reading)
integer tKHAX;//tCHAX // Clock High to Address Transition
integer tKHQV; //tCHQV // Clock High to Output Enable Valid
integer tKHTV; //tCHTV // Clock High to Wait Valid
integer tKHQX; //tCHQX // Clock High to Output Enable Transition
integer tKHTX; //tCHTX // Clock High to Wait Transition
integer tLLKH; //tVLCH/L // Latch Enable Low to Clock High
integer tLLKL; //tVLCH/L // Latch Enable Low to Clock High
integer tKHLL; //tCHVL //Clock valid to ADV# setup
integer tKHKH; //tCLK // Clock Period
integer tKHKL; //tCH/CL // Clock High to Clock Low
integer tKLKH; // Clock Low to Clock High
integer tCK_fall; //R203 // Clock Fall Time
integer tCK_rise; // Clock Rise Time
 
 
// *************************************************
//
// AC Write Specifications
//
// Table 28
//
// *************************************************
 
integer tAVWH; // Address Valid to Write Enable High
integer tDVWH; // Data Valid to Write Enable High
integer tELWL; // Chip Enable Low to Write Enable Low
integer tWHAV; //W18 // Write Enable High to Address Valid
integer tWHAX; // Write Enable High to Address Transition
integer tWHDX; // Write Enable High to Data Transition
integer tWHEH; // Write Enable High to Chip Enable High
integer tWHGL; // Write Enable High to Output Enable High
integer tWHLL; //W28 tWHVL // Write Enable High to Latch Enable Low
integer tWHWL; // Write Enable High to Latch Enable Low
integer tWHQV; // Write Enable High to Output Enable Valid
integer tWLWH; // Write Enable Low to Write Enable High
integer tQVVPL; //tQVVL // Output (Status Register) Valid to Vpp Low
integer tQVWPL; //tQVBL // Output (Status Register) Valid to Write Protect Low
integer tVPHWH; // Vpp High to Write Enable High
integer tWPHWH; //tBHWH // Write Protect High to Write Enable High
 
 
integer tELEH; // Chip Enable Low to Chip Enable High
 
 
//!// *************************************
//!//
//!// Power and Reset
//!//
//!// Table 20
//!//
//!// **************************************
 
integer tPHWL; //W1 // Reset High to Write Enable Low
integer tPLPH;//P1 // Reset High to Reset Low
 
integer tVDHPH; //tVCCPH // Supply voltages High to Reset High
 
 
 
initial begin
 
setTiming(`t_access);
end
 
// **********************
//
// FUNCTION getTime :
// return time value
//
// **********************
 
function getTime;
 
input [8*31 : 0] time_str;
 
begin
 
 
end
endfunction
 
// **********************
//
// Task setTiming :
// set timing values
//
// **********************
 
task setTiming;
 
input time_access;
 
integer time_access;
 
begin
 
// ***********************************************
//
// AC Read Specifications
//
// Table 27
//
// ***********************************************
 
tELQX = 0;
tEHQX = 0;
tGLQX = 0;
tGHQZ = 15;
tELLH = 10;
 
tAVAV = time_access;
tAVQV = time_access;
tELQV = time_access;
tLLQV = time_access;
tEHTZ = 20;
tAVQV1 = 25;
tELTV = 17;
tEHEL = 17;
tCK_fall = 3;
tCK_rise = 3;
tEHQZ = 20;
tGLQV = 25;
tAVLH = 10;
tLHAX = 9;
tLLLH = 10;
 
tAVKH = 9;
tELKH = 9;
tKHAX = 10;
tKHQV = 17;
tKHTV = 17;
tKHQX = 3;
tKHTX = 3;
tLLKH = 9;
tLLKL = 9;
tKHLL = 3;
tKHKH = 19.2;
tKHKL = 5;
tKLKH = 5;
tGLTV = 17;
tGLTX = 0;
tGHTZ = 20;
 
// *************************************************
//
// AC Write Specifications
//
// Table 28
//
// *************************************************
 
tELWL = 0;
tWHAV = 0;
tWHAX = 0;
tWHDX = 0;
tWHEH = 0;
tWHGL = 0;
tWHLL = 7;
tQVVPL = 0;
tQVWPL = 0;
tVPHWH = 200;
tWPHWH = 200;
tAVWH = 50;
tDVWH = 50;
tWHWL = 20;
tWHQV = tAVQV + 35; //tAVQV+35
tWLWH = 50;
tELEH = 50;
// *************************************
//
// Power and Reset
//
// Table 20
//
// **************************************
 
tPHWL = 150;
tPLPH = 100;
tVDHPH = 300;
 
 
end
endtask
 
endmodule
 
/cfi_ctrl/trunk/bench/verilog/include/BankLib.h
0,0 → 1,280
// _/ _/_/
// _/_/ _/_/_/
// _/_/_/_/ _/_/_/
// _/_/_/_/_/ _/_/_/ ____________________________________________
// _/_/_/_/_/ _/_/_/ / /
// _/_/_/_/_/ _/_/_/ / 28F256P30 /
// _/_/_/_/_/ _/_/_/ / /
// _/_/_/_/_/_/ _/_/_/ / 256Mbit /
// _/_/_/_/_/_/ _/_/_/ / single die /
// _/_/_/ _/_/_/ _/_/_/ / /
// _/_/_/ _/_/_/ _/_/_/ / Verilog Behavioral Model /
// _/_/_/ _/_/_/ _/_/_/ / Version 1.3 /
// _/_/_/ _/_/_/ _/_/_/ / /
// _/_/_/ _/_/_/_/_/_/ / Copyright (c) 2010 Numonyx B.V. /
// _/_/_/ _/_/_/_/_/ /___________________________________________/
// _/_/_/ _/_/_/_/
// _/_/ _/_/_/
//
//
// NUMONYX
 
// ****************************************************
//
// Block Library :
//
// define the architecture of the blocks and banks
//
// ****************************************************
 
`include "def.h"
`include "data.h"
`include "UserData.h"
 
`define BLOCK_dim 259
`define BLOCKDIM_range 0 : `BLOCK_dim - 1
`define BLOCKADDR_dim 16
`define BLOCKADDR_range `BLOCKADDR_dim - 1 : 0
 
// *********
//
// Parameter Block & Main Block
 
//
// *********
 
`define ParameterBlock_num 4
`define ParameterBlock_size 16 // Size of Parameter Block (Kword)
`define MainBlock_num 255
`define MainBlock_size 64 // Size of Main Block (Kword)
 
 
 
module BankLib;
 
integer BlockBoundaryStartAddr [`BLOCK_dim - 1 : 0]; // Block Boundary Start Address
integer BlockBoundaryEndAddr [`BLOCK_dim - 1 : 0]; // Block Boundary End Address
integer count;
 
initial
begin
 
begin: block_building
for (count = 0; count <= `BLOCK_dim - 1; count = count + 1)
BuildBlockBoundary(`organization, count, BlockBoundaryStartAddr[count], BlockBoundaryEndAddr[count]);
 
end
 
end
 
// ******************************************************************
//
// TASK BuildBlockBoundary: Build the Blocks Boundaries in two arrays
//
// ******************************************************************
 
task BuildBlockBoundary;
input organize;
input n_block;
output StartAddr;
output EndAddr;
 
reg [8*6:1] organize;
integer n_block;
integer StartAddr;
integer EndAddr;
 
begin
if (organize == "top") begin
if (n_block == 0) EndAddr = - 1;
if (n_block > `MainBlock_num - 1 && n_block <= `MainBlock_num + `ParameterBlock_num - 1) // parameter block
begin
StartAddr = EndAddr + 1;
EndAddr = StartAddr + `ParameterBlock_size * `Kword - 1;
end
else // Main block
begin
StartAddr = EndAddr + 1;
EndAddr = StartAddr + `MainBlock_size * `Kword - 1;
end
 
end else begin // organize = "bottom"
if (n_block == 0) EndAddr = - 1;
if (n_block > `ParameterBlock_num - 1)
begin
StartAddr = (`ParameterBlock_num * `ParameterBlock_size * `Kword ) +
(n_block - `ParameterBlock_num) * `MainBlock_size * `Kword;
EndAddr = StartAddr + `MainBlock_size * `Kword - 1;
end
//!
else // parameter block
begin
StartAddr = EndAddr + 1;
EndAddr = StartAddr + `ParameterBlock_size * `Kword - 1;
end
 
end
//!$display("n_block=%d, StartAddr =%h, EndAddr =%h", n_block, StartAddr , EndAddr);
end
endtask
 
 
 
// *********************************************
// FUNCTION getBlock : return block from address
//
// *********************************************
 
function [`INTEGER] getBlock; // BLOCK_dim in binary is 9 bit size
 
input address;
 
reg [`ADDRBUS_dim - 1 : 0] address;
reg found;
integer count;
 
begin
// $display ("function getBlock got address %h", address);
count = 0;
found = 0;
while ((count <= `BLOCK_dim) && (! found))
begin
 
if ((BlockBoundaryStartAddr[count] <= address) && (address <= BlockBoundaryEndAddr[count])) found= 1;
else count = count + 1;
 
end
if (!found) $display("%t address= %h !Error in Block Library : specified block address is out of range",$time,address);
getBlock= count;
end
endfunction
 
 
// ***************************
//
// FUNCTION getBlockAddress :
// return the block address
//
// ***************************
 
function [`ADDRBUS_dim - 1 : 0] getBlockAddress;
 
input block;
 
integer block;
 
begin
 
getBlockAddress = BlockBoundaryStartAddr[block];
 
end
endfunction
 
 
// *********************************************
//
// FUNCTION isParameterBlock :
// return true if the address
// is in a parameter block
//
// *********************************************
 
function isParameterBlock;
 
input address;
 
reg [`ADDRBUS_dim - 1 : 0] address;
reg prm;
integer count;
 
begin
 
prm = `FALSE;
if (`organization=="bottom") begin
 
for (count = 0; count <= `ParameterBlock_num - 1; count = count + 1) begin: cycle
 
if ((BlockBoundaryStartAddr[count] <= address) && (address <= BlockBoundaryEndAddr[count]))
begin
prm= `TRUE;
disable cycle;
end
end
end else begin
for (count = `BLOCK_dim - `ParameterBlock_num + 1; count <= `BLOCK_dim - 1; count = count + 1) begin: cycle1
 
if ((BlockBoundaryStartAddr[count] <= address) && (address <= BlockBoundaryEndAddr[count]))
begin
prm= `TRUE;
disable cycle1;
end
end
end
isParameterBlock = prm;
end
endfunction
 
 
// *********************************************
//
// FUNCTION isMainBlock :
// return true if the address is in a main block
//
// *********************************************
 
function isMainBlock;
 
input address;
 
reg [`ADDRBUS_dim - 1 : 0] address;
reg main;
integer count;
 
begin
 
main = `FALSE;
 
if (`organization=="bottom") begin
for (count = `BLOCK_dim - 1; count >= `BLOCK_dim - `ParameterBlock_num + 1; count = count - 1) begin: cycle2
 
if ((BlockBoundaryStartAddr[count] <= address) && (address <= BlockBoundaryEndAddr[count]))
begin
main = `TRUE;
disable cycle2;
end
end
end else begin
for (count = 0; count <= `MainBlock_num - 1; count = count + 1) begin: cycle3
 
 
if ((BlockBoundaryStartAddr[count] <= address) && (address <= BlockBoundaryEndAddr[count]))
begin
main = `TRUE;
disable cycle3;
end
end
end
isMainBlock = main;
end
endfunction
 
 
endmodule
/cfi_ctrl/trunk/bench/verilog/include/UserData.h
0,0 → 1,36
// _/ _/_/
// _/_/ _/_/_/
// _/_/_/_/ _/_/_/
// _/_/_/_/_/ _/_/_/ ____________________________________________
// _/_/_/_/_/ _/_/_/ / /
// _/_/_/_/_/ _/_/_/ / 28F256P30 /
// _/_/_/_/_/ _/_/_/ / /
// _/_/_/_/_/_/ _/_/_/ / 256Mbit /
// _/_/_/_/_/_/ _/_/_/ / single die /
// _/_/_/ _/_/_/ _/_/_/ / /
// _/_/_/ _/_/_/ _/_/_/ / Verilog Behavioral Model /
// _/_/_/ _/_/_/ _/_/_/ / Version 1.3 /
// _/_/_/ _/_/_/ _/_/_/ / /
// _/_/_/ _/_/_/_/_/_/ / Copyright (c) 2010 Numonyx B.V. /
// _/_/_/ _/_/_/_/_/ /___________________________________________/
// _/_/_/ _/_/_/_/
// _/_/ _/_/_/
//
//
// NUMONYX
 
// ************************************
//
// User Data definition file :
//
// here are defined all parameters
// that the user can change
//
// ************************************
 
`define organization "top" // top or bottom
`define BLOCKPROTECT "on" // if on the blocks are locked at power-up
`define TimingChecks "on" // on for checking timing constraints
`define t_access 100 // Access Time 100 ns, 110 ns
`define FILENAME_mem "memory.vmf" // Memory File Name
/cfi_ctrl/trunk/bench/verilog/cfi_ctrl_engine_wb_bench.v
0,0 → 1,369
/* Testbench of Wishbone classic-slave wrapped CFI engine controller */
 
`include "def.h"
`include "data.h"
 
`timescale 1ns/1ps
 
module cfi_ctrl_engine_wb_bench();
 
 
// Signal Bus
wire [`ADDRBUS_dim - 1:0] A; // Address Bus
wire [`DATABUS_dim - 1:0] DQ; // Data I/0 Bus
// Control Signal
wire WE_N; // Write Enable
wire OE_N; // Output Enable
wire CE_N; // Chip Enable
wire RST_N; // Reset
wire WP_N; // Write Protect
wire ADV_N; // Latch Enable
wire CLK; // Clock
wire WAIT; // Wait
 
// Voltage signal rappresentad by integer Vector which correspond to millivolts
wire [`Voltage_range] VCC; // Supply Voltage
wire [`Voltage_range] VCCQ; // Supply Voltage for I/O Buffers
wire [`Voltage_range] VPP; // Optional Supply Voltage for Fast Program & Erase
 
//wire STS;
wire Info; // Activate/Deactivate info device operation
assign Info = 1;
assign VCC = 36'd1700;
assign VCCQ = 36'd1700;
assign VPP = 36'd2000;
 
parameter sys_clk_half_period = 15.15/2; /* 66MHz */
parameter sys_clk_period = sys_clk_half_period*2;
reg sys_clk;
reg sys_rst;
 
initial begin
sys_clk = 0;
forever
#sys_clk_half_period sys_clk = ~sys_clk;
end
initial begin
sys_rst = 1;
#sys_clk_period;
#sys_clk_period;
sys_rst = 0;
end
 
reg [31:0] wb_adr_i;
reg [31:0] wb_dat_i;
reg wb_stb_i;
reg wb_cyc_i;
reg [3:0] wb_sel_i;
reg wb_we_i;
wire [31:0] wb_dat_o;
wire wb_ack_o;
task wb_wait_for_ack;
begin
while (!wb_ack_o)
#sys_clk_period;
 
wb_stb_i = 0;
wb_cyc_i = 0;
/* Leave these deasserted for a cycle */
#sys_clk_period;
end
endtask // wb_wait_for_ack
 
task wb_write_16bits;
input [31:0] address;
input [15:0] dat;
begin
wb_adr_i = {address[31:1],1'b0};
wb_dat_i = {dat,dat};
wb_sel_i = address[1] ? 4'h3 : 4'hc;
wb_we_i = 1;
wb_stb_i = 1;
wb_cyc_i = 1;
#sys_clk_period;
wb_wait_for_ack();
end
endtask // wb_write_16bits
 
task wb_write_32bits;
input [31:0] address;
input [31:0] dat;
begin
wb_adr_i = address;
wb_dat_i = dat;
wb_sel_i = 4'hf;
wb_we_i = 1;
wb_stb_i = 1;
wb_cyc_i = 1;
#sys_clk_period;
wb_wait_for_ack();
end
endtask // wb_write_32bits
 
task wb_read_8bits;
input [31:0] address;
output [7:0] dat;
begin
wb_adr_i = address[31:0];
wb_sel_i = address[1:0] == 2'b00 ? 4'h8 :
address[1:0] == 2'b01 ? 4'h4 :
address[1:0] == 2'b10 ? 4'h2 : 4'h1;
wb_we_i = 0;
wb_stb_i = 1;
wb_cyc_i = 1;
#sys_clk_period;
wb_wait_for_ack();
dat = address[1:0] == 2'b00 ? wb_dat_o[31:24] :
address[1:0] == 2'b01 ? wb_dat_o[23:16] :
address[1:0] == 2'b10 ? wb_dat_o[15:8] : wb_dat_o[7:0];
end
endtask // wb_read_16bits
task wb_read_16bits;
input [31:0] address;
output [15:0] dat;
begin
wb_adr_i = {address[31:1],1'b0};
wb_sel_i = address[1] ? 4'h3 : 4'hc;
wb_we_i = 0;
wb_stb_i = 1;
wb_cyc_i = 1;
#sys_clk_period;
wb_wait_for_ack();
dat = address[1] ? wb_dat_o[15:0] : wb_dat_o[31:16];
end
endtask // wb_read_16bits
task wb_read_32bits;
input [31:0] address;
output [31:0] dat;
begin
wb_adr_i = address;
wb_sel_i = 4'hf;
wb_we_i = 0;
wb_stb_i = 1;
wb_cyc_i = 1;
#sys_clk_period;
wb_wait_for_ack();
dat = wb_dat_o;
end
endtask // wb_read_32bits
 
reg [31:0] temp_data;
reg [7:0] status_reg;
 
task wb_cfi_write_16bits;
input [31:0] address;
input [15:0] dat;
begin
wb_write_16bits(address, dat);
wb_read_32bits(32'h0c00_0004, temp_data);
while (!temp_data[7])
wb_read_32bits(32'h0c00_0004, temp_data);
end
endtask // wb_cfi_write_32bits
task wb_cfi_write_32bits;
input [31:0] address;
input [31:0] dat;
begin
wb_cfi_write_16bits(address, dat[31:16]);
wb_cfi_write_16bits(address+2, dat[15:0]);
end
endtask // wb_cfi_write_32bits
 
task wb_cfi_unlock_and_erase_block;
input [31:0] address;
begin
wb_write_32bits(32'h0400_0000+address, 32'd0);
wb_write_32bits(32'h0800_0000+address, 32'd0);
wb_read_32bits(32'h0c00_0004, temp_data);
while (!temp_data[7])
wb_read_32bits(32'h0c00_0004, temp_data);
end
endtask
 
task wb_cfi_read_device_ident;
input [31:0] address;
output [15:0] data;
begin
wb_read_16bits(32'h0e00_0000+(address<<1), data);
end
endtask // wb_cfi_read_device_ident
 
task wb_cfi_query;
input [31:0] address;
output [15:0] data;
begin
wb_read_16bits(32'h0e01_0000+(address<<1), data);
end
endtask // wb_cfi_query
 
task wb_cfi_read_all_device_ident;
begin
$display("%t Reading device identifier information", $time);
wb_cfi_read_device_ident(0,temp_data[15:0]);
$display("%t Manufacturer code: %04h",$time,temp_data[15:0]);
wb_cfi_read_device_ident(31'h1,temp_data[15:0]);
$display("%t Device ID code: %04h",$time,temp_data[15:0]);
wb_cfi_read_device_ident(31'h5,temp_data[15:0]);
$display("%t RCR: %04h",$time,temp_data[15:0]);
wb_cfi_read_device_ident(31'h2 + ((128*1024)>>1),temp_data[15:0]);
$display("%t Block 0 locked?: %04h",$time,temp_data[15:0]);
end
endtask // wb_cfi_read_all_device_ident
 
task wb_cfi_queries;
begin
$display("%t Querying CFI device", $time);
wb_cfi_query(31'h10,temp_data[15:0]);
$display("%t Query ID string: %04h",$time,temp_data[15:0]);
wb_cfi_query(31'h13,temp_data[15:0]);
$display("%t Vendor command set and control interface ID: %04h",$time,temp_data[15:0]);
wb_cfi_query(31'h27,temp_data[15:0]);
$display("%t size 2^n: %04h",$time,temp_data[15:0]);
wb_cfi_query(31'h28,temp_data[15:0]);
$display("%t device interface code: %04h",$time,temp_data[15:0]);
wb_cfi_query(31'h2c,temp_data[15:0]);
$display("%t number of erase block regions: %04h",$time,temp_data[15:0]);
end
endtask
integer i;
/* Main test stimulus block */
initial begin
 
wb_adr_i = 0;
wb_dat_i = 0;
wb_stb_i = 0;
wb_cyc_i = 0;
wb_sel_i = 0;
wb_we_i = 0;
$dumpfile("../out/cfi_ctrl_wb_engine_bench.vcd");
$dumpvars(0);
$display("Starting CFI Wishbone controller test");
#550; // Wait for the part to power up
 
 
wb_cfi_read_all_device_ident();
#500;
wb_cfi_queries();
#500;
/* Ready first block for play*/
wb_cfi_unlock_and_erase_block(0);
/* Clear status register */
wb_write_32bits(32'h0c00_0000, {29'd0,3'b010});
/* Write a 32-bit word */
wb_cfi_write_32bits(32'h0000_0000, 32'hdeadbeef);
 
/* read it back */
wb_read_32bits(32'h0000_0000, temp_data);
 
/* Write 4k of data */
for (i = 0; i< ((4*1024)/4); i=i+1) begin
wb_cfi_write_32bits(32'h0000_0000+i*4, 32'hdeadbeef+i);
end
 
/* Read it back 16-bits at a time and check it */
for (i = 0; i< ((4*1024)/4); i=i+1) begin
wb_read_16bits(32'h0000_0000+i*4, temp_data[31:16]);
wb_read_16bits(32'h0000_0000+i*4+2, temp_data[15:0]);
if (temp_data != (32'hdeadbeef+i))
$display("Read verify error at %h",(i*4));
end
/* Read it back 8-bits at a time and check it */
for (i = 0; i< ((4*1024)/4); i=i+1) begin
wb_read_8bits(32'h0000_0000+i*4, temp_data[31:24]);
wb_read_8bits(32'h0000_0000+i*4+1, temp_data[23:16]);
wb_read_8bits(32'h0000_0000+i*4+2, temp_data[15:8]);
wb_read_8bits(32'h0000_0000+i*4+3, temp_data[7:0]);
if (temp_data != (32'hdeadbeef+i))
$display("Read verify error at %h",(i*4));
end
$finish();
/* Read it back and check it */
for (i = 0; i< ((4*1024)/4); i=i+1) begin
wb_read_32bits(32'h0000_0000+i*4, temp_data);
if (temp_data != (32'hdeadbeef+i))
$display("Read verify error at %h",(i*4));
end
 
/* Test doing things on next block */
wb_cfi_unlock_and_erase_block(32'h20000);
 
/* Write 4k of data */
for (i = 0; i< ((4*1024)/4); i=i+1) begin
wb_cfi_write_32bits(32'h0002_0000+i*4, 32'hdeadbeef+i);
end
/* Read it back and check it */
for (i = 0; i< ((4*1024)/4); i=i+1) begin
wb_read_32bits(32'h0002_0000+i*4, temp_data);
if (temp_data != (32'hdeadbeef+i))
$display("Read verify error at %h",(i*4));
end
 
/* Read it back 16-bits at a time and check it */
for (i = 0; i< ((4*1024)/4); i=i+1) begin
wb_read_16bits(32'h0002_0000+i*4, temp_data[31:16]);
wb_read_16bits(32'h0002_0000+i*4+2, temp_data[15:0]);
if (temp_data != (32'hdeadbeef+i))
$display("Read verify error at %h",(i*4));
end
$display("Finishing CFI Wishbone controller test");
$finish;
end
 
/* timeout function - sim shouldn't run much longer than this */
/*
initial begin
#55000;
$display("Simulation finish due to timeout");
$finish;
end
*/
cfi_ctrl
#(.cfi_engine("ENABLED"))
dut
(
.wb_clk_i(sys_clk),
.wb_rst_i(sys_rst),
 
.wb_adr_i(wb_adr_i),
.wb_dat_i(wb_dat_i),
.wb_stb_i(wb_stb_i),
.wb_cyc_i(wb_cyc_i),
.wb_we_i (wb_we_i ),
.wb_sel_i(wb_sel_i),
.wb_dat_o(wb_dat_o),
.wb_ack_o(wb_ack_o),
.flash_dq_io(DQ),
.flash_adr_o(A),
.flash_adv_n_o(ADV_N),
.flash_ce_n_o(CE_N),
.flash_clk_o(CLK),
.flash_oe_n_o(OE_N),
.flash_rst_n_o(RST_N),
.flash_wait_i(WAIT),
.flash_we_n_o(WE_N),
.flash_wp_n_o(WP_N)
);
 
x28fxxxp30 part(A, DQ, WE_N, OE_N, CE_N, ADV_N, CLK,
WAIT, WP_N, RST_N, VCC, VCCQ, VPP, Info);
 
 
endmodule
/cfi_ctrl/trunk/bench/verilog/x28fxxxp30.v
0,0 → 1,3796
// _/ _/_/
// _/_/ _/_/_/
// _/_/_/_/ _/_/_/
// _/_/_/_/_/ _/_/_/ ____________________________________________
// _/_/_/_/_/ _/_/_/ / /
// _/_/_/_/_/ _/_/_/ / 28F256P30 /
// _/_/_/_/_/ _/_/_/ / /
// _/_/_/_/_/_/ _/_/_/ / 256Mbit /
// _/_/_/_/_/_/ _/_/_/ / single die /
// _/_/_/ _/_/_/ _/_/_/ / /
// _/_/_/ _/_/_/ _/_/_/ / Verilog Behavioral Model /
// _/_/_/ _/_/_/ _/_/_/ / Version 1.3 /
// _/_/_/ _/_/_/ _/_/_/ / /
// _/_/_/ _/_/_/_/_/_/ / Copyright (c) 2010 Numonyx B.V. /
// _/_/_/ _/_/_/_/_/ /___________________________________________/
// _/_/_/ _/_/_/_/
// _/_/ _/_/_/
//
//
// NUMONYX
`include "def.h"
`include "CUIcommandData.h"
`include "data.h"
`include "UserData.h"
`include "BankLib.h"
`include "TimingData.h"
 
// **********************************
//
// Timing Lib Module :
//
// checks all timing constraints
//
// **********************************
 
module TimingLibModule(A, DQ, W_N, G_N, E_N, L_N, WP_N, CK, VPP);
 
input [`ADDRBUS_dim-1:0] A; // Address Bus
input [`DATABUS_dim-1:0] DQ; // Data I/0 Bus
 
input W_N, G_N, E_N, L_N, WP_N, CK;
input [`Voltage_range] VPP;
 
integer AddValid_time;
integer AddNotValid_time;
integer DataValid_time;
integer DataXX_time;
 
integer WriteEnableLow_time;
integer WriteEnableHigh_time;
integer OutputEnableLow_time;
integer OutputEnableHigh_time;
integer LatchEnableHigh_time;
integer LatchEnableLow_time;
integer ChipEnableLow_time;
integer ChipEnableHigh_time;
integer RisingEdge_time;
integer FallingEdge_time;
 
integer WaitValid_time;
 
integer WriteProtectHigh_time;
integer WriteProtectLow_time;
integer VPPSupplyHigh_time;
integer VPPSupplyLow_time;
 
reg afterReset;
 
reg isValid;
reg dataValid;
reg addressValid;
reg reading;
reg writing;
reg dataXX;
time temp;
 
 
initial begin
 
AddValid_time = 0;
AddNotValid_time = 0;
DataValid_time = 0;
DataXX_time = 0;
 
WriteEnableLow_time = 0;
WriteEnableHigh_time = 0;
OutputEnableLow_time = 0;
OutputEnableHigh_time = 0;
LatchEnableHigh_time = 0;
LatchEnableLow_time = 0;
ChipEnableLow_time = 0;
ChipEnableHigh_time = 0;
 
WaitValid_time = 0;
 
WriteProtectHigh_time = 0;
WriteProtectLow_time = 0;
 
RisingEdge_time = 0;
FallingEdge_time = 0;
 
dataValid = `FALSE;
dataXX = `FALSE;
addressValid = `FALSE;
 
reading = `FALSE;
writing = `FALSE;
 
afterReset = `FALSE;
 
end
 
 
// **************
//
// Change address
//
// **************
 
always @(A) begin : AddressCheck
 
if (`TimingChecks == "off")
disable AddressCheck;
 
if ($time > `Reset_time)
begin
if (isAddValid(A)) // Address Valid
begin
temp = $time - AddValid_time;
checkTiming("tAVAV", TimingData_man.tAVAV, temp, "min");
 
temp = $time - WriteEnableHigh_time;
checkTiming("tWHAV", TimingData_man.tWHAV, temp, "min");
 
AddValid_time = $time;
addressValid = `TRUE;
end
 
else
begin
if (isAddXX(A) || isAddZZ(A)) // Address XXXX o ZZZZ
begin
if (addressValid)
begin
temp = $time - LatchEnableHigh_time;
checkTiming("tLHAX", TimingData_man.tLHAX, temp, "min");
 
temp = $time - WriteEnableHigh_time;
checkTiming("tWHAX", TimingData_man.tWHAX, temp, "min");
 
AddNotValid_time = $time;
end
addressValid = `FALSE;
end
end
end
end
 
 
// ***********
//
// Change data
//
// ***********
 
always @(DQ) begin : DataCheck
 
if (`TimingChecks == "off")
disable DataCheck;
 
if ($time > `Reset_time)
begin
 
if (isDataValid(DQ)) // Data Valid
begin
if (ConfigReg_man.isSynchronous) // Synchronous mode
 
begin
if (reading)
if (ConfigReg_man.isRisingClockEdge)
begin
temp = $time - RisingEdge_time;
end
else
begin
temp = $time - FallingEdge_time;
 
end
end
 
else // Asynchronous mode
begin
temp = $time - AddValid_time;
 
temp = $time - LatchEnableLow_time;
 
temp = $time - ChipEnableLow_time;
 
if (reading)
begin
temp = $time - OutputEnableLow_time;
temp = $time - WriteEnableHigh_time;
end
 
DataValid_time = $time;
dataValid = `TRUE;
dataXX = `FALSE;
end
end
else
begin
if (isDataXX(DQ)) // Data XXXX
begin
if (dataValid)
begin
temp = $time - AddNotValid_time;
 
temp = $time - ChipEnableHigh_time;
checkTiming("tEHQX", TimingData_man.tEHQX, temp, "min");
 
temp = $time - OutputEnableHigh_time;
 
end
 
else
begin
temp = $time - ChipEnableLow_time;
checkTiming("tELQX", TimingData_man.tELQX, temp, "min");
 
if (reading)
begin
temp = $time - OutputEnableLow_time;
checkTiming("tGLQX", TimingData_man.tGLQX, temp, "min");
end
end
 
 
DataXX_time = $time;
dataValid = `FALSE;
dataXX = `TRUE;
end
 
else
if (isDataZZ(DQ))
begin
if (dataXX)
begin
temp = $time - ChipEnableHigh_time;
checkTiming("tEHQZ", TimingData_man.tEHQZ, temp, "max");
temp = $time - OutputEnableHigh_time;
checkTiming("tGHQZ", TimingData_man.tGHQZ, temp, "max");
end
 
if (dataValid)
begin
temp = $time - WriteEnableHigh_time;
checkTiming("tWHDX", TimingData_man.tWHDX, temp, "min");
end
dataValid = `FALSE;
dataXX = `FALSE;
end
end
end
end
 
// ******************
//
// Change Chip Enable
//
// ******************
 
always @(posedge E_N) begin : ChipHighCheck // Chip Enable High
 
if (`TimingChecks == "off")
disable ChipHighCheck;
 
if ($time > `Reset_time)
begin
temp = $time - WriteEnableHigh_time;
checkTiming("tWHEH", TimingData_man.tWHEH, temp, "min");
 
ChipEnableHigh_time = $time;
end
end
 
always @(negedge E_N) begin : ChipLowCheck // Chip Enable Low
 
if (`TimingChecks == "off")
disable ChipLowCheck;
 
if ($time > `Reset_time)
begin
ChipEnableLow_time = $time;
end
 
end
 
always @(posedge L_N) begin : LatchLowCheck // Latch Enable High
 
if (`TimingChecks == "off")
disable LatchLowCheck;
 
if ($time > `Reset_time)
begin
temp = $time - AddValid_time;
checkTiming("tAVLH", TimingData_man.tAVLH, temp, "min");
temp = $time - LatchEnableLow_time;
checkTiming("tLLLH", TimingData_man.tLLLH, temp, "min");
temp = $time - ChipEnableLow_time;
checkTiming("tELLH", TimingData_man.tELLH, temp, "min");
LatchEnableHigh_time = $time;
end
end
 
always @(negedge L_N) begin : LatchHighCheck // Latch Enable Low
 
if (`TimingChecks == "off")
disable LatchHighCheck;
 
if ($time > `Reset_time)
begin
temp = $time - WriteEnableHigh_time;
checkTiming("tWHLL", TimingData_man.tWHLL, temp, "min");
 
temp = $time - RisingEdge_time;
checkTiming("tKHLL", TimingData_man.tKHLL, temp, "min");
 
LatchEnableLow_time = $time;
end
 
end
 
always @(posedge G_N) begin : OutputHighCheck // Output Enable High
 
if (`TimingChecks == "off")
disable OutputHighCheck;
 
if ($time > `Reset_time)
begin
OutputEnableHigh_time = $time;
reading = `FALSE;
end
 
end
 
always @(negedge G_N) begin : OutputLowCheck // Output Enable Low
 
if (`TimingChecks == "off")
disable OutputLowCheck;
 
if ($time > `Reset_time)
begin
 
temp = $time - WriteEnableHigh_time;
checkTiming("tWHGL", TimingData_man.tWHGL, temp, "min");
 
 
OutputEnableLow_time = $time;
reading = `TRUE;
end
 
end
 
always @(posedge W_N) begin : WriteHighCheck // Write Enable High
 
if (`TimingChecks == "off")
disable WriteHighCheck;
 
if ($time > `Reset_time)
begin
 
temp = $time - AddValid_time;
checkTiming("tAVWH", TimingData_man.tAVWH, temp, "min");
 
if (writing)
begin
temp = $time - WriteEnableLow_time;
checkTiming("tWLWH", TimingData_man.tWLWH, temp, "min");
end
temp = $time - DataValid_time;
checkTiming("tDVWH", TimingData_man.tDVWH, temp, "min");
 
temp = $time - WriteProtectHigh_time;
checkTiming("tWPHWH", TimingData_man.tWPHWH, temp, "min");
 
temp = $time - VPPSupplyHigh_time;
checkTiming("tVPHWH", TimingData_man.tVPHWH, temp, "min");
 
WriteEnableHigh_time = $time;
writing = `FALSE;
end
end
 
always @(negedge W_N) begin : WriteLowCheck // Write Enable Low
 
if (`TimingChecks == "off")
disable WriteLowCheck;
 
if ($time > `Reset_time)
begin
temp = $time - ChipEnableLow_time;
checkTiming("tELWL", TimingData_man.tELWL, temp, "min");
 
temp = $time - WriteEnableHigh_time;
checkTiming("tWHWL", TimingData_man.tWHWL, temp, "min");
 
WriteEnableLow_time = $time;
writing = `TRUE;
end
end
 
always @(posedge WP_N) begin : WPHighCheck // Write Protect High
 
if (`TimingChecks == "off")
disable WPHighCheck;
 
if ($time > `Reset_time)
begin
WriteProtectHigh_time = $time;
end
end
 
always @(negedge WP_N) begin : WPLowCheck // Write Protect Low
 
if (`TimingChecks == "off")
disable WPLowCheck;
 
if ($time > `Reset_time)
begin
temp = $time - DataValid_time;
checkTiming("tQVWPL", TimingData_man.tQVWPL, temp, "min");
 
WriteProtectLow_time = $time;
end
end
 
always @(posedge VPP) begin : VPPHighCheck // Write Protect High
 
if (`TimingChecks == "off")
disable VPPHighCheck;
 
if ($time > `Reset_time)
begin
VPPSupplyHigh_time = $time;
end
end
 
always @(negedge VPP) begin : VPPLowCheck // Write Protect Low
 
if (`TimingChecks == "off")
disable VPPLowCheck;
 
if ($time > `Reset_time)
begin
temp = $time - DataValid_time;
checkTiming("tQVVPL", TimingData_man.tQVVPL, temp, "min");
 
VPPSupplyLow_time = $time;
 
end
end
 
always @(posedge CK) begin : RisingCKCheck
 
if (`TimingChecks == "off")
disable RisingCKCheck;
 
if ($time > `Reset_time)
begin
temp = $time - LatchEnableLow_time;
checkTiming("tLLKH", TimingData_man.tLLKH, temp, "min");
 
RisingEdge_time = $time;
end
end
 
always @(negedge CK) begin : FallingCKCheck
 
if (`TimingChecks == "off")
disable FallingCKCheck;
 
if ($time > `Reset_time)
begin
temp = $time - LatchEnableLow_time;
checkTiming("tLLKL", TimingData_man.tLLKL, temp, "min");
FallingEdge_time = $time;
end
end
 
 
 
// **********************************************
//
// FUNCTION isAddValid :
// return true if the input address is valid
//
// **********************************************
 
function isAddValid;
 
input [`ADDRBUS_dim - 1 : 0] Add;
 
reg [`ADDRBUS_dim - 1 : 0] Add;
 
reg valid;
integer count;
 
begin
 
valid = `TRUE;
begin : cycle
for (count = 0; count <= `ADDRBUS_dim - 1; count = count + 1)
begin
if ((Add[count] !== 1'b0) && (Add[count] !== 1'b1))
begin
valid = `FALSE;
disable cycle;
end
end
end
isAddValid = valid;
end
endfunction
 
 
// *********************************************
//
// FUNCTION isAddXX :
// return true if the input address is XXXX
//
// *********************************************
 
function isAddXX;
 
input [`ADDRBUS_dim - 1 : 0] Add;
 
reg [`ADDRBUS_dim - 1 : 0] Add;
 
reg allxx;
integer count;
 
begin
 
allxx = `TRUE;
begin : cycle
for (count = 0; count <= `ADDRBUS_dim - 1; count = count + 1)
begin
if (Add[count] !== 1'bx)
begin
allxx = `FALSE;
disable cycle;
end
end
end
isAddXX = allxx;
end
endfunction
 
// *********************************************
//
// FUNCTION isAddZZ :
// return true if the input address is ZZZZ
//
// *********************************************
 
function isAddZZ;
 
input [`ADDRBUS_dim - 1 : 0] Add;
 
reg [`ADDRBUS_dim - 1 : 0] Add;
 
reg allzz;
integer count;
 
begin
 
allzz = `TRUE;
begin : cycle
for (count = 0; count <= `ADDRBUS_dim - 1; count = count + 1)
begin
if (Add[count] !== 1'bz)
begin
allzz = `FALSE;
disable cycle;
end
end
end
isAddZZ = allzz;
end
endfunction
 
// **********************************************
//
// FUNCTION isDataValid :
// return true if the data is valid
//
// **********************************************
 
function isDataValid;
 
input [`DATABUS_dim - 1 : 0] Data;
 
reg [`DATABUS_dim - 1 : 0] Data;
 
reg valid;
integer count;
 
begin
 
valid = `TRUE;
begin : cycle
for (count = 0; count <= `DATABUS_dim - 1; count = count + 1)
begin
if ((Data[count] !== 1'b0) && (Data[count] !== 1'b1))
begin
valid = `FALSE;
disable cycle;
end
end
end
isDataValid = valid;
end
endfunction
 
// ***************************************
//
// FUNCTION isDataXX :
// return true if the data is unknown
//
// ***************************************
 
function isDataXX;
 
input [`DATABUS_dim - 1 : 0] Data;
 
reg [`DATABUS_dim - 1 : 0] Data;
 
reg allxx;
integer count;
 
begin
 
allxx = `TRUE;
begin : cycle
for (count = 0; count <= `DATABUS_dim - 1; count = count + 1)
begin
if (Data[count] !== 1'bx)
begin
allxx = `FALSE;
disable cycle;
end
end
end
isDataXX = allxx;
end
endfunction
 
// ************************************
//
// FUNCTION isDataZZ :
// return true if the data is Hi-Z
//
// ************************************
 
function isDataZZ;
 
input [`DATABUS_dim - 1 : 0] Data;
 
reg [`DATABUS_dim - 1 : 0] Data;
 
reg allzz;
integer count;
 
begin
 
allzz = `TRUE;
begin : cycle
for (count = 0; count <= `DATABUS_dim - 1; count = count + 1)
begin
if (Data[count] !== 1'bz)
begin
allzz = `FALSE;
disable cycle;
end
end
end
isDataZZ = allzz;
end
endfunction
 
// *****************************
//
// Task Check Timing
// check timing constraints
//
// *****************************
 
task checkTiming;
input [8*6:1] tstr;
input [31:0] tOK, tcheck;
input [8*3:1] check_str;
begin
if ((check_str == "min") && (tcheck < tOK)) begin
$display ("[%t] !ERROR: %0s timing constraint violation!! ", $time, tstr);
end
 
else
if ((check_str == "max") && (tcheck > tOK))
$display ("[%t] !ERROR: %0s timing constraint violation!! ", $time, tstr);
end
endtask
 
 
endmodule
 
 
// Protect Manager
// implements the architecture of the memory blocks
 
module BlockLockModule(address, WP_N, RP_N, Info);
input [`ADDRBUS_range] address;
input WP_N, RP_N;
input Info;
 
reg LockArray [`BLOCK_dim - 1 : 0];
reg LockDownArray [`BLOCK_dim - 1 : 0];
 
reg [`BYTE_range] Status;
integer count;
initial begin // constructor sequence
for (count = 0; count <= `BLOCK_dim - 1; count = count + 1) // all blocks are locked at power-up
begin
LockDownArray[count] = `UNLOCKDOWN;
if (`BLOCKPROTECT == "on") LockArray[count] = `LOCK;
else LockArray[count] = `UNLOCK;
end
end
 
always @(negedge RP_N) begin
initLockArray;
end
 
task initLockArray;
begin
for (count = 0; count <= `BLOCK_dim - 1; count = count + 1) // all blocks are locked at power-up
begin
LockDownArray[count] = `UNLOCKDOWN;
LockArray[count] = `LOCK;
end
end
endtask
 
 
 
// ********************************************
//
// FUNCTION isLocked : return the status of the
// specified block
//
// ********************************************
 
function IsLocked; // boolean function primitive
input [`ADDRBUS_range] address;
integer n_block;
 
begin
n_block = BankLib_man.getBlock(address);
IsLocked = (LockArray[n_block] == `LOCK) ? `TRUE : `FALSE;
end
endfunction
 
// ********************************************
//
// FUNCTION isLocked : return the status of the
// specified block
//
// ********************************************
 
function IsUnLocked; // boolean function primitive
input [`ADDRBUS_range] address;
integer n_block;
 
begin
n_block = BankLib_man.getBlock(address);
IsUnLocked = (LockArray[n_block] == `UNLOCK) ? `TRUE : `FALSE;
end
endfunction
 
 
function getLockBit; // boolean function primitive
input [`ADDRBUS_range] address;
integer n_block;
 
begin
n_block = BankLib_man.getBlock(address);
getLockBit = LockArray[n_block];
end
endfunction
 
function getLockDownBit; // boolean function primitive
input [`ADDRBUS_range] address;
integer n_block;
 
begin
n_block = BankLib_man.getBlock(address);
getLockDownBit = LockDownArray[n_block];
end
endfunction
 
 
// ********************************
//
// Task UnLock :
// implements Block UnLock Command
//
// ********************************
 
task UnLock;
output [`BYTE_range] Status;
reg [`BYTE_range] Status;
 
integer n_block;
begin
n_block = BankLib_man.getBlock(address);
Status = `NoError_msg;
if (LockDownArray[n_block]==`LOCKDOWN && WP_N==`LOW) Status = `NoUnLock_msg;
else LockArray[n_block] = `UNLOCK;
end
endtask
 
// ********************************
//
// Task Lock :
// implements Block Lock Command
//
// ********************************
 
task Lock;
output [`BYTE_range] Status;
reg [`BYTE_range] Status;
 
integer n_block;
begin
n_block = BankLib_man.getBlock(address);
Status = `NoError_msg;
LockArray[n_block] = `LOCK;
end
endtask
 
// *****************************************
//
// Task LockDown :
// implements the Block Lock-Down Command
//
// *****************************************
 
task LockDown;
output [`BYTE_range] Status;
reg [`BYTE_range] Status;
 
integer n_block;
begin
n_block = BankLib_man.getBlock(address);
Status = `NoError_msg;
LockDownArray[n_block] = `LOCKDOWN;
end
endtask
 
 
endmodule
 
 
// *************************
//
// CFI Query Module
// Implements the CFI memory
//
// *************************
 
module CFIqueryModule(); //, isCFI);
 
//input isCFI;
 
reg [`BYTE_range] CFIarray [0:`CFI_dim];
reg error;
reg [8*20:1] CFI_file;
integer i;
 
initial begin
if (`organization == "top") CFI_file = "CFImemory_top.vmf";
else CFI_file= "CFImemory_bottom.vmf";
 
for (i=0; i <= `CFI_dim; i = i + 1) CFIarray[i] = {8{`HIGH}}; // CFI Memory Init
$readmemb(CFI_file,CFIarray);
end
 
always @(posedge error) begin
Kernel.SetWarning(`RCFI_cmd,16'h00,`CFIAddrRange_msg);
error = `FALSE;
end
 
function [`WORD_range] Get;
 
input [`ADDRBUS_range] address;
begin
if (address[`BYTE_range] >= 9'h10 && address[`BYTE_range] <= `CFI_dim ) //verificare se tener conto che il primo indirizzo accessibile e' 10h
begin
if (address[`BYTE_range] >= 9'h39 && address[`BYTE_range] <= 9'h109) begin
Get = 8'hXX;
error = `TRUE;
end else begin
 
Get[`LOW_range] = CFIarray[address[`BYTE_range]];
Get[`HIGH_range] = 8'h00;
end
end else
begin
Get = 8'hXX;
error = `TRUE;
end
end
endfunction
 
endmodule
 
// ********************************
//
// Data Error Module
//
// search for errors in data.h
//
// ********************************
 
module DataErrorModule;
 
reg SevError;
 
initial begin
 
SevError = `FALSE;
 
if ((`organization != "top") && (`organization != "bottom"))
begin
SevError = `TRUE;
$display("!Error: BLOCK ORGANIZATION INVALID: it must be top or bottom!!!");
end
 
if ((`BLOCKPROTECT != "on") && (`BLOCKPROTECT != "off"))
begin
SevError = `TRUE;
$display("!Error: BLOCK PROTECT INVALID: it must be on or off!!!");
end
 
if ((`TimingChecks != "on") && (`TimingChecks != "off"))
begin
SevError = `TRUE;
$display("!Error: TIMING CHECKS INVALID: it must be on or off!!!");
end
 
 
if ((`t_access != 100) && (`t_access != 110))
begin
SevError = `TRUE;
$display("!Error: Access time INVALID: it must be 100 ns or 110 ns!!!");
end
 
 
if (SevError) $finish;
end
 
endmodule
 
// ******************************************
//
// Configuration Register module :
//
// implements the configuration register
//
// ******************************************
 
module ConfigRegModule(address,Info);
input [`ADDRBUS_range] address;
input Info;
 
reg [`ConfigurationReg_dim - 1 : 0] CR_reg;
reg [`BYTE_range] Status;
 
// **********************
//
// Setting default values
//
// **********************
 
`define ReadMode_bit 15
`define ClockLatency_MSBbit 14
`define ClockLatency_LSBbit 11
`define WaitPolarity_bit 10
`define WaitConfig_bit 8
`define BurstType_bit 7
`define ValidClockEdge_bit 6
`define WrapBurst_bit 3
`define BurstLength_MSBbit 2
`define BurstLength_LSBbit 0
 
// Interpreter Config Reg\\
 
wire isASynchronous = CR_reg[`ReadMode_bit] ? `TRUE : `FALSE;
wire isSynchronous = CR_reg[`ReadMode_bit] ? `FALSE : `TRUE;
wire [3:0] Xlatency = (CR_reg[`ClockLatency_MSBbit : `ClockLatency_LSBbit]<2 &&
CR_reg[`ClockLatency_MSBbit : `ClockLatency_LSBbit]>15) ? 0 :
CR_reg[`ClockLatency_MSBbit : `ClockLatency_LSBbit];
wire isWaitPolActiveHigh = CR_reg[`WaitPolarity_bit] ? `TRUE : `FALSE;
wire isWaitBeforeActive = CR_reg[`WaitConfig_bit] ? `TRUE : `FALSE;
wire isRisingClockEdge = CR_reg[`ValidClockEdge_bit] ? `TRUE : `FALSE;
wire isWrapBurst = CR_reg[`WrapBurst_bit] ? `FALSE : `TRUE;
wire isNoWrapBurst = CR_reg[`WrapBurst_bit] ? `TRUE : `FALSE;
 
wire [4:0] BurstLength = CR_reg[`BurstLength_MSBbit : `BurstLength_LSBbit] == 1 ? 4 :
CR_reg[`BurstLength_MSBbit : `BurstLength_LSBbit] == 2 ? 8 :
CR_reg[`BurstLength_MSBbit : `BurstLength_LSBbit] == 3 ? 16:
0; // continous Burst
 
 
wire [2:0] BurstLength_bit = CR_reg[`BurstLength_MSBbit : `BurstLength_LSBbit] == 1 ? 2 :
CR_reg[`BurstLength_MSBbit : `BurstLength_LSBbit] == 2 ? 3 :
CR_reg[`BurstLength_MSBbit : `BurstLength_LSBbit] == 3 ? 4:
0; // continous Burst
 
initial begin
Status = `NoError_msg;
CR_reg = `ConfigReg_default;
end
 
always @(isSynchronous) begin
if (Info)
if (isSynchronous)
$write("[%t] Synchronous Read Mode\n",$time);
else
$write("[%t] ASynchronous Read Mode\n",$time);
end
// **********************
//
// ReSet to default value
//
// **********************
always @(Kernel.ResetEvent) begin
Status = `NoError_msg;
CR_reg = `ConfigReg_default;
end
 
// **************************************
//
// FUNCTION getConfigReg :
//
// return the Configuration Register
//
// **************************************
 
function [`ConfigurationReg_dim - 1 : 0] getConfigReg;
input required;
begin
getConfigReg = CR_reg;
end
endfunction
 
// *************************************
//
// FUNCTION putConfigReg :
//
// write the Configuration Register
//
// *************************************
 
task putConfigReg;
output [`BYTE_range] outStatus;
reg [`BYTE_range] outStatus;
 
integer count;
 
begin
CR_reg = address[`ConfigurationReg_dim - 1 : 0];
 
outStatus = Status;
 
end
endtask
 
 
endmodule
 
// ***************************
//
// Electronic Signature Module
//
// ***************************
 
module SignatureModule;
 
reg error;
integer i;
integer n_block;
 
initial begin
end
 
always @(posedge error) begin
Kernel.SetWarning(`RSIG_cmd,16'h00,`SignAddrRange_msg);
error = `FALSE;
end
 
function [`WORD_range] Get;
 
input [`ADDRBUS_range] address;
begin
if (address[`SignAddress_range] == 9'h00)
begin
Get[`LOW_range] = `ManufacturerCode;
Get[`HIGH_range] = 8'h00;
end
else if (address[`SignAddress_range] == 9'h01)
begin
if (`organization == "top") Get[`LOW_range] = `TopDeviceCode;
else Get[`LOW_range] = `BottomDeviceCode;
 
Get[`HIGH_range] = 8'h89;
end
else if (address[`SignAddress_range] == 9'h02)
begin
Get[`LOW_range] = { 6'b0, BlockLock_man.getLockDownBit(address), BlockLock_man.getLockBit(address) };
Get[`HIGH_range] = 8'h00;
end
else if (address[`SignAddress_range] == 9'h05) // Configuration Register
Get = ConfigReg_man.getConfigReg(0);
else if ((address[`SignAddress_range] >= `REGSTART_addr) && (address[`SignAddress_range] <= `REGEND_addr))
begin
Get = ProtectReg_man.RegisterMemory[address[`SignAddress_range] - `REGSTART_addr ];
 
end
else begin
Get = 8'hXX;
error = `TRUE;
end
end
endfunction
 
endmodule
 
// ********************
//
// CUI decoder module :
// decode commands
//
// ********************
 
module CUIdecoder1(DataBus,Name,Cmd,CmdAllowed,Info);
input [`BYTE_range] DataBus, Cmd;
input [8*35:1] Name;
input Info;
input CmdAllowed;
always @Kernel.CUIcommandEvent begin
#1;
if (DataBus == Cmd && CmdAllowed) begin // is a First Command ?
#1 -> Kernel.VerifyEvent;
Kernel.CommandDecode1[Cmd] = !Kernel.CommandDecode1[Cmd];
if (Info) $display("[%t] Command Issued: %0s",$time,Name);
end
else begin
if (`FALSE) $display("[%t] The %0s instruction decode unit is waiting for operation to complete.",$time,Name);
@(Kernel.CompleteEvent or Kernel.ErrorEvent)
if (`FALSE) $display("[%t] The %0s instruction decode unit is listening for next command.",$time,Name);
end
end
endmodule
 
 
// ********************
//
// CUIdecoder manager :
// decode commands
//
// ********************
 
module CUIdecoder2(DataBus,Name,Cmd1,Cmd2,CmdAllowed,Info);
input [`BYTE_range] DataBus, Cmd1, Cmd2;
input [8*27:1] Name;
input Info;
input CmdAllowed;
 
always @Kernel.CUIcommandEvent begin
if (DataBus == Cmd1 && CmdAllowed) begin
#1 -> Kernel.VerifyEvent;
 
@Kernel.CUIcommandEvent
 
if (DataBus == Cmd2 && CmdAllowed) begin
#1 -> Kernel.VerifyEvent;
 
Kernel.CommandDecode2[{Cmd1,Cmd2}] = !Kernel.CommandDecode2[{Cmd1,Cmd2}];
if (Info) $display("[%t] Command Issued: %0s",$time,Name);
end
end
else begin
if (`FALSE) $display("%t The %0s instruction decode unit is waiting for operation to complete.",$time,Name);
@(Kernel.CompleteEvent or Kernel.ErrorEvent)
if (`FALSE) $display("%t The %0s instruction decode unit is listening for next command",$time,Name);
end
end
 
endmodule
 
 
// ****************************
//
// CUI Decoder Manager :
// decode the cUI commands
//
// ****************************
 
module CUIdecoder_Busy1(DataBus,Name,Cmd,CmdAllowed,Info);
input [`BYTE_range] DataBus, Cmd;
input [8*8:1] Name;
input Info;
input CmdAllowed;
 
always @Kernel.CUIcommandEvent begin
if ((DataBus == Cmd) && CmdAllowed) begin
-> Kernel.VerifyEvent;
Kernel.CommandDecode1[Cmd] = !Kernel.CommandDecode1[Cmd];
if (Info) $display("[%t] Command Issued: %0s",$time,Name);
end
 
 
 
end
 
endmodule
 
 
// Erase Manager
// manage the erase functionality
 
module EraseModule(address, data, progVoltOK, progHighVoltOK,Info);
input [`ADDRBUS_range] address;
input [`WORD_range] data;
 
input progVoltOK, progHighVoltOK;
 
input Info;
event ErrorCheckEvent, CompleteEvent;
 
reg [`BYTE_range] Status;
reg [`ADDRBUS_range] hold_address;
reg [`BLOCKADDR_range] hold_block;
 
reg Busy, Suspended, first_time;
integer i;
time startTime, delayTime,Erase_time;
 
initial begin // constructor sequence
Busy = `FALSE;
Suspended = `FALSE;
Erase_time = `MainBlockErase_time;
delayTime = Erase_time;
 
end
 
 
function IsBusy; // boolean function primitive
input obbl; // all functions require a parameter
IsBusy = Busy; // return Boolean value
endfunction
 
function IsSuspended; // boolean function primitive
input obbl; // all functions require a parameter
IsSuspended = Suspended; // return Boolean value
endfunction
 
function IsAddrSuspended; // boolean function primitive
input [`ADDRBUS_range] addr;
IsAddrSuspended = (Suspended && (addr == hold_address));
endfunction
 
function IsBlockSuspended; // boolean function primitive
input [`ADDRBUS_range] addr;
IsBlockSuspended = (Suspended && ((BankLib_man.getBlock(addr) == BankLib_man.getBlock(/*hold_*/addr/*ess*/))));
endfunction
 
// *********************
//
// Task checkConfirm :
// check confirm code
//
// *********************
 
task checkConfirm;
output [`BYTE_range] outStatus;
reg [`BYTE_range] outStatus;
 
begin
 
if (data == `BLKEEconfirm_cmd) outStatus = `NoError_msg;
else outStatus = `WrongEraseConfirm_msg;
 
end
endtask
 
 
task Suspend;
output [`BYTE_range] outStatus;
reg [`BYTE_range] outStatus;
begin
delayTime = delayTime - ($time - startTime);
#`EraseSuspendLatency_time
outStatus = `NoError_msg;
Status = `Suspend_msg;
Suspended = `TRUE;
-> CompleteEvent;
end
endtask
 
task Resume;
output [`BYTE_range] Status;
begin
Suspended = `FALSE;
BlockErase(Status);
end
endtask
 
task BlockErase;
output [`BYTE_range] outStatus;
reg [`BYTE_range] outStatus;
begin
 
 
if (progHighVoltOK)
if (BankLib_man.isMainBlock(address)) Erase_time = `FastMainBlockErase_time;
else Erase_time = `FastParameterBlockErase_time;
else
if (BankLib_man.isMainBlock(address)) Erase_time = `MainBlockErase_time;
else Erase_time = `ParameterBlockErase_time;
 
delayTime = Erase_time;
hold_address = address;
hold_block = BankLib_man.getBlock(address);
 
 
 
fork
begin : Operation
Busy = `TRUE;
startTime = $time;
-> ErrorCheckEvent;
#delayTime Memory_man.EraseBlock(hold_block,Status);
delayTime = Erase_time;
-> CompleteEvent;
end
@CompleteEvent
disable Operation;
join
outStatus = Status;
Busy = `FALSE;
end
endtask
 
always @(ErrorCheckEvent) begin
Status = `NoError_msg;
if (BlockLock_man.IsLocked(hold_address))
Status = `BlockLock_msg;
else if (Memory_man.IsBlockSuspended(hold_address))
Status = `SuspCmd_msg;
else if (!progVoltOK)
Status = `InvVDD_msg;
 
if (Status != `NoError_msg)
->CompleteEvent;
else
fork : ErrorCheck
@(negedge progVoltOK) Status = `InvVDD_msg;
@(Status) -> CompleteEvent;
@(CompleteEvent) disable ErrorCheck;
join
end
 
endmodule //end module Erase
 
 
// *********************
//
// Memory Manager :
// the memory array
//
// *********************
 
module MemoryModule(Info);
input Info;
reg [`WORD_range] memory [0:(`MEMORY_dim) - 1]; // the Memory: word organization
 
initial begin
LoadMemory;
end
 
task LoadMemory; // Initialize and load the memory from a file
integer i;
begin
#0 if (Info) $display("[%t] Inizialize the Memory to default value",$time);
/*
Don't need to preload this memory for these testbenches now -- Julius
for (i = 0; i < `MEMORY_dim; i = i + 1) memory[i] = {16{`HIGH}}; // Memory Init
if (`FILENAME_mem !== "") begin
$readmemb(`FILENAME_mem, memory);
 
if (Info) $display("[%t] Load Memory from file: %s",$time, `FILENAME_mem);
else if (Info) $display("[%t] Warning: File: %s not found",$time, `FILENAME_mem);
end
*/
end
endtask
 
 
function [`WORD_range] Get;
input [`ADDRBUS_range] address;
Get = memory[address];
endfunction
 
 
function IsSuspended;
input [`ADDRBUS_range] address;
IsSuspended = Program_man.IsAddrSuspended(address) || Erase_man.IsAddrSuspended(address) || ProgramBuffer_man.IsAddrSuspended(address);
endfunction
 
function IsBlockSuspended;
input [`ADDRBUS_range] address;
IsBlockSuspended = Program_man.IsBlockSuspended(address) || Erase_man.IsBlockSuspended(address);
endfunction
 
 
task Program;
input [`WORD_range] data;
input [`ADDRBUS_range] address;
output [`BYTE_range] Status;
begin
Status = `NoError_msg;
memory[address] = memory[address] & data;
if (memory[address] != data) Status = `PreProg_msg;
end
endtask
 
task EraseBlock;
input [`INTEGER] block;
output [`BYTE_range] ErrFlag;
 
reg [`ADDRBUS_range] start_address;
reg [`ADDRBUS_range] end_address;
reg [`ADDRBUS_range] address;
 
begin
ErrFlag = `NoError_msg;
start_address = BankLib_man.getBlockAddress(block);
end_address = BankLib_man.BlockBoundaryEndAddr[block];
 
if (start_address > end_address)
begin
address = start_address;
start_address = end_address;
end_address = address;
end
for (address = start_address; address <= end_address; address = address + 1)
memory[address] = `WORDNP;
 
end
endtask
 
task BlockBlankCheck;
input [`INTEGER] block;
output [`BYTE_range] ErrFlag;
 
reg [`ADDRBUS_range] start_address;
reg [`ADDRBUS_range] end_address;
reg [`ADDRBUS_range] address;
 
begin
ErrFlag = `NoError_msg;
start_address = BankLib_man.BlockBoundaryStartAddr[block];
end_address = BankLib_man.BlockBoundaryEndAddr[block];
 
if (start_address > end_address)
begin
address = start_address;
start_address = end_address;
end_address = address;
end
ErrFlag = `NoError_msg;
address = start_address;
while (memory[address] == `WORDNP && address <= end_address )
address = address + 1;
if (memory[address] != `WORDNP)
ErrFlag = `BlankCheckFailed_msg;
 
end
endtask
 
 
 
endmodule //end MemoryModule
 
 
// ***************************************
//
// Output Buffer :
//
// manage the communication between
// the memory and the output data bus
//
// ***************************************
 
module OutputBufferModule(DataInput, DataInputBurst, DataOutput, OutputEnable);
input [`WORD_range] DataInput;
input [`WORD_range] DataInputBurst;
output [`WORD_range] DataOutput;
input OutputEnable;
reg [`WORD_range] DataOutput;
time timeDataV, timeDataX, timeDataZ;
 
initial begin
timeDataV=0;
timeDataX=0;
timeDataZ=0;
SetZ(0);
end
 
task SetValid;
input [63:0] delayTime;
begin
 
if ((delayTime+$time > timeDataV) || (timeDataV < $time)) begin
timeDataV = delayTime + $time;
 
 
disable waitValid;
 
 
disable goValid;
 
end
end
endtask
 
always
fork
begin: goValid
 
#(timeDataV - $time)
if (OutputEnable == 1'b0) begin
if (ConfigReg_man.isASynchronous) DataOutput = DataInput;
else DataOutput = DataInputBurst;
end
end // goValid
begin: waitValid
wait (`FALSE);
end
join
 
task SetX;
input [63:0] delayTime;
begin
if ((delayTime+$time < timeDataX) || (timeDataX < $time)) begin
timeDataX = delayTime + $time;
disable waitX;
 
 
end
end
endtask
 
always fork
begin : goX
#(timeDataX - $time) if ((OutputEnable == `LOW) || (timeDataZ > timeDataX))
DataOutput = 16'hX;
end // goX
begin: waitX
wait (`FALSE);
end
join
 
task SetZ;
input [63:0] delayTime;
begin
if ((delayTime+$time < timeDataZ) || (timeDataZ < $time)) begin
timeDataZ = delayTime + $time;
disable waitZ;
if (timeDataZ < timeDataV)
disable goValid;
if (timeDataZ < timeDataX)
disable goX;
end
end
endtask
 
always begin: waitZ
#(timeDataZ - $time) DataOutput = 16'hZ;
wait (`FALSE);
end
 
endmodule
 
 
// *********************************
//
// Program module :
//
// manage the program operation
//
// *********************************
 
module ProgramModule(address,data, progVoltOK, progHighVoltOK, Info);
input [`WORD_range] data;
input [`ADDRBUS_range] address;
input progVoltOK,progHighVoltOK;
input Info;
event ErrorCheckEvent, CompleteEvent;
reg [`BYTE_range] Status;
reg [`WORD_range] hold_data;
reg [`ADDRBUS_range] hold_address;
reg Busy, Suspended;
 
integer i;
time startTime, delayTime, WordProgram_time;
 
initial begin // constructor sequence
Busy = `FALSE;
Suspended = `FALSE;
WordProgram_time = `WordProgram_time;
delayTime = WordProgram_time;
end
 
always @(progHighVoltOK) begin
if (progHighVoltOK) WordProgram_time=`FastWordProgram_time;
else WordProgram_time=`WordProgram_time;
end
 
function IsBusy; // boolean function primitive
input obbl; // all functions require a parameter
IsBusy = Busy; // return Boolean value
endfunction
 
function IsSuspended; // boolean function primitive
input obbl; // all functions require a parameter
IsSuspended = Suspended; // return Boolean value
endfunction
 
function IsAddrSuspended; // boolean function primitive
input [`ADDRBUS_range] addr;
IsAddrSuspended = (Suspended && (addr == hold_address));
endfunction
 
function IsBlockSuspended; // return true if block is suspended
input [`ADDRBUS_range] addr; begin
IsBlockSuspended = (Suspended && (BankLib_man.getBlock(addr) == BankLib_man.getBlock(/*hold_*/addr/*ess*/)));
end
endfunction
 
 
task Suspend;
output [`BYTE_range] suspErrFlag;
reg [`BYTE_range] suspErrFlag;
begin
delayTime = delayTime - ($time - startTime);
#`ProgramSuspendLatency_time suspErrFlag = `NoError_msg;
Status = `Suspend_msg;
Suspended = `TRUE;
-> CompleteEvent;
end
endtask
 
task Resume;
output [`BYTE_range] ErrFlag;
begin
Suspended = `FALSE;
Program(ErrFlag);
end
endtask
 
task Program;
output [`BYTE_range] outErrFlag;
reg [`BYTE_range] outErrFlag;
begin
if (delayTime == WordProgram_time) begin
hold_data = data;
hold_address = address;
end
fork
begin : Operation
Busy = `TRUE;
startTime = $time;
-> ErrorCheckEvent;
#delayTime Memory_man.Program(hold_data,hold_address,Status);
delayTime = `WordProgram_time;
-> CompleteEvent;
end
@CompleteEvent disable Operation;
join
outErrFlag = Status;
Busy = `FALSE;
end
endtask
 
always @(ErrorCheckEvent) begin
Status = `NoError_msg;
if (BlockLock_man.IsLocked(hold_address))
Status = `BlockLock_msg;
else
if (Memory_man.IsSuspended(hold_address))
Status = `SuspAcc_msg;
else if (!progVoltOK)
Status = `InvVDD_msg;
 
if (Status != `NoError_msg) ->CompleteEvent;
else
fork : ErrorCheck
@(negedge progVoltOK) Status = `InvVDD_msg;
@(Status) -> CompleteEvent;
@(CompleteEvent) disable ErrorCheck;
join
end
 
endmodule // end PrograModule
 
 
// *********************************
//
// Buffer Ehnanced Program module :
//
// program buffer functionality
//
// *********************************
 
module BuffEnhancedFactProgramModule(address, data, progVoltOK, progHighVoltOK, Info);
input [`ADDRBUS_range] address;
input [`WORD_range] data;
input progVoltOK, progHighVoltOK, Info;
 
event ErrorCheckEvent,ErrorCheckEvent_inVerify, CompleteEvent, WatchAddressEvent;
reg [`BYTE_range] Status;
reg [`WORD_range] hold_data, hold_StartBlock;
reg [`ADDRBUS_range] hold_address, startAddress;
reg [`WORD_range] bufferData [`BuffEnhProgramBuffer_range];
 
reg Busy;
time Program_time;
integer i,Len;
 
initial begin // constructor sequence
Busy = `FALSE;
Status = `NoError_msg;
Program_time = `WordProgram_time;
EmptyBuffer;
end
 
task EmptyBuffer;
begin
for (i = 0; i < `BuffEnhProgramBuffer_dim; i = i + 1)
bufferData[i] = 16'hFFFF;
Len=0;
end
endtask
 
function IsBusy; // boolean function primitive
input obbl; // all functions require a parameter
IsBusy = Busy; // return Boolean value
endfunction
 
task Setup;
output [`BYTE_range] outStatus;
begin
Status = `NoError_msg;
Len =0;
startAddress = address;
hold_address = address;
 
hold_StartBlock = BankLib_man.getBlock(address);
-> ErrorCheckEvent;
#0 outStatus=Status;
if (Status == `NoError_msg) begin
if (Info) $display("[%t] Enhanced Factory Program -> Setup Phase",$time);
if (Info) $display("[%t] Enhanced Factory Program: Start address: %h",$time,startAddress);
#`EnhBuffProgramSetupPhase_time;
Busy = `TRUE;
end
end
endtask
 
task Exit;
output [`BYTE_range] outStatus;
begin
Busy = `FALSE;
outStatus = Status;
if (Info) $display("[%t] Enhanced Factory Program -> Exit Phase",$time);
if (Len != `BuffEnhProgramBuffer_dim)
$display("[%t] Warning --- The buffer must be completely filled for programming to occur",$time);
end
endtask
 
task Load;
output [`BYTE_range] outStatus;
begin
if (BankLib_man.getBlock(address) != hold_StartBlock) Status = `ExitPHASE_BEFP_msg;
else begin
bufferData[Len] = data;
if (Info) $display("[%t] Enhanced Factory Program -> Load: data[%d]=%h ",$time,Len,bufferData[Len]);
Len = Len + 1;
if (Len == `BuffEnhProgramBuffer_dim) Status = `ProgramPHASE_BEFP_msg;
end
outStatus = Status;
end
endtask
 
task Program;
output [`BYTE_range] outStatus;
reg [`BYTE_range] outStatus;
begin
fork
begin : Operation
if (Info) $display("[%t] Enhanced Factory Program {Program Phase}",$time);
#`EnhBuffProgram_time
 
if (Info) $display("[%t] Enhanced Factory Program {End of Program Phase}",$time);
for (i = startAddress;i < (`BuffEnhProgramBuffer_dim + startAddress); i = i + 1) begin
Memory_man.Program(bufferData[i - startAddress],i,Status);
end
-> CompleteEvent; //end of program
end
@CompleteEvent begin
disable Operation;
end
join
if (Status == `ProgramPHASE_BEFP_msg) begin //prova
Status = `NoError_msg;
end
outStatus = Status;
end
endtask
 
always @(ErrorCheckEvent) begin
Status = `NoError_msg;
if (BlockLock_man.IsLocked(hold_address))
Status = `BlockLock_msg;
else if (!progVoltOK)
Status = `InvVDD_msg;
else if (!progHighVoltOK)
Status = `InvVPP_msg;
if (Status != `NoError_msg)
->CompleteEvent;
else
fork : ErrorCheck
@(negedge progVoltOK) Status = `InvVDD_msg;
@(negedge progHighVoltOK) Status = `InvVPP_msg;
@(CompleteEvent) disable ErrorCheck;
join
end
 
 
 
endmodule
 
// ******************************************
//
// Protect Register module :
//
// operations on the protection register
//
// ******************************************
 
module ProtectRegModule(address, data, voltOK, Info);
input [`ADDRBUS_range] address;
input [`DATABUS_range] data;
input voltOK, Info;
reg [`WORD_range] RegisterMemory[`REG_dim - 1 :0];
reg [`BYTE_range] Status;
reg Busy;
reg [`ADDRBUS_range] AddressLatched;
event ErrorCheckEvent, CompleteEvent;
integer i;
reg [`ADDRBUS_range] hold_addr;
reg [`DATABUS_range] hold_data;
 
 
initial begin // constructor sequence
Busy = `FALSE;
RegisterMemory[0] = `PRL_default;
for (i = 1; i < `REG_dim; i = i + 1) begin
RegisterMemory[i] = `WORDNP;
end
end
 
 
function IsBusy; // boolean function primitive
input required; // all functions require a parameter
IsBusy = Busy; // return Boolean value
endfunction
 
function UDNisLocked; // boolean function primitive
input obbl; // input is required
if ((RegisterMemory[`PROTECTREGLOCK_addr - `REGSTART_addr] | `UDNprotect_bit) == `UDNprotect_bit)
UDNisLocked = `TRUE;
else
UDNisLocked = `FALSE;
endfunction
 
function UPisLocked; // boolean function primitive
input obbl; // input is required
UPisLocked = ((RegisterMemory[`PROTECTREGLOCK_addr - `REGSTART_addr] | `UPprotect_bit) == `UPprotect_bit) ? `TRUE : `FALSE;
endfunction
 
function isUDNaddress;
input [`ADDRBUS_range] address;
if ((address >= `UDNREGSTART_addr) && ( address <= `UDNREGEND_addr)) // Check UDN register Address Bound
isUDNaddress = `TRUE;
else isUDNaddress = `FALSE;
endfunction
 
function isUPaddress;
input [`ADDRBUS_range] address;
if ((address >= `UPREGSTART_addr) && (address <= `UPREGEND_addr)) // Check UP register Address Bound
isUPaddress = `TRUE;
else isUPaddress = `FALSE;
endfunction
 
function [`BYTE_range] ExtIndexPRL; // bit index of PRL register
input [`ADDRBUS_range] addr;
ExtIndexPRL=(addr - `ExtREGSTART_regionaddr) / `ExtREG_regiondim;
endfunction
 
function isExtLocked; // boolean function primitive
input [`ADDRBUS_range] addr; // input is required
reg [`BYTE_range] bitIndex;
begin
bitIndex = ExtIndexPRL(addr); // protect bit index of Extended Protection Register Memory
isExtLocked = !(RegisterMemory[(`ExtPROTECTREGLOCK_addr - `REGSTART_addr)][bitIndex]);
end
endfunction
 
function isExtValidAddress;
input [`ADDRBUS_range] address;
if ((address >= `ExtREGSTART_regionaddr) && (address <= `ExtREGEND_regionaddr) ) // Check ExtRegister Address Bound
isExtValidAddress = `TRUE;
else isExtValidAddress = `FALSE;
endfunction
 
task Program;
output [`BYTE_range] outStatus;
reg [`BYTE_range] outStatus;
begin
Busy = `TRUE;
hold_addr = address[`REG_addrbitRange];
hold_data = data;
if (Info) $write("[%t] OTP Program Memory[%h]=%h\n",$time,hold_addr,data);
fork
begin : Operation
-> ErrorCheckEvent;
#`WordProgram_time RegisterMemory[hold_addr - `REGSTART_addr] = RegisterMemory[hold_addr - `REGSTART_addr] & hold_data;
-> CompleteEvent;
end
@CompleteEvent disable Operation;
join
outStatus = Status;
Busy = `FALSE;
end
endtask
 
always @(ErrorCheckEvent) begin
Status = `NoError_msg;
if (( address < `REGSTART_addr) || ( address > `REGEND_addr)) // Check Address Bound
Status = `AddrRange_msg;
else if ( isUDNaddress(address) && UDNisLocked(1'bX) )
Status = `UDNlock_msg;
else if ((isUPaddress(address) && UPisLocked(1'bX)))
Status = `UPlock_msg;
else if ( isExtValidAddress(hold_addr) & isExtLocked(hold_addr) )
Status = `ExtREGLock_msg;
else if (Kernel.Suspended)
Status = `SuspCmd_msg;
else if (!voltOK)
Status = `InvVDD_msg;
 
if (Status != `NoError_msg)
->CompleteEvent;
else
fork : ErrorCheck
@(negedge voltOK) Status = `InvVDD_msg;
@(Status) -> CompleteEvent;
@(CompleteEvent) disable ErrorCheck;
join
end
endmodule //end ProtectRegModule
 
 
// Read Manager
// Manage the read operation
 
module ReadModule(dataOutput,address,voltOK,Info);
output [`WORD_range] dataOutput;
input [`ADDRBUS_range] address;
input voltOK;
input Info;
reg [`WORD_range] dataOutput, regRead;
reg [1:0] Mode, oldMode;
reg [`BYTE_range] Status;
 
integer i;
 
initial begin
regRead = 0;
Mode = `ReadArray_bus;
oldMode = `ReadArray_bus;
dataOutput = `DATABUS_dim'hzzzz;
end
 
task SetMode;
input [1:0] newMode;
output [`BYTE_range] Status;
begin
Status = `NoError_msg;
if (Info && (newMode!=Mode)) begin
case (newMode)
`ReadArray_bus : $display ("[%t] Device now in Read Array mode ", $time);
`ReadCFI_bus : $display ("[%t] Device now in Read CFI mode ", $time);
`ReadSignature_bus : $display ("[%t] Device now in Read Electronic Signature Mode ", $time);
`ReadStatusReg_bus : $display ("[%t] Device now in Read Status Register Mode ", $time);
default : $display ("[%t] !!!Model Error: Read mode not recognized!!!", $time);
endcase
 
oldMode=Mode;
Mode = newMode;
end
end
endtask
 
 
always @Kernel.ResetEvent begin
Mode = `ReadArray_bus;
end
 
always @(negedge Kernel.Ready) begin // Configure according to status register
Mode = `ReadStatusReg_bus;
end
 
always @Kernel.ReadEvent begin // Main execution of a read is based on an event
 
 
case (Mode)
`ReadArray_bus : begin
dataOutput = Memory_man.Get(address);
if (Info) $display("[%t] Data Read result: memory[%h]=%h", $time,address,dataOutput);
end
`ReadCFI_bus : begin
dataOutput = CFIquery_man.Get(address);
if (Info) $display("[%t] Data Read result: CFI_memory[%h]=%h", $time,address,dataOutput);
end
`ReadSignature_bus : begin
dataOutput = Signature_man.Get(address);
if (Info) $display("[%t] Read Device Identifier(addr=%h) :%h", $time,address,dataOutput);
end
 
`ReadStatusReg_bus : begin
dataOutput = SR_man.SR;
if (Info) $display("[%t] Read Status Register: %b", $time,dataOutput[`BYTE_range]);
end
 
default : $display("[%t] !!!Model Error: Read mode not recognized!!!", $time);
endcase
if ((Mode == `ReadArray_bus) && (Memory_man.IsSuspended(address) == `TRUE)) begin
dataOutput = 16'hXX;
Kernel.SetWarning(`RD_cmd,8'hXX,`SuspAcc_msg);
end
end
 
endmodule
// end Module Read
 
 
// *************************************************
//
// Status Register module :
//
// implements the Status Register of the device
//
// *************************************************
 
module StatusRegModule(Info);
input Info;
 
 
reg EraseStatus, ProgramStatus,
VpenStatus, BlockProtectionStatus, BW_status;
 
reg [`BYTE_range] Status;
 
wire [7:0] SR = {Kernel.Ready, // bit 7
Erase_man.IsSuspended(1'bX), // bit 6
EraseStatus, // bit 5
ProgramStatus, // bit 4
VpenStatus, // bit 3
Program_man.IsSuspended(1'bX) || ProgramBuffer_man.IsSuspended(1'bX), // bit 2
BlockProtectionStatus, // bit 1
BW_status}; // bit 0
wire [7:0] SR_Info = SR;
 
 
 
//-----------------
// Init
//-----------------
 
initial begin
EraseStatus=1'b0;
ProgramStatus=1'b0;
VpenStatus=1'b0;
BlockProtectionStatus=1'b0;
BW_status=1'b0;
end
 
 
always @(SR_Info) if (Kernel.Ready!=1'bZ)
if (Info) $display("[%t] Status Register Update: %b",$time, SR_Info);
 
always @(Kernel.ResetEvent) begin
Clear(Status);
end
 
 
always @(Kernel.Ready,ProtectReg_man.Busy, BuffEnhancedFactProgram_man.Busy)
begin
if (Kernel.Ready)
BW_status = `FALSE;
else
if (BuffEnhancedFactProgram_man.Busy == `TRUE)
BW_status=`TRUE;
 
end
 
always @(Kernel.ErrorEvent) begin //Update status register bits upon specific errors
#0;
case(Kernel.GetError(1'bX))
`InvVDD_msg : begin VpenStatus = `TRUE; end
`InvVPP_msg : begin VpenStatus = `TRUE; end
`BlockLock_msg : begin BlockProtectionStatus = `TRUE; end
`UDNlock_msg : begin ProgramStatus = `TRUE; end
`UPlock_msg : begin ProgramStatus = `TRUE; end
 
`ProtRegAddrRange_msg : begin
BlockProtectionStatus = `TRUE;
end
`ExtREGLock_msg : begin
BlockProtectionStatus = `TRUE;
end
 
`CmdSeq_msg : begin ProgramStatus = `TRUE; EraseStatus = `TRUE; end
`AddrRange_msg : begin ProgramStatus = `TRUE; EraseStatus = `TRUE; end
`AddrTog_msg : begin ProgramStatus = `TRUE; EraseStatus = `TRUE; end
`PreProg_msg : begin ProgramStatus = `TRUE; end
`WrongEraseConfirm_msg : begin ProgramStatus = `TRUE; EraseStatus = `TRUE; end
`WrongBlankCheckConfirm_msg : begin
ProgramStatus = `TRUE; EraseStatus = `TRUE;
end
`BlankCheckFailed_msg : begin
EraseStatus = `TRUE;
end
`LeastAddr0: begin
ProgramStatus = `TRUE;
end
 
endcase
case(Kernel.GetCmd(4'h1))
`PG_cmd : begin ProgramStatus = `TRUE; end
`PRREG_cmd : begin ProgramStatus = `TRUE; end
`PB_cmd : begin ProgramStatus = `TRUE; end
`BLKEE_cmd : begin EraseStatus = `TRUE; end
`BL_cmd : if (Kernel.GetCmd(4'h2) == `BLconfirm_cmd) ProgramStatus = `TRUE;
`BUL_cmd : if (Kernel.GetCmd(4'h2) ==`BULconfirm_cmd) EraseStatus = `TRUE;
`BLD_cmd : if (Kernel.GetCmd(4'h2) ==`BLDconfirm_cmd) ProgramStatus = `TRUE;
`BuffEnhProgram_cmd :
if (Kernel.GetCmd(4'h2) == `BuffEnhProgramCfrm_cmd)
ProgramStatus = `TRUE;
 
endcase
end
 
task Clear;
output [`BYTE_range] Status;
begin
Status = `NoError_msg;
EraseStatus = `FALSE;
ProgramStatus = `FALSE;
VpenStatus = `FALSE;
BlockProtectionStatus = `FALSE;
BW_status = `FALSE;
end
endtask
 
endmodule // end module status register
 
 
// *************
//
// Kernel Module
//
// *************
 
module KernelModule(VDD, VDDQ, VPP, Info);
input [`Voltage_range] VDD, VDDQ, VPP;
input Info;
event CUIcommandEvent, VerifyEvent, ErrorEvent, CompleteEvent, ResetEvent, ReadEvent, ProgramCompleteEvent, EraseCompleteEvent;
 
reg voltOK, progVoltOK, eraseVoltOK, lockVoltOK, ioVoltOK, lockOverrideOK;
reg progHighVoltOK, eraseHighVoltOK;
reg [8'hFF:0] CommandDecode1;
reg [16'hFFFF:0] CommandDecode2;
reg [7:0] lastStatus, lastCmd1, lastCmd2;
 
// Device Status
 
wire Ready = (!Program_man.Busy && !ProgramBuffer_man.Busy && !BuffEnhancedFactProgram_man.Busy
&& !Erase_man.Busy && !ProtectReg_man.Busy && !BlankCheck_man.Busy);
 
 
wire Suspended = Program_man.Suspended || Erase_man.Suspended || ProgramBuffer_man.Suspended;
 
initial begin // constructor sequence
CommandDecode1 = 8'h00; // initialize decode success status variables
CommandDecode2 = 16'h0000;
end
 
 
always @(voltOK) begin
if (!voltOK) begin
$display("[%t] !ERROR: Invalid VDD Voltage.",$time);
-> ErrorEvent;
end
else
$display("[%t] VDD Voltage is OK",$time);
end
 
always @(ioVoltOK) begin
if (!ioVoltOK) begin
$display("[%t] !ERROR: Invalid VDDQ I/O voltage.", $time);
-> ErrorEvent;
end
else
$display("[%t] VDDQ Voltage is OK",$time);
end
 
always @(VDD) begin
if ((VDD < `VDDmin) | (VDD > `VDDmax))
voltOK = `FALSE;
else
voltOK = `TRUE;
end
 
 
always @(VDDQ) begin // check i/o voltage constraints
if ((VDDQ >= `VDDQmin) && (VDDQ <= `VDDQmax))
ioVoltOK = `TRUE;
else
ioVoltOK = `FALSE;
end
 
always @(VPP) begin // program/erase/lock
if ((VPP>=`VPPmin && VPP<=`VPPmax)) begin
progVoltOK = `TRUE;
eraseVoltOK = `TRUE;
lockVoltOK = `TRUE;
progHighVoltOK = `FALSE;
eraseHighVoltOK = `FALSE;
end
else if ((VPP>=`VPPHmin) && (VPP<=`VPPHmax)) begin
progVoltOK = `TRUE;
eraseVoltOK = `TRUE;
lockVoltOK = `TRUE;
progHighVoltOK = `TRUE;
eraseHighVoltOK = `TRUE;
end
else begin
progVoltOK = `FALSE;
eraseVoltOK = `FALSE;
lockVoltOK = `FALSE;
progHighVoltOK = `FALSE;
eraseHighVoltOK = `FALSE;
end
end
 
 
function [7:0] GetError;
input required;
GetError = lastStatus;
endfunction
 
function [7:0] GetCmd;
input commandNum;
GetCmd = (commandNum == 1) ? lastCmd1 : lastCmd2;
endfunction
 
task SetWarning;
input [7:0] Cmd1, Cmd2;
input [7:0] Status;
begin
Report(Cmd1,Cmd2,Status);
lastStatus = Status;
end
endtask
 
task SetError;
input [7:0] Cmd1, Cmd2;
input [7:0] ErrFlag;
begin
SetWarning(Cmd1,Cmd2,ErrFlag);
-> ErrorEvent; // Only errors set error event
end
endtask
 
 
task Report;
input [7:0] Cmd1, Cmd2;
input [7:0] Status;
begin
lastStatus = Status;
lastCmd1 = Cmd1;
lastCmd2 = Cmd2;
if ((lastStatus != `NoError_msg) || Info) begin //Display error .
$write("[%t] ",$time);
case(Status)
`NoError_msg : begin $write(" Command Completion Successful "); end
`CmdSeq_msg : begin $write(" !Error: [Invalid Command]\n Sequence Command Unknown"); -> ErrorEvent; end
`SuspCmd_msg : begin $write(" !Error: [Invalid Command]\n Cannot execute this command during suspend"); -> ErrorEvent; end
`SuspAcc_msg : begin $write(" !Error: [Invalid Command]\n Cannot access this address due to suspend"); -> ErrorEvent; end
`SignAddrRange_msg : begin $write(" !Error: [Invalid Address]\n Signature Address out of range"); end
`CFIAddrRange_msg : begin $write(" !Error: [Invalid Address]\n CFI Address out of range"); end
`AddrRange_msg : begin $write(" !Error: [Invalid Address]\n Address out of range"); -> ErrorEvent; end
`AddrTog_msg : begin $write(" !Error: [Program Buffer]\n Cannot change block address during command sequence"); -> ErrorEvent; end
`BuffSize_msg : begin $write(" !Error: [Program Buffer]\n Buffer size is too large (Max Size is %d) ",`ProgramBuffer_dim); -> ErrorEvent; end
`InvVDD_msg : begin $write(" !Error: [Invalid Supply]\n Voltage Supply must be: VDD>VDDmin and VDD<VDDmax "); -> ErrorEvent; end
`InvVPP_msg : begin $write(" !Error: [Invalid Program Supply]\n Program Supply Voltage must be: VPP>VPPHmin and VPP<VPPHmax for this Operation"); -> ErrorEvent; end
`ByteToggle_msg : begin $write(" !Error: [BYTE_N Toggled]\n Cannot toggle BYTE_N while busy"); -> ErrorEvent; end
`PreProg_msg : begin $write(" !Error: [Program Failure]\n Program Failure due to cell failure"); -> ErrorEvent; end
`UDNlock_msg : begin $write(" !Error: [Program Failure]\n Unique Device Number Register is locked"); -> ErrorEvent; end
`UPlock_msg : begin $write(" !Error: [Program Failure]\n User Programmable Register is locked"); -> ErrorEvent; end
`ExtREGLock_msg : begin $write(" !Error: [Program Failure]\n Extended User Programmable OTP is locked"); -> ErrorEvent; end
`NoUnLock_msg : begin $write(" #Warning: [Locked Down Warning]\n Invalid UnLock Block command in Locked-Down Block"); end
`SuspAccWarn_msg : begin $write(" #Warning: [Invalid Access]\n It isn't possible access this address due to suspend"); end
`BlockLock_msg : begin $write(" !Error: [Locked Error]\n Cannot complete operation when the block is locked "); -> ErrorEvent; end
`BlkBuffer_msg : begin $write(" !Error: [Program Buffer] Program Buffer cannot cross block boundary"); end
`AddrCFI_msg : begin $write(" #Warning: [Invalid CFI Address]\n CFI Address out of range"); end
`NoBusy_msg : begin $write(" #Warning: [NO Busy]\n Device is not Busy"); end
`NoSusp_msg : begin $write(" #Warning: [NO Suspend]\n Nothing previus suspend command"); end
`Suspend_msg : begin $write(" Suspend of "); end
`WrongEraseConfirm_msg : begin
$write(" !Error: [Wrong Erase Confirm Code ");
-> ErrorEvent;
end
`LeastAddr0 : begin
$write(" !Error: [Program Failure]\n Least Significative bit [%2d downto 0] of Start Address must be 0",`ProgramBuffer_addrDim-1);
-> ErrorEvent;
end
`WrongBlankCheckConfirm_msg : begin
$write(" !Error: [Confirm Code] Wrong Blank Check Confirm Code ");
-> ErrorEvent;
end
 
`WrongBlankCheckBlock: begin
$write(" !Error: [Blank Check Failure]\n The block must be a main block");
-> ErrorEvent;
end
 
`BlankCheckFailed_msg : begin $write(" !Error: [Blank Check]\n Blank Check Failed ");
-> ErrorEvent;
end
 
default : begin $write(" !ERROR: [Unknown error]\n Flag=%h, cmd1=%hh, cmd2=%hh",Status,Cmd1,Cmd2); -> ErrorEvent; end
endcase
case (Cmd1)
16'hXX : $display(" !Error: [General Error}\n Error not defined");
`RD_cmd : $display(" { Read Array }");
`RSR_cmd : $display(" { Read Status Register }");
`RSIG_cmd : $display(" { Read Electronic Signature }");
`RCFI_cmd : $display(" { Read CFI }");
`PG_cmd : $display(" { Program }");
`BuffEnhProgram_cmd : $display(" { Buffer Enhanced Factory Program }");
 
`SCR_cmd | `BL_cmd | `BUL_cmd | `BLD_cmd
: begin
if (Cmd2 == `SCRconfirm_cmd) $display(" { Set Configuration Register }");
if (Cmd2 == `BLconfirm_cmd) $display(" { Block Lock }");
if (Cmd2 == `BULconfirm_cmd) $display(" { Block UnLock }");
if (Cmd2 == `BLDconfirm_cmd) $display(" { Block Lock-Down }");
end
`PER_cmd : $display(" { Program/Erase Resume }");
`PRREG_cmd : $display(" { Protection Register Command }");
`BLKEE_cmd : $display(" { Block Erase }");
`BLNKCHK_cmd : $display(" { Blank Check }");
`CLRSR_cmd : $display(" { Clear Status Register }");
`PES_cmd : $display(" { Program/Erase Suspend }");
`PB_cmd : $display(" { Write to Buffer and Program }");
default : $display(" {unknown command: %hh}", Cmd1);
endcase
end
end
endtask
 
task CheckTime;
input [8*6:1] tstr;
input [31:0] tdiff, tprev;
begin
if ($time - tprev < tdiff) begin
$display ("[%t] !ERROR: %0s timing constraint violation: %0d-%0d < %0dns ", $time, tstr, $time, tprev, tdiff);
-> ErrorEvent;
end
end
endtask
 
endmodule // end module Kernel
 
 
 
 
 
module x28fxxxp30(A, DQ, W_N, G_N, E_N, L_N, K, WAIT, WP_N, RP_N, VDD, VDDQ, VPP, Info);
 
// Signal Bus
input [`ADDRBUS_dim-1:0] A; // Address Bus
inout [`DATABUS_dim-1:0] DQ; // Data I/0 Bus
// Control Signal
input W_N; // Write Enable
input G_N; // Output Enable
input E_N; // Chip Enable
input L_N; // Latch Enable
input K; // Clock
input WP_N; // Write Protect
input RP_N; // Reset/Power-Down
 
// Voltage signal rappresentad by integer Vector which correspond to millivolts
input [`Voltage_range] VDD; // Supply Voltage
input [`Voltage_range] VDDQ; // Input/Output Supply Voltage
input [`Voltage_range] VPP; // Optional Supply Voltage for fast Program & Erase
 
// Others Signal
output WAIT; // Wait
reg wait_;
assign WAIT = wait_;
input Info; // Enable/Disable Information of the operation in the memory
wire CLK;
assign CLK = (K ~^ ConfigReg_man.isRisingClockEdge);
reg CLOCK;
// === Internal Signal ===
// Chip Enable
wire CE_N = E_N & Kernel.voltOK & RP_N;
 
// Output Enable
wire OE_N = G_N | CE_N | !Kernel.ioVoltOK | !RP_N;
// Write Enable
wire WE_N = W_N | CE_N;
 
// Latch Enable
 
wire LE_N = L_N | CE_N;
// === Bus Latch ===
// Data Bus
wire [`DATABUS_dim-1:0] DataBusIn;
wire [`DATABUS_dim-1:0] DataBurst;
 
// read burst is in wait state
wire isWait;
 
// Address Bus
reg [`ADDRBUS_dim - 1:0] AddrBusIn;
 
// Status
//aggiunti stati buffenha...e blank....
reg [`BYTE_range] KernelStatus, ReadStatus, EraseStatus, ProgramStatus, BuffEnhancedProgramStatus,
LockStatus, ConfigStatus, BufferStatus,BlankCheckStatus,ProgramBufferStatus,
SuspendStatus, ResumeStatus, ClearSRStatus, ProtectRegStatus;
 
 
reg [`BYTE_range] status=`Free_pes;
 
//address latching in read operation
always @(negedge LE_N) if (W_N==`HIGH) begin
if (KernelStatus == `READY && ConfigReg_man.isASynchronous)
@(posedge LE_N) begin
if (L_N)
 
AddrBusIn = A; // AddressBus has been Latched
 
end
end
 
always @(negedge LE_N) if (W_N==`HIGH) begin :latching_a
if (KernelStatus == `READY) begin
if(ConfigReg_man.isSynchronous)
fork
begin : L_Address
 
@(posedge LE_N) if (L_N) begin
AddrBusIn = A; // AddressBus has been Latched
disable K_Address;
 
end
end
begin : K_Address
 
@(posedge CLK) begin
 
AddrBusIn = A; // AddressBus has been Latched
disable L_Address;
end
end
join
 
end
end
 
 
always @(negedge WE_N) begin
if (KernelStatus==`READY)
@(posedge WE_N) begin
if(OE_N==`HIGH)
AddrBusIn = A; // AddressBus has been Latched
 
end
end
 
integer i;
integer n_block;
 
// Wait Driver
time timeWaitDriver,timeWaitDriverZ;
 
reg PB_init=0;
reg P_init=0;
reg BP_init=0;
reg Prog_init=0;
 
always @(PB_init,P_init,BP_init) begin
Prog_init=(PB_init ||P_init || BP_init);
end
 
wire [`BYTE_range] AccessTime;
 
// ****************
//
// Modules Istances
//
// ****************
 
DataErrorModule DataError_man(); // Check for errors on UserData.h
 
CUIdecoder1 ReadArray_Command (DQ[`LOW_range], "Read Array ", `RD_cmd, (Kernel.Ready && !Prog_init), Info),
ReadSR_Command (DQ[`LOW_range], "Read Status Register ", `RSR_cmd, !Prog_init, Info),
ReadSign_Command (DQ[`LOW_range], "Read Electronic Signature ", `RSIG_cmd, (Kernel.Ready && !Prog_init), Info),
ReadCFI_Command (DQ[`LOW_range], "Read CFI ", `RCFI_cmd, (Kernel.Ready && !Prog_init), Info),
Program_Command (DQ[`LOW_range], "Program ", `PG_cmd, (Kernel.Ready && !Prog_init), Info),
 
ProgramBuffer_Command (DQ[`LOW_range], "Program Buffer ", `PB_cmd, (Kernel.Ready && !Prog_init), Info),
ProgramReg_Command (DQ[`LOW_range], "Protection Register Program ", `PRREG_cmd, (Kernel.Ready && !Prog_init), Info),
Resume_Command (DQ[`LOW_range], "Resume ", `PER_cmd, (Kernel.Ready && Kernel.Suspended), Info),
BlockErase_Command (DQ[`LOW_range], "Block Erase ", `BLKEE_cmd,(Kernel.Ready && !Prog_init), Info),
ClearSR_Command (DQ[`LOW_range], "Clear Status Register ", `CLRSR_cmd, (Kernel.Ready && !Prog_init), Info),
 
BlankCheck_Command (DQ[`LOW_range], "Blank Check ", `BLNKCHK_cmd, (Kernel.Ready && !Prog_init), Info),
BuffEnhactoryProgram_Command (DQ[`LOW_range], "Buffer Enh.Factory Program [Setup]", `BuffEnhProgram_cmd,(Kernel.Ready && !Prog_init), Info);
 
 
CUIdecoder_Busy1 Suspend_Command (DQ[`LOW_range], "Suspend ", `PES_cmd, !Kernel.Ready, Info);
 
CUIdecoder2 BlockLock_Command (DQ[`LOW_range], "Block Lock ", `BL_cmd, `BLconfirm_cmd, (Kernel.Ready && !Prog_init), Info),
BlockUnlock_Command (DQ[`LOW_range], "Block UnLock ", `BUL_cmd, `BULconfirm_cmd, (Kernel.Ready && !Prog_init), Info),
BlockLockDown_Command (DQ[`LOW_range], "Block Lock-Down ", `BLD_cmd, `BLDconfirm_cmd, (Kernel.Ready && !Prog_init), Info),
SetConfigReg_Command (DQ[`LOW_range], "Set Configuration Register ", `SCR_cmd, `SCRconfirm_cmd, (Kernel.Ready && !Prog_init), Info);
 
KernelModule Kernel (VDD, VDDQ, VPP, Info);
ReadModule Read_man (DataBusIn, AddrBusIn, Kernel.ioVoltOK, Info);
OutputBufferModule OutputBuffer_man (DataBusIn, DataBurst, DQ, OE_N);
StatusRegModule SR_man (Info);
MemoryModule Memory_man (Info);
ProgramModule Program_man (AddrBusIn, DQ, Kernel.progVoltOK, Kernel.progHighVoltOK, Info);
 
BuffEnhancedFactProgramModule BuffEnhancedFactProgram_man(AddrBusIn, DQ, Kernel.progVoltOK, Kernel.progHighVoltOK, Info);
ProtectRegModule ProtectReg_man (AddrBusIn, DQ, Kernel.progVoltOK, Info);
EraseModule Erase_man (AddrBusIn, DQ, Kernel.eraseVoltOK, Kernel.progHighVoltOK, Info);
 
 
BlankCheckModule BlankCheck_man (AddrBusIn, DQ, Kernel.eraseVoltOK, Kernel.progHighVoltOK, Info);
 
BlockLockModule BlockLock_man (AddrBusIn, WP_N, RP_N, Info);
ProgramBufferModule ProgramBuffer_man (AddrBusIn, DQ, Kernel.progVoltOK, Info);
SignatureModule Signature_man (); // , `FALSE);
CFIqueryModule CFIquery_man (); // , `TRUE);
ConfigRegModule ConfigReg_man (AddrBusIn,Info); // implements the Configuration Register
BurstModule Burst_man (AddrBusIn, DataBurst, isWait, CLK, CLOCK, L_N, G_N,W_N, Info);
 
BankLib BankLib_man ();
TimingDataModule TimingData_man ();
TimingLibModule TimingLib_man (A,DQ,W_N,G_N,E_N,L_N,WP_N,K,VPP);
 
initial begin
 
$timeformat(-9, 0, " ns", 12); // Format time displays to screen
-> Kernel.ResetEvent; // Reset Device
KernelStatus = `BUSY; // Device is Busy
$display ("[%t] --- Device is Busy (start up time) --- ", $time);
#(TimingData_man.tVDHPH) KernelStatus = `READY; // End of Start-Up Time
$display ("[%t] --- Device is Ready (end of start-up time) --- ", $time);
 
AddrBusIn = `ADDRBUS_dim'hZ;
 
wait_ = 1'hZ;
CLOCK = 1'b0;
end
 
// Recognize command input
always @(negedge WE_N) begin
if (KernelStatus==`READY)
@(posedge WE_N) begin
 
-> Kernel.CUIcommandEvent; // new command has been written into Kernel.
 
end
end
 
// Check error
always @(Kernel.CUIcommandEvent) begin : Timeout
#3
-> Kernel.ErrorEvent;
disable Verify;
end
 
// Verify command issued
always @(Kernel.CUIcommandEvent) begin : Verify
@(Kernel.VerifyEvent)
 
disable Timeout;
end
 
// Default to Read Array command
always @(negedge OE_N) begin
if (OE_N == `LOW && (ConfigReg_man.isASynchronous)) begin
if (L_N==0) AddrBusIn=A;
#1
-> Kernel.ReadEvent;
end
end
 
// Page Read
always @(A) begin
if ((OE_N == `LOW) && (A !== `ADDRBUS_dim'hZ) && (A !== `ADDRBUS_dim'hx) && (ConfigReg_man.isASynchronous)) begin
AddrBusIn = A;
#0 -> Kernel.ReadEvent;
end
end
 
 
// Reset the Kernel
always @(negedge RP_N) begin
-> Kernel.ResetEvent;
if (Info) $display ("[%t] Device has been reset ", $time);
KernelStatus = `BUSY;
@(posedge RP_N) KernelStatus = `READY;
end
 
// ----- Recognize Command Input -----
always @(Kernel.CommandDecode1[`RD_cmd]) if (KernelStatus==`READY) begin // Read Array
Read_man.SetMode(`ReadArray_bus, ReadStatus);
Kernel.Report(`RD_cmd, 8'hXX, ReadStatus);
#1 -> Kernel.CompleteEvent;
end
 
always @(Kernel.CommandDecode1[`RSR_cmd]) if (KernelStatus==`READY) begin // Read Status Register
Read_man.SetMode(`ReadStatusReg_bus, ReadStatus);
Kernel.Report(`RSR_cmd, 8'hXX, ReadStatus);
#1 -> Kernel.CompleteEvent;
end
 
 
always @(Kernel.CommandDecode1[`RSIG_cmd]) if (KernelStatus==`READY ) begin // Read Electronic Signature
Read_man.SetMode(`ReadSignature_bus, ReadStatus);
Kernel.Report(`RSIG_cmd, 8'hXX, ReadStatus);
#1 -> Kernel.CompleteEvent;
end
 
always @(Kernel.CommandDecode1[`RCFI_cmd]) if (KernelStatus==`READY) begin // Read CFI
Read_man.SetMode(`ReadCFI_bus, ReadStatus);
Kernel.Report(`RCFI_cmd, 8'hXX, ReadStatus);
#1 -> Kernel.CompleteEvent;
end
 
always @(Kernel.CommandDecode1[`PG_cmd]) if (KernelStatus==`READY) begin // Program
P_init=1;
@Kernel.CUIcommandEvent
#1 -> Kernel.VerifyEvent;
Program_man.Program(ProgramStatus);
Kernel.Report(`PG_cmd, 8'hXX, ProgramStatus);
-> Kernel.CompleteEvent;
P_init=0;
end
 
 
always @(Kernel.CommandDecode1[`PRREG_cmd]) if (KernelStatus==`READY) begin // Protection Register Program
@Kernel.CUIcommandEvent
#1 -> Kernel.VerifyEvent;
ProtectReg_man.Program(ProtectRegStatus);
Kernel.Report(`PRREG_cmd, 8'hXX, ProtectRegStatus);
-> Kernel.CompleteEvent;
end
 
always @(Kernel.CommandDecode1[`PES_cmd]) if (KernelStatus==`READY) begin // Suspend
if (Program_man.IsBusy(1'bX))
Program_man.Suspend(SuspendStatus);
else if (ProgramBuffer_man.IsBusy(1'bX))
ProgramBuffer_man.Suspend(SuspendStatus);
else if (Erase_man.IsBusy(1'bX))
Erase_man.Suspend(SuspendStatus);
-> Kernel.CompleteEvent;
end
 
 
always @(Kernel.CommandDecode1[`PER_cmd]) if (KernelStatus==`READY) begin // Program/Erase Resume
ResumeStatus = `NoError_msg;
if (Program_man.IsSuspended(1'bX)) begin
Program_man.Resume(ProgramStatus);
Kernel.Report(`PG_cmd, 8'hXX, ProgramStatus);
end
else if (ProgramBuffer_man.IsSuspended(1'bX)) begin
ProgramBuffer_man.Resume(BufferStatus);
Kernel.Report(`PB_cmd, 8'hXX, BufferStatus);
end
else if (Erase_man.IsSuspended(1'bX)) begin
Erase_man.Resume(EraseStatus);
Kernel.Report(`BLKEE_cmd, 8'hXX, EraseStatus);
end
else
ResumeStatus = `NoSusp_msg;
Kernel.Report(`PER_cmd, 8'hXX, ResumeStatus);
-> Kernel.CompleteEvent;
 
end
 
always @(Kernel.CommandDecode1[`BLKEE_cmd]) if (KernelStatus==`READY) begin // Block Erase
Read_man.SetMode(`ReadStatusReg_bus,ReadStatus);
EraseStatus=`NoError_msg;
@Kernel.CUIcommandEvent
Erase_man.checkConfirm(EraseStatus);
#1 -> Kernel.VerifyEvent;
if (EraseStatus != `NoError_msg)
Kernel.Report(`BLKEE_cmd, `BLKEEconfirm_cmd, EraseStatus);
else
begin
Erase_man.BlockErase(EraseStatus);
Kernel.Report(`BLKEE_cmd, `BLKEEconfirm_cmd , EraseStatus);
-> Kernel.CompleteEvent;
end
end
 
always @(Kernel.CommandDecode1[`CLRSR_cmd]) if (KernelStatus==`READY) begin // Clear Status Register
SR_man.Clear(ClearSRStatus);
Kernel.Report(`CLRSR_cmd, 8'hXX, ClearSRStatus);
#1 -> Kernel.CompleteEvent;
end
 
 
//aggiunta ************************************************
// PB Fast Program Commands
always @(Kernel.CommandDecode1[`PB_cmd]) if (KernelStatus==`READY) begin // Write to Program and Buffer
ProgramBufferStatus = `NoError_msg;
PB_init=1;
Read_man.SetMode(`ReadStatusReg_bus, ReadStatus);
@Kernel.CUIcommandEvent
ProgramBuffer_man.SetCount(ProgramBufferStatus);
#1 -> Kernel.VerifyEvent;
if (ProgramBufferStatus == `NoError_msg) begin
for (i=1; i <= ProgramBuffer_man.GetCount(1'bX); i=i+1) begin : GetData
@Kernel.CUIcommandEvent
#1;
 
ProgramBuffer_man.Load(ProgramBufferStatus);
#1 -> Kernel.VerifyEvent;
if (ProgramBufferStatus != `NoError_msg)
disable GetData;
end
@Kernel.CUIcommandEvent
if (DQ[`BYTE_range] != `PBcfm_cmd)
ProgramBufferStatus = `CmdSeq_msg;
else begin
#1 -> Kernel.VerifyEvent;
ProgramBuffer_man.Program(ProgramBufferStatus);
end
end
Kernel.Report(`PB_cmd, 8'hXX, ProgramBufferStatus);
->Kernel.CompleteEvent;
PB_init=0;
end
//*************************************************************************
 
always @(Kernel.CommandDecode2[{`BL_cmd,`BLconfirm_cmd}]) if (KernelStatus==`READY) begin // Block Lock
BlockLock_man.Lock(LockStatus);
Kernel.Report(`BL_cmd, `BLconfirm_cmd, LockStatus);
-> Kernel.CompleteEvent;
end
 
always @(Kernel.CommandDecode2[{`BUL_cmd,`BULconfirm_cmd}]) if (KernelStatus==`READY) begin // Block UnLock
BlockLock_man.UnLock(LockStatus);
Kernel.Report(`BUL_cmd,`BULconfirm_cmd, LockStatus);
-> Kernel.CompleteEvent;
end
 
always @(Kernel.CommandDecode2[{`BLD_cmd,`BLDconfirm_cmd}]) if (KernelStatus==`READY) begin // Block Lock-Down
BlockLock_man.LockDown(LockStatus);
Kernel.Report(`BLD_cmd,`BLDconfirm_cmd, LockStatus);
-> Kernel.CompleteEvent;
end
 
always @(Kernel.CommandDecode2[{`SCR_cmd,`SCRconfirm_cmd}]) if (KernelStatus==`READY) begin // Set Configuration Register
ConfigReg_man.putConfigReg(ConfigStatus);
Kernel.Report(`SCR_cmd,`SCRconfirm_cmd, ConfigStatus);
-> Kernel.CompleteEvent;
end
 
 
// BC
always @(Kernel.CommandDecode1[`BLNKCHK_cmd]) if (KernelStatus==`READY) begin // Blank Check
BlankCheckStatus=`NoError_msg;
Read_man.SetMode(`ReadStatusReg_bus, ReadStatus);
@Kernel.CUIcommandEvent
BlankCheck_man.checkConfirm(BlankCheckStatus);
#1 -> Kernel.VerifyEvent;
if (BlankCheckStatus != `NoError_msg) begin
Kernel.Report(`BLNKCHK_cmd, `BLNKCHKconfirm_cmd, BlankCheckStatus);
end else
begin
BlankCheck_man.BlankCheck(BlankCheckStatus);
Kernel.Report(`BLNKCHK_cmd, `BLNKCHKconfirm_cmd, BlankCheckStatus);
end
-> Kernel.CompleteEvent;
 
end
// BEFP
always @(Kernel.CommandDecode1[`BuffEnhProgram_cmd]) if (KernelStatus==`READY) begin // Buffer Enhanced Factory Program: Setup Phase
Read_man.SetMode(`ReadStatusReg_bus, ReadStatus);
BP_init=1;
@Kernel.CUIcommandEvent
#1 -> Kernel.VerifyEvent;
if (Kernel.Suspended | !Kernel.Ready)
BuffEnhancedProgramStatus = `SuspCmd_msg;
else begin
if (DQ[`LOW_range]!=`BuffEnhProgramCfrm_cmd)
BuffEnhancedProgramStatus=`CmdSeq_msg;
else begin
if (Info) $display("[%t] Command Issued: Buffer Enh.Factory Program [Confirm]",$time);
BuffEnhancedFactProgram_man.Setup(BuffEnhancedProgramStatus);
if (BuffEnhancedProgramStatus == `NoError_msg) begin
while (BuffEnhancedProgramStatus == `NoError_msg) begin // Loop Program - Enhanced Factory Program: Program Phase
if (Info) $display("[%t] Enhanced Factory Program -> Load Phase",$time);
while (BuffEnhancedProgramStatus == `NoError_msg ) begin // Loop Load - Enhanced Factory Program: Load Phase
@Kernel.CUIcommandEvent
#1 -> Kernel.VerifyEvent;
BuffEnhancedFactProgram_man.Load(BuffEnhancedProgramStatus);
end
if (BuffEnhancedProgramStatus==`ProgramPHASE_BEFP_msg) begin
BuffEnhancedFactProgram_man.Program(BuffEnhancedProgramStatus);
end
end
BuffEnhancedFactProgram_man.Exit(BuffEnhancedProgramStatus);
end
end
if (BuffEnhancedProgramStatus == `ExitPHASE_BEFP_msg)
BuffEnhancedProgramStatus = `NoError_msg;
end
Kernel.Report(`BuffEnhProgram_cmd,`BuffEnhProgramCfrm_cmd, BuffEnhancedProgramStatus);
-> Kernel.CompleteEvent;
BP_init=0;
end
 
 
 
//***********************************************************
 
// Decode Delays for Page Mode Reads
 
//******************************************************
 
// Page mode
always
begin :nopage
@(A[`ADDRBUS_dim - 1:4])
disable page;
 
OutputBuffer_man.SetValid(TimingData_man.tAVQV);
end
 
// Page mode
always
begin :page
@(A[3:0]) //pagina di 16 words
OutputBuffer_man.SetValid(TimingData_man.tAVQV1);
end
 
 
// Output Buffer delays
 
always @(negedge E_N) begin
OutputBuffer_man.SetX(TimingData_man.tELQX);
OutputBuffer_man.SetValid(TimingData_man.tELQV);
 
end
 
always @(negedge G_N) begin
#0;
OutputBuffer_man.SetX(TimingData_man.tGLQX);
OutputBuffer_man.SetValid(TimingData_man.tGLQV);
 
end
 
always @(posedge CLK) begin
CLOCK = !CLOCK;
end
 
always @(negedge CLK) begin
CLOCK = !CLOCK;
end
 
 
 
reg waiting=1;
 
always @(posedge G_N) begin
 
waiting=1;
 
end
 
 
 
always @(CLK) begin
 
if ((!G_N) && (CE_N == `LOW) && (ConfigReg_man.isSynchronous) && (CLK)) begin
 
if (ConfigReg_man.isWaitBeforeActive && Burst_man.firstEOWL && waiting) begin
OutputBuffer_man.SetX(TimingData_man.tKHQX);
@(posedge (CLK))
OutputBuffer_man.SetX(TimingData_man.tKHQX);
OutputBuffer_man.SetValid(TimingData_man.tKHQV);
waiting=0;
 
end else begin
OutputBuffer_man.SetX(TimingData_man.tKHQX);
OutputBuffer_man.SetValid(TimingData_man.tKHQV);
end
end
end
 
always @(negedge L_N) if(W_N==`HIGH)begin
if (ConfigReg_man.isSynchronous && CE_N==`LOW) begin
OutputBuffer_man.SetValid(TimingData_man.tLLQV);
 
end
end
 
 
always @(RP_N) begin
if (RP_N == `HIGH)
OutputBuffer_man.SetValid(TimingData_man.tPHWL);
end
 
always @(posedge CE_N) begin
OutputBuffer_man.SetZ(TimingData_man.tEHQZ);
end
 
always @(posedge G_N) begin
OutputBuffer_man.SetZ(TimingData_man.tGHQZ);
OutputBuffer_man.SetZ(TimingData_man.tGHTZ);
 
end
 
 
 
////////////////////////////////
always @(CE_N) begin
if (CE_N == `LOW && W_N==`HIGH && G_N == `LOW) begin
if (ConfigReg_man.isSynchronous)
wait_ = #(TimingData_man.tELTV) ConfigReg_man.isWaitPolActiveHigh;
else wait_ = #(TimingData_man.tELTV) !ConfigReg_man.isWaitPolActiveHigh;
end
else
wait_ = #(TimingData_man.tEHTZ) 1'hZ;
end
 
always @(G_N) begin
if (G_N == `LOW && CE_N == `LOW && W_N==`HIGH) begin
if (ConfigReg_man.isSynchronous) begin
wait_ = #(TimingData_man.tGLTV) ConfigReg_man.isWaitPolActiveHigh;
end else begin
wait_ = #(TimingData_man.tGLTV) !ConfigReg_man.isWaitPolActiveHigh;
end
end
else begin if (G_N == `HIGH )
wait_ = #(TimingData_man.tGHTZ) 1'hZ;
disable Burst_man.pollingBurst;
end
end
 
 
 
 
always @(isWait) begin
 
if ((CE_N == `LOW) && (G_N == `LOW) && ConfigReg_man.isSynchronous ) begin
if (CLK) begin
if (isWait == `LOW ) begin
if(!Burst_man.nWait) wait_ = #(TimingData_man.tKHTV) ConfigReg_man.isWaitPolActiveHigh;
else wait_ = #(TimingData_man.tKHTX) ConfigReg_man.isWaitPolActiveHigh;
end else begin
if (!Burst_man.nWait) wait_ = #(TimingData_man.tKHTV) !ConfigReg_man.isWaitPolActiveHigh;
else wait_ = #(TimingData_man.tKHTX) !ConfigReg_man.isWaitPolActiveHigh;
end
 
end else
fork
begin
@(posedge(CLK))
if (isWait == `LOW) begin
if(!Burst_man.nWait) wait_ = #(TimingData_man.tKHTV) ConfigReg_man.isWaitPolActiveHigh;
else wait_ = #(TimingData_man.tKHTX) ConfigReg_man.isWaitPolActiveHigh;
end else begin
if (!Burst_man.nWait) wait_ = #(TimingData_man.tKHTV) !ConfigReg_man.isWaitPolActiveHigh;
else wait_ = #(TimingData_man.tKHTX) !ConfigReg_man.isWaitPolActiveHigh;
end
end
 
begin
@(isWait)
if (CLK) begin
if (isWait == `LOW) begin
if(!Burst_man.nWait) wait_ = #(TimingData_man.tKHTV) ConfigReg_man.isWaitPolActiveHigh;
else wait_ = #(TimingData_man.tKHTX) ConfigReg_man.isWaitPolActiveHigh;
end else begin
if (!Burst_man.nWait) wait_ = #(TimingData_man.tKHTV) !ConfigReg_man.isWaitPolActiveHigh;
else wait_ = #(TimingData_man.tKHTX) !ConfigReg_man.isWaitPolActiveHigh;
end
 
end
end
 
join
end else if (G_N == `HIGH && isWait == `HIGH && W_N==`HIGH)
$display("%t --- WARNING --- WAIT should be deasserted but OE# is not yet LOW. Please check the timings!",$time);
end
 
 
endmodule
 
 
 
// *********************************
//
// Burst module :
//
// manage the Read Burst operation
//
// *********************************
 
module BurstModule(address, data, ISWAIT, CLK, CLOCK, L_N, G_N, W_N, Info);
input [`ADDRBUS_range] address;
output [`WORD_range] data;
reg [`WORD_range] data;
 
input CLK;
input CLOCK;
input L_N;
input G_N;
input W_N;
output ISWAIT;
input Info;
 
reg [`ADDRBUS_range] Start_address, Sync_address,new_address;
reg EnableBurst, isValidData, IsNowWait, endSingleSynchronous;
reg [2:0] incLSBaddress, incMSBaddress, temp_address;
 
wire isSingleSynchronous = (Read_man.Mode != `ReadArray_bus) ? `TRUE : `FALSE;
 
integer WaitState,nWait,nRead,xLatency;
//aggiunta per il calcolo degli nwait
integer boundary,offset;
reg firstEOWL;
 
initial begin // constructor sequence
Start_address = `ADDRBUS_dim'h000000;
EnableBurst = `FALSE;
endSingleSynchronous = `FALSE;
data = 16'hZZ;
nWait = 0;
IsNowWait = `FALSE;
isValidData = `FALSE;
xLatency=0;
nRead=0;
WaitState=0;
firstEOWL=0;
end
 
always @(G_N) if (G_N==`TRUE) begin
IsNowWait = `FALSE;
isValidData = `FALSE;
EnableBurst = `FALSE;
endSingleSynchronous = `FALSE;
data = 16'hZZ;
nWait = 0;
xLatency=0;
nRead=0;
WaitState=0;
firstEOWL=0;
end
 
 
always @(isValidData) begin
case (isValidData)
 
1: if (!ConfigReg_man.isWaitBeforeActive) begin
IsNowWait = `TRUE;
end
 
0: begin if (!ConfigReg_man.isWaitBeforeActive)
IsNowWait = `FALSE;
 
end
endcase
end
 
 
assign ISWAIT = (IsNowWait) ? `TRUE : `FALSE;
 
 
always @(negedge L_N) if(W_N==`HIGH) begin : pollingBurst
fork : pollingBurst
 
begin: L_lacthing
@(posedge L_N) if (ConfigReg_man.isSynchronous) begin
#1;
Start_address = address;
Sync_address = address;
firstEOWL=0;
disable K_lacthing;
@(posedge CLK) begin
 
case(ConfigReg_man.BurstLength)
 
0: begin
boundary =16;
offset = address[3:0];
end
16:begin
boundary =16;
offset = address[3:0];
end
 
8: begin
boundary =8;
offset = address[2:0];
end
 
 
4:begin
boundary =4;
offset = address[1:0];
end
endcase
xLatency = ConfigReg_man.Xlatency;
WaitState = xLatency - (boundary - offset);
if (WaitState < 0) WaitState =0;
nWait = 0;
EnableBurst = `TRUE;
data = 16'hXX;
nRead = 0;
isValidData = `FALSE;
endSingleSynchronous=`FALSE;
disable pollingBurst;
end
end
else EnableBurst = `FALSE;
end
 
begin: K_lacthing
@(posedge CLK) if (ConfigReg_man.isSynchronous && L_N==`LOW) begin
#1;
Start_address = address;
Sync_address = address;
firstEOWL=0;
disable L_lacthing;
 
@(posedge CLK) begin
 
case(ConfigReg_man.BurstLength)
 
0: begin
boundary =16;
offset = address[3:0];
end
16:begin
boundary =16;
offset = address[3:0];
end
 
8: begin
boundary =8;
offset = address[2:0];
end
 
 
4:begin
boundary =4;
offset = address[1:0];
end
endcase
xLatency = ConfigReg_man.Xlatency;
WaitState = xLatency - (boundary - offset); //
if (WaitState < 0) WaitState =0;
nWait = 0;
EnableBurst = `TRUE;
data = 16'hXX;
nRead = 0;
isValidData = `FALSE;
endSingleSynchronous=`FALSE;
disable pollingBurst;
end
end
else EnableBurst = `FALSE;
end
join
$display(" %t address=%h",$time,Start_address);
end
 
 
always @(posedge (CLK)) if(G_N==`LOW) begin
if (EnableBurst) begin
if (xLatency == 2 && ConfigReg_man.isWaitBeforeActive)
IsNowWait = `TRUE;
 
if (xLatency == 1) begin
isValidData = `TRUE;
if (offset == 4'd15 && ConfigReg_man.isWaitBeforeActive && WaitState!=0 && (ConfigReg_man.isNoWrapBurst || ConfigReg_man.BurstLength == 5'd00)) begin
IsNowWait = `FALSE;
 
end
 
end
if (xLatency) xLatency = xLatency - 1; //vuol dire se xLatency e' >1 o diverso da zero????
end
end
 
always @(nRead) begin
if (isSingleSynchronous && nRead>=1) begin //End of SingleBurstRead???
endSingleSynchronous=`TRUE;
isValidData = `FALSE;
end
if((offset + nRead) == 4'd15 && ConfigReg_man.isWaitBeforeActive && WaitState!=0 && (ConfigReg_man.isNoWrapBurst || ConfigReg_man.BurstLength == 5'd00)) begin
IsNowWait = `FALSE;
 
end
end
 
 
always @(CLK) begin
if (EnableBurst) begin
if (!xLatency) begin // burst is ongoing(after xLatency)
if (!G_N) begin
if (nWait || endSingleSynchronous) data = `DATABUS_dim'hXXXX; //Wait State;
else begin // Read is Possible!
// -- \\
case (Read_man.Mode)
`ReadArray_bus : begin
data = Memory_man.Get(Sync_address);
@(posedge (CLK)) if (Info && !G_N) $write("[%t] Burst Read: Memory[%h]=%h\n",$time,Sync_address,data);
end
`ReadCFI_bus : begin
data = CFIquery_man.Get(Sync_address);
@(posedge (CLK)) if (Info && !G_N) $write("[%t] Burst Read: CFIMemory[%h]=%h\n",$time,Sync_address,data);
end
`ReadSignature_bus : begin
data = Signature_man.Get(Sync_address);
@(posedge (CLK)) if (Info && !G_N) $write("[%t] Burst Read: Electronic Signature[%h]=%h\n",$time,Sync_address,data);
end
`ReadStatusReg_bus : begin
data = SR_man.SR;
@(posedge (CLK)) if (Info && !G_N) $write("[%t] Burst Read: StatusRegister: %b\n",$time,data[`BYTE_range]);
end
default : $display("[%t] !!!Model Error: Read mode not recognized!!!", $time);
endcase
// -- \\
end
if((CLK)) begin
if (!nWait) // Wait State??? if no calculate next address
begin
new_address = Sync_address + 1;
nRead = nRead + 1;
end
if (!isSingleSynchronous) begin
 
// Calcultate Address for Sequential and Wrap Burst
if ((ConfigReg_man.BurstLength != 5'd00) && ConfigReg_man.isWrapBurst) begin
case (ConfigReg_man.BurstLength_bit)
3'd2: new_address = {Sync_address[`ADDRBUS_dim - 1 : 2], new_address[1:0] };
3'd3: new_address = {Sync_address[`ADDRBUS_dim - 1 : 3], new_address[2:0] };
3'd4: new_address = {Sync_address[`ADDRBUS_dim - 1 : 4], new_address[3:0] };
endcase
end
// Calculate Next Wait State
if (ConfigReg_man.isNoWrapBurst || (ConfigReg_man.BurstLength == 5'd00) ) //Calculate WAIT STATE
if ((new_address[3:0]==4'd0) && (Sync_address[3:0] == 4'd15)) begin
if(!ConfigReg_man.isWaitBeforeActive) begin
 
if (nWait<WaitState && !firstEOWL) begin
nWait = nWait+1; // Another Wait State???
isValidData = `FALSE;
end else begin
nWait = 0; // end of wait state
Sync_address = new_address;
isValidData = `TRUE;
firstEOWL =1;
 
end
 
end else begin
if (nWait<WaitState-1 && !firstEOWL ) begin
nWait = nWait+1; // Another Wait State???
IsNowWait = `FALSE;
end else begin
nWait = 0; // end of wait state
Sync_address = new_address;
IsNowWait = `TRUE;
firstEOWL =1;
 
end
end
 
end
if (!nWait)
if ((nRead<ConfigReg_man.BurstLength) || (ConfigReg_man.BurstLength==5'd00) // Read Data is Over Burst Lenght???
&& !endSingleSynchronous) // end of SingleSinchronous Burst Read ???
Sync_address = new_address;
end // !isSyn
end //aggiunta
end //G_N
end // XLatency
end //Enable Burst
end
 
 
endmodule // end Burst Module
 
 
// Erase Manager
// manage the erase functionality
 
module BlankCheckModule(address, data, progVoltOK, progHighVoltOK,Info);
 
input [`WORD_range] data;
input [`ADDRBUS_range] address;
input progVoltOK, progHighVoltOK;
input Info;
 
event ErrorCheckEvent, CompleteEvent;
 
reg [`BYTE_range] Status;
reg [`ADDRBUS_range] hold_address;
reg [`BLOCKADDR_range] hold_block;
 
 
reg Busy;
integer i;
time startTime, delayTime, Erase_time;
 
initial begin // constructor sequence
Busy = `FALSE;
Erase_time = `MainBlockErase_time; //modificato
delayTime = Erase_time;
end
 
always @(progVoltOK,progHighVoltOK,address) begin
if (progHighVoltOK)
if (BankLib_man.isMainBlock(address)) Erase_time=`FastMainBlockErase_time;
else Erase_time=`FastParameterBlockErase_time;
else
if (BankLib_man.isMainBlock(address)) Erase_time=`MainBlockErase_time;
else Erase_time=`ParameterBlockErase_time;
end
 
 
function IsBusy; // boolean function primitive
input obbl; // all functions require a parameter
IsBusy = Busy; // return Boolean value
endfunction
 
 
 
// *********************
//
// Task checkConfirm :
// check confirm code
//
// *********************
 
task checkConfirm;
output [`BYTE_range] outStatus;
reg [`BYTE_range] outStatus;
 
begin
 
if (data == `BLNKCHKconfirm_cmd) outStatus = `NoError_msg;
else outStatus = `WrongBlankCheckConfirm_msg;
end
endtask
 
 
 
 
 
// ****************
//
// Task Blank Check
//
// ****************
 
task BlankCheck;
output [`BYTE_range] outStatus;
reg [`BYTE_range] outStatus;
 
integer hold_block;
reg [`ADDRBUS_range] hold_address;
 
begin
hold_address = address;
hold_block = BankLib_man.getBlock(hold_address);
if (BankLib_man.isMainBlock(address)) begin
// Main Block
delayTime = `MainBlankCheck_time;
end else // Parameter Block
-> ErrorCheckEvent;
disable Operation;
 
fork
begin: Operation
Busy = `TRUE;
startTime = $time;
-> ErrorCheckEvent;
#delayTime
Memory_man.BlockBlankCheck(hold_block, Status);
-> CompleteEvent;
end
@CompleteEvent
disable Operation;
join
outStatus = Status;
Busy = `FALSE;
end
endtask
 
 
 
always @(ErrorCheckEvent) begin
Status = `NoError_msg;
if (!progVoltOK)
Status = `InvVDD_msg;
if (BankLib_man.isParameterBlock(address)) begin
Status = `WrongBlankCheckBlock;
$display("parameter block");
end
if (Status != `NoError_msg) begin
->CompleteEvent;
disable ErrorCheck;
end
else
fork : ErrorCheck
@(negedge progVoltOK) Status = `InvVDD_msg;
@(Status) -> CompleteEvent;
@(CompleteEvent) disable ErrorCheck;
join
end
 
endmodule //end module Erase
 
 
// *********************************
//
// Program Buffer module :
//
// program buffer functionality
//
// *********************************
 
module ProgramBufferModule(address,data,voltOK,Info);
input [`ADDRBUS_range] address;
input [`WORD_range] data;
input voltOK, Info;
event ErrorCheckEvent, CompleteEvent, WatchAddressEvent;
reg [`BYTE_range] Status;
reg [`DATABUS_dim-1:0] Count;
 
reg [`WORD_range] bufferData [`ProgramBuffer_range];
 
reg [`ADDRBUS_range] AddressLatched, startAddress,newAddress;
reg Busy, Suspended, Empty;
time startTime, delayTime;
integer i;
 
initial begin // constructor sequence
Busy = `FALSE;
Suspended = `FALSE;
Empty = `TRUE;
delayTime = `ProgramBuffer_time;
end
 
function IsBusy; // boolean function primitive
input obbl; // all functions require a parameter
IsBusy = Busy; // return Boolean value
endfunction
 
function IsSuspended; // boolean function primitive
input obbl; // all functions require a parameter
IsSuspended = Suspended; // return Boolean value
endfunction
 
function IsAddrSuspended; // boolean function primitive
input [`ADDRBUS_range] addr;
IsAddrSuspended = (Suspended && ((addr >= startAddress) && (addr < (startAddress + Count))));
endfunction
 
 
function [`DATABUS_dim-1:0] GetCount;
input required;
GetCount = Count;
endfunction
 
task SetCount; // sets the number of writes
output [`BYTE_range] outStatus;
reg [`BYTE_range] outStatus;
begin
outStatus = `NoError_msg;
AddressLatched = address;
Count = data + 1;
 
if (Count > `ProgramBuffer_dim)
outStatus = `BuffSize_msg;
else if (BankLib_man.getBlock(AddressLatched) != BankLib_man.getBlock(AddressLatched + Count - 1))
outStatus = `BlkBuffer_msg;
else
-> WatchAddressEvent;
end
endtask
 
task Suspend;
output [`BYTE_range] outStatus;
reg [`BYTE_range] outStatus;
begin
delayTime = delayTime - ($time - startTime);
#`ProgramSuspendLatency_time;
outStatus = `NoError_msg;
Status = `Suspend_msg;
Suspended = `TRUE;
-> CompleteEvent;
end
endtask
 
task Resume;
output [`BYTE_range] Status;
begin
Suspended = `FALSE;
Program(Status);
end
endtask
 
task Load;
output [`BYTE_range] Status;
begin
if (Empty) begin
startAddress = address;
if (Info) $display("[%t] Buffer start address: %h",$time,startAddress);
Empty = `FALSE;
end
bufferData[address[`ProgramBuffer_addrRange]] = data;
 
end
endtask
 
task Program;
output [`BYTE_range] outStatus;
reg [`BYTE_range] outStatus;
begin
 
fork
begin : Operation
Busy = `TRUE;
startTime = $time;
-> ErrorCheckEvent;
-> WatchAddressEvent; // disable address watch
#delayTime
for (i = startAddress;i < ( Count + startAddress); i = i + 1) begin
Memory_man.Program(bufferData[i[`ProgramBuffer_addrRange]],i,Status);
 
end
delayTime = `ProgramBuffer_time;
-> CompleteEvent;
end
@CompleteEvent
disable Operation;
 
join
if(!Suspended)
for (i = 0; i < `ProgramBuffer_dim; i = i + 1) begin
bufferData[i] =16'hFFFF;
end
Empty = `TRUE;
outStatus = Status;
Busy = `FALSE;
end
endtask
 
always @(ErrorCheckEvent) begin
Status = `NoError_msg;
if (BlockLock_man.IsLocked(AddressLatched))
Status = `BlockLock_msg;
else if (Suspended)
Status = `SuspAcc_msg;
else if (!voltOK)
Status = `InvVDD_msg;
 
if (Status != `NoError_msg)
->CompleteEvent;
else
fork : ErrorCheck
@(negedge voltOK) Status = `InvVDD_msg;
@(Status) -> CompleteEvent;
@(CompleteEvent) disable ErrorCheck;
join
end
 
always @(WatchAddressEvent) fork : AddressWatch
while (`TRUE)
@address
if (BankLib_man.getBlock(address) != BankLib_man.getBlock(AddressLatched)) begin
Status = `AddrTog_msg;
-> CompleteEvent;
end
@WatchAddressEvent
disable AddressWatch;
join
 
endmodule
/cfi_ctrl/trunk/bench/verilog/cfi_ctrl_engine_bench.v
0,0 → 1,308
 
`include "def.h"
`include "data.h"
 
`timescale 1ns/1ps
 
module cfi_ctrl_engine_bench();
 
 
// Signal Bus
wire [`ADDRBUS_dim - 1:0] A; // Address Bus
wire [`DATABUS_dim - 1:0] DQ; // Data I/0 Bus
// Control Signal
wire WE_N; // Write Enable
wire OE_N; // Output Enable
wire CE_N; // Chip Enable
wire RST_N; // Reset
wire WP_N; // Write Protect
wire ADV_N; // Latch Enable
wire CLK; // Clock
wire WAIT; // Wait
 
// Voltage signal rappresentad by integer Vector which correspond to millivolts
wire [`Voltage_range] VCC; // Supply Voltage
wire [`Voltage_range] VCCQ; // Supply Voltage for I/O Buffers
wire [`Voltage_range] VPP; // Optional Supply Voltage for Fast Program & Erase
 
//wire STS;
wire Info; // Activate/Deactivate info device operation
assign Info = 1;
assign VCC = 36'd1700;
assign VCCQ = 36'd1700;
assign VPP = 36'd2000;
 
parameter sys_clk_half_period = 15.15/2;
parameter sys_clk_period = sys_clk_half_period*2;
reg sys_clk;
reg sys_rst;
 
initial begin
sys_clk = 0;
forever
#sys_clk_half_period sys_clk = ~sys_clk;
end
initial begin
sys_rst = 1;
#sys_clk_period;
#sys_clk_period;
sys_rst = 0;
end
 
reg do_rst, do_init, do_readstatus, do_clearstatus,
do_eraseblock, do_write, do_read,
do_unlockblock;
reg [15:0] bus_dat_i;
reg [23:0] bus_adr_i;
wire bus_ack_o;
wire [15:0] bus_dat_o;
wire bus_busy_o;
 
/* used in testbench only */
reg [7:0] cfi_status;
reg [15:0] cfi_read_data;
 
 
task cfi_engine_wait_for_ready;
begin
while (bus_busy_o)
#sys_clk_period;
end
endtask
 
task cfi_engine_read_status;
output [7:0] status_o;
begin
//$display("%t: Reading status ",$time);
do_readstatus = 1;
#sys_clk_period;
do_readstatus = 0;
while(!bus_ack_o) /* wait for ack back from internal FSMs */
#sys_clk_period;
//$display("%t: status: %h", $time, bus_dat_o[7:0]);
status_o = bus_dat_o[7:0];
cfi_engine_wait_for_ready();
/* status:
7 : write status ( 0 - busy, 1 - ready )
6 : erase suspend status
5 : erase status ( 0 - successful, 1 - error)
4 : program status ( 0 - successful, 1 - error)
others aren't important
*/
end
endtask
 
 
task cfi_engine_clear_status;
begin
$display("%t: Clearing status register ",$time);
do_clearstatus = 1;
#sys_clk_period;
do_clearstatus = 0;
 
cfi_engine_wait_for_ready();
 
end
endtask
 
task cfi_engine_unlock_block;
input [23:0] address;
begin
$display("%t: Unlocking block at address %h ",$time, address);
bus_adr_i = address;
do_unlockblock = 1;
#sys_clk_period;
do_unlockblock = 0;
 
cfi_engine_wait_for_ready();
cfi_engine_read_status(cfi_status);
while (!cfi_status[7])
cfi_engine_read_status(cfi_status);
 
end
endtask
 
 
task cfi_engine_erase_block;
input [23:0] address;
begin
$display("%t: Erasing block at address %h ",$time, address);
bus_adr_i = address;
do_eraseblock = 1;
#sys_clk_period;
do_eraseblock = 0;
 
cfi_engine_wait_for_ready();
cfi_engine_read_status(cfi_status);
while (!cfi_status[7])
cfi_engine_read_status(cfi_status);
 
/* Check status */
if (cfi_status[5])
$display("$t: Erase failed for address %h",$time, address);
else
$display("$t: Erase succeeded for address %h",$time, address);
end
endtask
 
 
task cfi_engine_write_word;
input [23:0] address;
input [15:0] data;
begin
$display("%t: Writing data %h to address %h",$time , data, address);
bus_adr_i = address;
bus_dat_i = data;
do_write = 1;
#sys_clk_period;
do_write = 0;
 
cfi_engine_wait_for_ready();
cfi_engine_read_status(cfi_status);
while (!cfi_status[7])
cfi_engine_read_status(cfi_status);
 
end
endtask
 
 
task cfi_engine_read_word;
input [23:0] address;
output [15:0] data;
begin
$display("%t: Reading word from address %h",$time , address);
bus_adr_i = address;
do_read = 1;
#sys_clk_period;
do_read = 0;
 
cfi_engine_wait_for_ready();
data = bus_dat_o;
end
endtask // cfi_engine_read_word
 
task cfi_engine_reset;
begin
$display("%t: Resetting flash device", $time);
 
do_rst = 1;
#sys_clk_period;
do_rst = 0;
 
cfi_engine_wait_for_ready();
end
endtask
 
/* Main test stimulus block */
initial begin
do_rst = 0;
do_init = 0;
do_readstatus =0;
do_clearstatus = 0;
do_eraseblock =0;
do_unlockblock =0;
do_write =0;
do_read =0;
bus_dat_i = 0;
bus_adr_i = 0;
$dumpfile("../out/cfi_ctrl_engine_bench.vcd");
$dumpvars(0);
$display("Starting CFI engine test");
#550; // Wait for the part to power up
cfi_engine_read_status(cfi_status);
cfi_engine_wait_for_ready();
cfi_engine_unlock_block(24'h00_1000);
cfi_engine_wait_for_ready();
cfi_engine_erase_block(24'h00_1000);
 
cfi_engine_clear_status();
 
cfi_engine_write_word(24'h00_1000, 16'hdead);
cfi_engine_write_word(24'h00_1001, 16'hcafe);
cfi_engine_write_word(24'h00_1002, 16'hc001);
cfi_engine_write_word(24'h00_1003, 16'h4311);
cfi_engine_write_word(24'h00_1004, 16'hecc1);
cfi_engine_write_word(24'h00_1005, 16'hd311);
 
cfi_engine_read_word(24'h00_1000, cfi_read_data);
cfi_engine_read_word(24'h00_1001, cfi_read_data);
cfi_engine_read_word(24'h00_1002, cfi_read_data);
cfi_engine_read_word(24'h00_1003, cfi_read_data);
cfi_engine_read_word(24'h00_1004, cfi_read_data);
cfi_engine_read_word(24'h00_1005, cfi_read_data);
 
cfi_engine_reset();
 
cfi_engine_read_word(24'h00_1000, cfi_read_data);
cfi_engine_read_word(24'h00_1001, cfi_read_data);
cfi_engine_read_word(24'h00_1002, cfi_read_data);
cfi_engine_read_word(24'h00_1003, cfi_read_data);
cfi_engine_read_word(24'h00_1004, cfi_read_data);
cfi_engine_read_word(24'h00_1005, cfi_read_data);
#1000
$display("Finishing CFI engine test");
$finish;
end
 
/* timeout function - sim shouldn't run much longer than this */
initial begin
#55000;
$display("Simulation finish due to timeout");
$finish;
end
 
 
cfi_ctrl_engine
/*# (.cfi_part_elov_cycles(10))*/
dut
(
.clk_i(sys_clk),
.rst_i(sys_rst),
 
.do_rst_i(do_rst),
.do_init_i(do_init),
.do_readstatus_i(do_readstatus),
.do_clearstatus_i(do_clearstatus),
.do_eraseblock_i(do_eraseblock),
.do_unlockblock_i(do_unlockblock),
.do_write_i(do_write),
.do_read_i(do_read),
 
.bus_dat_o(bus_dat_o),
.bus_dat_i(bus_dat_i),
.bus_adr_i(bus_adr_i),
.bus_req_done_o(bus_ack_o),
.bus_busy_o(bus_busy_o),
.flash_dq_io(DQ),
.flash_adr_o(A),
.flash_adv_n_o(ADV_N),
.flash_ce_n_o(CE_N),
.flash_clk_o(CLK),
.flash_oe_n_o(OE_N),
.flash_rst_n_o(RST_N),
.flash_wait_i(WAIT),
.flash_we_n_o(WE_N),
.flash_wp_n_o(WP_N)
 
);
 
x28fxxxp30 part(A, DQ, WE_N, OE_N, CE_N, ADV_N, CLK,
WAIT, WP_N, RST_N, VCC, VCCQ, VPP, Info);
 
 
endmodule
/cfi_ctrl/trunk/rtl/verilog/cfi_ctrl.v
0,0 → 1,547
////////////////////////////////////////////////////////////////// ////
//// ////
//// Common Flash Interface (CFI) controller ////
//// ////
//// This file is part of the cfi_ctrl project ////
//// http://opencores.org/project,cfi_ctrl ////
//// ////
//// Description ////
//// See below ////
//// ////
//// To Do: ////
//// - ////
//// ////
//// Author(s): ////
//// - Julius Baxter, julius@opencores.org ////
//// ////
//////////////////////////////////////////////////////////////////////
//// ////
//// Copyright (C) 2011 Authors and OPENCORES.ORG ////
//// ////
//// This source file may be used and distributed without ////
//// restriction provided that this copyright statement is not ////
//// removed from the file and that any derivative work contains ////
//// the original copyright notice and the associated disclaimer. ////
//// ////
//// This source file is free software; you can redistribute it ////
//// and/or modify it under the terms of the GNU Lesser General ////
//// Public License as published by the Free Software Foundation; ////
//// either version 2.1 of the License, or (at your option) any ////
//// later version. ////
//// ////
//// This source is distributed in the hope that it will be ////
//// useful, but WITHOUT ANY WARRANTY; without even the implied ////
//// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR ////
//// PURPOSE. See the GNU Lesser General Public License for more ////
//// details. ////
//// ////
//// You should have received a copy of the GNU Lesser General ////
//// Public License along with this source; if not, download it ////
//// from http://www.gnu.org/copyleft/lesser.html ////
//// ////
//////////////////////////////////////////////////////////////////////
 
/*
Top level of CFI controller with 32-bit Wishbone classic interface
Intended to be used at about 66MHz with a 32MB CFI flash part with 16-bit
data interface.
 
This module has two configurations - one where it pulls in the CFI control
engine, which is intended to simplify accesses to a CFI flash, such as block
unlock, erase, and programming. The alternate configuration is essentially
mapping Wishbone accesses to the flash's bus.
CFI Engine Wishbone interface:
Basic functionality:
Bits [27:26] decode the operation.
2'b00 : read/write to the flash memory
2'b01 : unlock block
2'b10 : erase block
2'b11 : block registers, other flash control features
0xc00_0000 : block status/control register
bits:
[0]: r/o : CFI controller busy
[1]: w/o : clear flash status register
[2]: w/o : reset flash device and controller
0xc00_0004 : flash device status register
bits
[7:0] : r/o : flash device status register
 
0xe00_0000 : read device identifier information
User is able to access the device identifier information such as:
offset 0x0 : manufacturer code
offset 0x2 : device id
offset bba + 0x4 : block (add increments of 128KB block size)
offset 0xa : read config register
See CFI docs for further details (shift offset left by 1)
0xe01_0000 : CFI query
User is able to access the CFI query information
The hex offsets in the CFI spec should be shifted left by one before
applying to the Wishbone bus.
Addresses under 0x000_0000 cause direct access to the flash
Addresses under 0x400_0000 cause the block (addressed in [24:0]) to be unlocked
Addresses under 0x800_0000 cause the block (addressed in [24:0]) to be erased
*/
 
module cfi_ctrl
(
wb_clk_i, wb_rst_i,
wb_dat_i, wb_adr_i,
wb_stb_i, wb_cyc_i,
wb_we_i, wb_sel_i,
wb_dat_o, wb_ack_o,
wb_err_o, wb_rty_o,
 
 
flash_dq_io,
flash_adr_o,
flash_adv_n_o,
flash_ce_n_o,
flash_clk_o,
flash_oe_n_o,
flash_rst_n_o,
flash_wait_i,
flash_we_n_o,
flash_wp_n_o
);
 
parameter flash_dq_width = 16;
parameter flash_adr_width = 24;
 
parameter flash_write_cycles = 4; // wlwh/Tclk = 50ns / 15 ns (66Mhz)
parameter flash_read_cycles = 7; // elqv/Tclk = 95 / 15 ns (66MHz)
 
parameter cfi_engine = "ENABLED";
 
inout [flash_dq_width-1:0] flash_dq_io;
output [flash_adr_width-1:0] flash_adr_o;
 
output flash_adv_n_o;
output flash_ce_n_o;
output flash_clk_o;
output flash_oe_n_o;
output flash_rst_n_o;
input flash_wait_i;
output flash_we_n_o;
output flash_wp_n_o;
 
 
input wb_clk_i, wb_rst_i;
 
 
input [31:0] wb_dat_i, wb_adr_i;
input wb_stb_i, wb_cyc_i,
wb_we_i;
input [3:0] wb_sel_i;
output reg [31:0] wb_dat_o;
output reg wb_ack_o;
output wb_err_o, wb_rty_o;
 
reg [3:0] wb_state;
generate
if (cfi_engine == "ENABLED") begin : cfi_engine_gen
wire do_rst, do_init, do_readstatus;
wire do_clearstatus, do_eraseblock, do_write,
do_read, do_unlockblock;
 
/* Track when we have new bus accesses and are currently serving them */
reg wb_req_in_progress;
wire wb_req_new;
always @(posedge wb_clk_i)
if (wb_rst_i)
wb_req_in_progress <= 0;
else if (wb_req_new)
wb_req_in_progress <= 1'b1;
else if (wb_ack_o)
wb_req_in_progress <= 0;
assign wb_req_new = (wb_stb_i & wb_cyc_i) & !wb_req_in_progress;
 
/* Registers for interfacing with the CFI controller */
reg [15:0] cfi_bus_dat_i;
wire [15:0] cfi_bus_dat_o;
reg [23:0] cfi_bus_adr_i;
wire cfi_bus_ack_o;
wire cfi_bus_busy_o;
wire cfi_rw_sel;
wire cfi_unlock_sel;
wire cfi_erase_sel;
wire cfi_scr_sel;
wire cfi_readstatus_sel;
wire cfi_clearstatus_sel;
wire cfi_rst_sel;
wire cfi_busy_sel;
wire cfi_readdeviceident_sel;
wire cfi_cfiquery_sel;
 
reg cfi_bus_go;
 
reg cfi_first_of_two_accesses;
assign cfi_rw_sel = wb_adr_i[27:26]==2'b00;
assign cfi_unlock_sel = wb_adr_i[27:26]==2'b01 && wb_we_i;
assign cfi_erase_sel = wb_adr_i[27:26]==2'b10 && wb_we_i;
assign cfi_scr_sel = wb_adr_i[27:26]==2'b11 && wb_adr_i[25:0]==26'd0;
assign cfi_readstatus_sel = wb_adr_i[27:26]==2'b11 &&
wb_adr_i[25:0]==26'd4 && !wb_we_i;
assign cfi_clearstatus_sel = cfi_scr_sel && wb_dat_i[1] && wb_we_i;
assign cfi_rst_sel = cfi_scr_sel && wb_dat_i[2] && wb_we_i;
assign cfi_busy_sel = cfi_scr_sel & !wb_we_i;
assign cfi_readdeviceident_sel = wb_adr_i[27:26]==2'b11 &&
wb_adr_i[25]==1'b1 && !wb_adr_i[16]==1'b1 &&
!wb_we_i;
 
assign cfi_cfiquery_sel = wb_adr_i[27:26]==2'b11 &&
wb_adr_i[25]==1'b1 && wb_adr_i[16]==1'b1 &&
!wb_we_i;
 
assign do_rst = cfi_rst_sel & cfi_bus_go;
assign do_init = 0;
assign do_readstatus = cfi_readstatus_sel & cfi_bus_go;
assign do_clearstatus = cfi_clearstatus_sel & cfi_bus_go;
assign do_eraseblock = cfi_erase_sel & cfi_bus_go;
assign do_write = cfi_rw_sel & wb_we_i & cfi_bus_go ;
assign do_read = cfi_rw_sel & !wb_we_i & cfi_bus_go ;
assign do_unlockblock = cfi_unlock_sel & cfi_bus_go ;
assign do_readdeviceident = cfi_readdeviceident_sel & cfi_bus_go ;
assign do_cfiquery = cfi_cfiquery_sel & cfi_bus_go ;
 
/* Main statemachine */
`define WB_FSM_IDLE 0
`define WB_FSM_CFI_CMD_WAIT 2
always @(posedge wb_clk_i)
if (wb_rst_i) begin
wb_state <= `WB_FSM_IDLE;
cfi_bus_go <= 0;
 
/* Wishbone regs */
wb_dat_o <= 0;
wb_ack_o <= 0;
 
cfi_first_of_two_accesses <= 0;
end
else begin
case (wb_state)
`WB_FSM_IDLE: begin
wb_ack_o <= 0;
cfi_bus_go <= 0;
/* Pickup new incoming accesses */
/* Potentially get into a state where we received a bus request
but the CFI was still busy so waited. In this case we'll get a
ACK from the controller and have a new request registered */
if (wb_req_new) begin
if (cfi_busy_sel) /* want to read the busy flag */
begin
wb_ack_o <= 1;
wb_dat_o <= {30'd0, cfi_bus_busy_o};
end
else if (!cfi_bus_busy_o | (wb_req_in_progress & cfi_bus_ack_o))
begin
if (cfi_rw_sel | cfi_unlock_sel | cfi_erase_sel |
cfi_readstatus_sel | cfi_clearstatus_sel |
cfi_rst_sel | cfi_readdeviceident_sel |
cfi_cfiquery_sel)
begin
wb_state <= `WB_FSM_CFI_CMD_WAIT;
cfi_bus_go <= 1;
if (cfi_rw_sel) begin
/* Map address onto the 16-bit word bus*/
/* Reads always do full 32-bits, so adjust
address accordingly.*/
 
/* setup address and number of cycles depending
on request */
if (wb_we_i) begin /* Writing */
/* Only possible to write shorts at a time */
cfi_bus_dat_i <= wb_sel_i[1:0]==2'b11 ?
wb_dat_i[15:0] :
wb_dat_i[31:16];
cfi_bus_adr_i[23:0] <= wb_adr_i[24:1];
end
else begin /* Reading */
/* Full or part word? */
if ((&wb_sel_i)) begin /* 32-bits */
cfi_first_of_two_accesses <= 1;
cfi_bus_adr_i[23:0] <= {wb_adr_i[24:2],1'b0};
end
else begin /*16-bits or byte */
cfi_bus_adr_i[23:0] <= {wb_adr_i[24:1]};
end
end
end
if (cfi_unlock_sel | cfi_erase_sel)
cfi_bus_adr_i[23:0] <= wb_adr_i[24:1];
if (cfi_readdeviceident_sel)
cfi_bus_adr_i[23:0] <= {wb_adr_i[24:17],1'b0,
7'd0,wb_adr_i[9:1]};
if (cfi_cfiquery_sel)
cfi_bus_adr_i[23:0] <= {14'd0,wb_adr_i[10:1]};
end // if (cfi_rw_sel | cfi_unlock_sel | ...
end // if (!cfi_bus_busy_o | (wb_req_in_progress & ...
end // if (wb_req_new)
end // case: `WB_FSM_IDLE
`WB_FSM_CFI_CMD_WAIT: begin
cfi_bus_go <= 0;
/* Wait for the CFI controller to do its thing */
if (cfi_bus_ack_o) begin
if (cfi_rw_sel) begin
/* Is this the first of two accesses? */
if (cfi_first_of_two_accesses) begin
cfi_bus_adr_i <= cfi_bus_adr_i+1;
cfi_first_of_two_accesses <= 0;
cfi_bus_go <= 1;
/* Dealing with a read or a write */
/*
if (wb_we_i)
cfi_bus_dat_i <= wb_dat_i[31:16];
else
*/
wb_dat_o[31:16] <= cfi_bus_dat_o;
end
else begin
wb_state <= `WB_FSM_IDLE;
wb_ack_o <= 1'b1;
if (!wb_we_i) begin
if (&wb_sel_i)
wb_dat_o[15:0] <= cfi_bus_dat_o;
else begin
case (wb_sel_i)
4'b0001 :
wb_dat_o[31:0] <= {4{cfi_bus_dat_o[7:0]}};
4'b0010:
wb_dat_o[31:0] <= {4{cfi_bus_dat_o[15:8]}};
4'b0011 :
wb_dat_o[31:0] <= {cfi_bus_dat_o,cfi_bus_dat_o};
4'b0100 :
wb_dat_o[31:0] <= {4{cfi_bus_dat_o[7:0]}};
4'b1100 :
wb_dat_o[31:0] <= {cfi_bus_dat_o,cfi_bus_dat_o};
4'b1000 :
wb_dat_o[31:0] <= {4{cfi_bus_dat_o[15:8]}};
endcase // case (wb_sel_i)
end
 
end
end // else: !if(cfi_first_of_two_accesses)
end // if (cfi_rw_sel)
else begin
/* All other accesses should be a single go of the CFI
controller */
wb_state <= `WB_FSM_IDLE;
wb_ack_o <= 1'b1;
/* Get the read status data out */
if (cfi_readstatus_sel)
wb_dat_o <= {4{cfi_bus_dat_o[7:0]}};
if (cfi_readdeviceident_sel | cfi_cfiquery_sel)
wb_dat_o <= {2{cfi_bus_dat_o[15:0]}};
end
end // if (cfi_bus_ack_o)
else if (cfi_rst_sel)begin
/* The reset command won't ACK back over the bus, incase
the FSM hung and it actually reset all of its internals */
wb_state <= `WB_FSM_IDLE;
wb_ack_o <= 1'b1;
end
end // case: `WB_FSM_CFI_CMD_WAIT
endcase // case (wb_state)
end // else: !if(wb_rst_i)
assign wb_err_o = 0;
assign wb_rty_o = 0;
 
cfi_ctrl_engine
# (.cfi_part_wlwh_cycles(flash_write_cycles),
.cfi_part_elqv_cycles(flash_read_cycles)
)
cfi_ctrl_engine0
(
.clk_i(wb_clk_i),
.rst_i(wb_rst_i),
 
.do_rst_i(do_rst),
.do_init_i(do_init),
.do_readstatus_i(do_readstatus),
.do_clearstatus_i(do_clearstatus),
.do_eraseblock_i(do_eraseblock),
.do_unlockblock_i(do_unlockblock),
.do_write_i(do_write),
.do_read_i(do_read),
.do_readdeviceident_i(do_readdeviceident),
.do_cfiquery_i(do_cfiquery),
 
.bus_dat_o(cfi_bus_dat_o),
.bus_dat_i(cfi_bus_dat_i),
.bus_adr_i(cfi_bus_adr_i),
.bus_req_done_o(cfi_bus_ack_o),
.bus_busy_o(cfi_bus_busy_o),
 
.flash_dq_io(flash_dq_io),
.flash_adr_o(flash_adr_o),
.flash_adv_n_o(flash_adv_n_o),
.flash_ce_n_o(flash_ce_n_o),
.flash_clk_o(flash_clk_o),
.flash_oe_n_o(flash_oe_n_o),
.flash_rst_n_o(flash_rst_n_o),
.flash_wait_i(flash_wait_i),
.flash_we_n_o(flash_we_n_o),
.flash_wp_n_o(flash_wp_n_o)
 
);
end // if (cfi_engine == "ENABLED")
else begin : cfi_simple
 
reg long_read;
reg [4:0] flash_ctr;
reg [3:0] wb_state;
 
 
reg [flash_dq_width-1:0] flash_dq_o_r;
reg [flash_adr_width-1:0] flash_adr_o_r;
reg flash_oe_n_o_r;
reg flash_we_n_o_r;
reg flash_rst_n_o_r;
wire our_flash_oe;
assign flash_ce_n_o = 0;
assign flash_clk_o = 1;
assign flash_rst_n_o = flash_rst_n_o_r;
assign flash_wp_n_o = 1;
assign flash_adv_n_o = 0;
assign flash_dq_io = (our_flash_oe) ? flash_dq_o_r :
{flash_dq_width{1'bz}};
assign flash_adr_o = flash_adr_o_r;
assign flash_oe_n_o = flash_oe_n_o_r;
assign flash_we_n_o = flash_we_n_o_r;
 
`define WB_STATE_IDLE 0
`define WB_STATE_WAIT 1
 
assign our_flash_oe = (wb_state == `WB_STATE_WAIT ||
wb_ack_o) & wb_we_i;
always @(posedge wb_clk_i)
if (wb_rst_i)
begin
wb_ack_o <= 0;
wb_dat_o <= 0;
wb_state <= `WB_STATE_IDLE;
flash_dq_o_r <= 0;
flash_adr_o_r <= 0;
flash_oe_n_o_r <= 1;
flash_we_n_o_r <= 1;
flash_rst_n_o_r <= 0; /* active */
long_read <= 0;
flash_ctr <= 0;
end
else begin
if (|flash_ctr)
flash_ctr <= flash_ctr - 1;
case(wb_state)
`WB_STATE_IDLE: begin
/* reset some signals to NOP status */
wb_ack_o <= 0;
flash_oe_n_o_r <= 1;
flash_we_n_o_r <= 1;
flash_rst_n_o_r <= 1;
 
if (wb_stb_i & wb_cyc_i & !wb_ack_o) begin
flash_adr_o_r <= wb_adr_i[flash_adr_width:1];
wb_state <= `WB_STATE_WAIT;
if (wb_adr_i[27]) begin
/* Reset the flash, no matter the access */
flash_rst_n_o_r <= 0;
flash_ctr <= 5'd16;
end
else if (wb_we_i) begin
/* load counter with write cycle counter */
flash_ctr <= flash_write_cycles - 1;
/* flash bus write command */
flash_we_n_o_r <= 0;
flash_dq_o_r <= (|wb_sel_i[3:2]) ? wb_dat_i[31:16] :
wb_dat_i[15:0];
end
else begin
/* load counter with write cycle counter */
flash_ctr <= flash_read_cycles - 1;
if (&wb_sel_i)
long_read <= 1; // Full 32-bit read, 2 read cycles
flash_oe_n_o_r <= 0;
end // else: !if(wb_we_i)
end // if (wb_stb_i & wb_cyc_i)
end
`WB_STATE_WAIT: begin
if (!(|flash_ctr)) begin
if (wb_we_i) begin
/* write finished */
wb_ack_o <= 1;
wb_state <= `WB_STATE_IDLE;
flash_we_n_o_r <= 1;
end
else begin
/* read finished */
if (!(&wb_sel_i)) /* short or byte read */ begin
case (wb_sel_i)
4'b0001,
4'b0100:
wb_dat_o <= {4{flash_dq_io[7:0]}};
4'b1000,
4'b0010:
wb_dat_o <= {4{flash_dq_io[15:8]}};
default:
wb_dat_o <= {2{flash_dq_io}};
endcase // case (wb_sel_i)
wb_state <= `WB_STATE_IDLE;
wb_ack_o <= 1;
flash_oe_n_o_r <= 1;
end
else if (long_read) begin
/* now go on to read next word */
wb_dat_o[31:16] <= flash_dq_io;
long_read <= 0;
flash_ctr <= flash_read_cycles;
flash_adr_o_r <= flash_adr_o_r + 1;
end
else begin
/* finished two-part read */
wb_dat_o[15:0] <= flash_dq_io;
wb_state <= `WB_STATE_IDLE;
wb_ack_o <= 1;
flash_oe_n_o_r <= 1;
end
end
end
end
 
default:
wb_state <= `WB_STATE_IDLE;
endcase // case (wb_state)
end // else: !if(wb_rst_i)
end // block: cfi_simple
endgenerate
 
endmodule // cfi_ctrl
 
/cfi_ctrl/trunk/rtl/verilog/cfi_ctrl_engine.v
0,0 → 1,479
////////////////////////////////////////////////////////////////// ////
//// ////
//// Common Flash Interface (CFI) controller ////
//// ////
//// This file is part of the cfi_ctrl project ////
//// http://opencores.org/project,cfi_ctrl ////
//// ////
//// Description ////
//// See below ////
//// ////
//// To Do: ////
//// - ////
//// ////
//// Author(s): ////
//// - Julius Baxter, julius@opencores.org ////
//// ////
//////////////////////////////////////////////////////////////////////
//// ////
//// Copyright (C) 2011 Authors and OPENCORES.ORG ////
//// ////
//// This source file may be used and distributed without ////
//// restriction provided that this copyright statement is not ////
//// removed from the file and that any derivative work contains ////
//// the original copyright notice and the associated disclaimer. ////
//// ////
//// This source file is free software; you can redistribute it ////
//// and/or modify it under the terms of the GNU Lesser General ////
//// Public License as published by the Free Software Foundation; ////
//// either version 2.1 of the License, or (at your option) any ////
//// later version. ////
//// ////
//// This source is distributed in the hope that it will be ////
//// useful, but WITHOUT ANY WARRANTY; without even the implied ////
//// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR ////
//// PURPOSE. See the GNU Lesser General Public License for more ////
//// details. ////
//// ////
//// You should have received a copy of the GNU Lesser General ////
//// Public License along with this source; if not, download it ////
//// from http://www.gnu.org/copyleft/lesser.html ////
//// ////
//////////////////////////////////////////////////////////////////////
/*
CFI controller engine.
Contains main state machine and bus controls.
 
Controlled via a simple interface to a bus controller interface.
For now just implements an asynchronous controller.
do_rst_i - reset the flash device
do_init_i - initialise the device (write "read configuration register")
do_readstatus_i - read the status of the device
do_eraseblock_i - erase a block
do_write_i - write a word an address
do_read_i - read a word from an address
bus_dat_o - data out to bus controller
bus_dat_i - data in from bus controller
bus_req_done_o - bus request done
*/
 
 
module cfi_ctrl_engine
(
 
clk_i, rst_i,
 
do_rst_i,
do_init_i,
do_readstatus_i,
do_clearstatus_i,
do_eraseblock_i,
do_unlockblock_i,
do_write_i,
do_read_i,
do_readdeviceident_i,
do_cfiquery_i,
 
bus_dat_o,
bus_dat_i,
bus_adr_i,
bus_req_done_o,
bus_busy_o,
flash_dq_io,
flash_adr_o,
flash_adv_n_o,
flash_ce_n_o,
flash_clk_o,
flash_oe_n_o,
flash_rst_n_o,
flash_wait_i,
flash_we_n_o,
flash_wp_n_o
 
);
 
parameter flash_dq_width = 16;
parameter flash_adr_width = 24;
input clk_i, rst_i;
input do_rst_i,
do_init_i,
do_readstatus_i,
do_clearstatus_i,
do_eraseblock_i,
do_unlockblock_i,
do_write_i,
do_read_i,
do_readdeviceident_i,
do_cfiquery_i;
output reg [flash_dq_width-1:0] bus_dat_o;
input [flash_dq_width-1:0] bus_dat_i;
input [flash_adr_width-1:0] bus_adr_i;
output bus_req_done_o;
output bus_busy_o;
inout [flash_dq_width-1:0] flash_dq_io;
output [flash_adr_width-1:0] flash_adr_o;
output flash_adv_n_o;
output flash_ce_n_o;
output flash_clk_o;
output flash_oe_n_o;
output flash_rst_n_o;
input flash_wait_i;
output flash_we_n_o;
output flash_wp_n_o;
 
wire clk, rst;
 
assign clk = clk_i;
assign rst = rst_i;
 
reg [5:0] bus_control_state;
reg [flash_dq_width-1:0] flash_cmd_to_write;
 
/* regs for flash bus control signals */
reg flash_adv_n_r;
reg flash_ce_n_r;
reg flash_oe_n_r;
reg flash_we_n_r;
reg flash_wp_n_r;
reg flash_rst_n_r;
reg [flash_dq_width-1:0] flash_dq_o_r;
reg [flash_adr_width-1:0] flash_adr_r;
 
reg [3:0] flash_phy_state;
reg [3:0] flash_phy_ctr;
wire flash_phy_async_wait;
`define CFI_PHY_FSM_IDLE 0
`define CFI_PHY_FSM_WRITE_GO 1
`define CFI_PHY_FSM_WRITE_WAIT 2
`define CFI_PHY_FSM_WRITE_DONE 3
`define CFI_PHY_FSM_READ_GO 4
`define CFI_PHY_FSM_READ_WAIT 5
`define CFI_PHY_FSM_READ_DONE 6
`define CFI_PHY_FSM_RESET_GO 7
`define CFI_PHY_FSM_RESET_WAIT 8
`define CFI_PHY_FSM_RESET_DONE 9
 
/* Defines according to CFI spec */
`define CFI_CMD_DAT_READ_STATUS_REG 8'h70
`define CFI_CMD_DAT_CLEAR_STATUS_REG 8'h50
`define CFI_CMD_DAT_WORD_PROGRAM 8'h40
`define CFI_CMD_DAT_BLOCK_ERASE 8'h20
`define CFI_CMD_DAT_READ_ARRAY 8'hff
`define CFI_CMD_DAT_WRITE_RCR 8'h60
`define CFI_CMD_DAT_CONFIRM_WRITE_RCR 8'h03
`define CFI_CMD_DAT_UNLOCKBLOCKSETUP 8'h60
`define CFI_CMD_DAT_CONFIRM_CMD 8'hd0
`define CFI_CMD_DAT_READDEVICEIDENT 8'h90
`define CFI_CMD_DAT_CFIQUERY 8'h98
 
 
/* Main bus-controlled FSM states */
`define CFI_FSM_IDLE 0
`define CFI_FSM_DO_WRITE 1
`define CFI_FSM_DO_WRITE_WAIT 2
`define CFI_FSM_DO_READ 3
`define CFI_FSM_DO_READ_WAIT 4
`define CFI_FSM_DO_BUS_ACK 5
`define CFI_FSM_DO_RESET 6
`define CFI_FSM_DO_RESET_WAIT 7
 
/* Used to internally track what read more we're in
2'b00 : read array mode
2'b01 : read status mode
else : something else*/
reg [1:0] flash_device_read_mode;
/* Track what read mode we're in */
always @(posedge clk)
if (rst)
flash_device_read_mode <= 2'b00;
else if (!flash_rst_n_o)
flash_device_read_mode <= 2'b00;
else if (flash_phy_state == `CFI_PHY_FSM_WRITE_DONE) begin
if (flash_cmd_to_write == `CFI_CMD_DAT_READ_ARRAY)
flash_device_read_mode <= 2'b00;
else if (flash_cmd_to_write == `CFI_CMD_DAT_READ_STATUS_REG)
flash_device_read_mode <= 2'b01;
else
/* Some other mode */
flash_device_read_mode <= 2'b11;
end
/* Main control state machine, controlled by the bus */
always @(posedge clk)
if (rst) begin
/* Power up and start an asynchronous write to the "read config reg" */
bus_control_state <= `CFI_FSM_IDLE;
flash_cmd_to_write <= 0;
end
else
case (bus_control_state)
`CFI_FSM_IDLE : begin
if (do_readstatus_i) begin
// if (flash_device_read_mode != 2'b01) begin
flash_cmd_to_write <= `CFI_CMD_DAT_READ_STATUS_REG;
bus_control_state <= `CFI_FSM_DO_WRITE;
// end
// else begin
// flash_cmd_to_write <= 0;
// bus_control_state <= `CFI_FSM_DO_READ;
// end
end
if (do_clearstatus_i) begin
flash_cmd_to_write <= `CFI_CMD_DAT_CLEAR_STATUS_REG;
bus_control_state <= `CFI_FSM_DO_WRITE;
end
if (do_eraseblock_i) begin
flash_cmd_to_write <= `CFI_CMD_DAT_BLOCK_ERASE;
bus_control_state <= `CFI_FSM_DO_WRITE;
end
if (do_write_i) begin
flash_cmd_to_write <= `CFI_CMD_DAT_WORD_PROGRAM;
bus_control_state <= `CFI_FSM_DO_WRITE;
end
if (do_read_i) begin
if (flash_device_read_mode != 2'b00) begin
flash_cmd_to_write <= `CFI_CMD_DAT_READ_ARRAY;
bus_control_state <= `CFI_FSM_DO_WRITE;
end
else begin
flash_cmd_to_write <= 0;
bus_control_state <= `CFI_FSM_DO_READ;
end
end
if (do_unlockblock_i) begin
flash_cmd_to_write <= `CFI_CMD_DAT_UNLOCKBLOCKSETUP;
bus_control_state <= `CFI_FSM_DO_WRITE;
end
if (do_rst_i) begin
flash_cmd_to_write <= 0;
bus_control_state <= `CFI_FSM_DO_RESET;
end
if (do_readdeviceident_i) begin
flash_cmd_to_write <= `CFI_CMD_DAT_READDEVICEIDENT;
bus_control_state <= `CFI_FSM_DO_WRITE;
end
if (do_cfiquery_i) begin
flash_cmd_to_write <= `CFI_CMD_DAT_CFIQUERY;
bus_control_state <= `CFI_FSM_DO_WRITE;
end
end // case: `CFI_FSM_IDLE
`CFI_FSM_DO_WRITE : begin
bus_control_state <= `CFI_FSM_DO_WRITE_WAIT;
end
`CFI_FSM_DO_WRITE_WAIT : begin
/* Wait for phy controller to finish the write command */
if (flash_phy_state==`CFI_PHY_FSM_WRITE_DONE) begin
if (flash_cmd_to_write == `CFI_CMD_DAT_READ_STATUS_REG ||
flash_cmd_to_write == `CFI_CMD_DAT_READ_ARRAY ||
flash_cmd_to_write == `CFI_CMD_DAT_READDEVICEIDENT ||
flash_cmd_to_write == `CFI_CMD_DAT_CFIQUERY) begin
/* we just changed the read mode, so go ahead and do the
read */
bus_control_state <= `CFI_FSM_DO_READ;
end
else if (flash_cmd_to_write == `CFI_CMD_DAT_WORD_PROGRAM) begin
/* Setting up to do a word write, go to write again */
/* clear the command, to use the incoming data from the bus */
flash_cmd_to_write <= 0;
bus_control_state <= `CFI_FSM_DO_WRITE;
end
else if (flash_cmd_to_write == `CFI_CMD_DAT_BLOCK_ERASE ||
flash_cmd_to_write == `CFI_CMD_DAT_UNLOCKBLOCKSETUP)
begin
/* first stage of a two-stage command requiring confirm */
bus_control_state <= `CFI_FSM_DO_WRITE;
flash_cmd_to_write <= `CFI_CMD_DAT_CONFIRM_CMD;
end
else
/* All other operations should see us acking the bus */
bus_control_state <= `CFI_FSM_DO_BUS_ACK;
end
end // case: `CFI_FSM_DO_WRITE_WAIT
`CFI_FSM_DO_READ : begin
bus_control_state <= `CFI_FSM_DO_READ_WAIT;
end
`CFI_FSM_DO_READ_WAIT : begin
if (flash_phy_state==`CFI_PHY_FSM_READ_DONE) begin
bus_control_state <= `CFI_FSM_DO_BUS_ACK;
end
end
`CFI_FSM_DO_BUS_ACK :
bus_control_state <= `CFI_FSM_IDLE;
`CFI_FSM_DO_RESET :
bus_control_state <= `CFI_FSM_DO_RESET_WAIT;
`CFI_FSM_DO_RESET_WAIT : begin
if (flash_phy_state==`CFI_PHY_FSM_RESET_DONE)
bus_control_state <= `CFI_FSM_IDLE;
end
default :
bus_control_state <= `CFI_FSM_IDLE;
endcase // case (bus_control_state)
 
/* Tell the bus we're done */
assign bus_req_done_o = (bus_control_state==`CFI_FSM_DO_BUS_ACK);
assign bus_busy_o = !(bus_control_state == `CFI_FSM_IDLE);
 
/* Sample flash data for the system bus interface */
always @(posedge clk)
if (rst)
bus_dat_o <= 0;
else if ((flash_phy_state == `CFI_PHY_FSM_READ_WAIT) &&
/* Wait for t_vlqv */
(!flash_phy_async_wait))
/* Sample flash data */
bus_dat_o <= flash_dq_io;
 
/* Flash physical interface control state machine */
always @(posedge clk)
if (rst)
begin
flash_adv_n_r <= 1'b0;
flash_ce_n_r <= 1'b1;
flash_oe_n_r <= 1'b1;
flash_we_n_r <= 1'b1;
flash_dq_o_r <= 0;
flash_adr_r <= 0;
flash_rst_n_r <= 0;
 
flash_phy_state <= `CFI_PHY_FSM_IDLE;
end
else
begin
case (flash_phy_state)
`CFI_PHY_FSM_IDLE : begin
flash_rst_n_r <= 1'b1;
flash_ce_n_r <= 1'b0;
/* Take address from the bus controller */
flash_adr_r <= bus_adr_i;
 
/* Wait for a read or write command */
if (bus_control_state == `CFI_FSM_DO_WRITE)
begin
flash_phy_state <= `CFI_PHY_FSM_WRITE_GO;
/* Are we going to write a command? */
if (flash_cmd_to_write) begin
flash_dq_o_r <= {{(flash_dq_width-8){1'b0}},
flash_cmd_to_write};
end
else
flash_dq_o_r <= bus_dat_i;
end
if (bus_control_state == `CFI_FSM_DO_READ) begin
flash_phy_state <= `CFI_PHY_FSM_READ_GO;
end
if (bus_control_state == `CFI_FSM_DO_RESET) begin
flash_phy_state <= `CFI_PHY_FSM_RESET_GO;
end
end
`CFI_PHY_FSM_WRITE_GO: begin
/* Assert CE, WE */
flash_we_n_r <= 1'b0;
flash_phy_state <= `CFI_PHY_FSM_WRITE_WAIT;
end
`CFI_PHY_FSM_WRITE_WAIT: begin
/* Wait for t_wlwh */
if (!flash_phy_async_wait) begin
flash_phy_state <= `CFI_PHY_FSM_WRITE_DONE;
flash_we_n_r <= 1'b1;
end
end
`CFI_PHY_FSM_WRITE_DONE: begin
flash_phy_state <= `CFI_PHY_FSM_IDLE;
end
 
`CFI_PHY_FSM_READ_GO: begin
/* Assert CE, OE */
/*flash_adv_n_r <= 1'b1;*/
flash_ce_n_r <= 1'b0;
flash_oe_n_r <= 1'b0;
flash_phy_state <= `CFI_PHY_FSM_READ_WAIT;
end
`CFI_PHY_FSM_READ_WAIT: begin
/* Wait for t_vlqv */
if (!flash_phy_async_wait) begin
flash_oe_n_r <= 1'b1;
flash_phy_state <= `CFI_PHY_FSM_READ_DONE;
end
end
`CFI_PHY_FSM_READ_DONE: begin
flash_phy_state <= `CFI_PHY_FSM_IDLE;
end
`CFI_PHY_FSM_RESET_GO: begin
flash_phy_state <= `CFI_PHY_FSM_RESET_WAIT;
flash_rst_n_r <= 1'b0;
flash_oe_n_r <= 1'b1;
end
`CFI_PHY_FSM_RESET_WAIT : begin
if (!flash_phy_async_wait) begin
flash_rst_n_r <= 1'b1;
flash_phy_state <= `CFI_PHY_FSM_RESET_DONE;
end
end
`CFI_PHY_FSM_RESET_DONE : begin
flash_phy_state <= `CFI_PHY_FSM_IDLE;
end
default:
flash_phy_state <= `CFI_PHY_FSM_IDLE;
endcase
end
 
/* Defaults are for 95ns access time part, 66MHz (15.15ns) system clock */
/* wlwh: cycles for WE assert to WE de-assert: write time */
parameter cfi_part_wlwh_cycles = 4; /* wlwh = 50ns, tck = 15ns, cycles = 4*/
/* elqv: cycles from adress to data valid */
parameter cfi_part_elqv_cycles = 7; /* tsop 256mbit elqv = 95ns, tck = 15ns, cycles = 6*/
 
assign flash_phy_async_wait = (|flash_phy_ctr);
 
/* Load counter with wait times in cycles, determined by parameters. */
always @(posedge clk)
if (rst)
flash_phy_ctr <= 0;
else if (flash_phy_state==`CFI_PHY_FSM_WRITE_GO)
flash_phy_ctr <= cfi_part_wlwh_cycles - 1;
else if (flash_phy_state==`CFI_PHY_FSM_READ_GO)
flash_phy_ctr <= cfi_part_elqv_cycles - 2;
else if (flash_phy_state==`CFI_PHY_FSM_RESET_GO)
flash_phy_ctr <= 10;
else if (|flash_phy_ctr)
flash_phy_ctr <= flash_phy_ctr - 1;
 
/* Signal to indicate when we should drive the data bus */
wire flash_bus_write_enable;
assign flash_bus_write_enable = (bus_control_state == `CFI_FSM_DO_WRITE) |
(bus_control_state == `CFI_FSM_DO_WRITE_WAIT);
/* Assign signals to physical bus */
assign flash_dq_io = flash_bus_write_enable ? flash_dq_o_r :
{flash_dq_width{1'bz}};
assign flash_adr_o = flash_adr_r;
assign flash_adv_n_o = flash_adv_n_r;
assign flash_wp_n_o = 1'b1; /* Never write protect */
assign flash_ce_n_o = flash_ce_n_r;
assign flash_oe_n_o = flash_oe_n_r;
assign flash_we_n_o = flash_we_n_r;
assign flash_clk_o = 1'b1;
assign flash_rst_n_o = flash_rst_n_r;
endmodule // cfi_ctrl_engine
 
 
/cfi_ctrl/trunk/doc/README
0,0 → 1,121
CFI Controller IP Core
======================
 
 
This core implements a very simple controller that will provide an interface to
16-bit data-bus flash memories using the common flash interface (CFI).
 
It uses asynchronous communication only, and thus should be configured with the
cycle counts for write (usually 50ns, so usually roundup(50ns / Tsys_clk) and
read (usually 85-115 ns - see your part's spec for exact details.) These cycle
counts are set via paramters to the core, and each read or write access
performed by the core will ensure the signals are held for this long.
 
== Interface Modes ==
 
Two interface modes are avilable.
 
=== Simple Mode ===
 
First is a very simple interface with the flash bus - essentially each classic
Wishbone access is mapped onto the flash bus (address is shifted right by 1
bit.) The only "advanced" feature of this mode, is that 32-bit reads will work,
that is the controller will perform two reads if a full-word read is requested,
which means this controller can be used for XIP (execute-in-place) by a
processor.
 
The functionality is demonstrated in the testbench cfi_ctrl_wb_bench.v
 
This mode appears to be compliant with the basic CFI software drivers available
under u-boot/Linux. It is the recommended mode if the controller is to be used
in a system running software such as this. The complexity is handled by the
driver software, meaning the controller implementation can be simple.
 
=== CFI Engine Mode ===
 
The second is the "CFI engine" mode, which aims to simplify the interface to the
flash, allowing single-access block unlock, erase and 16/32-bit writes.
 
This engine core can be used standalone (the source file
rtl/verilog/cfi_ctrl_engine.v) to provide access to a flash part for another FSM
or may be wrapped in a different bus interface wrapper.
 
The testbench for the standalone engine core is cfi_ctrl_engine_bench.v
 
The engine is provided with a Wishbone wrapper, and the core's capabilities are
mapped to the Wishbone bus as outlined below.
 
The testbench for the Wishbone-wrapped engine is cfi_ctrl_engine_wb_bench.v
 
==== Commands ====
 
Commands are essentially encoded on the address bus for the core. The following
is an outline of how this interface works:
 
Basic functionality:
Bits [27:26] decode the operation.
2'b00 : read/write to the flash memory
2'b01 : unlock block
2'b10 : erase block
2'b11 : block registers, other flash control features. See below.
 
Therefore:
Addresses under 0x000_0000 cause direct access to the flash
Addresses under 0x400_0000 cause the block (addressed in [24:0]) to be unlocked
Addresses under 0x800_0000 cause the block (addressed in [24:0]) to be erased
==== Registers ====
0xc00_0000 : block status/control register
bits:
[0]: r/o : CFI controller busy
[1]: w/o : clear flash status register
[2]: w/o : reset flash device and controller
0xc00_0004 : flash device status register
bits
[7:0] : r/o : flash device status register
 
0xe00_0000 : read device identifier information
User is able to access the device identifier information such as:
offset 0x0 : manufacturer code
offset 0x2 : device id
offset bba + 0x4 : block (add increments of 128KB block size)
offset 0xa : read config register
See CFI docs for further details (shift offset left by 1)
 
0xe01_0000 : CFI query
User is able to access the CFI query information
The hex offsets in the CFI spec should be shifted left by one before
applying to the Wishbone bus.
 
 
== Timing ==
 
Set the parameters flash_write_cycles and flash_read_cycles at the top-level to
ensure that CFI bus timing is met (usually 50ns for write, 85-115ns for read.)
The single clock going to the core is the clock used to count these accesses.
 
flash_write_cycles is used to count the wlwh (write-low-to-write-high) parameter
and flash_read_cycles is used to count elqv, or enable-low-data-valid.
 
== Simulations ==
 
The core's 3 configurations come with testbenches under bench/verilog.
 
To run these simulations, install Icarus Verilog (sudo apt-get install verilog)
, http://iverilog.icarus.com/.
 
from sim/run run "make all" to run all the tests - a VCD for each will be
automatically generated in sim/out. Or run individual tests with the following:
 
Simple mode controller:
make cfi_ctrl_wb_bench
Engine mode controller, generic bus interface:
make cfi_engine_bench
Engine mode controller, Wishbone bus interface:
make cfi_ctrl_engine_wb_bench
 
The model used is in bench/verilog/x28fxxxp30.v
 
= Author =
Julius Baxter, julius@opencores.org
/cfi_ctrl/trunk/sim/run/Makefile
0,0 → 1,2
include ../bin/Makefile
 
/cfi_ctrl/trunk/sim/bin/iver.script
0,0 → 1,4
+incdir+../../bench/verilog/include
-y ../../bench/verilog
-y ../../rtl/verilog
#../../bench/verilog/cfi_ctrl_engine_bench.v
/cfi_ctrl/trunk/sim/bin/Makefile
0,0 → 1,24
 
SIM_EXE=iversim.elf
 
all: cfi_ctrl_wb_bench cfi_engine_bench cfi_ctrl_engine_wb_bench
 
cfi_ctrl_engine_wb_bench:
iverilog -f ../bin/iver.script -s cfi_ctrl_engine_wb_bench \
../../bench/verilog/cfi_ctrl_engine_wb_bench.v -o $(SIM_EXE)
./$(SIM_EXE)
 
cfi_ctrl_wb_bench:
iverilog -f ../bin/iver.script -s cfi_ctrl_wb_bench \
../../bench/verilog/cfi_ctrl_wb_bench.v -o $(SIM_EXE)
./$(SIM_EXE)
 
 
cfi_engine_bench:
iverilog -f ../bin/iver.script -s cfi_ctrl_engine_bench \
../../bench/verilog/cfi_ctrl_engine_bench.v -o $(SIM_EXE)
./$(SIM_EXE)
 
 
clean:
rm -f *.* ../out/*

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.