german010 发表于 2013-2-22 04:52:45

modelsim仿真sdram,如何修改仿真模型参数?

本帖最后由 german010 于 2013-2-22 07:13 编辑

请教大家个问题:
我用 mt48lc8m16a2的仿真模型代替HY57V641620ETP-H来进行仿真,工作频率为100Mhz,

出现如下ERROR提示,应该是时序违例造成的吧,应该是模型代码最下面的参数 不满足100Mhz工作时的时序要求,应该如何修改?

run 2ms
#Note : Cyclone IV E PLL was reset
# Time: 0 nsInstance: modelsim_test_tb.sdr_test.uut_sysctrl.uut_PLL_ctrl.altpll_component.cycloneiii_pll.pll3
# ** Error: E:/log/13.02.18/232SDRAM3_1_many/mt48lc8m16a2.v(892): $hold( posedge Clk:260 ns, Cke:260 ns, 800 ps );
#    Time: 260 nsIteration: 6Instance: /modelsim_test_tb/mt48lc8m16a2
# ** Error: E:/log/13.02.18/232SDRAM3_1_many/mt48lc8m16a2.v(893): $hold( posedge Clk:260 ns, Cs_n:260 ns, 800 ps );
#    Time: 260 nsIteration: 6Instance: /modelsim_test_tb/mt48lc8m16a2
#Note : Cyclone IV E PLL locked to incoming clock
# Time: 420 nsInstance: modelsim_test_tb.sdr_test.uut_sysctrl.uut_PLL_ctrl.altpll_component.cycloneiii_pll.pll3
# ** Error: E:/log/13.02.18/232SDRAM3_1_many/mt48lc8m16a2.v(889): $width( negedge Clk:420 ns, :422187 ps, 2500 ps );
#    Time: 422187 psIteration: 3Instance: /modelsim_test_tb/mt48lc8m16a2
# ** Error: E:/log/13.02.18/232SDRAM3_1_many/mt48lc8m16a2.v(890): $period( negedge Clk:420 ns, :427187 ps, 7500 ps );
#    Time: 427187 psIteration: 3Instance: /modelsim_test_tb/mt48lc8m16a2

下面是 mt48lc8m16a2的仿真模型,大家帮忙看看
/****************************************************************************************
*
*    File Name:MT48LC8M16A2.V
*      Version:0.0f
*         Date:July 8th, 1999
*      Model:BUS Functional
*    Simulator:Model Technology (PC version 5.2e PE)
*
* Dependencies:None
*
*       Author:Son P. Huynh
*      Email:sphuynh@micron.com
*      Phone:(208) 368-3825
*      Company:Micron Technology, Inc.
*      Model:MT48LC8M16A2 (2Meg x 16 x 4 Banks)
*
*Description:Micron 128Mb SDRAM Verilog model
*
*   Limitation:- Doesn't check for 4096 cycle refresh
*
*         Note:- Set simulator resolution to "ps" accuracy
*                - Set Debug = 0 to disable $display messages
*
*   Disclaimer:THESE DESIGNS ARE PROVIDED "AS IS" WITH NO WARRANTY
*                WHATSOEVER AND MICRON SPECIFICALLY DISCLAIMS ANY
*                IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR
*                A PARTICULAR PURPOSE, OR AGAINST INFRINGEMENT.
*
*                Copyright © 1998 Micron Semiconductor Products, Inc.
*                All rights researved
*
* Rev   Author          Phone         Date      Changes
* ---------------------------------------------------------------------------------
* 0.0fSon Huynh       208-368-382507/08/1999- Fix tWR = 1 Clk + 7.5 ns (Auto)
*       Micron Technology Inc.                  - Fix tWR = 15 ns (Manual)
*                                                 - Fix tRP (Autoprecharge to AutoRefresh)
*
* 0.0aSon Huynh       208-368-382505/13/1998- First Release (from 64Mb rev 0.0e)
*       Micron Technology Inc.
****************************************************************************************/

