Files
FPGA_DESIGN_IP/stream_rx_ctrl/sim/func001/vip_uart.sv
2026-03-06 16:22:17 +08:00

216 lines
6.6 KiB
Systemverilog

`ifndef _VIP_UART_SV_
`define _VIP_UART_SV_
module vip_uart
(
input logic rx,
output logic tx
);
parameter CAPTURE = "none"; // "none": no capture, "hex": hex capture, "raw": raw capture(ascii)
parameter DW = 8;
parameter BAUD_RATE = 115200;
parameter CHK_MODE = "none";
parameter STOP_BITS = 1.0;
parameter BAUD_ERROR = 0.0;
parameter SAMPLES = 32;
parameter SAMPLE_TH = $floor(SAMPLES*0.9);
parameter IDLE_BYTES_MS = 0;
parameter RX_BIT_WIDTH_NS = 1.0/(BAUD_RATE) * 1e9;//receiption do not take baud rate skew into account
parameter TX_BIT_WIDTH_NS = 1.0/(BAUD_RATE * (1 - BAUD_ERROR)) * 1e9;//transmit takes baud rate skew into account
parameter TX_STOP_WIDTH_NS = STOP_BITS * TX_BIT_WIDTH_NS;
parameter RX_SAMPLE_WIDTH_NS = RX_BIT_WIDTH_NS/SAMPLES;
parameter integer STOP_BIT_SAMPLES = $ceil(STOP_BITS*SAMPLES);
logic rx_clk;
logic [SAMPLES-1:0] rx_sample_bits;
logic [STOP_BIT_SAMPLES-1:0] rx_sample_stop_bits;
logic [DW-1:0]rx_data;//valid while rx_valid =1
logic rx_valid;//asserted when a new word receiption has just completed,deasserted when new receiption starts,
logic parity_error;//asserted when a parity error has been detected,deasserted when new receiption starts
logic stop_error;//asserted when a stop error has been detected,deasserted when new receiption starts
initial begin
tx = 1;
rx_valid = 0;
parity_error = 0;
stop_error = 0;
end
initial begin
integer log_file;
string full_path;
string instance_name;
int last_dot_pos;
// Get the full hierarchical path into a string
full_path = $sformatf("%m");
instance_name = full_path;
if (CAPTURE != "none") begin
log_file = $fopen({instance_name,"_capture.log"},"w");
if(log_file == 0) begin
$error("Failed to open log file for writing.");
end
end
if (CAPTURE == "hex") begin
$fwrite(log_file,"# %s hex capture log:\n",instance_name);
forever begin
repeat(16) begin
@(posedge rx_valid);
$fwrite(log_file,"%02x ",rx_data);
$fwrite(log_file,"\n");
end
end
end else if (CAPTURE == "raw") begin
$fwrite(log_file,"// %s raw capture log:\n",instance_name);
forever @(posedge rx_valid) begin
$fwrite(log_file,"%c",rx_data);
end
end
end
task automatic send(logic [DW-1:0] data);
tx = 0;
#(TX_BIT_WIDTH_NS*1ns);
for(int i = 0;i < DW;i++) begin
tx = data[i];
#(TX_BIT_WIDTH_NS*1ns);
end
case (CHK_MODE)
"odd":begin
tx = (^data) ^ 1;
#(TX_BIT_WIDTH_NS*1ns);
end
"even":begin
tx = (^data) ^ 0;
#(TX_BIT_WIDTH_NS*1ns);
end
endcase
tx = 1;
#(TX_STOP_WIDTH_NS*1ns);
#(IDLE_BYTES_MS*1ms);
endtask
initial begin
rx_clk = 0;
forever begin
rx_clk =#(RX_BIT_WIDTH_NS/SAMPLES/2*1ns) ~rx_clk;//generate 32x clk for receive
end
end
function automatic logic vote(logic [SAMPLES-1:0] data,int th);
int count_ones = 0;
logic [SAMPLES-1:0] mask;
int i = 0;
do begin
i++;
end while(data[i] == 0 && i < SAMPLES);//jump over contineous zeros
do begin
i++;
end while(data[i] == 1 && i < SAMPLES);//jump over contineous ones
mask = ~(2**i-1);
if(i < SAMPLES && (data & mask != 0)) begin//the remaining should be all zeros
$warning("samples=%b,glitch occured",data);
end
foreach(data[i]) begin
count_ones = data[i] ? (count_ones + 1) : count_ones;//only logic high is weighted
end
if(count_ones >= th) begin//find the majority by threshold
return 1;
end else begin
return 0;
end;
endfunction
initial begin
forever begin
receive();
end
end
task automatic receive();
logic stop_bit;
logic calc_parity;
logic parity_bit;
logic rx_bit;
@(negedge rx);
rx_valid = 0;
parity_error = 0;
stop_error = 0;
sample_one_bit(rx_bit);
if(rx_bit == 0) begin
for(int i = 0;i<DW;i++)begin
sample_one_bit(rx_data[i]);
end
case (CHK_MODE)
"odd","even":begin
sample_one_bit(parity_bit);
end
endcase
do_sample(STOP_BIT_SAMPLES, rx_sample_stop_bits);
stop_bit = vote(rx_sample_stop_bits,STOP_BIT_SAMPLES*0.9);
calc_parity = (^rx_data) ^ parity_bit;
case (CHK_MODE)
"odd":begin
if(calc_parity != 1) begin
$warning("%s parity error,data=%08b,parity=%01b",CHK_MODE,rx_data,parity_bit);
parity_error = 1;
end
end
"even":begin
if(calc_parity != 0) begin
$warning("%s parity error,data=%08b,parity=%01b",CHK_MODE,rx_data,parity_bit);
parity_error = 1;
end
end
endcase
if(stop_bit != 1) begin
$warning("stop error,stop=%f,samples = %b",STOP_BITS,rx_sample_bits);
stop_error = 1;
end
rx_valid = 1;
end else begin
$display("searching start bit...,samples = %b",rx_sample_bits);
end
endtask
task automatic sample_one_bit(output logic rx_bit);
do_sample(SAMPLES, rx_sample_bits);
rx_bit = vote(rx_sample_bits, SAMPLE_TH);
endtask
task automatic do_sample(input int xpoints, output logic [(STOP_BIT_SAMPLES > SAMPLES ? STOP_BIT_SAMPLES : SAMPLES)-1:0] rx_vec);
rx_vec = 0;
#((RX_SAMPLE_WIDTH_NS/2.0)*1ns);
rx_vec[0] = rx;
for(int i = 1;i<xpoints;i++) begin
#(RX_SAMPLE_WIDTH_NS*1ns);
rx_vec[i] = rx;
end
#((RX_SAMPLE_WIDTH_NS/2.0)*1ns);
endtask
endmodule
`endif