⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 generate_ddr_sim_model.pl

📁 基于NIOS II的ddr2控制器,配有详细的文档,经验证后可使用.
💻 PL
📖 第 1 页 / 共 5 页
字号:
        #print "Avalon burst length is $local_burst_length \n";
        
        
        # Start building up a simulation-only display string.
        @write_lines = 
            (
             "",
             "**********************************************************************",
             "This testbench includes an SOPC Builder generated Altera memory model:",
             "'$sim_file', to simulate accesses to the $mem_pretty_name memory.",
             " ",
             );
              
       # if ($local_burst_length > 1) 
       # {
         # push @write_lines,(
             # "WARNING: The Altera $mem_pretty_name Controller supports Avalon bursts,", 
             # "but this simulation model does not. If any of the masters in your",
             # "SOPC Builder system will issue Avalon bursts, then you ",
             # "should use a memory model supplied by your memory vendor.   ",
             # " ",
             # );
       # }
             
            push @write_lines,
            (
             "Initial contents are loaded from the file: ".
             "'$sim_dat'."
             );
        push @write_lines,
        ("**********************************************************************");
    
    
        # Convert all lines to e_sim_write objects.
        map {$_ = e_sim_write->new({spec_string => $_ . '\\n'})} @write_lines;
        
        # Wrap the simulation-only display string in an e_initial_block, so we
        # only see the message once!
        if (@write_lines)
        {
            my $init = e_initial_block->new({
                contents => [ @write_lines ],
            });
            $module->add_contents($init);
        } # if (@write_lines)
      
        # sjh WRONG - should get the clock properly!
        $WSA->{system_clock_rate} = $project->system_ptf()->{WIZARD_SCRIPT_ARGUMENTS}{clock_freq};
            
        # New style contents generation (a'la OnchipMemoryII -- thanks AaronF)
        my $Opt = {name => $project->_target_module_name()};
        $project->do_makefile_target_ptf_assignments
            (
             's1',
             ['dat', 'sym', ],
             $Opt,
             );
        
        # Reality checks:
        
        
        #my $tempclockrate = $project->system_ptf()->{WIZARD_SCRIPT_ARGUMENTS}{clock_freq};
        my $clockrate = $wizard_shortcut->{PRIVATE}{clock_speed}{value};
        #print "clockrate = $clockrate\n";
        
        my $clockperiod = 1/$clockrate*1000;
        #print "clockperiod = $clockperiod\n";
    
    
        #print "Data width = ".$wizard_shortcut->{PRIVATE}{width}{value}."\n";
        #print "Data width2 = ".$WSA->{MEGACORE}{NETLIST_SECTION}{STATIC_SECTION}{PRIVATES}{NAMESPACE}{parameterization}{PRIVATE}{width}{value}."\n";
    
        # SODIMM allows all the same data path widths as the sdram controller
        &validate_parameter({
            hash => $wizard_shortcut->{PRIVATE}{width},
            name => "value",
            type => "integer",
            allowed => [8, 16, 32, 64],
        });
        
        
        #sjh Don't check these for now
        # &validate_parameter({
            # hash => $WSA,
            # name => "sdram_bank_width",
            # type => "integer",
            # default => "2", 
            # allowed => [1, 2],
        # });
        
        #sjh Don't check these for now
        # # Having a non-integer power of 2 for number of chip selects seems wrong.
        # my $num_chipselects = $WSA->{sdram_num_chipselects};
        my $num_chipselects = $wizard_shortcut->{PRIVATE}{chipselects}{value};
        my $num_chipselect_address_bits = log2($num_chipselects);
        # &validate_parameter({
            # hash => $WSA,
            # name => "sdram_num_chipselects",
            # type => "integer",
            # allowed => [1, 2, 4, 8],
        # });
        
        my $cas_latency = $wizard_shortcut->{PRIVATE}{cas_latency}{value};
        #print "CAS latency = $cas_latency\n";
    
        # In the real world, 3 bits of the mode register are used to encode
        # cas latency, with code "3'b000" reserved.
        &validate_parameter({
            hash => $wizard_shortcut->{PRIVATE}{cas_latency},
            name => "value",
            type => "string",
            allowed => ["2.0", "2.5", "3.0", "4.0", "5.0"],
        });
    
        my $resynch_phase = $wizard_shortcut->{PRIVATE}{resync_phase}{value};
        my $resynch_cycle = $wizard_shortcut->{PRIVATE}{resynch_cycle}{value};
        #print "resynch cycle = $resynch_cycle\n";
        #print "resynch phase = $resynch_phase\n";
    
        # approximate the roundtrip delay based on resynch cycle (taking CL into account) - 1/4 cycle + whatever the resynch phase is,.
        # my $rtl_sim_delay = (($resynch_cycle + 2 - $cas_latency)*$clockperiod) + ($clockperiod * ($resynch_phase/360));
        my $clock_board_delay = $wizard_shortcut->{PRIVATE}{board_tpd_clock_trace_nom}{value};
        my $dqs_board_delay = $wizard_shortcut->{PRIVATE}{board_tpd_dqs_trace_total_nom}{value};
        my $rtl_board_delay = ($clock_board_delay + $dqs_board_delay) / 1000;

        # split total delay in 90 deg segements because we can't set modelsim to use transport delays instead of inertial!
        # my $number_of_lump_delays = floor($rtl_sim_delay / ($clockperiod / 4) + 1);
        #print "sim delay  = $rtl_sim_delay spread over $number_of_lump_delays delays.\n";
        
        
    
    
        #sjh Not needed for DDR
        # This setting is hidden from the GUI, but takes affect as a result
        # of using the 'preset's...
        # FIXME: Our model doesn't care about refresh commands, but we might want
        # to indicate via printf/write/$display that they are occuring...
        # &validate_parameter({
            # hash => $WSA,
            # name => "init_refresh_commands",
            # type => "integer",
            # allowed => [1 .. 8],
        # });
        
    
        # Compute the width of the controller's address (as seen by the Avalon
        # bus) from input parameters.  SODIMM will address a raw memory array in
        # the same way that Avalon accesses the Controller.
        # my $addr_width =
            # $num_chipselect_address_bits +
            # $WSA->{sdram_bank_width} +
            # $WSA->{sdram_col_width} +
            # $WSA->{sdram_row_width};
        my $addr_width = $wizard_shortcut->{PRIVATE}{local_address_width}{value};
        my $ba_width = $wizard_shortcut->{PRIVATE}{bankbits}{value};
        my $row_width = $wizard_shortcut->{PRIVATE}{rowbits}{value};
        my $col_width = $wizard_shortcut->{PRIVATE}{colbits}{value};
        #print "Controller has address widths, a = $addr_width, ba = $ba_width, row = $row_width, col = $col_width\n"; 
        
        # print "ctrler width = $addr_width\t ".
        # "Num CSBits = $num_chipselect_address_bits\n";
        # print "Num Banks = ".$WSA->{sdram_num_banks}.
        # " \tNum BankBits = ".$WSA->{sdram_bank_width}."\n";
        # print "Rows = ".$WSA->{sdram_row_width}.
        # " \tCols = ".$WSA->{sdram_col_width}."\n";
    
        # FIXME:?  We check NOTHING about validity of SDRAM Controller Timing or
        # Protocol -- we trust the user to set the parameters as if for a real
        # SODIMM!
        
        
        my $dq_width  = $wizard_shortcut->{PRIVATE}{width}{value};
        my $dqs_width = $wizard_shortcut->{PRIVATE}{width}{value} / 8;
        my $dm_width  = $wizard_shortcut->{PRIVATE}{width}{value} / 8;
        
        my $mem_width = $dq_width * 2;
        my $mem_mask_width = $dm_width * 2;
        
        
        #my $dm_width = $WSA->{sdram_data_width} / 8;
        # if (int($dm_width) != $dm_width)
        # {
            # ribbit
                # (
                 # "Unexpected: SDRAM data width '", $dq_width}, "', ".
                 # "leads to non-integer DQM width ($dm_width)"
                 # );
        # }
        # else
        # {
        # printf ("make_sodimm: data_width = %d\tdqm_width = %d\n",
        # $WSA->{sdram_data_width},$dm_width);
        # }
        
        # Let's set up the str2hex CODE variable to be "INH" or 'some active
        # code', depening upon {cs_n[x], ras_n, cas_n, we_n}
    
        # set up some precoded 3 character wide strings for wave display below:
        my $STR_INH = &str2hex ("INH"); # Inhibit
        my $STR_LMR = &str2hex ("LMR"); # To grab cas_latency during LoadMoadReg
        my $STR_ACT = &str2hex ("ACT"); # To grab cs/row/bank addr during Activate
        my $STR__RD = &str2hex (" RD"); # To grab col addr during Read
        my $STR__WR = &str2hex (" WR"); # To grab col addr during Write
        # Precharge, AutoRefresh and Burst are ignored by this model!
        # NB: we may choose to later add a AutoRefresh timing check...
    
        # SRA modified so always read in file
        #my $ram_file = "";
        #if ($WSA->{is_initialized}) {
        my  $ram_file = $sim_dat;
        #}
    
        $module->add_contents
            (
             e_ram->new
             ({
                 comment => "Synchronous write when (CODE == $STR__WR (write))",
                 name => $project->get_top_module_name() . "_ram",
                 Read_Latency => "0",
                 dat_file => $ram_file,
                 port_map =>
                 {
                     #wren => "write_valid_r2",
                     wren => "write_to_ram_r",
                     data => "rmw_temp",
                     q    => "read_data",
                     wrclock => "clk",
                     #wraddress=>"wr_addr_delayed",
                     wraddress=>"wr_addr_delayed_r",
                     #rdaddress=>"(write_valid) ? wr_addr_pipe_1 : read_addr_delayed",
                     rdaddress=>"rmw_address",
                 }
             }),
             );
    
        # Tho the Altera SDR SDRAM Controller's always wire their clk_en 'ON',
        # some users may wire their testbench to flick the bit...
        
        # Port Naming matches common SODIMM conventions, with some exceptions:
        # Since the controller only drives one clock, and one clock_enable, we
        # never create a bus of inputs for those signals (many sodimms have 2 or
        # more ck and cke's); we do not support any sort of Serial Presence
        # Detect, nor the associated SCL (serial-clock) and SDA (serial-data)
        # signals.
        
        # NOTE: WSA->{sdram_addr_width} is not necessarily WSA->{sdram_row_width}!
        my $dq;                     # variable for dq signal name, for 3-state mode
        my $dqs;                     # variable for dq signal name, for 3-state mode
        $dq = $default_pin_prefix."dq";             # Dedicated pin-mode dq name
        $dqs = $default_pin_prefix."dqs";             # Dedicated pin-mode dq name
        
        # Dedicated pin-mode sodimm port names and assignments
        $module->add_contents
            (
             e_port->news
             (
              {name => "clk"},
              {name => $default_pin_prefix."cke",   width => $num_chipselects},
              {name => $default_pin_prefix."cs_n",  width => $num_chipselects},
              {name => $default_pin_prefix."ras_n"},
              {name => $default_pin_prefix."cas_n"},
              {name => $default_pin_prefix."we_n"},
              {name => $default_pin_prefix."dm",    width => $dm_width },
              {name => $default_pin_prefix."ba",    width => $ba_width },
              {name => $default_pin_prefix."a",     width => $row_width },
              {name => $default_pin_prefix."dq",    width => $dq_width, direction => "inout"},
              {name => $default_pin_prefix."dqs",   width => $dqs_width, direction => "inout"},
              ),
             e_signal->news
             (
              {name => "cke",  width => $num_chipselects},
              {name => "cs_n",  width => $num_chipselects},
              {name => "ras_n"},
              {name => "cas_n"},
              {name => "we_n"},
              {name => "dm",   width => $dm_width,export => 0, never_export => 1},
              {name => "ba",    width => $ba_width},
              {name => "a",     width => $row_width},
              {name => "read_dq",      width => $dq_width},
              {name => "dqs",           width => $dqs_width},
              {name => "first_half_dq", width => $dq_width,export => 0, never_export => 1},
              {name => "second_half_dq",width => $dq_width,export => 0, never_export => 1},
              {name => "dq_captured",   width=> $dq_width*2,export => 0, never_export => 1},
              {name => "dq_valid",     width=> 1,export => 0, never_export => 1},
              {name => "dqs_valid",     width=> 1,export => 0, never_export => 1},
              {name => "dqs_valid_temp",  width=> 1,export => 0, never_export => 1},
              {name => "dm_captured",   width=> $dqs_width*2,export => 0, never_export => 1},
              {name => "open_rows",     width => $row_width, depth => (2 ** ($ba_width + $num_chipselects))},
              {name => "current_row",   width => ($ba_width + $num_chipselects),export => 0, never_export => 1},
              
              {name => "dqs_temp",     width => $dqs_width},

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -