📄 em_de2_pio.pl
字号:
type => "integer", default => 0, }); # Test to make sure the reset-value fits: $Options->{reset_value_bits} = &Bits_To_Encode($Options->{reset_value}); &validate_parameter ({hash => $Options, name => "reset_value_bits", range => [0, $Options->{width}], }); # Build-up some derived "Option" values, which are handy to # have as booleans: $Options->{has_any_input} = $Options->{has_tri} || $Options->{has_in}; $Options->{has_any_output} = $Options->{has_tri} || $Options->{has_out}; # If we've specified an IRQ, there must be some kind of input. # Likewise for edge-detection. $Options->{has_edge} = $Options->{edge_type} ne "NONE"; $Options->{irq_on_edge} = $Options->{irq_type} eq "EDGE"; &validate_parameter ({hash => $Options, name => "has_irq", optional => 1, requires => "has_any_input", }); &validate_parameter ({hash => $Options, name => "has_edge", optional => 1, requires => "has_any_input", }); &validate_parameter ({hash => $Options, name => "irq_on_edge", optional => 1, requires => "has_edge", });# warn "done with options\n";# foreach my $key (keys (%$Options))# {# warn " $key gets $Options->{$key}\n";# }}################################################################# make_pio## Given a name and a hashful of options, builds an e_module object# which implements a PIO peripheral.#################################################################sub make_pio{ my ($module, $Opt) = (@_); &Validate_PIO_Options ($Opt); # Create a new, empty module, and mark it as the one into which # all new "things" should go. It gets unmarked when this subroutine # exits and "$marker" is destroyed. # my $marker = e_default_module_marker->new($module); # Leo is silly about hating the range [0:0] applied to scalars. # To get around this, we precompute the bit-ragen appropriate for # this PIO -as a string-, which may be null ("") for a 1-bit PIO. # my $bitrange = ($Opt->{width} > 1)? '[' . ($Opt->{width} - 1) . ':0]' : ""; e_signal->adds ( [edge_capture_wr_strobe => 1], [clk_en => 1,0,1], [chipselect => 1], [clk => 1], [reset_n => 1], ); # We don't really use the global clock-enable in this peripheral: e_assign->add (["clk_en", 1]); ################ # First, declare my PIO port signals: # e_port->add(["bidir_port", $Opt->{width}, "inout"]) if $Opt->{has_tri}; e_port->add(["in_port", $Opt->{width}, "in" ]) if $Opt->{has_in}; e_port->add(["out_port", $Opt->{width}, "out" ]) if $Opt->{has_out}; ################ # Addressable-register infrastructure: # Read-mux (starts off blank--sometimes doesn't exist) # readdata-register (also sometimes doesn't exist) # avalon-slave port (always exists) # read/writedata ports (sometimes don't exist) # e_avalon_slave->add ({name => "s1",}); # I want my slave-ports seen by the SOPC-Builder. e_port->add(["address", 2, "in"]); if ($Opt->{has_any_output} || $Opt->{has_irq} || $Opt->{has_edge}) { e_port->adds(["writedata", $Opt->{width}, "in"], ["write_n" , 1 , "in"]); } my $read_mux; if ($Opt->{has_any_input}) { e_port->add(["readdata", $Opt->{width}, "output"]); $read_mux = e_mux->add ({lhs => e_signal->add (["read_mux_out", $Opt->{width} ]), type => "and-or", }); # Note that the register on "readdata" implies one-wait-state access. e_register->add ({out => "readdata", in => "read_mux_out"}); } ################ # Writeable data-out register, if reqired. # if ($Opt->{has_any_output}) { e_register->add ({out => e_signal->add (["data_out", $Opt->{width}]), in => "writedata $bitrange", enable => "chipselect && ~write_n && (address == 0)", async_value => $Opt->{reset_value}, }); # While we're here, do the actual output-assignment: if ($Opt->{has_tri}) { # Lovingly-assign each bit depending on direction-register. # Deal with Leo's hatred of bit-selects on scalar wires: if ($Opt->{width} == 1) { e_assign->add (["bidir_port", "data_dir ? data_out : 1'bZ"]); } else { for (my $i = 0; $i < $Opt->{width}; $i++) { e_assign->add (["bidir_port[$i]", "data_dir[$i] ? data_out[$i] : 1'bZ"]); } } } e_assign->add (["out_port", "data_out"]) if $Opt->{has_out}; } ################ # Readable data-in register, if required. # if ($Opt->{has_any_input}) { e_signal->add(["data_in", $Opt->{width}]); e_assign->add(["data_in", "in_port" ]) if $Opt->{has_in}; e_assign->add(["data_in", "bidir_port"]) if $Opt->{has_tri}; $read_mux->add_table ("(address == 0)" => "data_in"); } ################ # Writeable / Readable data-direction register, if required. # if ($Opt->{has_tri}) { e_register->add ({out => e_signal->add (["data_dir", $Opt->{width}]), in => "writedata $bitrange", enable => "chipselect && ~write_n && (address == 1)", }); $read_mux->add_table ("(address == 1)" => "data_dir"); } ################ # Writeable/readable interrupt-masking register, if required. # if ($Opt->{has_irq}) { e_register->add ({out => e_signal->add (["irq_mask", $Opt->{width}]), in => "writedata $bitrange", enable => "chipselect && ~write_n && (address == 2)", }); $read_mux->add_table ("(address == 2)" => "irq_mask"); e_port->add(["irq" => 1, "output"]); ########## # While we're in here, compute the IRQ-result: if ($Opt->{irq_type} eq "LEVEL") { e_assign->add (["irq", "|(data_in & irq_mask)"]) } elsif ($Opt->{irq_type} eq "EDGE") { e_assign->add (["irq", "|(edge_capture & irq_mask)"]) } else { &ribbit ("Unexpected bad irq_type: $Opt->{irq_type}"); } } ################ # Readable / clearable edge-capture register. # Each bit of this register is set by an edge on the corresponding # input-bit, and all # if ($Opt->{has_edge}) { e_signal->add (["edge_capture", $Opt->{width}]); $read_mux->add_table ("(address == 3)" => "edge_capture"); e_assign->add ([ "edge_capture_wr_strobe", "chipselect && ~write_n && (address == 3)", ]); # Create S/R registers for each bit, MSB-first (so list is in right order) # Deal with Leo's hatred of bit-selects on scalar wires: if ($Opt->{width} == 1) { e_register->add ({out => "edge_capture", sync_set => "edge_detect", sync_reset => "edge_capture_wr_strobe", }); } else { for (my $i = 0; $i < $Opt->{width}; $i++) { e_register->add ({out => "edge_capture[$i]", sync_set => "edge_detect[$i]", sync_reset => "edge_capture_wr_strobe", }); } } ################ # Edge-detection mechanism # # Synchronize incoming data-signals (this bit us in both the # 1.0 and 1.1 releases). e_register->add({in => "data_in", delay => 2}); e_signal->add (["edge_detect", $Opt->{width}]); if ($Opt->{edge_type} eq "RISING") { e_assign->add (["edge_detect", " d1_data_in & ~d2_data_in"]); } elsif ($Opt->{edge_type} eq "FALLING") { e_assign->add (["edge_detect", "~d1_data_in & d2_data_in"]); } elsif ($Opt->{edge_type} eq "ANY") { e_assign->add (["edge_detect", " d1_data_in ^ d2_data_in"]); } else { &ribbit ("Unexpected bad edge type: $Opt->{edge_type}"); } } return $module;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -