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/* |