Files
vhdl/lib/models/memory/flash/serial/S25fl064a/model/s25fl064a.v
T
jens 2edaa4d7cb - added models
git-svn-id: http://moon:8086/svn/vhdl/trunk@1290 cc03376c-175c-47c8-b038-4cd826a8556b
2015-06-10 19:27:35 +00:00

1218 lines
36 KiB
Verilog

//////////////////////////////////////////////////////////////////////////////
// File name : s25fl064a.v
//////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2006-2007 Spansion, LLC.
//
// MODIFICATION HISTORY :
//
// version: | author: | mod date: | changes made:
// V1.0 G.Gojanovic 05 May 16 Initial release
// V1.1 D.Randjelovic 06 Apr 11 MSB of latched address is ignored
// V1.2 D.Randjelovic 06 May 04 Page Program Command used with the
// single byte data corrected.
// Release from Deep Power Down when
// Electronic Signature is not read
// fixed
// V1.3 D.Stanojkovic 07 Jul 02 Fixed missing Sec_Prot initialization
//
//////////////////////////////////////////////////////////////////////////////
// PART DESCRIPTION:
//
// Library: FLASH
// Technology: Flash Memory
// Part: S25FL064A
//
// Description: 64 Megabit Serial Flash Memory with 50MHz SPI Bus Interface
//
//////////////////////////////////////////////////////////////////////////////
// Known Bugs:
//
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
// MODULE DECLARATION //
//////////////////////////////////////////////////////////////////////////////
`timescale 1 ns/1 ns
module s25fl064a
(
SCK ,
SI ,
CSNeg ,
HOLDNeg ,
WNeg ,
SO
);
////////////////////////////////////////////////////////////////////////
// Port / Part Pin Declarations
////////////////////////////////////////////////////////////////////////
input SCK ;
input SI ;
input CSNeg ;
input HOLDNeg ;
input WNeg ;
output SO ;
// interconnect path delay signals
wire SCK_ipd ;
wire SI_ipd ;
wire CSNeg_ipd ;
wire HOLDNeg_ipd ;
wire WNeg_ipd ;
// internal delays
reg PP_in ;
reg PP_out ;
reg PE_in ;
reg PE_out ;
reg BE_in ;
reg BE_out ;
reg SE_in ;
reg SE_out ;
reg WR_in ;
reg WR_out ;
reg DP_in ;
reg DP_out ;
reg RES_in ;
reg RES_out ;
reg SO_zd = 1'bZ;
reg SO_z = 1'bZ;
parameter UserPreload = 1;
parameter mem_file_name = "none";//"s25fl064a.mem";
parameter TimingModel = "DefaultTimingModel";
parameter PartID = "s25fl064a";
parameter MaxData = 255;
parameter SecSize = 65535;
parameter SecNum = 127;
parameter HiAddrBit = 22;
parameter AddrRANGE = 24'h7FFFFF;
parameter BYTE = 8;
parameter ES = 8'h16;
parameter DeviceID = 24'h010216;
// powerup
reg PoweredUp;
reg PDONE ; ////Prog. Done
reg PSTART ; ////Start Programming
reg EDONE ; ////Era. Done
reg ESTART ; ////Start Erasing
reg WDONE ; //// Writing Done
reg WSTART ; ////Start writing
//Command Register
reg write;
reg read_out;
//Status reg.
reg[7:0] Status_reg = 8'b0;
reg[7:0] Status_reg_in = 8'b0;
integer SA = 0; // 0 TO SecNum+1
integer Byte_number = 0;
//Address
integer Address = 0; // 0 - AddrRANGE
reg change_addr;
reg rd_fast;// = 1'b1;
reg rd_slow;
wire fast_rd;
wire rd;
//Sector Protection Status
reg [SecNum:0] Sec_Prot; //= SecNum'b0;
// timing check violation
reg Viol = 1'b0;
integer Mem[0:AddrRANGE];
integer WByte[0:255];
integer AddrLo;
integer AddrHi;
reg[7:0] old_bit, new_bit;
integer old_int, new_int;
integer wr_cnt;
integer read_cnt = 0;
integer read_addr = 0;
reg[7:0] data_out;
reg[23:0] ident_out;
reg oe = 1'b0;
event oe_event;
///////////////////////////////////////////////////////////////////////////////
//Interconnect Path Delay Section
///////////////////////////////////////////////////////////////////////////////
buf (SCK_ipd, SCK);
buf (SI_ipd, SI);
buf (CSNeg_ipd, CSNeg);
buf (HOLDNeg_ipd, HOLDNeg);
buf (WNeg_ipd, WNeg);
///////////////////////////////////////////////////////////////////////////////
// Propagation delay Section
///////////////////////////////////////////////////////////////////////////////
nmos (SO, SO_z, 1);
specify
// tipd delays: interconnect path delays , mapped to input port delays.
// In Verilog is not necessary to declare any tipd_ delay variables,
// they can be taken from SDF file
// With all the other delays real delays would be taken from SDF file
// tpd delays
specparam tpd_SCK_SO =1;
specparam tpd_CSNeg_SO =1;
specparam tpd_HOLDNeg_SO =1;
specparam tsetup_SI_SCK =1; //tsuDAT /
specparam tsetup_CSNeg_SCK =1; // tCSS /
specparam tsetup_HOLDNeg_SCK =1; //tHD /
specparam tsetup_SCK_HOLDNeg =1; //tCH \
specparam tsetup_WNeg_CSNeg =1; //tWPS \
// thold values: hold times
specparam thold_SI_SCK =1; //thdDAT /
specparam thold_CSNeg_SCK =1; //tCSH /
specparam thold_HOLDNeg_SCK =1; //tCD /
specparam thold_SCK_HOLDNeg =1; //tHC \
specparam thold_WNeg_CSNeg =1; //tWPH \
// tpw values: pulse width
specparam tpw_SCK_posedge =1; //tWH
specparam tpw_SCK_negedge =1; //tWL
specparam tpw_CSNeg_posedge =1; //tCS
// tperiod min (calculated as 1/max freq)
specparam tperiod_SCK_rd =1; // fSCK = 33MHz
specparam tperiod_SCK_fast_rd =1; // fSCK = 50MHz
// tdevice values: values for internal delays
// Page Program Operation
specparam tdevice_PP = 3000000; //3 ms;
//Sector Erase Operation
specparam tdevice_SE = 3e9; //3 sec;
//Bulk Erase Operation
specparam tdevice_BE = 384e9; //384 sec;
//Write Status Register Operation
specparam tdevice_WR = 60000000; // 60 ms;
//Software Protect Mode
specparam tdevice_DP = 3000; // 3 us;
//Release from Software Protect Mode
specparam tdevice_RES = 30000; // 30 us;
//VCC (min) to CS# Low
specparam tdevice_PU = 10000000; //10 ms;
///////////////////////////////////////////////////////////////////////////////
// Input Port Delays don't require Verilog description
///////////////////////////////////////////////////////////////////////////////
// Path delays //
///////////////////////////////////////////////////////////////////////////////
(SCK => SO) = tpd_SCK_SO;
(CSNeg => SO) = tpd_CSNeg_SO;
(HOLDNeg => SO) = tpd_HOLDNeg_SO;
////////////////////////////////////////////////////////////////////////////////
// Timing Violation //
////////////////////////////////////////////////////////////////////////////////
$setup ( WNeg , negedge CSNeg, tsetup_WNeg_CSNeg, Viol);
$setup ( negedge HOLDNeg, posedge SCK, tsetup_HOLDNeg_SCK, Viol);
$setup ( posedge SCK, posedge HOLDNeg, tsetup_SCK_HOLDNeg, Viol);
$hold ( posedge CSNeg, WNeg, thold_WNeg_CSNeg, Viol);
$hold ( posedge SCK, negedge HOLDNeg, thold_HOLDNeg_SCK, Viol);
$hold ( posedge HOLDNeg, posedge SCK, thold_SCK_HOLDNeg, Viol);
$setuphold ( posedge SCK, SI, tsetup_SI_SCK, thold_SI_SCK, Viol);
$setuphold ( posedge SCK, CSNeg, tsetup_CSNeg_SCK,
thold_CSNeg_SCK, Viol);
$width (posedge SCK, tpw_SCK_posedge);
$width (negedge SCK, tpw_SCK_negedge);
$width (posedge CSNeg, tpw_CSNeg_posedge);
$period (posedge SCK &&& rd, tperiod_SCK_rd);
$period (posedge SCK &&& fast_rd, tperiod_SCK_fast_rd);
endspecify
////////////////////////////////////////////////////////////////////////////////
// Main Behavior Block //
////////////////////////////////////////////////////////////////////////////////
// FSM states
parameter IDLE =4'd0;
parameter WRITE_SR =4'd1;
parameter DP_DOWN =4'd2;
parameter SECTOR_ER =4'd3;
parameter BULK_ER =4'd4;
parameter PAGE_PG =4'd5;
reg [3:0] current_state;
reg [3:0] next_state;
// Instructions
parameter NONE =5'd0;
parameter WREN =5'd1;
parameter WRDI =5'd2;
parameter WRSR =5'd3;
parameter RDSR =5'd4;
parameter READ =5'd5;
parameter FAST_READ =5'd6;
parameter SE =5'd8;
parameter BE =5'd9;
parameter PP =5'd10;
parameter DP =5'd11;
parameter RDID =5'd12;
parameter RES_READ_ES =5'd13;
reg [4:0] Instruct;
//Bus cycle states
parameter STAND_BY =3'd0;
parameter CODE_BYTE =3'd1;
parameter ADDRESS_BYTES =3'd2;
parameter DUMMY_BYTES =3'd3;
parameter DATA_BYTES =3'd4;
reg [2:0] bus_cycle_state;
initial
begin : Init
write = 1'b0;
read_out = 1'b0;
Address = 0;
change_addr = 1'b0;
PDONE = 1'b1;
PSTART = 1'b0;
EDONE = 1'b1;
ESTART = 1'b0;
WDONE = 1'b1;
WSTART = 1'b0;
DP_in = 1'b0;
DP_out = 1'b0;
RES_in = 1'b0;
RES_out = 1'b0;
Instruct = NONE;
bus_cycle_state = STAND_BY;
current_state = IDLE;
next_state = IDLE;
Sec_Prot = 0;
end
// initialize memory
initial
begin: InitMemory
integer i;
for (i=0;i<=AddrRANGE;i=i+1)
begin
Mem[i] = MaxData;
end
if ((UserPreload) && !(mem_file_name == "none"))
begin
// Memory Preload
//s25fl016a.mem, memory preload file
// @aaaaaa - <aaaaaa> stands for address
// dd - <dd> is byte to be written at Mem(aaaaaa++)
// (aaaaaa is incremented at every load)
$readmemh(mem_file_name,Mem);
end
end
//Power Up time;
initial
begin
PoweredUp = 1'b0;
#tdevice_PU PoweredUp = 1'b1;
end
always @(posedge DP_in)
begin:TDPr
#tdevice_DP DP_out = DP_in;
end
always @(negedge DP_in)
begin:TDPf
#1 DP_out = DP_in;
end
always @(posedge RES_in)
begin:TRESr
#tdevice_RES RES_out = RES_in;
end
always @(negedge RES_in)
begin:TRESf
#1 RES_out = RES_in;
end
always @(next_state or PoweredUp)
begin: StateTransition
if (PoweredUp)
begin
current_state = next_state;
end
end
always @(PoweredUp)
begin:CheckCEOnPowerUP
if ((~PoweredUp) && (~CSNeg_ipd))
$display ("Device is selected during Power Up");
end
// ///////////////////////////////////////////////////////////////////////////
// // Instruction cycle decode
// ///////////////////////////////////////////////////////////////////////////
integer data_cnt = 0;
integer addr_cnt = 0;
integer code_cnt = 0;
integer dummy_cnt = 0;
integer bit_cnt = 0;
reg[2047:0] Data_in = 2048'b0;
reg[7:0] code = 8'b0;
reg[7:0] code_in = 8'b0;
reg[7:0] Byte_slv = 8'b0;
reg[HiAddrBit:0] addr_bytes;
reg[23:0] Address_in = 8'b0;
always @(negedge CSNeg_ipd)
begin: Buscycle1
if (bus_cycle_state==STAND_BY)
begin
bus_cycle_state = CODE_BYTE;
Instruct = NONE;
write = 1'b1;
code_cnt = 0;
addr_cnt = 0;
data_cnt = 0;
dummy_cnt = 0;
end
end
always @(posedge SCK_ipd)
begin: Buscycle2
integer i;
if ( HOLDNeg_ipd)
begin
case (bus_cycle_state)
CODE_BYTE :
begin
code_in[code_cnt] = SI_ipd;
code_cnt = code_cnt + 1;
if (code_cnt == BYTE)
begin
for (i=0;i<=7;i=i+1)
begin
code[i] = code_in[7-i];
end
case(code)
8'b00000110 :
begin
Instruct = WREN;
bus_cycle_state = DATA_BYTES;
end
8'b00000100 :
begin
Instruct = WRDI;
bus_cycle_state = DATA_BYTES;
end
8'b00000001 :
begin
Instruct = WRSR;
bus_cycle_state = DATA_BYTES;
end
8'b00000101 :
begin
Instruct = RDSR;
bus_cycle_state = DATA_BYTES;
end
8'b00000011 :
begin
Instruct = READ;
bus_cycle_state = ADDRESS_BYTES;
end
8'b00001011 :
begin
Instruct = FAST_READ;
bus_cycle_state = ADDRESS_BYTES;
end
8'b10101011 :
begin
Instruct = RES_READ_ES;
bus_cycle_state = DUMMY_BYTES;
end
8'b11011000 :
begin
Instruct = SE;
bus_cycle_state = ADDRESS_BYTES;
end
8'b11000111 :
begin
Instruct = BE;
bus_cycle_state = DATA_BYTES;
end
8'b00000010 :
begin
Instruct = PP;
bus_cycle_state = ADDRESS_BYTES;
end
8'b10111001 :
begin
Instruct = DP;
bus_cycle_state = DATA_BYTES;
end
8'b10011111 :
begin
Instruct = RDID;
bus_cycle_state = DATA_BYTES;
end
endcase
end
end
ADDRESS_BYTES :
begin
Address_in[addr_cnt] = SI_ipd;
addr_cnt = addr_cnt + 1;
if (addr_cnt == 3*BYTE)
begin
for (i=23;i>=23-HiAddrBit;i=i-1)
begin
addr_bytes[23-i] = Address_in[i];
end
Address = addr_bytes;
change_addr = 1'b1;
#1 change_addr = 1'b0;
if (Instruct == FAST_READ)
bus_cycle_state = DUMMY_BYTES;
else
bus_cycle_state = DATA_BYTES;
end
end
DUMMY_BYTES :
begin
dummy_cnt = dummy_cnt + 1;
if ((dummy_cnt == BYTE && Instruct == FAST_READ) ||
(dummy_cnt == 3*BYTE && Instruct == RES_READ_ES))
bus_cycle_state = DATA_BYTES;
end
DATA_BYTES :
begin
if (data_cnt > 2047)
//In case of PP, if more than 256 bytes are
//sent to the device
begin
if (bit_cnt == 0)
begin
for (i=0;i<=(255*BYTE-1);i=i+1)
begin
Data_in[i] = Data_in[i+8];
end
end
Data_in[2040 + bit_cnt] = SI_ipd;
bit_cnt = bit_cnt + 1;
if (bit_cnt == 8)
begin
bit_cnt = 0;
end
data_cnt = data_cnt + 1;
end
else
begin
Data_in[data_cnt] = SI_ipd;
data_cnt = data_cnt + 1;
bit_cnt = 0;
end
end
endcase
end
end
always @(negedge SCK_ipd)
begin: Buscycle3
if (bus_cycle_state==DATA_BYTES && (~CSNeg_ipd) && (HOLDNeg_ipd))
if (Instruct == READ || Instruct == RES_READ_ES ||
Instruct == FAST_READ || Instruct == RDSR ||
Instruct == RDID)
read_out = 1'b1;
#1 read_out = 1'b0;
end
always @(posedge CSNeg_ipd)
begin: Buscycle4
integer i;
integer j;
if (bus_cycle_state == DATA_BYTES)
begin
bus_cycle_state = STAND_BY;
if (HOLDNeg_ipd)
begin
case (Instruct)
WREN,
WRDI,
DP,
BE,
SE :
begin
if (data_cnt == 0)
write = 1'b0;
end
RES_READ_ES,
RDID :
begin
write = 1'b0;
end
WRSR :
begin
if (data_cnt == BYTE)
write = 1'b0;
Status_reg_in = Data_in[7:0];
end
PP :
begin
if ((data_cnt > 0) && ((data_cnt % 8) == 0))
begin
write = 1'b0;
for (i=0;i<=255;i=i+1)
begin
for (j=7;j>=0;j=j-1)
begin
Byte_slv[j] = Data_in[(i*8) + (7-j)];
end
WByte[i] = Byte_slv;
end
if (data_cnt > 256*BYTE)
Byte_number = 255;
else
Byte_number = ((data_cnt/8) - 1);
end
end
endcase
end
end
if (bus_cycle_state == DUMMY_BYTES)
begin
bus_cycle_state = STAND_BY;
if (HOLDNeg_ipd && Instruct == RES_READ_ES)
write = 1'b0;
end
end
// /////////////////////////////////////////////////////////////////////////
// // Timing control for the Program Operations
// // start
// /////////////////////////////////////////////////////////////////////////
event pdone_event;
always @(PSTART)
begin
if (PSTART && PDONE)
begin
PDONE = 1'b0;
->pdone_event;
end
end
always @(pdone_event)
begin:pdone_process
PDONE = 1'b0;
#tdevice_PP PDONE = 1'b1;
end
// /////////////////////////////////////////////////////////////////////////
// // Timing control for the Write Status Register Operation
// // start
// /////////////////////////////////////////////////////////////////////////
event wdone_event;
always @(WSTART)
begin
if (WSTART && WDONE)
begin
WDONE = 1'b0;
->wdone_event;
end
end
always @(wdone_event)
begin:wdone_process
WDONE = 1'b0;
#tdevice_WR WDONE = 1'b1;
end
// /////////////////////////////////////////////////////////////////////////
// // Timing control for the Erase Operations
// /////////////////////////////////////////////////////////////////////////
integer cnt_erase = 0;
time duration_erase;
event edone_event;
always @(ESTART)
begin: erase
if (ESTART && EDONE)
begin
if (Instruct == BE)
begin
duration_erase = tdevice_BE;
end
else //if (Instruct == SE)
begin
duration_erase = tdevice_SE;
end
EDONE = 1'b0;
->edone_event;
end
end
always @(edone_event)
begin : edone_process
EDONE = 1'b0;
#duration_erase EDONE = 1'b1;
end
// /////////////////////////////////////////////////////////////////////////
// // Main Behavior Process
// // combinational process for next state generation
// /////////////////////////////////////////////////////////////////////////
integer sect;
always @(negedge write)
begin: StateGen1
case (current_state)
IDLE :
begin
if (~write)
begin
if (Instruct == WRSR && Status_reg[1])
begin
if (~(Status_reg[7] && (~WNeg_ipd)))
next_state = WRITE_SR;
end
else if (Instruct == PP && Status_reg[1])
begin
sect = Address / 24'h10000;
if (Sec_Prot[sect] == 1'b0)
next_state = PAGE_PG;
end
else if (Instruct == SE && Status_reg[1])
begin
sect = Address / 24'h10000;
if (Sec_Prot[sect] == 1'b0)
next_state = SECTOR_ER;
end
else if (Instruct == BE && Status_reg[1])
begin
if (Status_reg[2] == 1'b0 && Status_reg[3] == 1'b0 &&
Status_reg[4] == 1'b0)
next_state = BULK_ER;
end
else if (Instruct == DP)
next_state = DP_DOWN;
else
next_state = IDLE;
end
end
DP_DOWN:
begin
if (~write)
begin
if (Instruct == RES_READ_ES)
next_state = IDLE;
end
end
endcase
end
always @(posedge PDONE)
begin: StateGen2
if (current_state==PAGE_PG)
begin
next_state = IDLE;
end
end
always @(posedge WDONE)
begin: StateGen3
if (current_state==WRITE_SR)
begin
next_state = IDLE;
end
end
always @(posedge EDONE)
begin: StateGen4
if (current_state==SECTOR_ER || current_state==BULK_ER)
begin
next_state = IDLE;
end
end
///////////////////////////////////////////////////////////////////////////
//FSM Output generation and general funcionality
///////////////////////////////////////////////////////////////////////////
always @(posedge read_out)
begin
if (PoweredUp == 1'b1)
->oe_event;
end
always @(oe_event)
begin
oe = 1'b1;
#1 oe = 1'b0;
end
always @(Instruct)
begin
read_cnt = 0;
end
always @(change_addr)
begin
if (change_addr)
read_addr = Address;
end
always @(Instruct)
begin
rd_fast = 1'b1;
rd_slow = 1'b0;
end
always @(oe or current_state)
begin
case (current_state)
IDLE :
begin
if (oe && RES_in == 1'b0)
begin
if (Instruct == RDSR)
begin
//Read Status Register
SO_zd = Status_reg[7-read_cnt];
read_cnt = read_cnt + 1;
if (read_cnt == 8)
read_cnt = 0;
end
else if (Instruct == READ || Instruct == FAST_READ)
begin
//Read Memory array
if (Instruct == READ)
begin
rd_fast = 1'b0;
rd_slow = 1'b1;
end
data_out[7:0] = Mem[read_addr];
SO_zd = data_out[7-read_cnt];
read_cnt = read_cnt + 1;
if (read_cnt == 8)
begin
read_cnt = 0;
if (read_addr == AddrRANGE)
read_addr = 0;
else
read_addr = read_addr + 1;
end
end
else if (Instruct == RDID)
begin
// Read ID
ident_out[23:0] = DeviceID;
SO_zd = ident_out[23-read_cnt];
read_cnt = read_cnt + 1;
if (read_cnt == 24)
read_cnt = 0;
end
else if (Instruct == RES_READ_ES)
begin
// Read ID
data_out[7:0] = ES;
SO_zd = data_out[7-read_cnt];
read_cnt = read_cnt + 1;
if (read_cnt == 8)
read_cnt = 0;
end
end
else if (oe && RES_in == 1'b1)
begin
$display ("Command results can be corrupted");
SO_zd = 1'bX;
read_cnt = read_cnt + 1;
if (read_cnt == 8)
read_cnt = 0;
end
end
WRITE_SR,
SECTOR_ER,
BULK_ER,
PAGE_PG :
begin
if (oe && Instruct == RDSR)
begin
//Read Status Register
SO_zd = Status_reg[7-read_cnt];
read_cnt = read_cnt + 1;
if (read_cnt == 8)
read_cnt = 0;
end
end
DP_DOWN :
begin
if (~write)
begin
if (Instruct == RES_READ_ES)
RES_in = 1'b1;
end
else if (oe && Instruct == RES_READ_ES)
begin
// Read ES
data_out[7:0] = ES;
SO_zd = data_out[7-read_cnt];
read_cnt = read_cnt + 1;
if (read_cnt == 8)
read_cnt = 0;
end
end
endcase
end
assign fast_rd = rd_fast;
assign rd = rd_slow;
integer sector;
integer WData [0:255];
integer Addr;
always @(negedge write)
begin : Output_generation
integer i;
case (current_state)
IDLE :
begin
if (~write)
begin
if (RES_in == 1'b1)
begin
$display ("Command results can be corrupted");
end
if (Instruct == WREN)
Status_reg[1] = 1'b1;
else if (Instruct == WRDI)
Status_reg[1] = 1'b0;
else if (Instruct == WRSR && Status_reg[1] &&
(~(Status_reg[7] == 1'b1 && WNeg_ipd == 1'b0)))
begin
WSTART = 1'b1;
WSTART <= #1 1'b0;
Status_reg[0] = 1'b1;
end
else if (Instruct == PP && Status_reg[1] == 1'b1)
begin
sector = Address / 20'h10000;
if (Sec_Prot[sector] == 1'b0)
begin
PSTART = 1'b1;
PSTART <= #1 1'b0;
Status_reg[0] = 1'b1;
Addr = Address;
SA = sector;
wr_cnt = Byte_number;
for (i=0;i<=wr_cnt;i=i+1)
begin
if (Viol!=1'b0)
WData[i] = -1;
else
WData[i] = WByte[i];
end
end
end
else if (Instruct == SE && Status_reg[1] == 1'b1)
begin
sector = Address / 20'h10000;
if (Sec_Prot[sector] == 1'b0)
begin
ESTART = 1'b1;
ESTART <= #1 1'b0;
Status_reg[0] = 1'b1;
Addr = Address;
end
end
else if (Instruct == BE && Status_reg[1] == 1'b1 &&
Status_reg[2] == 1'b0 && Status_reg[3] == 1'b0 &&
Status_reg[4] == 1'b0)
begin
ESTART = 1'b1;
ESTART <= #1 1'b0;
Status_reg[0] = 1'b1;
end
else if (Instruct == DP && RES_in == 1'b0)
DP_in = 1'b1;
end
end
DP_DOWN :
begin
if (~write)
begin
if (Instruct == RES_READ_ES)
RES_in = 1'b1;
end
end
endcase
end
always @(RES_out)
begin : DPDOWN1
if (RES_out)
begin
RES_in = 1'b0;
end
end
always @(current_state or EDONE)
begin: ERASE1
integer i;
case (current_state)
SECTOR_ER :
begin
ADDRHILO_SEC(AddrLo, AddrHi, Addr);
for (i=AddrLo;i<=AddrHi;i=i+1)
begin
Mem[i] = -1;
end
if (EDONE)
begin
Status_reg[0] = 1'b0;
Status_reg[1] = 1'b0;
for (i=AddrLo;i<=AddrHi;i=i+1)
begin
Mem[i] = MaxData;
end
end
end
BULK_ER :
begin
for (i=0;i<=AddrRANGE;i=i+1)
begin
Mem[i] = -1;
end
if (EDONE)
begin
Status_reg[0] = 1'b0;
Status_reg[1] = 1'b0;
for (i=0;i<=AddrRANGE;i=i+1)
begin
Mem[i] = MaxData;
end
end
end
endcase
end
always @(current_state or WDONE)
begin: WRSR1
if (current_state == WRITE_SR)
begin
if (WDONE)
begin
Status_reg[0] = 1'b0;//WIP
Status_reg[1] = 1'b0;//WEL
Status_reg[7] = Status_reg_in[0];//MSB first, SRWD
Status_reg[4] = Status_reg_in[3];//MSB first, BP2
Status_reg[3] = Status_reg_in[4];//MSB first, BP1
Status_reg[2] = Status_reg_in[5];//MSB first, BP0
case (Status_reg[4:2])
3'b000 :
begin
Sec_Prot = 128'h00000000000000000000000000000000;
end
3'b001 :
begin
Sec_Prot = 128'hC0000000000000000000000000000000;
end
3'b010 :
begin
Sec_Prot = 128'hF0000000000000000000000000000000;
end
3'b011 :
begin
Sec_Prot = 128'hFF000000000000000000000000000000;
end
3'b100 :
begin
Sec_Prot = 128'hFFFF0000000000000000000000000000;
end
3'b101 :
begin
Sec_Prot = 128'hFFFFFFFF000000000000000000000000;
end
3'b110 :
begin
Sec_Prot = 128'hFFFFFFFFFFFFFFFF0000000000000000;
end
3'b111 :
begin
Sec_Prot = 128'hFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF;
end
endcase
end
end
end
always @(current_state or PDONE)
begin: PPPG1
integer i, j;
if (current_state == PAGE_PG)
begin
ADDRHILO_PG(AddrLo, AddrHi, Addr);
if ((Addr + wr_cnt) > AddrHi)
wr_cnt = AddrHi - Addr;
for (i=Addr;i<=Addr+wr_cnt;i=i+1)
begin
new_int = WData[i-Addr];
old_int = Mem[i];
if (new_int > -1)
begin
new_bit = new_int;
if (old_int > -1)
begin
old_bit = old_int;
for(j=0;j<=7;j=j+1)
if (~old_bit[j])
new_bit[j]=1'b0;
new_int=new_bit;
end
WData[i-Addr]= new_int;
end
else
begin
WData[i-Addr] = -1;
end
end
for (i=Addr;i<=Addr+wr_cnt;i=i+1)
begin
Mem[i] = -1;
end
if (PDONE)
begin
Status_reg[0] = 1'b0;//wip
Status_reg[1] = 1'b0;// wel
for (i=Addr;i<=Addr+wr_cnt;i=i+1)
begin
Mem[i] = WData[i-Addr];
end
end
end
end
// Output Control
always @(CSNeg_ipd or HOLDNeg_ipd or SCK_ipd)
begin
//Output Disable Control
if (CSNeg_ipd )
SO_zd = 1'bZ;
end
always @(SO_zd or HOLDNeg_ipd)
begin
if (HOLDNeg_ipd == 1)
SO_z = SO_zd;
else
SO_z = 1'bZ;
end
// Procedure ADDRHILO_SEC
task ADDRHILO_SEC;
inout AddrLOW;
inout AddrHIGH;
input Addr;
integer AddrLOW;
integer AddrHIGH;
integer Addr;
integer sector;
begin
sector = Addr / 20'h10000;
AddrLOW = sector * 20'h10000;
AddrHIGH = sector * 20'h10000 + 16'hFFFF;
end
endtask
// Procedure ADDRHILO_PG
task ADDRHILO_PG;
inout AddrLOW;
inout AddrHIGH;
input Addr;
integer AddrLOW;
integer AddrHIGH;
integer Addr;
integer page;
begin
page = Addr / 16'h100;
AddrLOW = page * 16'h100;
AddrHIGH = page * 16'h100 + 8'hFF;
end
endtask
endmodule