NAND Flash Simulation Model设计总结

NAND Flash Simulation Model设计总结:
重点是如何建立这样的模型:
通常做ASIC设计所可以使用的Verilog语言的成分比Verilog能提供的要小。它必须是可综合的。而用于仿真的Verilog程序,就可以使用整个Verilog所提供的语言全集。下面介绍一些设计仿真模型的相关技术:
1.    task的使用
task便于封装一些通用的任务,这常常在Test bench中使用。
例如:
task    memory_read;
   input  [BLCK_BITS-1:0] block;
   input  [PAGE_BITS-1:0]  page;
   input  [COL_BITS-1:0]    col;
   output [DQ_BITS-1:0]    data;

   reg    [(ROW_BITS + COL_BITS) -1:0] addr;
   reg    [(ROW_BITS) -1:0]       page_addr;

   begin
      // chop off the lowest address bits
      addr = {block, page, col};
      page_addr = {block, page};

      data = mem_array[addr];
   end
endtask
    使用Task便于提供一个接口,这个接口可以被用来调用。

2.     如何模拟电路中的一些Timing
比如建立,保持时间
   每个Chip都有一些Timing之类的参数,一般在Chip的Datasheet中提供。为了模拟Chip的Timing特性。
   Io_buf <= #tREA_max status_register;
   #tWB_max;
    第一句,是在延迟#tREA_max后,输出status_register的内容到Io_buf去。
    第二句,是简单的延迟tWB_max。

3.     如何建立模型:
因为模型不必是可综合的,所以,可以采用Verilog中所有的语言成分。
我们的地址,命令和数据都是在We_n的上升沿进行的锁存。所以采用这样的结构来采样地址,命令和数据。

//
//   address state enable.这下面是接收地址的允许条件
//

assign address_enable = (~Cle && Ale && ~Ce_n && Re_n);

//   Address Latch, get the latched address on the rising edge of We_n

always @ (posedge We_n) begin // positive edge of We_n
    
    if (address_enable) begin : latch_address
        // Latch Column Address
        if (addr_start <= COL_BYTES && addr_start <= addr_stop && ~col_valid) begin : latch_col_addr

            case (addr_start)
                1 : col_addr[7 : 0] = Io[7 : 0];
                2 : col_addr[COL_BITS - 1 : 8] = Io[7 : 0];
            endcase

            if (addr_start >= 2) begin
                col_valid = 1'b1;
            end
        end // latch_col_addr

        // Latch Row Address
        if (addr_start >= (COL_BYTES +1) && addr_start <= addr_stop) begin : latch_row_addr
        
            case (addr_start)
                3 : begin
                    row_addr_last[active_plane] = new_addr;
                    row_valid = 1'b0; ####
                    new_addr[7:0] = Io[7:0];
                end
                
                4 : begin
                    new_addr[15:8] = Io[7:0];
                end
                
                5 : begin
                    new_addr[(ROW_BITS -1):16] = Io[(ROW_BITS -1 -16):0];
                    end
            endcase
                
            //   make sure interleaved ops don't allow the inactive die to continue when
            //   the address is out of it's range
            
            if ((addr_start >= ADDR_BYTES)) begin
                row_valid = 1'b1; // This will trigger the always @(row_valid) procedure. ###
            end
        
        end // latch_row_addr

        addr_start = addr_start + 1; // Increase Address Counter

    end // latch_address
end

//
// Set active plane and address once address is valid
//

一旦接收完地址,这个always块将被立刻执行。

always @ (posedge row_valid) begin
    
   //   The bit 6 of the first byte of the row address indicate the plane number.
   active_plane = new_addr[PAGE_BITS + (NUM_PLANES >> 2) : PAGE_BITS];
   
   row_addr[active_plane] = new_addr;
end

//
//    Command input
//

assign command_enable  = (Cle && ~Ale && ~Ce_n && Re_n);

