📄 em_dma.pm
字号:
# # Outputs: # read_select # mem_read_n # inc_read # my $fsm_read = make_fsm( $top_module->name() . "_mem_read", "go", "p1_done_read", "read_waitrequest", "p1_fifo_full", "read_select", "mem_read_n", "inc_read" ); $top_module->add_contents( e_instance->new({ name => "the_" . $fsm_read->name(), module => $fsm_read, }) ); $top_module->add_contents( e_assign->new({ lhs => "fifo_write", rhs => "fifo_write_data_valid", }), ); $top_module->add_contents( e_assign->new({ lhs => "enabled_write_endofpacket", rhs => "write_endofpacket & ween", }), e_register->new({ out => 'd1_enabled_write_endofpacket', in => 'enabled_write_endofpacket', }) ); # WRITE FSM (read from FIFO, write to memory): my $fsm_write = make_write_machine($Options, $top_module->name() . "_mem_write"); $top_module->add_contents(e_instance->new({module => $fsm_write,}));}# Why do I care about the masters of my slave port?# 1) If I have 0 masters, then I might want to make a slave-port-free# module. Then a system with no Nios can be built. Currently, I don't# bother.# 2) My slave port's masters have a certain data width (I hope it's either# 16 or 32). Certain arcane details of the master's SDK (e.g. sizeof(int)) # depend on that data width. It's best if a given DMA peripheral advertises# the same data width as the master of its slave port, so that SDK pointer# values like &np_uart->np_uartrxdata can be written into DMA address # register without translation.# In this function I query all masters of my slave port, find their data# widths, and set the read and write masters' data widths to that same width.# If I have multiple masters whose data widths are different, print a warning# and use the max width.sub learn_about_the_masters_of_my_slave_port{ my ($module, $project, $Options) = @_; # How many masters do I have? Interesting answers are # "0" and "non-zero". my $slave_sbi = $project->SBI($control_port_name); $Options->{masters_of_my_slave_port} = [map {/MASTERED_BY/i ? keys %{$slave_sbi->{$_}} : ()} keys %$slave_sbi]; $module->comment($module->comment() . "Mastered by:\n"); for my $master_name (@{$Options->{masters_of_my_slave_port}}) { $module->comment(" " . $module->comment() . "$master_name; "); } $module->comment($module->comment() . "\n"); # Check the data widths of all masters. If we're lucky, they all have # the same data width. If not, print a warning and try to cope. my @master_data_widths; for my $master_name (@{$Options->{masters_of_my_slave_port}}) { my $master_sbi = $project->SBI($master_name, "MASTER"); push @master_data_widths, $master_sbi->{Data_Width}; }}{ # I think it might be useful as an optimization to disallow # certain transaction sizes. For example, if the read and # write masters connect to 32-bit slaves, read- and write-mux # logic is generated to enable byte and halfword transactions, # even if they will never occur. If byte and halfword transactions # are not explicitly allowed, those muxes need not be generated. my @allowed_transactions; my %transaction_size; sub transaction_size_in_bits { my $t = shift; return $transaction_size{$t} if exists($transaction_size{$t}); my @t = reverse @all_transactions; for (0 .. @t - 1) { my $width = 8 * (1 << $_); my $transaction = $t[$_]; $transaction_size{$transaction} = $width; } return $transaction_size{$t} if exists($transaction_size{$t}); ribbit("transaction_size(): I never heard of transaction '$t'\n"); } sub set_allowed_transactions { my ($lr) = @_; @allowed_transactions = @{$lr}; # Strip whitespace. map {s/^\s+//g; s/\s+$//} @allowed_transactions; # Check transaction names for legality. @allowed_transactions = grep { my $t = $_; if (not grep {$t eq $_} get_transaction_size_bit_names()) { print STDERR "Ignoring request to allow transaction '$t'\n"; 0; } else { 1; } } @allowed_transactions; } sub limit_max_allowed_transaction { my $max = shift; # Limit transactions to no wider than the widest data width supported. @allowed_transactions = grep { $max >= transaction_size_in_bits($_) } @allowed_transactions; } sub is_transaction_allowed { my $trans = shift; return 0 + grep {$trans eq $_} @allowed_transactions; } sub get_allowed_transactions { return @allowed_transactions; }}sub get_options{ my ($module, $project) = @_; my $wsa = $project->WSA(); my $Options = {}; my @copy_options = grep {/reset_value$/} keys %$wsa; # Copy the reset values over, converting to decimal if necessary. map {$Options->{$_} = eval($wsa->{$_})} @copy_options; # Copy the minimum lengthwidth spec $Options->{lengthwidth} = $wsa->{lengthwidth}; # copy the burst attributes as well $Options->{burst_enable} = $wsa->{burst_enable}; $Options->{max_burst_size} = $wsa->{max_burst_size}; learn_about_the_masters_of_my_slave_port($module, $project, $Options); # Go out and get info from the slaves. We'll use this info to # decide: # Fifo depth: # depends on maximum read latency of all slaves of the read master. # Fifo width: # depends on the data width of all read and write slaves. # Read port address bits: # maximum address bits of all read slaves # Write port address bits: # maximum address bits of all write slaves. my $read_master_address; my $write_master_address; my @read_byteaddr_widths; my @write_byteaddr_widths; my @read_data_widths; my @write_data_widths; my @read_slave_names = $project->get_slaves_by_master_name($module->name(), $read_master_name); my @write_slave_names = $project->get_slaves_by_master_name($module->name(), $write_master_name); # Report info about the slaves. $module->comment($module->comment() . "Read slaves:\n"); for (@read_slave_names) { $module->comment($module->comment() . "$_; "); } $module->comment($module->comment() . "\n\n"); $module->comment($module->comment() . "Write slaves:\n"); for (@write_slave_names) { $module->comment($module->comment() . "$_; "); } $module->comment($module->comment() . "\n\n"); my $read_master_desc = $module->name() . "/" . $read_master_name; # Accumulate the maximum address span over all read and write slaves, # to determine the necessary number of bits for the length and # writelength registers. $Options->{max_slave_address_span} = 0; for my $slave_desc (@read_slave_names) { my ($address_width, $base_addr, $last_addr) = master_address_width_from_slave_parameters( $project, $read_master_desc, $slave_desc); $Options->{max_slave_address_span} = max($Options->{max_slave_address_span}, $last_addr - $base_addr + 1); push @read_byteaddr_widths, $address_width; push @read_data_widths, 0 + $project->SBI($slave_desc)->{Data_Width}; } my $write_master_desc = $module->name() . "/" . $write_master_name; for my $slave_desc (@write_slave_names) { my ($address_width, $base_addr, $last_addr) = master_address_width_from_slave_parameters( $project, $write_master_desc, $slave_desc); $Options->{max_slave_address_span} = max($Options->{max_slave_address_span}, $last_addr - $base_addr + 1); push @write_byteaddr_widths, $address_width; push @write_data_widths, 0 + $project->SBI($slave_desc)->{Data_Width}; } $Options->{fifo_in_logic_elements} = $wsa->{fifo_in_logic_elements}; # Rule of thumb: set the fifo depth to the max over all read slave # read latencies. $Options->{max_read_latency} = $project->get_max_slave_read_latency( $project->_target_module_name(), $read_master_name, ); # My experiments indicate that a FIFO depth of 4 makes for # efficient data transfers, while lower depths cause inefficient # use of bandwidth (frequent stalls as the fifo fills or empties. # But, the ptf file can override the fifo_depth with a larger value. my $wsa_fifo_depth = $project->WSA()->{fifo_depth}; $Options->{fifo_depth} = max(4, $wsa_fifo_depth, $Options->{burst_enable} ? $Options->{max_burst_size} : 0 , $Options->{max_read_latency}); # Fifo depth must be an integer power of 2. # Note that 1 is an interesting special case: fifo address width is 0! #FIXIT - don't need this we think... if ($Options->{fifo_depth} < 1) { $Options->{fifo_depth} = 1; } if (not is_power_of_two($Options->{fifo_depth})) { $Options->{fifo_depth} = next_higher_power_of_two($Options->{fifo_depth}); } # Warning! I decree that all y'all have a fifo_read_latency of 1. $Options->{fifo_read_latency} = 1; # "allowed_transactions": let the user promise not to make # some transactions, which lets the DMA logic (byte enable, # read data mux) be simpler. # # Backwards compatibility: if the "allowed_transactions" wsa value is # not present, provide the default (all transactions), limited of # course by the maximum possible, aka fifodatawidth. delete $wsa->{allowed_transactions}; # Any not-present transaction size is set to 1. map { my $key = "allow_$_\_transactions"; $wsa->{$key} = 1 if not exists($wsa->{$key}) } @all_transactions; my @allowed_transactions = grep { my $key = "allow_$_\_transactions"; $wsa->{$key} } @all_transactions; set_allowed_transactions(\@allowed_transactions); # These are the widths of the read and write master data ports. # Note that masters are restricted in their data widths: only # 8, 16, 32, ... are allowed. $Options->{writedatawidth} = round_up_to_next_computer_acceptable_bit_width(max(@write_data_widths)); $Options->{readdatawidth} = round_up_to_next_computer_acceptable_bit_width(max(@read_data_widths)); # Limit the read- and write-data buses to no greater than the largest # allowed transaction sizes. There's no need to sprout port pins that # will never be used (the synthesizer may not be able to determine they'll # never be used, so logic could be wasted) and as a side benefit, the # fifo data memory will be no larger than necessary. map {$_ = min($_, get_max_transaction_size_in_bits())} ($Options->{writedatawidth}, $Options->{readdatawidth}); # The FIFO will contain data only as wide as the narrowest # master. This is not as good as it could be, because we # might be mastering some peripheral which advertises a 16-bit # data path, of which only 8 bits are active (e.g. UART). # This sub-optimality can only be resolved with user input, # via "allowed_transactions". # Consider a system where one of the master's max data width slave # is a native peripheral with data width 24 bits. The actual fifo # that's built need only be 24 bits, but we need to treat it as though # it's 32 bits, as far as transaction sizes go. Should investigate # whether or not the fifo ends up larger than it needs to be, after # synthesis. $Options->{fifodatawidth} = max( $Options->{writedatawidth}, $Options->{readdatawidth} ); # Finally, since we're restricted to transactions no greater than # the fifo data width, set the read and write masters to be no # wider than fifo data width. $Options->{writedatawidth} = $Options->{fifodatawidth}; $Options->{readdatawidth} = $Options->{fifodatawidth}; # Now that we know how wide the read- and write-master data is, # go back and limit the max transaction to no larger than that. limit_max_allowed_transaction($Options->{fifodatawidth}); Progress(" @{[$module->name()]}: allowing these transactions: " . "@{[join(', ', get_allowed_transactions())]}"); Progress("P4 $p4_revision $p4_datetime") if $Options->{europa_debug}; # SPR 178278: provide a minimum address width of 5 bits (sufficient to # span a single doubleword of address space). $Options->{readaddresswidth} = max(@read_byteaddr_widths, 5); $Options->{writeaddresswidth} = max(@write_byteaddr_widths, 5); return $Options;}sub set_SBI_values{ my ($Options, $module, $project) = @_; my $module_name = $module->name(); # Go modify my SBI, so that when the system is generated I'll get my # wires. my $sys_ptf = $project->system_ptf(); my $write_master_sbi = $sys_ptf-> {"MODULE $module_name"}-> {"MASTER $write_master_name"}-> {"SYSTEM_BUILDER_INFO"}; ribbit("what th'?") if (!$write_master_sbi); $write_master_sbi->{Data_Width} = $Options->{writedatawidth}; $write_master_sbi->{Address_Width} = $Options->{writeaddresswidth}; my $read_master_sbi = $sys_ptf-> {"MODULE $module_name"}-> {"MASTER $read_master_name"}-> {"SYSTEM_BUILDER_INFO"}; ribbit("what th'?") if (!$read_master_sbi); $read_master_sbi->{Data_Width} = $Options->{readdatawidth}; $read_master_sbi->{Address_Width} = $Options->{readaddresswidth};}sub set_sim_ptf{ my ($Options, $module, $project) = @_; # Signals which match any of the following regexps should be # radix hex. my @bus_signals = qw( length address data$ byteenable ); my $module_name = $module->name(); my $sys_ptf = $project->system_ptf(); my $mod_ptf = $sys_ptf->{"MODULE $module_name"}; $mod_ptf->{SIMULATION} = {} if (!defined($mod_ptf->{SIMULATION})); $mod_ptf->{SIMULATION}->{DISPLAY} = {} if (!defined($mod_ptf->{SIMULATION}->{DISPLAY})); my $sig_ptf = $mod_ptf->{SIMULATION}->{DISPLAY}; # Make a list of interesting signals, in order, with out-of-band 'divider' # names. my @signals; push @signals, qw( busy done length fifo_empty p1_fifo_full ); push @signals, "Divider $module_name $read_master_name"; my %read_signals = get_read_master_type_map($Options); push @signals, sort keys %read_signals; push @signals, "Divider $module_name $write_master_name"; my %write_signals = get_write_master_type_map($Options); push @signals, sort keys %write_signals; $project->set_sim_wave_signals(\@signals);}sub make_write_master_data_mux{ my ($Options, $input, $output) = @_; my @things; # How sad. I need a write-data mux for narrow writes. # For each possible transaction size, make a "fifo_read_as_transaction_size" # signal, by replicating the fifo read data up to the write data bus size. my @trans_names = reverse get_transaction_size_bit_names(); # Make a
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -