////////////////////////////////////////////////////////////////////////////// // File Name: sst25vf064c.v ////////////////////////////////////////////////////////////////////////////// // Copyright (C) 2010 Free Model Foundry; http://www.FreeModelFoundry.com // // MODIFICATION HISTORY : // // version: | author: | mod date: | changes made: // V1.0 V.Mancev 10 May 18 Inital Release // ////////////////////////////////////////////////////////////////////////////// // PART DESCRIPTION: // // Library: FLASH // Technology: FLASH MEMORY // Part: SST25VF064C // // Description: 64 Mbit SPI Serial Dual I/O Flash // Comments : // For correct simulation, simulator resolution should be set to 1 ps // ////////////////////////////////////////////////////////////////////////////// // Known Bugs: // ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// // MODULE DECLARATION // ////////////////////////////////////////////////////////////////////////////// `timescale 1 ps/1 ps module sst25vf064c ( // Data Inputs/Outputs SI , SO , // Controls SCK , CENeg , WPNeg , RSTNeg ); /////////////////////////////////////////////////////////////////////////////// // Port / Part Pin Declarations /////////////////////////////////////////////////////////////////////////////// inout SI ; // Serial Data Input inout SO ; // Serial Data Output input SCK ; // Serial Clock input CENeg ; // Chip Select input WPNeg ; // Write Protect input RSTNeg ; // RST#/HOLD# // interconnect path delay signals wire SI_ipd ; wire SO_ipd ; wire SCK_ipd ; wire CENeg_ipd ; wire WPNeg_ipd ; wire RSTNeg_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 ; // internal delays reg PowerUp_in ; reg PowerUp_out ; reg SectorErase_in ; reg SectorErase_out ; reg BlockErase_in ; reg BlockErase_out ; reg ChipErase_in ; reg ChipErase_out ; reg PageProgram_in ; reg PageProgram_out ; reg ProgramSecID_in ; reg ProgramSecID_out ; // event control registers reg rising_edge_CENeg_ipd = 1'b0; reg falling_edge_CENeg_ipd = 1'b0; reg rising_edge_SCK_ipd = 1'b0; reg falling_edge_SCK_ipd = 1'b0; reg falling_edge_RST = 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 ; assign SI_z = SIOut_z; assign SO_z = SOut_z; parameter mem_file_name = "none";//"sst25vf064c.mem"; parameter SecID_file_name = "none";//"sst25vf064cSecID.mem"; parameter UserPreload = 1; parameter TimingModel = "DefaultTimingModel"; parameter PartID = "sst25vf064c"; parameter MaxData = 255; parameter MemSize = 24'h7FFFFF; parameter SecSize = 12'hFFF; // 4 KByte parameter SecNum = 2047; parameter BlockSize_32 = 16'h7FFF; parameter Block32Num = 255; parameter BlockSize_64 = 16'hFFFF; parameter Block64Num = 127; parameter PageNum = 16'h7FFF; parameter HiAddrBit = 23; parameter AddrRANGE = 24'h7FFFFF; parameter SecIDSize = 31; parameter SecIDLoAddr = 8'h00; parameter SecIDLoAddrPg = 8'h08; parameter SecIDHiAddr = 8'h1F; parameter BYTE = 8; // Manufacturer Identification parameter Manuf_ID = 8'hBF; // Device ID parameter DeviceID = 8'h4B; // JEDEC Read-ID Data // Manufacturer Identification && Memory Type && Memory Capacity parameter Jedec_ID = 8'hBF; parameter DeviceID1 = 8'h25; parameter DeviceID2 = 8'h4B; // If speed simulation is needed uncomment following line // `define SPEEDSIM; // powerup reg PoweredUp = 1'b0; // FSM control signals reg PDONE = 1; reg PSTART = 0; reg PRESET = 0; reg EDONE = 1; reg ESTART = 0; reg ERESET = 0; // Programming buffer integer WByte[0:255]; integer WSIDByte[0:31]; // Security ID Memory Array integer SecIDMem[SecIDLoAddr:SecIDHiAddr]; // Flash Memory Array integer Mem[0:AddrRANGE]; //Command Register reg write = 0; reg read_out = 0; //Address integer Address = 0; // 0 - AddrRANGE reg change_addr = 0; integer AddrLo = 0; integer AddrHi = 0; integer read_cnt = 0; integer read_addr = 0; reg[7:0] data_out = 8'b0; reg[23:0] ident_out = 23'b0; reg oe = 1'b0; event oe_event; integer Byte_number = 0; reg[7:0] old_bit = 8'b0; reg[7:0] new_bit = 8'b0; integer old_int = 0; integer new_int = 0; integer wr_cnt = 0; integer cnt; reg RST = 1; reg reseted ; reg hold_mode = 1'b0; reg HOLD_EN = 1'b0; // RST#/HOLD# pin is configured as a RST# pin reg hold_act = 1'b0; // HOLD# pin deactivated reg change_BP = 0; reg dual = 1'b0; reg dual_io = 1'b0; reg rd_fast = 1'b1; reg rd_slow = 1'b0; wire rd ; wire dual_rd ; wire dual_io_rd ; wire fast_rd ; assign rd = rd_slow; assign dual_rd = dual; assign dual_io_rd = dual_io; assign fast_rd = rd_fast; reg WRSR_EN = 1'b0; reg LOCKSECID_FLAG = 1'b0; // Sector is protect if Sec_Prot(SecNum) = '1' reg [SecNum:0] Sec_Prot = 2048'b0; reg [Block32Num:0] Block32_Prot = 256'b0; reg [Block64Num:0] Block64_Prot = 128'b0; //Status register reg[7:0] Status_reg = 8'b0; reg[7:0] Status_reg_in = 8'b0; wire BPL; wire SEC; wire [3:0]BP; wire WEL; wire BUSY; assign BPL = Status_reg[7]; assign SEC = Status_reg[6]; assign BP = Status_reg[5:2]; assign WEL = Status_reg[1]; assign BUSY = Status_reg[0]; // timing check violation reg Viol = 1'b0; /////////////////////////////////////////////////////////////////////////////// //Interconnect Path Delay Section /////////////////////////////////////////////////////////////////////////////// buf (SCK_ipd, SCK); buf (SI_ipd, SI); buf (SO_ipd, SO); buf (WPNeg_ipd, WPNeg); buf (RSTNeg_ipd, RSTNeg); buf (CENeg_ipd, CENeg); /////////////////////////////////////////////////////////////////////////////// // Propagation delay Section /////////////////////////////////////////////////////////////////////////////// nmos (SO, SO_z , 1); nmos (SI, SI_z , 1); wire deg_pin; wire deg_sin; wire slow; wire fast; wire slow_io; wire fast_io; wire fast_sck; wire power; wire hold_pin_act; wire rst_pin_act; wire rst_rd; wire rst_pg; wire rst_ers; assign power = PoweredUp; assign hold_pin_act = HOLD_EN; assign rst_pin_act = ~HOLD_EN; assign slow = rd_slow || (deg_sin && dual_io); assign fast = rd_fast || (deg_sin && dual); assign slow_io = dual_io && deg_pin; assign fast_sck = rd_fast || dual; assign rst_rd = ~HOLD_EN && ~PRESET && ~ERESET; assign rst_pg = ~HOLD_EN && PRESET; assign rst_ers =~HOLD_EN && ERESET; specify // tpd delays: propagation delays (pin-to-pin delay within a component) specparam tpd_CENeg_SO =1; specparam tpd_SCK_SO_slow =1; // tV (33MHZ) \ specparam tpd_SCK_SO_dual_io =1; // tV (50MHZ) \ specparam tpd_SCK_SO_fast =1; // tV (75/80MHz)\ specparam tpd_HOLDNeg_SO =1; specparam tpd_RSTNeg_SO =1; //tsetup values: setup times specparam tsetup_CENeg_SCK =1; // tCES, tCHS / specparam tsetup_HOLDNeg_SCK =1; // tHLS, tHHS / specparam tsetup_SI_SCK_slow =1; // tDS (33/50MHz) / specparam tsetup_SI_SCK_fast =1; // tDS (75/80MHz) / //thold values: hold times specparam thold_CENeg_SCK =1; // tCEH, tCHH / specparam thold_HOLDNeg_SCK =1; // tHLH, tHHH / specparam thold_SI_SCK_slow =1; // tDH (33/50MHz) / specparam thold_SI_SCK_fast =1; // tDH (75/80MHz) / specparam thold_CENeg_RSTNeg_rd =1; // tRECR specparam thold_CENeg_RSTNeg_pg =1; // tRECP specparam thold_CENeg_RSTNeg_ers =1; // tRECE // tpw values: pulse width specparam tpw_SCK_rd_posedge =1; // tSCKH (33MHz) specparam tpw_SCK_rd_negedge =1; // tSCKL (33MHz) specparam tpw_SCK_dual_io_posedge =1; // tSCKH (50MHz) specparam tpw_SCK_dual_io_negedge =1; // tSCKL (50MHz) specparam tpw_SCK_fast_rd_posedge =1; // tSCKH (75/80MHz) specparam tpw_SCK_fast_rd_negedge =1; // tSCKL (75/80MHz) specparam tpw_CENeg_posedge =1; // tCPH specparam tpw_RSTNeg_negedge =1; // tRST // tperiod min (calculated as 1/max freq) specparam tperiod_SCK_rd =1; // tCLK (33MHz) specparam tperiod_SCK_dual_io =1; // tCLK (50MHz) specparam tperiod_SCK_dual_rd =1; // tCLK (75MHz) specparam tperiod_SCK_fast_rd =1; // tCLK (80MHz) // tdevice values: values for internal delays `ifdef SPEEDSIM // VDD Min to Read/Write Operation (Power-up time) specparam tdevice_PowerUp = 100e6; // Sector Erase Operation specparam tdevice_SectorErase = 25e7; // Block Erase Operation specparam tdevice_BlockErase = 25e7; // Chip Erase Operation specparam tdevice_ChipErase = 50e7; // Page Program Operation specparam tdevice_PageProgram = 2.5e7; // Program User Security ID area Time specparam tdevice_ProgramSecID = 1e7; `else // VDD Min to Read/Write Operation (Power-up time) specparam tdevice_PowerUp = 100e6; //tPU = 100us // Sector Erase Operation specparam tdevice_SectorErase = 25e9; //tSE = 25ms // Block Erase Operation specparam tdevice_BlockErase = 25e9; //tBE = 25ms // Chip Erase Operation specparam tdevice_ChipErase = 50e9; //tSCE = 50ms // Page Program Operation specparam tdevice_PageProgram = 2.5e9; //tPP = 2.5ms // Program User Security ID area Time specparam tdevice_ProgramSecID = 1e9; //tPSID = 1ms `endif//SPEEDSIM /////////////////////////////////////////////////////////////////////////////// // Input Port Delays don't require Verilog description /////////////////////////////////////////////////////////////////////////////// // Path delays // /////////////////////////////////////////////////////////////////////////////// if (CENeg) (CENeg => SO) = tpd_CENeg_SO; if (dual && CENeg)(CENeg => SI) = tpd_CENeg_SO; if (dual_io && CENeg)(CENeg => SI) = tpd_CENeg_SO; if (rd_slow) (SCK => SO) = tpd_SCK_SO_slow; if (dual_io) (SCK => SO) = tpd_SCK_SO_dual_io; if (dual_io && deg_sin) (SCK => SI) = tpd_SCK_SO_dual_io; if (rd_fast || dual) (SCK => SO) = tpd_SCK_SO_fast; if (dual) (SCK => SI) = tpd_SCK_SO_fast; if (HOLD_EN) (RSTNeg => SO) = tpd_HOLDNeg_SO; if (HOLD_EN && deg_sin) (RSTNeg => SI) = tpd_HOLDNeg_SO; if (~RST && ~RSTNeg) (RSTNeg => SO) = tpd_RSTNeg_SO; /////////////////////////////////////////////////////////////////////////////// // Timing Violation // /////////////////////////////////////////////////////////////////////////////// $setup ( CENeg , posedge SCK &&& power, tsetup_CENeg_SCK, Viol); $setup ( RSTNeg , posedge SCK &&& hold_pin_act, tsetup_HOLDNeg_SCK,Viol); $setup ( SI , posedge SCK &&& slow, tsetup_SI_SCK_slow,Viol); $setup ( SI , posedge SCK &&& fast, tsetup_SI_SCK_fast,Viol); $setup ( SO , posedge SCK &&& slow_io, tsetup_SI_SCK_slow,Viol); $hold ( posedge SCK&&& power, CENeg , thold_CENeg_SCK, Viol); $hold ( posedge SCK &&& hold_pin_act, RSTNeg, thold_HOLDNeg_SCK,Viol); $hold ( posedge SCK &&& slow, SI, thold_SI_SCK_slow,Viol); $hold ( posedge SCK &&& fast, SI, thold_SI_SCK_fast,Viol); $hold ( posedge SCK &&& slow_io,SO, thold_SI_SCK_slow,Viol); $hold ( posedge RSTNeg &&& rst_rd, negedge CENeg, thold_CENeg_RSTNeg_rd,Viol); $hold ( posedge RSTNeg &&& rst_pg, negedge CENeg, thold_CENeg_RSTNeg_pg,Viol); $hold ( posedge RSTNeg &&& rst_ers, negedge CENeg, thold_CENeg_RSTNeg_ers,Viol); $width ( posedge SCK &&& rd , tpw_SCK_rd_posedge); $width ( negedge SCK &&& rd , tpw_SCK_rd_negedge); $width ( posedge SCK &&& dual_io_rd, tpw_SCK_dual_io_posedge); $width ( negedge SCK &&& dual_io_rd, tpw_SCK_dual_io_negedge); $width ( posedge SCK &&& fast_sck , tpw_SCK_fast_rd_posedge); $width ( negedge SCK &&& fast_sck , tpw_SCK_fast_rd_negedge); $width ( posedge CENeg , tpw_CENeg_posedge); $width ( negedge RSTNeg &&& rst_pin_act, tpw_RSTNeg_negedge); $period (posedge SCK &&& rd , tperiod_SCK_rd); $period (posedge SCK &&& dual_rd , tperiod_SCK_dual_rd); $period (posedge SCK &&& dual_io_rd, tperiod_SCK_dual_io); $period (posedge SCK &&& fast_rd , tperiod_SCK_fast_rd); endspecify /////////////////////////////////////////////////////////////////////////////// // Main Behavior Block // /////////////////////////////////////////////////////////////////////////////// // FSM states parameter IDLE = 4'd0; parameter RESET = 4'd1; parameter SECTOR_ERS = 4'd2; parameter BLOCK32_ERS = 4'd3; parameter BLOCK64_ERS = 4'd4; parameter CHIP_ERS = 4'd5; parameter PAGE_PG = 4'd6; parameter SECID_PG = 4'd7; parameter LOCK_SECID = 4'd8; reg [3:0] current_state = RESET; reg [3:0] next_state = RESET; // Instruction type parameter NONE = 6'd0; parameter WREN = 6'd1; // Write Enable parameter WRDI = 6'd2; // Write Disable parameter READ = 6'd3; // Read parameter FAST_READ = 6'd4; // High Speed Read parameter RDDO = 6'd5; // Fast-Read Dual-Output parameter RDDIO = 6'd6; // Fast-Read Dual I/O parameter RDSR = 6'd7; // Read Status Register parameter RDID = 6'd8; // Read-ID parameter RDIDJ = 6'd9; // JEDEC-ID Read parameter RDSID = 6'd10; // Read Security ID parameter PSID = 6'd11; // Program User Security ID area parameter LSID = 6'd12; // Lockout Security ID Programming parameter SE = 6'd13; // Sector Erase parameter BE_32 = 6'd14; // Block Erase 32 kB parameter BE_64 = 6'd15; // Block Erase 64 kB parameter CE = 6'd16; // Chip Erase parameter PP = 6'd17; // Page Program parameter DUAL_PP = 6'd18; // Dual-Input Page Program parameter EWSR = 6'd19; // Enable Write Status Register parameter WRSR = 6'd20; // Write Status Register parameter EHLD = 6'd21; // Enable HOLD# pin functionality reg [5:0] Instruct = NONE; //Bus cycle state parameter STAND_BY = 3'd0; parameter OPCODE_BYTE = 3'd1; parameter ADDRESS_BYTES = 3'd2; parameter DUMMY_BYTES = 3'd3; parameter DATA_BYTES = 3'd4; reg [2:0] bus_cycle_state = STAND_BY; reg deq_pin; always @(SO_in, SOut_z) begin if (SO_in === SOut_z) deq_pin=1'b0; else deq_pin=1'b1; end // check when data is generated from model to avoid setup/hold check in // this occasion assign deg_pin=deq_pin; reg deq_sin; always @(SI_in, SIOut_z) begin if (SI_in === SIOut_z) deq_sin=1'b0; else deq_sin=1'b1; end // check when data is generated from model to avoid setuphold check in // this occasion assign deg_sin=deq_sin; // /////////////////////////////////////////////////////////////////////////// // // Power Up time // /////////////////////////////////////////////////////////////////////////// initial begin PoweredUp = 1'b0; #tdevice_PowerUp PoweredUp = 1'b1; end // /////////////////////////////////////////////////////////////////////////// // // Memory Initialization // /////////////////////////////////////////////////////////////////////////// // initialize memory and load preload files if any initial begin: InitMemory integer i; // /////////////////////////////////////////////////////////////////////// // // Memory Preload // /////////////////////////////////////////////////////////////////////// for (i=0;i<=AddrRANGE;i=i+1) begin Mem[i] = MaxData; end if ((UserPreload) && !(mem_file_name == "none")) begin // sst25vf064c.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 // /////////////////////////////////////////////////////////////////////// // //sst25vf064c_SecID memory file // /////////////////////////////////////////////////////////////////////// for (i=SecIDLoAddr;i<=SecIDHiAddr;i=i+1) begin SecIDMem[i] = MaxData; end if (UserPreload && !(SecID_file_name == "none")) begin // / - comment // @aa - stands for address // dd -
is byte to be written at OTPMem(aa++) // (aa is incremented at every load) // only first 1-3 columns are loaded. NO empty lines !!!!!!!!!!!!!!!! $readmemh(SecID_file_name,SecIDMem); end end // /////////////////////////////////////////////////////////////////////////// // // sequential process for FSM state transition // /////////////////////////////////////////////////////////////////////////// always @(next_state or PoweredUp or falling_edge_RST) begin: StateTransition if (PoweredUp) begin if (RSTNeg) begin current_state = next_state; reseted = 1'b1; end else if (falling_edge_RST && ~RSTNeg) begin current_state = RESET; reseted = 1'b0; end end else begin current_state = RESET; reseted = 1'b0; end end always @(PoweredUp or falling_edge_CENeg_ipd) begin:CheckCEOnPowerUP if ((~PoweredUp) && falling_edge_CENeg_ipd) $display ("Device is selected during Power Up"); end // /////////////////////////////////////////////////////////////////////////// // // Internal Delays // /////////////////////////////////////////////////////////////////////////// // /////////////////////////////////////////////////////////////////////////// // // write cycle decode // /////////////////////////////////////////////////////////////////////////// integer opcode_cnt = 0; integer addr_cnt = 0; integer dummy_cnt = 0; integer data_cnt = 0; integer bit_cnt = 0; integer dual_data_in[0:1023]; reg [7:0] opcode; reg [7:0] opcode_in; reg [HiAddrBit:0] addr_bytes = 24'b0; reg [23:0] Address_in = 24'b0; reg [2047:0] Data_in = 2048'b0; reg [1:0] dual_nybble; reg [1:0] dual_slv; reg [7:0] Byte_slv; always @(falling_edge_CENeg_ipd or rising_edge_CENeg_ipd or rising_edge_SCK_ipd or falling_edge_SCK_ipd) begin: Buscycle integer i; integer j; integer k; if (falling_edge_CENeg_ipd) begin if (bus_cycle_state==STAND_BY) begin Instruct = NONE; write = 1'b1; opcode_cnt = 0; addr_cnt = 0; dummy_cnt = 0; data_cnt = 0; bus_cycle_state = OPCODE_BYTE; end end if (rising_edge_SCK_ipd) begin if (~CENeg_ipd) begin hold_act = HOLD_EN && ~(RSTNeg_ipd); case (bus_cycle_state) OPCODE_BYTE : begin if (~(hold_act)) 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'b00000100 : // 04h begin Instruct = WRDI; 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 = RDDO; bus_cycle_state = ADDRESS_BYTES; end 8'b10111011 : // BBh begin Instruct = RDDIO; bus_cycle_state = ADDRESS_BYTES; end 8'b00000101 : // 05h begin Instruct = RDSR; bus_cycle_state = DATA_BYTES; end 8'b10010000 : // 90h begin Instruct = RDID; bus_cycle_state = ADDRESS_BYTES; end 8'b10101011 : // ABh begin Instruct = RDID; bus_cycle_state = ADDRESS_BYTES; end 8'b10011111 : // 9Fh begin Instruct = RDIDJ; bus_cycle_state = DATA_BYTES; end 8'b10001000 : // 88h begin Instruct = RDSID; bus_cycle_state = ADDRESS_BYTES; end 8'b10100101 : // A5h begin Instruct = PSID; bus_cycle_state = ADDRESS_BYTES; end 8'b10000101 : // 85h begin Instruct = LSID; bus_cycle_state = DATA_BYTES; 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 : // C7h begin Instruct = CE; bus_cycle_state = DATA_BYTES; end 8'b01100000 : // 60h begin Instruct = CE; bus_cycle_state = DATA_BYTES; end 8'b00000010 : // 02h begin Instruct = PP; bus_cycle_state = ADDRESS_BYTES; end 8'b10100010 : // A2h begin Instruct = DUAL_PP; bus_cycle_state = ADDRESS_BYTES; end 8'b01010000 : // 50h begin Instruct = EWSR; bus_cycle_state = DATA_BYTES; end 8'b00000001 : // 01h begin Instruct = WRSR; bus_cycle_state = DATA_BYTES; end 8'b10101010 : // AAh begin Instruct = EHLD; bus_cycle_state = DATA_BYTES; end endcase end end end //end of OPCODE BYTE ADDRESS_BYTES : begin if (Instruct == RDDIO && ~(hold_act)) begin //Odd address bits A23 through A1 are //input on SIO1(SO) and even address bits //A22 through A0 are input on SIO0(SI). 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 == 12) begin addr_cnt = 0; for (i=23;i>=23-HiAddrBit;i=i-1) begin addr_bytes[23-i] = Address_in[i]; end Address = addr_bytes; change_addr = 1'b1; #1 change_addr = 1'b0; bus_cycle_state = DUMMY_BYTES; end end else if ((Instruct == RDSID || Instruct == PSID) && ~(hold_act)) begin Address_in[addr_cnt] = SI_ipd; addr_cnt = addr_cnt + 1; if (addr_cnt == BYTE) begin for (i=7;i>=0;i=i-1) begin addr_bytes[23:8] = 16'h0000; addr_bytes[7-i] = Address_in[i]; end Address = addr_bytes; change_addr = 1'b1; #1 change_addr = 1'b0; if (Instruct == RDSID) bus_cycle_state = DUMMY_BYTES; else bus_cycle_state = DATA_BYTES; end end else if (~(hold_act)) begin Address_in[addr_cnt] = SI_ipd; addr_cnt = addr_cnt + 1; if (addr_cnt == 3*BYTE) begin for (i=23;i>=23-HiAddrBit;i=i-1) begin addr_bytes[23-i] = Address_in[i]; end Address = addr_bytes; change_addr = 1'b1; #1 change_addr = 1'b0; if (Instruct == FAST_READ || Instruct == RDDO) bus_cycle_state = DUMMY_BYTES; else bus_cycle_state = DATA_BYTES; end end end //end of ADDRESS_BYTES DUMMY_BYTES : begin if (Instruct == RDDIO && ~(hold_act)) begin dummy_cnt = dummy_cnt + 1; if (dummy_cnt == BYTE/2) bus_cycle_state = DATA_BYTES; end else if(~(hold_act)) begin dummy_cnt = dummy_cnt + 1; if (dummy_cnt == BYTE) bus_cycle_state = DATA_BYTES; end end //end of DUMMY_BYTES DATA_BYTES : begin if (Instruct==DUAL_PP) begin dual_nybble = {SO_in, SI_in}; if(data_cnt > 1023) begin //In case of dual mode and DUAL_PP, //if more than 256 bytes are sent to the device if(bit_cnt == 0) begin for(i=0;i<=1019;i=i+1) begin dual_data_in[i] = dual_data_in[i+4]; end end dual_data_in[1020 + bit_cnt] = dual_nybble; bit_cnt = bit_cnt + 1; if(bit_cnt == 4) begin bit_cnt = 0; end data_cnt = data_cnt + 1; end else begin if(dual_nybble !== 2'bZZ) begin dual_data_in[data_cnt] = dual_nybble; end data_cnt = data_cnt + 1; if((data_cnt % 4)== 0) Byte_number = data_cnt/4 -1; end end else if(~(hold_act)) 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 end endcase end end if (falling_edge_SCK_ipd) begin if ((bus_cycle_state == DATA_BYTES) && (~CENeg_ipd)) begin if ((Instruct == READ || Instruct == FAST_READ || Instruct == RDDO || Instruct == RDDIO || Instruct == RDSR || Instruct == RDID || Instruct == RDIDJ || Instruct == RDSID) && ~(hold_act)) begin read_out = 1'b1; #10 read_out = 1'b0; end end end if (rising_edge_CENeg_ipd) begin if (bus_cycle_state == DATA_BYTES) begin bus_cycle_state = STAND_BY; case (Instruct) WREN, WRDI, SE, BE_32, BE_64, CE, EWSR, EHLD, LSID: begin if (data_cnt == 0) write = 1'b0; end WRSR : begin if (data_cnt == 8) begin write = 1'b0; for(i=0;i<=7;i=i+1) begin Status_reg_in[i]= Data_in[7-i]; end end end PP : begin if(((data_cnt % 8) == 0) && data_cnt > 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 DUAL_PP : begin if(((data_cnt % 4) == 0) && data_cnt > 0) begin write = 1'b0; for(i=0;i<=255;i=i+1) begin for(j=3;j>=0;j=j-1) begin dual_slv = dual_data_in[(i*4)+(3-j)]; if (j==3) Byte_slv[7:6] = dual_slv; else if (j==2) Byte_slv[5:4] = dual_slv; else if (j==1) Byte_slv[3:2] = dual_slv; else Byte_slv[1:0] = dual_slv; end WByte[i] = Byte_slv; end if(data_cnt > 1024) Byte_number = 255; else Byte_number = ((data_cnt/4)-1); end end PSID : begin if((data_cnt > 0) && (data_cnt % 8 == 0)) begin write = 1'b0; for(i=0;i<=23;i=i+1) begin for(j=7;j>=0;j=j-1) begin Byte_slv[j] = Data_in[(i*8) + (7-j)]; end WSIDByte[i] = Byte_slv; end Byte_number = data_cnt/8 - 1; end end endcase end end end // ///////////////////////////////////////////////////////////////////////// // // Timing control for the Program Operations // // start // ///////////////////////////////////////////////////////////////////////// time duration_program; event pdone_event; always @(PSTART) begin if (PSTART && PDONE) begin if (Instruct == PSID || Instruct == LSID) begin duration_program = tdevice_ProgramSecID; end else begin duration_program = tdevice_PageProgram; end PDONE = 1'b0; ->pdone_event; end end always @(pdone_event) begin:pdone_process PDONE = 1'b0; #duration_program PDONE = 1'b1; end // ///////////////////////////////////////////////////////////////////////// // // Timing control for the Erase Operations // ///////////////////////////////////////////////////////////////////////// time duration_erase; event edone_event; always @(ESTART) begin: erase if (ESTART && EDONE) begin if (Instruct == BE_32 || Instruct == BE_64) begin duration_erase = tdevice_BlockErase; end else if (Instruct == SE) begin duration_erase = tdevice_SectorErase; end else begin duration_erase = tdevice_ChipErase; end EDONE = 1'b0; ->edone_event; end end always @(edone_event) begin : edone_process EDONE = 1'b0; #duration_erase EDONE = 1'b1; end // /////////////////////////////////////////////////////////////////////////// // // Reset Timing // /////////////////////////////////////////////////////////////////////////// always @(RSTNeg) begin if (~HOLD_EN) RST <= #99000 RSTNeg; end always @(posedge reseted) begin disable pdone_process; disable edone_process; PDONE = 1'b1; EDONE = 1'b1; end // /////////////////////////////////////////////////////////////////////////// // // Main Behavior Process // // combinational process for next state generation // /////////////////////////////////////////////////////////////////////////// integer sect = 0; integer block_32 = 0; integer block_64 = 0; always @(posedge RSTNeg) begin: StateGen1 if (current_state==RESET) begin next_state = IDLE; end end always @(negedge write or negedge reseted) begin: StateGen2 if (reseted!=1'b1) next_state = current_state; else if (~write) case (current_state) IDLE : begin if ((Instruct == PP || Instruct == DUAL_PP) && WEL == 1) begin sect = Address / 16'h1000; if (Sec_Prot[sect] == 1'b0) next_state = PAGE_PG; end else if (Instruct == PSID && WEL == 1) begin if ((Address>=SecIDLoAddrPg && Address<=SecIDHiAddr) && SEC == 0) next_state = SECID_PG; end else if (Instruct == LSID && WEL == 1) begin next_state = LOCK_SECID; end else if (Instruct == SE && WEL == 1) begin sect = Address / (SecSize+1); if (Sec_Prot[sect] == 1'b0) next_state = SECTOR_ERS; end else if (Instruct == BE_32 && WEL == 1) begin block_32 = Address / (BlockSize_32+1); if (Block32_Prot[block_32] == 1'b0) next_state = BLOCK32_ERS; end else if (Instruct == BE_64 && WEL == 1) begin block_64 = Address / (BlockSize_64+1); if (Block64_Prot[block_64] == 1'b0) next_state = BLOCK64_ERS; end else if (Instruct == CE && WEL == 1) begin if (BP == 4'b0000) next_state = CHIP_ERS; end else next_state = IDLE; end endcase end always @(posedge PDONE) begin: StateGen3 if (current_state==PAGE_PG || current_state==SECID_PG || current_state==LOCK_SECID) begin next_state = IDLE; end end always @(posedge EDONE) begin: StateGen4 if (current_state==SECTOR_ERS || current_state==BLOCK32_ERS || current_state==BLOCK64_ERS || current_state==CHIP_ERS) begin next_state = IDLE; end end // /////////////////////////////////////////////////////////////////////////// // // FSM Output generation and general functionality // /////////////////////////////////////////////////////////////////////////// integer Addr; integer Addr_tmp; integer WData [0:255]; integer WSECIDData [0:23]; always @(posedge read_out) begin if (PoweredUp == 1'b1) ->oe_event; end always @(oe_event) begin oe = 1'b1; #1000 oe = 1'b0; end always @(posedge change_addr) begin read_addr = Address; end always @(Instruct) begin read_cnt = 0; dual = 1'b0; dual_io = 1'b0; rd_fast = 1'b1; rd_slow = 1'b0; PRESET = 1'b0; ERESET = 1'b0; end always @(posedge PoweredUp) begin //the default condition after power-up //The RST#/HOLD# pin functionality returns as a reset pin (RST#) //after the power on. HOLD_EN = 1'b0; //The BUSY bit is cleared. Status_reg[0] = 0; //The WEL bit is cleared. Status_reg[1] = 0; //The BP3-0 bits in Status Register will be reset to //binary 1111 after power-up Status_reg[2] = 1'b1;// BP0 Status_reg[3] = 1'b1;// BP1 Status_reg[4] = 1'b1;// BP2 Status_reg[5] = 1'b1;// BP3 // The Security ID status will always be ‘1’ at power-up after a // successful execution of the Lockout SID instruction; otherwise, //the default at power up is ‘0’. if (LOCKSECID_FLAG == 0 ) Status_reg[6] = 1'b0; else Status_reg[6] = 1'b1; //The BPL bit is cleared. Status_reg[7] = 0; change_BP = 1'b1; #1 change_BP = 1'b0; end always @(oe or current_state) begin case (current_state) IDLE : begin if (oe) begin if (Instruct == RDSR) begin //Read Status Register SOut_zd = Status_reg[7-read_cnt]; read_cnt = read_cnt + 1; if (read_cnt == 8) read_cnt = 0; end else if (Instruct == READ || Instruct == FAST_READ) begin //Read Memory array if (Instruct == READ) begin dual = 1'b0; dual_io = 1'b0; rd_fast = 1'b0; rd_slow = 1'b1; end else begin dual = 1'b0; dual_io = 1'b0; rd_fast = 1'b1; rd_slow = 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 == RDDO || Instruct == RDDIO) begin //Read Memory array if (Instruct == RDDIO) begin dual = 1'b0; dual_io = 1'b1; rd_fast = 1'b0; rd_slow = 1'b0; end else begin dual = 1'b1; dual_io = 1'b0; rd_fast = 1'b0; rd_slow = 1'b0; end 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 = 4'bx; SIOut_zd = 4'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 if (Instruct == RDID) begin // Read ID if (read_addr % 2 == 0) begin data_out[7:0] = Manuf_ID; SOut_zd = data_out[7-read_cnt]; read_cnt = read_cnt + 1; if (read_cnt == 8) begin read_cnt = 0; read_addr = read_addr + 1; end end else begin data_out[7:0] = DeviceID; SOut_zd = data_out[7-read_cnt]; read_cnt = read_cnt + 1; if (read_cnt == 8) begin read_cnt = 0; read_addr = 0; end end end else if (Instruct == RDIDJ) begin ident_out = {Jedec_ID,DeviceID1,DeviceID2}; SOut_zd = ident_out[23-read_cnt]; read_cnt = read_cnt + 1; if (read_cnt == 24) read_cnt = 0; end else if (Instruct == RDSID) begin if(read_addr>=SecIDLoAddr && read_addr<=SecIDHiAddr) begin //Read Security ID array data_out = SecIDMem[read_addr]; SOut_zd = data_out[7-read_cnt]; read_cnt = read_cnt + 1; if (read_cnt == 8) begin read_cnt = 0; if (read_addr == SecIDHiAddr) read_addr = 0; else read_addr = read_addr + 1; end end end end end PAGE_PG, SECID_PG, LOCK_SECID, SECTOR_ERS, BLOCK32_ERS, BLOCK64_ERS, CHIP_ERS : begin if (oe && Instruct == RDSR) begin //Read Status Register SOut_zd = Status_reg[7-read_cnt]; read_cnt = read_cnt + 1; if (read_cnt == 8) read_cnt = 0; end end endcase end always @(negedge write) begin : Output_generation integer i; if (current_state == IDLE) begin if (Instruct == WREN) //The WEL bit is set. Status_reg[1] = 1'b1; else if (Instruct == WRDI) //The WEL bit is cleared. Status_reg[1] = 1'b0; else if (Instruct == EWSR) WRSR_EN = 1'b1; else if ((Instruct == WRSR) && (WEL == 1 || WRSR_EN == 1)) if (~(BPL && ~WPNeg_ipd)) begin WRSR_EN = 1'b0; Status_reg[1] = 1'b0;//WEL Status_reg[2] = Status_reg_in[2];// BP0 Status_reg[3] = Status_reg_in[3];// BP1 Status_reg[4] = Status_reg_in[4];// BP2 Status_reg[5] = Status_reg_in[5];// BP3 Status_reg[7] = Status_reg_in[7];// BPL change_BP = 1'b1; #1 change_BP = 1'b0; end else Status_reg[1] = 1'b0;//WEL else if (Instruct == EHLD) HOLD_EN = 1'b1; else if ((Instruct == PP || Instruct == DUAL_PP) && WEL == 1) begin if (Instruct == DUAL_PP) begin dual = 1'b0; dual_io = 1'b1; rd_fast = 1'b0; rd_slow = 1'b0; end sect = Address / 16'h1000; if (Sec_Prot[sect] == 1'b0) begin PSTART = 1'b1; PSTART <= #1 1'b0; PRESET = 1'b1; Status_reg[0] = 1'b1;//BUSY 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_reg[1] = 1'b0;//WEL end else if (Instruct == PSID && WEL == 1) begin if ((Address>=SecIDLoAddrPg && Address<=SecIDHiAddr) && SEC == 0) begin PSTART = 1'b1; PSTART <= #1 1'b0; PRESET = 1'b1; Status_reg[0] = 1'b1;//BUSY Addr = Address; Addr_tmp= Address; wr_cnt = Byte_number; for (i=wr_cnt;i>=0;i=i-1) begin if (Viol != 0) WSECIDData[i] = -1; else WSECIDData[i] = WSIDByte[i]; end end else if (Address < SecIDLoAddrPg || Address > SecIDHiAddr) begin Status_reg[1] = 1'b0; if (Address < SecIDLoAddrPg) begin $display ("Given address is in "); $display ("reserved Security ID address range"); end else begin $display ("Given address is out "); $display ("of Security ID address range"); end end else begin Status_reg[1] = 1'b0;//WEL $display ("SEC = '1' "); $display ("Security ID space is locked!"); end end else if (Instruct == LSID && WEL == 1) begin PSTART = 1'b1; PSTART <= #1 1'b0; PRESET = 1'b1; Status_reg[0] = 1'b1;//BUSY end else if (Instruct == SE && WEL == 1) begin sect = Address / (SecSize+1); if (Sec_Prot[sect] == 1'b0) begin ESTART = 1'b1; ESTART <= #1 1'b0; ERESET = 1'b1; Status_reg[0] = 1'b1; Addr = Address; end else begin Status_reg[1] = 1'b0;//WEL $display ("Erase operation to a protected memory "); $display ("area is not allowed "); end end else if (Instruct == BE_32 && WEL == 1) begin block_32 = Address / (BlockSize_32+1); if (Block32_Prot[block_32] == 1'b0) begin ESTART = 1'b1; ESTART <= #1 1'b0; ERESET = 1'b1; Status_reg[0] = 1'b1; Addr = Address; end else begin Status_reg[1] = 1'b0;//WEL $display ("Erase operation to a protected memory "); $display ("area is not allowed!"); end end else if (Instruct == BE_64 && WEL == 1) begin block_64 = Address / (BlockSize_64+1); if (Block64_Prot[block_64] == 1'b0) begin ESTART = 1'b1; ESTART <= #1 1'b0; ERESET = 1'b1; Status_reg[0] = 1'b1; Addr = Address; end else begin Status_reg[1] = 1'b0;//WEL $display ("Erase operation to a protected memory "); $display ("area is not allowed!"); end end else if (Instruct == CE && WEL == 1) begin if (BP == 4'b0000) begin ESTART = 1'b1; ESTART <= #1 1'b0; Status_reg[0] = 1'b1; Addr = Address; end else begin Status_reg[1] = 1'b0;//WEL $display ("Erase operation to a protected memory "); $display ("area is not allowed!"); end end end end always @(current_state or PDONE) begin: PROGRAM_OUTPUT integer i; integer j; case (current_state) PAGE_PG : begin if (~PDONE) begin ADDRHILO_PP(AddrLo, AddrHi, Addr); cnt = 0; for (i=0;i<=wr_cnt;i=i+1) begin new_int = WData[i]; old_int = Mem[Addr + i - cnt]; 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 Mem[Addr + i - cnt] = - 1; if ((Addr + i) == AddrHi) begin Addr = AddrLo; cnt = i + 1; end end end cnt = 0; if (PDONE) begin Status_reg[0] = 1'b0; // BUSY Status_reg[1] = 1'b0; // WEL for (i=0;i<=wr_cnt;i=i+1) begin Mem[Addr_tmp + i - cnt] = WData[i]; if ((Addr_tmp + i) == AddrHi) begin Addr_tmp = AddrLo; cnt = i + 1; end end end end SECID_PG : begin if (~PDONE) begin if (Address + wr_cnt <= SecIDHiAddr) begin for (i=0;i<=wr_cnt;i=i+1) begin new_int = WSECIDData[i]; old_int = SecIDMem[Addr + i]; if (new_int > -1) begin new_bit = new_int; if (old_int > -1) begin old_bit = old_int; for(j=0;j<=7;j=j+1) begin if (~old_bit[j]) new_bit[j] = 1'b0; end new_int = new_bit; end WSECIDData[i] = new_int; end else begin WSECIDData[i] = -1; end SecIDMem[Addr + i] = -1; end end else begin $display ("Programming will reach over "); $display ("address limit of SecID array"); end end if (PDONE) begin Status_reg[0] = 1'b0; // BUSY Status_reg[1] = 1'b0; // WEL for(i=0;i<=wr_cnt;i=i+1) begin SecIDMem[Addr_tmp + i] = WSECIDData[i]; end end end LOCK_SECID : begin if (PDONE) begin Status_reg[0] = 1'b0; // BUSY Status_reg[1] = 1'b0; // WEL Status_reg[6] = 1'b1; // SEC LOCKSECID_FLAG = 1'b1; end end endcase end always @(current_state or EDONE) begin: ERASE_OUTPUT integer i; case (current_state) SECTOR_ERS : begin ADDRHILO_SEC(AddrLo, AddrHi, Addr); for (i=AddrLo;i<=AddrHi;i=i+1) begin Mem[i] = -1; end if (EDONE) begin Status_reg[0] = 1'b0; // BUSY Status_reg[1] = 1'b0; // WEL for (i=AddrLo;i<=AddrHi;i=i+1) begin Mem[i] = MaxData; end end end BLOCK32_ERS : begin ADDRHILO_B32(AddrLo, AddrHi, Addr); for (i=AddrLo;i<=AddrHi;i=i+1) begin Mem[i] = -1; end if (EDONE) begin Status_reg[0] = 1'b0; // BUSY Status_reg[1] = 1'b0; // WEL for (i=AddrLo;i<=AddrHi;i=i+1) begin Mem[i] = MaxData; end end end BLOCK64_ERS : begin ADDRHILO_B64(AddrLo, AddrHi, Addr); for (i=AddrLo;i<=AddrHi;i=i+1) begin Mem[i] = -1; end if (EDONE) begin Status_reg[0] = 1'b0; // BUSY Status_reg[1] = 1'b0; // WEL for (i=AddrLo;i<=AddrHi;i=i+1) begin Mem[i] = MaxData; end end end CHIP_ERS : begin for (i=0;i<=AddrRANGE;i=i+1) begin Mem[i] = -1; end if (EDONE) begin Status_reg[0] = 1'b0; // BUSY Status_reg[1] = 1'b0; // WEL for (i=0;i<=AddrRANGE;i=i+1) begin Mem[i] = MaxData; end end end endcase end always @(current_state) begin: RESET_OUTPUT if (current_state == RESET) begin //The BUSY bit is cleared. Status_reg[0] = 0; //The WEL bit is cleared. Status_reg[1] = 0; //The BP3-0 bits in Status Register will be reset to //binary 1111 after power-up Status_reg[2] = 1'b1;// BP0 Status_reg[3] = 1'b1;// BP1 Status_reg[4] = 1'b1;// BP2 Status_reg[5] = 1'b1;// BP3 //The BPL bit is cleared. Status_reg[7] = 0; change_BP = 1'b1; #1 change_BP = 1'b0; end end // /////////////////////////////////////////////////////////////////////////// // // Output Control // /////////////////////////////////////////////////////////////////////////// always @(CENeg_ipd) begin if (CENeg_ipd) begin //Output Disable Control SOut_zd = 1'bZ; SIOut_zd = 1'bZ; end end always @(negedge RST) begin if (~RSTNeg) SOut_zd = 1'bZ; end always @(SOut_zd or RSTNeg_ipd or SIOut_zd) begin if (RSTNeg_ipd == 0 && HOLD_EN) 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 // /////////////////////////////////////////////////////////////////////////// // // Protection Registers // ///////////////////////////////////////////////////////////////////////////f always @(posedge change_BP) begin case (Status_reg[5:2]) 4'b0000 : begin Sec_Prot = 2048'h0; Block32_Prot = 256'b0; Block64_Prot = 128'b0; end 4'b0001 : begin Sec_Prot[SecNum : (SecNum+1)*127/128] = {16 {1'b1}}; Sec_Prot[(SecNum+1)*127/128 - 1 : 0] = 2032'h0; Block32_Prot[Block32Num : (Block32Num+1)*127/128] = {2 {1'b1}}; Block32_Prot[(Block32Num+1)*127/128 - 1 : 0] = 254'h0; Block64_Prot[Block64Num : (Block64Num+1)*127/128] = 1'b1; Block64_Prot[(Block64Num+1)*127/128 - 1 : 0] = 127'h0; end 4'b0010 : begin Sec_Prot[SecNum : (SecNum+1)*63/64] = {32 {1'b1}}; Sec_Prot[(SecNum+1)*63/64 - 1 : 0] = 2016'h0; Block32_Prot[Block32Num : (Block32Num+1)*63/64] = {4 {1'b1}}; Block32_Prot[(Block32Num+1)*63/64 - 1 : 0] = 252'h0; Block64_Prot[Block64Num : (Block64Num+1)*63/64] = {2 {1'b1}}; Block64_Prot[(Block64Num+1)*63/64 - 1 : 0] = 126'h0; end 4'b0011 : begin Sec_Prot[SecNum : (SecNum+1)*31/32] = {64 {1'b1}}; Sec_Prot[(SecNum+1)*31/32 - 1 : 0] = 1984'h0; Block32_Prot[Block32Num : (Block32Num+1)*31/32] = {8 {1'b1}}; Block32_Prot[(Block32Num+1)*31/32 - 1 : 0] = 248'h0; Block64_Prot[Block64Num : (Block64Num+1)*31/32] = {4 {1'b1}}; Block64_Prot[(Block64Num+1)*31/32 - 1 : 0] = 124'h0; end 4'b0100 : begin Sec_Prot[SecNum : (SecNum+1)*15/16] = {128 {1'b1}}; Sec_Prot[(SecNum+1)*15/16 - 1 : 0] = 1920'h0; Block32_Prot[Block32Num : (Block32Num+1)*15/16] = {16 {1'b1}}; Block32_Prot[(Block32Num+1)*15/16 - 1 : 0] = 240'h0; Block64_Prot[Block64Num : (Block64Num+1)*15/16] = {8 {1'b1}}; Block64_Prot[(Block64Num+1)*15/16 - 1 : 0] = 120'h0; end 4'b0101 : begin Sec_Prot[SecNum : (SecNum+1)*7/8] = {256 {1'b1}}; Sec_Prot[(SecNum+1)*7/8 - 1 : 0] = 1792'h0; Block32_Prot[Block32Num : (Block32Num+1)*7/8] = {32 {1'b1}}; Block32_Prot[(Block32Num+1)*7/8 - 1 : 0] = 224'h0; Block64_Prot[Block64Num : (Block64Num+1)*7/8] = {16 {1'b1}}; Block64_Prot[(Block64Num+1)*7/8 - 1 : 0] = 112'h0; end 4'b0110 : begin Sec_Prot[SecNum : (SecNum+1)*3/4] = {512 {1'b1}}; Sec_Prot[(SecNum+1)*3/4 - 1 : 0] = 1536'h0; Block32_Prot[Block32Num : (Block32Num+1)*3/4] = {64 {1'b1}}; Block32_Prot[(Block32Num+1)*3/4 - 1 : 0] = 192'h0; Block64_Prot[Block64Num : (Block64Num+1)*3/4] = {32 {1'b1}}; Block64_Prot[(Block64Num+1)*3/4 - 1 : 0] = 96'h0; end 4'b0111 : begin Sec_Prot[SecNum : (SecNum+1)/2] = {1024 {1'b1}}; Sec_Prot[(SecNum+1)/2 - 1 : 0] = 1024'h0; Block32_Prot[Block32Num : (Block32Num+1)/2] = {128 {1'b1}}; Block32_Prot[(Block32Num+1)/2 - 1 : 0] = 128'h0; Block64_Prot[Block64Num : (Block64Num+1)/2] = {64 {1'b1}}; Block64_Prot[(Block64Num+1)/2 - 1 : 0] = 64'h0; end 4'b1000,4'b1001,4'b1010,4'b1011,4'b1100,4'b1101,4'b1110,4'b1111: begin Sec_Prot= {2048 {1'b1}}; Block32_Prot= {256 {1'b1}}; Block64_Prot = {128 {1'b1}}; end endcase end // /////////////////////////////////////////////////////////////////////////// // // functions & tasks // /////////////////////////////////////////////////////////////////////////// // Procedure ADDRHILO_SEC task ADDRHILO_SEC; inout AddrLOW; inout AddrHIGH; input Addr; integer AddrLOW; integer AddrHIGH; integer Addr; integer sector; begin sector = Addr / (SecSize+1); AddrLOW = sector * (SecSize+1); AddrHIGH = sector * (SecSize+1) + SecSize; end endtask // Procedure ADDRHILO_B32 task ADDRHILO_B32; inout AddrLOW; inout AddrHIGH; input Addr; integer AddrLOW; integer AddrHIGH; integer Addr; integer sector; begin AddrLOW = (Address/(BlockSize_32+1))*(BlockSize_32+1); AddrHIGH = (Address/(BlockSize_32+1))*(BlockSize_32+1) + BlockSize_32; end endtask // Procedure ADDRHILO_B64 task ADDRHILO_B64; inout AddrLOW; inout AddrHIGH; input Addr; integer AddrLOW; integer AddrHIGH; integer Addr; integer sector; begin AddrLOW = (Address/(BlockSize_64+1))*(BlockSize_64+1); AddrHIGH = (Address/(BlockSize_64+1))*(BlockSize_64+1) + BlockSize_64; end endtask // Procedure ADDRHILO_PP task ADDRHILO_PP; inout AddrLOW; inout AddrHIGH; input Addr; integer AddrLOW; integer AddrHIGH; integer Addr; integer page; begin page = Addr/12'h100; AddrLOW = page*12'h100; AddrHIGH = page*12'h100 + 8'hFF; end endtask // /////////////////////////////////////////////////////////////////////////// // // edge controll processes // /////////////////////////////////////////////////////////////////////////// always @(negedge CENeg_ipd) begin falling_edge_CENeg_ipd = 1'b1; #1 falling_edge_CENeg_ipd = 1'b0; end always @(posedge CENeg_ipd) begin rising_edge_CENeg_ipd = 1'b1; #10 rising_edge_CENeg_ipd = 1'b0; end always @(posedge SCK_ipd) begin rising_edge_SCK_ipd = 1'b1; #1 rising_edge_SCK_ipd = 1'b0; end always @(negedge SCK_ipd) begin falling_edge_SCK_ipd = 1'b1; #1 falling_edge_SCK_ipd = 1'b0; end always @(negedge RST) begin falling_edge_RST = 1'b1; #1 falling_edge_RST = 1'b0; end endmodule