From 38f7ee86faaa849c32217437f1f5c92a497b8981 Mon Sep 17 00:00:00 2001 From: Fischer Moseley <42497969+fischermoseley@users.noreply.github.com> Date: Sun, 9 Jul 2023 18:19:49 -0700 Subject: [PATCH] add uart_rx and refactor uart_tx and bridge_tx --- .gitignore | 5 +- src/manta/uart_iface/bridge_rx.v | 50 ++++++------ src/manta/uart_iface/bridge_tx.v | 59 +++++++------- src/manta/uart_iface/uart_rx.v | 70 +++++++++++++++++ .../uart_iface/uart_rx_bridge_rx_inst_templ.v | 19 ++--- src/manta/uart_iface/uart_tx.v | 67 +++++++--------- .../uart_iface/uart_tx_bridge_tx_inst_templ.v | 18 ++--- test/functional_sim/uart_tb.sv | 72 ++++++++++------- test/virtual_uart/manta.yaml | 11 +++ test/virtual_uart/tb_manta.cpp | 78 +++++++++++++++++++ 10 files changed, 306 insertions(+), 143 deletions(-) create mode 100644 src/manta/uart_iface/uart_rx.v create mode 100644 test/virtual_uart/manta.yaml create mode 100644 test/virtual_uart/tb_manta.cpp diff --git a/.gitignore b/.gitignore index c9f83aa..a42d63d 100644 --- a/.gitignore +++ b/.gitignore @@ -23,4 +23,7 @@ manta.v # Python Packaging output products dist/ *.egg-info -__pycache__/ \ No newline at end of file +__pycache__/ + +# Verilator outputs +obj_dir/ \ No newline at end of file diff --git a/src/manta/uart_iface/bridge_rx.v b/src/manta/uart_iface/bridge_rx.v index 4440750..32082cc 100644 --- a/src/manta/uart_iface/bridge_rx.v +++ b/src/manta/uart_iface/bridge_rx.v @@ -4,11 +4,11 @@ module bridge_rx ( input wire clk, - input wire[7:0] rx_data, - input wire rx_valid, + input wire [7:0] data_i, + input wire valid_i, - output reg[15:0] addr_o, - output reg[15:0] wdata_o, + output reg [15:0] addr_o, + output reg [15:0] wdata_o, output reg rw_o, output reg valid_o); @@ -40,32 +40,32 @@ module bridge_rx ( state = ACQUIRE; end - reg [3:0] rx_data_decoded; - reg rx_data_is_0_thru_9; - reg rx_data_is_A_thru_F; + reg [3:0] data_i_decoded; + reg data_i_is_0_thru_9; + reg data_i_is_A_thru_F; always @(*) begin - rx_data_is_0_thru_9 = (rx_data >= 8'h30) & (rx_data <= 8'h39); - rx_data_is_A_thru_F = (rx_data >= 8'h41) & (rx_data <= 8'h46); + data_i_is_0_thru_9 = (data_i >= 8'h30) & (data_i <= 8'h39); + data_i_is_A_thru_F = (data_i >= 8'h41) & (data_i <= 8'h46); - if (rx_data_is_0_thru_9) rx_data_decoded = rx_data - 8'h30; - else if (rx_data_is_A_thru_F) rx_data_decoded = rx_data - 8'h41 + 'd10; - else rx_data_decoded = 0; + if (data_i_is_0_thru_9) data_i_decoded = data_i - 8'h30; + else if (data_i_is_A_thru_F) data_i_decoded = data_i - 8'h41 + 'd10; + else data_i_decoded = 0; end always @(posedge clk) begin if (state == ACQUIRE) begin - if(rx_valid) begin + if(valid_i) begin if (bytes_received == 0) begin - if(rx_data == PREAMBLE) bytes_received <= 1; + if(data_i == PREAMBLE) bytes_received <= 1; end else if( (bytes_received >= 1) & (bytes_received <= 4) ) begin // only advance if byte is valid hex digit - if(rx_data_is_0_thru_9 | rx_data_is_A_thru_F) begin - addr_o <= (addr_o << 4) | rx_data_decoded; + if(data_i_is_0_thru_9 | data_i_is_A_thru_F) begin + addr_o <= (addr_o << 4) | data_i_decoded; bytes_received <= bytes_received + 1; end @@ -73,16 +73,16 @@ module bridge_rx ( end else if( bytes_received == 5) begin - if( (rx_data == CR) | (rx_data == LF)) begin + if( (data_i == CR) | (data_i == LF)) begin valid_o <= 1; - rw_o = 0; + rw_o <= 0; bytes_received <= 0; state <= TRANSMIT; end - else if (rx_data_is_0_thru_9 | rx_data_is_A_thru_F) begin + else if (data_i_is_0_thru_9 | data_i_is_A_thru_F) begin bytes_received <= bytes_received + 1; - wdata_o <= (wdata_o << 4) | rx_data_decoded; + wdata_o <= (wdata_o << 4) | data_i_decoded; end else state <= ERROR; @@ -90,8 +90,8 @@ module bridge_rx ( else if ( (bytes_received >= 6) & (bytes_received <= 8) ) begin - if (rx_data_is_0_thru_9 | rx_data_is_A_thru_F) begin - wdata_o <= (wdata_o << 4) | rx_data_decoded; + if (data_i_is_0_thru_9 | data_i_is_A_thru_F) begin + wdata_o <= (wdata_o << 4) | data_i_decoded; bytes_received <= bytes_received + 1; end @@ -100,7 +100,7 @@ module bridge_rx ( else if (bytes_received == 9) begin bytes_received <= 0; - if( (rx_data == CR) | (rx_data == LF)) begin + if( (data_i == CR) | (data_i == LF)) begin valid_o <= 1; rw_o <= 1; state <= TRANSMIT; @@ -118,8 +118,8 @@ module bridge_rx ( state <= ACQUIRE; end - if(rx_valid) begin - if ( (rx_data != CR) & (rx_data != LF)) begin + if(valid_i) begin + if ( (data_i != CR) & (data_i != LF)) begin valid_o <= 0; state <= ERROR; end diff --git a/src/manta/uart_iface/bridge_tx.v b/src/manta/uart_iface/bridge_tx.v index 0f403ce..9baa70c 100644 --- a/src/manta/uart_iface/bridge_tx.v +++ b/src/manta/uart_iface/bridge_tx.v @@ -1,67 +1,66 @@ `default_nettype none `timescale 1ns/1ps +function [7:0] ascii_hex; + // convert a number from 0-15 into the corresponding ascii char + input [3:0] n; + ascii_hex = (n > 10) ? (n + 8'h30) : (n + 8'h41 - 'd10); +endfunction + module bridge_tx ( input wire clk, - input wire [15:0] rdata_i, + input wire [15:0] data_i, input wire rw_i, input wire valid_i, output reg [7:0] data_o, - input wire ready_i, - output reg valid_o); + output reg start_o, + input wire done_i); localparam PREAMBLE = 8'h4D; localparam CR = 8'h0D; localparam LF = 8'h0A; - logic busy; - logic [15:0] buffer; - logic [3:0] byte_counter; + reg busy = 0; + reg [15:0] buffer = 0; + reg [3:0] count = 0; - initial begin - busy = 0; - buffer = 0; - byte_counter = 0; - valid_o = 0; - end + assign start_o = busy; always @(posedge clk) begin + // idle until valid read transaction arrives on bus if (!busy) begin if (valid_i && !rw_i) begin busy <= 1; - buffer <= rdata_i; - byte_counter <= 0; - valid_o <= 1; + buffer <= data_i; end end if (busy) begin + // uart module is done transmitting a byte + if(done_i) begin + count <= count + 1; - if(ready_i) begin - byte_counter <= byte_counter + 1; + // message has been transmitted + if (count > 5) begin + count <= 0; - if (byte_counter > 5) begin - byte_counter <= 0; - - // stop transmitting if we don't have both valid and read - if ( !(valid_i && !rw_i) ) begin - busy <= 0; - valid_o <= 0; - end + // go back to idle or transmit next message + if (valid_i && !rw_i) buffer <= data_i; + else busy <= 0; end end end end always @(*) begin - case (byte_counter) + case (count) 0: data_o = PREAMBLE; - 1: data_o = (buffer[15:12] < 10) ? (buffer[15:12] + 8'h30) : (buffer[15:12] + 8'h41 - 'd10); - 2: data_o = (buffer[11:8] < 10) ? (buffer[11:8] + 8'h30) : (buffer[11:8] + 8'h41 - 'd10); - 3: data_o = (buffer[7:4] < 10) ? (buffer[7:4] + 8'h30) : (buffer[7:4] + 8'h41 - 'd10); - 4: data_o = (buffer[3:0] < 10) ? (buffer[3:0] + 8'h30) : (buffer[3:0] + 8'h41 - 'd10); + 1: data_o = ascii_hex(buffer[15:12]); + 2: data_o = ascii_hex(buffer[11:8]); + 3: data_o = ascii_hex(buffer[7:4]); + 4: data_o = ascii_hex(buffer[3:0]); 5: data_o = CR; 6: data_o = LF; default: data_o = 0; diff --git a/src/manta/uart_iface/uart_rx.v b/src/manta/uart_iface/uart_rx.v new file mode 100644 index 0000000..de3ef34 --- /dev/null +++ b/src/manta/uart_iface/uart_rx.v @@ -0,0 +1,70 @@ +`default_nettype none +`timescale 1ns/1ps + +module uart_rx ( + input wire clk, + + input wire rx, + + output reg [7:0] data_o, + output reg valid_o); + + parameter CLOCKS_PER_BAUD = 0; + + initial data_o = 0; + initial valid_o = 0; + + reg [$clog2(CLOCKS_PER_BAUD)-1:0] baud_counter = 0; + reg [7:0] buffer = 0; + reg [3:0] bit_index = 0; + + reg prev_rx = 1; + reg busy = 0; + + always @(posedge clk) begin + prev_rx <= rx; + valid_o <= 0; + + if (!busy) begin + if (prev_rx && !rx) begin + busy <= 1; + end + end + + else begin + // run baud counter + baud_counter <= (baud_counter < CLOCKS_PER_BAUD-1) ? baud_counter + 1 : 0; + + // sample rx in the middle of a baud period + if (baud_counter == (CLOCKS_PER_BAUD/2) - 2) begin + + // fill buffer until end of byte on the wire + if(bit_index <= 8) begin + buffer <= {rx, buffer[7:1]}; + bit_index = bit_index + 1; + end + + else begin + // reset system state + busy <= 0; + baud_counter <= 0; + bit_index <= 0; + + // output word if stop bit received + if(rx) begin + data_o <= buffer; + valid_o <= 1; + end + end + end + end + + + + + + + end + +endmodule +`default_nettype wire \ No newline at end of file diff --git a/src/manta/uart_iface/uart_rx_bridge_rx_inst_templ.v b/src/manta/uart_iface/uart_rx_bridge_rx_inst_templ.v index fcc2f85..62d1cd6 100644 --- a/src/manta/uart_iface/uart_rx_bridge_rx_inst_templ.v +++ b/src/manta/uart_iface/uart_rx_bridge_rx_inst_templ.v @@ -1,17 +1,18 @@ -rx_uart #(.CLOCKS_PER_BAUD(/* CLOCKS_PER_BAUD */)) urx ( - .i_clk(clk), - .i_uart_rx(rx), - .o_wr(urx_brx_axiv), - .o_data(urx_brx_axid)); +uart_rx #(.CLOCKS_PER_BAUD(/* CLOCKS_PER_BAUD */)) urx ( + .clk(clk), + .rx(rx), -reg [7:0] urx_brx_axid; -reg urx_brx_axiv; + .data_o(urx_brx_data), + .valid_o(urx_brx_valid)); + +reg [7:0] urx_brx_data; +reg urx_brx_valid; bridge_rx brx ( .clk(clk), - .rx_data(urx_brx_axid), - .rx_valid(urx_brx_axiv), + .data_i(urx_brx_data), + .valid_i(urx_brx_valid), .addr_o(), .wdata_o(), diff --git a/src/manta/uart_iface/uart_tx.v b/src/manta/uart_iface/uart_tx.v index 47d7286..ea249a7 100644 --- a/src/manta/uart_iface/uart_tx.v +++ b/src/manta/uart_iface/uart_tx.v @@ -4,65 +4,54 @@ module uart_tx ( input wire clk, - input wire [7:0] data, - input wire valid, - output reg busy, - output reg ready, + input wire [7:0] data_i, + input wire start_i, + output reg done_o, output reg tx); - // this transmitter only works with 8N1 serial, at configurable baudrate - parameter CLOCKS_PER_BAUD = 868; + // this module supports only 8N1 serial at a configurable baudrate + parameter CLOCKS_PER_BAUD = 0; + reg [$clog2(CLOCKS_PER_BAUD)-1:0] baud_counter = 0; - reg [9:0] baud_counter; - reg [8:0] data_buf; - reg [3:0] bit_index; + reg [8:0] buffer = 0; + reg [3:0] bit_index = 0; - initial begin - baud_counter = CLOCKS_PER_BAUD; - data_buf = 0; - bit_index = 0; - busy = 0; - ready = 1; - tx = 1; - end + initial done_o = 1; + initial tx = 1; always @(posedge clk) begin - if (valid && !busy) begin - data_buf <= {1'b1, data}; - bit_index <= 0; - tx <= 0; //wafflestomp that start bit + if (start_i && done_o) begin baud_counter <= CLOCKS_PER_BAUD - 1; - busy <= 1; - ready <= 0; + buffer <= {1'b1, data_i}; + bit_index <= 0; + done_o <= 0; + tx <= 0; end - else if (busy) begin + else if (!done_o) begin baud_counter <= baud_counter - 1; + done_o <= (baud_counter == 1) && (bit_index == 9); - ready <= (baud_counter == 1) && (bit_index == 9); - + // a baud period has elapsed if (baud_counter == 0) begin baud_counter <= CLOCKS_PER_BAUD - 1; + // clock out another bit if there are any left + if (bit_index < 9) begin + tx <= buffer[bit_index]; + bit_index <= bit_index + 1; + end - if (bit_index == 9) begin - if(valid) begin - data_buf <= {1'b1, data}; + // byte has been sent, send out next one or go to idle + else begin + if(start_i) begin + buffer <= {1'b1, data_i}; bit_index <= 0; tx <= 0; end - else begin - busy <= 0; - ready <= 1; - end - // if valid happens here then we should bool - end - - else begin - tx <= data_buf[bit_index]; - bit_index <= bit_index + 1; + else done_o <= 1; end end end diff --git a/src/manta/uart_iface/uart_tx_bridge_tx_inst_templ.v b/src/manta/uart_iface/uart_tx_bridge_tx_inst_templ.v index fe26827..bfe68b6 100644 --- a/src/manta/uart_iface/uart_tx_bridge_tx_inst_templ.v +++ b/src/manta/uart_iface/uart_tx_bridge_tx_inst_templ.v @@ -1,23 +1,23 @@ bridge_tx btx ( .clk(clk), - .rdata_i(), + .data_i(), .rw_i(), .valid_i(), - .ready_i(utx_btx_ready), .data_o(btx_utx_data), - .valid_o(btx_utx_valid)); + .start_o(btx_utx_start), + .done_i(utx_btx_done)); -logic utx_btx_ready; -logic btx_utx_valid; -logic [7:0] btx_utx_data; +reg [7:0] btx_utx_data; +reg btx_utx_start; +reg utx_btx_done; uart_tx #(.CLOCKS_PER_BAUD(/* CLOCKS_PER_BAUD */)) utx ( .clk(clk), - .data(btx_utx_data), - .valid(btx_utx_valid), - .ready(utx_btx_ready), + .data_i(btx_utx_data), + .start_i(btx_utx_start), + .done_o(utx_btx_done), .tx(tx)); \ No newline at end of file diff --git a/test/functional_sim/uart_tb.sv b/test/functional_sim/uart_tb.sv index b96c597..5f6f398 100644 --- a/test/functional_sim/uart_tb.sv +++ b/test/functional_sim/uart_tb.sv @@ -4,38 +4,50 @@ module uart_tb(); logic clk; logic rst; - logic [7:0] tx_data, rx_data; - logic tx_start, rx_ready; - logic tx_busy, rx_busy; - logic txd; + logic [7:0] tx_data; + logic tx_start; - uart_tx #( - .DATA_WIDTH(8), - .CLK_FREQ_HZ(100_000_000), - .BAUDRATE(115200)) - tx ( + // transmitters + logic tx_done_manta; + logic txd_manta; + uart_tx #(.CLOCKS_PER_BAUD(10)) tx_manta ( .clk(clk), - .rst(rst), - .data(tx_data), - .start(tx_start), - .busy(tx_busy), - .txd(txd)); + .data_i(tx_data), + .start_i(tx_start), + .done_o(tx_done_manta), + .tx(txd_manta)); - uart_rx #( - .DATA_WIDTH(8), - .CLK_FREQ_HZ(100_000_000), - .BAUDRATE(115200)) - rx ( + logic tx_busy_zipcpu; + logic tx_done_zipcpu; + logic txd_zipcpu; + assign tx_done_zipcpu = ~tx_busy_zipcpu; + tx_uart #(.CLOCKS_PER_BAUD(10)) tx_zipcpu ( + .i_clk(clk), + + .i_wr(tx_start), + .i_data(tx_data), + .o_uart_tx(txd_zipcpu), + .o_busy(tx_busy_zipcpu)); + + // receivers + logic [7:0] rx_data_manta; + logic rx_valid_manta; + uart_rx #(.CLOCKS_PER_BAUD(10)) rx_manta ( .clk(clk), - .rst(rst), - .rxd(txd), + .rx(txd_manta), + .data_o(rx_data_manta), + .valid_o(rx_valid_manta)); - .data(rx_data), - .ready(rx_ready), - .busy(rx_busy)); + logic [7:0] rx_data_zipcpu; + logic rx_valid_zipcpu; + rx_uart #(.CLOCKS_PER_BAUD(10)) rx_zipcpu ( + .i_clk(clk), + .i_uart_rx(txd_zipcpu), + .o_wr(rx_valid_zipcpu), + .o_data(rx_data_zipcpu)); always begin #5; @@ -46,8 +58,8 @@ module uart_tb(); $dumpfile("uart.vcd"); $dumpvars(0, uart_tb); clk = 0; - rst = 1; - tx_data = 'h0F; + + tx_data = 'hFF; tx_start = 0; #10; rst = 0; @@ -55,14 +67,14 @@ module uart_tb(); tx_start = 1; #10; tx_start = 0; - #150000; + #10000; // send another byte! - tx_data = 'hBE; + tx_data = 'b0100_1101; tx_start = 1; - #10; + #3000; tx_start = 0; - #150000; + #10000; $finish(); end diff --git a/test/virtual_uart/manta.yaml b/test/virtual_uart/manta.yaml new file mode 100644 index 0000000..2af3d8d --- /dev/null +++ b/test/virtual_uart/manta.yaml @@ -0,0 +1,11 @@ +--- +cores: + mem: + type: block_mem + width: 18 + depth: 256 + +uart: + port: "auto" + baudrate: 115200 + clock_freq: 100000000 \ No newline at end of file diff --git a/test/virtual_uart/tb_manta.cpp b/test/virtual_uart/tb_manta.cpp new file mode 100644 index 0000000..8a3a76b --- /dev/null +++ b/test/virtual_uart/tb_manta.cpp @@ -0,0 +1,78 @@ +#include +#include +#include +#include +#include +#include "Vmanta.h" + +vluint64_t sim_time = 0; + +int main(int argc, char** argv, char** env) { + Vmanta *dut = new Vmanta; + + Verilated::traceEverOn(true); + VerilatedVcdC *m_trace = new VerilatedVcdC; + dut->trace(m_trace, 5); + m_trace->open("waveform.vcd"); + + while(true) { + + // get line from stdin + std::string line; + std::getline(std::cin, line); + + for (int i=0; i < line.length(); i++) { + // advance simulation + dut->clk ^= 1; + dut->mem_clk ^= 1; + dut->eval(); + m_trace->dump(sim_time); + sim_time++; + + // feed it to the serial port + dut->urx_brx_axiv = 1; + dut->urx_brx_axid = line[i]; + + if (line[i] == 'C') + dut->urx_brx_axid = '\r'; + + if (line[i] == 'L') + dut->urx_brx_axid = '\n'; + + // advance simulation + dut->clk ^= 1; + dut->mem_clk ^= 1; + dut->eval(); + m_trace->dump(sim_time); + sim_time++; + } + + for (int i=0; i < 30; i++) { + + // advance simulation + dut->clk ^= 1; + dut->mem_clk ^= 1; + dut->eval(); + m_trace->dump(sim_time); + sim_time++; + + + // print whatever's on the port + if(dut->btx_utx_start) + std::cout << dut->btx_utx_data; + + // advance simulation + dut->clk ^= 1; + dut->mem_clk ^= 1; + dut->eval(); + m_trace->dump(sim_time); + sim_time++; + } + + + } + + m_trace->close(); + delete dut; + exit(EXIT_SUCCESS); +}