📄 generate_ddr_sim_model.pl
字号:
#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 + -