/////////////////////////////////////////////////////////////////////////////// // File name : s25fl004k.v /////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// // Copyright (C) 2010 Free Model Foundry; http://www.FreeModelFoundry.com // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License version 2 as // published by the Free Software Foundation. // // MODIFICATION HISTORY : // // version: | author: | mod date: | changes made: // V1.0 R.Prokopovic 10 Oct 05 Initial // /////////////////////////////////////////////////////////////////////////////// // PART DESCRIPTION: // // Library: FLASH // Technology: FLASH MEMORY // Part: S25FL004K // // Description: 4 Megabit Serial Flash Memory // /////////////////////////////////////////////////////////////////////////////// // Comments : // ////////////////////////////////////////////////////////////////////////////// // Known Bugs: // ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// // MODULE DECLARATION // ////////////////////////////////////////////////////////////////////////////// `timescale 1 ps/1 ps module s25fl004k ( // 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 ; 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";//"s25fl004k.mem"; parameter screg_file_name = "s25fl004kscreg.mem";//"none"; parameter TimingModel = "DefaultTimingModel"; parameter PartID = "s25fl004k"; parameter MaxData = 255; parameter AddrRANGE = 24'h7FFFF; parameter PageNum = 16'h7FF; parameter SecSize_4 = 12'hFFF; parameter SecSize_32 = 16'h7FFF; parameter SecSize_64 = 16'hFFFF; parameter Blk_4_Num = 127; parameter Blk_64_Num = 7; parameter Blk_32_Num = 15; 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'h12; parameter Device_ID2 = 8'h40; parameter Device_ID3 = 8'h13; 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 LB3; // wire LB2; // wire LB1; 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 LB2 = Status_reg2[4]; // assign LB1 = Status_reg2[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 = {128{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; // integer w_size; reg hold_mode = 1'b0; // 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; /////////////////////////////////////////////////////////////////////////////// //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; 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; 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 (SIOut_z !== 1'bZ) deq_sin=1'b0; else deq_sin=1'b1; end assign deg_sin = deq_sin; /*&& (~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_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; // 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 = 4e10; // 40 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 = 4e12; // 4 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 (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) (SCK => SI) = tpd_SCK_SO_1; if (CSNeg && ~deg_sin) (CSNeg => SI) = tpd_CSNeg_SO; if (~quad_read && dual_read) (HOLDNeg => SI) = tpd_HOLDNeg_SO; // if (QE) (SCK => SI) = tpd_SCK_SO_1; if (quad_read) (SCK => WPNeg) = tpd_SCK_SO_1; if (quad_read) (SCK => HOLDNeg) = tpd_SCK_SO_1; 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 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); 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 //s25fl004k.mem, memory preload file // @aaaaaa - stands for address // 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 //s25fl004kSCREG memory file // / - comment // @aaa - stands for address of specific Security register // 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'h3F; SFDP_array[8'h87] = 8'h00; 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 // SFDP_array[8'h90:8'hFF] = {112{8'hFF}}; 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_double_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, // WRENV, 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 /////////////////////////////////////////////////////////////////////////// // 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; SOut_zd = 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; SOut_zd = ident_out2[15-2*read_cnt]; SIOut_zd = 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; SOut_zd = 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}; SOut_zd = 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; SOut_zd = 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; SOut_zd = 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; SOut_zd = ident_out2[15-2*read_cnt]; SIOut_zd = 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; SOut_zd = 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}; SOut_zd = 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 // SOut_zd = data_out[7-read_cnt]; // read_cnt = read_cnt + 1; 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; SOut_zd = 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; SOut_zd = ident_out2[15-2*read_cnt]; SIOut_zd = 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; SOut_zd = 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}; SOut_zd = 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; SOut_zd = 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; 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[127:0] = {128{1'b0}}; else Sec_Prot[127:0] = {128{1'b1}}; end 3'b001: begin if (Status_reg2[6] ==1'b0) begin case (Status_reg1[6:5]) 2'b00: begin Sec_Prot[127:112] = {16{1'b1}}; Sec_Prot[111:0] = {112{1'b0}}; end 2'b01: begin Sec_Prot[127:16] = {112{1'b0}}; Sec_Prot[15:0] = {16{1'b1}}; end 2'b10: begin Sec_Prot[127] = 1'b1; Sec_Prot[126:0] = {127{1'b0}}; end 2'b11: begin Sec_Prot[127:1] = {127{1'b0}}; Sec_Prot[0] = 1'b1; end endcase end else begin case (Status_reg1[6:5]) 2'b00: begin Sec_Prot[127:112] = {16{1'b0}}; Sec_Prot[111:0] = {112{1'b1}}; end 2'b01: begin Sec_Prot[127:16] = {112{1'b1}}; Sec_Prot[15:0] = {16{1'b0}}; end 2'b10: begin Sec_Prot[127] = 1'b0; Sec_Prot[126:0] = {127{1'b1}}; end 2'b11: begin Sec_Prot[127:1] = {127{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[127:96] = {32{1'b1}} ; Sec_Prot[95:0] = {96{1'b0}} ; end 2'b01: begin Sec_Prot[127:32] = {96{1'b0}} ; Sec_Prot[31:0] = {32{1'b1}} ; end 2'b10: begin Sec_Prot[127:126] = 2'b11; Sec_Prot[125:0] = {126{1'b0}}; end 2'b11: begin Sec_Prot[127:2] = {126{1'b0}}; Sec_Prot[1:0] = 2'b11; end endcase end else begin case (Status_reg1[6:5]) 2'b00: begin Sec_Prot[127:96] = {32{1'b0}} ; Sec_Prot[95:0] = {96{1'b1}} ; end 2'b01: begin Sec_Prot[127:32] = {96{1'b1}} ; Sec_Prot[31:0] = {32{1'b0}} ; end 2'b10: begin Sec_Prot[127:126] = 2'b00; Sec_Prot[125:0] = {126{1'b1}}; end 2'b11: begin Sec_Prot[127:2] = {126{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[127:64] = {64{1'b1}} ; Sec_Prot[63:0] = {64{1'b0}} ; end 2'b01: begin Sec_Prot[127:64] = {64{1'b0}} ; Sec_Prot[63:0] = {64{1'b1}} ; end 2'b10: begin Sec_Prot[127:124] = 4'b1111; Sec_Prot[123:0] = {124{1'b0}}; end 2'b11: begin Sec_Prot[127:4] = {124{1'b0}}; Sec_Prot[3:0] = 4'b1111; end endcase end else begin case (Status_reg1[6:5]) 2'b00: begin Sec_Prot[127:64] = {64{1'b0}} ; Sec_Prot[63:0] = {64{1'b1}} ; end 2'b01: begin Sec_Prot[127:64] = {64{1'b1}} ; Sec_Prot[63:0] = {64{1'b0}} ; end 2'b10: begin Sec_Prot[127:124] = {4{1'b0}}; Sec_Prot[123:0] = {124{1'b1}}; end 2'b11: begin Sec_Prot[127:4] = {124{1'b1}}; Sec_Prot[3:0] = {4{1'b0}}; end endcase end end 3'b100, 3'b101, 3'b110: begin if (Status_reg2[6] == 1'b0) begin if (Status_reg1[6] == 1'b0) Sec_Prot[127:0] = {128{1'b1}}; else begin if (Status_reg1[5] == 1'b0) begin Sec_Prot[127:120] = {8{1'b1}}; Sec_Prot[119:0] = {120{1'b0}}; end else begin Sec_Prot[127:120] = {8{1'b0}}; Sec_Prot[119:0] = {120{1'b1}}; end end end else begin if (Status_reg1[6] == 1'b1) begin if (Status_reg1[5] == 1'b0) begin Sec_Prot[127:120] = {8{1'b0}}; Sec_Prot[119:0] = {120{1'b1}}; end else begin Sec_Prot[127:8] = {120{1'b1}}; Sec_Prot[7:0] = {8{1'b0}}; end end end end 3'b111: begin if (Status_reg2[6]== 1'b0) Sec_Prot[127:0] = {128{1'b1}}; else Sec_Prot[127:0] = {128{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 endmodule