git-svn-id: http://moon:8086/svn/vhdl/trunk@1290 cc03376c-175c-47c8-b038-4cd826a8556b
4276 lines
165 KiB
Verilog
4276 lines
165 KiB
Verilog
///////////////////////////////////////////////////////////////////////////////
|
|
// File name : s25fl128k.v
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// Copyright (C) 2010 Spansion, LLC.
|
|
//
|
|
// MODIFICATION HISTORY :
|
|
//
|
|
// version: | author: | mod date: | changes made:
|
|
// V1.0 R.Prokopovic 10 Oct 08 Initial
|
|
//
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// PART DESCRIPTION:
|
|
//
|
|
// Library: FLASH
|
|
// Technology: FLASH MEMORY
|
|
// Part: S25FL128K
|
|
//
|
|
// Description: 128 Megabit Serial Flash Memory
|
|
//
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// Comments :
|
|
//
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
// Known Bugs:
|
|
//
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
// MODULE DECLARATION //
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
`timescale 1 ps/1 ps
|
|
|
|
module s25fl128k
|
|
(
|
|
// Data Inputs/Outputs
|
|
SI ,
|
|
SO ,
|
|
// Controls
|
|
SCK ,
|
|
CSNeg ,
|
|
HOLDNeg,
|
|
WPNeg
|
|
|
|
);
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// Port / Part Pin Declarations
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
inout SI ;
|
|
inout SO ;
|
|
input SCK ;
|
|
input CSNeg ;
|
|
inout HOLDNeg ;
|
|
inout WPNeg ;
|
|
|
|
// interconnect path delay signals
|
|
wire SCK_ipd ;
|
|
wire SI_ipd ;
|
|
wire SO_ipd ;
|
|
|
|
wire SI_in ;
|
|
assign SI_in = SI_ipd ;
|
|
|
|
wire SI_out ;
|
|
assign SI_out = SI ;
|
|
|
|
wire SO_in ;
|
|
assign SO_in = SO_ipd ;
|
|
|
|
wire SO_out ;
|
|
assign SO_out = SO ;
|
|
|
|
wire CSNeg_ipd ;
|
|
wire HOLDNeg_ipd ;
|
|
wire WPNeg_ipd ;
|
|
|
|
wire HOLDNeg_in ;
|
|
//Internal pull-up
|
|
assign HOLDNeg_in = (HOLDNeg_ipd === 1'bx) ? 1'b1 : HOLDNeg_ipd;
|
|
|
|
wire HOLDNeg_out ;
|
|
assign HOLDNeg_out = HOLDNeg ;
|
|
|
|
wire WPNeg_in ;
|
|
//Internal pull-up
|
|
assign WPNeg_in = (WPNeg_ipd === 1'bx) ? 1'b1 : WPNeg_ipd;
|
|
|
|
wire WPNeg_out ;
|
|
assign WPNeg_out = WPNeg ;
|
|
|
|
// ***** internal delays *********************
|
|
reg PP_in ;
|
|
reg PP_out ;
|
|
reg BP_in ;
|
|
reg BP_out ;
|
|
reg SE_in ;
|
|
reg SE_out ;
|
|
reg BE_in ;
|
|
reg BE_out ;
|
|
reg PRGSUSP_in ;
|
|
reg PRGSUSP_out ;
|
|
reg ERSSUSP_in ;
|
|
reg ERSSUSP_out ;
|
|
reg PRGRES_out ;
|
|
reg ERSRES_out ;
|
|
reg PRGRES_in ;
|
|
reg ERSRES_in ;
|
|
reg WRR_in ;
|
|
reg WRR_out ;
|
|
reg DP_in ;
|
|
reg DP_out ;
|
|
reg RES_in ;
|
|
reg RES_out ;
|
|
// ******* event control registers ************
|
|
reg PRGSUSP_out_event;
|
|
reg PRGRES_out_event;
|
|
reg ERSSUSP_out_event;
|
|
reg ERSRES_out_event;
|
|
reg PGSUSP_event;
|
|
reg PGRES_event;
|
|
reg ESUSP_event;
|
|
reg ERES_event;
|
|
reg next_state_event;
|
|
|
|
reg rising_edge_PoweredUp;
|
|
reg rising_edge_RES_out;
|
|
reg rising_edge_PRGRES_out;
|
|
reg rising_edge_PSTART;
|
|
reg rising_edge_WSTART;
|
|
reg rising_edge_VLTSTART;
|
|
reg rising_edge_ESTART;
|
|
reg rising_edge_prot_bits;
|
|
reg rising_edge_CSNeg_ipd = 1'b0;
|
|
reg falling_edge_CSNeg_ipd = 1'b0;
|
|
reg rising_edge_SCK_ipd = 1'b0;
|
|
reg falling_edge_SCK_ipd = 1'b0;
|
|
|
|
reg SOut_zd = 1'bZ ;
|
|
reg SOut_z = 1'bZ ;
|
|
|
|
reg DataDriveOut_SO = 1'bZ ;
|
|
reg DataDriveOut_SI = 1'bZ ;
|
|
reg DataDriveOut_HOLD = 1'bZ ;
|
|
reg DataDriveOut_WP = 1'bZ ;
|
|
|
|
wire SI_z ;
|
|
wire SO_z ;
|
|
|
|
reg SIOut_zd = 1'bZ ;
|
|
reg SIOut_z = 1'bZ ;
|
|
|
|
reg WPNegOut_zd = 1'bZ ;
|
|
reg HOLDNegOut_zd = 1'bZ ;
|
|
|
|
assign SI_z = SIOut_z;
|
|
assign SO_z = SOut_z;
|
|
|
|
parameter UserPreload = 1;
|
|
parameter mem_file_name = "none";//"s25fl128k.mem";
|
|
parameter screg_file_name = "s25fl128kscreg.mem";//"none";
|
|
parameter TimingModel = "DefaultTimingModel";
|
|
|
|
parameter PartID = "s25fl128k";
|
|
parameter MaxData = 255;
|
|
parameter AddrRANGE = 24'hFFFFFF;
|
|
parameter PageNum = 16'hFFFF;
|
|
parameter SecSize_4 = 12'hFFF;
|
|
parameter SecSize_32 = 16'h7FFF;
|
|
parameter SecSize_64 = 16'hFFFF;
|
|
parameter Blk_4_Num = 4095;
|
|
parameter Blk_64_Num = 255;
|
|
parameter Blk_32_Num = 511;
|
|
parameter SFDP_HiAddr = 8'hFF;
|
|
parameter SFDP_LoAddr = 8'h00;
|
|
parameter SecReg_HiAddr = 8'hFF;
|
|
parameter SecReg_LoAddr = 8'h00;
|
|
parameter SCREG_LoAddr = 12'h000;
|
|
parameter SCREG_HiAddr = 12'h2FF;
|
|
parameter BYTE = 8;
|
|
|
|
// Manufacturer Identification and Device Identification
|
|
parameter Manuf_ID = 8'hEF;
|
|
parameter Device_ID1 = 8'h17;
|
|
parameter Device_ID2 = 8'h40;
|
|
parameter Device_ID3 = 8'h18;
|
|
parameter unique_id = 64'h000000000000ABAB;
|
|
|
|
// If speedsimulation is needed uncomment following line
|
|
|
|
// `define SPEEDSIM;
|
|
|
|
// powerup
|
|
reg PoweredUp;
|
|
|
|
// FSM control signals
|
|
reg PDONE ;
|
|
reg PSTART ;
|
|
reg PGSUSP ;
|
|
reg PGRES ;
|
|
// reg ERSRES ;
|
|
|
|
reg WDONE ;
|
|
reg WSTART ;
|
|
reg VLTSTART ;
|
|
reg VLTDONE ;
|
|
|
|
reg EDONE ;
|
|
reg ESTART ;
|
|
reg ESUSP ;
|
|
reg ERES ;
|
|
|
|
// Programming buffer
|
|
integer WByte[0:255];
|
|
|
|
// Flash Memory Array
|
|
integer Mem[0:AddrRANGE];
|
|
|
|
// Registers
|
|
// Status Register 1
|
|
reg[7:0] Status_reg1 = 8'h00;
|
|
reg[7:0] Status_reg1_in = 8'h00;
|
|
|
|
wire SRP0;
|
|
wire SEC;
|
|
wire TB;
|
|
wire BP2;
|
|
wire BP1;
|
|
wire BP0;
|
|
wire WEL;
|
|
wire BUSY;
|
|
assign SRP0 = Status_reg1[7];
|
|
assign SEC = Status_reg1[6];
|
|
assign TB = Status_reg1[5];
|
|
assign BP2 = Status_reg1[4];
|
|
assign BP1 = Status_reg1[3];
|
|
assign BP0 = Status_reg1[2];
|
|
assign WEL = Status_reg1[1];
|
|
assign BUSY = Status_reg1[0];
|
|
|
|
// Status Register 2
|
|
reg[7:0] Status_reg2 = 8'h00;
|
|
reg[7:0] Status_reg2_in = 8'h00;
|
|
|
|
wire SUS;
|
|
wire CMP;
|
|
|
|
wire [2:0]LB;
|
|
wire QE;
|
|
wire SRP1;
|
|
assign SUS = Status_reg2[7];
|
|
assign CMP = Status_reg2[6];
|
|
assign LB = Status_reg2[5:3];
|
|
assign QE = Status_reg2[1];
|
|
assign SRP1 = Status_reg2[0];
|
|
|
|
reg[15:0] Status_reg; // Status_reg2 & Status_reg1
|
|
reg[15:0] Status_reg_in; // Status_reg2 & Status_reg1
|
|
|
|
// Sector is protect if Sec_Prot(SecNum) = '1'
|
|
reg [Blk_4_Num:0] Sec_Prot = {4095{1'b0}};
|
|
|
|
// Security registers array
|
|
integer Security_Reg[SCREG_LoAddr:SCREG_HiAddr];
|
|
integer Security_Reg1[SecReg_LoAddr:SecReg_HiAddr];
|
|
integer Security_Reg2[SecReg_LoAddr:SecReg_HiAddr];
|
|
integer Security_Reg3[SecReg_LoAddr:SecReg_HiAddr];
|
|
|
|
// SFDP register array
|
|
integer SFDP_array[SFDP_LoAddr:SFDP_HiAddr];
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
// Command Register
|
|
reg write;
|
|
reg read_out;
|
|
reg slow_read;
|
|
reg dual_read;
|
|
reg fast_read;
|
|
reg quad_read;
|
|
reg pp_quad;
|
|
reg oe = 1'b0;
|
|
event oe_event;
|
|
|
|
reg[7:0] old_bit, new_bit;
|
|
integer old_int, new_int;
|
|
integer wr_cnt;
|
|
integer cnt;
|
|
integer Byte_number = 0;
|
|
integer read_cnt = 0;
|
|
integer read_addr = 0;
|
|
reg[7:0] data_out;
|
|
reg[23:0] ident_out;
|
|
reg[15:0] ident_out2;
|
|
integer AddrLo;
|
|
integer AddrHi;
|
|
integer AddrLo_ers;
|
|
integer AddrHi_ers;
|
|
integer AddrLo_wrap;
|
|
integer AddrHi_wrap;
|
|
|
|
reg change_prot_bits = 0;
|
|
|
|
//Address
|
|
integer Address = 0; // 0 - AddrRANGE
|
|
reg change_addr;
|
|
|
|
//Sector and subsector addresses
|
|
integer SA = 0;
|
|
integer sect;
|
|
integer sect_tmp_pg;
|
|
integer sect_tmp_ers;
|
|
integer sfdp_addr;
|
|
integer w_size;
|
|
|
|
reg hold_mode = 1'b0;
|
|
|
|
time SCK_cycle = 0;
|
|
time prev_SCK;
|
|
|
|
// Flag for release from deep power down, read ID or not
|
|
reg res_flag;
|
|
reg pg_screg_flag = 1'b0;
|
|
reg ers_screg_flag = 1'b0;
|
|
reg wren_vlt_flag = 1'b0;
|
|
reg susp_flag = 1'b0;
|
|
// timing check violation
|
|
reg Viol = 1'b0;
|
|
reg sr_read = 1'b0;
|
|
reg read_id = 1'b0;
|
|
|
|
reg glitch = 1'b0;
|
|
time SCK_SO_2;
|
|
time start_rdid;
|
|
time out_time;
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
//Interconnect Path Delay Section
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
buf (SCK_ipd, SCK);
|
|
buf (SI_ipd, SI);
|
|
|
|
buf (SO_ipd, SO);
|
|
buf (CSNeg_ipd, CSNeg);
|
|
buf (HOLDNeg_ipd, HOLDNeg);
|
|
buf (WPNeg_ipd, WPNeg);
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// Propagation delay Section
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
nmos (SI, SI_z , 1);
|
|
|
|
nmos (SO, SO_z , 1);
|
|
nmos (HOLDNeg, HOLDNegOut_zd , 1);
|
|
nmos (WPNeg, WPNegOut_zd , 1);
|
|
|
|
wire deg_pin;
|
|
wire deg_sin;
|
|
wire deg_holdin;
|
|
|
|
reg deq_holdin;
|
|
always @(HOLDNeg_ipd, HOLDNegOut_zd)
|
|
begin
|
|
if (HOLDNeg_ipd==HOLDNegOut_zd)
|
|
deq_holdin=1'b0;
|
|
else
|
|
deq_holdin=1'b1;
|
|
end
|
|
//VHDL VITAL CheckEnable equivalents
|
|
wire rd_slow;
|
|
assign rd_slow = slow_read;
|
|
wire rd_fast;
|
|
assign rd_fast = fast_read && ~quad_read;
|
|
wire quad_spi;
|
|
assign quad_spi = pp_quad || quad_read;
|
|
wire quad_rd;
|
|
assign quad_rd = deg_holdin && QE && ~dual_read && (SIOut_z != 1'bz);
|
|
wire quad_pg;
|
|
assign quad_pg = QE && WEL && pp_quad;
|
|
wire wr_prot;
|
|
assign wr_prot = SRP0 && WEL;
|
|
wire dual_rd;
|
|
assign dual_rd = dual_read ;
|
|
wire power;
|
|
assign power = PoweredUp;
|
|
wire hold_cond;
|
|
assign hold_cond = PoweredUp && ~QE && HOLDNeg_in != 1'bX;
|
|
wire any_read;
|
|
assign any_read = (dual_read || quad_read || slow_read || fast_read)
|
|
&& ~WEL && ~sr_read;
|
|
// check when data is generated from model to avoid setuphold check in
|
|
// this occasion
|
|
assign deg_holdin=deq_holdin;
|
|
|
|
reg deq_sin;
|
|
always @(SI_in, SIOut_z)
|
|
begin
|
|
if (SI_in !== 1'bZ)
|
|
deq_sin=1'b0;
|
|
else
|
|
deq_sin=1'b1;
|
|
end
|
|
assign deg_sin = deq_sin && ~read_out; /*&& (~any_read);*/
|
|
|
|
wire pg_ers;
|
|
assign pg_ers = PSTART || ESTART || sr_read;
|
|
|
|
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 =1; // tCLQV1
|
|
specparam tpd_SCK_SO_2 =1; // tCLQV2 -for read ID instructions
|
|
specparam tpd_CSNeg_SO =1; // tSHQZ (tDIS)
|
|
specparam tpd_HOLDNeg_SO =1; // tHLQZ, tHHQX
|
|
|
|
//tsetup values: setup times
|
|
specparam tsetup_CSNeg_SCK =1; // tSLCH, tSHCH
|
|
specparam tsetup_SI_SCK =1; // tDVCH
|
|
specparam tsetup_HOLDNeg_SCK =1; // tHLCH, tHHCH
|
|
specparam tsetup_WPNeg_CSNeg =1; // tWHSL
|
|
|
|
//thold values: hold times
|
|
specparam thold_CSNeg_SCK =1; // tCHSL, tCHSH
|
|
specparam thold_SI_SCK =1; // tCHDX
|
|
specparam thold_HOLDNeg_SCK =1; // tCHHL, tCHHH
|
|
specparam thold_WPNeg_CSNeg =1; // tSHWL
|
|
|
|
// tpw values: pulse width
|
|
specparam tpw_SCK_slow_posedge =1; // tCH
|
|
specparam tpw_SCK_slow_negedge =1; // tCL
|
|
specparam tpw_SCK_fast_posedge =1; // tCH
|
|
specparam tpw_SCK_fast_negedge =1; // tCL
|
|
specparam tpw_SCK_quad_posedge =1; // tCH
|
|
specparam tpw_SCK_quad_negedge =1; // tCL
|
|
specparam tpw_CSNeg_read_posedge =1; // tSHSL1
|
|
specparam tpw_CSNeg_pger_posedge =1; // tSHSL2
|
|
|
|
// tperiod min (calculated as 1/max freq)
|
|
specparam tperiod_SCK_slow =1;
|
|
specparam tperiod_SCK_fast =1;
|
|
specparam tperiod_SCK_quad =1;
|
|
|
|
// tdevice values: values for internal delays
|
|
|
|
// VCC (min) to CS# Low
|
|
specparam tdevice_PU = 1e7; // 10 us
|
|
// CS# High to Power Down Mode -- tDP
|
|
specparam tdevice_DP = 3e6; // 3 us
|
|
// CS# High to StandBy mode without Electronic Signature read
|
|
specparam tdevice_RES1 = 3e6; // 3 us
|
|
// CS# High to StandBy mode with Electronic Signature read
|
|
specparam tdevice_RES2 = 18e5; // 1.8 us
|
|
// CS# High to next Instruction after Suspend
|
|
specparam tdevice_SUS = 2e7; // 20 us
|
|
// Resume Suspend to Program/Erase time
|
|
specparam tdevice_PRGSUSP = 2e5; // 200 ns
|
|
|
|
`ifdef SPEEDSIM
|
|
// Page Program Time
|
|
specparam tdevice_PP = 3e8; // 30 us
|
|
// Byte Program Time (First Byte)
|
|
specparam tdevice_BP1 = 5e5; // 0.5 us
|
|
// Additional Byte Program Time (After First Byte)
|
|
specparam tdevice_BP2 = 12e4; // 120 ns
|
|
// Sector Erase Time (4KB)
|
|
specparam tdevice_SE = 4e9; // 4 ms
|
|
// Block Erase Time (32KB)
|
|
specparam tdevice_BE1 = 8e9; // 8 ms
|
|
// Block Erase Time (64KB)
|
|
specparam tdevice_BE2 = 1e10; // 10 ms
|
|
// Chip Erase Time
|
|
specparam tdevice_CE = 40e10; // 400 ms
|
|
// Write Status Register Time
|
|
specparam tdevice_WRR = 15e7; // 150 us
|
|
// Write Volatile Status Register Time
|
|
specparam tdevice_VRR = 5e4; // 50 ns
|
|
`else
|
|
// Page Program Time
|
|
specparam tdevice_PP = 3e9; // 3 ms
|
|
// Byte Program Time (First Byte)
|
|
specparam tdevice_BP1 = 5e7; // 50 us
|
|
// Additional Byte Program Time (After First Byte)
|
|
specparam tdevice_BP2 = 12e6; // 12 us
|
|
// Sector Erase Time (4KB)
|
|
specparam tdevice_SE = 4e11; // 400 ms
|
|
// Block Erase Time (32KB)
|
|
specparam tdevice_BE1 = 8e11; // 800 ms
|
|
// Block Erase Time (64KB)
|
|
specparam tdevice_BE2 = 1e12; // 1000 ms
|
|
// Chip Erase Time
|
|
specparam tdevice_CE = 40e12; // 40 s
|
|
// Write Status Register Time
|
|
specparam tdevice_WRR = 15e9; // 15 ms
|
|
// Write Volatile Status Register Time
|
|
specparam tdevice_VRR = 5e4; // 50 ns
|
|
`endif // SPEEDSIM
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// Input Port Delays don't require Verilog description
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// Path delays //
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
if (~read_id) (SCK => SO) = tpd_SCK_SO_1;
|
|
if ((~glitch || quad_read) && read_id) (SCK => SO) = tpd_SCK_SO_2;
|
|
if (CSNeg) (CSNeg => SO) = tpd_CSNeg_SO;
|
|
if (~quad_read) (HOLDNeg => SO) = tpd_HOLDNeg_SO;
|
|
if ((dual_read || quad_read) && ~read_id) (SCK => SI) = tpd_SCK_SO_1;
|
|
if (dual_read && read_id && ~glitch) (SCK => SI) = tpd_SCK_SO_2;
|
|
if (quad_read && read_id) (SCK => SI) = tpd_SCK_SO_2;
|
|
if (CSNeg && ~deg_sin) (CSNeg => SI) = tpd_CSNeg_SO;
|
|
if (~quad_read && dual_read) (HOLDNeg => SI) = tpd_HOLDNeg_SO;
|
|
|
|
if (quad_read && ~read_id) (SCK => WPNeg) = tpd_SCK_SO_1;
|
|
if (quad_read && read_id) (SCK => WPNeg) = tpd_SCK_SO_2;
|
|
if (quad_read && ~read_id) (SCK => HOLDNeg) = tpd_SCK_SO_1;
|
|
if (quad_read && read_id) (SCK => HOLDNeg) = tpd_SCK_SO_2;
|
|
if (CSNeg && QE) (CSNeg => SI) = tpd_CSNeg_SO;
|
|
if (CSNeg && QE) (CSNeg => WPNeg) = tpd_CSNeg_SO;
|
|
if (CSNeg && QE) (CSNeg => HOLDNeg) = tpd_CSNeg_SO;
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// Timing Violation //
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
$setup ( CSNeg , posedge SCK &&& power,
|
|
tsetup_CSNeg_SCK , Viol);
|
|
$setup ( SI , posedge SCK &&& deg_sin,
|
|
tsetup_SI_SCK , Viol);
|
|
$setup ( SO , posedge SCK &&& quad_pg,
|
|
tsetup_SI_SCK , Viol);
|
|
$setup ( WPNeg , posedge SCK &&& quad_pg,
|
|
tsetup_SI_SCK , Viol);
|
|
$setup ( HOLDNeg , posedge SCK &&& quad_pg,
|
|
tsetup_SI_SCK , Viol);
|
|
$setup ( HOLDNeg , posedge SCK &&& hold_cond,
|
|
tsetup_HOLDNeg_SCK , Viol);
|
|
$setup ( WPNeg , negedge CSNeg &&& WPNeg,
|
|
tsetup_WPNeg_CSNeg , Viol);
|
|
|
|
$hold ( posedge SCK &&& power, CSNeg,
|
|
thold_CSNeg_SCK , Viol);
|
|
$hold ( posedge SCK &&& deg_sin, SI ,
|
|
thold_SI_SCK , Viol);
|
|
$hold ( posedge SCK &&& quad_pg, SO ,
|
|
thold_SI_SCK , Viol);
|
|
$hold ( posedge SCK &&& quad_pg, WPNeg,
|
|
thold_SI_SCK , Viol);
|
|
$hold ( posedge SCK &&& quad_pg, HOLDNeg,
|
|
thold_SI_SCK , Viol);
|
|
$hold ( posedge SCK &&& hold_cond, HOLDNeg,
|
|
thold_HOLDNeg_SCK, Viol);
|
|
$hold ( posedge CSNeg &&& wr_prot, WPNeg,
|
|
thold_WPNeg_CSNeg, Viol);
|
|
|
|
$width ( posedge SCK &&& rd_slow , tpw_SCK_slow_posedge);
|
|
$width ( negedge SCK &&& rd_slow , tpw_SCK_slow_negedge);
|
|
$width ( posedge SCK &&& rd_fast , tpw_SCK_fast_posedge);
|
|
$width ( negedge SCK &&& rd_fast , tpw_SCK_fast_negedge);
|
|
$width ( posedge SCK &&& quad_spi , tpw_SCK_quad_posedge);
|
|
$width ( negedge SCK &&& quad_spi , tpw_SCK_quad_negedge);
|
|
$width ( posedge CSNeg &&& any_read , tpw_CSNeg_read_posedge);
|
|
$width ( posedge CSNeg &&& pg_ers , tpw_CSNeg_pger_posedge);
|
|
|
|
$period ( posedge SCK &&& rd_slow , tperiod_SCK_slow);
|
|
$period ( posedge SCK &&& rd_fast , tperiod_SCK_fast);
|
|
$period ( posedge SCK &&& quad_spi , tperiod_SCK_quad);
|
|
|
|
endspecify
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// Main Behavior Block //
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// FSM states
|
|
parameter IDLE = 4'd0;
|
|
parameter WRITE_SR = 4'd1;
|
|
parameter PAGE_PG = 4'd2;
|
|
parameter PG_SUSP = 4'd3;
|
|
parameter SECTOR_ERS = 4'd4;
|
|
parameter BULK_ERS = 4'd5;
|
|
parameter ERS_SUSP = 4'd6;
|
|
parameter ERS_SUSP_PG = 4'd7;
|
|
parameter PG_SUSP_ERS = 4'd8;
|
|
parameter DP_DOWN = 4'd9;
|
|
parameter WRITE_SR_V = 4'd10;
|
|
|
|
reg [3:0] current_state;
|
|
reg [3:0] next_state;
|
|
|
|
// Instruction type
|
|
parameter NONE = 6'd0;
|
|
parameter WREN = 6'd1; // 06h
|
|
parameter WRENV = 6'd2; // 50h
|
|
parameter WRDI = 6'd3; // 04h
|
|
parameter RDSR = 6'd4; // 05h
|
|
parameter RDSR2 = 6'd5; // 35h
|
|
parameter WRR = 6'd6; // 01h
|
|
parameter READ = 6'd7; // 03h
|
|
parameter FAST_READ = 6'd8; // 0Bh
|
|
parameter FAST_DREAD = 6'd9; // 3Bh
|
|
parameter FAST_QREAD = 6'd10; // 6Bh
|
|
parameter FAST_DREAD_2 = 6'd11; // BBh
|
|
parameter FAST_QREAD_4 = 6'd12; // EBh
|
|
parameter W_QREAD = 6'd13; // E7h
|
|
parameter WOCT_QREAD = 6'd14; // E3h
|
|
parameter SET_BURST_WRAP = 6'd15; // 77h
|
|
parameter CONT_RD_RST = 6'd16; // FFh or FFFFH
|
|
parameter PP = 6'd17; // 02h
|
|
parameter QPP = 6'd18; // 32h
|
|
parameter SE = 6'd19; // 20h
|
|
parameter BE_32 = 6'd20; // 52h
|
|
parameter BE_64 = 6'd21; // D8h
|
|
parameter CE = 6'd22; // C7h or 60h
|
|
parameter ERS_PG_SUSP = 6'd23; // 75h
|
|
parameter ERS_PG_RES = 6'd24; // 7Ah
|
|
parameter DP = 6'd25; // B9h
|
|
parameter RES_RD_ID = 6'd26; // ABh
|
|
parameter RDID = 6'd27; // 90h
|
|
parameter RDID_DUAL = 6'd28; // 92h
|
|
parameter RDID_QUAD = 6'd29; // 94h
|
|
parameter RD_UNIQ_ID = 6'd30; // 4Bh
|
|
parameter RDIDJ = 6'd31; // 9Fh
|
|
parameter RD_SFDP = 6'd32; // 5Ah
|
|
parameter ERS_SCREG = 6'd33; // 44h
|
|
parameter PG_SCREG = 6'd34; // 42h
|
|
parameter RD_SCREG = 6'd35; // 48h
|
|
|
|
reg [5:0] Instruct;
|
|
|
|
//Bus cycle state
|
|
parameter STAND_BY = 3'd0;
|
|
parameter OPCODE_BYTE = 3'd1;
|
|
parameter ADDRESS_BYTES = 3'd2;
|
|
parameter DUMMY_BYTES = 3'd3;
|
|
parameter MODE_BYTE = 3'd4;
|
|
parameter DATA_BYTES = 3'd5;
|
|
|
|
reg [2:0] bus_cycle_state;
|
|
|
|
|
|
//Power Up time;
|
|
initial
|
|
begin
|
|
PoweredUp = 1'b0;
|
|
#tdevice_PU PoweredUp = 1'b1;
|
|
end
|
|
|
|
always @(PoweredUp or falling_edge_CSNeg_ipd)
|
|
begin:CheckCEOnPowerUP
|
|
if ((~PoweredUp) && falling_edge_CSNeg_ipd)
|
|
$display ("Device is selected during Power Up");
|
|
end
|
|
|
|
initial
|
|
begin : Init
|
|
write = 1'b0;
|
|
read_out = 1'b0;
|
|
Address = 0;
|
|
change_addr = 1'b0;
|
|
// cnt = 0;
|
|
PGSUSP = 1'b0;
|
|
PGRES = 1'b0;
|
|
ESUSP = 1'b0;
|
|
ERES = 1'b0;
|
|
PDONE = 1'b1;
|
|
PSTART = 1'b0;
|
|
EDONE = 1'b1;
|
|
ESTART = 1'b0;
|
|
WDONE = 1'b1;
|
|
WSTART = 1'b0;
|
|
VLTDONE = 1'b1;
|
|
VLTSTART = 1'b0;
|
|
|
|
DP_in = 1'b0;
|
|
DP_out = 1'b0;
|
|
RES_in = 1'b0;
|
|
RES_out = 1'b0;
|
|
PRGRES_in = 1'b0;
|
|
ERSRES_in = 1'b0;
|
|
Instruct = NONE;
|
|
bus_cycle_state = STAND_BY;
|
|
current_state = IDLE;
|
|
next_state = IDLE;
|
|
|
|
end
|
|
|
|
// initialize memory and load preload files if any
|
|
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
|
|
//s25fl128k.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
|
|
|
|
for (i=SCREG_LoAddr;i<=SCREG_HiAddr;i=i+1)
|
|
begin
|
|
Security_Reg[i] = MaxData;
|
|
end
|
|
|
|
if (UserPreload && !(screg_file_name == "none"))
|
|
begin
|
|
//s25fl128kSCREG memory file
|
|
// / - comment
|
|
// @aaa - <aaa> stands for address of specific Security register
|
|
// dd - <dd> is byte to be written at SCREG(aaa++)
|
|
// (aa is incremented at every load)
|
|
// only first 1-4 columns are loaded. NO empty lines !!!!!!!!!!!!!!!!
|
|
$readmemh(screg_file_name,Security_Reg);
|
|
end
|
|
for (i=0;i<=255;i=i+1)
|
|
begin
|
|
Security_Reg1[i] = Security_Reg[i];
|
|
Security_Reg2[i] = Security_Reg[256+i];
|
|
Security_Reg3[i] = Security_Reg[512+i];
|
|
end
|
|
end
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
// SFDP - Serial Flash Discoverable Parameter register
|
|
initial
|
|
begin: InitSFDP
|
|
integer i;
|
|
integer j;
|
|
SFDP_array[8'h00] = 8'h53;
|
|
SFDP_array[8'h01] = 8'h46;
|
|
SFDP_array[8'h02] = 8'h44;
|
|
SFDP_array[8'h03] = 8'h50;
|
|
SFDP_array[8'h04] = 8'h01;
|
|
SFDP_array[8'h05] = 8'h01;
|
|
SFDP_array[8'h06] = 8'h00;
|
|
SFDP_array[8'h07] = 8'hFF;
|
|
SFDP_array[8'h08] = 8'hEF;
|
|
SFDP_array[8'h09] = 8'h00;
|
|
SFDP_array[8'h0A] = 8'h01;
|
|
SFDP_array[8'h0B] = 8'h04;
|
|
SFDP_array[8'h0C] = 8'h80;
|
|
SFDP_array[8'h0D] = 8'h00;
|
|
SFDP_array[8'h0E] = 8'h00;
|
|
SFDP_array[8'h0F] = 8'hFF;
|
|
SFDP_array[8'h10] = 8'hEF;
|
|
SFDP_array[8'h11] = 8'h00;
|
|
SFDP_array[8'h12] = 8'h01;
|
|
SFDP_array[8'h13] = 8'h00;
|
|
SFDP_array[8'h14] = 8'h90;
|
|
SFDP_array[8'h15] = 8'h00;
|
|
SFDP_array[8'h16] = 8'h00;
|
|
SFDP_array[8'h17] = 8'hFF;
|
|
|
|
for (i=24;i<=127;i=i+1)
|
|
begin
|
|
SFDP_array[i] = MaxData;
|
|
end
|
|
|
|
SFDP_array[8'h80] = 8'hE5;
|
|
SFDP_array[8'h81] = 8'h20;
|
|
SFDP_array[8'h82] = 8'hF1;
|
|
SFDP_array[8'h83] = 8'hFF;
|
|
SFDP_array[8'h84] = 8'hFF;
|
|
SFDP_array[8'h85] = 8'hFF;
|
|
SFDP_array[8'h86] = 8'hFF;
|
|
SFDP_array[8'h87] = 8'h07;
|
|
SFDP_array[8'h88] = 8'h44;
|
|
SFDP_array[8'h89] = 8'hEB;
|
|
SFDP_array[8'h8A] = 8'h08;
|
|
SFDP_array[8'h8B] = 8'h6B;
|
|
SFDP_array[8'h8C] = 8'h08;
|
|
SFDP_array[8'h8D] = 8'h3B;
|
|
SFDP_array[8'h8E] = 8'h80;
|
|
SFDP_array[8'h8F] = 8'hBB;
|
|
|
|
for (i=144;i<=255;i=i+1)
|
|
begin
|
|
SFDP_array[i] = MaxData;
|
|
end
|
|
|
|
end
|
|
///////////////////////////////////////////////////////////////////////////
|
|
//// Internal Delays
|
|
///////////////////////////////////////////////////////////////////////////
|
|
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
|
|
if (res_flag) // res_flag is '1' when read ID after resume DP
|
|
// res_flag will be set to '1' in DUMMY_BYTES if read ID
|
|
#tdevice_RES2 RES_out = RES_in;
|
|
else
|
|
#tdevice_RES1 RES_out = RES_in;
|
|
end
|
|
always @(negedge RES_in)
|
|
begin:TRESf
|
|
#1 RES_out = RES_in;
|
|
end
|
|
|
|
always @(posedge PRGSUSP_in)
|
|
begin:PRGSuspend
|
|
PRGSUSP_out = 1'b0;
|
|
#tdevice_SUS PRGSUSP_out = 1'b1;
|
|
end
|
|
|
|
always @(posedge PRGRES_in)
|
|
begin:ProgSuspend
|
|
PRGRES_out = 1'b0;
|
|
#tdevice_PRGSUSP PRGRES_out = 1'b1;
|
|
end
|
|
|
|
always @(posedge ERSSUSP_in)
|
|
begin:ERSSuspend
|
|
ERSSUSP_out = 1'b0;
|
|
#tdevice_SUS ERSSUSP_out = 1'b1;
|
|
end
|
|
|
|
always @(posedge ERSRES_in)
|
|
begin:ERSresume
|
|
ERSRES_out = 1'b0;
|
|
#tdevice_PRGSUSP ERSRES_out = 1'b1;
|
|
end
|
|
|
|
always @(posedge ERSRES_in or posedge PRGRES_in)
|
|
begin
|
|
susp_flag = 1'b1;
|
|
#tdevice_SUS susp_flag = 1'b0;
|
|
end
|
|
|
|
always @(next_state or PoweredUp)
|
|
begin: StateTransition
|
|
if (PoweredUp)
|
|
begin
|
|
current_state = next_state;
|
|
end
|
|
end
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// write cycle decode
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
integer opcode_cnt = 0;
|
|
integer addr_cnt = 0;
|
|
integer mode_cnt = 0;
|
|
integer wrap_cnt = 0;
|
|
integer dummy_cnt = 0;
|
|
integer data_cnt = 0;
|
|
integer bit_cnt = 0;
|
|
|
|
reg [4095:0] Data_in = 4096'b0;
|
|
reg [7:0] opcode;
|
|
reg [15:0] opcode_double;
|
|
reg [7:0] opcode_in;
|
|
reg [15:0] opcode_double_in;
|
|
reg [23:0] addr_bytes;
|
|
reg [23:0] Address_in;
|
|
reg [7:0] mode_byte;
|
|
reg [7:0] mode_in;
|
|
reg [7:0] wrap_in;
|
|
reg [7:0] wrap_byte;
|
|
|
|
integer quad_data_in [0:511];
|
|
reg [3:0] quad_nybble = 4'b0;
|
|
reg [3:0] Quad_slv;
|
|
reg [7:0] Byte_slv;
|
|
|
|
always @(rising_edge_CSNeg_ipd or falling_edge_CSNeg_ipd or
|
|
rising_edge_SCK_ipd or falling_edge_SCK_ipd)
|
|
begin: Buscycle
|
|
integer i;
|
|
integer j;
|
|
integer k;
|
|
if (falling_edge_CSNeg_ipd)
|
|
begin
|
|
if (bus_cycle_state==STAND_BY)
|
|
begin
|
|
bus_cycle_state = OPCODE_BYTE;
|
|
Instruct = NONE;
|
|
write = 1'b1;
|
|
opcode_cnt = 0;
|
|
addr_cnt = 0;
|
|
data_cnt = 0;
|
|
mode_cnt = 0;
|
|
wrap_cnt = 0;
|
|
dummy_cnt = 0;
|
|
end
|
|
else if (bus_cycle_state==DATA_BYTES && (mode_byte[5:4]==2'b10))
|
|
begin
|
|
bus_cycle_state = ADDRESS_BYTES;
|
|
dummy_cnt = 0;
|
|
opcode_cnt = 0;
|
|
end
|
|
end
|
|
if (rising_edge_SCK_ipd && PoweredUp)
|
|
begin
|
|
if (~CSNeg_ipd)
|
|
begin
|
|
case (bus_cycle_state)
|
|
OPCODE_BYTE :
|
|
begin
|
|
if ((HOLDNeg_in && ~QE) || QE)
|
|
begin
|
|
opcode_in[opcode_cnt] = SI_in;
|
|
opcode_cnt = opcode_cnt + 1;
|
|
if (opcode_cnt == BYTE)
|
|
begin
|
|
for (i=0;i<=7;i=i+1)
|
|
begin
|
|
opcode[i] = opcode_in[7-i];
|
|
end
|
|
case(opcode)
|
|
8'b00000110 : // 06h
|
|
begin
|
|
Instruct = WREN;
|
|
bus_cycle_state = DATA_BYTES;
|
|
end
|
|
8'b01010000 : // 50h
|
|
begin
|
|
Instruct = WRENV;
|
|
bus_cycle_state = DATA_BYTES;
|
|
end
|
|
8'b00000100 : // 04h
|
|
begin
|
|
Instruct = WRDI;
|
|
bus_cycle_state = DATA_BYTES;
|
|
end
|
|
8'b00000101 : // 05h
|
|
begin
|
|
Instruct = RDSR;
|
|
bus_cycle_state = DATA_BYTES;
|
|
end
|
|
8'b00110101 : // 05h
|
|
begin
|
|
Instruct = RDSR2;
|
|
bus_cycle_state = DATA_BYTES;
|
|
end
|
|
8'b00000001 : // 01h
|
|
begin
|
|
Instruct = WRR;
|
|
bus_cycle_state = DATA_BYTES;
|
|
end
|
|
8'b00000011 : // 03h
|
|
begin
|
|
Instruct = READ;
|
|
bus_cycle_state = ADDRESS_BYTES;
|
|
end
|
|
8'b00001011 : // 0Bh
|
|
begin
|
|
Instruct = FAST_READ;
|
|
bus_cycle_state = ADDRESS_BYTES;
|
|
end
|
|
8'b00111011 : // 3Bh
|
|
begin
|
|
Instruct = FAST_DREAD;
|
|
bus_cycle_state = ADDRESS_BYTES;
|
|
end
|
|
8'b01101011 : // 6Bh
|
|
begin
|
|
Instruct = FAST_QREAD;
|
|
if (QE)
|
|
bus_cycle_state = ADDRESS_BYTES;
|
|
else
|
|
bus_cycle_state = STAND_BY;
|
|
end
|
|
8'b10111011 : // BBh
|
|
begin
|
|
Instruct = FAST_DREAD_2;
|
|
bus_cycle_state = ADDRESS_BYTES;
|
|
end
|
|
8'b11101011 : // EBh
|
|
begin
|
|
Instruct = FAST_QREAD_4;
|
|
if (QE)
|
|
bus_cycle_state = ADDRESS_BYTES;
|
|
else
|
|
bus_cycle_state = STAND_BY;
|
|
end
|
|
8'b11100111 : // E7h
|
|
begin
|
|
Instruct = W_QREAD;
|
|
if (QE)
|
|
bus_cycle_state = ADDRESS_BYTES;
|
|
else
|
|
bus_cycle_state = STAND_BY;
|
|
end
|
|
8'b11100011 : // E3h
|
|
begin
|
|
Instruct = WOCT_QREAD;
|
|
if (QE)
|
|
bus_cycle_state = ADDRESS_BYTES;
|
|
else
|
|
bus_cycle_state = STAND_BY;
|
|
end
|
|
8'b01110111 : // 77h
|
|
begin
|
|
Instruct = SET_BURST_WRAP;
|
|
if (QE)
|
|
bus_cycle_state = DUMMY_BYTES;
|
|
else
|
|
bus_cycle_state = STAND_BY;
|
|
end
|
|
8'b11111111 : // FFh
|
|
begin
|
|
Instruct = CONT_RD_RST;
|
|
bus_cycle_state = MODE_BYTE;
|
|
end
|
|
8'b00000010 : // 02h
|
|
begin
|
|
Instruct = PP;
|
|
bus_cycle_state = ADDRESS_BYTES;
|
|
end
|
|
8'b00110010 : // 32h
|
|
begin
|
|
Instruct = QPP;
|
|
if (QE)
|
|
bus_cycle_state = ADDRESS_BYTES;
|
|
else
|
|
bus_cycle_state = STAND_BY;
|
|
end
|
|
8'b00100000 : // 20h
|
|
begin
|
|
Instruct = SE;
|
|
bus_cycle_state = ADDRESS_BYTES;
|
|
end
|
|
8'b01010010 : // 52h
|
|
begin
|
|
Instruct = BE_32;
|
|
bus_cycle_state = ADDRESS_BYTES;
|
|
end
|
|
8'b11011000 : // D8h
|
|
begin
|
|
Instruct = BE_64;
|
|
bus_cycle_state = ADDRESS_BYTES;
|
|
end
|
|
8'b11000111, 8'b01100000 : // C7h or 60h
|
|
begin
|
|
Instruct = CE;
|
|
bus_cycle_state = DATA_BYTES;
|
|
end
|
|
8'b01110101 : // 75h
|
|
begin
|
|
Instruct = ERS_PG_SUSP;
|
|
bus_cycle_state = DATA_BYTES;
|
|
end
|
|
8'b01111010 : // 7Ah
|
|
begin
|
|
Instruct = ERS_PG_RES;
|
|
bus_cycle_state = DATA_BYTES;
|
|
end
|
|
8'b10111001 : // B9h
|
|
begin
|
|
Instruct = DP;
|
|
bus_cycle_state = DATA_BYTES;
|
|
end
|
|
8'b10101011: // ABh
|
|
begin
|
|
Instruct = RES_RD_ID;
|
|
bus_cycle_state = DUMMY_BYTES;
|
|
end
|
|
8'b10010000: // 90h
|
|
begin
|
|
Instruct = RDID;
|
|
bus_cycle_state = ADDRESS_BYTES;
|
|
end
|
|
8'b10010010: // 92h
|
|
begin
|
|
Instruct = RDID_DUAL;
|
|
bus_cycle_state = ADDRESS_BYTES;
|
|
end
|
|
8'b10010100: // 94h
|
|
begin
|
|
Instruct = RDID_QUAD;
|
|
if (QE)
|
|
bus_cycle_state = ADDRESS_BYTES;
|
|
else
|
|
bus_cycle_state = STAND_BY;
|
|
end
|
|
8'b01001011: // 4Bh
|
|
begin
|
|
Instruct = RD_UNIQ_ID;
|
|
bus_cycle_state = DUMMY_BYTES;
|
|
end
|
|
8'b10011111: // 9Fh
|
|
begin
|
|
Instruct = RDIDJ;
|
|
bus_cycle_state = DATA_BYTES;
|
|
end
|
|
8'b01011010: // 5Ah
|
|
begin
|
|
Instruct = RD_SFDP;
|
|
bus_cycle_state = ADDRESS_BYTES;
|
|
end
|
|
8'b01000100: // 44h
|
|
begin
|
|
Instruct = ERS_SCREG;
|
|
bus_cycle_state = ADDRESS_BYTES;
|
|
end
|
|
8'b01000010: // 42h
|
|
begin
|
|
Instruct = PG_SCREG;
|
|
bus_cycle_state = ADDRESS_BYTES;
|
|
end
|
|
8'b01001000: // 48h
|
|
begin
|
|
Instruct = RD_SCREG;
|
|
bus_cycle_state = ADDRESS_BYTES;
|
|
end
|
|
endcase
|
|
end
|
|
end
|
|
else
|
|
$display("Device is in HOLD mode, opcode");
|
|
end // end of OPCODE_BYTE
|
|
|
|
ADDRESS_BYTES :
|
|
begin
|
|
if ((HOLDNeg_in && ~QE) || QE)
|
|
begin
|
|
if (Instruct == READ || Instruct == FAST_READ ||
|
|
Instruct == FAST_DREAD || Instruct == RDID ||
|
|
Instruct == SE || Instruct == PP ||
|
|
Instruct == RD_SCREG || Instruct == PG_SCREG ||
|
|
Instruct == RD_SFDP || Instruct == BE_32 ||
|
|
Instruct == BE_64 || Instruct == ERS_SCREG ||
|
|
((Instruct == QPP || Instruct == FAST_QREAD)
|
|
&& QE))
|
|
begin
|
|
Address_in[addr_cnt] = SI_in;
|
|
addr_cnt = addr_cnt + 1;
|
|
if (addr_cnt == 3*BYTE)
|
|
begin
|
|
for (i=23;i>=0;i=i-1)
|
|
begin
|
|
addr_bytes[23-i] = Address_in[i];
|
|
end
|
|
Address = addr_bytes ;
|
|
change_addr = 1'b1;
|
|
#1000 change_addr = 1'b0;
|
|
if (Instruct == PP || Instruct == QPP
|
|
|| Instruct == READ || Instruct == SE
|
|
|| Instruct == BE_32 || Instruct == BE_64
|
|
|| Instruct == RDID || Instruct == PG_SCREG
|
|
|| Instruct == ERS_SCREG)
|
|
bus_cycle_state = DATA_BYTES;
|
|
else
|
|
bus_cycle_state = DUMMY_BYTES;
|
|
end
|
|
end
|
|
else if (Instruct == RDID_DUAL ||
|
|
Instruct == FAST_DREAD_2)
|
|
begin
|
|
if (SO_in !== 1'bX)
|
|
begin
|
|
Address_in[2*addr_cnt] = SO_in;
|
|
Address_in[2*addr_cnt + 1] = SI_in;
|
|
read_cnt = 0;
|
|
addr_cnt = addr_cnt + 1;
|
|
if (addr_cnt == 3*BYTE/2)
|
|
begin
|
|
addr_cnt = 0;
|
|
for (i=23;i>=0;i=i-1)
|
|
begin
|
|
addr_bytes[23-i] = Address_in[i];
|
|
end
|
|
Address = addr_bytes ;
|
|
change_addr = 1'b1;
|
|
#1000 change_addr = 1'b0;
|
|
bus_cycle_state = MODE_BYTE;
|
|
end
|
|
end
|
|
else
|
|
begin
|
|
if (mode_byte[5:4] == 2'b10)
|
|
begin
|
|
opcode_double_in[opcode_cnt] = SI_in;
|
|
opcode_cnt = opcode_cnt + 1;
|
|
|
|
if (opcode_cnt == 2*BYTE)
|
|
begin
|
|
for (i=0;i<=15;i=i+1)
|
|
begin
|
|
opcode_double[i] =
|
|
opcode_double_in[15-i];
|
|
end
|
|
if (opcode_double == 16'hFFFF)
|
|
begin
|
|
Instruct = CONT_RD_RST;
|
|
bus_cycle_state = MODE_BYTE;
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
else if (QE && (Instruct == FAST_QREAD_4 ||
|
|
Instruct == W_QREAD ||
|
|
Instruct == WOCT_QREAD ||
|
|
Instruct == RDID_QUAD))
|
|
begin
|
|
if (SO_in !== 1'bX)
|
|
begin
|
|
Address_in[4*addr_cnt] = HOLDNeg_in;
|
|
Address_in[4*addr_cnt+1] = WPNeg_in;
|
|
Address_in[4*addr_cnt+2] = SO_in;
|
|
Address_in[4*addr_cnt+3] = SI_in;
|
|
read_cnt = 0;
|
|
addr_cnt = addr_cnt + 1;
|
|
if (addr_cnt == 3*BYTE/4)
|
|
begin
|
|
addr_cnt = 0;
|
|
for(i=23;i>=0;i=i-1)
|
|
begin
|
|
addr_bytes[23-i] = Address_in[i];
|
|
end
|
|
Address = addr_bytes ;
|
|
change_addr = 1'b1;
|
|
#1000 change_addr = 1'b0;
|
|
bus_cycle_state = MODE_BYTE;
|
|
end
|
|
end
|
|
else
|
|
begin
|
|
if (mode_byte[5:4] == 2'b10)
|
|
begin
|
|
opcode_in[opcode_cnt] = SI_in;
|
|
opcode_cnt = opcode_cnt + 1;
|
|
if (opcode_cnt == BYTE)
|
|
begin
|
|
for (i=0;i<=7;i=i+1)
|
|
begin
|
|
opcode[i] = opcode_in[7-i];
|
|
end
|
|
if (opcode == 8'hFF)
|
|
begin
|
|
Instruct = CONT_RD_RST;
|
|
bus_cycle_state = MODE_BYTE;
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
else
|
|
$display("Device is in HOLD mode, addr");
|
|
end // end of ADDRESS_BYTES
|
|
|
|
MODE_BYTE:
|
|
begin
|
|
if (QE || (HOLDNeg_in && ~QE))
|
|
begin
|
|
if (Instruct == SET_BURST_WRAP && QE)
|
|
begin
|
|
wrap_in[4*wrap_cnt] = HOLDNeg_in;
|
|
wrap_in[4*wrap_cnt+1] = WPNeg_in;
|
|
wrap_in[4*wrap_cnt+2] = SO_in;
|
|
wrap_in[4*wrap_cnt+3] = SI_in;
|
|
wrap_cnt = wrap_cnt + 1;
|
|
if (wrap_cnt == BYTE/4)
|
|
begin
|
|
wrap_cnt = 0;
|
|
for(i=7;i>=0;i=i-1)
|
|
begin
|
|
wrap_byte[i] = wrap_in[7-i];
|
|
end
|
|
bus_cycle_state = DATA_BYTES;
|
|
end
|
|
case (wrap_byte[6:5])
|
|
2'b00:
|
|
w_size = 8;
|
|
2'b01:
|
|
w_size = 16;
|
|
2'b10:
|
|
w_size = 32;
|
|
2'b11:
|
|
w_size = 64;
|
|
endcase
|
|
end
|
|
else if ((Instruct == FAST_QREAD_4 ||
|
|
Instruct == WOCT_QREAD ||
|
|
Instruct == W_QREAD ||
|
|
Instruct == RDID_QUAD ) && QE)
|
|
// FAST_QREAD_4,WOCT_QREAD,W_QREAD,RDID_QUAD
|
|
begin
|
|
mode_in[4*mode_cnt] = HOLDNeg_in;
|
|
mode_in[4*mode_cnt+1] = WPNeg_in;
|
|
mode_in[4*mode_cnt+2] = SO_in;
|
|
mode_in[4*mode_cnt+3] = SI_in;
|
|
mode_cnt = mode_cnt + 1;
|
|
if (mode_cnt == BYTE/4)
|
|
begin
|
|
mode_cnt = 0;
|
|
for(i=7;i>=0;i=i-1)
|
|
begin
|
|
mode_byte[i] = mode_in[7-i];
|
|
end
|
|
if (Instruct == WOCT_QREAD)
|
|
bus_cycle_state = DATA_BYTES;
|
|
else
|
|
bus_cycle_state = DUMMY_BYTES;
|
|
end
|
|
end
|
|
else if (Instruct == RDID_DUAL ||
|
|
Instruct == FAST_DREAD_2)
|
|
begin
|
|
mode_in[2*mode_cnt] = SO_in;
|
|
mode_in[2*mode_cnt+1] = SI_in;
|
|
mode_cnt = mode_cnt + 1;
|
|
if (mode_cnt == BYTE/2)
|
|
begin
|
|
mode_cnt = 0;
|
|
for(i=7;i>=0;i=i-1)
|
|
begin
|
|
mode_byte[i] = mode_in[7-i];
|
|
end
|
|
bus_cycle_state = DATA_BYTES;
|
|
end
|
|
end
|
|
end
|
|
else
|
|
$display("Device is in HOLD mode, mode");
|
|
|
|
end // end of MODE_BYTE
|
|
|
|
DUMMY_BYTES:
|
|
begin
|
|
if (QE || (HOLDNeg_in && ~QE))
|
|
begin
|
|
if ((Instruct == FAST_QREAD_4 ||
|
|
Instruct == RDID_QUAD) && QE)
|
|
begin
|
|
dummy_cnt = dummy_cnt + 1;
|
|
if (dummy_cnt == BYTE/2)
|
|
bus_cycle_state = DATA_BYTES;
|
|
end
|
|
else if (Instruct == W_QREAD && QE)
|
|
begin
|
|
dummy_cnt = dummy_cnt + 1;
|
|
if (dummy_cnt == BYTE/4)
|
|
bus_cycle_state = DATA_BYTES;
|
|
end
|
|
else if (Instruct == SET_BURST_WRAP && QE)
|
|
begin
|
|
dummy_cnt = dummy_cnt + 1;
|
|
if (dummy_cnt == 3*BYTE/4)
|
|
bus_cycle_state = MODE_BYTE;
|
|
end
|
|
else if (Instruct == FAST_QREAD && QE)
|
|
begin
|
|
dummy_cnt = dummy_cnt + 1;
|
|
if (dummy_cnt == BYTE)
|
|
bus_cycle_state = DATA_BYTES;
|
|
end
|
|
else if (Instruct==FAST_READ || Instruct==RD_SFDP
|
|
|| Instruct == FAST_DREAD || Instruct == RD_SCREG)
|
|
begin
|
|
dummy_cnt = dummy_cnt + 1;
|
|
if (dummy_cnt == BYTE)
|
|
bus_cycle_state = DATA_BYTES;
|
|
end
|
|
else if (Instruct == RD_UNIQ_ID)
|
|
begin
|
|
dummy_cnt = dummy_cnt + 1;
|
|
if (dummy_cnt == 4*BYTE)
|
|
bus_cycle_state = DATA_BYTES;
|
|
end
|
|
else // for RES_RD_ID
|
|
begin
|
|
dummy_cnt = dummy_cnt + 1;
|
|
if (dummy_cnt == 3*BYTE)
|
|
bus_cycle_state = DATA_BYTES;
|
|
end
|
|
end
|
|
else
|
|
$display("Device is in HOLD mode, dummy");
|
|
end // end of DUMMY_BYTES
|
|
|
|
DATA_BYTES:
|
|
begin
|
|
if (Instruct == PP || Instruct == WRR ||
|
|
Instruct == PG_SCREG)
|
|
begin
|
|
if ((HOLDNeg_in && ~QE) || QE)
|
|
begin
|
|
if (data_cnt > 2047)
|
|
//In case of serial mode and 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_in;
|
|
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_in;
|
|
data_cnt = data_cnt + 1;
|
|
bit_cnt = 0;
|
|
end
|
|
end
|
|
else
|
|
$display("Device is in HOLD mode, data");
|
|
end
|
|
else if (Instruct == QPP && QE)
|
|
begin
|
|
pp_quad = 1'b1;
|
|
quad_nybble = {HOLDNeg_in, WPNeg_in,
|
|
SO_in, SI_in};
|
|
if (data_cnt > 511)
|
|
begin
|
|
//In case of quad mode and QPP,if more than
|
|
// 256 bytes are sent to the device
|
|
for(i=0;i<=510;i=i+1)
|
|
begin
|
|
quad_data_in[i] = quad_data_in[i+1];
|
|
end
|
|
quad_data_in[511] = quad_nybble;
|
|
data_cnt = data_cnt +1;
|
|
end
|
|
else
|
|
begin
|
|
if (quad_nybble !== 4'bZZZZ)
|
|
begin
|
|
quad_data_in[data_cnt] = quad_nybble;
|
|
end
|
|
data_cnt = data_cnt +1;
|
|
end
|
|
end
|
|
end // end of DATA_BYTES
|
|
endcase // end of case bus_cycle_state
|
|
end // end of ~CSNeg
|
|
end // end of rising_edge_SCK
|
|
|
|
if (falling_edge_SCK_ipd)
|
|
begin
|
|
if ((bus_cycle_state == DATA_BYTES) && (~CSNeg_ipd))
|
|
begin
|
|
if (((Instruct == RDSR || Instruct == RDSR2 ||
|
|
Instruct == FAST_READ || Instruct == FAST_DREAD ||
|
|
Instruct == FAST_DREAD_2 || Instruct == RES_RD_ID ||
|
|
Instruct == RDID || Instruct == RDID_DUAL ||
|
|
Instruct == RD_UNIQ_ID || Instruct == RDIDJ ||
|
|
Instruct == RD_SFDP || Instruct == RD_SCREG ||
|
|
Instruct == READ) && ((HOLDNeg_in && ~QE) || QE)) ||
|
|
((Instruct == FAST_QREAD || Instruct == FAST_QREAD_4 ||
|
|
Instruct == W_QREAD || Instruct == RDID_QUAD ||
|
|
Instruct == WOCT_QREAD) && QE))
|
|
begin
|
|
read_out = 1'b1;
|
|
#1 read_out = 1'b0;
|
|
end
|
|
end // end of ~CSNeg_ipd
|
|
end // end of falling_edge_SCK_ipd
|
|
|
|
if (rising_edge_CSNeg_ipd)
|
|
begin
|
|
if (bus_cycle_state==MODE_BYTE && Instruct == CONT_RD_RST)
|
|
begin
|
|
mode_byte[5:4] = 2'b11;
|
|
mode_byte[7:6] = 2'b00;
|
|
mode_byte[3:0] = 4'b0000;
|
|
bus_cycle_state = STAND_BY;
|
|
end
|
|
else if (bus_cycle_state==DATA_BYTES && ~(mode_byte[5:4]==2'b10))
|
|
begin
|
|
bus_cycle_state = STAND_BY;
|
|
case (Instruct)
|
|
WREN,
|
|
WRDI,
|
|
SET_BURST_WRAP,
|
|
SE,
|
|
BE_32,
|
|
BE_64,
|
|
CE,
|
|
ERS_PG_RES,
|
|
DP,
|
|
ERS_SCREG:
|
|
begin
|
|
if (data_cnt == 0)
|
|
write = 1'b0;
|
|
end
|
|
|
|
WRENV:
|
|
begin
|
|
write = 1'b0;
|
|
wren_vlt_flag = 1'b1;
|
|
end
|
|
|
|
RES_RD_ID:
|
|
begin
|
|
write = 1'b0;
|
|
res_flag = 1'b1;
|
|
end
|
|
|
|
WRR:
|
|
begin
|
|
if (data_cnt == 8)
|
|
//If CS# is driven high after eight
|
|
//cycle,only the Status Register is
|
|
//written to.
|
|
begin
|
|
write = 1'b0;
|
|
for(i=0;i<=7;i=i+1)
|
|
begin
|
|
Status_reg1_in[i]=
|
|
Data_in[7-i];
|
|
end
|
|
end
|
|
else if (data_cnt == 16)
|
|
//After the 16th cycle both the
|
|
//Status and Configuration Registers
|
|
//are written to.
|
|
begin
|
|
write = 1'b0;
|
|
for(i=0;i<=7;i=i+1)
|
|
begin
|
|
Status_reg1_in[i]=
|
|
Data_in[7-i];
|
|
Status_reg2_in[i]=
|
|
Data_in[15-i];
|
|
end
|
|
end
|
|
end
|
|
|
|
PP,
|
|
PG_SCREG:
|
|
begin
|
|
if (data_cnt > 0)
|
|
begin
|
|
if ((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
|
|
end
|
|
|
|
QPP:
|
|
begin
|
|
if (data_cnt >0)
|
|
begin
|
|
if ((data_cnt % 2) == 0)
|
|
begin
|
|
write = 1'b0;
|
|
for (i=0;i<=255;i=i+1)
|
|
begin
|
|
for(j=1;j>=0;j=j-1)
|
|
begin
|
|
Quad_slv =
|
|
quad_data_in[(i*2)+(1-j)];
|
|
if (j==1)
|
|
Byte_slv[7:4] = Quad_slv;
|
|
else // if (j==0)
|
|
Byte_slv[3:0] = Quad_slv;
|
|
end
|
|
WByte[i] = Byte_slv;
|
|
end
|
|
if (data_cnt > 256*BYTE/4)
|
|
Byte_number = 255;
|
|
else
|
|
Byte_number = ((data_cnt/2) - 1);
|
|
end
|
|
end
|
|
end
|
|
|
|
endcase
|
|
end
|
|
else if (bus_cycle_state==DATA_BYTES && (mode_byte[5:4]==2'b10))
|
|
begin
|
|
bus_cycle_state = DATA_BYTES;
|
|
end
|
|
else
|
|
begin
|
|
bus_cycle_state = STAND_BY;
|
|
if (HOLDNeg_in && (Instruct == RES_RD_ID) &&
|
|
(dummy_cnt == 0))
|
|
begin
|
|
write = 1'b0;
|
|
res_flag = 1'b0;
|
|
end
|
|
end
|
|
end // end of rising_edge_CSNeg_ipd
|
|
|
|
end // end of Buscycle
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
// Timing control for the Page Program
|
|
///////////////////////////////////////////////////////////////////////////
|
|
time pob;
|
|
time elapsed;
|
|
time start;
|
|
time duration;
|
|
event pdone_event;
|
|
|
|
always @(rising_edge_PSTART)
|
|
begin
|
|
if ((Instruct == PP) || (Instruct == QPP) || (Instruct == PG_SCREG))
|
|
pob = tdevice_PP;
|
|
else
|
|
pob = tdevice_BP1;
|
|
if ((rising_edge_PSTART) && PDONE)
|
|
begin
|
|
elapsed = 0;
|
|
PDONE = 1'b0;
|
|
->pdone_event;
|
|
start = $time;
|
|
end
|
|
end
|
|
|
|
always @(PGSUSP_event)
|
|
begin
|
|
if ((PGSUSP_event) && PGSUSP && (~PDONE))
|
|
begin
|
|
disable pdone_process;
|
|
elapsed = $time - start;
|
|
duration = pob - elapsed;
|
|
PDONE = 1'b0;
|
|
end
|
|
end
|
|
|
|
always @(PGRES_event)
|
|
begin
|
|
if ((PGRES_event) && PGRES && (~PDONE))
|
|
begin
|
|
start = $time;
|
|
->pdone_event;
|
|
end
|
|
end
|
|
|
|
always @(pdone_event)
|
|
begin:pdone_process
|
|
PDONE = 1'b0;
|
|
#pob PDONE = 1'b1;
|
|
end
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
// Timing control for the Write Status Register Operation
|
|
// start
|
|
///////////////////////////////////////////////////////////////////////////
|
|
time wob;
|
|
always @(WSTART)
|
|
begin
|
|
wob = tdevice_WRR;
|
|
if ((rising_edge_WSTART) && WDONE)
|
|
begin
|
|
WDONE = 1'b0;
|
|
#wob WDONE = 1'b1;
|
|
end
|
|
end
|
|
///////////////////////////////////////////////////////////////////////////
|
|
// Timing control for the Volatile Write Status Register Operation
|
|
// start
|
|
///////////////////////////////////////////////////////////////////////////
|
|
time vob;
|
|
always @(VLTSTART)
|
|
begin
|
|
vob = tdevice_VRR;
|
|
if (rising_edge_VLTSTART && VLTDONE)
|
|
begin
|
|
VLTDONE = 1'b0;
|
|
#vob VLTDONE = 1'b1;
|
|
end
|
|
end
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
// Timing control for the Erase Operations
|
|
///////////////////////////////////////////////////////////////////////////
|
|
time seo;
|
|
time beo32;
|
|
time beo64;
|
|
time ceo;
|
|
event edone_event;
|
|
|
|
always @(rising_edge_ESTART)
|
|
begin
|
|
seo = tdevice_SE;
|
|
beo32 = tdevice_BE1;
|
|
beo64 = tdevice_BE2;
|
|
ceo = tdevice_CE;
|
|
if ((rising_edge_ESTART) && EDONE)
|
|
begin
|
|
if (Instruct == CE)
|
|
begin
|
|
duration = ceo;
|
|
end
|
|
else if (Instruct == BE_64)
|
|
begin
|
|
duration = beo64;
|
|
end
|
|
else if (Instruct == BE_32)
|
|
begin
|
|
duration = beo32;
|
|
end
|
|
else
|
|
begin
|
|
duration = seo;
|
|
end
|
|
elapsed = 0;
|
|
EDONE = 1'b0;
|
|
->edone_event;
|
|
start = $time;
|
|
end
|
|
end
|
|
|
|
always @(ESUSP_event)
|
|
begin
|
|
if ((ESUSP_event) && ESUSP && (~EDONE))
|
|
begin
|
|
disable edone_process;
|
|
elapsed = $time - start;
|
|
duration = duration - elapsed;
|
|
EDONE = 1'b0;
|
|
end
|
|
end
|
|
|
|
always @(ERES_event)
|
|
begin
|
|
if ((ERES_event) && ERES && (~EDONE))
|
|
begin
|
|
start = $time;
|
|
->edone_event;
|
|
end
|
|
end
|
|
|
|
always @(edone_event)
|
|
begin : edone_process
|
|
EDONE = 1'b0;
|
|
#duration EDONE = 1'b1;
|
|
end
|
|
|
|
///////////////////////////////////////////////////////////////////
|
|
// Process for clock frequency determination
|
|
///////////////////////////////////////////////////////////////////
|
|
always @(posedge SCK_ipd)
|
|
begin : clock_period
|
|
if (SCK_ipd)
|
|
begin
|
|
SCK_cycle = $time - prev_SCK;
|
|
prev_SCK = $time;
|
|
end
|
|
end
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
// Main Behavior Process
|
|
// combinational process for next state generation
|
|
///////////////////////////////////////////////////////////////////////////
|
|
reg rising_edge_PDONE = 1'b0;
|
|
reg rising_edge_EDONE = 1'b0;
|
|
reg rising_edge_WDONE = 1'b0;
|
|
reg rising_edge_VLTDONE = 1'b0;
|
|
reg falling_edge_write = 1'b0;
|
|
reg rising_edge_DP_out = 1'b0;
|
|
|
|
integer i;
|
|
integer j;
|
|
|
|
always @(rising_edge_PoweredUp or falling_edge_write or rising_edge_DP_out
|
|
or rising_edge_PDONE or rising_edge_WDONE or rising_edge_EDONE or
|
|
ERSSUSP_out_event or ERSRES_out_event or RES_out or
|
|
PRGSUSP_out_event or PRGRES_out_event or rising_edge_VLTDONE)
|
|
begin: StateGen1
|
|
|
|
if (rising_edge_PoweredUp)
|
|
next_state = IDLE;
|
|
else
|
|
begin
|
|
case (current_state)
|
|
IDLE :
|
|
begin
|
|
if (falling_edge_write)
|
|
begin
|
|
if (Instruct == WRR && (~SRP1 &&
|
|
(~SRP0 || (SRP0 && WPNeg))))
|
|
begin
|
|
if (WEL && ~wren_vlt_flag)
|
|
next_state = WRITE_SR;
|
|
else if (~WEL && wren_vlt_flag)
|
|
next_state = WRITE_SR_V;
|
|
end
|
|
else if (Instruct == PP && WEL)
|
|
begin
|
|
sect = Address / 16'h1000;
|
|
sect_tmp_pg = sect;
|
|
if (Sec_Prot[sect] == 0)
|
|
next_state = PAGE_PG;
|
|
end
|
|
else if (Instruct == QPP && WEL && QE)
|
|
begin
|
|
sect = Address / 16'h1000;
|
|
sect_tmp_pg = sect;
|
|
if (Sec_Prot[sect] == 0)
|
|
next_state = PAGE_PG;
|
|
end
|
|
else if (Instruct == PG_SCREG && WEL)
|
|
begin
|
|
sect = Address / 16'h1000;
|
|
if ((sect < 4 && sect > 0) && LB[sect-1]==0)
|
|
next_state = PAGE_PG;
|
|
end
|
|
else if (Instruct == ERS_SCREG && WEL)
|
|
begin
|
|
sect = Address / 16'h1000;
|
|
if ((sect <= 3) && LB[sect-1]==0)
|
|
next_state = SECTOR_ERS;
|
|
end
|
|
else if ((Instruct == SE || Instruct == BE_32 ||
|
|
Instruct == BE_64) && WEL)
|
|
begin
|
|
sect = Address / 16'h1000;
|
|
sect_tmp_ers = sect;
|
|
if (Sec_Prot[sect] == 0)
|
|
next_state = SECTOR_ERS;
|
|
end
|
|
else if (Instruct == CE && WEL &&
|
|
((~CMP && ~BP2 && ~BP1 && ~BP0) ||
|
|
(CMP && BP2 && BP1 && BP0)))
|
|
next_state = BULK_ERS;
|
|
else
|
|
next_state = IDLE;
|
|
end
|
|
else if (rising_edge_DP_out)
|
|
next_state = DP_DOWN;
|
|
end // end of IDLE
|
|
|
|
WRITE_SR:
|
|
begin
|
|
if (rising_edge_WDONE)
|
|
next_state = IDLE;
|
|
end // end of WRITE_SR
|
|
|
|
WRITE_SR_V:
|
|
begin
|
|
if (rising_edge_VLTDONE)
|
|
next_state = IDLE;
|
|
end
|
|
|
|
PAGE_PG:
|
|
begin
|
|
if (PRGSUSP_out_event && PRGSUSP_out == 1)
|
|
next_state = PG_SUSP;
|
|
else if (rising_edge_PDONE)
|
|
next_state = IDLE;
|
|
end // end of PAGE_PG
|
|
|
|
PG_SUSP:
|
|
begin
|
|
if (PRGRES_out_event && PRGRES_out == 1)
|
|
next_state = PAGE_PG;
|
|
else if (falling_edge_write)
|
|
begin
|
|
if (Instruct == SE || Instruct == BE_32 ||
|
|
Instruct == BE_64)
|
|
begin
|
|
sect = Address / 16'h1000;
|
|
if ((Sec_Prot[sect] == 0) && (sect != sect_tmp_pg))
|
|
next_state = PG_SUSP_ERS;
|
|
end
|
|
end
|
|
end // end of PG_SUSP
|
|
|
|
PG_SUSP_ERS:
|
|
begin
|
|
if (rising_edge_EDONE)
|
|
next_state = PG_SUSP;
|
|
else
|
|
next_state = PG_SUSP_ERS;
|
|
end
|
|
|
|
BULK_ERS:
|
|
begin
|
|
if (rising_edge_EDONE)
|
|
next_state = IDLE;
|
|
end
|
|
|
|
SECTOR_ERS:
|
|
begin
|
|
if (ERSSUSP_out_event && ERSSUSP_out == 1)
|
|
next_state = ERS_SUSP;
|
|
else if (rising_edge_EDONE)
|
|
next_state = IDLE;
|
|
end
|
|
|
|
ERS_SUSP:
|
|
begin
|
|
if (ERSRES_out_event && ERSRES_out == 1)
|
|
next_state = SECTOR_ERS;
|
|
else if (falling_edge_write)
|
|
begin
|
|
if (Instruct == PP || (Instruct == QPP && QE))
|
|
begin
|
|
sect = Address / 16'h1000;
|
|
if ((Sec_Prot[sect] == 0)&&(sect != sect_tmp_ers))
|
|
next_state = ERS_SUSP_PG;
|
|
end
|
|
else if (Instruct == PG_SCREG)
|
|
begin
|
|
sect = Address / 16'h1000;
|
|
if ((sect < 4 && sect > 0) && LB[sect-1]==0)
|
|
next_state = ERS_SUSP_PG;
|
|
end
|
|
end
|
|
end
|
|
|
|
ERS_SUSP_PG:
|
|
begin
|
|
if (rising_edge_PDONE)
|
|
next_state = ERS_SUSP;
|
|
else
|
|
next_state = ERS_SUSP_PG;
|
|
end
|
|
|
|
DP_DOWN:
|
|
begin
|
|
if (rising_edge_RES_out)
|
|
next_state = IDLE;
|
|
end
|
|
|
|
endcase // end case of current_state
|
|
end //
|
|
end // end of StateGen1
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
//FSM Output generation and general functionality
|
|
///////////////////////////////////////////////////////////////////////////
|
|
reg rising_edge_read_out = 1'b0;
|
|
reg Instruct_event = 1'b0;
|
|
reg change_addr_event = 1'b0;
|
|
reg current_state_event = 1'b0;
|
|
|
|
integer WData [0:255];
|
|
integer Addr;
|
|
integer Addr_ers;
|
|
integer Addr_tmp;
|
|
integer Addr_tmp_2;
|
|
integer Addr_tmp_3;
|
|
integer Addr_screg;
|
|
|
|
always @(oe_event)
|
|
begin
|
|
oe = 1'b1;
|
|
#1000 oe = 1'b0;
|
|
end
|
|
|
|
always @(rising_edge_read_out or Instruct or rising_edge_SCK_ipd or
|
|
change_addr_event or oe or current_state_event or Address or
|
|
falling_edge_write or PDONE or rising_edge_WDONE or Instruct_event
|
|
or rising_edge_EDONE or ERSSUSP_out or rising_edge_PoweredUp or
|
|
rising_edge_CSNeg_ipd or rising_edge_RES_out or ERSRES_out or
|
|
PRGSUSP_out or PRGRES_out_event or rising_edge_VLTDONE or
|
|
rising_edge_DP_out)
|
|
|
|
begin: Functionality
|
|
integer i,j;
|
|
|
|
if (rising_edge_read_out)
|
|
begin
|
|
if (PoweredUp == 1'b1)
|
|
->oe_event;
|
|
end
|
|
|
|
if (Instruct_event)
|
|
begin
|
|
read_cnt = 0;
|
|
fast_read = 1'b1;
|
|
dual_read = 1'b0;
|
|
slow_read = 1'b0;
|
|
quad_read = 1'b0;
|
|
sr_read = 1'b0;
|
|
read_id = 1'b0;
|
|
pp_quad = 1'b0;
|
|
if (current_state == IDLE)
|
|
begin
|
|
if (DP_in == 1'b1)
|
|
begin
|
|
$display ("Command results can be corrupted ");
|
|
end
|
|
end
|
|
end
|
|
|
|
if (rising_edge_PoweredUp)
|
|
begin
|
|
Status_reg1[1] = 1'b0; // WEL bit
|
|
Status_reg1[0] = 1'b0; // BUSY bit
|
|
|
|
Status_reg2[7] = 1'b0; // SUS bit
|
|
end
|
|
|
|
if (change_addr_event)
|
|
begin
|
|
read_addr = Address;
|
|
end
|
|
|
|
if (rising_edge_RES_out)
|
|
begin
|
|
if(RES_out)
|
|
begin
|
|
RES_in = 1'b0;
|
|
end
|
|
end
|
|
|
|
case (current_state)
|
|
IDLE :
|
|
begin
|
|
fast_read = 1'b1;
|
|
dual_read = 1'b0;
|
|
slow_read = 1'b0;
|
|
quad_read = 1'b0;
|
|
sr_read = 1'b0;
|
|
res_flag = 1'b0;
|
|
pg_screg_flag = 1'b0;
|
|
ers_screg_flag = 1'b0;
|
|
if (falling_edge_write && ~DP_in)
|
|
begin
|
|
read_cnt = 0;
|
|
if (Instruct == WREN)
|
|
Status_reg1[1] = 1'b1;
|
|
else if (Instruct == WRDI)
|
|
Status_reg1[1] = 1'b0;
|
|
else if (Instruct == WRR)
|
|
begin
|
|
if(~SRP1 && (~SRP0 || (SRP0 && WPNeg)))
|
|
begin
|
|
if (WEL && ~wren_vlt_flag)
|
|
begin
|
|
WSTART = 1'b1;
|
|
WSTART <= #5 1'b0;
|
|
Status_reg1[0] = 1'b1;
|
|
end
|
|
else if (~WEL && wren_vlt_flag)
|
|
begin
|
|
VLTSTART = 1'b1;
|
|
VLTSTART <= #5 1'b0;
|
|
end
|
|
end
|
|
else
|
|
Status_reg1[1] = 1'b0;
|
|
end
|
|
else if ((Instruct == PP || (Instruct == QPP && QE))
|
|
&& WEL && PDONE)
|
|
begin
|
|
sect = Address / 16'h1000;
|
|
if (Sec_Prot[sect] == 0)
|
|
begin
|
|
PSTART = 1'b1;
|
|
PSTART <= #5 1'b0;
|
|
PGSUSP = 1'b0;
|
|
PGRES = 1'b0;
|
|
Status_reg1[0] = 1'b1;
|
|
SA = sect;
|
|
Addr = Address;
|
|
Addr_tmp= Address;
|
|
wr_cnt = Byte_number;
|
|
for (i=wr_cnt;i>=0;i=i-1)
|
|
begin
|
|
if (Viol != 0)
|
|
WData[i] = -1;
|
|
else
|
|
WData[i] = WByte[i];
|
|
end
|
|
end
|
|
else
|
|
Status_reg1[1] = 1'b0;
|
|
end
|
|
else if (Instruct == PG_SCREG && WEL)
|
|
begin
|
|
sect = Address / 16'h1000;
|
|
if ((sect <= 3) && LB[sect-1]==0)
|
|
begin
|
|
PSTART = 1'b1;
|
|
PSTART <= #5 1'b0;
|
|
PGSUSP = 1'b0;
|
|
PGRES = 1'b0;
|
|
Status_reg1[0] = 1'b1;
|
|
SA = sect;
|
|
wr_cnt = Byte_number;
|
|
Addr_screg = Address % 16'h1000;
|
|
pg_screg_flag = 1'b1;
|
|
for (i=wr_cnt;i>=0;i=i-1)
|
|
begin
|
|
if (Viol != 0)
|
|
WData[i] = -1;
|
|
else
|
|
WData[i] = WByte[i];
|
|
end
|
|
end
|
|
else
|
|
begin
|
|
Status_reg1[1] = 1'b0;
|
|
end
|
|
end
|
|
else if ((Instruct == SE || Instruct == BE_32 ||
|
|
Instruct == BE_64) && WEL)
|
|
begin
|
|
sect = Address / 16'h1000;
|
|
if (Sec_Prot[sect] == 0)
|
|
begin
|
|
ESTART = 1'b1;
|
|
ESTART <= #5 1'b0;
|
|
ESUSP = 1'b0;
|
|
ERES = 1'b0;
|
|
Status_reg1[0] = 1'b1;
|
|
Addr_ers = Address;
|
|
end
|
|
else
|
|
Status_reg1[1] = 1'b0;
|
|
end
|
|
else if (Instruct == CE && WEL)
|
|
begin
|
|
// if ((~CMP && ~BP2 && ~BP1 && ~BP0) ||
|
|
// (CMP && BP2 && BP1 && BP0))
|
|
if (Sec_Prot == 0)
|
|
begin
|
|
ESTART = 1'b1;
|
|
ESTART <= #5 1'b0;
|
|
ESUSP = 1'b0;
|
|
ERES = 1'b0;
|
|
Status_reg1[0] = 1'b1;
|
|
end
|
|
else
|
|
Status_reg1[1] = 1'b0;
|
|
end
|
|
else if (Instruct == ERS_SCREG && WEL)
|
|
begin
|
|
sect = Address / 16'h1000;
|
|
if ((sect <= 3) && LB[sect-1]==0)
|
|
begin
|
|
ESTART = 1'b1;
|
|
ESTART <= #5 1'b0;
|
|
ESUSP = 1'b0;
|
|
ERES = 1'b0;
|
|
Status_reg1[0] = 1'b1;
|
|
SA = sect;
|
|
ers_screg_flag = 1'b1;
|
|
end
|
|
else
|
|
Status_reg1[1] = 1'b0;
|
|
end
|
|
else if (Instruct == DP)
|
|
begin
|
|
RES_in <= 1'b0;
|
|
DP_in <= 1'b1;
|
|
end
|
|
end // end of falling_edge_write
|
|
else if (oe && ~DP_in)
|
|
begin
|
|
if (Instruct == RDSR)
|
|
begin //Read Status Register
|
|
sr_read = 1'b1;
|
|
SOut_zd = Status_reg1[7-read_cnt];
|
|
read_cnt = read_cnt + 1;
|
|
if (read_cnt == 8)
|
|
read_cnt = 0;
|
|
end
|
|
else if (Instruct == RDSR2)
|
|
begin
|
|
sr_read = 1'b1;
|
|
SOut_zd = Status_reg2[7-read_cnt];
|
|
read_cnt = read_cnt + 1;
|
|
if (read_cnt == 8)
|
|
read_cnt = 0;
|
|
end
|
|
else if (Instruct == READ || Instruct == FAST_READ)
|
|
begin
|
|
if (Instruct == READ)
|
|
begin
|
|
fast_read = 1'b0;
|
|
dual_read = 1'b0;
|
|
slow_read = 1'b1;
|
|
quad_read = 1'b0;
|
|
sr_read = 1'b0;
|
|
end
|
|
else
|
|
begin
|
|
fast_read = 1'b1;
|
|
dual_read = 1'b0;
|
|
slow_read = 1'b0;
|
|
quad_read = 1'b0;
|
|
sr_read = 1'b0;
|
|
end
|
|
if (Mem[read_addr] !== -1)
|
|
begin
|
|
data_out[7:0] = Mem[read_addr];
|
|
SOut_zd = data_out[7-read_cnt];
|
|
end
|
|
else
|
|
begin
|
|
SOut_zd = 8'bx;
|
|
end
|
|
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==FAST_DREAD || Instruct==FAST_DREAD_2)
|
|
begin
|
|
fast_read = 1'b0;
|
|
dual_read = 1'b1;
|
|
slow_read = 1'b0;
|
|
quad_read = 1'b0;
|
|
sr_read = 1'b0;
|
|
data_out[7:0] = Mem[read_addr];
|
|
SOut_zd = data_out[7-2*read_cnt];
|
|
SIOut_zd = data_out[6-2*read_cnt];
|
|
read_cnt = read_cnt + 1;
|
|
if (read_cnt == 4)
|
|
begin
|
|
read_cnt = 0;
|
|
if (read_addr == AddrRANGE)
|
|
read_addr = 0;
|
|
else
|
|
read_addr = read_addr + 1;
|
|
end
|
|
end
|
|
else if ((Instruct==FAST_QREAD || Instruct==FAST_QREAD_4 ||
|
|
Instruct==W_QREAD || Instruct==WOCT_QREAD)
|
|
&& QE)
|
|
begin
|
|
if ((Instruct==W_QREAD && Address[0]) ||
|
|
(Instruct==WOCT_QREAD && ~(Address[3:0] == 4'h0)))
|
|
begin
|
|
read_cnt = read_cnt + 1;
|
|
if (read_cnt == 2)
|
|
begin
|
|
read_cnt = 0;
|
|
$display("Word Read could not execute");
|
|
$display("Wrong Read Address");
|
|
end
|
|
end
|
|
else
|
|
begin
|
|
fast_read = 1'b0;
|
|
dual_read = 1'b0;
|
|
slow_read = 1'b0;
|
|
quad_read = 1'b1;
|
|
sr_read = 1'b0;
|
|
data_out[7:0] = Mem[read_addr];
|
|
HOLDNegOut_zd = data_out[7-4*read_cnt];
|
|
WPNegOut_zd = data_out[6-4*read_cnt];
|
|
SOut_zd = data_out[5-4*read_cnt];
|
|
SIOut_zd = data_out[4-4*read_cnt];
|
|
read_cnt = read_cnt + 1;
|
|
if (read_cnt == 2)
|
|
begin
|
|
read_cnt = 0;
|
|
if (wrap_byte[4]==1'b0 &&
|
|
(Instruct==FAST_QREAD_4 || Instruct==W_QREAD))
|
|
begin
|
|
ADDRHILO_WRAP(AddrLo_wrap,AddrHi_wrap,
|
|
Address,w_size);
|
|
if (read_addr == AddrHi_wrap)
|
|
read_addr = AddrLo_wrap;
|
|
else
|
|
read_addr = read_addr + 1;
|
|
end
|
|
else
|
|
begin
|
|
if (read_addr == AddrRANGE)
|
|
read_addr = 0;
|
|
else
|
|
read_addr = read_addr + 1;
|
|
end
|
|
end
|
|
end
|
|
end
|
|
else if (Instruct==RDID || Instruct==RDID_DUAL ||
|
|
Instruct==RDID_QUAD)
|
|
begin
|
|
if (read_addr % 2 == 0)
|
|
begin
|
|
ident_out2 = {Manuf_ID,Device_ID1};
|
|
end
|
|
else
|
|
begin
|
|
ident_out2 = {Device_ID1,Manuf_ID};
|
|
end
|
|
read_id = 1'b1;
|
|
if (Instruct == RDID)
|
|
begin
|
|
fast_read = 1'b1;
|
|
dual_read = 1'b0;
|
|
slow_read = 1'b0;
|
|
quad_read = 1'b0;
|
|
sr_read = 1'b0;
|
|
DataDriveOut_SO = ident_out2[15-read_cnt];
|
|
read_cnt = read_cnt + 1;
|
|
if (read_cnt == 16)
|
|
read_cnt = 0;
|
|
end
|
|
else if (Instruct == RDID_DUAL)
|
|
begin
|
|
fast_read = 1'b0;
|
|
dual_read = 1'b1;
|
|
slow_read = 1'b0;
|
|
quad_read = 1'b0;
|
|
sr_read = 1'b0;
|
|
DataDriveOut_SO = ident_out2[15-2*read_cnt];
|
|
DataDriveOut_SI = ident_out2[14-2*read_cnt];
|
|
read_cnt = read_cnt + 1;
|
|
if (read_cnt == 8)
|
|
read_cnt = 0;
|
|
end
|
|
else // (Instruct == RDID_QUAD)
|
|
begin
|
|
fast_read = 1'b0;
|
|
dual_read = 1'b0;
|
|
slow_read = 1'b0;
|
|
quad_read = 1'b1;
|
|
sr_read = 1'b0;
|
|
HOLDNegOut_zd = ident_out2[15-4*read_cnt];
|
|
WPNegOut_zd = ident_out2[14-4*read_cnt];
|
|
SOut_zd = ident_out2[13-4*read_cnt];
|
|
SIOut_zd = ident_out2[12-4*read_cnt];
|
|
read_cnt = read_cnt + 1;
|
|
if (read_cnt == 4)
|
|
read_cnt = 0;
|
|
end
|
|
end
|
|
else if (Instruct == RD_UNIQ_ID)
|
|
begin
|
|
// unique ID number is not in data sheet
|
|
read_id = 1'b1;
|
|
DataDriveOut_SO = unique_id[63-read_cnt];
|
|
read_cnt = read_cnt + 1;
|
|
if (read_cnt == 64)
|
|
read_cnt = 0;
|
|
end
|
|
else if (Instruct == RDIDJ)
|
|
begin
|
|
read_id = 1'b1;
|
|
ident_out = {Manuf_ID,Device_ID2,Device_ID3};
|
|
DataDriveOut_SO = ident_out[23-read_cnt];
|
|
read_cnt = read_cnt + 1;
|
|
if (read_cnt == 24)
|
|
read_cnt = 0;
|
|
end
|
|
else if (Instruct == RD_SFDP)
|
|
begin
|
|
sfdp_addr = read_addr / 12'h100;
|
|
if (sfdp_addr == 0)
|
|
begin
|
|
Addr_tmp_2 = (read_addr % 12'h100);
|
|
data_out[7:0] = SFDP_array[Addr_tmp_2];
|
|
SOut_zd = data_out[7-read_cnt];
|
|
read_cnt = read_cnt + 1;
|
|
if (read_cnt == 8)
|
|
begin
|
|
read_cnt = 0;
|
|
if (read_addr == SFDP_HiAddr)
|
|
read_addr = 0;
|
|
else
|
|
read_addr = read_addr + 1;
|
|
end
|
|
end
|
|
else
|
|
begin
|
|
read_cnt = read_cnt + 1;
|
|
if (read_cnt == 8)
|
|
begin
|
|
read_cnt = 0;
|
|
$display("Given SFDP address is out of range");
|
|
end
|
|
end
|
|
end
|
|
else if (Instruct == RD_SCREG)
|
|
begin
|
|
Addr_tmp_2 = read_addr / 12'h100;
|
|
Addr_tmp_3 = read_addr % 12'h100;
|
|
if (Addr_tmp_2 == 16)
|
|
begin
|
|
// Security Register No.1
|
|
data_out[7:0] = Security_Reg1[Addr_tmp_3];
|
|
SOut_zd = data_out[7-read_cnt];
|
|
read_cnt = read_cnt + 1;
|
|
end
|
|
else if (Addr_tmp_2 == 32)
|
|
begin
|
|
// Security Register No.2
|
|
data_out[7:0] = Security_Reg2[Addr_tmp_3];
|
|
SOut_zd = data_out[7-read_cnt];
|
|
read_cnt = read_cnt + 1;
|
|
end
|
|
else if (Addr_tmp_2 == 48)
|
|
// Security Register No.2
|
|
begin
|
|
data_out[7:0] = Security_Reg3[Addr_tmp_3];
|
|
SOut_zd = data_out[7-read_cnt];
|
|
read_cnt = read_cnt + 1;
|
|
end
|
|
else
|
|
begin
|
|
read_cnt = read_cnt + 1;
|
|
if (read_cnt == 8)
|
|
begin
|
|
read_cnt = 0;
|
|
$display("Given Security Register Read ");
|
|
$display("address is out of range ");
|
|
end
|
|
end
|
|
if (read_cnt == 8)
|
|
begin
|
|
read_cnt = 0;
|
|
if (read_addr % 256 == SecReg_HiAddr)
|
|
read_addr = (read_addr/256)*(SecReg_HiAddr+1);
|
|
else
|
|
read_addr = read_addr + 1;
|
|
end
|
|
end
|
|
else if (Instruct == RES_RD_ID)
|
|
begin
|
|
read_id = 1'b1;
|
|
data_out[7:0] = Device_ID1;
|
|
DataDriveOut_SO = data_out[7-read_cnt];
|
|
read_cnt = read_cnt + 1;
|
|
if (read_cnt == 8)
|
|
read_cnt = 0;
|
|
end
|
|
end // end of oe
|
|
else if (rising_edge_DP_out)
|
|
DP_in = 1'b0;
|
|
end // end of IDLE state
|
|
|
|
WRITE_SR:
|
|
begin
|
|
if (WDONE)
|
|
begin
|
|
Status_reg1[0] = 1'b0;
|
|
Status_reg1[1] = 1'b0;
|
|
|
|
Status_reg1[7:2] = Status_reg1_in[7:2];
|
|
Status_reg2[6] = Status_reg2_in[6];
|
|
Status_reg2[1] = Status_reg2_in[1];
|
|
// SRP1 bit will only change value from '0' to '1'
|
|
// if SRP1 is '1' than Status Register is protected
|
|
//and is not possible to write it
|
|
Status_reg2[0] = Status_reg2_in[0];
|
|
for(i=5;i>=3;i=i-1)
|
|
begin
|
|
if (Status_reg2[i] == 1'b0)
|
|
Status_reg2[i] = Status_reg2_in[i];
|
|
else
|
|
begin
|
|
$display("LB bit is set to '1'");
|
|
$display("No change allowed");
|
|
end
|
|
end
|
|
change_prot_bits = 1'b1;
|
|
#1000 change_prot_bits = 1'b0;
|
|
end // end of WDONE
|
|
|
|
if (oe)
|
|
begin
|
|
if (Instruct == RDSR)
|
|
begin
|
|
//Read Status Register 1
|
|
sr_read = 1'b1;
|
|
SOut_zd = Status_reg1[7-read_cnt];
|
|
read_cnt = read_cnt + 1;
|
|
if (read_cnt == 8)
|
|
read_cnt = 0;
|
|
end
|
|
end // end of oe
|
|
end // end of WRITE_SR
|
|
|
|
WRITE_SR_V:
|
|
begin
|
|
if (VLTDONE)
|
|
begin
|
|
Status_reg1[7:2] = Status_reg1_in[7:2];
|
|
Status_reg2[6] = Status_reg2_in[6];
|
|
Status_reg2[1] = Status_reg2_in[1];
|
|
// SRP1 bit will only change value from '0' to '1'
|
|
// if SRP1 is '1' than Status Register is protected
|
|
//and is not possible to write it
|
|
Status_reg2[0] = Status_reg2_in[0];
|
|
for(i=5;i>=3;i=i-1)
|
|
begin
|
|
if (Status_reg2[i] == 1'b0)
|
|
Status_reg2[i] = Status_reg2_in[i];
|
|
else
|
|
begin
|
|
$display("LB bit is set to '1'");
|
|
$display("No change allowed");
|
|
end
|
|
end
|
|
change_prot_bits = 1'b1;
|
|
#1000 change_prot_bits = 1'b0;
|
|
wren_vlt_flag = 1'b0;
|
|
end
|
|
end
|
|
|
|
PAGE_PG,
|
|
ERS_SUSP_PG:
|
|
begin
|
|
if (current_state_event && ~PDONE)
|
|
begin
|
|
if (Instruct !== PG_SCREG)
|
|
begin
|
|
ADDRHILO_PG(AddrLo, AddrHi, Addr);
|
|
end
|
|
cnt = 0;
|
|
|
|
for (i=0;i<=wr_cnt;i=i+1)
|
|
begin
|
|
new_int = WData[i];
|
|
if (Instruct == PG_SCREG)
|
|
begin
|
|
if (sect == 1)
|
|
old_int = Security_Reg1[Addr_screg + i - cnt];
|
|
else if (sect == 2)
|
|
old_int = Security_Reg2[Addr_screg + i - cnt];
|
|
else
|
|
old_int = Security_Reg3[Addr_screg + i - cnt];
|
|
end
|
|
else
|
|
begin
|
|
old_int = Mem[Addr + i - cnt];
|
|
end
|
|
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)
|
|
begin
|
|
if (~old_bit[j])
|
|
new_bit[j]=1'b0;
|
|
end
|
|
new_int=new_bit;
|
|
end
|
|
WData[i]= new_int;
|
|
end
|
|
else
|
|
begin
|
|
WData[i] = -1;
|
|
end
|
|
if (Instruct == PG_SCREG)
|
|
begin
|
|
if (sect == 1)
|
|
Security_Reg1[Addr_screg + i - cnt] = - 1;
|
|
else if (sect == 2)
|
|
Security_Reg2[Addr_screg + i - cnt] = - 1;
|
|
else
|
|
Security_Reg3[Addr_screg + i - cnt] = - 1;
|
|
end
|
|
else
|
|
Mem[Addr + i - cnt] = - 1;
|
|
if ((Addr + i) == AddrHi)
|
|
begin
|
|
|
|
Addr = AddrLo;
|
|
cnt = i + 1;
|
|
end
|
|
end
|
|
cnt = 0;
|
|
end // end of current_state_event
|
|
|
|
if (PDONE)
|
|
begin
|
|
if (current_state !== ERS_SUSP_PG)
|
|
begin
|
|
Status_reg1[0] = 1'b0;
|
|
end
|
|
Status_reg1[1] = 1'b0;
|
|
for (i=0;i<=wr_cnt;i=i+1)
|
|
begin
|
|
if (pg_screg_flag )
|
|
begin
|
|
if (sect == 1)
|
|
Security_Reg1[Addr_screg + i - cnt] = WData[i];
|
|
else if (sect == 2)
|
|
Security_Reg2[Addr_screg + i - cnt] = WData[i];
|
|
else
|
|
Security_Reg3[Addr_screg + i - cnt] = WData[i];
|
|
|
|
if ((Addr_screg + i) == SecReg_HiAddr)
|
|
begin
|
|
Addr_screg = SecReg_LoAddr;
|
|
cnt = i + 1;
|
|
end
|
|
end
|
|
else
|
|
begin
|
|
Mem[Addr_tmp + i - cnt] = WData[i];
|
|
if ((Addr_tmp + i) == AddrHi)
|
|
begin
|
|
Addr_tmp = AddrLo;
|
|
cnt = i + 1;
|
|
end
|
|
end
|
|
end
|
|
end // end of PDONE
|
|
|
|
if (Instruct == ERS_PG_SUSP && current_state == PAGE_PG && ~susp_flag)
|
|
begin
|
|
PGSUSP = 1'b1;
|
|
PGSUSP <= #1000 1'b0;
|
|
PRGSUSP_in = 1'b1;
|
|
end
|
|
|
|
if (oe)
|
|
begin
|
|
if (Instruct == RDSR)
|
|
begin
|
|
//Read Status Register 1
|
|
sr_read = 1'b1;
|
|
SOut_zd = Status_reg1[7-read_cnt];
|
|
read_cnt = read_cnt + 1;
|
|
if (read_cnt == 8)
|
|
read_cnt = 0;
|
|
end
|
|
end
|
|
end // end of PAGE_PG
|
|
|
|
PG_SUSP:
|
|
begin
|
|
fast_read = 1'b1;
|
|
dual_read = 1'b0;
|
|
slow_read = 1'b0;
|
|
quad_read = 1'b0;
|
|
sr_read = 1'b0;
|
|
if (PRGSUSP_out == 1 && ~(Instruct == ERS_PG_RES))
|
|
begin
|
|
PRGSUSP_in = 1'b0;
|
|
//The BUSY bit in the Status Register will indicate that
|
|
//the device is ready for another operation.
|
|
Status_reg1[0] = 1'b0;
|
|
//The Suspend (SUS) bit in the Status Register2 will
|
|
//be set to the logical “1” state to indicate that the
|
|
//program operation has been suspended.
|
|
Status_reg2[7] = 1'b1;
|
|
end
|
|
if (PRGRES_out_event && PRGRES_out == 1)
|
|
begin
|
|
PRGRES_in = 1'b0;
|
|
Status_reg1[0] = 1'b1;
|
|
end
|
|
if (SUS)
|
|
begin
|
|
if (falling_edge_write)
|
|
begin
|
|
if (Instruct == ERS_PG_RES)
|
|
begin
|
|
Status_reg2[7] = 1'b0;
|
|
PRGRES_in = 1'b1;
|
|
PGRES = 1'b1;
|
|
PGRES <= #1000 1'b0;
|
|
end
|
|
else if ((Instruct == SE || Instruct == BE_32 ||
|
|
Instruct == BE_64) && WEL)
|
|
begin
|
|
sect = Address / 16'h1000;
|
|
if (sect !== sect_tmp_pg && Sec_Prot[sect] == 0)
|
|
begin
|
|
ESTART = 1'b1;
|
|
ESTART <= #5 1'b0;
|
|
ESUSP = 1'b0;
|
|
ERES = 1'b0;
|
|
Status_reg1[0] = 1'b1;
|
|
Addr_ers = Address;
|
|
end
|
|
else
|
|
begin
|
|
Status_reg1[0] = 1'b0;
|
|
$display("Can't erase sector/block");
|
|
$display("Block is protected or suspended");
|
|
end
|
|
end
|
|
end
|
|
else if (oe)
|
|
begin
|
|
if (Instruct == RDSR)
|
|
begin
|
|
//Read Status Register 1
|
|
sr_read = 1'b1;
|
|
SOut_zd = Status_reg1[7-read_cnt];
|
|
read_cnt = read_cnt + 1;
|
|
if (read_cnt == 8)
|
|
read_cnt = 0;
|
|
end
|
|
else if (Instruct == RDSR2)
|
|
begin
|
|
//Read Status Register 2
|
|
sr_read = 1'b1;
|
|
SOut_zd = Status_reg2[7-read_cnt];
|
|
read_cnt = read_cnt + 1;
|
|
if (read_cnt == 8)
|
|
read_cnt = 0;
|
|
end
|
|
else if (Instruct == READ || Instruct == FAST_READ)
|
|
begin
|
|
if (sect_tmp_pg !== read_addr / 16'h1000)
|
|
begin
|
|
if (Instruct == READ)
|
|
begin
|
|
fast_read = 1'b0;
|
|
dual_read = 1'b0;
|
|
slow_read = 1'b1;
|
|
quad_read = 1'b0;
|
|
sr_read = 1'b0;
|
|
end
|
|
else
|
|
begin
|
|
fast_read = 1'b1;
|
|
dual_read = 1'b0;
|
|
slow_read = 1'b0;
|
|
quad_read = 1'b0;
|
|
sr_read = 1'b0;
|
|
end
|
|
if (Mem[read_addr] !== -1)
|
|
begin
|
|
data_out[7:0] = Mem[read_addr];
|
|
SOut_zd = data_out[7-read_cnt];
|
|
end
|
|
else
|
|
begin
|
|
SOut_zd = 8'bx;
|
|
end
|
|
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
|
|
begin
|
|
read_cnt = read_cnt + 1;
|
|
if (read_cnt == 8)
|
|
begin
|
|
$display("Can't read suspended sector");
|
|
read_cnt = 0;
|
|
end
|
|
end
|
|
end
|
|
else if (Instruct==FAST_DREAD ||
|
|
Instruct==FAST_DREAD_2)
|
|
begin
|
|
if (sect_tmp_pg !== read_addr / 16'h1000)
|
|
begin
|
|
fast_read = 1'b0;
|
|
dual_read = 1'b1;
|
|
slow_read = 1'b0;
|
|
quad_read = 1'b0;
|
|
sr_read = 1'b0;
|
|
if (Mem[read_addr] !== -1)
|
|
begin
|
|
data_out[7:0] = Mem[read_addr];
|
|
SOut_zd = data_out[7-2*read_cnt];
|
|
SIOut_zd = data_out[6-2*read_cnt];
|
|
end
|
|
else
|
|
begin
|
|
SOut_zd = 1'bx;
|
|
SIOut_zd = 1'bx;
|
|
end
|
|
read_cnt = read_cnt + 1;
|
|
if (read_cnt == 4)
|
|
begin
|
|
read_cnt = 0;
|
|
if (read_addr == AddrRANGE)
|
|
read_addr = 0;
|
|
else
|
|
read_addr = read_addr + 1;
|
|
end
|
|
end
|
|
else
|
|
begin
|
|
read_cnt = read_cnt + 1;
|
|
if (read_cnt == 4)
|
|
begin
|
|
$display("Can't read suspended sector");
|
|
read_cnt = 0;
|
|
end
|
|
end
|
|
end
|
|
else if ((Instruct==FAST_QREAD || Instruct==W_QREAD
|
|
|| Instruct==FAST_QREAD_4 || Instruct==WOCT_QREAD)
|
|
&& QE)
|
|
begin
|
|
if (sect_tmp_pg !== read_addr / 16'h1000)
|
|
begin
|
|
if ((Instruct==W_QREAD && Address[0]) ||
|
|
(Instruct==WOCT_QREAD &&
|
|
~(Address[3:0] == 4'h0)))
|
|
begin
|
|
read_cnt = read_cnt + 1;
|
|
if (read_cnt == 2)
|
|
begin
|
|
read_cnt = 0;
|
|
$display("Word Read can't execute");
|
|
$display("Wrong Read Address");
|
|
end
|
|
end
|
|
else
|
|
begin
|
|
fast_read = 1'b0;
|
|
dual_read = 1'b0;
|
|
slow_read = 1'b0;
|
|
quad_read = 1'b1;
|
|
sr_read = 1'b0;
|
|
data_out[7:0] = Mem[read_addr];
|
|
HOLDNegOut_zd = data_out[7-4*read_cnt];
|
|
WPNegOut_zd = data_out[6-4*read_cnt];
|
|
SOut_zd = data_out[5-4*read_cnt];
|
|
SIOut_zd = data_out[4-4*read_cnt];
|
|
read_cnt = read_cnt + 1;
|
|
if (read_cnt == 2)
|
|
begin
|
|
read_cnt = 0;
|
|
if (wrap_byte[4]==0 &&
|
|
(Instruct==FAST_QREAD_4 ||
|
|
Instruct==W_QREAD))
|
|
begin
|
|
ADDRHILO_WRAP(AddrLo_wrap,
|
|
AddrHi_wrap, Address,w_size);
|
|
if (read_addr == AddrHi_wrap)
|
|
read_addr = AddrLo_wrap;
|
|
else
|
|
read_addr = read_addr + 1;
|
|
end
|
|
else
|
|
begin
|
|
if (read_addr == AddrRANGE)
|
|
read_addr = 0;
|
|
else
|
|
read_addr = read_addr + 1;
|
|
end
|
|
end
|
|
end
|
|
end
|
|
else
|
|
begin
|
|
read_cnt = read_cnt + 1;
|
|
if (read_cnt == 2)
|
|
begin
|
|
$display("Can't read suspended sector");
|
|
read_cnt = 0;
|
|
end
|
|
end
|
|
end
|
|
else if (Instruct==RDID || Instruct==RDID_DUAL ||
|
|
Instruct==RDID_QUAD)
|
|
begin
|
|
if (read_addr % 2 == 0)
|
|
begin
|
|
ident_out2 = {Manuf_ID,Device_ID1};
|
|
end
|
|
else
|
|
begin
|
|
ident_out2 = {Device_ID1,Manuf_ID};
|
|
end
|
|
read_id = 1'b1;
|
|
if (Instruct == RDID)
|
|
begin
|
|
fast_read = 1'b1;
|
|
dual_read = 1'b0;
|
|
slow_read = 1'b0;
|
|
quad_read = 1'b0;
|
|
sr_read = 1'b0;
|
|
DataDriveOut_SO = ident_out2[15-read_cnt];
|
|
read_cnt = read_cnt + 1;
|
|
if (read_cnt == 16)
|
|
read_cnt = 0;
|
|
end
|
|
else if (Instruct == RDID_DUAL)
|
|
begin
|
|
fast_read = 1'b0;
|
|
dual_read = 1'b1;
|
|
slow_read = 1'b0;
|
|
quad_read = 1'b0;
|
|
sr_read = 1'b0;
|
|
DataDriveOut_SO = ident_out2[15-2*read_cnt];
|
|
DataDriveOut_SI = ident_out2[14-2*read_cnt];
|
|
read_cnt = read_cnt + 1;
|
|
if (read_cnt == 8)
|
|
read_cnt = 0;
|
|
end
|
|
else // (Instruct == RDID_QUAD)
|
|
begin
|
|
fast_read = 1'b0;
|
|
dual_read = 1'b0;
|
|
slow_read = 1'b0;
|
|
quad_read = 1'b1;
|
|
sr_read = 1'b0;
|
|
HOLDNegOut_zd = ident_out2[15-4*read_cnt];
|
|
WPNegOut_zd = ident_out2[14-4*read_cnt];
|
|
SOut_zd = ident_out2[13-4*read_cnt];
|
|
SIOut_zd = ident_out2[12-4*read_cnt];
|
|
read_cnt = read_cnt + 1;
|
|
if (read_cnt == 4)
|
|
read_cnt = 0;
|
|
end
|
|
end
|
|
else if (Instruct == RD_UNIQ_ID)
|
|
begin
|
|
// unique ID number is not in data sheet
|
|
read_id = 1'b1;
|
|
DataDriveOut_SO = unique_id[63-read_cnt];
|
|
read_cnt = read_cnt + 1;
|
|
if (read_cnt == 64)
|
|
read_cnt = 0;
|
|
end
|
|
else if (Instruct == RDIDJ)
|
|
begin
|
|
read_id = 1'b1;
|
|
ident_out = {Manuf_ID,Device_ID2,Device_ID3};
|
|
DataDriveOut_SO = ident_out[23-read_cnt];
|
|
read_cnt = read_cnt + 1;
|
|
if (read_cnt == 24)
|
|
read_cnt = 0;
|
|
end
|
|
else if (Instruct == RD_SFDP)
|
|
begin
|
|
sfdp_addr = read_addr / 12'h100;
|
|
if (sfdp_addr == 0)
|
|
begin
|
|
Addr_tmp_2 = (read_addr % 12'h100);
|
|
data_out[7:0] = SFDP_array[Addr_tmp_2];
|
|
SOut_zd = data_out[7-read_cnt];
|
|
read_cnt = read_cnt + 1;
|
|
if (read_cnt == 8)
|
|
begin
|
|
read_cnt = 0;
|
|
if (read_addr == SFDP_HiAddr)
|
|
read_addr = 0;
|
|
else
|
|
read_addr = read_addr + 1;
|
|
end
|
|
end
|
|
else
|
|
begin
|
|
read_cnt = read_cnt + 1;
|
|
if (read_cnt == 8)
|
|
begin
|
|
read_cnt = 0;
|
|
$display("SFDP address is out of range");
|
|
end
|
|
end
|
|
end
|
|
else if (Instruct == RD_SCREG)
|
|
begin
|
|
Addr_tmp_2 = read_addr / 12'h100;
|
|
Addr_tmp_3 = read_addr % 12'h100;
|
|
if (Addr_tmp_2 == 16)
|
|
begin
|
|
// Security Register No.1
|
|
data_out[7:0] = Security_Reg1[Addr_tmp_3];
|
|
SOut_zd = data_out[7-read_cnt];
|
|
read_cnt = read_cnt + 1;
|
|
end
|
|
else if (Addr_tmp_2 == 32)
|
|
begin
|
|
// Security Register No.2
|
|
data_out[7:0] = Security_Reg2[Addr_tmp_3];
|
|
SOut_zd = data_out[7-read_cnt];
|
|
read_cnt = read_cnt + 1;
|
|
end
|
|
else if (Addr_tmp_2 == 48)
|
|
// Security Register No.2
|
|
begin
|
|
data_out[7:0] = Security_Reg3[Addr_tmp_3];
|
|
SOut_zd = data_out[7-read_cnt];
|
|
read_cnt = read_cnt + 1;
|
|
end
|
|
else
|
|
begin
|
|
read_cnt = read_cnt + 1;
|
|
if (read_cnt == 8)
|
|
begin
|
|
read_cnt = 0;
|
|
$display("Given Security Register Read ");
|
|
$display("address is out of range ");
|
|
end
|
|
end
|
|
if (read_cnt == 8)
|
|
begin
|
|
read_cnt = 0;
|
|
if (read_addr % 256 == SecReg_HiAddr)
|
|
read_addr=(read_addr/256)*
|
|
(SecReg_HiAddr+1);
|
|
else
|
|
read_addr = read_addr + 1;
|
|
end
|
|
end
|
|
end // end of 'oe'
|
|
end
|
|
end // end of PG_SUSP
|
|
|
|
SECTOR_ERS,
|
|
PG_SUSP_ERS:
|
|
begin
|
|
if (current_state_event && ~EDONE)
|
|
begin
|
|
if (Instruct == SE)
|
|
ADDRHILO_SEC4(AddrLo_ers, AddrHi_ers, Addr_ers);
|
|
else if (Instruct == BE_32)
|
|
ADDRHILO_SEC32(AddrLo_ers, AddrHi_ers, Addr_ers);
|
|
else if (Instruct == BE_64)
|
|
begin
|
|
ADDRHILO_SEC64(AddrLo_ers, AddrHi_ers, Addr_ers);
|
|
end
|
|
if (Instruct !== ERS_SCREG)
|
|
begin
|
|
for (i=AddrLo_ers;i<=AddrHi_ers;i=i+1)
|
|
begin
|
|
Mem[i] = -1;
|
|
end
|
|
end
|
|
else
|
|
begin
|
|
if (sect == 1)
|
|
begin
|
|
for(i=SecReg_LoAddr;i<=SecReg_HiAddr;i=i+1)
|
|
begin
|
|
Security_Reg1[i] = -1;
|
|
end
|
|
end
|
|
else if (sect == 2)
|
|
begin
|
|
for(i=SecReg_LoAddr;i<=SecReg_HiAddr;i=i+1)
|
|
begin
|
|
Security_Reg2[i] = -1;
|
|
end
|
|
end
|
|
else
|
|
begin
|
|
for(i=SecReg_LoAddr;i<=SecReg_HiAddr;i=i+1)
|
|
begin
|
|
Security_Reg3[i] = -1;
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
if (EDONE == 1)
|
|
begin
|
|
if (current_state !== PG_SUSP_ERS)
|
|
begin
|
|
Status_reg1[0] = 1'b0;
|
|
end
|
|
Status_reg1[1] = 1'b0;
|
|
if (ers_screg_flag )
|
|
begin
|
|
if (sect == 1)
|
|
begin
|
|
for(i=SecReg_LoAddr;i<=SecReg_HiAddr;i=i+1)
|
|
begin
|
|
Security_Reg1[i] = MaxData;
|
|
end
|
|
end
|
|
else if (sect == 2)
|
|
for(i=SecReg_LoAddr;i<=SecReg_HiAddr;i=i+1)
|
|
begin
|
|
Security_Reg2[i] = MaxData;
|
|
end
|
|
else
|
|
for(i=SecReg_LoAddr;i<=SecReg_HiAddr;i=i+1)
|
|
begin
|
|
Security_Reg3[i] = MaxData;
|
|
end
|
|
|
|
end
|
|
else
|
|
begin
|
|
for (i=AddrLo_ers;i<=AddrHi_ers;i=i+1)
|
|
begin
|
|
Mem[i] = MaxData;
|
|
end
|
|
end
|
|
end
|
|
|
|
if (Instruct == ERS_PG_SUSP && current_state == SECTOR_ERS)
|
|
begin
|
|
ESUSP = 1'b1;
|
|
ESUSP <= #1000 1'b0;
|
|
ERSSUSP_in = 1'b1;
|
|
end
|
|
if (oe)
|
|
begin
|
|
if (Instruct == RDSR)
|
|
begin
|
|
//Read Status Register 1
|
|
sr_read = 1'b1;
|
|
SOut_zd = Status_reg1[7-read_cnt];
|
|
read_cnt = read_cnt + 1;
|
|
if (read_cnt == 8)
|
|
read_cnt = 0;
|
|
end
|
|
end
|
|
end // end of SECTOR_ERS
|
|
|
|
BULK_ERS:
|
|
begin
|
|
if (current_state_event && ~EDONE)
|
|
begin
|
|
for (i=0;i<=AddrRANGE;i=i+1)
|
|
begin
|
|
Mem[i] = -1;
|
|
end
|
|
end
|
|
if (EDONE == 1)
|
|
begin
|
|
Status_reg1[0] = 1'b0;
|
|
Status_reg1[1] = 1'b0;
|
|
for (i=0;i<=AddrRANGE;i=i+1)
|
|
begin
|
|
Mem[i] = MaxData;
|
|
end
|
|
end
|
|
if (oe)
|
|
begin
|
|
if (Instruct == RDSR)
|
|
begin
|
|
//Read Status Register 1
|
|
sr_read = 1'b1;
|
|
SOut_zd = Status_reg1[7-read_cnt];
|
|
read_cnt = read_cnt + 1;
|
|
if (read_cnt == 8)
|
|
read_cnt = 0;
|
|
end
|
|
end
|
|
end // end of BULK_ERS
|
|
|
|
ERS_SUSP:
|
|
begin
|
|
fast_read = 1'b1;
|
|
dual_read = 1'b0;
|
|
slow_read = 1'b0;
|
|
quad_read = 1'b0;
|
|
sr_read = 1'b0;
|
|
if (ERSSUSP_out == 1 && ~(Instruct == ERS_PG_RES))
|
|
begin
|
|
ERSSUSP_in = 1'b0;
|
|
//The BUSY bit in the Status Register will indicate that
|
|
//the device is ready for another operation.
|
|
Status_reg1[0] = 1'b0;
|
|
//The Suspend (SUS) bit in the Status Register2 will
|
|
//be set to the logical “1” state to indicate that the
|
|
//program operation has been suspended.
|
|
Status_reg2[7] = 1'b1;
|
|
end
|
|
if (ERSRES_out_event && ERSRES_out == 1)
|
|
begin
|
|
ERSRES_in = 1'b0;
|
|
Status_reg1[0] = 1'b1;
|
|
end
|
|
if (SUS)
|
|
begin
|
|
if (falling_edge_write)
|
|
begin
|
|
if (Instruct == ERS_PG_RES)
|
|
begin
|
|
Status_reg2[7] = 1'b0;
|
|
ERSRES_in = 1'b1;
|
|
ERES = 1'b1;
|
|
ERES <= #1000 1'b0;
|
|
end
|
|
else if ((Instruct == PP || (Instruct==QPP && QE))
|
|
&& WEL)
|
|
begin
|
|
sect = Address / 16'h1000;
|
|
if (sect !== sect_tmp_ers && Sec_Prot[sect]==0)
|
|
begin
|
|
PSTART = 1'b1;
|
|
PSTART <= #5 1'b0;
|
|
PGSUSP = 1'b0;
|
|
PGRES = 1'b0;
|
|
Status_reg1[0] = 1'b1;
|
|
SA = sect;
|
|
Addr = Address;
|
|
Addr_tmp= Address;
|
|
wr_cnt = Byte_number;
|
|
for (i=wr_cnt;i>=0;i=i-1)
|
|
begin
|
|
if (Viol != 0)
|
|
WData[i] = -1;
|
|
else
|
|
WData[i] = WByte[i];
|
|
end
|
|
end
|
|
else
|
|
begin
|
|
Status_reg1[0] = 1'b0;
|
|
$display("Can't program sector/block");
|
|
$display("Block is protected or suspended");
|
|
end
|
|
end
|
|
else if (Instruct == PG_SCREG)
|
|
begin
|
|
sect = Address / 16'h1000;
|
|
if ((sect <= 3 && sect >=1) && LB[sect-1]==0)
|
|
begin
|
|
PSTART = 1'b1;
|
|
PSTART <= #5 1'b0;
|
|
PGSUSP = 1'b0;
|
|
PGRES = 1'b0;
|
|
Status_reg1[0] = 1'b1;
|
|
SA = sect;
|
|
wr_cnt = Byte_number;
|
|
Addr_screg = Address % 16'h1000;
|
|
pg_screg_flag = 1'b1;
|
|
for (i=wr_cnt;i>=0;i=i-1)
|
|
begin
|
|
if (Viol != 0)
|
|
WData[i] = -1;
|
|
else
|
|
WData[i] = WByte[i];
|
|
end
|
|
end
|
|
else
|
|
Status_reg1[1] = 1'b0;
|
|
end
|
|
end
|
|
else if (oe)
|
|
begin
|
|
if (Instruct == RDSR)
|
|
begin
|
|
//Read Status Register 1
|
|
sr_read = 1'b1;
|
|
SOut_zd = Status_reg1[7-read_cnt];
|
|
read_cnt = read_cnt + 1;
|
|
if (read_cnt == 8)
|
|
read_cnt = 0;
|
|
end
|
|
else if (Instruct == RDSR2)
|
|
begin
|
|
//Read Status Register 2
|
|
sr_read = 1'b1;
|
|
SOut_zd = Status_reg2[7-read_cnt];
|
|
read_cnt = read_cnt + 1;
|
|
if (read_cnt == 8)
|
|
read_cnt = 0;
|
|
end
|
|
else if (Instruct == READ || Instruct == FAST_READ)
|
|
begin
|
|
if (sect !== read_addr / 16'h1000)
|
|
begin
|
|
if (Instruct == READ)
|
|
begin
|
|
fast_read = 1'b0;
|
|
dual_read = 1'b0;
|
|
slow_read = 1'b1;
|
|
quad_read = 1'b0;
|
|
sr_read = 1'b0;
|
|
end
|
|
else
|
|
begin
|
|
fast_read = 1'b1;
|
|
dual_read = 1'b0;
|
|
slow_read = 1'b0;
|
|
quad_read = 1'b0;
|
|
sr_read = 1'b0;
|
|
end
|
|
if (Mem[read_addr] !== -1)
|
|
begin
|
|
data_out[7:0] = Mem[read_addr];
|
|
SOut_zd = data_out[7-read_cnt];
|
|
end
|
|
else
|
|
begin
|
|
SOut_zd = 8'bx;
|
|
end
|
|
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
|
|
begin
|
|
read_cnt = read_cnt + 1;
|
|
if (read_cnt == 8)
|
|
begin
|
|
$display("Can't read suspended sector");
|
|
read_cnt = 0;
|
|
end
|
|
end
|
|
end
|
|
else if (Instruct==FAST_DREAD || Instruct==FAST_DREAD_2)
|
|
begin
|
|
if (sect !== read_addr / 16'h1000)
|
|
begin
|
|
fast_read = 1'b0;
|
|
dual_read = 1'b1;
|
|
slow_read = 1'b0;
|
|
quad_read = 1'b0;
|
|
sr_read = 1'b0;
|
|
if (Mem[read_addr] !== -1)
|
|
begin
|
|
data_out[7:0] = Mem[read_addr];
|
|
SOut_zd = data_out[7-2*read_cnt];
|
|
SIOut_zd = data_out[6-2*read_cnt];
|
|
end
|
|
else
|
|
begin
|
|
SOut_zd = 1'bx;
|
|
SIOut_zd = 1'bx;
|
|
end
|
|
read_cnt = read_cnt + 1;
|
|
if (read_cnt == 4)
|
|
begin
|
|
read_cnt = 0;
|
|
if (read_addr == AddrRANGE)
|
|
read_addr = 0;
|
|
else
|
|
read_addr = read_addr + 1;
|
|
end
|
|
end
|
|
else
|
|
begin
|
|
read_cnt = read_cnt + 1;
|
|
if (read_cnt == 4)
|
|
begin
|
|
$display("Can't read suspended sector");
|
|
read_cnt = 0;
|
|
end
|
|
end
|
|
end
|
|
else if ((Instruct==FAST_QREAD || Instruct==W_QREAD
|
|
|| Instruct==FAST_QREAD_4 || Instruct==WOCT_QREAD)
|
|
&& QE)
|
|
begin
|
|
if (sect_tmp_ers !== read_addr / 16'h1000)
|
|
begin
|
|
if ((Instruct==W_QREAD && Address[0]) ||
|
|
(Instruct==WOCT_QREAD &&
|
|
~(Address[3:0]==4'h0)))
|
|
begin
|
|
read_cnt = read_cnt + 1;
|
|
if (read_cnt == 2)
|
|
begin
|
|
read_cnt = 0;
|
|
$display("Word Read can't execute");
|
|
$display("Wrong Read Address");
|
|
end
|
|
end
|
|
else
|
|
begin
|
|
fast_read = 1'b0;
|
|
dual_read = 1'b0;
|
|
slow_read = 1'b0;
|
|
quad_read = 1'b1;
|
|
sr_read = 1'b0;
|
|
data_out[7:0] = Mem[read_addr];
|
|
HOLDNegOut_zd = data_out[7-4*read_cnt];
|
|
WPNegOut_zd = data_out[6-4*read_cnt];
|
|
SOut_zd = data_out[5-4*read_cnt];
|
|
SIOut_zd = data_out[4-4*read_cnt];
|
|
read_cnt = read_cnt + 1;
|
|
if (read_cnt == 2)
|
|
begin
|
|
read_cnt = 0;
|
|
if (wrap_byte[4]==0 &&
|
|
(Instruct==FAST_QREAD_4
|
|
|| Instruct==W_QREAD))
|
|
begin
|
|
ADDRHILO_WRAP(AddrLo_wrap,
|
|
AddrHi_wrap,Address,w_size);
|
|
if (read_addr == AddrHi_wrap)
|
|
read_addr = AddrLo_wrap;
|
|
else
|
|
read_addr = read_addr + 1;
|
|
end
|
|
else
|
|
begin
|
|
if (read_addr == AddrRANGE)
|
|
read_addr = 0;
|
|
else
|
|
read_addr = read_addr + 1;
|
|
end
|
|
end
|
|
end
|
|
end
|
|
else
|
|
begin
|
|
read_cnt = read_cnt + 1;
|
|
if (read_cnt == 2)
|
|
begin
|
|
$display("Can't read suspended sector");
|
|
read_cnt = 0;
|
|
end
|
|
end
|
|
end
|
|
else if (Instruct==RDID || Instruct==RDID_DUAL ||
|
|
Instruct==RDID_QUAD)
|
|
begin
|
|
if (read_addr % 2 == 0)
|
|
begin
|
|
ident_out2 = {Manuf_ID,Device_ID1};
|
|
end
|
|
else
|
|
begin
|
|
ident_out2 = {Device_ID1,Manuf_ID};
|
|
end
|
|
read_id = 1'b1;
|
|
if (Instruct == RDID)
|
|
begin
|
|
fast_read = 1'b1;
|
|
dual_read = 1'b0;
|
|
slow_read = 1'b0;
|
|
quad_read = 1'b0;
|
|
sr_read = 1'b0;
|
|
DataDriveOut_SO = ident_out2[15-read_cnt];
|
|
read_cnt = read_cnt + 1;
|
|
if (read_cnt == 16)
|
|
read_cnt = 0;
|
|
end
|
|
else if (Instruct == RDID_DUAL)
|
|
begin
|
|
fast_read = 1'b0;
|
|
dual_read = 1'b1;
|
|
slow_read = 1'b0;
|
|
quad_read = 1'b0;
|
|
sr_read = 1'b0;
|
|
DataDriveOut_SO = ident_out2[15-2*read_cnt];
|
|
DataDriveOut_SI = ident_out2[14-2*read_cnt];
|
|
read_cnt = read_cnt + 1;
|
|
if (read_cnt == 8)
|
|
read_cnt = 0;
|
|
end
|
|
else // (Instruct == RDID_QUAD)
|
|
begin
|
|
fast_read = 1'b0;
|
|
dual_read = 1'b0;
|
|
slow_read = 1'b0;
|
|
quad_read = 1'b1;
|
|
sr_read = 1'b0;
|
|
HOLDNegOut_zd = ident_out2[15-4*read_cnt];
|
|
WPNegOut_zd = ident_out2[14-4*read_cnt];
|
|
SOut_zd = ident_out2[13-4*read_cnt];
|
|
SIOut_zd = ident_out2[12-4*read_cnt];
|
|
read_cnt = read_cnt + 1;
|
|
if (read_cnt == 4)
|
|
read_cnt = 0;
|
|
end
|
|
end
|
|
else if (Instruct == RD_UNIQ_ID)
|
|
begin
|
|
// unique ID number is not in data sheet
|
|
read_id = 1'b1;
|
|
DataDriveOut_SO = unique_id[63-read_cnt];
|
|
read_cnt = read_cnt + 1;
|
|
if (read_cnt == 64)
|
|
read_cnt = 0;
|
|
end
|
|
else if (Instruct == RDIDJ)
|
|
begin
|
|
read_id = 1'b1;
|
|
ident_out = {Manuf_ID,Device_ID2,Device_ID3};
|
|
DataDriveOut_SO = ident_out[23-read_cnt];
|
|
read_cnt = read_cnt + 1;
|
|
if (read_cnt == 24)
|
|
read_cnt = 0;
|
|
end
|
|
else if (Instruct == RD_SFDP)
|
|
begin
|
|
sfdp_addr = read_addr / 12'h100;
|
|
if (sfdp_addr == 0)
|
|
begin
|
|
Addr_tmp_2 = (read_addr % 12'h100);
|
|
data_out[7:0] = SFDP_array[Addr_tmp_2];
|
|
SOut_zd = data_out[7-read_cnt];
|
|
read_cnt = read_cnt + 1;
|
|
if (read_cnt == 8)
|
|
begin
|
|
read_cnt = 0;
|
|
if (read_addr == SFDP_HiAddr)
|
|
read_addr = 0;
|
|
else
|
|
read_addr = read_addr + 1;
|
|
end
|
|
end
|
|
else
|
|
begin
|
|
read_cnt = read_cnt + 1;
|
|
if (read_cnt == 8)
|
|
begin
|
|
read_cnt = 0;
|
|
$display("SFDP address is out of range");
|
|
end
|
|
end
|
|
end
|
|
else if (Instruct == RD_SCREG)
|
|
begin
|
|
Addr_tmp_2 = read_addr / 12'h100;
|
|
Addr_tmp_3 = read_addr % 12'h100;
|
|
if (Addr_tmp_2 == 16)
|
|
begin
|
|
// Security Register No.1
|
|
data_out[7:0] = Security_Reg1[Addr_tmp_3];
|
|
SOut_zd = data_out[7-read_cnt];
|
|
read_cnt = read_cnt + 1;
|
|
end
|
|
else if (Addr_tmp_2 == 32)
|
|
begin
|
|
// Security Register No.2
|
|
data_out[7:0] = Security_Reg2[Addr_tmp_3];
|
|
SOut_zd = data_out[7-read_cnt];
|
|
read_cnt = read_cnt + 1;
|
|
end
|
|
else if (Addr_tmp_2 == 48)
|
|
// Security Register No.2
|
|
begin
|
|
data_out[7:0] = Security_Reg3[Addr_tmp_3];
|
|
SOut_zd = data_out[7-read_cnt];
|
|
read_cnt = read_cnt + 1;
|
|
end
|
|
else
|
|
begin
|
|
read_cnt = read_cnt + 1;
|
|
if (read_cnt == 8)
|
|
begin
|
|
read_cnt = 0;
|
|
$display("Given Security Register Read ");
|
|
$display("address is out of range ");
|
|
end
|
|
end
|
|
if (read_cnt == 8)
|
|
begin
|
|
read_cnt = 0;
|
|
if (read_addr % 256 == SecReg_HiAddr)
|
|
read_addr = (read_addr/256)*
|
|
(SecReg_HiAddr+1);
|
|
else
|
|
read_addr = read_addr + 1;
|
|
end
|
|
end
|
|
end // end of 'oe'
|
|
end // end of SUS
|
|
end // end of ERS_SUSP
|
|
|
|
DP_DOWN:
|
|
begin
|
|
if (oe)
|
|
begin
|
|
if (Instruct == RES_RD_ID)
|
|
begin
|
|
read_id = 1'b1;
|
|
data_out[7:0] = Device_ID1;
|
|
DataDriveOut_SO = data_out[7-read_cnt];
|
|
read_cnt = read_cnt + 1;
|
|
if (read_cnt == 8)
|
|
read_cnt = 0;
|
|
end
|
|
end
|
|
if (falling_edge_write)
|
|
begin
|
|
if (Instruct == RES_RD_ID)
|
|
begin
|
|
RES_in = 1'b1;
|
|
end
|
|
else
|
|
begin
|
|
$display("Device is in Deep Power Down Mode");
|
|
$display("No instructions allowed");
|
|
end
|
|
end
|
|
end
|
|
|
|
endcase
|
|
//Output Disable Control
|
|
if (CSNeg_ipd )
|
|
begin
|
|
SIOut_zd = 1'bZ;
|
|
HOLDNegOut_zd = 1'bZ;
|
|
WPNegOut_zd = 1'bZ;
|
|
SOut_zd = 1'bZ;
|
|
DataDriveOut_SO = 1'bZ;
|
|
DataDriveOut_SI = 1'bZ;
|
|
end
|
|
end // end of Functionality
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
always @(posedge change_prot_bits)
|
|
begin
|
|
case (Status_reg1[4:2])
|
|
3'b000:
|
|
begin
|
|
if (Status_reg2[6] == 1'b0)
|
|
Sec_Prot[4095:0] = {4096{1'b0}};
|
|
else
|
|
Sec_Prot[4095:0] = {4096{1'b1}};
|
|
end
|
|
|
|
3'b001:
|
|
begin
|
|
if (Status_reg2[6] ==1'b0)
|
|
begin
|
|
case (Status_reg1[6:5])
|
|
2'b00:
|
|
begin
|
|
Sec_Prot[4095:4032] = {64{1'b1}};
|
|
Sec_Prot[4031:0] = {4032{1'b0}};
|
|
end
|
|
2'b01:
|
|
begin
|
|
Sec_Prot[4095:64] = {4032{1'b0}};
|
|
Sec_Prot[63:0] = {64{1'b1}};
|
|
end
|
|
2'b10:
|
|
begin
|
|
Sec_Prot[4095] = 1'b1;
|
|
Sec_Prot[4094:0] = {4095{1'b0}};
|
|
end
|
|
2'b11:
|
|
begin
|
|
Sec_Prot[4095:1] = {4095{1'b0}};
|
|
Sec_Prot[0] = 1'b1;
|
|
end
|
|
endcase
|
|
end
|
|
else
|
|
begin
|
|
case (Status_reg1[6:5])
|
|
2'b00:
|
|
begin
|
|
Sec_Prot[4095:4032] = {64{1'b0}};
|
|
Sec_Prot[4031:0] = {4032{1'b1}};
|
|
end
|
|
2'b01:
|
|
begin
|
|
Sec_Prot[4095:64] = {4032{1'b1}};
|
|
Sec_Prot[63:0] = {64{1'b0}};
|
|
end
|
|
2'b10:
|
|
begin
|
|
Sec_Prot[4095] = 1'b0;
|
|
Sec_Prot[4094:0] = {4095{1'b1}};
|
|
end
|
|
2'b11:
|
|
begin
|
|
Sec_Prot[4095:1] = {4095{1'b1}};
|
|
Sec_Prot[0] = 1'b0;
|
|
end
|
|
endcase
|
|
end
|
|
end
|
|
|
|
3'b010:
|
|
begin
|
|
if (Status_reg2[6] == 1'b0)
|
|
begin
|
|
case (Status_reg1[6:5])
|
|
2'b00:
|
|
begin
|
|
Sec_Prot[4095:3968] = {128{1'b1}} ;
|
|
Sec_Prot[3967:0] = {3968{1'b0}} ;
|
|
end
|
|
2'b01:
|
|
begin
|
|
Sec_Prot[4095:128] = {3968{1'b0}} ;
|
|
Sec_Prot[127:0] = {128{1'b1}} ;
|
|
end
|
|
2'b10:
|
|
begin
|
|
Sec_Prot[4095:4094] = 2'b11;
|
|
Sec_Prot[4093:0] = {4094{1'b0}};
|
|
end
|
|
2'b11:
|
|
begin
|
|
Sec_Prot[4095:2] = {4094{1'b0}};
|
|
Sec_Prot[1:0] = 2'b11;
|
|
end
|
|
endcase
|
|
end
|
|
else
|
|
begin
|
|
case (Status_reg1[6:5])
|
|
2'b00:
|
|
begin
|
|
Sec_Prot[4095:3968] = {128{1'b0}} ;
|
|
Sec_Prot[3967:0] = {3968{1'b1}} ;
|
|
end
|
|
2'b01:
|
|
begin
|
|
Sec_Prot[4095:128] = {3968{1'b1}} ;
|
|
Sec_Prot[127:0] = {128{1'b0}} ;
|
|
end
|
|
2'b10:
|
|
begin
|
|
Sec_Prot[4095:4094] = 2'b00;
|
|
Sec_Prot[4093:0] = {4094{1'b1}};
|
|
end
|
|
2'b11:
|
|
begin
|
|
Sec_Prot[4095:2] = {4094{1'b1}};
|
|
Sec_Prot[1:0] = 2'b00;
|
|
end
|
|
endcase
|
|
end
|
|
end
|
|
|
|
3'b011:
|
|
begin
|
|
if (Status_reg2[6] == 1'b0)
|
|
begin
|
|
case (Status_reg1[6:5])
|
|
2'b00:
|
|
begin
|
|
Sec_Prot[4095:3840] = {256{1'b1}} ;
|
|
Sec_Prot[3839:0] = {3840{1'b0}} ;
|
|
end
|
|
2'b01:
|
|
begin
|
|
Sec_Prot[4095:256] = {3840{1'b0}} ;
|
|
Sec_Prot[255:0] = {256{1'b1}} ;
|
|
end
|
|
2'b10:
|
|
begin
|
|
Sec_Prot[4095:4092] = 4'b1111;
|
|
Sec_Prot[4091:0] = {4092{1'b0}};
|
|
end
|
|
2'b11:
|
|
begin
|
|
Sec_Prot[4095:4] = {4092{1'b0}};
|
|
Sec_Prot[3:0] = 4'b1111;
|
|
end
|
|
endcase
|
|
end
|
|
else
|
|
begin
|
|
case (Status_reg1[6:5])
|
|
2'b00:
|
|
begin
|
|
Sec_Prot[4095:3840] = {256{1'b0}} ;
|
|
Sec_Prot[3839:0] = {3840{1'b1}} ;
|
|
end
|
|
2'b01:
|
|
begin
|
|
Sec_Prot[4095:256] = {3840{1'b1}} ;
|
|
Sec_Prot[255:0] = {256{1'b0}} ;
|
|
end
|
|
2'b10:
|
|
begin
|
|
Sec_Prot[4095:4092] = 4'b0000;
|
|
Sec_Prot[4091:0] = {4092{1'b1}};
|
|
end
|
|
2'b11:
|
|
begin
|
|
Sec_Prot[4095:4] = {4092{1'b1}};
|
|
Sec_Prot[3:0] = 4'b0000;
|
|
end
|
|
endcase
|
|
end
|
|
end
|
|
|
|
3'b100:
|
|
begin
|
|
if (Status_reg2[6] == 1'b0)
|
|
begin
|
|
case (Status_reg1[6:5])
|
|
2'b00:
|
|
begin
|
|
Sec_Prot[4095:3584] = {512{1'b1}} ;
|
|
Sec_Prot[3583:0] = {3584{1'b0}} ;
|
|
end
|
|
2'b01:
|
|
begin
|
|
Sec_Prot[4095:512] = {3584{1'b0}} ;
|
|
Sec_Prot[511:0] = {512{1'b1}} ;
|
|
end
|
|
2'b10:
|
|
begin
|
|
Sec_Prot[4095:4088] = 8'hFF;
|
|
Sec_Prot[4087:0] = {4088{1'b0}};
|
|
end
|
|
2'b11:
|
|
begin
|
|
Sec_Prot[4095:8] = {4088{1'b0}};
|
|
Sec_Prot[7:0] = 8'hFF;
|
|
end
|
|
endcase
|
|
end
|
|
else
|
|
begin
|
|
case (Status_reg1[6:5])
|
|
2'b00:
|
|
begin
|
|
Sec_Prot[4095:3584] = {512{1'b0}} ;
|
|
Sec_Prot[3583:0] = {3584{1'b1}} ;
|
|
end
|
|
2'b01:
|
|
begin
|
|
Sec_Prot[4095:512] = {3584{1'b1}} ;
|
|
Sec_Prot[511:0] = {512{1'b0}} ;
|
|
end
|
|
2'b10:
|
|
begin
|
|
Sec_Prot[4095:4088] = 8'h00;
|
|
Sec_Prot[4087:0] = {4088{1'b1}};
|
|
end
|
|
2'b11:
|
|
begin
|
|
Sec_Prot[4095:8] = {4088{1'b1}};
|
|
Sec_Prot[7:0] = 8'h00;
|
|
end
|
|
endcase
|
|
end
|
|
end
|
|
|
|
3'b101:
|
|
begin
|
|
if (Status_reg2[6] == 1'b0)
|
|
begin
|
|
case (Status_reg1[6:5])
|
|
2'b00:
|
|
begin
|
|
Sec_Prot[4095:3072] = {1024{1'b1}} ;
|
|
Sec_Prot[3071:0] = {3072{1'b0}} ;
|
|
end
|
|
2'b01:
|
|
begin
|
|
Sec_Prot[4095:1024] = {3072{1'b0}} ;
|
|
Sec_Prot[1023:0] = {1024{1'b1}} ;
|
|
end
|
|
2'b10:
|
|
begin
|
|
Sec_Prot[4095:4088] = 8'hFF;
|
|
Sec_Prot[4087:0] = {4088{1'b0}};
|
|
end
|
|
2'b11:
|
|
begin
|
|
Sec_Prot[4095:8] = {4088{1'b0}};
|
|
Sec_Prot[7:0] = 8'hFF;
|
|
end
|
|
endcase
|
|
end
|
|
else
|
|
begin
|
|
case (Status_reg1[6:5])
|
|
2'b00:
|
|
begin
|
|
Sec_Prot[4095:3072] = {1024{1'b0}} ;
|
|
Sec_Prot[3071:0] = {3072{1'b1}} ;
|
|
end
|
|
2'b01:
|
|
begin
|
|
Sec_Prot[4095:1024] = {3072{1'b1}} ;
|
|
Sec_Prot[1023:0] = {1024{1'b0}} ;
|
|
end
|
|
2'b10:
|
|
begin
|
|
Sec_Prot[4095:4088] = 8'h00;
|
|
Sec_Prot[4087:0] = {4088{1'b1}};
|
|
end
|
|
2'b11:
|
|
begin
|
|
Sec_Prot[4095:8] = {4088{1'b1}};
|
|
Sec_Prot[7:0] = 8'h00;
|
|
end
|
|
endcase
|
|
end
|
|
end
|
|
|
|
3'b110:
|
|
begin
|
|
if (Status_reg2[6] == 1'b0)
|
|
begin
|
|
case (Status_reg1[6:5])
|
|
2'b00:
|
|
begin
|
|
Sec_Prot[4095:2048] = {2048{1'b1}} ;
|
|
Sec_Prot[2047:0] = {2048{1'b0}} ;
|
|
end
|
|
2'b01:
|
|
begin
|
|
Sec_Prot[4095:2048] = {2048{1'b0}} ;
|
|
Sec_Prot[2047:0] = {2048{1'b1}} ;
|
|
end
|
|
2'b10, 2'b11:
|
|
begin
|
|
$display("This combination of bits ");
|
|
$display("is not deffined");
|
|
end
|
|
endcase
|
|
end
|
|
else
|
|
begin
|
|
case (Status_reg1[6:5])
|
|
2'b00:
|
|
begin
|
|
Sec_Prot[4095:2048] = {2048{1'b0}} ;
|
|
Sec_Prot[2047:0] = {2048{1'b1}} ;
|
|
end
|
|
2'b01:
|
|
begin
|
|
Sec_Prot[4095:2048] = {2048{1'b1}} ;
|
|
Sec_Prot[2047:0] = {2048{1'b0}} ;
|
|
end
|
|
2'b10, 2'b11:
|
|
begin
|
|
$display("This combination of bits ");
|
|
$display("is not deffined");
|
|
end
|
|
endcase
|
|
end
|
|
end
|
|
|
|
3'b111:
|
|
begin
|
|
if (Status_reg2[6]== 1'b0)
|
|
Sec_Prot[4095:0] = {4096{1'b1}};
|
|
else
|
|
Sec_Prot[4095:0] = {4096{1'b0}};
|
|
end
|
|
endcase
|
|
end // end of rising_edge_prot_bits
|
|
////////////////////////////////////////////////////////////////////////
|
|
always @(SOut_zd or HOLDNeg_in or SIOut_zd)
|
|
begin
|
|
if (HOLDNeg_in == 0 && ~QE)
|
|
begin
|
|
hold_mode = 1'b1;
|
|
SIOut_z = 1'bZ;
|
|
SOut_z = 1'bZ;
|
|
end
|
|
else
|
|
begin
|
|
if (hold_mode == 1)
|
|
begin
|
|
SIOut_z <= #(tpd_HOLDNeg_SO) SIOut_zd;
|
|
SOut_z <= #(tpd_HOLDNeg_SO) SOut_zd;
|
|
hold_mode = #(tpd_HOLDNeg_SO) 1'b0;
|
|
end
|
|
else
|
|
begin
|
|
SIOut_z = SIOut_zd;
|
|
SOut_z = SOut_zd;
|
|
hold_mode = 1'b0;
|
|
end
|
|
end
|
|
end
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
// functions & tasks
|
|
////////////////////////////////////////////////////////////////////////
|
|
// Procedure ADDRHILO_SEC 4KB, 32KB, 64KB
|
|
task ADDRHILO_SEC64;
|
|
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 + 20'h0FFFF;
|
|
end
|
|
endtask
|
|
|
|
task ADDRHILO_SEC32;
|
|
inout AddrLOW;
|
|
inout AddrHIGH;
|
|
input Addr;
|
|
integer AddrLOW;
|
|
integer AddrHIGH;
|
|
integer Addr;
|
|
integer sector;
|
|
begin
|
|
sector = Addr / 16'h8000;
|
|
AddrLOW = sector * 16'h8000;
|
|
AddrHIGH = sector * 16'h8000 + 16'h7FFF;
|
|
end
|
|
endtask
|
|
|
|
task ADDRHILO_SEC4;
|
|
inout AddrLOW;
|
|
inout AddrHIGH;
|
|
input Addr;
|
|
integer AddrLOW;
|
|
integer AddrHIGH;
|
|
integer Addr;
|
|
integer sector;
|
|
begin
|
|
sector = Addr / 16'h1000;
|
|
AddrLOW = sector * 16'h1000;
|
|
AddrHIGH = sector * 16'h1000 + 16'h0FFF;
|
|
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'h0100;
|
|
AddrLOW = page * 16'h0100;
|
|
AddrHIGH = page * 16'h0100 + 16'h00FF;
|
|
end
|
|
endtask
|
|
|
|
// Procedure ADDRHILO_WRAP
|
|
task ADDRHILO_WRAP;
|
|
inout Addr_low_wrap;
|
|
inout Addr_hi_wrap;
|
|
input Address;
|
|
input w_size;
|
|
integer Addr_low_wrap;
|
|
integer Addr_hi_wrap;
|
|
integer Address;
|
|
integer w_size;
|
|
integer sect_wrap;
|
|
begin
|
|
sect_wrap = Address / w_size;
|
|
Addr_low_wrap = sect_wrap * w_size;
|
|
Addr_hi_wrap = sect_wrap * w_size + w_size - 1;
|
|
end
|
|
endtask
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
// edge controll processes
|
|
///////////////////////////////////////////////////////////////////////////
|
|
always @(posedge PoweredUp)
|
|
begin
|
|
rising_edge_PoweredUp = 1;
|
|
#1000 rising_edge_PoweredUp = 0;
|
|
end
|
|
|
|
always @(posedge SCK_ipd)
|
|
begin
|
|
rising_edge_SCK_ipd = 1'b1;
|
|
#1000 rising_edge_SCK_ipd = 1'b0;
|
|
end
|
|
|
|
always @(negedge SCK_ipd)
|
|
begin
|
|
falling_edge_SCK_ipd = 1'b1;
|
|
#1000 falling_edge_SCK_ipd = 1'b0;
|
|
end
|
|
|
|
always @(posedge read_out)
|
|
begin
|
|
rising_edge_read_out = 1'b1;
|
|
#1000 rising_edge_read_out = 1'b0;
|
|
end
|
|
|
|
always @(negedge write)
|
|
begin
|
|
falling_edge_write = 1'b1;
|
|
#1000 falling_edge_write = 1'b0;
|
|
end
|
|
|
|
always @(posedge CSNeg_ipd)
|
|
begin
|
|
rising_edge_CSNeg_ipd = 1'b1;
|
|
#1000 rising_edge_CSNeg_ipd = 1'b0;
|
|
end
|
|
|
|
always @(negedge CSNeg_ipd)
|
|
begin
|
|
falling_edge_CSNeg_ipd = 1'b1;
|
|
#1000 falling_edge_CSNeg_ipd = 1'b0;
|
|
end
|
|
|
|
always @(posedge PDONE)
|
|
begin
|
|
rising_edge_PDONE = 1'b1;
|
|
#1000 rising_edge_PDONE = 1'b0;
|
|
end
|
|
|
|
always @(posedge WDONE)
|
|
begin
|
|
rising_edge_WDONE = 1'b1;
|
|
#1000 rising_edge_WDONE = 1'b0;
|
|
end
|
|
|
|
always @(posedge VLTDONE)
|
|
begin
|
|
rising_edge_VLTDONE = 1'b1;
|
|
#1000 rising_edge_VLTDONE = 1'b0;
|
|
end
|
|
|
|
always @(posedge WSTART)
|
|
begin
|
|
rising_edge_WSTART = 1'b1;
|
|
#1000 rising_edge_WSTART = 1'b0;
|
|
end
|
|
|
|
always @(posedge VLTSTART)
|
|
begin
|
|
rising_edge_VLTSTART = 1'b1;
|
|
#1000 rising_edge_VLTSTART = 1'b0;
|
|
end
|
|
|
|
always @(posedge EDONE)
|
|
begin
|
|
rising_edge_EDONE = 1'b1;
|
|
#1000 rising_edge_EDONE = 1'b0;
|
|
end
|
|
|
|
always @(posedge ESTART)
|
|
begin
|
|
rising_edge_ESTART = 1'b1;
|
|
#1000 rising_edge_ESTART = 1'b0;
|
|
end
|
|
|
|
always @(posedge PSTART)
|
|
begin
|
|
rising_edge_PSTART = 1'b1;
|
|
#1000 rising_edge_PSTART = 1'b0;
|
|
end
|
|
|
|
always @(posedge DP_out)
|
|
begin
|
|
rising_edge_DP_out = 1'b1;
|
|
#1 rising_edge_DP_out = 1'b0;
|
|
end
|
|
|
|
always @(posedge RES_out)
|
|
begin
|
|
rising_edge_RES_out = 1'b1;
|
|
#1000 rising_edge_RES_out = 1'b0;
|
|
end
|
|
|
|
always @(Instruct)
|
|
begin
|
|
Instruct_event = 1'b1;
|
|
#1000 Instruct_event = 1'b0;
|
|
end
|
|
|
|
always @(change_addr)
|
|
begin
|
|
change_addr_event = 1'b1;
|
|
#1000 change_addr_event = 1'b0;
|
|
end
|
|
|
|
always @(next_state)
|
|
begin
|
|
next_state_event = 1'b1;
|
|
#1000 next_state_event = 1'b0;
|
|
end
|
|
|
|
always @(current_state)
|
|
begin
|
|
current_state_event = 1'b1;
|
|
#1000 current_state_event = 1'b0;
|
|
end
|
|
|
|
always @(posedge PRGSUSP_out)
|
|
begin
|
|
PRGSUSP_out_event = 1;
|
|
#1000 PRGSUSP_out_event = 0;
|
|
end
|
|
|
|
always @(posedge PRGRES_out)
|
|
begin
|
|
PRGRES_out_event = 1;
|
|
#1000 PRGRES_out_event = 0;
|
|
end
|
|
|
|
always @(posedge ESUSP)
|
|
begin
|
|
ESUSP_event = 1'b1;
|
|
#1000 ESUSP_event = 1'b0;
|
|
end
|
|
|
|
always @(posedge ERSSUSP_out)
|
|
begin
|
|
ERSSUSP_out_event = 1;
|
|
#1000 ERSSUSP_out_event = 0;
|
|
end
|
|
|
|
always @(posedge ERSRES_out)
|
|
begin
|
|
ERSRES_out_event = 1;
|
|
#1000 ERSRES_out_event = 0;
|
|
end
|
|
|
|
always @(posedge PGSUSP)
|
|
begin
|
|
PGSUSP_event = 1'b1;
|
|
#1000 PGSUSP_event = 1'b0;
|
|
end
|
|
|
|
always @(posedge PGRES)
|
|
begin
|
|
PGRES_event = 1'b1;
|
|
#1000 PGRES_event = 1'b0;
|
|
end
|
|
|
|
always @(posedge ERES)
|
|
begin
|
|
ERES_event = 1'b1;
|
|
#1000 ERES_event = 1'b0;
|
|
end
|
|
|
|
always @(posedge change_prot_bits)
|
|
begin
|
|
rising_edge_prot_bits = 1'b1;
|
|
#1000 rising_edge_prot_bits = 1'b0;
|
|
end
|
|
|
|
reg update_time = 1'b0;
|
|
always @(posedge read_id)
|
|
begin
|
|
start_rdid = $time;
|
|
update_time = 1'b1;
|
|
end
|
|
|
|
always @(SO_out)
|
|
begin
|
|
if (read_id && update_time)
|
|
out_time = $time;
|
|
SCK_SO_2 = out_time - start_rdid;
|
|
update_time = 1'b0;
|
|
end
|
|
|
|
always @(DataDriveOut_SO,DataDriveOut_SI)
|
|
begin
|
|
if (SCK_SO_2 > SCK_cycle)
|
|
begin
|
|
glitch = 1;
|
|
SOut_zd <= #SCK_SO_2 DataDriveOut_SO;
|
|
SIOut_zd <= #SCK_SO_2 DataDriveOut_SI;
|
|
end
|
|
else
|
|
begin
|
|
glitch = 0;
|
|
SOut_zd <= DataDriveOut_SO;
|
|
SIOut_zd <= DataDriveOut_SI;
|
|
end
|
|
end
|
|
|
|
endmodule |