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

📄 generate_ddr_sim_model.pl

📁 基于NIOS II的ddr2控制器,配有详细的文档,经验证后可使用.
💻 PL
📖 第 1 页 / 共 4 页
字号:
        #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_r",
                     wren => "write_to_ram_r",
                     data => "rmw_temp",
                     q    => "read_data",
                     wrclock => "clk",
                     wraddress=>"wr_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 = "ddr_dq";             # Dedicated pin-mode dq name
        $dqs = "ddr_dqs";             # Dedicated pin-mode dq name
        
        # Dedicated pin-mode sodimm port names and assignments
        $module->add_contents
            (
             e_port->news
             (
              {name => "clk"},
              {name => "ddr_cke",   width => $num_chipselects},
              {name => "ddr_cs_n",  width => $num_chipselects},
              {name => "ddr_ras_n"},
              {name => "ddr_cas_n"},
              {name => "ddr_we_n"},
              {name => "ddr_dm",    width => $dm_width },
              {name => "ddr_ba",    width => $ba_width },
              {name => "ddr_a",     width => $row_width },
              {name => "ddr_dq",    width => $dq_width, direction => "inout"},
              {name => "ddr_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},
              {name => "dq_temp",      width => $dq_width},
              {name => "dqs_out_0",     width => $dqs_width},
              {name => "dq_out_0",      width => $dq_width},
              
              ),
             e_assign->news
             (
              ["cke"   => "ddr_cke"],
              ["cs_n"  => "ddr_cs_n"],
              ["ras_n" => "ddr_ras_n"],
              ["cas_n" => "ddr_cas_n"],
              ["we_n"  => "ddr_we_n"],
              ["dm"    => "ddr_dm"],
              ["ba"    => "ddr_ba"],
              ["a"     => "ddr_a"],
              ),
             );
        
        
        # Now the fun begins ;-)
    
        $module->add_contents
            (
             # Define txt_code based on ras/cas/we
             e_assign->new
             ({
                 lhs => e_signal->new({name => "cmd_code", width => 3}),
                 rhs => "{ras_n, cas_n, we_n}",
             }),
             e_sim_wave_text->new
             ({
                 out     => "txt_code",
                 selecto => "cmd_code",
                 table   =>
                     [
                      "3'h0" => "LMR",
                      "3'h1" => "ARF",
                      "3'h2" => "PRE",
                      "3'h3" => "ACT",
                      "3'h4" => " WR",
                      "3'h5" => " RD",
                      "3'h6" => "BST",
                      "3'h7" => "NOP",
                      ],
                     default => "BAD",
                 }),
             # "Inhibit" if no chip_selects,
             e_signal->new({name => "CODE", width=> 8*3, never_export => 1}),
             e_assign->new(["CODE" => "(\&cs_n) ? $STR_INH : txt_code"]),
             );
    
        ## Row/Col Address Construction:
        # We're constructing a monolithic address into a single large array.
        # If there are multiple chip-selects, we assume they are one-hot
        # encoded (that's what our controller drives).
    
       
        # First, we'll build up row/bank. (arb == address_row_bank)
        my $arb_rhs;
        #my $arb_width = $WSA->{sdram_bank_width} + $WSA->{sdram_row_width};
        my $arb_width = $ba_width + $row_width;
    
        $arb_rhs = "{ba, a}";
        # if ($ba_width == 1)
        # {
            # # We only have 2 banks, row/addr build as {row,bank}
            # $arb_rhs = "{a, ba}";
        # }
        # elsif ($ba_width == 2)
        # {
            # # 4 banks construct address as {bank[1],row,bank[0]}
            # $arb_rhs = "{ba[1], a, ba[0]}"
        # }
    
        # then we'll tack cs_encoded bits as the top bits, if applicable
        # (acrb == addr_chip-select_row_bank)
        my $acrb_rhs;
        my $acrb_width = $arb_width;
        if ($num_chipselects < 2)
        {
            # Single chipselect does not affect address:
            $acrb_rhs  = $arb_rhs;
        }
        else
        {
            # Multiple chipselects are encoded to create high order addr bits.
            # Note that &one_hot_encoding outputs a properly ordered @list!
            my %cs_encode_hash = 
                ( default => ["cs_encode" => $num_chipselect_address_bits."'h0"] );
            my @raw_cs = &one_hot_encoding($num_chipselects);
            # print "\&make_sodimm: num_cs = $num_chipselects \t \@raw_cs = @raw_cs\n";
            my $cs_count = 0;
            foreach my $chip_select (@raw_cs) {
                $cs_encode_hash{$chip_select} =
                    [
                     e_assign->new
                     (
                      ["cs_encode" => $num_chipselect_address_bits."'h".$cs_count],
                      )
                     ];
                $cs_count++;
            } # foreach (@raw_cs)
    
            # Create the cs_encode signal, and use a case statement to define it.
            $module->add_contents
                (
                 e_signal->news
                 (
                  {name => "cs",        width=> $num_chipselects},
                  {name => "cs_encode", width=> $num_chipselect_address_bits},
                  ),
                 e_assign->new(["cs" => "~cs_n"]), # invert cs_n for encoding
                 e_process->new({
                     clock   => "",
                     comment =>
                         "Encode 1-hot ChipSelects into high order address bit(s)",
                     contents=>
                         [
                          e_case->new({
                              switch => "cs",
                              parallel => 1,
                              contents => {%cs_encode_hash},
                          }),
                          ],
                 }),
                 );
            # prepend the encoded bits as upper order addr bits, and remember width
            $acrb_rhs    = "{cs_encode, $arb_rhs}";
            $acrb_width += $num_chipselect_address_bits;
        }
        # define/assign final construction signals
        # (ac_rhs == addr_col), constructed to avoid A[10] for large col_width
        my $ac_rhs = "a[".($col_width-1).":1]";
        # if ($col_width < 11) {
            # $ac_rhs = "a[".($col_width-1).":0]";
        # } elsif ($col_width == 11) {
            # $ac_rhs = "{a[11],a[9:0]}";
        # } else {
            # $ac_rhs = "{a[".$col_width.":11],a[9:0]}";
        # }
        my $read_addr_width = $acrb_width + $col_width;
        $module->add_contents
            (
             e_signal->news
             (
              #{name => "addr_crb", width=> $acrb_width},
              {name => "addr_col", width=> $col_width - 1},
              {name => "test_addr",width=> $read_addr_width},
              # {name => "temp_addr",width=> $read_addr_width},
              ),
             e_signal->news
             (
              {name => "rd_addr_pipe_0", width=> $read_addr_width, default_value => "0",export => 0, never_export => 1},
              {name => "rd_addr_pipe_1", width=> $read_addr_width, default_value => "0",export => 0, never_export => 1},
              {name => "rd_addr_pipe_2", width=> $read_addr_width, default_value => "0",export => 0, never_export => 1},
              {name => "rd_addr_pipe_3", width=> $read_addr_width, default_value => "0",export => 0, never_export => 1},
              {name => "rd_addr_pipe_4", width=> $read_addr_width, default_value => "0",export => 0, never_export => 1},
              {name => "rd_addr_pipe_5", width=> $read_addr_width, default_value => "0",export => 0, never_export => 1},
              {name => "read_addr_delayed", width=> $read_addr_width, default_value => "0",export => 0, never_export => 1},
              {name => "rmw_address", width=> $read_addr_width, default_value => "0",export => 0, never_export => 1},
              {name => "rd_burst_counter", width=> $read_addr_width, default_value => "0",export => 0, never_export => 1},
          
              {name => "wr_addr_pipe_0", width=> $read_addr_width, default_value => "0",export => 0, never_export => 1},
              {name => "wr_addr_pipe_1", width=> $read_addr_width, default_value => "0",export => 0, never_export => 1},
              {name => "wr_addr_pipe_2", width=> $read_addr_width, default_value => "0",export => 0, never_export => 1},
              {name => "wr_addr_pipe_3", width=> $read_addr_width, default_value => "0",export => 0, never_export => 1},
              {name => "wr_addr_pipe_4", width=> $read_addr_width, default_value => "0",export => 0, never_export => 1},
              {name => "wr_addr_pipe_5", width=> $read_addr_width, default_value => "0",export => 0, never_export => 1},
              {name => "wr_addr_delayed", width=> $read_addr_width, default_value => "0",export => 0, never_export => 1},
              {name => "wr_burst_counter", width=> $read_addr_width, default_value => "0",export => 0, never_export => 1},

              ),
             e_assign->news
             (
              ["addr_col" => $ac_rhs],
              # ["test_addr"=> "{addr_crb, addr_col}"],
              ),
             );
    
        ## Define some random necessary variables:
        # we only support up to a max cas_latency of 3, and just soak up that many
        #resources, and pluck off an earlier version if the cas_latency is set
        #lower during LMR...
        $module->add_contents
            (

⌨️ 快捷键说明

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