📄 em_uart.pl
字号:
my $newline = "\n";
my $cr = "\n";
my $double_quote = "\"";
$char_stream =~ s/\\n\\r/\n/sg;
$char_stream =~ s/\\n/$newline/sg;
$char_stream =~ s/\\r/$cr/sg;
$char_stream =~ s/\\\"/$double_quote/sg;
my $crlf = "\n\r";
$char_stream =~ s/\n/$crlf/smg;
$Options->{stream_length} = length ($char_stream);
$Options->{char_data_file} = $Options->{name} . "_input_data_stream.dat";
$Options->{char_mutex_file} = $Options->{name} . "_input_data_mutex.dat";
my $sim_dir_name = $project->simulation_directory();
&Create_Dir_If_Needed($sim_dir_name);
open (DATFILE, "> $sim_dir_name/$Options->{char_data_file}")
or &ribbit ("couldn't open $sim_dir_name/$Options->{char_data_file} ($!)");
my $addr = 0;
foreach my $char (split (//, $char_stream)) {
printf DATFILE "\@%X\n", $addr;
printf DATFILE "%X\n", ord($char);
$addr++;
}
printf DATFILE "\@%X\n", $addr;
printf DATFILE "%X\n", 0;
close DATFILE;
open (MUTFILE, "> $sim_dir_name/$Options->{char_mutex_file}")
or &ribbit ("couldn't open $sim_dir_name/$Options->{char_mutex_file} ($!)");
if ($Options->{interactive_in})
{ # force user to use interactive window if selected by making mutex 0
printf MUTFILE "0\n";
}
else
{ # set up proper stream file size in Mutex:
printf MUTFILE "%X\n", $addr;
}
close MUTFILE;
$Options->{mutex_file_size} = $addr;
}
sub make_uart
{
my ($project) = (@_);
my $module = $project->top();
my $Options = ©_of_hash ($project->WSA());
$Options->{name} = $module->name();
$Options->{clock_freq} =
$project->system_ptf->{WIZARD_SCRIPT_ARGUMENTS}{clock_freq};
my $int_in_section =
$project->spaceless_module_ptf($Options->{name})->{SIMULATION}{INTERACTIVE_IN};
my $int_out_section=
$project->spaceless_module_ptf($Options->{name})->{SIMULATION}{INTERACTIVE_OUT};
my $interactive_in = 0; # default to non-interactive mode.
my $interactive_out= 0;
my $int_key;
my $this_int_section;
foreach $int_key (sort(keys (%{$int_in_section}))) {
$this_int_section = $int_in_section->{$int_key};
$interactive_in = $this_int_section->{enable};
}
foreach $int_key (sort(keys (%{$int_out_section}))) {
$this_int_section = $int_out_section->{$int_key};
$interactive_out = $this_int_section->{enable};
}
$Options->{interactive_in} = $interactive_in;
$Options->{interactive_out}= $interactive_out;
&Validate_Uart_Options ($Options, $project);
&Setup_Input_Stream ($Options, $project);
return if $project->_software_only();
$Options->{tx_module_name} = $Options->{name} . "_tx";
$Options->{rx_module_name} = $Options->{name} . "_rx";
$Options->{reg_module_name} = $Options->{name} . "_regs";
$Options->{log_module_name} = $Options->{name} . "_log";
my $tx_module = &make_uart_tx ($Options);
my $rx_module = &make_uart_rx ($Options);
my $reg_module = &make_uart_regs($Options);
my $log_instance = &make_uart_log ($Options);
my $marker = e_default_module_marker->new ($module);
e_assign->add(["clk_en", 1]);
e_instance->add ({module => $tx_module });
e_instance->add ({module => $rx_module });
e_instance->add ({module => $reg_module});
$module->add_contents ( $log_instance );
if ($Options->{interactive_in})
{
&Perlcopy ($project->_module_lib_dir . "/uart.pl",
$project->simulation_directory () . "/uart.pl" );
}
if ($Options->{interactive_out})
{
&Perlcopy ($project->_module_lib_dir . "/tail-f.pl",
$project->simulation_directory () . "/tail-f.pl" );
}
e_avalon_slave->add ({name => "s1"});
return $module;
}
sub make_uart_log {
my ($Options) = (@_);
return e_log->new ({
name => $Options->{"log_module_name"},
tag => "simulation",
port_map => {
"valid" => "~tx_ready",
"strobe" => "tx_wr_strobe",
"data" => "tx_data",
"log_file" => $Options->{log_file},
},
});
};
sub make_uart_tx
{
my ($Options) = (@_);
my $module = e_module->new ({name => $Options->{tx_module_name}});
my $marker = e_default_module_marker->new ($module);
# calculation the text for the code
my $parity_expr = "";
$parity_expr = "1'b0" if ($Options->{parity} =~ /^S0$/i);
$parity_expr = "1'b1" if ($Options->{parity} =~ /^S1$/i);
$parity_expr = " ^tx_data " if ($Options->{parity} =~ /^E$/i );
$parity_expr = "~(^tx_data)" if ($Options->{parity} =~ /^O$/i );
# calculating the size of the shift reister
my $tx_shift_bits =
($Options->{stop_bits} ) + # stop bits.
($Options->{parity} =~ /N/i ? 0 : 1) + # parity bit (opt.)
($Options->{data_bits} ) + # "payload"
(1 ) ; # start-bit
if($Options->{use_fifo} == 0)
{
e_assign->add (["tx_wr_strobe_onset", "tx_wr_strobe && begintransfer"]), # cruben this should be based on if you need a fifo or not
e_signal->add(["tx_data", $Options->{data_bits}]);
}
else
{
e_assign->add (["tx_wr_strobe_onset", "tx_wr_strobe && tx_ready"]), #cruben
e_signal->add(["tx_data", $Options->{data_bits}]);
}
my $load_val_expr = &concatenate ("\{$Options->{stop_bits} \{1'b1\}\}",
$parity_expr,
"tx_data",
"1'b0",
);
e_assign->add ({lhs => e_signal->add (["tx_load_val", $tx_shift_bits]),
rhs => $load_val_expr,
});
e_assign->add (["shift_done", "~(|tx_shift_register_contents)"]);
# added an additional port used when with fifos cruben
# e_register->add ({out => e_port->add (["do_load_shifter",1,"out"]),
# in => "(~tx_ready) && shift_done",
# })if $Options->{use_fifo};
e_register->add ({out => "do_load_shifter",
in => "(~tx_ready) && shift_done",
});
e_register->add ({
out => e_port->add (["tx_ready", 1, "out"]),
sync_set => "do_load_shifter",
sync_reset => "tx_wr_strobe_onset",
async_value => "1'b1",
});
e_register->add ({
out => "tx_overrun",
sync_set => "(~tx_ready && tx_wr_strobe_onset)",
sync_reset => "status_wr_strobe",
})if !$Options->{use_fifo};
e_register->add ({
out => "tx_shift_empty",
in => "tx_ready && shift_done",
async_value => "1'b1",
});
e_register->add ({
out => e_signal->add({name => "baud_rate_counter",
width => $Options->{divisor_bits}
}),
in => "baud_rate_counter - 1",
sync_set => "baud_rate_counter_is_zero || do_load_shifter",
set_value => "baud_divisor",
});
e_assign->add(["baud_rate_counter_is_zero", "baud_rate_counter == 0"]);
e_register->add ({out => "baud_clk_en",
in => "baud_rate_counter_is_zero",
});
e_assign->add(["do_shift", "baud_clk_en &&
(~shift_done) &&
(~do_load_shifter)"
]);
e_shift_register->add ({
serial_out => "tx_shift_reg_out",
serial_in => "1'b0",
parallel_in => "tx_load_val",
parallel_out => "tx_shift_register_contents",
shift_length => $tx_shift_bits,
direction => "LSB-first",
load => "do_load_shifter",
shift_enable => "do_shift",
});
e_register->add({
out => "pre_txd",
in => "tx_shift_reg_out",
enable => "~shift_done",
async_value => "1",
});
e_register->add ({
out => "txd",
in => "pre_txd & ~do_force_break",
async_value => "1",
});
return $module;
}
sub make_uart_rx
{
my ($Options) = (@_);
$Options->{rx_source_module_name} =
$Options->{rx_module_name} . "_stimulus_source";
my $stim_module = &make_uart_rxd_source($Options);
my $module = e_module->new ({name => $Options->{rx_module_name}});
my $marker = e_default_module_marker->new ($module);
e_instance->add ({module => $stim_module});
e_register->add({
out => "sync_rxd",
in => "source_rxd",
delay => 2,
});
e_edge_detector->add({
in => "sync_rxd",
out => "rxd_falling",
edge => "falling",
});
e_edge_detector->add({
in => "sync_rxd",
out => "rxd_edge",
edge => "any",
});
if($Options->{use_fifo} == 0)
{
e_assign->add (["rx_rd_strobe_onset", "rx_rd_strobe && begintransfer"]);
}
else
{
e_assign->add (["rx_rd_strobe_onset", "rx_rd_strobe"]);
}
e_signal->add (["half_bit_cell_divisor", $Options->{divisor_bits} - 1]);
e_assign->add ({
lhs => "half_bit_cell_divisor",
rhs => 'baud_divisor [baud_divisor.msb : 1]',
});
e_mux->add ({
lhs => e_signal->add (["baud_load_value", $Options->{divisor_bits}]),
table => [rxd_edge => "half_bit_cell_divisor"],
default => "baud_divisor",
});
e_register->add ({
out => e_signal->add(["baud_rate_counter",$Options->{divisor_bits}]),
in => "baud_rate_counter - 1",
sync_set => "baud_rate_counter_is_zero || rxd_edge",
set_value => "baud_load_value",
});
e_assign->add (["baud_rate_counter_is_zero", "baud_rate_counter == 0"]);
e_register->add ({
in => "baud_rate_counter_is_zero",
out => "baud_clk_en",
sync_set => "rxd_edge",
set_value => "0",
});
e_assign->add (["sample_enable", "baud_clk_en && rx_in_process"]);
e_register->add ({
out => "do_start_rx",
in => "0",
sync_set => "(~rx_in_process && rxd_falling)",
set_value => "1",
async_value => "0",
});
my $rx_shift_bits =
(1 ) + # stop bit.
($Options->{parity} =~ /N/i ? 0 : 1) + # parity bit (opt.)
($Options->{data_bits} ) + # "payload"
(1 ) ;
e_shift_register->add ({
parallel_out => "rxd_shift_reg",
serial_in => "sync_rxd",
serial_out => "shift_reg_start_bit_n",
parallel_in => "\{$rx_shift_bits\{1'b1\}\}",
shift_length => $rx_shift_bits,
direction => "LSB-first",
load => "do_start_rx",
shift_enable => "sample_enable",
});
e_assign->add (["rx_in_process", "shift_reg_start_bit_n"]);
e_signal->add (["raw_data_in", $Options->{data_bits}]);
my $start_bit_sig = e_signal->add(["unused_start_bit", 1]);
$start_bit_sig->never_export(1);
my @register_segments = ("stop_bit" );
push (@register_segments, "parity_bit") unless $Options->{parity} =~/^N$/i;
push (@register_segments, "raw_data_in",
"unused_start_bit");
e_assign->add([&concatenate (@register_segments), "rxd_shift_reg"]);
e_assign->adds(["is_break", "~(|rxd_shift_reg)" ],
["is_framing_error", "~stop_bit && ~is_break" ]);
e_edge_detector->add ({
out => "got_new_char",
in => "rx_in_process",
edge => "falling",
});
e_register->add({
in => "raw_data_in",
out => e_signal->add(["rx_data", $Options->{data_bits}]),
enable => "got_new_char",
});
e_register->add({
out => "framing_error",
sync_set => "(got_new_char && is_framing_error)",
sync_reset => "status_wr_strobe",
});
e_register->add({
out => "break_detect",
sync_set => "(got_new_char && is_break)",
sync_reset => "status_wr_strobe",
});
e_register->add({
out => "rx_overrun",
sync_set => "(got_new_char && rx_char_ready)",
sync_reset => "status_wr_strobe",
});
e_register->add({
out => e_port->add (["rx_char_ready", 1, "out"]),
sync_set => "got_new_char",
sync_reset => "rx_rd_strobe_onset",
priority => "reset",
});
if ($Options->{parity} =~ /^N$/i) {
e_assign->add (["parity_error", "0"]);
} else {
my $correct_parity_expr = "";
$correct_parity_expr = "0" if $Options->{parity} =~ /^S0$/i;
$correct_parity_expr = "1" if $Options->{parity} =~ /^S1$/i;
$correct_parity_expr = " (^raw_data_in)" if $Options->{parity} =~ /^E$/i;
$correct_parity_expr = "~(^raw_data_in)" if $Options->{parity} =~ /^O$/i;
e_assign->add (["correct_parity", $correct_parity_expr]);
e_assign->add ({
lhs => "is_parity_error",
rhs => "(correct_parity != parity_bit) && ~is_break",
});
e_register->add ({
out => "parity_error",
sync_set => "got_new_char && is_parity_error",
sync_reset => "status_wr_strobe",
});
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -