////////////////////////////////////////////////////////////////////////////// // File name : s19mn512p00.sv ////////////////////////////////////////////////////////////////////////////// // Copyright (C) 2007 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 D.Popovic 07 Mar 09 Initial Release // ////////////////////////////////////////////////////////////////////////////// // PART DESCRIPTION: // // Library: FLASH // Technology: FLASH MEMORY // Part: S19MN512P00 // // Description: MirrorBit Quad Flash Memory 512 Megabit // ////////////////////////////////////////////////////////////////////////////// // Known Bugs: // ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// // MODULE DECLARATION // ////////////////////////////////////////////////////////////////////////////// `timescale 1 ns/1 ns module s19mn512p00 ( IO7 , IO6 , IO5 , IO4 , IO3 , IO2 , IO1 , IO0 , CLE , ALE , CENeg , RENeg , WENeg , WPNeg , RY, PRE ); //////////////////////////////////////////////////////////////////////// // Port / Part Pin Declarations //////////////////////////////////////////////////////////////////////// inout IO7 ; inout IO6 ; inout IO5 ; inout IO4 ; inout IO3 ; inout IO2 ; inout IO1 ; inout IO0 ; input CLE ; input ALE ; input CENeg ; input RENeg ; input WENeg ; input WPNeg ; output RY ; input PRE; // interconnect path delay signals wire IO7_ipd ; wire IO6_ipd ; wire IO5_ipd ; wire IO4_ipd ; wire IO3_ipd ; wire IO2_ipd ; wire IO1_ipd ; wire IO0_ipd ; wire [7 : 0] A; assign A = {IO7_ipd, IO6_ipd, IO5_ipd, IO4_ipd, IO3_ipd, IO2_ipd, IO1_ipd, IO0_ipd }; wire [7 : 0 ] DIn; assign DIn = {IO7_ipd, IO6_ipd, IO5_ipd, IO4_ipd, IO3_ipd, IO2_ipd, IO1_ipd, IO0_ipd }; wire [7 : 0 ] DOut; assign DOut = {IO7, IO6, IO5, IO4, IO3, IO2, IO1, IO0 }; wire CLE_ipd ; wire ALE_ipd ; wire CENeg_ipd ; wire RENeg_ipd ; wire WENeg_ipd ; wire WPNeg_ipd ; wire PRE_ipd ; // internal delays reg PROG_in ; reg PROG_out ; reg BERS_in ; reg BERS_out ; reg TR_in ; reg TR_out ; reg [7 : 0] DOut_zd; wire IO7_zd ; wire IO6_zd ; wire IO5_zd ; wire IO4_zd ; wire IO3_zd ; wire IO2_zd ; wire IO1_zd ; wire IO0_zd ; assign {IO7_zd, IO6_zd, IO5_zd, IO4_zd, IO3_zd, IO2_zd, IO1_zd, IO0_zd } = DOut_zd; reg R_zd = 1'b0; parameter mem_file_name = "none"; parameter invblocks_file_name = "none"; parameter UserPreload = 1'b0; parameter TimingModel = "DefaultTimingModel"; parameter PartID = "s19mn512p00"; parameter MaxData = 8'hFF; parameter BlockNum = 511; parameter BlockSize = 63; parameter PageSize = 2111; parameter SegmentNum = 3; // 4 segment pairs within page parameter SegmentSize = 16'h200; parameter SperSegSize = 16'h10; parameter SpareSize = 63; parameter PageNum = 16'h7FFF; parameter InvalidData = 2; parameter InvBlocksNum = 10; // If generic Long_Timming is set to 0, you need to uncomment line below //`define SPEEDSIM; // constraint memory preload file parameters parameter preload_line_width = 160; parameter preload_address_width = 7; parameter preload_data_width = 2; integer memory_read_data; // control signals reg STAT_ACT =1'b0; reg ERS_ACT =1'b0; reg PRG_ACT =1'b0; reg RSTSTART =1'b0; reg RSTDONE =1'b0; // Control signals for read operation reg PGR_ACT =1'b0; // Page read in progress reg PGD_ACT =1'b0; // Page Duplicate // powerup reg PoweredUp =1'b0; reg reseted =1'b0; reg write =1'b0; reg read =1'b0; integer WER_01; // 8 bit Address integer AddrCom ; // Address within page integer Address ; // 0 - Pagesize // Page Number integer PageAddr = -1; //-1 - PageNum // Block Number integer BlockAddr = -1; //-1 - BlockNum //Data integer Data ; //-1 - MaxData //ID control signals integer IDAddr ; // 0 - 4 integer BlockPage ; // RANGE 0 TO BlockSize; integer Pom_Address ; // RANGE 0 TO PageSize; integer WrBuffData[0:PageSize]; integer WrAddr ; // -1 - Pagesize +1 integer WrPage ; // 0 - PageNum reg [0:SegmentNum] SegForProg; //array [0:SegmentNum] of 0/1 integer PDBuffer [0:PageSize]; integer CashBuffData [0: PageSize]; integer Page_pom; integer cnt_addr; integer segment ; // RANGE -1 TO SegmentNum; integer pom_seg ; // RANGE -1 TO SegmentNum; reg [0:(PageNum+1)*(SegmentNum+1)-1] ProgramedFlag = 0; integer ssam[0:SegmentNum]; // has to be initialized integer ssas[0:SegmentNum]; // has to be initialized integer seam[0:SegmentNum]; integer seas[0:SegmentNum]; integer BadBlockTable [0:BlockNum]; // ID Array integer IDArray[0:3]; // timing check violation reg Viol = 1'b0; // initial integer i,j; //RstTime time duration; //Functional reg[7:0] Status = 8'b01000000; reg oe = 1'b0; integer Page; // 0 - PageNum integer Blck; // 0 - BlockNum reg [0:BlockNum] corrupt_flag; reg rising_edge_read; reg rising_edge_reseted; reg falling_edge_write; reg rising_edge_TR_out; reg rising_edge_PROG_out; reg rising_edge_RSTDONE; reg rising_edge_BERS_out; // states reg [5:0] current_state; reg [5:0] next_state; // FSM states parameter IDLE =6'h00; // parameter UNKNOWN =6'h01; // wrong command sequneces parameter PREL_RD =6'h02; // parameter RESET =6'h03; // parameter A0_RD =6'h04; // parameter A1_RD =6'h05; // parameter A2_RD =6'h06; // parameter RD_WCMD =6'h07; // waiting for the confirm read command parameter BUFF_TR =6'h08; // parameter RD =6'h09; // parameter CAC_PREL =6'h0A; // Coloumn address change parameter A0_CAC =6'h0B; // parameter A1_CAC =6'h0C; // Wait for confirm EO command parameter ID_PREL =6'h0D; // parameter ID =6'h0E; // parameter PREL_PRG =6'h0F; // parameter PGD_PREL =6'h10; // parameter A0_PRG =6'h11; // parameter A1_PRG =6'h12; // parameter A2_PRG =6'h13; // parameter DATA_PRG =6'h14; // parameter PGMS_CAC =6'h17; parameter A0_PRG_CAC =6'h18; parameter PGMS =6'h19; parameter PREL_ERS =6'h1C; parameter A1_ERS =6'h1D; parameter A2_ERS =6'h1E; parameter BERS_EXEC =6'h1F; parameter A0_PGD =6'h20; parameter A1_PGD =6'h21; parameter A2_PGD =6'h22; parameter CONF_PGD =6'h23; /////////////////////////////////////////////////////////////////////////////// //Interconnect Path Delay Section /////////////////////////////////////////////////////////////////////////////// buf (IO7_ipd , IO7 ); buf (IO6_ipd , IO6 ); buf (IO5_ipd , IO5 ); buf (IO4_ipd , IO4 ); buf (IO3_ipd , IO3 ); buf (IO2_ipd , IO2 ); buf (IO1_ipd , IO1 ); buf (IO0_ipd , IO0 ); buf (CLE_ipd , CLE ); buf (ALE_ipd , ALE ); buf (CENeg_ipd , CENeg ); buf (RENeg_ipd , RENeg ); buf (WENeg_ipd , WENeg ); buf (WPNeg_ipd , WPNeg ); buf (PRE_ipd , PRE ); /////////////////////////////////////////////////////////////////////////////// // Propagation delay Section /////////////////////////////////////////////////////////////////////////////// nmos (IO7 , IO7_zd , 1); nmos (IO6 , IO6_zd , 1); nmos (IO5 , IO5_zd , 1); nmos (IO4 , IO4_zd , 1); nmos (IO3 , IO3_zd , 1); nmos (IO2 , IO2_zd , 1); nmos (IO1 , IO1_zd , 1); nmos (IO0 , IO0_zd , 1); nmos (RY , 1'b0 , ~R_zd); wire deg; // Needed for TimingChecks // VHDL CheckEnable Equivalent wire Check_IO0_WENeg; assign Check_IO0_WENeg = ~CENeg; wire Check_WENeg; assign Check_WENeg = PoweredUp; memory_features memory_features_i0(); 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 specparam tpd_CENeg_IO0 = 1;//tcea, tchz specparam tpd_RENeg_IO0 = 1;//trea, trhZ specparam tpd_WENeg_RY = 1;//twb //tsetup values specparam tsetup_CLE_WENeg = 1;//tcls edge \ specparam tsetup_CENeg_WENeg = 1;//tcs edge \ specparam tsetup_ALE_WENeg = 1;//tals edge \ specparam tsetup_IO0_WENeg = 1;//tds edge / specparam tsetup_WPNeg_WENeg = 1;//tww edge / specparam tsetup_CLE_RENeg = 1;//tar edge \ specparam tsetup_ALE_RENeg = 1;//tclr edge \ specparam tsetup_CENeg_RENeg = 1;//tcr edge \ specparam tsetup_RENeg_WENeg = 1;//twhw edge \ specparam tsetup_WENeg_CENeg = 1;//twhc edge \ specparam tsetup_WENeg_RENeg = 1;//twhr edge \ //thold values specparam thold_CLE_WENeg = 1;//tclh edge / specparam thold_CENeg_WENeg = 1;//tch edge / specparam thold_ALE_WENeg = 1;//talh edge / specparam thold_IO0_WENeg = 1;//tdh edge / //tpw values specparam tpw_WENeg_negedge = 1;//twp specparam tpw_WENeg_posedge = 1;//twh specparam tpw_RENeg_negedge = 1;//trp specparam tpw_RENeg_posedge = 1;//treh specparam tperiod_WENeg = 1;//twc specparam tperiod_RENeg = 1;//trc //tdevice values: values for internal delays `ifdef SPEEDSIM // Program Operation specparam tdevice_PROG = 60000; //Block Erase Operation specparam tdevice_BERS = 437500; //Page transfer time specparam tdevice_TR = 17000; `else // not SPEEDSIM //tdevice values: values for internal delays // Program Operation specparam tdevice_PROG = 6000000; //Block Erase Operation specparam tdevice_BERS = 70000000; //Page transfer time specparam tdevice_TR = 85000; `endif // SPEEDSIM /////////////////////////////////////////////////////////////////////////////// // Input Port Delays don't require Verilog description /////////////////////////////////////////////////////////////////////////////// // Path delays // /////////////////////////////////////////////////////////////////////////////// // specify transport delay for Data output paths specparam PATHPULSE$CENeg$IO0 = (0); specparam PATHPULSE$CENeg$IO1 = (0); specparam PATHPULSE$CENeg$IO2 = (0); specparam PATHPULSE$CENeg$IO3 = (0); specparam PATHPULSE$CENeg$IO4 = (0); specparam PATHPULSE$CENeg$IO5 = (0); specparam PATHPULSE$CENeg$IO6 = (0); specparam PATHPULSE$CENeg$IO7 = (0); specparam PATHPULSE$RENeg$IO0 = (0); specparam PATHPULSE$RENeg$IO1 = (0); specparam PATHPULSE$RENeg$IO2 = (0); specparam PATHPULSE$RENeg$IO3 = (0); specparam PATHPULSE$RENeg$IO4 = (0); specparam PATHPULSE$RENeg$IO5 = (0); specparam PATHPULSE$RENeg$IO6 = (0); specparam PATHPULSE$RENeg$IO7 = (0); // Data ouptut paths ( CENeg => IO0 ) = tpd_CENeg_IO0; ( CENeg => IO1 ) = tpd_CENeg_IO0; ( CENeg => IO2 ) = tpd_CENeg_IO0; ( CENeg => IO3 ) = tpd_CENeg_IO0; ( CENeg => IO4 ) = tpd_CENeg_IO0; ( CENeg => IO5 ) = tpd_CENeg_IO0; ( CENeg => IO6 ) = tpd_CENeg_IO0; ( CENeg => IO7 ) = tpd_CENeg_IO0; ( RENeg => IO0 ) = tpd_RENeg_IO0; ( RENeg => IO1 ) = tpd_RENeg_IO0; ( RENeg => IO2 ) = tpd_RENeg_IO0; ( RENeg => IO3 ) = tpd_RENeg_IO0; ( RENeg => IO4 ) = tpd_RENeg_IO0; ( RENeg => IO5 ) = tpd_RENeg_IO0; ( RENeg => IO6 ) = tpd_RENeg_IO0; ( RENeg => IO7 ) = tpd_RENeg_IO0; // R output path (WENeg => RY) = tpd_WENeg_RY; //////////////////////////////////////////////////////////////////////////////// // Timing Violation // //////////////////////////////////////////////////////////////////////////////// $setup ( IO0 ,posedge WENeg &&& Check_IO0_WENeg ,tsetup_IO0_WENeg,Viol); $setup ( IO1 ,posedge WENeg &&& Check_IO0_WENeg ,tsetup_IO0_WENeg,Viol); $setup ( IO2 ,posedge WENeg &&& Check_IO0_WENeg ,tsetup_IO0_WENeg,Viol); $setup ( IO3 ,posedge WENeg &&& Check_IO0_WENeg ,tsetup_IO0_WENeg,Viol); $setup ( IO4 ,posedge WENeg &&& Check_IO0_WENeg ,tsetup_IO0_WENeg,Viol); $setup ( IO5 ,posedge WENeg &&& Check_IO0_WENeg ,tsetup_IO0_WENeg,Viol); $setup ( IO6 ,posedge WENeg &&& Check_IO0_WENeg ,tsetup_IO0_WENeg,Viol); $setup ( IO7 ,posedge WENeg &&& Check_IO0_WENeg ,tsetup_IO0_WENeg,Viol); $hold ( posedge WENeg &&& Check_IO0_WENeg , IO0 ,thold_IO0_WENeg, Viol); $hold ( posedge WENeg &&& Check_IO0_WENeg , IO1 ,thold_IO0_WENeg, Viol); $hold ( posedge WENeg &&& Check_IO0_WENeg , IO2 ,thold_IO0_WENeg, Viol); $hold ( posedge WENeg &&& Check_IO0_WENeg , IO3 ,thold_IO0_WENeg, Viol); $hold ( posedge WENeg &&& Check_IO0_WENeg , IO4 ,thold_IO0_WENeg, Viol); $hold ( posedge WENeg &&& Check_IO0_WENeg , IO5 ,thold_IO0_WENeg, Viol); $hold ( posedge WENeg &&& Check_IO0_WENeg , IO6 ,thold_IO0_WENeg, Viol); $hold ( posedge WENeg &&& Check_IO0_WENeg , IO7 ,thold_IO0_WENeg, Viol); $setup ( CLE ,negedge WENeg ,tsetup_CLE_WENeg , Viol); $setup ( ALE ,negedge WENeg ,tsetup_ALE_WENeg , Viol); $setup ( CENeg ,negedge WENeg ,tsetup_CENeg_WENeg , Viol); $setup ( WENeg ,negedge CENeg ,tsetup_WENeg_CENeg , Viol); $setup ( CLE ,negedge RENeg ,tsetup_CLE_RENeg , Viol); $setup ( ALE ,negedge RENeg ,tsetup_ALE_RENeg , Viol); $setup ( WENeg ,negedge RENeg ,tsetup_WENeg_RENeg , Viol); $setup ( CENeg ,negedge RENeg ,tsetup_WENeg_RENeg , Viol); $setup ( RENeg ,negedge WENeg ,tsetup_RENeg_WENeg , Viol); $setup ( WPNeg ,negedge WENeg ,tsetup_WENeg_RENeg , Viol); $hold ( posedge WENeg &&& Check_WENeg,CLE,thold_CLE_WENeg, Viol); $hold ( posedge WENeg &&& Check_WENeg,ALE,thold_ALE_WENeg, Viol); $hold ( posedge WENeg &&& Check_WENeg,CENeg,thold_CENeg_WENeg,Viol); $width (posedge WENeg , tpw_WENeg_posedge); $width (negedge WENeg , tpw_WENeg_negedge); $period(negedge WENeg , tperiod_WENeg); $period(posedge WENeg , tperiod_WENeg); $width (posedge RENeg , tpw_RENeg_posedge); $width (negedge RENeg , tpw_RENeg_negedge); $period(negedge RENeg , tperiod_RENeg); $period(posedge RENeg , tperiod_RENeg); endspecify //Used as wait periods `ifdef SPEEDSIM time poweredupT = 10000; // 10 us time RstErsT = 50000; // 50 us time RstProgT = 10000; // 10 us time RstReadT = 5000; // 5 us `else // not SPEEDSIM time poweredupT = 10000; // 10 us time RstErsT = 500000;// 500 us time RstProgT = 10000; // 10 us time RstReadT = 5000; // 5 us `endif // SPEEDSIM //////////////////////////////////////////////////////////////////////////////// // Main Behavior Block // //////////////////////////////////////////////////////////////////////////////// reg deq; always @(DIn, DOut) begin if (DIn==DOut) deq=1'b1; else deq=1'b0; end // check when data is generated from model to avoid setuphold check in // those occasion assign deg=deq; initial begin : IDPreload ////////////////////////////////////////////////////////////////// //ID array data / S19MN512P00 DEVICE SPECIFIC ////////////////////////////////////////////////////////////////// IDArray[0] = 8'h01; IDArray[1] = 8'h28; IDArray[2] = 8'h04; IDArray[3] = 8'h95; end // ------------------------------------------------------------------------- // preload section modified for embedded memory management routines // ------------------------------------------------------------------------- // preload dedicated declarations reg [preload_line_width*8 : 1] scanf_str; reg [8:1] fetch_char; integer preload_iter; integer preload_file; integer scanf_address; integer scanf_data; // initialize memory and load preoload files if any initial begin: InitMemory integer i,j,k; // memory region implicitly initialized memory_features_i0.initialize_w(); // initialize flags only for (i=0;i<(PageNum+1)*(SegmentNum+1);i=i+1) ProgramedFlag[i] = 1'b0; for (i=0; i<= BlockNum; i=i+1) BadBlockTable[i] = 0; if (UserPreload && !(invblocks_file_name == "none")) $readmemh(invblocks_file_name, BadBlockTable); if (UserPreload && !(mem_file_name == "none")) begin //----------------------------------------------------------------- // Memory preload file format for s19mn-p //----------------------------------------------------------------- // / - comment // @aaaaaaa - stands for page address and address within // first 2112 bytes of the page // dd -
is byte to be written at Mem(Page)(offset++) // page is div 2048 // offset is mod 2048 // offset is incremented on every write //----------------------------------------------------------------- scanf_address = 0; preload_file = $fopen(mem_file_name, "r"); while($fgets(scanf_str, preload_file)) begin fetch_char = scanf_str [preload_line_width * 8 : preload_line_width * 8 - 7]; while (!fetch_char) begin scanf_str = scanf_str << 8; fetch_char = scanf_str [preload_line_width * 8 : preload_line_width * 8 - 7]; end if ((fetch_char == "/") || (fetch_char == "\n")) begin // empty lines and comments not processed end else begin if (fetch_char == "@") begin scanf_address = 0; for(preload_iter = 0; preload_iter < preload_address_width; preload_iter = preload_iter + 1) begin scanf_str = scanf_str << 8; fetch_char = scanf_str[ preload_line_width * 8 : preload_line_width * 8 - 7 ]; scanf_address = scanf_address * 16; if ((fetch_char >= "0")&&(fetch_char <= "9")) scanf_address = scanf_address + (fetch_char - "0"); else if ((fetch_char >= "A")&&(fetch_char <= "F")) scanf_address = scanf_address + (fetch_char - "A") + 10; else if ((fetch_char >= "a")&&(fetch_char <= "f")) scanf_address = scanf_address + (fetch_char - "a") + 10; end end else begin scanf_data = 0; for(preload_iter = 0; preload_iter < preload_data_width; preload_iter = preload_iter + 1) begin scanf_data = scanf_data * 16; if ((fetch_char >= "0") && (fetch_char <= "9")) scanf_data = scanf_data + (fetch_char - "0"); else if ((fetch_char >= "A")&&(fetch_char <= "F")) scanf_data = scanf_data + (fetch_char - "A") + 10; else if ((fetch_char >= "a")&&(fetch_char <= "f")) scanf_data = scanf_data + (fetch_char - "a") + 10; scanf_str = scanf_str << 8; fetch_char = scanf_str[ preload_line_width * 8 : preload_line_width * 8-7 ]; end if (scanf_data !== MaxData) begin if (scanf_address < ((PageNum + 1) * (PageSize + 1))) begin memory_features_i0.write_mem_w (scanf_address, scanf_data); ProgramedFlag[scanf_address / SegmentSize] = 1'b1; end else $display("Memory address out of range."); end scanf_address++; end end end $fclose(mem_file_name); end for (i=0; i<= BlockNum; i=i+1) begin if (BadBlockTable[i] == 1) begin for (j=0; j< 2*(PageSize+1); j=j+1) memory_features_i0.write_mem_w( i*(BlockSize+1)*(PageSize+1) + j, InvalidData ); end end end // ------------------------------------------------------------------------- // --------------- the end of preload section modifications -------------- // ------------------------------------------------------------------------- initial begin STAT_ACT =1'b0; ERS_ACT =1'b0; PRG_ACT =1'b0; RSTSTART =1'b0; RSTDONE =1'b0; write =1'b0; read =1'b0; //page segment start address offset ssam[0] =12'h000; ssam[1] =12'h200; ssam[2] =12'h400; ssam[3] =12'h600; ssas[0] =12'h800; ssas[1] =12'h810; ssas[2] =12'h820; ssas[3] =12'h830; //page segment end address offset seam[0] =12'h1FF; seam[1] =12'h3FF; seam[2] =12'h5FF; seam[3] =12'h7FF; seas[0] =12'h80F; seas[1] =12'h81F; seas[2] =12'h82F; seas[3] =12'h83F; for(j=0;j<=PageSize;j=j+1) begin WrBuffData[j] = -1; end for(j=0;j<=SegmentNum;j=j+1) begin SegForProg[i]=1'b0; end WrAddr = -1; WrPage = -1; for (j=0; j<= BlockNum; j=j+1) corrupt_flag[j] = 0; current_state = IDLE; next_state = IDLE; Status = 8'b01000000; PROG_in = 1'b0; PROG_out = 1'b0; BERS_in = 1'b0; BERS_out = 1'b0; TR_in = 1'b0; TR_out = 1'b0; end //Power Up time 10 us; initial begin PoweredUp = 1'b0; #poweredupT PoweredUp = 1'b1; end //Program Operation always @(posedge PROG_in) begin:ProgTime #(tdevice_PROG+ WER_01) PROG_out = 1'b1; end always @(negedge PROG_in) begin disable ProgTime; #1 PROG_out = 1'b0; end //Block Erase Operation always @(posedge BERS_in) begin : ErsTime #(tdevice_BERS + WER_01) BERS_out = 1'b1; end always @(negedge BERS_in) begin disable ErsTime; #1 BERS_out = 1'b0; end //Page transfer time always @(posedge TR_in) begin : PageTransferTime #(tdevice_TR + WER_01) TR_out = 1'b1; end always @(negedge TR_in) begin disable PageTransferTime; #1 TR_out = 1'b0; end //////////////////////////////////////////////////////////////////////////// // process for reset control and FSM state transition //////////////////////////////////////////////////////////////////////////// always @(PoweredUp, next_state) begin if (PoweredUp) begin reseted = 1'b1; current_state = next_state; end else begin current_state = IDLE; reseted = 1'b0; end end ////////////////////////////////////////////////////////////////////////// //process for generating the write and read signals ////////////////////////////////////////////////////////////////////////// always @ (WENeg, CENeg, RENeg) begin if (~WENeg && ~CENeg && RENeg) write = 1'b1; else if (WENeg && ~CENeg && RENeg) write = 1'b0; else write = 1'b0; if (WENeg && ~CENeg && ~RENeg ) read = 1'b1; else if (WENeg && ~CENeg && RENeg ) read = 1'b0; else read = 1'b0; end ////////////////////////////////////////////////////////////////////////// //Latches 8 bit address on rising edge of WE# //Latches data on rising edge of WE# ////////////////////////////////////////////////////////////////////////// always @ (posedge WENeg) begin // latch 8 bit read address if (WENeg && ALE && ~CENeg && ~CLE) AddrCom = A[7:0]; // latch data if (WENeg && ~ALE && RENeg) Data = DIn[7:0]; end //////////////////////////////////////////////////////////////////////////// // Timing control for the Reset Operation //////////////////////////////////////////////////////////////////////////// event rstdone_event; always @ (posedge reseted) begin disable rstdone_process; RSTDONE = 1'b1; // reset done end always @ (posedge RSTSTART) begin if (reseted && RSTDONE) begin if (ERS_ACT) duration = RstErsT; else if (PRG_ACT) duration = RstProgT; else duration = RstReadT; RSTDONE = 1'b0; ->rstdone_event; end end always @(rstdone_event) begin:rstdone_process #duration RSTDONE = 1'b1; end /////////////////////////////////////////////////////////////////////////// // Main Behavior Process // combinational process for next state generation /////////////////////////////////////////////////////////////////////////// always @(rising_edge_read, rising_edge_reseted, reseted,falling_edge_write, rising_edge_TR_out, rising_edge_PROG_out, rising_edge_BERS_out, rising_edge_RSTDONE) begin : StateGen oe = rising_edge_read; if (reseted != 1) next_state = current_state; else if (rising_edge_reseted) begin if (PRE) next_state = BUFF_TR; else next_state = IDLE; end else begin case (current_state) IDLE: begin if (falling_edge_write) begin if (CLE && ~ALE && Data == 8'h00) next_state = PREL_RD; else if (CLE && ~ALE && Data == 8'h90) next_state = ID_PREL; else if (CLE && ~ALE && Data == 8'h80) next_state = PREL_PRG; else if (CLE && ~ALE && Data == 8'h60) next_state = PREL_ERS; else if (CLE && ~ALE && Data == 8'hff) next_state = RESET; else if (CLE && ~ALE && Data == 8'h70) next_state = IDLE; else if (CLE) next_state = IDLE; end end UNKNOWN: begin if (falling_edge_write) if (CLE && ~ALE && Data == 8'hff) next_state = RESET; end RESET : begin if (rising_edge_RSTDONE) next_state = IDLE; end PREL_RD: begin if (falling_edge_write) if (ALE) next_state = A0_RD; else if (CLE && Data==8'hFF) next_state = RESET; // reset else if (CLE) next_state = UNKNOWN; else if (oe) next_state = IDLE; end A0_RD: begin if (falling_edge_write) if (ALE) next_state = A1_RD; else if (CLE && Data == 8'hff) next_state = RESET; else if (CLE) next_state = UNKNOWN; end A1_RD: begin if (falling_edge_write) if (ALE) next_state = A2_RD; else if (CLE && Data == 8'hff) next_state = RESET; else if (CLE) next_state = UNKNOWN; end A2_RD: begin if (falling_edge_write) if (ALE) next_state = RD_WCMD; else if (CLE && Data == 8'hff) next_state = RESET; else if (CLE) next_state = UNKNOWN; end RD_WCMD : begin if (falling_edge_write) if (CLE && ~ALE && Data == 8'h30) next_state = BUFF_TR; else if (CLE && ~ALE && Data == 8'h35) next_state = BUFF_TR; else if (CLE && ~ALE && Data == 8'hff) next_state = RESET; else if (CLE) next_state = UNKNOWN; end BUFF_TR : begin if (falling_edge_write) begin if (CLE && ~ALE && Data == 8'hff) next_state = RESET; else if (CLE && STAT_ACT) next_state = BUFF_TR; end else if (rising_edge_TR_out) next_state = RD; end RD: begin if (falling_edge_write) begin if (CLE && ~ALE && Data == 8'h00) begin if (STAT_ACT && PGR_ACT) next_state = RD; else if (PGR_ACT) next_state = PREL_RD; else next_state = UNKNOWN; end else if (CLE && ~ALE && Data == 8'h80 && ~PGD_ACT) next_state = PREL_PRG; else if (CLE && ~ALE && Data == 8'h90 && ~PGD_ACT) next_state = ID_PREL; else if (CLE && ~ALE && Data == 8'h70) next_state = RD; else if (CLE && ~ALE && Data == 8'hFF) next_state = RESET; else if (CLE && ~ALE && Data == 8'h60 && ~PGD_ACT) next_state = PREL_ERS; else if (CLE && ~ALE && Data == 8'h85 && PGD_ACT) next_state = PGD_PREL; else if (CLE && ~ALE && Data == 8'h05 && ~PGD_ACT) next_state = CAC_PREL; else if (CLE && STAT_ACT) next_state = RD; else next_state = RD; end end CAC_PREL: begin if (falling_edge_write) begin if (ALE) next_state = A0_CAC; else if (CLE && Data == 8'hff) next_state = RESET; else if (CLE) next_state = UNKNOWN; end end A0_CAC: begin if (falling_edge_write) begin if (ALE) next_state = A1_CAC; else if (CLE && Data == 8'hff) next_state = RESET; else if (CLE) next_state = UNKNOWN; end end A1_CAC: begin if (falling_edge_write) begin if (CLE && ~ALE && Data == 8'he0) next_state = RD; else if (CLE && ~ALE && Data == 8'hff) next_state = RESET; else if (CLE || ALE) next_state = UNKNOWN; end end ID_PREL: begin if (falling_edge_write) begin if (ALE && AddrCom == 8'h00) next_state = ID; else if (CLE && ~ALE && Data == 8'hff) next_state = RESET; else if (CLE || ALE) next_state = UNKNOWN; end end ID: begin if (falling_edge_write) begin if (CLE && ~ALE && Data == 8'h00) next_state = PREL_RD; else if (CLE && ~ALE && Data == 8'h90) next_state = ID_PREL; else if (CLE && ~ALE && Data == 8'h80) next_state = PREL_PRG; else if (CLE && ~ALE && Data == 8'h60) next_state = PREL_ERS; else if (CLE && ~ALE && Data == 8'hff) next_state = RESET; else if (CLE && ~ALE && Data == 8'h70) next_state = IDLE; else if (CLE) next_state = IDLE; end end PREL_PRG: begin if (falling_edge_write) begin if (ALE) #1 next_state = A0_PRG; else if (CLE && ~ALE && Data == 8'hff) next_state = RESET; else if (CLE) next_state = UNKNOWN; end end A0_PRG: begin if (falling_edge_write) begin if (ALE) #1 next_state = A1_PRG; else if (CLE && ~ALE && Data == 8'hff) next_state = RESET; else if (CLE) next_state = UNKNOWN; end end A1_PRG: begin if (falling_edge_write) begin if (ALE) #1 next_state = A2_PRG; else if (CLE && ~ALE && Data == 8'hff) next_state = RESET; else if (CLE) next_state = UNKNOWN; end end A2_PRG: begin if (falling_edge_write) begin if (ALE) #1 next_state = DATA_PRG; else if (CLE && ~ALE && Data == 8'hff) next_state = RESET; else if (CLE) next_state = UNKNOWN; end end DATA_PRG: begin if (falling_edge_write) begin if ((ALE && (cnt_addr < 2 || cnt_addr >= 4)) || (CLE && ~ALE && cnt_addr > 4)) next_state = UNKNOWN; else if (CLE && ~ALE && Data == 8'h10) begin if (~PRG_ACT) #1 next_state = PGMS; end else if (CLE && ~ALE && Data == 8'h85) next_state = PGMS_CAC; else if (CLE && ~ALE && Data == 8'hff) next_state = RESET; else if (CLE) next_state = UNKNOWN; else if (~ALE && ~CLE && WrAddr < (PageSize+1)) next_state = DATA_PRG; end end PGMS_CAC: begin if (falling_edge_write) begin if (CLE && ~ALE && Data==8'hFF) next_state = RESET; else if (ALE) next_state = A0_PRG_CAC; else if (CLE) next_state = UNKNOWN; end end PGMS : begin if (falling_edge_write) begin if ( CLE && ~ALE && Data==8'hFF) next_state = RESET; // reset else if (CLE && STAT_ACT) next_state = PGMS; end else if (rising_edge_PROG_out ) next_state = IDLE; // programing done end A0_PRG_CAC: begin if (falling_edge_write) begin if (ALE) next_state = DATA_PRG; else if (CLE && Data==8'hFF) next_state = RESET; else if (CLE) next_state = UNKNOWN; end end PREL_ERS : begin if (falling_edge_write) begin if (ALE) #1 next_state = A1_ERS; else if (CLE && Data==8'hFF) next_state = RESET; // reset else if (CLE) next_state = UNKNOWN; // reset end end A1_ERS : begin if (falling_edge_write) begin if (ALE) next_state = A2_ERS; else if (CLE && Data==8'hFF) next_state = RESET; // reset else if (CLE) next_state = UNKNOWN; // reset end end A2_ERS : begin if (falling_edge_write) begin if (CLE && ~ALE && Data==8'hD0) next_state = BERS_EXEC; else if (CLE && ~ALE && Data==8'hFF) next_state = RESET; // reset else if (CLE || ALE) next_state = UNKNOWN; // reset end end BERS_EXEC : begin if (falling_edge_write) begin if ( CLE && ~ALE && Data==8'hFF ) next_state = RESET; // reset else if (CLE && STAT_ACT) next_state = BERS_EXEC; end else if (rising_edge_BERS_out ) #1 next_state = IDLE; end PGD_PREL : begin if (falling_edge_write) begin if (ALE) next_state = A0_PGD; else if (CLE && Data==8'hFF) next_state = RESET; // reset else if (CLE) next_state = UNKNOWN; // reset end end A0_PGD : begin if (falling_edge_write) begin if ( ALE ) next_state = A1_PGD; else if ( CLE && Data==8'hFF ) next_state = RESET; // reset else if ( CLE ) next_state = UNKNOWN; // reset end end A1_PGD : begin if (falling_edge_write) begin if ( ALE ) next_state = A2_PGD; else if ( CLE && Data==8'hFF ) next_state = RESET; // reset else if ( CLE ) next_state = UNKNOWN; // reset end end A2_PGD : begin if (falling_edge_write) begin if ( ALE ) next_state = CONF_PGD; else if ( CLE && Data==8'hFF ) next_state = RESET; // reset else if ( CLE ) next_state = UNKNOWN; // reset end end CONF_PGD : begin if (falling_edge_write) begin if ((ALE && cnt_addr >= 4) || (CLE && ~ALE && cnt_addr > 4)) next_state = UNKNOWN; else if( CLE && ~ALE && Data==8'h10) next_state = PGMS; else if ( CLE && ~ALE && Data==8'h85) next_state = PGMS_CAC; else if( CLE && ~ALE && Data==8'hFF) next_state = RESET; // reset else if ( CLE ) next_state = UNKNOWN; // reset end end endcase end end /////////////////////////////////////////////////////////////////////////// //FSM Output generation and general funcionality /////////////////////////////////////////////////////////////////////////// always @(rising_edge_reseted, reseted, falling_edge_write,rising_edge_read, rising_edge_RSTDONE, rising_edge_TR_out, rising_edge_BERS_out, rising_edge_PROG_out, RENeg, CENeg, TR_out, PROG_out, read) begin : OutputGeneration oe = rising_edge_read; Status[7] = WPNeg_ipd; if (reseted != 1) R_zd = 0; else if (rising_edge_reseted) begin if (PRE) begin Address = 0; Pom_Address = 0; PageAddr = 0; BlockAddr = 0; PGR_ACT = 1; TR_in = 1; end else begin PGR_ACT = 0; R_zd = 1; end end else begin case (current_state) IDLE: begin if (falling_edge_write) begin if (CLE && ~ALE && Data == 16'h00) begin Status[6:0] = 7'b1000000; STAT_ACT = 0; end else if (CLE && ~ALE && Data == 16'h70) STAT_ACT = 1; else if (CLE && ~ALE && (Data == 16'h80 || Data == 16'h90)) begin STAT_ACT = 0; Status[6:0] = 7'b1000000; end else if (CLE && ~ALE && Data == 16'h60) begin STAT_ACT = 0; Status[6:0] = 7'b1000000; end else if (CLE && ~ALE && Data == 16'hFF) begin set_reset; end else if (CLE && STAT_ACT) STAT_ACT = 0; end if (oe) if (STAT_ACT) Read_Status; end UNKNOWN: begin if (falling_edge_write) begin if (CLE && ~ALE && Data == 8'hff) begin STAT_ACT = 0; ERS_ACT = 0; PGD_ACT = 0; PGR_ACT = 0; Status[6:0] = 7'b1000000; RSTSTART = 1; #1 RSTSTART = 0; R_zd = 0; end end end RESET: begin if (falling_edge_write) begin if (CLE && ~ALE && Data == 8'h70) STAT_ACT = 1; end if (rising_edge_RSTDONE) begin ERS_ACT = 0; PGD_ACT = 0; PGR_ACT = 0; R_zd = 1; Status[6:0] = 7'b1000000; end else begin Status[6:0] = 7'b0000000; end if (oe) if (STAT_ACT) Read_Status; end PREL_RD: begin if (falling_edge_write) begin if (ALE) begin Pom_Address = AddrCom; cnt_addr = 0; end else if (CLE && ~ALE && Data == 8'hff) set_reset; end if (oe && STAT_ACT) STAT_ACT = 0; end A0_RD: begin if (falling_edge_write) begin if (ALE) begin Pom_Address = (AddrCom* 12'h100) + Pom_Address; cnt_addr = cnt_addr + 1; end else if (CLE && Data == 8'hff) begin set_reset; end end end A1_RD: begin if (falling_edge_write) begin if (ALE) begin Page = AddrCom * 1; cnt_addr = cnt_addr + 1; end else if (CLE && Data == 8'hff) begin set_reset; end end end A2_RD: begin if (falling_edge_write) begin if (ALE) begin Page = AddrCom * 12'h100 + Page; cnt_addr = cnt_addr + 1; end else if (CLE && Data == 8'hff) begin set_reset; end end end RD_WCMD: begin if (falling_edge_write) begin if (CLE && ~ALE && Data == 8'h30) begin PGR_ACT = 1; Address = Pom_Address; PageAddr = Page; BlockAddr = Page / (BlockSize + 1); Blck = Page / (BlockSize + 1); TR_in = 1; R_zd = 0; Status[6] = 1'b0; end else if (CLE && ~ALE && Data == 8'h35) begin PGD_ACT = 1; Address = Pom_Address; PageAddr = Page; BlockAddr = Page / (BlockSize + 1); Blck = Page / (BlockSize + 1); TR_in = 1; R_zd = 0; Status[6] = 1'b0; for (i= 0; i<= PageSize; i=i+1) PDBuffer[i] = -1; end else if (CLE && ~ALE && Data == 8'hff) begin set_reset; end else if (ALE) cnt_addr = cnt_addr + 1; end end BUFF_TR: begin if (falling_edge_write) begin if (CLE && ~ALE && Data == 8'hff) begin TR_in = 0; set_reset; end else if (CLE && ~ALE && Data == 8'h70) STAT_ACT = 1; else if (CLE && STAT_ACT) STAT_ACT = 0; end else if (rising_edge_TR_out) begin R_zd = 1; Status[6] = 1'b1; TR_in = 0; if (PGD_ACT) begin for (i=0; i<= PageSize; i=i+1) begin memory_features_i0.read_mem_w( memory_read_data, PageAddr * (PageSize + 1) + i ); PDBuffer[i] = memory_read_data; end end end if (oe) if (STAT_ACT) Read_Status; end RD: begin if (falling_edge_write) begin if (CLE && ~ALE && Data == 8'h00) begin if (STAT_ACT) begin STAT_ACT = 0; Address = Pom_Address; end else if (~PGD_ACT) begin PGR_ACT = 0; STAT_ACT = 0; Status[6:0] = 7'b1000000; end end else if (CLE && ~ALE && Data == 8'h70) STAT_ACT = 1; else if (CLE && ~ALE && Data == 8'h90 && ~PGD_ACT) begin STAT_ACT = 0; PGR_ACT = 0; end else if (CLE && ~ALE && Data == 8'h80 && ~PGD_ACT) begin STAT_ACT = 0; Status[6:0] = 7'b1000000; PGR_ACT = 0; end else if (CLE && ~ALE && Data == 8'h60 && ~PGD_ACT) begin STAT_ACT = 0; PGR_ACT = 0; Status[6:0] = 7'b1000000; end else if (CLE && ~ALE && Data == 8'hff) begin set_reset; end else if (CLE && ~ALE && Data == 8'h85 && PGD_ACT) begin STAT_ACT = 0; Status[6:0] = 7'b1000000; end else if (CLE && ~ALE && Data == 8'h05 && ~PGD_ACT) begin STAT_ACT = 0; Status[6:0] = 7'b1000000; end else if (CLE && STAT_ACT) STAT_ACT = 0; end if (oe) begin if (~PGD_ACT && ~STAT_ACT ) Read_Data(Address, PageAddr); else if (STAT_ACT) Read_Status; end end CAC_PREL: begin if (falling_edge_write) begin if (ALE) begin Pom_Address = AddrCom; cnt_addr = 0; end else if (CLE && Data == 8'hff) begin set_reset; end end end A0_CAC: begin if (falling_edge_write) begin if (ALE) begin Pom_Address = Pom_Address + AddrCom * 12'h100; cnt_addr = cnt_addr + 1; end else if (CLE && Data == 8'hff) begin set_reset; end end end A1_CAC: begin if (falling_edge_write) begin if (CLE && ~ALE && Data == 8'he0) Address = Pom_Address; else if (CLE && ~ALE && Data == 8'hff) set_reset; else if (ALE) cnt_addr = cnt_addr + 1; end end ID_PREL: begin if (falling_edge_write) begin if (ALE && AddrCom == 8'h00) IDAddr = 0; else if (CLE && ~ALE && Data == 8'hff) set_reset; end end ID: begin if (falling_edge_write) begin if (CLE && ~ALE && Data == 8'hff) set_reset; else if (CLE && ~ALE && Data == 8'h70) STAT_ACT = 1; else if (CLE && ~ALE && Data == 8'h00) STAT_ACT = 0; else if (CLE && STAT_ACT) STAT_ACT = 0; end if (oe) begin if (IDAddr < 4) begin DOut_zd = IDArray[IDAddr]; IDAddr = IDAddr + 1; end else DOut_zd = 8'bz; end end PREL_PRG: begin if (falling_edge_write) begin if (ALE) begin WrAddr = AddrCom; cnt_addr = 0; end else if (CLE && Data == 8'hff) set_reset; end end A0_PRG: begin if (falling_edge_write) begin if (ALE) begin WrAddr = (AddrCom * 12'h100) + WrAddr; for (i=0; i<=PageSize; i=i+1) CashBuffData[i] = -1; cnt_addr = cnt_addr + 1; end else if (CLE && Data == 8'hff) set_reset; end end A1_PRG: begin if (falling_edge_write) begin if (ALE) begin Page = AddrCom; cnt_addr = cnt_addr + 1; end else if (CLE && Data == 8'hff) set_reset; end end A2_PRG: begin if (falling_edge_write) begin if (ALE) begin Page = Page + (AddrCom * 12'h100); Blck = Page / (BlockSize + 1); cnt_addr = cnt_addr + 1; BlockPage = Page % (BlockSize+1); Page_pom = BlockPage; for (i=0; i<=SegmentNum; i=i+1) SegForProg[i] = ProgramedFlag[Blck*(BlockSize+1)*(SegmentNum+1) +BlockPage*(SegmentNum+1)+i]; end else if (CLE && Data == 8'hff) set_reset; end end DATA_PRG: begin if (falling_edge_write) begin if (CLE && ~ALE && Data == 8'hff) set_reset; else if (~ALE && ~CLE && WrAddr < PageSize+1) begin getSegment(WrAddr, segment); if (ProgramedFlag[Blck*(BlockSize+1)*(SegmentNum+1) +BlockPage*(SegmentNum+1)+segment] == 0) CashBuffData[WrAddr] = Data; SegForProg[segment] = 1; Page_pom = BlockPage; WrAddr = WrAddr+1; if (WrAddr == ssam[1]) WrAddr = ssas[0]; else if (WrAddr == ssas[1]) WrAddr = ssam[1]; else if (WrAddr == ssam[2]) WrAddr = ssas[1]; else if (WrAddr == ssas[2]) WrAddr = ssam[2]; else if (WrAddr == ssam[3]) WrAddr = ssas[2]; else if (WrAddr == ssas[3]) WrAddr = ssam[3]; else if (WrAddr == ssas[0]) WrAddr = ssas[3]; end else if (CLE && ~ALE && Data == 8'h10) begin if (~PRG_ACT) WrPage = Page; R_zd = 0; Status[6] = 0; end else if (ALE) cnt_addr = cnt_addr + 1; end end PGMS_CAC: begin if (falling_edge_write) if (ALE) begin cnt_addr = 0; WrAddr = AddrCom; end else if (CLE && Data == 8'hff) set_reset; end A0_PRG_CAC: begin if (falling_edge_write) begin if (ALE) begin WrAddr = (AddrCom * 12'h100 + WrAddr); cnt_addr = cnt_addr + 1; end else if (CLE && Data == 8'hff) set_reset; end end PGMS: begin if (WPNeg != 0) begin for (i=0; i<= PageSize; i=i+1) WrBuffData[i] = CashBuffData[i]; for (i=0; i<= PageSize; i=i+1) begin getSegment(i,segment); if (ProgramedFlag[WrPage *(SegmentNum+1) +segment]== 0 && CashBuffData[i] != -1 && BadBlockTable[WrPage/(BlockSize+1)] == 0) memory_features_i0.write_mem_w( WrPage * (PageSize + 1) + i, -1 ); end end if (rising_edge_PROG_out ) begin R_zd = 1; PGD_ACT = 0; end if (falling_edge_write) begin if (CLE && ~ALE && Data == 8'hff) set_reset; else if (CLE && ~ALE && Data == 8'h70) STAT_ACT = 1; else if (CLE && STAT_ACT) STAT_ACT = 0; end if (oe) if (STAT_ACT) Read_Status; end PREL_ERS: begin if (falling_edge_write) begin if (ALE) begin Page = AddrCom; cnt_addr = 0; end else if (CLE && ~ALE && Data == 8'hff) set_reset; end end A1_ERS: begin if (falling_edge_write) begin if (ALE) begin Page = Page + (AddrCom* 12'h100); WrPage = Page; cnt_addr = cnt_addr +1; end else if (CLE && Data == 8'hff) set_reset; end end A2_ERS: begin if (falling_edge_write) begin if (CLE && ~ALE && Data == 8'hff) set_reset; else if (CLE && ~ALE && Data == 8'hD0) begin Blck = Page / (BlockSize + 1); BlockAddr = Blck; if (WPNeg != 0 && BadBlockTable[Blck] == 0) begin corrupt_flag[Blck] = 1; for (i= Blck*(BlockSize+1)*(SegmentNum+1); i<= (Blck+1)*(BlockSize+1)*(SegmentNum+1) -1; i=i+1) ProgramedFlag[i] = 0; end BERS_in = 1; ERS_ACT = 1; R_zd = 0; Status[6] = 1'b0; end else if (ALE) cnt_addr = cnt_addr + 1; end end BERS_EXEC: begin if (rising_edge_BERS_out ) begin if (WPNeg != 0 && BadBlockTable[Blck] == 0) begin memory_features_i0.erase_mem_w( Blck *(BlockSize + 1) *(PageSize + 1), (Blck+1)*(BlockSize + 1) *(PageSize + 1)-1 ); corrupt_flag[Blck] = 0; end if (BadBlockTable[Blck] == 1) Status[0] = 1; else Status[0] = 0; BERS_in = 0; ERS_ACT = 0; R_zd = 1; Status[6] = 1'b1; end if (falling_edge_write) begin if (CLE && ~ALE && Data == 8'hff) begin BERS_in = 0; set_reset; end else if (CLE && ~ALE && Data == 8'h70) STAT_ACT = 1; else if (CLE && STAT_ACT) STAT_ACT = 0; end if (oe) if (STAT_ACT) Read_Status; end PGD_PREL: begin if (falling_edge_write) if (ALE) begin Pom_Address = AddrCom; cnt_addr = 0; end else if (CLE && Data == 8'hff) set_reset; end A0_PGD: begin if (falling_edge_write) if (ALE) begin Pom_Address = (AddrCom*12'h100)+Pom_Address; WrAddr = Pom_Address; cnt_addr = cnt_addr+1; end else if (CLE && Data == 8'hff) set_reset; end A1_PGD: begin if (falling_edge_write) if (ALE) begin Page = AddrCom; cnt_addr = cnt_addr+1; end else if (CLE && Data == 8'hff) set_reset; end A2_PGD: begin if (falling_edge_write) if (ALE) begin Page = (AddrCom* 12'h100 + Page); Blck = Page / (BlockSize+1); BlockPage = Page % (BlockSize+1); cnt_addr = cnt_addr + 1; end else if (CLE && Data == 8'hff) set_reset; end CONF_PGD: begin if (falling_edge_write) begin if (CLE && ~ALE && (Data == 8'h10 || Data == 8'h85)) begin for (i=0; i<= PageSize; i=i+1) CashBuffData[i] = PDBuffer[i]; for (i=0; i<=SegmentNum; i=i+1) SegForProg[i] = 1; WrPage = Page; if (CLE && ~ALE && Data == 8'h10) begin R_zd = 0; Status[6] = 0; end end else if (ALE) begin cnt_addr = cnt_addr + 1; end else if (CLE && ~ALE && Data == 8'hff) set_reset; end end endcase end if (RENeg || CENeg) DOut_zd = 8'bz; if ((TR_out || PROG_out ) && read && STAT_ACT) Read_Status; end //////////////////////////////////////////////////////////////////// // Flag generation process //////////////////////////////////////////////////////////////////// always @(rising_edge_RSTDONE, falling_edge_write, rising_edge_PROG_out) begin : FlagGeneration if (falling_edge_write) begin if ((current_state == DATA_PRG || current_state == CONF_PGD) && CLE && ~ALE && Data == 8'h10) begin if (~PRG_ACT) begin PRG_ACT = 1; PROG_in = 1; end end end if (current_state == PGMS ) begin if (rising_edge_PROG_out ) begin PRG_ACT = 0; Status[6] = 1; PROG_in = 0; if (WPNeg != 0 && BadBlockTable[WrPage/(BlockSize+1)]==0) begin for (j=0; j<= PageSize; j=j+1) begin getSegment(j, pom_seg); if (WrBuffData[j] != -1 && ProgramedFlag[WrPage*(SegmentNum+1) +pom_seg] == 0) memory_features_i0.write_mem_w( WrPage * (PageSize + 1) + j, WrBuffData[j]); end for (j=0; j<= SegmentNum; j=j+1) ProgramedFlag [WrPage*(SegmentNum+1) +j] = SegForProg[j]; end end else if (falling_edge_write) begin if (CLE && ~ALE && Data == 8'hff && PRG_ACT) begin PROG_in = 0; end end end else if (current_state == RESET) if (rising_edge_RSTDONE) PRG_ACT = 0; end task set_reset; begin STAT_ACT = 1'b0; RSTSTART = 1'b1; RSTSTART <= #1 1'b0; R_zd = 1'b0; end endtask task Read_Data; inout [31:0] Addr; inout [31:0] Page; integer memory_read_data_internal; begin memory_features_i0.read_mem_w( memory_read_data_internal, Page * (PageSize + 1) + Addr ); if (memory_read_data_internal != -1) DOut_zd = memory_read_data_internal; else DOut_zd = 8'bx; if (corrupt_flag[Blck] == 1) DOut_zd = 8'bx; if (Addr < PageSize) Addr = Addr + 1; end endtask task Read_Status; begin DOut_zd = Status; end endtask task getSegment; input integer paddress; output integer m; integer v; begin for (v = 0; v<= SegmentNum; v=v+1) begin if ((paddress >= ssam[v] && paddress <= seam[v]) || (paddress >= ssas[v] && paddress <= seas[v])) m = v; end end endtask always @(posedge read) begin rising_edge_read = 1; #1 rising_edge_read = 0; end always @(posedge reseted) begin rising_edge_reseted = 1; #1 rising_edge_reseted = 0; end always @(negedge write) begin falling_edge_write = 1; #1 falling_edge_write = 0; end always @(posedge TR_out) begin rising_edge_TR_out = 1; #1 rising_edge_TR_out = 0; end always @(posedge PROG_out) begin rising_edge_PROG_out = 1; #1 rising_edge_PROG_out = 0; end always @(posedge BERS_out) begin rising_edge_BERS_out = 1; #1 rising_edge_BERS_out = 0; end always @(posedge RSTDONE) begin rising_edge_RSTDONE = 1; #1 rising_edge_RSTDONE = 0; end reg BuffInR; wire BuffOutR; BUFFER BUFR (BuffOutR , BuffInR); initial begin BuffInR = 1'b1; end always @(posedge BuffOutR) begin WER_01 = $time; end endmodule module BUFFER (OUT,IN); input IN; output OUT; buf (OUT, IN); endmodule module memory_features(); // ------------------------------------------------------------------------- // ---------------- start of memory management section --------------- // ------------------------------------------------------------------------- // memory partitioning parameters parameter list_num = 512; parameter list_size = 20'h21000; // memory initial data value parameter MaxData = 8'hFF; // memory management routines // handle dynamic memory allocation // abstract memory region model class linked_list_c; // memory element model reg[31:0] key_address; integer val_data; // organize memory storage elements into a linked list linked_list_c successor; function new( integer address_a, integer data_a); begin key_address = address_a; val_data = data_a; successor = null; end endfunction endclass // partition memory region for faster access linked_list_c linked_list [list_num]; // class methods internal communication pool linked_list_c found; linked_list_c prev; linked_list_c sub_linked_list; linked_list_c sub_linked_list_last; // low-level routines class low_level_interface_c; // assure proper initialization function new; integer new_iter; begin // initialize linked list handles for(new_iter=0; new_iter < list_num; new_iter = new_iter + 1) linked_list[new_iter] = null; found = null; prev = null; sub_linked_list = null; sub_linked_list_last = null; end endfunction // Iterate through linked listed comapring key values // Stop when key value greater or equal task position_list( integer address_a, linked_list_c root); begin found = root; prev = null; while ((found != null) && (found.key_address < address_a)) begin prev = found; found = found.successor; end end endtask // Add new element to a linked list task insert_list( integer address_a, integer data_a, integer list_id); linked_list_c new_element; begin this.position_list( address_a, linked_list[list_id]); // Insert at list tail if (found == null) begin prev.successor = new(address_a, data_a); end else begin // Element exists, update memory data value if (found.key_address == address_a) begin found.val_data = data_a; end else begin // No element found, allocate and link new_element = new(address_a, data_a); new_element.successor = found; // Possible root position if (prev != null) begin prev.successor = new_element; end else begin linked_list[list_id] = new_element; end end end end endtask // Remove element from a linked list task remove_list( integer address_a, integer list_id); begin this.position_list( address_a, linked_list[list_id]); if (found != null) // Key value match if (found.key_address == address_a) begin // Handle root position removal if (prev != null) prev.successor = found.successor; else linked_list[list_id] = found.successor; // garbage collector found = null; end end endtask // Remove range of elements from a linked list // Higher performance than one-by-one removal task remove_list_range( integer address_low, integer address_high, integer list_id); linked_list_c iter; linked_list_c prev_remove; linked_list_c link_element; begin iter = linked_list[list_id]; prev_remove = null; // Find first linked list element belonging to // a specified address range [address_low, address_high] while ((iter != null) && !( (iter.key_address >= address_low) && (iter.key_address <= address_high))) begin prev_remove = iter; iter = iter.successor; end // Continue until address_high reached // Deallocate linked list elements pointed by iterator if (iter != null) begin while ((iter != null) && (iter.key_address >= address_low) && (iter.key_address <= address_high)) begin link_element = iter.successor; //garbage collector iter.successor = null; iter = link_element; end // Handle possible root value change if ( prev_remove != null ) prev_remove.successor = link_element; else linked_list[list_id] = link_element; end end endtask endclass // higher-level routines // provided memory RW operation class interface class rw_interface_c; low_level_interface_c low_level_interface; // assure proper initialization function new; integer new_iter; begin // allocate low level interface object low_level_interface = new; end endfunction task read_mem( inout integer data_a, input integer address_a); integer mem_data; integer list_id; begin // Higher performance, segment paritioning list_id = address_a / list_size; if (linked_list[list_id] == null) // Not allocated, not written, initial value mem_data = MaxData; else begin low_level_interface.position_list( address_a, linked_list[list_id]); if (found != null) begin if (found.key_address == address_a) // Allocated, val_data stored mem_data = found.val_data; else // Not allocated, not written, initial value mem_data = MaxData; end else begin // Not allocated, not written, initial value mem_data = MaxData; end end data_a = mem_data; end endtask // Memory WRITE operation performed above dynamically allocated space task write_mem( input integer address_a, input integer data_a); integer list_id; begin // Higher performance, segment paritioning list_id = address_a / list_size; if (data_a !== MaxData) begin // Handle possible root value update if (linked_list[list_id] !== null) begin low_level_interface.insert_list( address_a, data_a, list_id); end else begin linked_list[list_id] = new(address_a, data_a); end end else begin // Deallocate if initial value written // No linked list, NOP, initial value implicit if (linked_list[list_id] !== null) begin low_level_interface.remove_list( address_a, list_id); end end end endtask // Address range to be erased task erase_mem( input integer address_low, input integer address_high); integer list_id; begin list_id = address_low / list_size; low_level_interface.remove_list_range( address_low, address_high, list_id ); end endtask endclass // object declaration holding memory management model rw_interface_c rw_interface; //interface towards higher hierarchy instances routine calls //wrapped from within the memory_features module //low-level routine access forbidden task initialize_w; begin rw_interface = new; end endtask task read_mem_w( inout integer data_a, input integer address_a); begin rw_interface.read_mem(data_a, address_a); end endtask task write_mem_w( input integer address_a, input integer data_a); begin rw_interface.write_mem(address_a, data_a); end endtask task erase_mem_w( input integer address_low, input integer address_high); begin rw_interface.erase_mem(address_low, address_high); end endtask // ------------------------------------------------------------------------- // ---------------- the end of memory management section ------------- // ------------------------------------------------------------------------- endmodule