打三排降低亚稳态概率并下降沿检测;保证在波特率的循环周期正中央采样;
module uart_tx#(
parameter CLK_FRE = 50,
parameter BAUD_RATE = 115200
)
(
clk,
rst_n,
tx_data,
tx_vld,
tx_pin,
tx_rdy
);
//==================modport
input clk;
input rst_n;
input [7 : 0] tx_data;
input tx_vld;
output tx_pin;
output tx_rdy;
//===================parameter
parameter CYCLE = CLK_FRE * 1000000 / BAUD_RATE;
parameter BITS = 11;
//===================defination
reg tx_rdy;
reg [10 : 0] data_r;
reg tx_pin;
reg [15 : 0] cnt_cycle;
wire add_cnt_cycle;
wire end_cnt_cycle;
reg [15 : 0] cnt_bit;
wire add_cnt_bit;
wire end_cnt_bit;
//===================defination
always@(posedge clk or negedge rst_n)begin
if(!rst_n) tx_rdy <= 1'b1;
else if(tx_vld && tx_rdy) tx_rdy <= 1'b0;
else if(end_cnt_bit) tx_rdy <= 1'b1;
end
always@(posedge clk or negedge rst_n)begin
if(!rst_n) data_r <= 'd0;
else if(tx_vld) data_r <= {1'b0, tx_data, 2'b0};
else if(end_cnt_bit) data_r <= 'd0;
end
always@(posedge clk or negedge rst_n)begin
if(!rst_n) tx_pin <= 1'b1;
else if(~tx_rdy) tx_pin <= data_r[10 - cnt_bit];
else tx_pin <= 1'b1;
end
assign add_cnt_cycle = ~tx_rdy;
assign end_cnt_cycle = add_cnt_cycle && (cnt_cycle == CYCLE - 1);
always@(posedge clk or negedge rst_n)begin
if(!rst_n) cnt_cycle <= 'd0;
else if(end_cnt_cycle) cnt_cycle <= 'd0;
else if(add_cnt_cycle) cnt_cycle <= cnt_cycle + 1'b1;
end
assign add_cnt_bit = end_cnt_cycle;
assign end_cnt_bit = add_cnt_bit && (cnt_bit == BITS - 1);
always@(posedge clk or negedge rst_n)begin
if(!rst_n) cnt_bit <= 'd0;
else if(end_cnt_bit) cnt_bit <= 'd0;
else if(add_cnt_bit) cnt_bit <= cnt_bit + 1'b1;
end
endmodule
module uart_rx#(
parameter CLK_FRE = 50,
parameter BAUD_RATE = 115200
)
(
clk,
rst_n,
rx_pin,
rx_rdy,
rx_data,
rx_vld
);
//==================modport
input clk;
input rst_n;
input rx_pin;
input rx_rdy;
output [7 : 0] rx_data;
output rx_vld;
//===================parameter
parameter CYCLE = CLK_FRE * 1000000 / BAUD_RATE;
parameter BITS = 11;
//===================defination
reg rx_pin_r, rx_pin_rr, rx_pin_rrr;
wire rx_pin_neg;
reg trans;
reg [7 : 0] rx_data;
reg rx_vld;
reg [15 : 0] cnt_cycle;
wire add_cnt_cycle;
wire end_cnt_cycle;
reg [15 : 0] cnt_bit;
wire add_cnt_bit;
wire end_cnt_bit;
//===================defination
always@(posedge clk or negedge rst_n)begin
if(!rst_n) {rx_pin_rrr, rx_pin_rr, rx_pin_r} <= 'd0;
else {rx_pin_rrr, rx_pin_rr, rx_pin_r} <= {rx_pin_rr, rx_pin_r, rx_pin};
end
assign rx_pin_neg = rx_pin_rrr && ~rx_pin_rr;
always@(posedge clk or negedge rst_n)begin
if(!rst_n) trans <= 1'b0;
else if(rx_pin_neg) trans <= 1'b1;
else if(end_cnt_bit) trans <= 1'b0;
end
assign add_cnt_cycle = trans;
assign end_cnt_cycle = add_cnt_cycle && (cnt_cycle == CYCLE - 1);
always@(posedge clk or negedge rst_n)begin
if(!rst_n) cnt_cycle <= 'd0;
else if(end_cnt_cycle) cnt_cycle <= 'd0;
else if(add_cnt_cycle) cnt_cycle <= cnt_cycle + 1'b1;
end
assign add_cnt_bit = end_cnt_cycle;
assign end_cnt_bit = add_cnt_bit && (cnt_bit == BITS - 1);
always@(posedge clk or negedge rst_n)begin
if(!rst_n) cnt_bit <= 'd0;
else if(end_cnt_bit) cnt_bit <= 'd0;
else if(add_cnt_bit) cnt_bit <= cnt_bit + 1'b1;
end
always@(posedge clk or negedge rst_n)begin
if(!rst_n) rx_data <= 'd0;
else if(cnt_bit > 1 && cnt_bit < 9) begin
if(add_cnt_cycle && cnt_cycle == CYCLE / 2)
rx_data <= {rx_data[6 : 0], rx_pin};
end
else rx_data <= 'd0;
end
always@(posedge clk or negedge rst_n)begin
if(!rst_n) rx_vld <= 1'b0;
else if(cnt_bit == 8 && add_cnt_cycle & cnt_cycle == CYCLE / 2) rx_vld <= 1'b1;
else rx_vld <= 1'b0;
end
endmodule
module top(
clk,
rst_n,
tx_data,
tx_vld,
tx_rdy
);
//================modport
input clk;
input rst_n;
input [7 : 0] tx_data;
input tx_vld;
output tx_rdy;
//================parameter
parameter BAUD_RATE = 115200;
parameter CLK_FRE = 50;
//================defination
wire tx_pin;
wire [7 : 0] rx_data;
wire rx_vld;
wire rx_rdy;
//================output
assign rx_rdy = 1;
//================instance
uart_tx#(
.CLK_FRE (CLK_FRE),
.BAUD_RATE (BAUD_RATE)
)
u_tx
(
.clk (clk),
.rst_n (rst_n),
.tx_data (tx_data),
.tx_vld (tx_vld),
.tx_pin (tx_pin),
.tx_rdy (tx_rdy)
);
uart_rx#(
.CLK_FRE (CLK_FRE),
.BAUD_RATE (BAUD_RATE)
)
u_rx
(
.clk (clk),
.rst_n (rst_n),
.rx_data (rx_data),
.rx_vld (rx_vld),
.rx_pin (tx_pin),
.rx_rdy (rx_rdy)
);
endmodule
module tb_top();
//===================parameter
parameter PERIOD = 20 / 2;
//===================defination
reg clk, rst_n;
reg [7 : 0] tx_data;
reg tx_vld;
wire tx_rdy;
//===================output
initial begin
clk = 0;
forever
#PERIOD clk = ~clk;
end
initial begin
rst_n = 0;
#20
rst_n = 1;
end
initial begin
wait(rst_n);
wait(tx_rdy);
tx(8'd5);
wait(tx_rdy);
tx(8'd9);
wait(tx_rdy);
#1000 $finish;
end
task tx(input [7 : 0] data);
begin
@(posedge clk);
#1;
tx_data = data;
tx_vld = 1'b1;
@(posedge clk);
#1;
tx_vld = 1'b0;
end
endtask
top u_top(
.clk (clk),
.rst_n (rst_n),
.tx_data(tx_data),
.tx_vld (tx_vld),
.tx_rdy (tx_rdy)
);
`ifdef FSDB
initial begin
$fsdbDumpfile("tb_top.fsdb");
$fsdbDumpvars;
$fsdbDumpMDA();
end
`endif
endmodule