`timescale 1ns / 1ps

module mt48lc8m16a2 (Dq, Addr, Ba, Clk, Cke, Cs_n, Ras_n, Cas_n, We_n, Dqm);

    parameter addr_bits =      12;
    parameter data_bits =      16;
    //parameter col_bits=       9;
    parameter col_bits=       8;
    //parameter mem_sizes = 2097151;
    parameter mem_sizes = 1048575;                                  // 2 Meg

    inout    Dq;
    input    Addr;
    input                Ba;
    input                         Clk;
    input                         Cke;
    input                         Cs_n;
    input                         Ras_n;
    input                         Cas_n;
    input                         We_n;
    input                Dqm;

    reg       Bank0 ;
    reg       Bank1 ;
    reg       Bank2 ;
    reg       Bank3 ;

    reg                   Bank_addr ;                // Bank Address Pipeline
    reg       Col_addr ;               // Column Address Pipeline
    reg                   Command ;                  // Command Operation Pipeline
    reg                   Dqm_reg0, Dqm_reg1;               // DQM Operation Pipeline
    reg       B0_row_addr, B1_row_addr, B2_row_addr, B3_row_addr;

    reg       Mode_reg;
    reg       Dq_reg, Dq_dqm;
    reg       Col_temp, Burst_counter;

    reg                           Act_b0, Act_b1, Act_b2, Act_b3;   // Bank Activate
    reg                           Pc_b0, Pc_b1, Pc_b2, Pc_b3;       // Bank Precharge

    reg                   Bank_precharge   ;       // Precharge Command
    reg                           A10_precharge      ;       // Addr = 1 (All banks)
    reg                           Auto_precharge   ;       // RW AutoPrecharge (Bank)
    reg                           Read_precharge   ;       // RAutoPrecharge
    reg                           Write_precharge    ;       //W AutoPrecharge
    integer                     Count_precharge    ;       // RW AutoPrecharge (Counter)
    reg                           RW_interrupt_read;       // RW Interrupt Read with Auto Precharge
    reg                           RW_interrupt_write ;       // RW Interrupt Write with Auto Precharge

    reg                           Data_in_enable;
    reg                           Data_out_enable;

    reg                   Bank, Previous_bank;
    reg       Row;
    reg       Col, Col_brst;

    // Internal system clock
    reg                           CkeZ, Sys_clk;

    // Commands Decode
    wire      Active_enable    = ~Cs_n & ~Ras_n &Cas_n &We_n;
    wire      Aref_enable      = ~Cs_n & ~Ras_n & ~Cas_n &We_n;
    wire      Burst_term       = ~Cs_n &Ras_n &Cas_n & ~We_n;
    wire      Mode_reg_enable= ~Cs_n & ~Ras_n & ~Cas_n & ~We_n;
    wire      Prech_enable   = ~Cs_n & ~Ras_n &Cas_n & ~We_n;
    wire      Read_enable      = ~Cs_n &Ras_n & ~Cas_n &We_n;
    wire      Write_enable   = ~Cs_n &Ras_n & ~Cas_n & ~We_n;

    // Burst Length Decode
    wire      Burst_length_1   = ~Mode_reg & ~Mode_reg & ~Mode_reg;
    wire      Burst_length_2   = ~Mode_reg & ~Mode_reg &Mode_reg;
    wire      Burst_length_4   = ~Mode_reg &Mode_reg & ~Mode_reg;
    wire      Burst_length_8   = ~Mode_reg &Mode_reg &Mode_reg;

    // CAS Latency Decode
    wire      Cas_latency_2    = ~Mode_reg &Mode_reg & ~Mode_reg;
    wire      Cas_latency_3    = ~Mode_reg &Mode_reg &Mode_reg;

    // Write Burst Mode
    wire      Write_burst_mode = Mode_reg;

    wire      Debug            = 1'b0;                        // Debug messages : 1 = On
    wire      Dq_chk         = Sys_clk & Data_in_enable;      // Check setup/hold time for DQ

    assign    Dq               = Dq_reg;                        // DQ buffer

    // Commands Operation
    `define   ACT       0
    `define   NOP       1
    `define   READ      2
    `define   READ_A    3
    `define   WRITE   4
    `define   WRITE_A   5
    `define   PRECH   6
    `define   A_REF   7
    `define   BST       8
    `define   LMR       9

    // Timing Parameters for -75 (PC133) and CAS Latency = 2
    parameter tAC=   6.0;
    parameter tHZ=   7.0;
    parameter tOH=   2.7;
    parameter tMRD =   2.0;   // 2 Clk Cycles
    parameter tRAS =44.0;
    parameter tRC=66.0;
    parameter tRCD =20.0;
    parameter tRP=20.0;
    parameter tRRD =15.0;
    parameter tWRa =   7.5;   // A2 Version - Auto precharge mode only (1 Clk + 7.5 ns)
    parameter tWRp =0.0;   // A2 Version - Precharge mode only (15 ns)

    // Timing Check variable
    integer   MRD_chk;
    integer   WR_counter ;
    time      WR_chk ;
    time      RC_chk, RRD_chk;
    time      RAS_chk0, RAS_chk1, RAS_chk2, RAS_chk3;
    time      RCD_chk0, RCD_chk1, RCD_chk2, RCD_chk3;
    time      RP_chk0, RP_chk1, RP_chk2, RP_chk3;

    initial begin
      Dq_reg = {data_bits{1'bz}};
      {Data_in_enable, Data_out_enable} = 0;
      {Act_b0, Act_b1, Act_b2, Act_b3} = 4'b0000;
      {Pc_b0, Pc_b1, Pc_b2, Pc_b3} = 4'b0000;
      {WR_chk, WR_chk, WR_chk, WR_chk} = 0;
      {WR_counter, WR_counter, WR_counter, WR_counter} = 0;
      {RW_interrupt_read, RW_interrupt_read, RW_interrupt_read, RW_interrupt_read} = 0;
      {RW_interrupt_write, RW_interrupt_write, RW_interrupt_write, RW_interrupt_write} = 0;
      {MRD_chk, RC_chk, RRD_chk} = 0;
      {RAS_chk0, RAS_chk1, RAS_chk2, RAS_chk3} = 0;
      {RCD_chk0, RCD_chk1, RCD_chk2, RCD_chk3} = 0;
      {RP_chk0, RP_chk1, RP_chk2, RP_chk3} = 0;
      $timeformat (-9, 0, " ns", 12);
      //$readmemh("bank0.txt", Bank0);
      //$readmemh("bank1.txt", Bank1);
      //$readmemh("bank2.txt", Bank2);
      //$readmemh("bank3.txt", Bank3);
    end

    // System clock generator
    always begin
      @ (posedge Clk) begin
            Sys_clk = CkeZ;
            CkeZ = Cke;
      end
      @ (negedge Clk) begin
            Sys_clk = 1'b0;
      end
    end

    always @ (posedge Sys_clk) begin
      // Internal Commamd Pipelined
      Command = Command;
      Command = Command;
      Command = Command;
      Command = `NOP;

      Col_addr = Col_addr;
      Col_addr = Col_addr;
      Col_addr = Col_addr;
      Col_addr = {col_bits{1'b0}};

      Bank_addr = Bank_addr;
      Bank_addr = Bank_addr;
      Bank_addr = Bank_addr;
      Bank_addr = 2'b0;

      Bank_precharge = Bank_precharge;
      Bank_precharge = Bank_precharge;
      Bank_precharge = Bank_precharge;
      Bank_precharge = 2'b0;

      A10_precharge = A10_precharge;
      A10_precharge = A10_precharge;
      A10_precharge = A10_precharge;
      A10_precharge = 1'b0;

      // Dqm pipeline for Read
      Dqm_reg0 = Dqm_reg1;
      Dqm_reg1 = Dqm;

      // Read or Write with Auto Precharge Counter
      if (Auto_precharge == 1'b1) begin
            Count_precharge = Count_precharge + 1;
      end
      if (Auto_precharge == 1'b1) begin
            Count_precharge = Count_precharge + 1;
      end
      if (Auto_precharge == 1'b1) begin
            Count_precharge = Count_precharge + 1;
      end
      if (Auto_precharge == 1'b1) begin
            Count_precharge = Count_precharge + 1;
      end

      // tMRD Counter
      MRD_chk = MRD_chk + 1;

      // tWR Counter for Write
      WR_counter = WR_counter + 1;
      WR_counter = WR_counter + 1;
      WR_counter = WR_counter + 1;
      WR_counter = WR_counter + 1;

      // Auto Refresh
      if (Aref_enable == 1'b1) begin
            if (Debug) $display ("at time %t AREF : Auto Refresh", $time);
            // Auto Refresh to Auto Refresh
            if ($time - RC_chk < tRC) begin
                $display ("at time %t ERROR: tRC violation during Auto Refresh", $time);
            end
            // Precharge to Auto Refresh
            if ($time - RP_chk0 < tRP || $time - RP_chk1 < tRP || $time - RP_chk2 < tRP || $time - RP_chk3 < tRP) begin
                $display ("at time %t ERROR: tRP violation during Auto Refresh", $time);
            end
            // Precharge to Refresh
            if (Pc_b0 == 1'b0 || Pc_b1 == 1'b0 || Pc_b2 == 1'b0 || Pc_b3 == 1'b0) begin
                $display ("at time %t ERROR: All banks must be Precharge before Auto Refresh", $time);
            end
            // Record Current tRC time
            RC_chk = $time;
      end
      
      // Load Mode Register
      if (Mode_reg_enable == 1'b1) begin
            // Decode CAS Latency, Burst Length, Burst Type, and Write Burst Mode
            if (Pc_b0 == 1'b1 && Pc_b1 == 1'b1 && Pc_b2 == 1'b1 && Pc_b3 == 1'b1) begin
                Mode_reg = Addr;
                if (Debug) begin
                  $display ("at time %t LMR: Load Mode Register", $time);
                  // CAS Latency
                  if (Addr == 3'b010)
                        $display ("                            CAS Latency      = 2");
                  else if (Addr == 3'b011)
                        $display ("                            CAS Latency      = 3");
                  else
                        $display ("                            CAS Latency      = Reserved");
                  // Burst Length
                  if (Addr == 3'b000)
                        $display ("                            Burst Length   = 1");
                  else if (Addr == 3'b001)
                        $display ("                            Burst Length   = 2");
                  else if (Addr == 3'b010)
                        $display ("                            Burst Length   = 4");
                  else if (Addr == 3'b011)
                        $display ("                            Burst Length   = 8");
                  else if (Addr == 4'b0111)
                        $display ("                            Burst Length   = Full");
                  else
                        $display ("                            Burst Length   = Reserved");
                  // Burst Type
                  if (Addr == 1'b0)
                        $display ("                            Burst Type       = Sequential");
                  else if (Addr == 1'b1)
                        $display ("                            Burst Type       = Interleaved");
                  else
                        $display ("                            Burst Type       = Reserved");
                  // Write Burst Mode
                  if (Addr == 1'b0)
                        $display ("                            Write Burst Mode = Programmed Burst Length");
                  else if (Addr == 1'b1)
                        $display ("                            Write Burst Mode = Single Location Access");
                  else
                        $display ("                            Write Burst Mode = Reserved");
                end
            end else begin
                $display ("at time %t ERROR: all banks must be Precharge before Load Mode Register", $time);
            end
            // REF to LMR
            if ($time - RC_chk < tRC) begin
                $display ("at time %t ERROR: tRC violation during Load Mode Register", $time);
            end
            // LMR to LMR
            if (MRD_chk < tMRD) begin
                $display ("at time %t ERROR: tMRD violation during Load Mode Register", $time);
            end
            MRD_chk = 0;
      end
      
      // Active Block (Latch Bank Address and Row Address)
      if (Active_enable == 1'b1) begin
            if (Ba == 2'b00 && Pc_b0 == 1'b1) begin
                {Act_b0, Pc_b0} = 2'b10;
                B0_row_addr = Addr ;
                RCD_chk0 = $time;
                RAS_chk0 = $time;
                if (Debug) $display ("at time %t ACT: Bank = 0 Row = %d", $time, Addr);
                // Precharge to Activate Bank 0
                if ($time - RP_chk0 < tRP) begin
                  $display ("at time %t ERROR: tRP violation during Activate bank 0", $time);
                end
            end else if (Ba == 2'b01 && Pc_b1 == 1'b1) begin
                {Act_b1, Pc_b1} = 2'b10;
                B1_row_addr = Addr ;
                RCD_chk1 = $time;
                RAS_chk1 = $time;
                if (Debug) $display ("at time %t ACT: Bank = 1 Row = %d", $time, Addr);
                // Precharge to Activate Bank 1
                if ($time - RP_chk1 < tRP) begin
                  $display ("at time %t ERROR: tRP violation during Activate bank 1", $time);
                end
            end else if (Ba == 2'b10 && Pc_b2 == 1'b1) begin
                {Act_b2, Pc_b2} = 2'b10;
                B2_row_addr = Addr ;
                RCD_chk2 = $time;
                RAS_chk2 = $time;
                if (Debug) $display ("at time %t ACT: Bank = 2 Row = %d", $time, Addr);
                // Precharge to Activate Bank 2
                if ($time - RP_chk2 < tRP) begin
                  $display ("at time %t ERROR: tRP violation during Activate bank 2", $time);
                end
            end else if (Ba == 2'b11 && Pc_b3 == 1'b1) begin
                {Act_b3, Pc_b3} = 2'b10;
                B3_row_addr = Addr ;
                RCD_chk3 = $time;
                RAS_chk3 = $time;
                if (Debug) $display ("at time %t ACT: Bank = 3 Row = %d", $time, Addr);
                // Precharge to Activate Bank 3
                if ($time - RP_chk3 < tRP) begin
                  $display ("at time %t ERROR: tRP violation during Activate bank 3", $time);
                end
            end else if (Ba == 2'b00 && Pc_b0 == 1'b0) begin
                $display ("at time %t ERROR: Bank 0 is not Precharged.", $time);
            end else if (Ba == 2'b01 && Pc_b1 == 1'b0) begin
                $display ("at time %t ERROR: Bank 1 is not Precharged.", $time);
            end else if (Ba == 2'b10 && Pc_b2 == 1'b0) begin
                $display ("at time %t ERROR: Bank 2 is not Precharged.", $time);
            end else if (Ba == 2'b11 && Pc_b3 == 1'b0) begin
                $display ("at time %t ERROR: Bank 3 is not Precharged.", $time);
            end
            // Active Bank A to Active Bank B
            if ((Previous_bank != Ba) && ($time - RRD_chk < tRRD)) begin
                $display ("at time %t ERROR: tRRD violation during Activate bank = %d", $time, Ba);
            end
            // Load Mode Register to Active
            if (MRD_chk < tMRD ) begin
                $display ("at time %t ERROR: tMRD violation during Activate bank = %d", $time, Ba);
            end
            // Auto Refresh to Activate
            if ($time - RC_chk < tRC) begin
                $display ("at time %t ERROR: tRC violation during Activate bank = %d", $time, Ba);
            end
            // Record variables for checking violation
            RRD_chk = $time;
            Previous_bank = Ba;
      end
      
      // Precharge Block
      if (Prech_enable == 1'b1) begin
            if (Addr == 1'b1) begin
                {Pc_b0, Pc_b1, Pc_b2, Pc_b3} = 4'b1111;
                {Act_b0, Act_b1, Act_b2, Act_b3} = 4'b0000;
                RP_chk0 = $time;
                RP_chk1 = $time;
                RP_chk2 = $time;
                RP_chk3 = $time;
                if (Debug) $display ("at time %t PRE: Bank = ALL",$time);
                // Activate to Precharge all banks
                if (($time - RAS_chk0 < tRAS) || ($time - RAS_chk1 < tRAS) ||
                  ($time - RAS_chk2 < tRAS) || ($time - RAS_chk3 < tRAS)) begin
                  $display ("at time %t ERROR: tRAS violation during Precharge all bank", $time);
                end
                // tWR violation check for write
                if (($time - WR_chk < tWRp) || ($time - WR_chk < tWRp) ||
                  ($time - WR_chk < tWRp) || ($time - WR_chk < tWRp)) begin
                  $display ("at time %t ERROR: tWR violation during Precharge all bank", $time);
                end
            end else if (Addr == 1'b0) begin
                if (Ba == 2'b00) begin
                  {Pc_b0, Act_b0} = 2'b10;
                  RP_chk0 = $time;
                  if (Debug) $display ("at time %t PRE: Bank = 0",$time);
                  // Activate to Precharge Bank 0
                  if ($time - RAS_chk0 < tRAS) begin
                        $display ("at time %t ERROR: tRAS violation during Precharge bank 0", $time);
                  end
                end else if (Ba == 2'b01) begin
                  {Pc_b1, Act_b1} = 2'b10;
                  RP_chk1 = $time;
                  if (Debug) $display ("at time %t PRE: Bank = 1",$time);
                  // Activate to Precharge Bank 1
                  if ($time - RAS_chk1 < tRAS) begin
                        $display ("at time %t ERROR: tRAS violation during Precharge bank 1", $time);
                  end
                end else if (Ba == 2'b10) begin
                  {Pc_b2, Act_b2} = 2'b10;
                  RP_chk2 = $time;
                  if (Debug) $display ("at time %t PRE: Bank = 2",$time);
                  // Activate to Precharge Bank 2
                  if ($time - RAS_chk2 < tRAS) begin
                        $display ("at time %t ERROR: tRAS violation during Precharge bank 2", $time);
                  end
                end else if (Ba == 2'b11) begin
                  {Pc_b3, Act_b3} = 2'b10;
                  RP_chk3 = $time;
                  if (Debug) $display ("at time %t PRE: Bank = 3",$time);
                  // Activate to Precharge Bank 3
                  if ($time - RAS_chk3 < tRAS) begin
                        $display ("at time %t ERROR: tRAS violation during Precharge bank 3", $time);
                  end
                end
                // tWR violation check for write
                if ($time - WR_chk < tWRp) begin
                  $display ("at time %t ERROR: tWR violation during Precharge bank %d", $time, Ba);
                end
            end
            // Terminate a Write Immediately (if same bank or all banks)
            if (Data_in_enable == 1'b1 && (Bank == Ba || Addr == 1'b1)) begin
                Data_in_enable = 1'b0;
            end
            // Precharge Command Pipeline for Read
            if (Cas_latency_3 == 1'b1) begin
                Command = `PRECH;
                Bank_precharge = Ba;
                A10_precharge = Addr;
            end else if (Cas_latency_2 == 1'b1) begin
                Command = `PRECH;
                Bank_precharge = Ba;
                A10_precharge = Addr;
            end
      end
      
      // Burst terminate
      if (Burst_term == 1'b1) begin
            // Terminate a Write Immediately
            if (Data_in_enable == 1'b1) begin
                Data_in_enable = 1'b0;
            end
            // Terminate a Read Depend on CAS Latency
            if (Cas_latency_3 == 1'b1) begin
                Command = `BST;
            end else if (Cas_latency_2 == 1'b1) begin
                Command = `BST;
            end
            if (Debug) $display ("at time %t BST: Burst Terminate",$time);
      end
      
      // Read, Write, Column Latch
      if (Read_enable == 1'b1 || Write_enable == 1'b1) begin
            // Check to see if bank is open (ACT)
            if ((Ba == 2'b00 && Pc_b0 == 1'b1) || (Ba == 2'b01 && Pc_b1 == 1'b1) ||
                (Ba == 2'b10 && Pc_b2 == 1'b1) || (Ba == 2'b11 && Pc_b3 == 1'b1)) begin
                $display("at time %t ERROR: Cannot Read or Write - Bank %d is not Activated", $time, Ba);
            end
            // Activate to Read or Write
            if ((Ba == 2'b00) && ($time - RCD_chk0 < tRCD))
                $display("at time %t ERROR: tRCD violation during Read or Write to Bank 0", $time);
            if ((Ba == 2'b01) && ($time - RCD_chk1 < tRCD))
                $display("at time %t ERROR: tRCD violation during Read or Write to Bank 1", $time);
            if ((Ba == 2'b10) && ($time - RCD_chk2 < tRCD))
                $display("at time %t ERROR: tRCD violation during Read or Write to Bank 2", $time);
            if ((Ba == 2'b11) && ($time - RCD_chk3 < tRCD))
                $display("at time %t ERROR: tRCD violation during Read or Write to Bank 3", $time);
            // Read Command
            if (Read_enable == 1'b1) begin
                // CAS Latency pipeline
                if (Cas_latency_3 == 1'b1) begin
                  if (Addr == 1'b1) begin
                        Command = `READ_A;
                  end else begin
                        Command = `READ;
                  end
                  Col_addr = Addr;
                  Bank_addr = Ba;
                end else if (Cas_latency_2 == 1'b1) begin
                  if (Addr == 1'b1) begin
                        Command = `READ_A;
                  end else begin
                        Command = `READ;
                  end
                  Col_addr = Addr;
                  Bank_addr = Ba;
                end

                // Read interrupt Write (terminate Write immediately)
                if (Data_in_enable == 1'b1) begin
                  Data_in_enable = 1'b0;
                end

            // Write Command
            end else if (Write_enable == 1'b1) begin
                if (Addr == 1'b1) begin
                  Command = `WRITE_A;
                end else begin
                  Command = `WRITE;
                end
                Col_addr = Addr;
                Bank_addr = Ba;

                // Write interrupt Write (terminate Write immediately)
                if (Data_in_enable == 1'b1) begin
                  Data_in_enable = 1'b0;
                end

                // Write interrupt Read (terminate Read immediately)
                if (Data_out_enable == 1'b1) begin
                  Data_out_enable = 1'b0;
                end
            end

            // Interrupting a Write with Autoprecharge
            if (Auto_precharge == 1'b1 && Write_precharge == 1'b1) begin
                RW_interrupt_write = 1'b1;
                if (Debug) $display ("at time %t NOTE : Read/Write Bank %d interrupt Write Bank %d with Autoprecharge", $time, Ba, Bank);
            end

            // Interrupting a Read with Autoprecharge
            if (Auto_precharge == 1'b1 && Read_precharge == 1'b1) begin
                RW_interrupt_read = 1'b1;
                if (Debug) $display ("at time %t NOTE : Read/Write Bank %d interrupt Read Bank %d with Autoprecharge", $time, Ba, Bank);
            end

            // Read or Write with Auto Precharge
            if (Addr == 1'b1) begin
                Auto_precharge = 1'b1;
                Count_precharge = 0;
                if (Read_enable == 1'b1) begin
                  Read_precharge = 1'b1;
                end else if (Write_enable == 1'b1) begin
                  Write_precharge = 1'b1;
                end
            end
      end

      //Read with Auto Precharge Calculation
      //      The device start internal precharge:
      //          1.CAS Latency - 1 cycles before last burst
      //      and 2.Meet minimum tRAS requirement
      //       or 3.Interrupt by a Read or Write (with or without AutoPrecharge)
      if ((Auto_precharge == 1'b1) && (Read_precharge == 1'b1)) begin
            if ((($time - RAS_chk0 >= tRAS) &&                                                      // Case 2
                ((Burst_length_1 == 1'b1 && Count_precharge >= 1) ||                           // Case 1
               (Burst_length_2 == 1'b1 && Count_precharge >= 2) ||
               (Burst_length_4 == 1'b1 && Count_precharge >= 4) ||
               (Burst_length_8 == 1'b1 && Count_precharge >= 8))) ||
               (RW_interrupt_read == 1'b1)) begin                                              // Case 3
                  Pc_b0 = 1'b1;
                  Act_b0 = 1'b0;
                  RP_chk0 = $time;
                  Auto_precharge = 1'b0;
                  Read_precharge = 1'b0;
                  RW_interrupt_read = 1'b0;
                  if (Debug) $display ("at time %t NOTE : Start Internal Auto Precharge for Bank 0", $time);
            end
      end
      if ((Auto_precharge == 1'b1) && (Read_precharge == 1'b1)) begin
            if ((($time - RAS_chk1 >= tRAS) &&
                ((Burst_length_1 == 1'b1 && Count_precharge >= 1) ||
               (Burst_length_2 == 1'b1 && Count_precharge >= 2) ||
               (Burst_length_4 == 1'b1 && Count_precharge >= 4) ||
               (Burst_length_8 == 1'b1 && Count_precharge >= 8))) ||
               (RW_interrupt_read == 1'b1)) begin
                  Pc_b1 = 1'b1;
                  Act_b1 = 1'b0;
                  RP_chk1 = $time;
                  Auto_precharge = 1'b0;
                  Read_precharge = 1'b0;
                  RW_interrupt_read = 1'b0;
                  if (Debug) $display ("at time %t NOTE : Start Internal Auto Precharge for Bank 1", $time);
            end
      end
      if ((Auto_precharge == 1'b1) && (Read_precharge == 1'b1)) begin
            if ((($time - RAS_chk2 >= tRAS) &&
                ((Burst_length_1 == 1'b1 && Count_precharge >= 1) ||
               (Burst_length_2 == 1'b1 && Count_precharge >= 2) ||
               (Burst_length_4 == 1'b1 && Count_precharge >= 4) ||
               (Burst_length_8 == 1'b1 && Count_precharge >= 8))) ||
               (RW_interrupt_read == 1'b1)) begin
                  Pc_b2 = 1'b1;
                  Act_b2 = 1'b0;
                  RP_chk2 = $time;
                  Auto_precharge = 1'b0;
                  Read_precharge = 1'b0;
                  RW_interrupt_read = 1'b0;
                  if (Debug) $display ("at time %t NOTE : Start Internal Auto Precharge for Bank 2", $time);
            end
      end
      if ((Auto_precharge == 1'b1) && (Read_precharge == 1'b1)) begin
            if ((($time - RAS_chk3 >= tRAS) &&
                ((Burst_length_1 == 1'b1 && Count_precharge >= 1) ||
               (Burst_length_2 == 1'b1 && Count_precharge >= 2) ||
               (Burst_length_4 == 1'b1 && Count_precharge >= 4) ||
               (Burst_length_8 == 1'b1 && Count_precharge >= 8))) ||
               (RW_interrupt_read == 1'b1)) begin
                  Pc_b3 = 1'b1;
                  Act_b3 = 1'b0;
                  RP_chk3 = $time;
                  Auto_precharge = 1'b0;
                  Read_precharge = 1'b0;
                  RW_interrupt_read = 1'b0;
                  if (Debug) $display ("at time %t NOTE : Start Internal Auto Precharge for Bank 3", $time);
            end
      end

      // Internal Precharge or Bst
      if (Command == `PRECH) begin                         // Precharge terminate a read with same bank or all banks
            if (Bank_precharge == Bank || A10_precharge == 1'b1) begin
                if (Data_out_enable == 1'b1) begin
                  Data_out_enable = 1'b0;
                end
            end
      end else if (Command == `BST) begin                  // BST terminate a read to current bank
            if (Data_out_enable == 1'b1) begin
                Data_out_enable = 1'b0;
            end
      end

      if (Data_out_enable == 1'b0) begin
            Dq_reg <= #tOH {data_bits{1'bz}};
      end

      // Detect Read or Write command
      if (Command == `READ || Command == `READ_A) begin
            Bank = Bank_addr;
            Col = Col_addr;
            Col_brst = Col_addr;
            if (Bank_addr == 2'b00) begin
                Row = B0_row_addr;
            end else if (Bank_addr == 2'b01) begin
                Row = B1_row_addr;
            end else if (Bank_addr == 2'b10) begin
                Row = B2_row_addr;
            end else if (Bank_addr == 2'b11) begin
                Row = B3_row_addr;
            end
            Burst_counter = 0;
            Data_in_enable = 1'b0;
            Data_out_enable = 1'b1;
      end else if (Command == `WRITE || Command == `WRITE_A) begin
            Bank = Bank_addr;
            Col = Col_addr;
            Col_brst = Col_addr;
            if (Bank_addr == 2'b00) begin
                Row = B0_row_addr;
            end else if (Bank_addr == 2'b01) begin
                Row = B1_row_addr;
            end else if (Bank_addr == 2'b10) begin
                Row = B2_row_addr;
            end else if (Bank_addr == 2'b11) begin
                Row = B3_row_addr;
            end
            Burst_counter = 0;
            Data_in_enable = 1'b1;
            Data_out_enable = 1'b0;
      end

      // DQ buffer (Driver/Receiver)
      if (Data_in_enable == 1'b1) begin                                 // Writing Data to Memory
            // Array buffer
            if (Bank == 2'b00) Dq_dqm = Bank0 [{Row, Col}];
            if (Bank == 2'b01) Dq_dqm = Bank1 [{Row, Col}];
            if (Bank == 2'b10) Dq_dqm = Bank2 [{Row, Col}];
            if (Bank == 2'b11) Dq_dqm = Bank3 [{Row, Col}];
            // Dqm operation
            if (Dqm == 1'b0) Dq_dqm [ 7 : 0] = Dq [ 7 : 0];
            if (Dqm == 1'b0) Dq_dqm = Dq ;
            // Write to memory
            if (Bank == 2'b00) Bank0 [{Row, Col}] = Dq_dqm ;
            if (Bank == 2'b01) Bank1 [{Row, Col}] = Dq_dqm ;
            if (Bank == 2'b10) Bank2 [{Row, Col}] = Dq_dqm ;
            if (Bank == 2'b11) Bank3 [{Row, Col}] = Dq_dqm ;
            // Output result
            if (Dqm == 2'b11) begin
                if (Debug) $display("at time %t WRITE: Bank = %d Row = %d, Col = %d, Data = Hi-Z due to DQM", $time, Bank, Row, Col);
            end else begin
                if (Debug) $display("at time %t WRITE: Bank = %d Row = %d, Col = %d, Data = %d, Dqm = %b", $time, Bank, Row, Col, Dq_dqm, Dqm);
                // Record tWR time and reset counter
                WR_chk = $time;
                WR_counter = 0;
            end
            // Advance burst counter subroutine
            #tHZ Burst;
      end else if (Data_out_enable == 1'b1) begin                         // Reading Data from Memory
            // Array buffer
            if (Bank == 2'b00) Dq_dqm = Bank0 [{Row, Col}];
            if (Bank == 2'b01) Dq_dqm = Bank1 [{Row, Col}];
            if (Bank == 2'b10) Dq_dqm = Bank2 [{Row, Col}];
            if (Bank == 2'b11) Dq_dqm = Bank3 [{Row, Col}];
            // Dqm operation
            if (Dqm_reg0 == 1'b1) Dq_dqm [ 7 : 0] = 8'bz;
            if (Dqm_reg0 == 1'b1) Dq_dqm = 8'bz;
            // Display result
            Dq_reg = #tAC Dq_dqm ;
            if (Dqm_reg0 == 2'b11) begin
                if (Debug) $display("at time %t READ : Bank = %d Row = %d, Col = %d, Data = Hi-Z due to DQM", $time, Bank, Row, Col);
            end else begin
                if (Debug) $display("at time %t READ : Bank = %d Row = %d, Col = %d, Data = %d, Dqm = %b", $time, Bank, Row, Col, Dq_reg, Dqm_reg0);
            end
            // Advance burst counter subroutine
            Burst;
      end
    end

    //Write with Auto Precharge Calculation
    //      The device start internal precharge:
    //          1.tWR Clock after last burst
    //      and 2.Meet minimum tRAS requirement
    //       or 3.Interrupt by a Read or Write (with or without AutoPrecharge)
    always @ (WR_counter) begin
      if ((Auto_precharge == 1'b1) && (Write_precharge == 1'b1)) begin
            if ((($time - RAS_chk0 >= tRAS) &&                                                          // Case 2
               (((Burst_length_1 == 1'b1 || Write_burst_mode == 1'b1) && Count_precharge >= 1) ||   // Case 1
               (Burst_length_2 == 1'b1 && Count_precharge >= 2) ||
               (Burst_length_4 == 1'b1 && Count_precharge >= 4) ||
               (Burst_length_8 == 1'b1 && Count_precharge >= 8))) ||
               (RW_interrupt_write == 1'b1 && WR_counter >= 2)) begin                           // Case 3 (stop count when interrupt)
                  Auto_precharge = 1'b0;
                  Write_precharge = 1'b0;
                  RW_interrupt_write = 1'b0;
                  #tWRa;                        // Wait for tWR
                  Pc_b0 = 1'b1;
                  Act_b0 = 1'b0;
                  RP_chk0 = $time;
                  if (Debug) $display ("at time %t NOTE : Start Internal Auto Precharge for Bank 0", $time);
            end
      end
    end
    always @ (WR_counter) begin
      if ((Auto_precharge == 1'b1) && (Write_precharge == 1'b1)) begin
            if ((($time - RAS_chk1 >= tRAS) &&
               (((Burst_length_1 == 1'b1 || Write_burst_mode == 1'b1) && Count_precharge >= 1) ||
               (Burst_length_2 == 1'b1 && Count_precharge >= 2) ||
               (Burst_length_4 == 1'b1 && Count_precharge >= 4) ||
               (Burst_length_8 == 1'b1 && Count_precharge >= 8))) ||
               (RW_interrupt_write == 1'b1 && WR_counter >= 2)) begin
                  Auto_precharge = 1'b0;
                  Write_precharge = 1'b0;
                  RW_interrupt_write = 1'b0;
                  #tWRa;                        // Wait for tWR
                  Pc_b1 = 1'b1;
                  Act_b1 = 1'b0;
                  RP_chk1 = $time;
                  if (Debug) $display ("at time %t NOTE : Start Internal Auto Precharge for Bank 1", $time);
            end
      end
    end
    always @ (WR_counter) begin
      if ((Auto_precharge == 1'b1) && (Write_precharge == 1'b1)) begin
            if ((($time - RAS_chk2 >= tRAS) &&
               (((Burst_length_1 == 1'b1 || Write_burst_mode == 1'b1) && Count_precharge >= 1) ||
               (Burst_length_2 == 1'b1 && Count_precharge >= 2) ||
               (Burst_length_4 == 1'b1 && Count_precharge >= 4) ||
               (Burst_length_8 == 1'b1 && Count_precharge >= 8))) ||
               (RW_interrupt_write == 1'b1 && WR_counter >= 2)) begin
                  Auto_precharge = 1'b0;
                  Write_precharge = 1'b0;
                  RW_interrupt_write = 1'b0;
                  #tWRa;                        // Wait for tWR
                  Pc_b2 = 1'b1;
                  Act_b2 = 1'b0;
                  RP_chk2 = $time;
                  if (Debug) $display ("at time %t NOTE : Start Internal Auto Precharge for Bank 2", $time);
            end
      end
    end
    always @ (WR_counter) begin
      if ((Auto_precharge == 1'b1) && (Write_precharge == 1'b1)) begin
            if ((($time - RAS_chk3 >= tRAS) &&
               (((Burst_length_1 == 1'b1 || Write_burst_mode == 1'b1) && Count_precharge >= 1) ||
               (Burst_length_2 == 1'b1 && Count_precharge >= 2) ||
               (Burst_length_4 == 1'b1 && Count_precharge >= 4) ||
               (Burst_length_8 == 1'b1 && Count_precharge >= 8))) ||
               (RW_interrupt_write == 1'b1 && WR_counter >= 2)) begin
                  Auto_precharge = 1'b0;
                  Write_precharge = 1'b0;
                  RW_interrupt_write = 1'b0;
                  #tWRa;                        // Wait for tWR
                  Pc_b3 = 1'b1;
                  Act_b3 = 1'b0;
                  RP_chk3 = $time;
                  if (Debug) $display ("at time %t NOTE : Start Internal Auto Precharge for Bank 3", $time);
            end
      end
    end

    task Burst;
      begin
            // Advance Burst Counter
            Burst_counter = Burst_counter + 1;

            // Burst Type
            if (Mode_reg == 1'b0) begin                                  // Sequential Burst
                Col_temp = Col + 1;
            end else if (Mode_reg == 1'b1) begin                         // Interleaved Burst
                Col_temp =Burst_counter ^Col_brst;
                Col_temp =Burst_counter ^Col_brst;
                Col_temp =Burst_counter ^Col_brst;
            end

            // Burst Length
            if (Burst_length_2) begin                                       // Burst Length = 2
                Col = Col_temp ;
            end else if (Burst_length_4) begin                              // Burst Length = 4
                Col = Col_temp ;
            end else if (Burst_length_8) begin                              // Burst Length = 8
                Col = Col_temp ;
            end else begin                                                // Burst Length = FULL
                Col = Col_temp;
            end

            // Burst Read Single Write            
            if (Write_burst_mode == 1'b1) begin
                Data_in_enable = 1'b0;
            end

            // Data Counter
            if (Burst_length_1 == 1'b1) begin
                if (Burst_counter >= 1) begin
                  Data_in_enable = 1'b0;
                  Data_out_enable = 1'b0;
                end
            end else if (Burst_length_2 == 1'b1) begin
                if (Burst_counter >= 2) begin
                  Data_in_enable = 1'b0;
                  Data_out_enable = 1'b0;
                end
            end else if (Burst_length_4 == 1'b1) begin
                if (Burst_counter >= 4) begin
                  Data_in_enable = 1'b0;
                  Data_out_enable = 1'b0;
                end
            end else if (Burst_length_8 == 1'b1) begin
                if (Burst_counter >= 8) begin
                  Data_in_enable = 1'b0;
                  Data_out_enable = 1'b0;
                end
            end
      end
    endtask

    // Timing Parameters for -75 (PC133) and CAS Latency = 2
    specify
      specparam
                  tAH=0.8,                                        // Addr, Ba Hold Time
                  tAS=1.5,                                        // Addr, Ba Setup Time
                  tCH=2.5,                                        // Clock High-Level Width
                  tCL=2.5,                                        // Clock Low-Level Width
//                  tCK= 10.0,                                        // Clock Cycle Time100mhz
                  tCK= 7.5,                                       // Clock Cycle Time133mhz
                  tDH=0.8,                                        // Data-in Hold Time
                  tDS=1.5,                                        // Data-in Setup Time
                  tCKH =0.8,                                        // CKE HoldTime
                  tCKS =1.5,                                        // CKE Setup Time
                  tCMH =0.8,                                        // CS#, RAS#, CAS#, WE#, DQM# HoldTime
                  tCMS =1.5;                                        // CS#, RAS#, CAS#, WE#, DQM# Setup Time
Ln#
888      $width    (posedge Clk,         tCH);
889      $width    (negedge Clk,         tCL);
890      $period   (negedge Clk,         tCK);
891      $period   (posedge Clk,         tCK);
892      $setuphold(posedge Clk,    Cke,   tCKS, tCKH);
893      $setuphold(posedge Clk,    Cs_n,tCMS, tCMH);
894      $setuphold(posedge Clk,    Cas_n, tCMS, tCMH);
895      $setuphold(posedge Clk,    Ras_n, tCMS, tCMH);
896      $setuphold(posedge Clk,    We_n,tCMS, tCMH);
897      $setuphold(posedge Clk,    Addr,tAS,tAH);
898      $setuphold(posedge Clk,    Ba,    tAS,tAH);
899      $setuphold(posedge Clk,    Dqm,   tCMS, tCMH);
900      $setuphold(posedge Dq_chk, Dq,    tDS,tDH);
    endspecify

endmodule


页: [1]
查看完整版本: modelsim仿真sdram,如何修改仿真模型参数?