📄 em_uart.pl
字号:
return $module;
}
sub make_uart_regs
{
my ($Options) = (@_);
my $module = e_module->new ({name => $Options->{reg_module_name}});
my $marker = e_default_module_marker->new ($module);
e_register->add({
out => e_signal->add (["readdata", 16]),
in => e_signal->add (["selected_read_data", 16]),
});
#irq get connected automatically so I have to cahnge the name so it will not
if ( $SBI->{Has_IRQ})
{
e_register->add({
out => "irq",
in => "qualified_irq",
});
}
else
{
e_register->add({
out => "irqs",
in => "qualified_irq",
});
}
e_port->adds (
["address", 3, "in" ],
["writedata", 16, "in" ],
["tx_wr_strobe", 1, "out"],
["status_wr_strobe", 1, "out"],
["rx_rd_strobe", 1, "out"],
["baud_divisor", $Options->{divisor_bits}, "out"],
);
# e_assign->adds(
# ["rx_rd_strb", "rx_char_ready"],
# ["tx_wr_strb", "tx_shift_empty && ~tx_empty"],) if $Options->{use_fifo};
e_assign->adds(
["status_wr_strobe", "chipselect && ~write_n && (address == 3'd2)"],
["control_wr_strobe", "chipselect && ~write_n && (address == 3'd3)"],);
e_assign->add(["rx_rd_strobe", "chipselect && ~read_n && (address == 3'd0)"])if !$Options->{use_fifo};
e_assign->add(["rx_fifo_rd_strobe", "chipselect && ~read_n && (address == 3'd0) && begintransfer"])if $Options->{use_fifo};
e_assign->add(["rx_rd_strobe", "rx_char_ready && rx_not_full"])if $Options->{use_fifo};
e_assign->add(["tx_wr_strobe", "chipselect && ~write_n && (address == 3'd1)"])if !$Options->{use_fifo};
e_assign->add(["tx_fifo_wr_strobe", "chipselect && ~write_n && (address == 3'd1) && begintransfer"])if $Options->{use_fifo};
e_assign->add(["tx_wr_strobe", "tx_ready && tx_not_empty"])if $Options->{use_fifo};
e_assign->add([ e_signal->add (["reset",1]),"~reset_n",]) if $Options->{use_fifo};
e_assign->add([
"divisor_wr_strobe", "chipselect && ~write_n && (address == 3'd4)",
]) if !$Options->{fixed_baud};
e_assign->add([
"eop_char_wr_strobe","chipselect && ~write_n && (address == 3'd5)",
]) if $Options->{use_eop_register};
my $tx_data_sig = e_signal->add(["tx_data", $Options->{data_bits}]);
$tx_data_sig->export(1);
e_register->add ({
out => $tx_data_sig,
in => "writedata\[tx_data.msb : 0\]",
enable => "tx_wr_strobe",
})if !$Options->{use_fifo}; #fifo will supply if present
e_register->add ({
out => $tx_data_sig,
in => "tx_fifo_q",
enable => "tx_wr_strobe",
})if $Options->{use_fifo}; #fifo will supply if present
e_register->add ({
out => e_signal->add(["control_reg", $Options->{num_control_reg_bits}]),
in => "writedata\[control_reg.msb:0\]",
enable => "control_wr_strobe",
});
e_register->add ({
out => e_signal->add(["eop_char_reg", $Options->{data_bits}]),
in => "writedata\[eop_char_reg.msb:0\]",
enable => "eop_char_wr_strobe",
}) if $Options->{use_eop_register};
e_register->add ({
out => "tx_overrun",
sync_set => "tx_full && tx_fifo_wr_strobe",
sync_reset => "status_wr_strobe",
})if $Options->{use_fifo};
e_edge_detector->add ({
tag => "simulation",
out => "do_write_char",
in => "tx_ready",
});
e_process->add ({
tag => "simulation",
contents => [
e_if->new ({
tag => "simulation",
condition => "do_write_char",
then => [
e_sim_write->new ({
spec_string => '%c',
expressions => ["tx_data"],
})
],
}),
]});
e_signal->add (["divisor_constant", $Options->{divisor_bits}]);
e_assign->add ({
tag => $Options->{sim_true_baud} ? "normal" : "synthesis",
lhs => "divisor_constant",
rhs => $Options->{baud_divisor_constant}
});
e_assign->add ({
tag => "simulation",
lhs => "divisor_constant",
rhs => 4,
}) if !$Options->{sim_true_baud};
if ($Options->{fixed_baud}) {
e_assign->add(["baud_divisor", "divisor_constant"]);
} else {
e_register->add ({
in => "writedata\[baud_divisor.msb:0\]",
out => "baud_divisor",
enable => "divisor_wr_strobe",
async_value => "divisor_constant",
});
}
if ($Options->{use_cts_rts}) {
e_register->add ({
in => "~cts_n",
out => "cts_status_bit",
async_value => 1,
});
e_edge_detector->add ({
in => "cts_status_bit",
out => "cts_edge",
edge => "any",
});
e_register->add ({
out => "dcts_status_bit",
sync_set => "cts_edge",
sync_reset => "status_wr_strobe",
async_value => 0,
});
e_assign->add (["rts_n", "~rts_control_bit"]);
} else {
e_assign->adds (["cts_status_bit", 0],
["dcts_status_bit", 0]);
}
e_signal->adds({name => "rts_control_bit", never_export => 1},
{name => "ie_dcts", never_export => 1});
my @control_reg_bits = ();
push (@control_reg_bits, "ie_eop" ) if $Options->{use_eop_register};
push (@control_reg_bits, "rts_control_bit",
"ie_dcts" ) if ($Options->{use_cts_rts} |
$Options->{use_eop_register});
push (@control_reg_bits, "do_force_break",
"ie_any_error",
"ie_rx_char_ready",
"ie_tx_ready",
"ie_tx_shift_empty",
"ie_tx_overrun",
"ie_rx_overrun",
"ie_break_detect",
"ie_framing_error",
"ie_parity_error",
);
e_assign->add([&concatenate(@control_reg_bits), "control_reg"]);
e_assign->add ({
lhs => "any_error",
rhs => join (" ||\n", "tx_overrun",
"rx_overrun",
"parity_error",
"framing_error",
"break_detect",
),
});
my @status_reg_bits = ();
push (@status_reg_bits, "eop_status_bit",
"cts_status_bit",
"dcts_status_bit",
"1'b0",
"any_error",
"rx_char_ready",
"tx_ready",
"tx_shift_empty",
"tx_overrun",
"rx_overrun",
"break_detect",
"framing_error",
"parity_error",
)if !$Options->{use_fifo};
push (@status_reg_bits, "eop_status_bit",
"cts_status_bit",
"dcts_status_bit",
"1'b0",
"any_error",
"rx_not_empty",
"tx_not_full",
"tx_shift_empty",
"tx_overrun",
"rx_overrun",
"break_detect",
"framing_error",
"parity_error",
)if $Options->{use_fifo};
e_assign->add ({
lhs => e_signal->add(["status_reg", $Options->{num_status_reg_bits}]),
rhs => &concatenate (@status_reg_bits),
});
# comment
if ( $Options->{use_fifo})
{
e_register->add({
in => "rx_not_empty",
});
e_register->add({
in => "tx_not_full",
});
e_register->add({
in => "rx_rd_strobe",
});
e_register->add({
in => "rx_fifo_rd_strobe",
});
# e_register->add({
# in => "tx_ready",
# });
e_register->add({
in => "tx_wr_strobe",
});
e_assign->adds
([e_port->new (["dataavailable", 1, "out"]), "d1_rx_not_empty"],
[e_port->new (["readyfordata", 1, "out"]), "d1_tx_not_full" ] );
}
else
{
e_register->add({
in => "rx_char_ready",
});
e_register->add({
in => "tx_ready",
});
e_assign->adds
([e_port->new (["dataavailable", 1, "out"]), "d1_rx_char_ready"],
[e_port->new (["readyfordata", 1, "out"]), "d1_tx_ready" ] );
}
my $fifo_address_bits = log2($Options->{fifo_size});
if ( $Options->{use_fifo})
{
my $in_tx_port_map = {
rdreq => 'd1_tx_wr_strobe', #needs to be one clock late
sclr => 'reset',
clock => 'clk',
wrreq => 'tx_fifo_wr_strobe',
data => "writedata\[tx_data.msb:0\]",
};
my $out_tx_port_map = {
q => 'tx_fifo_q',
usedw => 'tx_used',
empty => 'tx_empty',
full => 'tx_full',
};
my $in_rx_port_map = {
rdreq => 'd1_rx_fifo_rd_strobe',
sclr => 'reset',
clock => 'clk',
wrreq => 'd1_rx_rd_strobe',
data => 'rx_data',
};
my $out_rx_port_map = {
q => 'rx_data_b',
usedw => 'rx_used',
empty => 'rx_empty',
full => 'rx_full',
};
my $parameter_map = {
lpm_width => $Options->{data_bits},
lpm_numwords => $Options->{fifo_size},
lpm_widthu => $fifo_address_bits,
lpm_type => qq("scfifo"),
lpm_showahead => qq("ON"),
overflow_checking => qq("ON"),
underflow_checking => qq("ON"),
use_eab => qq("ON"),
};
e_blind_instance->add({
tag => 'normal',
use_sim_models => 1,
name => 'write_fifo',
module => 'scfifo',
in_port_map => $in_tx_port_map,
out_port_map => $out_tx_port_map,
parameter_map => $parameter_map,
});
# e_instance->new({
# name => 'write_fifo',
# module => 'scfifo',
# port_map => {
# 'rdreq' => 'do_load_shifter',
# 'sclr' => 'reset',
# 'clock' => 'clk',
# 'wrreq' => 'tx_wr_strobe',
# 'data' => "writedata\[tx_data.msb:0\]", #"writedata\[tx_data.msb : 0\]" $Options->{data_bits}
# 'q' => 'tx_data',
# 'usedw' => 'tx_used',
# 'empty' => 'tx_empty',
# 'full' => 'tx_full',
# }
# parameter_map => $parameter_map,
# });
e_blind_instance->add({
tag => 'normal',
use_sim_models => 1,
name => 'read_fifo',
module => 'scfifo',
in_port_map => $in_rx_port_map,
out_port_map => $out_rx_port_map,
parameter_map => $parameter_map,
});
e_signal->add(["rx_buff_used", $fifo_address_bits+1]);
e_signal->add(["tx_buff_used", $fifo_address_bits+1]);
e_signal->add(["rx_used", $fifo_address_bits]);
e_signal->add(["tx_used", $fifo_address_bits]);
e_signal->add(["rx_data_b", $Options->{data_bits}]);
e_signal->add(["tx_fifo_q", $Options->{data_bits}]);
e_assign->add(["rx_buff_used", "\{rx_full,rx_used\}"]);
e_assign->add(["rx_not_empty", "~rx_empty"]);
e_assign->add(["rx_not_full", "~rx_full"]);
e_assign->add(["tx_buff_used", "\{tx_full,tx_used\}"]);
e_assign->add(["tx_not_full", "~tx_full"]);
e_assign->add(["tx_not_empty", "~tx_empty"]);
}
if ($Options->{fifo_export_used} && $Options->{use_fifo}) {
e_port->add(["rxused", ($fifo_address_bits + 1), "out"]);
e_port->add(["txused", ($fifo_address_bits + 1), "out"]);
e_assign->add(["txused", "tx_buff_used"]);
e_assign->add(["rxused", "rx_buff_used"]);
}
if ($Options->{use_eop_register}) {
e_register->add ({
out => "eop_status_bit",
sync_set => "(rx_rd_strobe && (eop_char_reg == rx_data)) ||
(tx_wr_strobe &&
(eop_char_reg == writedata\[tx_data.msb:0\]))",
sync_reset => "status_wr_strobe",
async_value => 0,
});
e_assign->add
([e_port->new (["endofpacket", 1, "out"]), "eop_status_bit"]);
} else {
e_assign->add (["eop_status_bit", "1'b0"]);
}
my @read_mux_table = (
"(address == 3'd1)" => "tx_data",
"(address == 3'd2)" => "status_reg",
"(address == 3'd3)" => "control_reg",
);
push (@read_mux_table, "(address == 3'd0)" => "rx_data")
if !$Options->{use_fifo};
push (@read_mux_table, "(address == 3'd0)" => "rx_data_b")
if $Options->{use_fifo};
push (@read_mux_table, "(address == 3'd4)" => "baud_divisor")
if !$Options->{fixed_baud};
push (@read_mux_table, "(address == 3'd5)" => "eop_char_reg")
if $Options->{use_eop_register};
push (@read_mux_table, "(address == 3'd6)" => "rx_buff_used")
if $Options->{use_fifo};
push (@read_mux_table, "(address == 3'd7)" => "tx_buff_used")
if $Options->{use_fifo};
e_mux->add ({
lhs => e_signal->add(["selected_read_data", 16]),
table => \@read_mux_table,
type => "and-or",
});
my @irq_terms = ();
push (@irq_terms, "(ie_dcts && dcts_status_bit )")
if $Options->{use_cts_rts};
push (@irq_terms, "(ie_eop && eop_status_bit )")
if $Options->{use_eop_register};
push (@irq_terms, "(ie_any_error && any_error )",
"(ie_tx_shift_empty && tx_shift_empty )",
"(ie_tx_overrun && tx_overrun )",
"(ie_rx_overrun && rx_overrun )",
"(ie_break_detect && break_detect )",
"(ie_framing_error && framing_error )",
"(ie_parity_error && parity_error )",
"(ie_rx_char_ready && rx_char_ready )",
"(ie_tx_ready && tx_ready )",
)if !$Options->{use_fifo};
push (@irq_terms, "(ie_any_error && any_error )",
"(ie_tx_shift_empty && tx_shift_empty )",
"(ie_tx_overrun && tx_overrun )",
"(ie_rx_overrun && rx_overrun )",
"(ie_break_detect && break_detect )",
"(ie_framing_error && framing_error )",
"(ie_parity_error && parity_error )",
"(ie_rx_char_ready && rx_char_ready )",
"(ie_tx_ready && tx_not_full )",
)if $Options->{use_fifo};
e_assign->add (["qualified_irq", join (" ||\n", @irq_terms)]);
return $module,
}
sub make_uart_rxd_source
{
my ($Options) = (@_);
my $module = e_module->new ({name => $Options->{rx_source_module_name}});
my $marker = e_default_module_marker->new ($module);
e_port->adds(
["rxd", 1, "in"],
["source_rxd", 1, "out"],
["rx_char_ready", 1, "in"],
["clk", 1, "in"],
["clk_en", 1, "in"],
["reset_n", 1, "in"],
["rx_char_ready", 1, "in"],
["baud_divisor", $Options->{divisor_bits}, "in"],
);
e_assign->add({
tag => "synthesis",
lhs => "source_rxd",
rhs => "rxd",
});
my @dummies = e_signal->adds (
["unused_overrun"],
["unused_ready" ],
["unused_empty" ],
);
foreach my $dummy_sig (@dummies) {
$dummy_sig->never_export (1);
}
e_instance->add ({
module => $Options->{"tx_module_name"},
name => "stimulus_transmitter",
tag => "simulation",
port_map => {
txd => "source_rxd",
tx_overrun => "unused_overrun",
tx_ready => "unused_ready",
tx_shift_empty => "unused_empty",
do_force_break => "1'b0",
status_wr_strobe => "1'b0",
tx_data => "d1_stim_data",
begintransfer => "do_send_stim_data",
tx_wr_strobe => "1'b1",
},
});
e_signal->add ({
tag => "simulation",
name => "stim_data",
width => $Options->{data_bits},
});
e_register->add ({
tag => "simulation",
in => "stim_data",
out => e_signal->add(["d1_stim_data", $Options->{data_bits}]),
enable => "do_send_stim_data",
});
my $size = &max ($Options->{mutex_file_size} + 1, 1024);
e_drom->add ({
name => $module->name()."_character_source_rom",
rom_size => $size,
dat_name => $Options->{char_data_file},
mutex_name => $Options->{char_mutex_file},
interactive => $Options->{interactive_in},
port_map => {"q" => "stim_data",
"new_rom" => "new_rom_pulse",
"incr_addr" => "do_send_stim_data",
}
});
e_edge_detector->add ({
tag => "simulation",
out => "pickup_pulse",
in => "rx_char_ready",
edge => "falling",
});
e_assign->add ({
tag => "simulation",
lhs => "do_send_stim_data",
rhs => "(pickup_pulse || new_rom_pulse) && safe",
});
return $module;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -