📄 em_dma.pm
字号:
e_assign->new({ lhs => ["p1_writeincov_eq_0", 1, 0, 1], rhs => $is0_p1_rhs, }), e_register->new({ out => ["writeincov_eq_0", 1, 0, 1], in => "p1_writeincov_eq_0", enable => $incov_clken, async_value => $async_val, }), ); } my $transaction_size = get_transaction_size_expression(); my @top_priority = $Options->{writeincovwidth} ? ("~writeincov_eq_0", "writeincov") : (); $module->add_contents( e_mux->new({ lhs => e_signal->new({ name => "writeaddress_inc", # The increment width is at least the number of transaction-size bits # in the control register, but can be as large as the override. width => max( scalar(get_transaction_size_bit_indices()), $Options->{writeincovwidth} ), }), type => "priority", table => [ @top_priority, "wcon", "0", "$burst_enable", "0", ], default => "$transaction_size", }), ); @top_priority = $Options->{readincovwidth} ? ("~readincov_eq_0", "readincov") : (); $module->add_contents( e_mux->new({ lhs => e_signal->new({ name => "readaddress_inc", # The increment width is at least the number of transaction-size bits # in the control register, but can be as large as the override. width => max( scalar(get_transaction_size_bit_indices()), $Options->{readincovwidth} ), }), type => "priority", table => [ @top_priority, "rcon", "0", "$burst_enable", "0", ], default => "$transaction_size", }), ); # How about a nice read-data mux? my @muxtable = (); for (my $i = 0; $i < @reg_info; ++$i) { # Skip "reserved" registers. next if $reg_info[$i]->[1] =~ /reserved/; # Skip any register with width 0. next if $reg_info[$i]->[2] == 0; # Register select. push @muxtable, "dma_ctl_address == $i"; # Selected register name. my $reg_name = @{$reg_info[$i]}->[1]; # Special case: when "reserved3" is read, you get "control". $reg_name = "control" if ($reg_name eq "reserved3"); # Special case: when "length" is read, you get # writelength instead. That's because the value in the # (user-invisible) writelength register keeps track of # transfers which are fully completed, while length # can run ahead a bit. $reg_name = "writelength" if ($reg_name eq "length"); push @muxtable, $reg_name; } my $data_width = get_slave_port_data_width($Options); $module->add_contents( e_mux->new({ lhs => ["p1_dma_ctl_readdata", $data_width, ], type => "and_or", table => \@muxtable, }), e_register->new({ in => "p1_dma_ctl_readdata", out => "dma_ctl_readdata", }), ); $module->add_contents( e_assign->new({ lhs => e_signal->new({name => "done_transaction", width => 1}), rhs => "go & done_write", }) ); $module->add_contents( e_register->new({ out => "done", sync_set => "done_transaction & ~d1_done_transaction", sync_reset => "status_register_write", clock => "clk", async_value => 0, }), ); $module->add_contents( e_register->new({ out => "d1_done_transaction", in => "done_transaction", clock => "clk", async_value => 0, }), ); $module->add_contents( e_assign->new({ lhs => e_signal->new({name => "busy", width => 1}), rhs => "go & ~done_write", }) ); # Pull the status and control bits out into their own lists, # indexed by bit number. my @status_bits; map { # $_ = ["reg_name", "bit_name", "bit_pos", "comment"]; $status_bits[$_->[2]] = $_->[1]; } get_status_bits(); my @control_bits; map { # $_ = ["reg_name", "bit_name", "bit_pos", "comment"]; $control_bits[$_->[2]] = $_->[1]; } get_control_bits(); $module->add_contents( e_signal->new({ name => "status", width => 0 + @status_bits, never_export => 1, }), ); # Assign each status bit from its status reg. for my $i (0 .. @status_bits - 1) { $module->add_contents( e_assign->new({ rhs => "$status_bits[$i]", lhs => "status[$i]", }) ); } # Assign random control bit signals from the control register. for my $i (0 .. @control_bits - 1) { my $bit_name = $control_bits[$i]; my $rhs = "control[$i]"; if ($Options->{burst_enable} && ($bit_name =~ /^[rw]een$/)) { # Bursting DMAs are not allowed to terminate early on # write endofpacket events (doing so would violate the # burst master rule that all requested burst transactions # must be done - in all likelihood, the result would be system # lockup). To avoid this, prevent the ween bit from being set. # Also prevent the reen bit from being set, because I can't see # any use in setting reen on a read burst. $rhs = "1'b0"; } $module->add_contents( e_assign->new({ lhs => e_signal->new({ name => $bit_name, never_export => 1 }), rhs => $rhs, }) ); } # How about an IRQ output? $module->add_contents( e_assign->new({ lhs => "dma_ctl_irq", rhs => "i_en & done", }) );}sub push_global_ports{ my $module = shift; $module->add_contents( e_port->new({name => "clk", type => "clk",}), e_port->new({name => "system_reset_n", type => "reset_n",}), );}sub get_control_interface_map{ my $Options = shift; # Even master-less DMAs need these signals. my @map = ( "dma_ctl_irq" => "irq", "dma_ctl_readyfordata" => "readyfordata", ); if (@{$Options->{masters_of_my_slave_port}}) { # If the slave port has master(s), these ports are also needed. push @map, ( "dma_ctl_chipselect" => "chipselect", "dma_ctl_address" => "address", "dma_ctl_write_n" => "write_n", "dma_ctl_writedata" => "writedata", "dma_ctl_readdata" => "readdata", "clk" => "clk", "system_reset_n" => "reset_n", ); } return @map;}sub modify_burst_system_ptf_asssignments { my ($project, $module, $Options) = @_; my $max_burst_size = $Options->{burst_enable} ? $Options->{max_burst_size} : 1; my $module_name = $module->name(); my $sys_ptf = $project->system_ptf(); $sys_ptf-> {"MODULE $module_name"}-> {"MASTER $write_master_name"}-> {"SYSTEM_BUILDER_INFO"}->{Maximum_Burst_Size} = $max_burst_size; $sys_ptf-> {"MODULE $module_name"}-> {"MASTER $read_master_name"}-> {"SYSTEM_BUILDER_INFO"}->{Maximum_Burst_Size} = $max_burst_size;}sub push_control_interface_ports{ my ($project, $module, $Options) = @_; my $data_width = get_slave_port_data_width($Options); my $addr_width = get_slave_port_addr_width($Options); # While we're here, why not update the SBI section of the slave? # It's got probably-reasonable values from the class.ptf, but it # will be wrong if e.g. there's a large read- or write-address port. my $module_name = $module->name(); my $sys_ptf = $project->system_ptf(); my $slave_sbi = $sys_ptf-> {"MODULE $module_name"}-> {"SLAVE $control_port_name"}-> {"SYSTEM_BUILDER_INFO"}; ribbit("what th'?") if (!$slave_sbi); $slave_sbi->{Data_Width} = $data_width; $slave_sbi->{Address_Width} = $addr_width; if (@{$Options->{masters_of_my_slave_port}}) { $module->add_contents( e_port->new({name => "dma_ctl_irq", type => "irq", direction => "output"}), ); $module->add_contents( e_port->new({ name => "dma_ctl_readyfordata", type => "readyfordata", direction => "output" }), e_assign->new(["dma_ctl_readyfordata", "~busy"]), ); $module->add_contents( e_port->new({name => "dma_ctl_chipselect", type => "chipselect",}), e_port->new({ name => "dma_ctl_address", type => "address", width => $addr_width, }), e_port->new({name => "dma_ctl_write_n", type => "write_n",}), e_port->new({ name => "dma_ctl_writedata", width => $data_width, type => "writedata", }), e_port->new({ name => "dma_ctl_readdata", width => $data_width, type => "readdata", direction => "output", },), ); } else { # No masters. Generate a minimal port set; generate default-level signals # for other control signals. $module->add_contents( e_port->new({ name => "dma_ctl_readyfordata", direction => "output" }), e_assign->new(["dma_ctl_readyfordata", "~busy"]), e_port->new({name => "dma_ctl_irq", direction => "output"}), e_assign->new([ e_signal->new(["dma_ctl_chipselect", 1, 0, 1,]), 0 ]), e_assign->new([ e_signal->new(["dma_ctl_address", $addr_width, 0, 1]), 0 ]), e_assign->new([ e_signal->new(["dma_ctl_write_n", 1, 0, 1,]), 1 ]), e_assign->new([ e_signal->new(["dma_ctl_writedata", $data_width, 0, 1]), 0 ]), e_signal->new([ "dma_ctl_readdata", $data_width, 0, 1 ]), ); }}sub get_read_master_type_list{ return qw( readdata readdatavalid read_n flush );}sub get_write_master_type_list{ return qw( write_n writedata byteenable );}sub get_master_type_list{ my $Options = shift; my $burst_enable = $Options->{burst_enable}; my @master_type_list = qw( address chipselect waitrequest endofpacket ); push @master_type_list, "burstcount" if $burst_enable; return @master_type_list;}sub get_write_master_type_map{ my $Options = shift; ribbit("no Options hash\n") if (!$Options); my $port_prefix = 'write'; my @types = get_master_type_list($Options); # Add in all write-master-specific ports. Omit # byteenable if there ain't none. push @types, grep {has_byteenables($Options) or $_ ne 'byteenable'} get_write_master_type_list(); # Make a hash of $port_prefix . "_" . $type[] => $type[]. return map {($port_prefix . "_$_" => $_)} @types;}sub get_read_master_type_map{ my $Options = shift; ribbit("no Options hash\n") if (!$Options); my $port_prefix = 'read'; my @types = get_master_type_list($Options); push @types, get_read_master_type_list(); # Make a hash of $port_prefix . "_" . $type[] => $type[]. return map {($port_prefix . "_$_" => $_)} @types;}sub has_byteenables{ my $Options = shift; # We need byteenables if more than one transaction size # is allowed. my $has_byteenables = scalar(get_allowed_transactions()) > 1; return $has_byteenables;}# This is the point where the transaction size bits have an impact.# The write master sends out its byte address as always, but must modulate# the byte enables according to 1) the lower address bits and 2) the# transaction size.# The maximum number of bytes transferred in one write is equal to the # number represented by '1' in the most-significant transaction size bit,# and '0' in all other bits.# Loop over all possible transaction sizes. Note that the number of# byteenables (related to the write port data width) determines the# maximum transaction size. Example: if the write data port is 32 bits,# there are 4 byte enables and the max transaction size is 4 bytes aka# 'word'.sub make_write_byteenables{ my ($Options, $module, $project) = @_; my $port_prefix = 'write'; my $num_byteenables = $Options->{writedatawidth} / 8; # SPR 12225. return () if not has_byteenables($Options); my $byteenable_module = e_module->new({ name => $module->name() . "_byteenables", });
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -