Skip to content

Commit b1c07c9

Browse files
committed
Added Verilog versions of UART components
1 parent 0d9f67f commit b1c07c9

File tree

4 files changed

+239
-8
lines changed

4 files changed

+239
-8
lines changed

uart_rx.sv

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,19 @@
1-
//--------------------------------------------------------------------------------
1+
//------------------------------------------------------------------------------
22
// uart_rx.sv
3+
// published as part of https://github.com/pConst/basic_verilog
34
// Konstantin Pavlov, pavlovconst@gmail.com
4-
//--------------------------------------------------------------------------------
5+
//------------------------------------------------------------------------------
56

6-
// INFO --------------------------------------------------------------------------------
7+
// INFO ------------------------------------------------------------------------
78
// Straightforward yet simple UART receiver implementation
8-
// for FPGA written in Verilog
9-
9+
// for FPGA written in SystemVerilog
10+
//
1011
// Expects at least one stop bit
1112
// Features continuous data aquisition at BAUD levels up to CLK_HZ / 2
1213
// Features early asynchronous 'busy' reset
13-
14+
//
15+
// see also "uart_rx.v" for equivalent Verilog version
16+
//
1417

1518
/* --- INSTANTIATION TEMPLATE BEGIN ---
1619
@@ -62,7 +65,7 @@ delay #(
6265
logic start_bit_strobe;
6366
edge_detect rxd_fall_detector (
6467
.clk( clk ),
65-
.nrst( nrst ),
68+
.anrst( nrst ),
6669
.in( rxd_s ),
6770
.falling( start_bit_strobe )
6871
);
@@ -88,7 +91,7 @@ always_ff @ (posedge clk) begin
8891
// wait for 1,5-bit period till next sample
8992
rx_sample_cntr[15:0] <= (BAUD_DIVISOR_2 * 3 - 1'b1);
9093
rx_busy <= 1'b1;
91-
{rx_data[7:0],rx_data_9th_bit} <= 9'b100000000;
94+
{rx_data[7:0],rx_data_9th_bit} <= 9'b10000000_0;
9295

9396
end
9497
end else begin

uart_rx.v

Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
//------------------------------------------------------------------------------
2+
// uart_rx.v
3+
// published as part of https://github.com/pConst/basic_verilog
4+
// Konstantin Pavlov, pavlovconst@gmail.com
5+
//------------------------------------------------------------------------------
6+
7+
// INFO ------------------------------------------------------------------------
8+
// Straightforward yet simple UART receiver implementation
9+
// for FPGA written in Verilog
10+
//
11+
// Expects at least one stop bit
12+
// Features continuous data aquisition at BAUD levels up to CLK_HZ / 2
13+
// Features early asynchronous 'busy' reset
14+
//
15+
// see also "uart_rx.sv" for equivalent SystemVerilog version
16+
//
17+
18+
19+
/* --- INSTANTIATION TEMPLATE BEGIN ---
20+
21+
uart_rx #(
22+
.CLK_HZ( 200_000_000 ), // in Hertz
23+
.BAUD( 9600 ) // max. BAUD is CLK_HZ / 2
24+
)(
25+
.clk( ),
26+
.nrst( ),
27+
28+
.rx_data( ),
29+
.rx_done( ),
30+
.rxd( )
31+
);
32+
33+
--- INSTANTIATION TEMPLATE END ---*/
34+
35+
36+
module uart_rx #( parameter
37+
CLK_HZ = 200_000_000,
38+
BAUD = 9600,
39+
bit [15:0] BAUD_DIVISOR_2 = CLK_HZ / BAUD / 2
40+
)(
41+
input clk,
42+
input nrst,
43+
44+
output reg [7:0] rx_data = 0,
45+
output reg rx_busy = 1'b0,
46+
output rx_done, // read strobe
47+
output rx_err,
48+
input rxd
49+
);
50+
51+
52+
// synchronizing external rxd pin to avoid metastability
53+
wire rxd_s;
54+
delay #(
55+
.LENGTH( 2 ),
56+
.WIDTH( 1 )
57+
) rxd_synch (
58+
.clk( clk ),
59+
.nrst( nrst ),
60+
.ena( 1'b1 ),
61+
.in( rxd ),
62+
.out( rxd_s )
63+
);
64+
65+
66+
wire start_bit_strobe;
67+
edge_detect rxd_fall_detector (
68+
.clk( clk ),
69+
.anrst( nrst ),
70+
.in( rxd_s ),
71+
.falling( start_bit_strobe )
72+
);
73+
74+
75+
reg [15:0] rx_sample_cntr = (BAUD_DIVISOR_2 - 1'b1);
76+
77+
wire rx_do_sample;
78+
assign rx_do_sample = (rx_sample_cntr[15:0] == 1'b0);
79+
80+
81+
// {rx_data[7:0],rx_data_9th_bit} is actually a shift register
82+
reg rx_data_9th_bit = 1'b0;
83+
always @ (posedge clk) begin
84+
if( ~nrst ) begin
85+
rx_busy <= 1'b0;
86+
rx_sample_cntr <= (BAUD_DIVISOR_2 - 1'b1);
87+
{rx_data[7:0],rx_data_9th_bit} <= 0;
88+
end else begin
89+
if( ~rx_busy ) begin
90+
if( start_bit_strobe ) begin
91+
92+
// wait for 1,5-bit period till next sample
93+
rx_sample_cntr[15:0] <= (BAUD_DIVISOR_2 * 3 - 1'b1);
94+
rx_busy <= 1'b1;
95+
{rx_data[7:0],rx_data_9th_bit} <= 9'b10000000_0;
96+
97+
end
98+
end else begin
99+
100+
if( rx_sample_cntr[15:0] == 0 ) begin
101+
// wait for 1-bit-period till next sample
102+
rx_sample_cntr[15:0] <= (BAUD_DIVISOR_2 * 2 - 1'b1);
103+
end else begin
104+
// counting and sampling only when 'busy'
105+
rx_sample_cntr[15:0] <= rx_sample_cntr[15:0] - 1'b1;
106+
end
107+
108+
if( rx_do_sample ) begin
109+
if( rx_data_9th_bit == 1'b1 ) begin
110+
// early asynchronous 'busy' reset
111+
rx_busy <= 1'b0;
112+
end else begin
113+
{rx_data[7:0],rx_data_9th_bit} <= {rxd_s, rx_data[7:0]};
114+
end
115+
end
116+
117+
end // ~rx_busy
118+
end // ~nrst
119+
end
120+
121+
always @* begin
122+
// rx_done and rx_busy fall simultaneously
123+
rx_done <= rx_data_9th_bit && rx_do_sample && rxd_s;
124+
rx_err <= rx_data_9th_bit && rx_do_sample && ~rxd_s;
125+
end
126+
127+
endmodule
128+

uart_tx.sv

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@
1212
// Features early asynchronous 'busy' set and reset to gain time to prepare new data
1313
// If multiple UartTX instances should be inferred - make tx_sample_cntr logic
1414
// that is common for all TX instances for effective chip area usage
15+
//
16+
// see also "uart_tx.v" for equivalent Verilog version
17+
//
1518

1619

1720
/* --- INSTANTIATION TEMPLATE BEGIN ---

uart_tx.v

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
//------------------------------------------------------------------------------
2+
// uart_tx.v
3+
// published as part of https://github.com/pConst/basic_verilog
4+
// Konstantin Pavlov, pavlovconst@gmail.com
5+
//------------------------------------------------------------------------------
6+
7+
// INFO ------------------------------------------------------------------------
8+
// Straightforward yet simple UART transmitter implementation
9+
// for FPGA written in Verilog
10+
//
11+
// One stop bit setting is hardcoded
12+
// Features continuous data output at BAUD levels up to CLK_HZ / 2
13+
// Features early asynchronous 'busy' set and reset to gain time to prepare new data
14+
// If multiple UartTX instances should be inferred - make tx_sample_cntr logic
15+
// that is common for all TX instances for effective chip area usage
16+
//
17+
// see also "uart_tx.sv" for equivalent SystemVerilog version
18+
//
19+
20+
21+
/* --- INSTANTIATION TEMPLATE BEGIN ---
22+
23+
uart_tx #(
24+
.CLK_HZ( 200_000_000 ), // in Hertz
25+
.BAUD( 9600 ) // max. BAUD is CLK_HZ / 2
26+
) tx1 (
27+
.clk( ),
28+
.nrst( 1'b1 ),
29+
//.tx_do_sample( ),
30+
.tx_data( ),
31+
.tx_start( ),
32+
.tx_busy( ),
33+
.txd( )
34+
);
35+
36+
--- INSTANTIATION TEMPLATE END ---*/
37+
38+
39+
module uart_tx #( parameter
40+
CLK_HZ = 200_000_000,
41+
BAUD = 9600,
42+
bit [15:0] BAUD_DIVISOR = CLK_HZ / BAUD
43+
)(
44+
input clk,
45+
input nrst,
46+
//input tx_do_sample,
47+
48+
input [7:0] tx_data,
49+
input tx_start, // write strobe
50+
output reg tx_busy = 1'b0,
51+
output reg txd = 1'b1
52+
);
53+
54+
reg [9:0] tx_shifter = 0;
55+
reg [15:0] tx_sample_cntr = 0;
56+
always @ (posedge clk) begin
57+
if( (~nrst) || (tx_sample_cntr[15:0] == 0) ) begin
58+
tx_sample_cntr[15:0] <= (BAUD_DIVISOR-1'b1);
59+
end else begin
60+
tx_sample_cntr[15:0] <= tx_sample_cntr[15:0] - 1'b1;
61+
end
62+
end
63+
64+
wire tx_do_sample;
65+
assign tx_do_sample = (tx_sample_cntr[15:0] == 0);
66+
67+
68+
always @ (posedge clk) begin
69+
if( ~nrst ) begin
70+
tx_busy <= 1'b0;
71+
tx_shifter[9:0] <= 0;
72+
txd <= 1'b1;
73+
end else begin
74+
if( ~tx_busy ) begin
75+
// asynchronous data load and 'busy' set
76+
if( tx_start ) begin
77+
tx_shifter[9:0] <= { 1'b1,tx_data[7:0],1'b0 };
78+
tx_busy <= 1'b1;
79+
end
80+
end else begin
81+
82+
if( tx_do_sample ) begin // next bit
83+
// txd MUST change only on tx_do_sample although data may be loaded earlier
84+
{ tx_shifter[9:0],txd } <= { tx_shifter[9:0],txd } >> 1;
85+
// early asynchronous 'busy' reset
86+
if( ~|tx_shifter[9:1] ) begin
87+
// txd still holds data, but shifter is ready to get new info
88+
tx_busy <= 1'b0;
89+
end
90+
end // tx_do_sample
91+
92+
end // ~tx_busy
93+
end // ~nrst
94+
end
95+
96+
endmodule
97+

0 commit comments

Comments
 (0)