always @ (posedge We_n) begin : cLatch

        if (Rb_n_int === 1'b1) begin : cLatch_unbusy
            if (Io[7:0] === 8'h00) begin : cmnd_00h
            end else if (Io[7:0] === 8'h05) begin
            end else if ((Io[7:0] === 8'h10)) begin
            end else if (Io[7 : 0] === 8'h11) begin
            end else if (Io[7:0] === 8'h30) begin
            end else if ((Io[7:0] === 8'h35)) begin
            end else if (Io[7:0] === 8'h60) begin
            end else if (Io[7:0] === 8'h70) begin
            end else if (Io[7:0] === 8'h7B) begin
            end else if (Io[7:0] === 8'h80) begin
            end else if (Io[7:0] === 8'h85) begin
            end else if ((Io[7:0] === 8'h90)) begin
            end else if (Io[7:0] === 8'hD0) begin
            end else if (Io[7:0] === 8'hE0) begin
            end else if (Io[7:0] === 8'hFF) begin
            end else begin
            end
        end //  cLatch_unbusy
        else if (Rb_n_int === 1'b0) begin
            //   else we are busy and only certain commands are allowed
            //   even when busy we need to do status and reset
            if (Io[7:0] === 8'h70) begin
            end else if (Io[7:0] === 8'h7B) begin
            end else if (Io[7:0] === 8'hFF) begin
            end else begin
            end
        end // : cLatch_unbusy/busy_command
    end // : Cle_enable
end    // : cLatch

//-----------------------------------------------------------------
// Data input
//-----------------------------------------------------------------

assign datain = (~Cle & ~Ale & ~Ce_n & Re_n & Wp_n & (Rb_n_int === 1'b1));

//
//   data input
//

always @(posedge We_n) begin
    
   //  data input
   if (datain) begin : latch_data
   
         if (col_valid && row_valid && (col_addr + col_counter <= NUM_COL - 1))  begin
             
            // Data Register
            data_reg[active_plane][col_addr + col_counter] = Io;
         
            // Increase Column Counter
            col_counter = col_counter + 1;
        end
    end // latch_data

end

// Data output

assign    data_out_enable = (~Cle && ~Ale && ~Ce_n && We_n);

always @ (negedge Re_n) begin
    
    //   status output
    
    if (data_out_enable && ((cmnd_70h === 1'b1) || (cmnd_7Bh === 1'b1))) begin

        output_status; // output the status.

    end else begin
        
        //   only need to go here if not a status reg read
        if   (data_out_enable && (Rb_n_int === 1'b1)) begin : not_busy

            // Normal Page Read
            if (col_valid && row_valid && (col_addr + col_counter <= NUM_COL - 1))  begin
               Io_buf <= #(tm_ce_n_f + tCEA_max - $realtime) data_reg[active_plane][col_addr + col_counter];
               rd_out <= #(tm_ce_n_f + tCEA_max - $realtime) 1'b1;

               // Increase Column Counter
               col_counter = col_counter + 1;

            //-----------------
            // extra case to drive data bus high z after column boundary is reached
            //-----------------

            end else if (~cmnd_70h && ~cmnd_7Bh && col_valid && row_valid && (col_addr + col_counter > NUM_COL - 1)) begin
                rd_out <= #(tREA_max) 1'b0;
            end else if (lastCmd === 8'h90) begin

                if (id_reg_addr === 8'h00) begin : regular_id_read

                    //   Read ID
                    if (col_counter > (NUM_ID_BYTES - 1)) begin
                        col_counter = 0;
                       end
                    case (col_counter)
                        0 : begin Io_buf <= #(tREA_max) READ_ID_BYTE0; end
                        1 : begin Io_buf <= #(tREA_max) READ_ID_BYTE1; end
                        2 : begin Io_buf <= #(tREA_max) READ_ID_BYTE2; end
                        3 : begin Io_buf <= #(tREA_max) READ_ID_BYTE3; end
                        4 : begin Io_buf <= #(tREA_max) READ_ID_BYTE4; end
                    endcase

                    rd_out <= #(tREA_max) 1'b1;

                    // Advance counter
                    col_counter = col_counter + 1;

               end // end of regular_id_read block
            end else begin

                //  No valid data
                rd_out <= #(tREA_max) 1'b0;
            end
        end else begin  

            //   not_busy block : else (if busy)
            //   this will output zz's if Re_n is toggled during busy with a status command

            if   (~(cmnd_70h || cmnd_7Bh)) begin rd_out <= #(tREA_max) 1'b0; end
        end // : not_busy
    end
end

//#####################################################
// Tri - stating the IO bus
//
//  This section control the tri-stating of the IO
// bus based on when Re_n and Ce_n transition.
//
//#####################################################

//---------------------------
//  Re_n->IO transitions
//---------------------------

always @ (posedge Re_n) begin

    //   posedge Re_n with Ce_n low
    if (data_out_enable && Re_n) begin
        //   schedule these transitions
        IoX_enable <= #(tRHOH_min) 1'b1;
        IoX_enable <= #(tRHZ_max-1) 1'b1;
        IoX_enable <= #(tRHZ_max) 1'b0;
        rd_out <= #tRHOH_min 1'b0;     
        t_readtox = ($realtime + tRHOH_min);
        t_readtoz = ($realtime + tRHZ_max);
    end
end

//   enable X's on output
always @(posedge IoX_enable) begin
    if (t_readtox == $realtime) begin
        IoX <= 1'b1;
        rd_out <= 1'b0;
    end
end

//   disable X's on output
always @(negedge IoX_enable) begin
    if (t_readtoz == $realtime) begin
        IoX <= 1'b0;
        rd_out <= 1'b0;
    end
end

4. 如何做Timing Checks
看看芯片的Datasheet,你可以了解很多的Timing是有基准的,以某个信号点为基准,然后来讨论其建立时间,保持时间什么的。这里,很多是以We_n的上升边沿为基准的,于是,我们可以利用这个特点来做Timing Checks。

//#############################################################################
// Timing checks
//#############################################################################

always @ (We_n) begin // 这个是以We_n为基准的Timing Checks。

if (~We_n) begin : negedge_We_n // negative edge

        if (~Ce_n) begin
           // 这里是进行Timing Checks的语句。
            tm_we_n_f <= $realtime;   // 这里记录We_n信号的下降沿发生的时间
        end

    end else begin : posedge_We_n   // positive edge
    
        if (~Ce_n) begin

            //  这里是进行Timing Checks的语句。    
            tm_we_n_r <= $realtime;  // // 这里记录We_n信号的上升沿发生的时间

        if (Ale) tm_we_n_r_ale <= $realtime;
    end //   posedge_We_n

end

//---------------------------------------------------------------------------------------
//
//---------------------------------------------------------------------------------------

always @ (Re_n) begin // 这个是以Re_n为基准所进行的Timing Checks
    
    if (~Re_n) begin : negedge_Re_n
    
        if (~Ce_n) begin

            // 这里是以Re_n的下降沿为基准所进行的Timing Checks。
        end
 
        tm_re_n_f <= $realtime; // 记录Re_n的下降沿发生的时间
        
    end else begin : posedge_Re_n
    
        if (~Ce_n) begin
            
           //  这里是以Re_n的上升沿为基准所进行的Timing Checks。
        end
        
        tm_re_n_r <= $realtime; // 记录Re_n的上升沿发生的时间
    end // posedge_Re_n
end

//----------------------------------------------------------------------------
//
//----------------------------------------------------------------------------

always @ (Ce_n) begin // 这个是以Ce_n为基准所进行的Timing Checks
    
    if (~Ce_n) begin // negedge Ce_n
    
        tm_ce_n_f <= $realtime;
        
    end else begin   // posedge Ce_n
        
    // ......
       
        tm_ce_n_r <= $realtime;
    end

end

//------------------------------------------------------------------------------
//
//------------------------------------------------------------------------------

always @ (Rb_n) begin
    
    if (~Rb_n) begin
        tm_rb_n_f <= $realtime;
    end else begin
        tm_rb_n_r <= $realtime;
    end

end

//-------------------------------------------------------------------------------
//
//-------------------------------------------------------------------------------

always @ (Cle) begin
    
   if (~Ce_n) begin
      
      if (~Cle) begin // negedge Cle
         tm_cle_f <= $realtime;
      end else begin  // posedge Cle
         tm_cle_r <= $realtime;
      end
    
   end // && ~Ce_n
 
end

//--------------------------------------------------------------------------------
//
//--------------------------------------------------------------------------------

always @ (Ale) begin
    
   if (~Ce_n) begin
    
      if (~Ale) begin // negedge Ale
         tm_ale_f <= $realtime;
      end else begin  // posedge Ale
         tm_ale_r <= $realtime;
      end
    
   end // ~Ce_n

end

//-------------------------------------------------------------------------------
//
//-------------------------------------------------------------------------------

always @ (Io_buf) begin
    
  if (~Ce_n) begin
      
    if ((Io_buf === {DQ_BITS{1'bx}}) && ($realtime == t_readtox)) begin
        
        if (PowerUp_Complete) begin

       // ......                
        end
        
        tm_io_datatoz <= $realtime;

    end else begin
        tm_io_ztodata <= $realtime;
    end

  end // ~Ce_n
 
end

你可能感兴趣的:(IO,command,Flash,input,byte,output)