URL
https://opencores.org/ocsvn/wbuart32/wbuart32/trunk
Subversion Repositories wbuart32
Compare Revisions
- This comparison shows the changes necessary to convert path
/wbuart32/trunk/rtl
- from Rev 17 to Rev 18
- ↔ Reverse comparison
Rev 17 → Rev 18
/Makefile
44,6 → 44,7
CXX := g++ |
FBDIR := . |
VDIRFB:= $(FBDIR)/obj_dir |
VERILATOR := verilator |
|
.PHONY: test |
test: $(VDIRFB)/Vtxuart__ALL.a |
73,7 → 74,7
$(VDIRFB)/Vwbuart.h $(VDIRFB)/Vwbuart.cpp $(VDIRFB)/Vwbuart.mk: wbuart.v ufifo.v txuart.v rxuart.v |
|
$(VDIRFB)/V%.cpp $(VDIRFB)/V%.h $(VDIRFB)/V%.mk: $(FBDIR)/%.v |
verilator -cc $*.v |
$(VERILATOR) -Wall -cc $*.v |
|
$(VDIRFB)/V%__ALL.a: $(VDIRFB)/V%.mk |
cd $(VDIRFB); make -f V$*.mk |
/rxuart.v
122,7 → 122,9
parameter [30:0] INITIAL_SETUP = 31'd868; |
// 8 data bits, no parity, (at least 1) stop bit |
input wire i_clk, i_reset; |
/* verilator lint_off UNUSED */ |
input wire [30:0] i_setup; |
/* verilator lint_on UNUSED */ |
input wire i_uart_rx; |
output reg o_wr; |
output reg [7:0] o_data; |
/rxuartlite.v
66,7 → 66,7
output reg [7:0] o_data; |
|
|
wire [23:0] clocks_per_baud, half_baud; |
wire [23:0] half_baud; |
reg [3:0] state; |
|
assign half_baud = { 1'b0, CLOCKS_PER_BAUD[23:1] } - 24'h1; |
152,8 → 152,6
// available. |
// |
initial o_data = 8'h00; |
reg pre_wr; |
initial pre_wr = 1'b0; |
always @(posedge i_clk) |
if ((zero_baud_counter)&&(state == `RXUL_STOP)) |
begin |
166,7 → 164,7
// |
// This is used as a "clock divider" if you will, but the clock needs |
// to be reset before any byte can be decoded. In all other respects, |
// we set ourselves up for clocks_per_baud counts between baud |
// we set ourselves up for CLOCKS_PER_BAUD counts between baud |
// intervals. |
always @(posedge i_clk) |
if ((zero_baud_counter)|||(state == `RXUL_IDLE)) |
/txuartlite.v
14,7 → 14,7
// high for one cycle, and your data will be off. Wait until the 'o_busy' |
// line is low before strobing the i_wr line again--this implementation |
// has NO BUFFER, so strobing i_wr while the core is busy will just |
// get ignored. The output will be placed on the o_txuart output line. |
// get ignored. The output will be placed on the o_txuart output line. |
// |
// (I often set both data and strobe on the same clock, and then just leave |
// them set until the busy line is low. Then I move on to the next piece |
64,7 → 64,7
// |
// |
module txuartlite(i_clk, i_wr, i_data, o_uart_tx, o_busy); |
parameter [23:0] CLOCKS_PER_BAUD = 24'd868; |
parameter [23:0] CLOCKS_PER_BAUD = 24'd8; // 24'd868; |
input wire i_clk; |
input wire i_wr; |
input wire [7:0] i_data; |
82,7 → 82,6
|
initial r_busy = 1'b1; |
initial state = `TXUL_IDLE; |
initial lcl_data= 8'h0; |
always @(posedge i_clk) |
begin |
if (!zero_baud_counter) |
103,7 → 102,7
state <= state + 1; |
else |
state <= `TXUL_IDLE; |
end |
end |
end |
|
// o_busy |
204,5 → 203,126
else |
baud_counter <= CLOCKS_PER_BAUD - 24'h01; |
end |
|
// |
// |
// FORMAL METHODS |
// |
// |
// |
`ifdef FORMAL |
|
`ifdef TXUARTLITE |
`define ASSUME assume |
`else |
`define ASSUME assert |
`endif |
|
// Setup |
|
reg f_past_valid, f_last_clk; |
|
always @($global_clock) |
begin |
restrict(i_clk == !f_last_clk); |
f_last_clk <= i_clk; |
if (!$rose(i_clk)) |
begin |
`ASSUME($stable(i_wr)); |
`ASSUME($stable(i_data)); |
end |
end |
|
initial f_past_valid = 1'b0; |
always @(posedge i_clk) |
f_past_valid <= 1'b1; |
|
always @(posedge i_clk) |
if ((f_past_valid)&&($past(i_wr))&&($past(o_busy))) |
begin |
`ASSUME(i_wr == $past(i_wr)); |
`ASSUME(i_data == $past(i_data)); |
end |
|
// Check the baud counter |
always @(posedge i_clk) |
if (zero_baud_counter) |
assert(baud_counter == 0); |
|
always @(posedge i_clk) |
if ((f_past_valid)&&($past(baud_counter != 0))&&($past(state != `TXUL_IDLE))) |
assert(baud_counter == $past(baud_counter - 1'b1)); |
|
always @(posedge i_clk) |
if ((f_past_valid)&&(!$past(zero_baud_counter))&&($past(state != `TXUL_IDLE))) |
assert($stable(o_uart_tx)); |
|
reg [23:0] f_baud_count; |
initial f_baud_count = 1'b0; |
always @(posedge i_clk) |
if (zero_baud_counter) |
f_baud_count <= 0; |
else |
f_baud_count <= f_baud_count + 1'b1; |
|
always @(posedge i_clk) |
assert(f_baud_count < CLOCKS_PER_BAUD); |
|
always @(posedge i_clk) |
if (baud_counter != 0) |
assert(o_busy); |
|
reg [9:0] f_txbits; |
initial f_txbits = 0; |
always @(posedge i_clk) |
if (zero_baud_counter) |
f_txbits <= { o_uart_tx, f_txbits[9:1] }; |
|
reg [3:0] f_bitcount; |
initial f_bitcount = 0; |
always @(posedge i_clk) |
//if (baud_counter == CLOCKS_PER_BAUD - 24'h01) |
//f_bitcount <= f_bitcount + 1'b1; |
if ((!f_past_valid)||(!$past(f_past_valid))) |
f_bitcount <= 0; |
else if ((state == `TXUL_IDLE)&&(zero_baud_counter)) |
f_bitcount <= 0; |
else if (zero_baud_counter) |
f_bitcount <= f_bitcount + 1'b1; |
|
always @(posedge i_clk) |
assert(f_bitcount <= 4'ha); |
|
reg [7:0] f_request_tx_data; |
always @(posedge i_clk) |
if ((i_wr)&&(!o_busy)) |
f_request_tx_data <= i_data; |
|
wire [3:0] subcount; |
assign subcount = 10-f_bitcount; |
always @(posedge i_clk) |
if (f_bitcount > 0) |
assert(!f_txbits[subcount]); |
/* |
|
always @(posedge i_clk) |
if ((f_bitcount > 2)&&(f_bitcount <= 10)) |
assert(f_txbits[f_bitcount-2:0] |
== f_request_tx_data[7:(9-f_bitcount)]); |
*/ |
|
always @(posedge i_clk) |
if (f_bitcount == 4'ha) |
begin |
assert(f_txbits[8:1] == f_request_tx_data); |
assert( f_txbits[9]); |
end |
|
always @(posedge i_clk) |
assert((state <= `TXUL_STOP + 1'b1)||(state == `TXUL_IDLE)); |
// |
// |
|
`endif // FORMAL |
endmodule |
|
/ufifo.v
4,7 → 4,14
// |
// Project: wbuart32, a full featured UART with simulator |
// |
// Purpose: |
// Purpose: A synchronous data FIFO, designed for supporting the Wishbone |
// UART. Particular features include the ability to read and |
// write on the same clock, while maintaining the correct output FIFO |
// parameters. Two versions of the FIFO exist within this file, separated |
// by the RXFIFO parameter's value. One, where RXFIFO = 1, produces status |
// values appropriate for reading and checking a read FIFO from logic, |
// whereas the RXFIFO = 0 applies to writing to the FIFO from bus logic |
// and reading it automatically any time the transmit UART is idle. |
// |
// Creator: Dan Gisselquist, Ph.D. |
// Gisselquist Technology, LLC |
111,7 → 118,7
if (i_rst) |
will_underflow <= 1'b1; |
else if (i_wr) |
will_underflow <= (will_underflow)&&(i_rd); |
will_underflow <= 1'b0; |
else if (i_rd) |
will_underflow <= (will_underflow)||(w_last_plus_one == r_first); |
else |
125,6 → 132,7
// reg r_unfl; |
// initial r_unfl = 1'b0; |
initial r_last = 0; |
initial r_next = { {(LGFLEN-1){1'b0}}, 1'b1 }; |
always @(posedge i_clk) |
if (i_rst) |
begin |
133,7 → 141,7
// r_unfl <= 1'b0; |
end else if (i_rd) |
begin |
if ((i_wr)||(!will_underflow)) // (r_first != r_last) |
if (!will_underflow) // (r_first != r_last) |
begin |
r_last <= r_next; |
r_next <= r_last +{{(LGFLEN-2){1'b0}},2'b10}; |
176,10 → 184,10
r_empty_n <= 1'b0; |
else casez({i_wr, i_rd, will_underflow}) |
3'b00?: r_empty_n <= (r_first != r_last); |
3'b11?: r_empty_n <= (r_first != r_last); |
3'b010: r_empty_n <= (r_first != w_last_plus_one); |
3'b10?: r_empty_n <= 1'b1; |
3'b010: r_empty_n <= (r_first != w_last_plus_one); |
// 3'b001: r_empty_n <= 1'b0; |
3'b110: r_empty_n <= (r_first != r_last); |
3'b111: r_empty_n <= 1'b1; |
default: begin end |
endcase |
|
194,7 → 202,13
// |
// Adjust for these differences here. |
reg [(LGFLEN-1):0] r_fill; |
initial r_fill = 0; |
generate |
if (RXFIFO != 0) |
initial r_fill = 0; |
else |
initial r_fill = -1; |
endgenerate |
|
always @(posedge i_clk) |
if (RXFIFO!=0) begin |
// Calculate the number of elements in our FIFO |
204,9 → 218,10
// another context. |
if (i_rst) |
r_fill <= 0; |
else case({(i_wr)&&(!will_overflow), (i_rd)&&(!will_underflow)}) |
2'b01: r_fill <= r_first - r_next; |
2'b10: r_fill <= r_first - r_last + 1'b1; |
else casez({(i_wr), (!will_overflow), (i_rd)&&(!will_underflow)}) |
3'b0?1: r_fill <= r_first - r_next; |
3'b110: r_fill <= r_first - r_last + 1'b1; |
3'b1?1: r_fill <= r_first - r_last; |
default: r_fill <= r_first - r_last; |
endcase |
end else begin |
215,10 → 230,10
// not the fill, but (SIZE-1)-fill. |
if (i_rst) |
r_fill <= { (LGFLEN){1'b1} }; |
else case({i_wr, i_rd}) |
2'b01: r_fill <= r_last - r_first; |
2'b10: r_fill <= r_last - w_first_plus_two; |
default: r_fill <= r_last - w_first_plus_one; |
else casez({i_wr, (!will_overflow), (i_rd)&&(!will_underflow)}) |
3'b0?1: r_fill <= r_fill + 1'b1; |
3'b110: r_fill <= r_fill - 1'b1; |
default: r_fill <= r_fill; |
endcase |
end |
|
228,6 → 243,7
wire [3:0] lglen; |
assign lglen = LGFLEN; |
|
wire w_half_full; |
wire [9:0] w_fill; |
assign w_fill[(LGFLEN-1):0] = r_fill; |
generate if (LGFLEN < 10) |
234,7 → 250,6
assign w_fill[9:(LGFLEN)] = 0; |
endgenerate |
|
wire w_half_full; |
assign w_half_full = r_fill[(LGFLEN-1)]; |
|
assign o_status = { |
257,5 → 272,103
}; |
|
assign o_empty_n = r_empty_n; |
|
|
// |
// |
// |
// FORMAL METHODS |
// |
// |
// |
`ifdef FORMAL |
|
`ifdef UFIFO |
`define ASSUME assume |
`else |
`define ASSUME assert |
`endif |
|
// |
// Assumptions about our input(s) |
// |
// |
reg f_past_valid, f_last_clk; |
|
initial restrict(i_rst); |
|
always @($global_clock) |
begin |
restrict(i_clk == !f_last_clk); |
f_last_clk <= i_clk; |
if (!$rose(i_clk)) |
begin |
`ASSUME($stable(i_rst)); |
`ASSUME($stable(i_wr)); |
`ASSUME($stable(i_data)); |
`ASSUME($stable(i_rd)); |
end |
end |
|
// |
// Underflows are a very real possibility, should the user wish to |
// read from this FIFO while it is empty. Our parent module will need |
// to deal with this. |
// |
// always @(posedge i_clk) |
// `ASSUME((!will_underflow)||(!i_rd)||(i_rst)); |
// |
// Assertions about our outputs |
// |
// |
|
initial f_past_valid = 1'b0; |
always @(posedge i_clk) |
f_past_valid <= 1'b1; |
|
wire [(LGFLEN-1):0] f_fill, f_next, f_empty; |
assign f_fill = r_first - r_last; |
assign f_empty = {(LGFLEN){1'b1}} -f_fill; |
assign f_next = r_last + 1'b1; |
always @(posedge i_clk) |
begin |
if (RXFIFO) |
assert(f_fill == r_fill); |
else |
assert(f_empty== r_fill); |
if (f_fill == 0) |
begin |
assert(will_underflow); |
assert(!o_empty_n); |
end else begin |
assert(!will_underflow); |
assert(o_empty_n); |
end |
|
if (f_fill == {(LGFLEN){1'b1}}) |
assert(will_overflow); |
else |
assert(!will_overflow); |
|
assert(r_next == f_next); |
end |
|
always @(posedge i_clk) |
if (f_past_valid) |
begin |
if ($past(i_rst)) |
assert(!o_err); |
else begin |
// No underflow detection in this core |
// |
// if (($past(i_rd))&&($past(r_fill == 0))) |
// assert(o_err); |
// |
// We do, though, have overflow detection |
if (($past(i_wr))&&(!$past(i_rd)) |
&&($past(will_overflow))) |
assert(o_err); |
end |
end |
|
`endif |
endmodule |
/wbuart.v
64,9 → 64,10
// |
input wire i_clk, i_rst; |
// Wishbone inputs |
input wire i_wb_cyc, i_wb_stb, i_wb_we; |
input wire i_wb_cyc; // We ignore CYC for efficiency |
input wire i_wb_stb, i_wb_we; |
input wire [1:0] i_wb_addr; |
input wire [31:0] i_wb_data; |
input wire [31:0] i_wb_data; // and only use 30 lines here |
output reg o_wb_ack; |
output wire o_wb_stall; |
output reg [31:0] o_wb_data; |
95,7 → 96,8
// baud rate are all captured within this uart_setup register. |
// |
reg [30:0] uart_setup; |
initial uart_setup = INITIAL_SETUP; |
initial uart_setup = INITIAL_SETUP |
| ((HARDWARE_FLOW_CONTROL_PRESENT==1'b0)? 31'h40000000 : 0); |
always @(posedge i_clk) |
// Under wishbone rules, a write takes place any time i_wb_stb |
// is high. If that's the case, and if the write was to the |
180,11 → 182,14
// Why N-1? Because at N-1 we are totally full, but already so full |
// that if the transmit end starts sending we won't have a location to |
// receive it. (Transmit might've started on the next character by the |
// time we set this--need to set it to one character before necessary |
// time we set this--thus we need to set it to one, one character before |
// necessary). |
wire [(LCLLGFLEN-1):0] check_cutoff; |
assign check_cutoff = -3; |
always @(posedge i_clk) |
o_rts_n = ((HARDWARE_FLOW_CONTROL_PRESENT) |
o_rts_n <= ((HARDWARE_FLOW_CONTROL_PRESENT) |
&&(!uart_setup[30]) |
&&(rxf_status[(LCLLGFLEN+1):4]=={(LCLLGFLEN-2){1'b1}})); |
&&(rxf_status[(LCLLGFLEN+1):2] > check_cutoff)); |
|
// If the bus requests that we read from the receive FIFO, we need to |
// tell this to the receive FIFO. Note that because we are using a |
418,4 → 423,10
// set this value to zero. |
assign o_wb_stall = 1'b0; |
|
// Make verilator happy |
// verilator lint_off UNUSED |
wire [33:0] unused; |
assign unused = { i_rst, i_wb_cyc, i_wb_data }; |
// verilator lint_on UNUSED |
|
endmodule |