From e022696b31bd6fff57d374ee1e629e5f74aca591 Mon Sep 17 00:00:00 2001 From: Fischer Moseley <42497969+fischermoseley@users.noreply.github.com> Date: Tue, 7 Mar 2023 09:18:40 -0500 Subject: [PATCH] add working example for macOS bug --- .../nexys_a7/single_lut_ram/block_verify.py | 43 ++++ examples/nexys_a7/single_lut_ram/read.py | 12 - .../nexys_a7/single_lut_ram/src/bridge_tx.v | 99 ++++---- examples/nexys_a7/single_lut_ram/src/manta.v | 114 ++++----- .../nexys_a7/single_lut_ram/src/rx_uart.v | 2 +- .../nexys_a7/single_lut_ram/src/top_level.sv | 4 +- .../nexys_a7/single_lut_ram/src/tx_uart.v | 180 ++++++++++++++ .../nexys_a7/single_lut_ram/src/uart_tx.v | 105 ++++---- examples/nexys_a7/single_lut_ram/write.py | 11 - src/manta/bit_fifo.v | 90 +++++++ src/manta/bridge_tx.v | 99 ++++---- src/manta/fifo.v | 84 ------- src/manta/manta_template.v | 224 ----------------- src/manta/uart_tx.v | 104 ++++---- ...nx_true_dual_port_read_first_2_clock_ram.v | 149 ----------- test/bit_fifo_tb.sv | 75 ++++++ test/bus.gtkw | 101 -------- test/{minimal_bus_tb.sv => bus_fix_tb.sv} | 114 ++++++--- test/bus_tb.sv | 233 ------------------ test/lut_mem.gtkw | 69 ------ test/uart_tx_tb.sv | 120 ++++++--- test/yeet_tb.sv | 93 +++++++ 22 files changed, 886 insertions(+), 1239 deletions(-) create mode 100644 examples/nexys_a7/single_lut_ram/block_verify.py delete mode 100644 examples/nexys_a7/single_lut_ram/read.py create mode 100644 examples/nexys_a7/single_lut_ram/src/tx_uart.v delete mode 100644 examples/nexys_a7/single_lut_ram/write.py create mode 100644 src/manta/bit_fifo.v delete mode 100644 src/manta/fifo.v delete mode 100644 src/manta/manta_template.v delete mode 100644 src/manta/xilinx_true_dual_port_read_first_2_clock_ram.v create mode 100644 test/bit_fifo_tb.sv delete mode 100644 test/bus.gtkw rename test/{minimal_bus_tb.sv => bus_fix_tb.sv} (57%) delete mode 100644 test/bus_tb.sv delete mode 100644 test/lut_mem.gtkw create mode 100644 test/yeet_tb.sv diff --git a/examples/nexys_a7/single_lut_ram/block_verify.py b/examples/nexys_a7/single_lut_ram/block_verify.py new file mode 100644 index 0000000..41d395e --- /dev/null +++ b/examples/nexys_a7/single_lut_ram/block_verify.py @@ -0,0 +1,43 @@ +import serial +from time import sleep +import random + +usb_device = "/dev/tty.usbserial-2102926963071" + + +def write_block(data, base_addr = 0): + msg = b'' + + for addr, data in enumerate(data): + addr_str = '{:04X}'.format(base_addr + addr) + data_str = '{:04X}'.format(data) + msg += f"M{addr_str}{data_str}\r\n".encode('ascii') + + with serial.Serial(usb_device, 115200) as ser: + ser.write(msg) + + +def read_block(addrs, base_addr): + msg = b'' + + for addr in range(addrs): + addr_str = '{:04X}'.format(base_addr + addr) + msg += f"M{addr_str}\r\n".encode('ascii') + + with serial.Serial(usb_device, 115200) as ser: + ser.write(msg) + response = ser.read(7*addrs) + response = response.decode('ascii').replace('\r\n', '').split('M') + return [int(i, 16) for i in response if i] + +if __name__ == "__main__": + for i in range(1000): + test_data = [random.randint(0, 65535) for i in range(32)] + write_block(test_data, 0) + + received = read_block(32, 0) + print(i) + + if(received != test_data): + exit() + diff --git a/examples/nexys_a7/single_lut_ram/read.py b/examples/nexys_a7/single_lut_ram/read.py deleted file mode 100644 index d981ca7..0000000 --- a/examples/nexys_a7/single_lut_ram/read.py +++ /dev/null @@ -1,12 +0,0 @@ -import serial -from time import sleep - -with serial.Serial("/dev/tty.usbserial-210292AE39A41", 115200) as ser: - for i in range(8): - req = '{:04X}'.format(i) - req = f"M{req}\r\n " - req = req.encode('ascii') - - ser.write(req) - resp = ser.read(7) - print(f"req --> {req} resp (bytes) --> {resp}") diff --git a/examples/nexys_a7/single_lut_ram/src/bridge_tx.v b/examples/nexys_a7/single_lut_ram/src/bridge_tx.v index c1a81d8..7376739 100644 --- a/examples/nexys_a7/single_lut_ram/src/bridge_tx.v +++ b/examples/nexys_a7/single_lut_ram/src/bridge_tx.v @@ -3,85 +3,70 @@ module bridge_tx( input wire clk, - - output reg [7:0] axiod, - output reg axiov, - input wire axior, - input wire [15:0] res_data, - input wire res_valid, - output reg res_ready -); + input wire [15:0] rdata_i, + input wire rw_i, + input wire valid_i, + input wire ready_i, -parameter ADDR_WIDTH = 0; -parameter DATA_WDITH = 0; + output reg [7:0] data_o, + output reg valid_o); localparam PREAMBLE = 8'h4D; localparam CR = 8'h0D; localparam LF = 8'h0A; -reg [3:0] bytes_transmitted; -reg [15:0] buffer; +logic busy; +logic [15:0] buffer; +logic [3:0] byte_counter; initial begin - axiod = 0; - axiov = 0; - res_ready = 1; - bytes_transmitted = 0; + busy = 0; buffer = 0; + byte_counter = 0; + valid_o = 0; end always @(posedge clk) begin - if (res_ready) begin - if(res_valid) begin - buffer <= res_data; - res_ready <= 0; - bytes_transmitted <= 0; - axiod <= PREAMBLE; - axiov <= 1; + if (!busy) begin + if (valid_i && !rw_i) begin + busy <= 1; + buffer <= rdata_i; + byte_counter <= 0; + valid_o <= 1; end end - else begin - if (bytes_transmitted == 0) begin - if(axior) bytes_transmitted <= 1; - end + if (busy) begin - if (bytes_transmitted == 1) begin - axiod <= (buffer[15:12] < 10) ? (buffer[15:12] + 8'h30) : (buffer[15:12] + 8'h41 - 'd10); - if (axior) bytes_transmitted <= 2; - end + if(ready_i) begin + byte_counter <= byte_counter + 1; + + if (byte_counter > 5) begin + byte_counter <= 0; - else if(bytes_transmitted == 2) begin - axiod <= (buffer[11:8] < 10) ? (buffer[11:8] + 8'h30) : (buffer[11:8] + 8'h41 - 'd10); - if (axior) bytes_transmitted <= 3; - end - - else if(bytes_transmitted == 3) begin - axiod <= (buffer[7:4] < 10) ? (buffer[7:4] + 8'h30) : (buffer[7:4] + 8'h41 - 'd10); - if (axior) bytes_transmitted <= 4; - end - - else if(bytes_transmitted == 4) begin - axiod <= (buffer[3:0] < 10) ? (buffer[3:0] + 8'h30) : (buffer[3:0] + 8'h41 - 'd10); - if (axior) bytes_transmitted <= 5; - end - - else if(bytes_transmitted == 5) begin - axiod <= 8'h0D; - if (axior) bytes_transmitted <= 6; - end - - else if(bytes_transmitted == 6) begin - axiod <= 8'h0A; - if (axior) begin - axiov <= 0; - res_ready <= 1; - bytes_transmitted <= 0; + // stop transmitting if we don't have both valid and read + if ( !(valid_i && !rw_i) ) begin + busy <= 0; + valid_o <= 0; + end end end end end +always @(*) begin + case (byte_counter) + 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); + 5: data_o = CR; + 6: data_o = LF; + default: data_o = 0; + endcase +end + endmodule `default_nettype wire \ No newline at end of file diff --git a/examples/nexys_a7/single_lut_ram/src/manta.v b/examples/nexys_a7/single_lut_ram/src/manta.v index 6b44000..6e48196 100644 --- a/examples/nexys_a7/single_lut_ram/src/manta.v +++ b/examples/nexys_a7/single_lut_ram/src/manta.v @@ -5,99 +5,81 @@ module manta( input wire clk, input wire rst, input wire rxd, - output reg txd -); + output reg txd); - // tb --> uart_rx signals - // uart_rx #( - // .DATA_WIDTH(8), - // .CLK_FREQ_HZ(100_000_000), - // .BAUDRATE(115200) - // ) urx ( - // .clk(clk), - // .rst(rst), - // .rxd(rxd), - - // .axiod(urx_brx_axid), - // .axiov(urx_brx_axiv)); - - rxuart urx( + rx_uart #(.CLOCKS_PER_BAUD(868)) urx ( .i_clk(clk), .i_uart_rx(rxd), .o_wr(urx_brx_axiv), .o_data(urx_brx_axid)); // uart_rx --> bridge_rx signals - reg [7:0] urx_brx_axid; - reg urx_brx_axiv; + logic [7:0] urx_brx_axid; + logic urx_brx_axiv; bridge_rx brx ( .clk(clk), + .axiid(urx_brx_axid), .axiiv(urx_brx_axiv), - .req_addr(brx_mem_1_addr), - .req_data(brx_mem_1_wdata), - .req_rw(brx_mem_1_rw), - .req_valid(brx_mem_1_valid), + .req_addr(brx_mem_addr), + .req_data(brx_mem_wdata), + .req_rw(brx_mem_rw), + .req_valid(brx_mem_valid), .req_ready(1'b1)); - // bridge_rx --> mem_1 signals - reg [15:0] brx_mem_1_addr; - reg [15:0] brx_mem_1_wdata; - reg brx_mem_1_rw; - reg brx_mem_1_valid; + // bridge_rx --> mem signals + logic [15:0] brx_mem_addr; + logic [15:0] brx_mem_wdata; + logic brx_mem_rw; + logic brx_mem_valid; lut_mem #( - .DEPTH(8), + .DEPTH(32), .BASE_ADDR(0) - ) mem_1 ( + ) mem ( .clk(clk), - .addr_i(brx_mem_1_addr), - .wdata_i(brx_mem_1_wdata), - .rdata_i(0), - .rw_i(brx_mem_1_rw), - .valid_i(brx_mem_1_valid), + .addr_i(brx_mem_addr), + .wdata_i(brx_mem_wdata), + .rdata_i(16'h0), + .rw_i(brx_mem_rw), + .valid_i(brx_mem_valid), .addr_o(), .wdata_o(), - .rdata_o(mem_1_btx_rdata), - .rw_o(), - .valid_o(mem_1_btx_valid)); - - reg [15:0] mem_1_btx_rdata; - reg mem_1_btx_valid; + .rdata_o(mem_btx_rdata), + .rw_o(mem_btx_rw), + .valid_o(mem_btx_valid)); + + // mem --> frizzle signals, it's frizzle because that's a bus you wanna get off of + logic [15:0] mem_btx_rdata; + logic mem_btx_rw; + logic mem_btx_valid; bridge_tx btx ( .clk(clk), - - .res_data(mem_1_btx_rdata), - .res_valid(mem_1_btx_valid), - .res_ready(), - - .axiod(btx_utx_axid), - .axiov(btx_utx_axiv), - .axior(btx_utx_axir)); - - // bridge_tx --> uart_tx signals - reg [7:0] btx_utx_axid; - reg btx_utx_axiv; - reg btx_utx_axir; - - uart_tx #( - .DATA_WIDTH(8), - .CLK_FREQ_HZ(100_000_000), - .BAUDRATE(115200) - ) utx ( - .clk(clk), - .rst(rst), - - .axiid(btx_utx_axid), - .axiiv(btx_utx_axiv), - .axiir(btx_utx_axir), - .txd(txd)); + .rdata_i(mem_btx_rdata), + .rw_i(mem_btx_rw), + .valid_i(mem_btx_valid), + .ready_i(utx_btx_ready), + .data_o(btx_utx_data), + .valid_o(btx_utx_valid)); + + logic utx_btx_ready; + logic btx_utx_valid; + logic [7:0] btx_utx_data; + + uart_tx #(.CLOCKS_PER_BAUD(868)) utx ( + .clk(clk), + + .data(btx_utx_data), + .valid(btx_utx_valid), + .ready(utx_btx_ready), + + .tx(txd)); endmodule `default_nettype wire \ No newline at end of file diff --git a/examples/nexys_a7/single_lut_ram/src/rx_uart.v b/examples/nexys_a7/single_lut_ram/src/rx_uart.v index 039af9b..1206348 100644 --- a/examples/nexys_a7/single_lut_ram/src/rx_uart.v +++ b/examples/nexys_a7/single_lut_ram/src/rx_uart.v @@ -49,7 +49,7 @@ // `default_nettype none -module rxuart( +module rx_uart( input wire i_clk, input wire i_uart_rx, output reg o_wr, diff --git a/examples/nexys_a7/single_lut_ram/src/top_level.sv b/examples/nexys_a7/single_lut_ram/src/top_level.sv index 656a692..f8dc8a5 100644 --- a/examples/nexys_a7/single_lut_ram/src/top_level.sv +++ b/examples/nexys_a7/single_lut_ram/src/top_level.sv @@ -24,14 +24,14 @@ module top_level ( .txd(uart_rxd_out) ); - assign led = manta.brx_mem_1_addr; + assign led = manta.brx_mem_addr; logic [6:0] cat; assign {cg,cf,ce,cd,cc,cb,ca} = cat; ssd ssd ( .clk_in(clk), .rst_in(btnc), - .val_in( (manta.mem_1_btx_rdata << 16) | (manta.brx_mem_1_wdata) ), + .val_in( (manta.mem_btx_rdata << 16) | (manta.brx_mem_wdata) ), .cat_out(cat), .an_out(an)); diff --git a/examples/nexys_a7/single_lut_ram/src/tx_uart.v b/examples/nexys_a7/single_lut_ram/src/tx_uart.v new file mode 100644 index 0000000..eb5ed0d --- /dev/null +++ b/examples/nexys_a7/single_lut_ram/src/tx_uart.v @@ -0,0 +1,180 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// Filename: txuart.v +// +// Project: Verilog Tutorial Example file +// +// Purpose: Transmit outputs over a single UART line. This particular UART +// implementation has been extremely simplified: it does not handle +// generating break conditions, nor does it handle anything other than the +// 8N1 (8 data bits, no parity, 1 stop bit) UART sub-protocol. +// +// To interface with this module, connect it to your system clock, and +// pass it the byte of data you wish to transmit. Strobe the i_wr line +// 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. +// +// There are known deficiencies in the formal proof found within this +// module. These have been left behind for you (the student) to fix. +// +// Creator: Dan Gisselquist, Ph.D. +// Gisselquist Technology, LLC +// +//////////////////////////////////////////////////////////////////////////////// +// +// Written and distributed by Gisselquist Technology, LLC +// +// This program is hereby granted to the public domain. +// +// This program is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or +// FITNESS FOR A PARTICULAR PURPOSE. +// +//////////////////////////////////////////////////////////////////////////////// +// +// +`default_nettype none +// +// +// +module tx_uart( + input wire i_clk, + input wire i_wr, + input wire [7:0] i_data, + output reg o_uart_tx, + output reg o_busy); + + parameter [23:0] CLOCKS_PER_BAUD = 24'd868; + + // A line to tell others when we are ready to accept data. If + // (i_wr)&&(!o_busy) is ever true, then the core has accepted a byte + // for transmission. + + // Define several states + localparam [3:0] START = 4'h0, + BIT_ZERO = 4'h1, + BIT_ONE = 4'h2, + BIT_TWO = 4'h3, + BIT_THREE = 4'h4, + BIT_FOUR = 4'h5, + BIT_FIVE = 4'h6, + BIT_SIX = 4'h7, + BIT_SEVEN = 4'h8, + LAST = 4'h8, + IDLE = 4'hf; + + reg [23:0] counter; + reg [3:0] state; + reg [8:0] lcl_data; + reg baud_stb; + + // o_busy + // + // This is a register, designed to be true is we are ever busy above. + // originally, this was going to be true if we were ever not in the + // idle state. The logic has since become more complex, hence we have + // a register dedicated to this and just copy out that registers value. + + initial o_busy = 1'b0; + initial state = IDLE; + always @(posedge i_clk) + if ((i_wr)&&(!o_busy)) + // Immediately start us off with a start bit + { o_busy, state } <= { 1'b1, START }; + else if (baud_stb) + begin + if (state == IDLE) // Stay in IDLE + { o_busy, state } <= { 1'b0, IDLE }; + else if (state < LAST) begin + o_busy <= 1'b1; + state <= state + 1'b1; + end else // Wait for IDLE + { o_busy, state } <= { 1'b1, IDLE }; + end + + + + // lcl_data + // + // This is our working copy of the i_data register which we use + // when transmitting. It is only of interest during transmit, and is + // allowed to be whatever at any other time. Hence, if o_busy isn't + // true, we can always set it. On the one clock where o_busy isn't + // true and i_wr is, we set it and o_busy is true thereafter. + // Then, on any baud_stb (i.e. change between baud intervals) + // we simple logically shift the register right to grab the next bit. + initial lcl_data = 9'h1ff; + always @(posedge i_clk) + if ((i_wr)&&(!o_busy)) + lcl_data <= { i_data, 1'b0 }; + else if (baud_stb) + lcl_data <= { 1'b1, lcl_data[8:1] }; + + // o_uart_tx + // + // This is the final result/output desired of this core. It's all + // centered about o_uart_tx. This is what finally needs to follow + // the UART protocol. + // + assign o_uart_tx = lcl_data[0]; + + + // All of the above logic is driven by the baud counter. Bits must last + // CLOCKS_PER_BAUD in length, and this baud counter is what we use to + // make certain of that. + // + // The basic logic is this: at the beginning of a bit interval, start + // the baud counter and set it to count CLOCKS_PER_BAUD. When it gets + // to zero, restart it. + // + // However, comparing a 28'bit number to zero can be rather complex-- + // especially if we wish to do anything else on that same clock. For + // that reason, we create "baud_stb". baud_stb is + // nothing more than a flag that is true anytime baud_counter is zero. + // It's true when the logic (above) needs to step to the next bit. + // Simple enough? + // + // I wish we could stop there, but there are some other (ugly) + // conditions to deal with that offer exceptions to this basic logic. + // + // 1. When the user has commanded a BREAK across the line, we need to + // wait several baud intervals following the break before we start + // transmitting, to give any receiver a chance to recognize that we are + // out of the break condition, and to know that the next bit will be + // a stop bit. + // + // 2. A reset is similar to a break condition--on both we wait several + // baud intervals before allowing a start bit. + // + // 3. In the idle state, we stop our counter--so that upon a request + // to transmit when idle we can start transmitting immediately, rather + // than waiting for the end of the next (fictitious and arbitrary) baud + // interval. + // + // When (i_wr)&&(!o_busy)&&(state == IDLE) then we're not only in + // the idle state, but we also just accepted a command to start writing + // the next word. At this point, the baud counter needs to be reset + // to the number of CLOCKS_PER_BAUD, and baud_stb set to zero. + // + // The logic is a bit twisted here, in that it will only check for the + // above condition when baud_stb is false--so as to make + // certain the STOP bit is complete. + initial baud_stb = 1'b1; + initial counter = 0; + always @(posedge i_clk) + if ((i_wr)&&(!o_busy)) + begin + counter <= CLOCKS_PER_BAUD - 1'b1; + baud_stb <= 1'b0; + end else if (!baud_stb) + begin + baud_stb <= (counter == 24'h01); + counter <= counter - 1'b1; + end else if (state != IDLE) + begin + counter <= CLOCKS_PER_BAUD - 1'b1; + baud_stb <= 1'b0; + end +endmodule diff --git a/examples/nexys_a7/single_lut_ram/src/uart_tx.v b/examples/nexys_a7/single_lut_ram/src/uart_tx.v index 9f2f2f5..920e98c 100644 --- a/examples/nexys_a7/single_lut_ram/src/uart_tx.v +++ b/examples/nexys_a7/single_lut_ram/src/uart_tx.v @@ -3,80 +3,73 @@ module uart_tx( input wire clk, - input wire rst, - input wire [DATA_WIDTH-1:0] axiid, - input wire axiiv, - output reg axiir, + input wire [7:0] data, + input wire valid, + output reg busy, + output reg ready, - output reg txd - ); - - parameter DATA_WIDTH = 0; - parameter CLK_FREQ_HZ = 0; - parameter BAUDRATE = 0; + output reg tx); - localparam BAUD_PERIOD = CLK_FREQ_HZ / BAUDRATE; + // this transmitter only works with 8N1 serial, at configurable baudrate + parameter CLOCKS_PER_BAUD = 868; - reg busy; - assign axiir = ~busy; + reg [9:0] baud_counter; + reg [8:0] data_buf; + reg [3:0] bit_index; - reg [$clog2(BAUD_PERIOD) - 1:0] baud_counter; - reg [$clog2(DATA_WIDTH + 2):0] bit_index; - reg [DATA_WIDTH - 1:0] data_buf; - - // make secondary logic for baudrate - always @(posedge clk) begin - if(rst) baud_counter <= 0; - else begin - baud_counter <= (baud_counter == BAUD_PERIOD - 1) ? 0 : baud_counter + 1; - end + initial begin + baud_counter = CLOCKS_PER_BAUD; + data_buf = 0; + bit_index = 0; + busy = 0; + ready = 1; + tx = 1; end - + always @(posedge clk) begin - - // reset logic - if(rst) begin + if (valid && !busy) begin + data_buf <= {1'b1, data}; bit_index <= 0; - busy <= 0; - txd <= 1; // idle high - end - - // enter transmitting state logic - // don't allow new requests to interrupt current - // transfers - if(axiiv && ~busy) begin + tx <= 0; //wafflestomp that start bit + baud_counter <= CLOCKS_PER_BAUD - 1; busy <= 1; - baud_counter <= 0; - data_buf <= axiid; + ready <= 0; end + else if (busy) begin + baud_counter <= baud_counter - 1; - // transmitting state logic - else if(baud_counter == 0 && busy) begin + ready <= (baud_counter == 1) && (bit_index == 9); - if (bit_index == 0) begin - txd <= 0; - bit_index <= bit_index + 1; - end + if (baud_counter == 0) begin + baud_counter <= CLOCKS_PER_BAUD - 1; - else if ((bit_index < DATA_WIDTH + 1) && (bit_index > 0)) begin - txd <= data_buf[bit_index - 1]; - bit_index <= bit_index + 1; - end - - else if (bit_index == DATA_WIDTH + 1) begin - txd <= 1; - bit_index <= bit_index + 1; - end - else if (bit_index >= DATA_WIDTH + 1) begin - busy <= 0; - bit_index <= 0; + if (bit_index == 9) begin + if(valid) begin + data_buf <= {1'b1, data}; + 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; + end end end end + + + endmodule - `default_nettype wire diff --git a/examples/nexys_a7/single_lut_ram/write.py b/examples/nexys_a7/single_lut_ram/write.py deleted file mode 100644 index 9911c25..0000000 --- a/examples/nexys_a7/single_lut_ram/write.py +++ /dev/null @@ -1,11 +0,0 @@ -import serial -from time import sleep - -with serial.Serial("/dev/tty.usbserial-210292AE39A41", 115200) as ser: - for i in range(8): - req = '{:04X}'.format(i) - req = f"M{req}5678\r\n" - req = req.encode('ascii') - - ser.write(req) - print(f"req --> {req}") diff --git a/src/manta/bit_fifo.v b/src/manta/bit_fifo.v new file mode 100644 index 0000000..68ad4a0 --- /dev/null +++ b/src/manta/bit_fifo.v @@ -0,0 +1,90 @@ +`default_nettype none +`timescale 1ns/1ps + +module bit_fifo( + input wire clk, + + input wire en, + input wire [IWIDTH-1:0] in, + input wire in_valid, + output reg [OWIDTH-1:0] out, + output reg out_valid); + + parameter IWIDTH = 0; + parameter OWIDTH = 0; + + localparam BWIDTH = OWIDTH-1 + IWIDTH; + + reg [OWIDTH-1:0] buffer; + reg [$clog2(OWIDTH)-1:0] buffer_size; + + initial begin + buffer = 0; + buffer_size = 0; + out = 0; + out_valid = 0; + end + + reg [OWIDTH-1:0] mask; + reg [OWIDTH-1:0] top_half; + reg [OWIDTH-1:0] bottom_half; + reg [OWIDTH-1:0] joined_halves; + + always @(*) begin + mask = (1 << buffer_size) - 1; + top_half = (buffer & mask) << (OWIDTH - buffer_size); + bottom_half = in >> (IWIDTH- (OWIDTH - buffer_size)); + joined_halves = top_half | bottom_half; + end + + always @(posedge clk) begin + out_valid <= 0; + + // RUN state + if(en && in_valid) begin + // this module should spit out values as soon as it's able, + // so if we'll have enough once the present value's clocked in, + // then we'll need to immediately assign the output as a combination + // of what's in the buffer and what's on the line. + + if(buffer_size + IWIDTH >= OWIDTH) begin + // compute buffer size + // -> everything that was in the buffer is now in the output, + // so what we put back in the buffer is purely what's left over + // from our input data once we've sliced out what we need + buffer_size <= buffer_size + IWIDTH - OWIDTH; + + // compute buffer contents + buffer <= ( (1 << (buffer_size + IWIDTH - OWIDTH)) - 1 ) & in; + + /* + $display("buffer_size: %h in: %b ", buffer_size, in); + $display(" buffer: %b", buffer); + $display(" mask: %b", mask); + $display(" top_half: %b", top_half); + $display(" bottom_half: %b", bottom_half); + $display(" out: %b \n", joined_halves); + */ + + // compute output + out <= joined_halves; + out_valid <= 1; + end + + else begin + // shift into the right side of the buffer + buffer <= {buffer[BWIDTH-1-IWIDTH:0], in}; + buffer_size <= buffer_size + IWIDTH; + end + end + + // FLUSH state + else if(buffer_size > 0) begin + out <= (buffer) & ((1 << buffer_size) - 1); + out_valid <= 1; + buffer_size <= 0; + end + end +endmodule + +`default_nettype wire \ No newline at end of file diff --git a/src/manta/bridge_tx.v b/src/manta/bridge_tx.v index c1a81d8..7376739 100644 --- a/src/manta/bridge_tx.v +++ b/src/manta/bridge_tx.v @@ -3,85 +3,70 @@ module bridge_tx( input wire clk, - - output reg [7:0] axiod, - output reg axiov, - input wire axior, - input wire [15:0] res_data, - input wire res_valid, - output reg res_ready -); + input wire [15:0] rdata_i, + input wire rw_i, + input wire valid_i, + input wire ready_i, -parameter ADDR_WIDTH = 0; -parameter DATA_WDITH = 0; + output reg [7:0] data_o, + output reg valid_o); localparam PREAMBLE = 8'h4D; localparam CR = 8'h0D; localparam LF = 8'h0A; -reg [3:0] bytes_transmitted; -reg [15:0] buffer; +logic busy; +logic [15:0] buffer; +logic [3:0] byte_counter; initial begin - axiod = 0; - axiov = 0; - res_ready = 1; - bytes_transmitted = 0; + busy = 0; buffer = 0; + byte_counter = 0; + valid_o = 0; end always @(posedge clk) begin - if (res_ready) begin - if(res_valid) begin - buffer <= res_data; - res_ready <= 0; - bytes_transmitted <= 0; - axiod <= PREAMBLE; - axiov <= 1; + if (!busy) begin + if (valid_i && !rw_i) begin + busy <= 1; + buffer <= rdata_i; + byte_counter <= 0; + valid_o <= 1; end end - else begin - if (bytes_transmitted == 0) begin - if(axior) bytes_transmitted <= 1; - end + if (busy) begin - if (bytes_transmitted == 1) begin - axiod <= (buffer[15:12] < 10) ? (buffer[15:12] + 8'h30) : (buffer[15:12] + 8'h41 - 'd10); - if (axior) bytes_transmitted <= 2; - end + if(ready_i) begin + byte_counter <= byte_counter + 1; + + if (byte_counter > 5) begin + byte_counter <= 0; - else if(bytes_transmitted == 2) begin - axiod <= (buffer[11:8] < 10) ? (buffer[11:8] + 8'h30) : (buffer[11:8] + 8'h41 - 'd10); - if (axior) bytes_transmitted <= 3; - end - - else if(bytes_transmitted == 3) begin - axiod <= (buffer[7:4] < 10) ? (buffer[7:4] + 8'h30) : (buffer[7:4] + 8'h41 - 'd10); - if (axior) bytes_transmitted <= 4; - end - - else if(bytes_transmitted == 4) begin - axiod <= (buffer[3:0] < 10) ? (buffer[3:0] + 8'h30) : (buffer[3:0] + 8'h41 - 'd10); - if (axior) bytes_transmitted <= 5; - end - - else if(bytes_transmitted == 5) begin - axiod <= 8'h0D; - if (axior) bytes_transmitted <= 6; - end - - else if(bytes_transmitted == 6) begin - axiod <= 8'h0A; - if (axior) begin - axiov <= 0; - res_ready <= 1; - bytes_transmitted <= 0; + // stop transmitting if we don't have both valid and read + if ( !(valid_i && !rw_i) ) begin + busy <= 0; + valid_o <= 0; + end end end end end +always @(*) begin + case (byte_counter) + 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); + 5: data_o = CR; + 6: data_o = LF; + default: data_o = 0; + endcase +end + endmodule `default_nettype wire \ No newline at end of file diff --git a/src/manta/fifo.v b/src/manta/fifo.v deleted file mode 100644 index 6a90a67..0000000 --- a/src/manta/fifo.v +++ /dev/null @@ -1,84 +0,0 @@ -`default_nettype none -`timescale 1ns / 1ps - -module fifo ( - input wire clk, - input wire rst, - - input wire [WIDTH - 1:0] data_in, - input wire input_ready, - - input wire request_output, - output reg [WIDTH - 1:0] data_out, - output reg output_valid, - - output reg [AW:0] size, - output reg empty, - output reg full - ); - - parameter WIDTH = 8; - parameter DEPTH = 4096; - localparam AW = $clog2(DEPTH); - - reg [AW:0] write_pointer; - reg [AW:0] read_pointer; - - reg empty_int; - assign empty_int = (write_pointer[AW] == read_pointer[AW]); - - reg full_or_empty; - assign full_or_empty = (write_pointer[AW-1:0] == read_pointer[AW-1:0]); - - assign full = full_or_empty & !empty_int; - assign empty = full_or_empty & empty_int; - assign size = write_pointer - read_pointer; - - reg output_valid_pip_0; - reg output_valid_pip_1; - - always @(posedge clk) begin - if (input_ready && ~full) - write_pointer <= write_pointer + 1'd1; - - if (request_output && ~empty) - read_pointer <= read_pointer + 1'd1; - output_valid_pip_0 <= request_output; - output_valid_pip_1 <= output_valid_pip_0; - output_valid <= output_valid_pip_1; - - if (rst) begin - read_pointer <= 0; - write_pointer <= 0; - end - end - - xilinx_true_dual_port_read_first_2_clock_ram #( - .RAM_WIDTH(WIDTH), - .RAM_DEPTH(DEPTH), - .RAM_PERFORMANCE("HIGH_PERFORMANCE") - - ) buffer ( - - // write port - .clka(clk), - .rsta(rst), - .ena(1), - .addra(write_pointer), - .dina(data_in), - .wea(input_ready), - .regcea(1), - .douta(), - - // read port - .clkb(clk), - .rstb(rst), - .enb(1), - .addrb(read_pointer), - .dinb(), - .web(0), - .regceb(1), - .doutb(data_out)); - endmodule - -`default_nettype wire diff --git a/src/manta/manta_template.v b/src/manta/manta_template.v deleted file mode 100644 index f469dfe..0000000 --- a/src/manta/manta_template.v +++ /dev/null @@ -1,224 +0,0 @@ -`default_nettype none -`timescale 1ns / 1ps - -/* -This manta definition was autogenerated on @TIMESTAMP by @USER - -If this breaks or if you've got dank formal verification memes, -please contact fischerm [at] mit.edu. -*/ - -`define IDLE 0 -`define ARM 1 -`define FILL 2 -`define DOWNLINK 3 - -`define ARM_BYTE 8'b00110000 - -module manta ( - input wire clk, - input wire rst, - - /* Begin autogenerated probe definitions */ - @PROBES - /* End autogenerated probe definitions */ - - input wire rxd, - output reg txd); - - /* Begin autogenerated parameters */ - localparam SAMPLE_WIDTH = @SAMPLE_WIDTH; - localparam SAMPLE_DEPTH = @SAMPLE_DEPTH; - - localparam DATA_WIDTH = @DATA_WIDTH; - localparam BAUDRATE = @BAUDRATE; - localparam CLK_FREQ_HZ = @CLK_FREQ_HZ; - - reg trigger; - assign trigger = @TRIGGER; - - reg [SAMPLE_WIDTH - 1 : 0] concat; - assign concat = @CONCAT; - /* End autogenerated parameters */ - - - // FIFO - reg [7:0] fifo_data_in; - reg fifo_input_ready; - - reg fifo_request_output; - reg [7:0] fifo_data_out; - reg fifo_output_valid; - - reg [11:0] fifo_size; - reg fifo_empty; - reg fifo_full; - - fifo #( - .WIDTH(SAMPLE_WIDTH), - .DEPTH(SAMPLE_DEPTH) - ) fifo ( - .clk(clk), - .rst(rst), - - .data_in(fifo_data_in), - .input_ready(fifo_input_ready), - - .request_output(fifo_request_output), - .data_out(fifo_data_out), - .output_valid(fifo_output_valid), - - .size(fifo_size), - .empty(fifo_empty), - .full(fifo_full)); - - // Serial interface - reg tx_start; - reg [7:0] tx_data; - reg tx_busy; - - reg [7:0] rx_data; - reg rx_ready; - reg rx_busy; - - - uart_tx #( - .DATA_WIDTH(DATA_WIDTH), - .CLK_FREQ_HZ(CLK_FREQ_HZ), - .BAUDRATE(BAUDRATE)) - tx ( - .clk(clk), - .rst(rst), - .start(tx_start), - .data(tx_data), - - .busy(tx_busy), - .txd(txd)); - - uart_rx #( - .DATA_WIDTH(DATA_WIDTH), - .CLK_FREQ_HZ(CLK_FREQ_HZ), - .BAUDRATE(BAUDRATE)) - rx ( - .clk(clk), - .rst(rst), - .rxd(rxd), - - .data(rx_data), - .ready(rx_ready), - .busy(rx_busy)); - - - /* State Machine */ - /* - - IDLE: - - literally nothing is happening. the FIFO isn't being written to or read from. it should be empty. - - an arm command over serial is what brings us into the ARM state - - ARM: - - popping things onto FIFO. if the fifo is halfway full, we pop them off too. - - meeting the trigger condition is what moves us into the filing state - - FILL: - - popping things onto FIFO, until it's full. once it is full, we move into the downlinking state - - DOWNLINK: - - popping thing off of the FIFO until it's empty. once it's empty, we move back into the IDLE state - */ - - /* Downlink State Machine Controller */ - /* - - - ila enters the downlink state - - set fifo_output_request high for a clock cycle - - when fifo_output_valid goes high, send fifo_data_out across the line - - do nothing until tx_busy goes low - - goto step 2 - - */ - - reg [1:0] state; - reg [2:0] downlink_fsm_state; - - always @(posedge clk) begin - if(rst) begin - state <= `IDLE; - downlink_fsm_state <= 0; - tx_data <= 0; - tx_start <= 0; - end - else begin - - case (state) - `IDLE : begin - fifo_input_ready <= 0; - fifo_request_output <= 0; - - if (rx_ready && rx_data == `ARM_BYTE) state <= `ARM; - - end - - `ARM : begin - // place samples into FIFO - fifo_input_ready <= 1; - fifo_data_in <= concat; - - // remove old samples if we're more than halfway full - fifo_request_output <= (fifo_size >= SAMPLE_DEPTH / 2); - - if(trigger) state <= `FILL; - end - - `FILL : begin - // place samples into FIFO - fifo_input_ready <= 1; - fifo_data_in <= concat; - - // don't pop anything out the FIFO - fifo_request_output <= 0; - - if(fifo_size == SAMPLE_DEPTH - 1) state <= `DOWNLINK; - end - - `DOWNLINK : begin - // place no samples into FIFO - fifo_input_ready <= 0; - - - case (downlink_fsm_state) - 0 : begin - if (~fifo_empty) begin - fifo_request_output <= 1; - downlink_fsm_state <= 1; - end - - else state <= `IDLE; - end - - 1 : begin - fifo_request_output <= 0; - - if (fifo_output_valid) begin - tx_data <= fifo_data_out; - tx_start <= 1; - downlink_fsm_state <= 2; - end - end - - 2 : begin - tx_start <= 0; - - if (~tx_busy && ~tx_start) downlink_fsm_state <= 0; - end - endcase - - end - endcase - end - end - -endmodule - - -`default_nettype wire \ No newline at end of file diff --git a/src/manta/uart_tx.v b/src/manta/uart_tx.v index 554d087..920e98c 100644 --- a/src/manta/uart_tx.v +++ b/src/manta/uart_tx.v @@ -3,79 +3,73 @@ module uart_tx( input wire clk, - input wire rst, - input wire [DATA_WIDTH-1:0] axiid, - input wire axiiv, - output reg axiir, + input wire [7:0] data, + input wire valid, + output reg busy, + output reg ready, - output reg txd - ); - - parameter DATA_WIDTH = 0; - parameter CLK_FREQ_HZ = 0; - parameter BAUDRATE = 0; + output reg tx); - localparam BAUD_PERIOD = CLK_FREQ_HZ / BAUDRATE; + // this transmitter only works with 8N1 serial, at configurable baudrate + parameter CLOCKS_PER_BAUD = 868; - reg busy; - assign axiir = ~busy; + reg [9:0] baud_counter; + reg [8:0] data_buf; + reg [3:0] bit_index; - reg [$clog2(BAUD_PERIOD) - 1:0] baud_counter; - reg [$clog2(DATA_WIDTH + 2):0] bit_index; - reg [DATA_WIDTH - 1:0] data_buf; - - // make secondary logic for baudrate - always @(posedge clk) begin - if(rst) baud_counter <= 0; - else begin - baud_counter <= (baud_counter == BAUD_PERIOD - 1) ? 0 : baud_counter + 1; - end + initial begin + baud_counter = CLOCKS_PER_BAUD; + data_buf = 0; + bit_index = 0; + busy = 0; + ready = 1; + tx = 1; end - + always @(posedge clk) begin - - // reset logic - if(rst) begin + if (valid && !busy) begin + data_buf <= {1'b1, data}; bit_index <= 0; - busy <= 0; - txd <= 1; // idle high - end - - // enter transmitting state logic - // don't allow new requests to interrupt current - // transfers - if(axiiv && ~busy) begin + tx <= 0; //wafflestomp that start bit + baud_counter <= CLOCKS_PER_BAUD - 1; busy <= 1; - data_buf <= axiid; + ready <= 0; end + else if (busy) begin + baud_counter <= baud_counter - 1; - // transmitting state logic - else if(baud_counter == 0 && busy) begin + ready <= (baud_counter == 1) && (bit_index == 9); - if (bit_index == 0) begin - txd <= 0; - bit_index <= bit_index + 1; - end + if (baud_counter == 0) begin + baud_counter <= CLOCKS_PER_BAUD - 1; - else if ((bit_index < DATA_WIDTH + 1) && (bit_index > 0)) begin - txd <= data_buf[bit_index - 1]; - bit_index <= bit_index + 1; - end - - else if (bit_index == DATA_WIDTH + 1) begin - txd <= 1; - bit_index <= bit_index + 1; - end - else if (bit_index >= DATA_WIDTH + 1) begin - busy <= 0; - bit_index <= 0; + if (bit_index == 9) begin + if(valid) begin + data_buf <= {1'b1, data}; + 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; + end end end end + + + endmodule - `default_nettype wire diff --git a/src/manta/xilinx_true_dual_port_read_first_2_clock_ram.v b/src/manta/xilinx_true_dual_port_read_first_2_clock_ram.v deleted file mode 100644 index 7e975e5..0000000 --- a/src/manta/xilinx_true_dual_port_read_first_2_clock_ram.v +++ /dev/null @@ -1,149 +0,0 @@ - -// Xilinx True Dual Port RAM, Read First, Dual Clock -// This code implements a parameterizable true dual port memory (both ports can read and write). -// The behavior of this RAM is when data is written, the prior memory contents at the write -// address are presented on the output port. If the output data is -// not needed during writes or the last read value is desired to be retained, -// it is suggested to use a no change RAM as it is more power efficient. -// If a reset or enable is not necessary, it may be tied off or removed from the code. - -module xilinx_true_dual_port_read_first_2_clock_ram #( - parameter RAM_WIDTH = 18, // Specify RAM data width - parameter RAM_DEPTH = 1024, // Specify RAM depth (number of entries) - parameter RAM_PERFORMANCE = "HIGH_PERFORMANCE", // Select "HIGH_PERFORMANCE" or "LOW_LATENCY" - parameter INIT_FILE = "" // Specify name/location of RAM initialization file if using one (leave blank if not) -) ( - input [clogb2(RAM_DEPTH-1)-1:0] addra, // Port A address bus, width determined from RAM_DEPTH - input [clogb2(RAM_DEPTH-1)-1:0] addrb, // Port B address bus, width determined from RAM_DEPTH - input [RAM_WIDTH-1:0] dina, // Port A RAM input data - input [RAM_WIDTH-1:0] dinb, // Port B RAM input data - input clka, // Port A clock - input clkb, // Port B clock - input wea, // Port A write enable - input web, // Port B write enable - input ena, // Port A RAM Enable, for additional power savings, disable port when not in use - input enb, // Port B RAM Enable, for additional power savings, disable port when not in use - input rsta, // Port A output reset (does not affect memory contents) - input rstb, // Port B output reset (does not affect memory contents) - input regcea, // Port A output register enable - input regceb, // Port B output register enable - output [RAM_WIDTH-1:0] douta, // Port A RAM output data - output [RAM_WIDTH-1:0] doutb // Port B RAM output data -); - - reg [RAM_WIDTH-1:0] BRAM [RAM_DEPTH-1:0]; - reg [RAM_WIDTH-1:0] ram_data_a = {RAM_WIDTH{1'b0}}; - reg [RAM_WIDTH-1:0] ram_data_b = {RAM_WIDTH{1'b0}}; - - //this loop below allows for rendering with iverilog simulations! - /* - integer idx; - for(idx = 0; idx < RAM_DEPTH; idx = idx+1) begin: cats - wire [RAM_WIDTH-1:0] tmp; - assign tmp = BRAM[idx]; - end - */ - - // The following code either initializes the memory values to a specified file or to all zeros to match hardware - generate - if (INIT_FILE != "") begin: use_init_file - initial - $readmemh(INIT_FILE, BRAM, 0, RAM_DEPTH-1); - end else begin: init_bram_to_zero - integer ram_index; - initial - for (ram_index = 0; ram_index < RAM_DEPTH; ram_index = ram_index + 1) - BRAM[ram_index] = {RAM_WIDTH{1'b0}}; - end - endgenerate - integer idx; - // initial begin - // for (idx = 0; idx < RAM_DEPTH; idx = idx + 1) begin - // $dumpvars(0, BRAM[idx]); - // end - // end - always @(posedge clka) - if (ena) begin - if (wea) - BRAM[addra] <= dina; - ram_data_a <= BRAM[addra]; - end - - always @(posedge clkb) - if (enb) begin - if (web) - BRAM[addrb] <= dinb; - ram_data_b <= BRAM[addrb]; - end - - // The following code generates HIGH_PERFORMANCE (use output register) or LOW_LATENCY (no output register) - generate - if (RAM_PERFORMANCE == "LOW_LATENCY") begin: no_output_register - - // The following is a 1 clock cycle read latency at the cost of a longer clock-to-out timing - assign douta = ram_data_a; - assign doutb = ram_data_b; - - end else begin: output_register - - // The following is a 2 clock cycle read latency with improve clock-to-out timing - - reg [RAM_WIDTH-1:0] douta_reg = {RAM_WIDTH{1'b0}}; - reg [RAM_WIDTH-1:0] doutb_reg = {RAM_WIDTH{1'b0}}; - - always @(posedge clka) - if (rsta) - douta_reg <= {RAM_WIDTH{1'b0}}; - else if (regcea) - douta_reg <= ram_data_a; - - always @(posedge clkb) - if (rstb) - doutb_reg <= {RAM_WIDTH{1'b0}}; - else if (regceb) - doutb_reg <= ram_data_b; - - assign douta = douta_reg; - assign doutb = doutb_reg; - - end - endgenerate - - // The following function calculates the address width based on specified RAM depth - function integer clogb2; - input integer depth; - for (clogb2=0; depth>0; clogb2=clogb2+1) - depth = depth >> 1; - endfunction - -endmodule - -// The following is an instantiation template for xilinx_true_dual_port_read_first_2_clock_ram -/* - // Xilinx True Dual Port RAM, Read First, Dual Clock - xilinx_true_dual_port_read_first_2_clock_ram #( - .RAM_WIDTH(18), // Specify RAM data width - .RAM_DEPTH(1024), // Specify RAM depth (number of entries) - .RAM_PERFORMANCE("HIGH_PERFORMANCE"), // Select "HIGH_PERFORMANCE" or "LOW_LATENCY" - .INIT_FILE("") // Specify name/location of RAM initialization file if using one (leave blank if not) - ) your_instance_name ( - .addra(addra), // Port A address bus, width determined from RAM_DEPTH - .addrb(addrb), // Port B address bus, width determined from RAM_DEPTH - .dina(dina), // Port A RAM input data, width determined from RAM_WIDTH - .dinb(dinb), // Port B RAM input data, width determined from RAM_WIDTH - .clka(clka), // Port A clock - .clkb(clkb), // Port B clock - .wea(wea), // Port A write enable - .web(web), // Port B write enable - .ena(ena), // Port A RAM Enable, for additional power savings, disable port when not in use - .enb(enb), // Port B RAM Enable, for additional power savings, disable port when not in use - .rsta(rsta), // Port A output reset (does not affect memory contents) - .rstb(rstb), // Port B output reset (does not affect memory contents) - .regcea(regcea), // Port A output register enable - .regceb(regceb), // Port B output register enable - .douta(douta), // Port A RAM output data, width determined from RAM_WIDTH - .doutb(doutb) // Port B RAM output data, width determined from RAM_WIDTH - ); -*/ - - diff --git a/test/bit_fifo_tb.sv b/test/bit_fifo_tb.sv new file mode 100644 index 0000000..1d48559 --- /dev/null +++ b/test/bit_fifo_tb.sv @@ -0,0 +1,75 @@ +`default_nettype none +`timescale 1ns/1ps + +`define CP 10 +`define HCP 5 + +module bit_fifo_tb; + + //boilerplate + logic clk; + integer test_num; + + always begin + #`HCP + clk = !clk; + end + + parameter IWIDTH = 3; + parameter OWIDTH = 7; + + logic en; + logic [IWIDTH-1:0] in; + logic in_valid; + logic [OWIDTH-1:0] out; + logic out_valid; + + bit_fifo #(.IWIDTH(IWIDTH), .OWIDTH(OWIDTH)) bfifo ( + .clk(clk), + + .en(en), + .in(in), + .in_valid(in_valid), + .out(out), + .out_valid(out_valid)); + + initial begin + $dumpfile("bit_fifo_tb.vcd"); + $dumpvars(0, bit_fifo_tb); + + // setup and reset + clk = 0; + test_num = 0; + en = 0; + in_valid = 0; + in = 0; + #`HCP + + #(10*`CP); + + /* ==== Test 1 Begin ==== */ + $display("\n=== test 1: make sure invalid data isn't added to buffer ==="); + test_num = 1; + en = 1; + #(10*`CP); + en = 0; + /* ==== Test 1 End ==== */ + + /* ==== Test 2 Begin ==== */ + $display("\n=== test 2: just throw bits at it! ==="); + test_num = 1; + en = 1; + in_valid = 1; + in = 3'b101; + + #(10*`CP); + in_valid = 0; + en = 0; + + #(10*`CP); + /* ==== Test 2 End ==== */ + $finish(); + end +endmodule + +`default_nettype wire \ No newline at end of file diff --git a/test/bus.gtkw b/test/bus.gtkw deleted file mode 100644 index dfb01bb..0000000 --- a/test/bus.gtkw +++ /dev/null @@ -1,101 +0,0 @@ -[*] -[*] GTKWave Analyzer v3.3.107 (w)1999-2020 BSI -[*] Wed Mar 1 02:04:43 2023 -[*] -[dumpfile] "/Users/fischerm/fpga/manta/bus.vcd" -[dumpfile_mtime] "Wed Mar 1 02:00:40 2023" -[dumpfile_size] 91134 -[savefile] "/Users/fischerm/fpga/manta/bus.gtkw" -[timestart] 0 -[size] 1710 994 -[pos] -1 -1 -*-21.981709 8420000 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -[treeopen] bus_tb. -[sst_width] 353 -[signals_width] 276 -[sst_expanded] 1 -[sst_vpaned_height] 296 -@28 -bus_tb.clk -bus_tb.rst -@420 -bus_tb.test_num -@200 -- -- --tb --> uart_rx -@28 -bus_tb.tb_urx_rxd -@200 -- -- --uart_rx --> bridge_rx -@820 -bus_tb.urx_brx_axid[7:0] -@28 -bus_tb.urx_brx_axiv -@22 -bus_tb.urx.bit_index[4:0] -@200 -- -- --bridge_rx --> mem_1 -@22 -bus_tb.brx_mem_1_addr[15:0] -bus_tb.brx_mem_1_rdata[15:0] -bus_tb.brx_mem_1_wdata[15:0] -@28 -bus_tb.brx_mem_1_rw -bus_tb.brx_mem_1_valid -@200 -- -- --mem_1 --> mem_2 -@22 -bus_tb.mem_1_mem_2_addr[15:0] -bus_tb.mem_1_mem_2_rdata[15:0] -bus_tb.mem_1_mem_2_wdata[15:0] -@28 -bus_tb.mem_1_mem_2_rw -bus_tb.mem_1_mem_2_valid -@200 -- -- --mem_2 --> mem_3 -@22 -bus_tb.mem_2_mem_3_addr[15:0] -bus_tb.mem_2_mem_3_rdata[15:0] -@28 -bus_tb.mem_2_mem_3_rw -bus_tb.mem_2_mem_3_valid -@22 -bus_tb.mem_2_mem_3_wdata[15:0] -@200 -- -- --mem_3 --> bridge_tx -@22 -bus_tb.mem_3_btx_addr[15:0] -bus_tb.mem_3_btx_rdata[15:0] -@28 -bus_tb.mem_3_btx_rw -bus_tb.mem_3_btx_valid -@22 -bus_tb.mem_3_btx_wdata[15:0] -@200 -- -- --bridge_tx --> uart_tx -@23 -bus_tb.btx_utx_axid[7:0] -@28 -bus_tb.btx_utx_axir -bus_tb.btx_utx_axiv -@200 -- -- --uart_tx --> tb -@28 -bus_tb.utx_tb_txd -[pattern_trace] 1 -[pattern_trace] 0 diff --git a/test/minimal_bus_tb.sv b/test/bus_fix_tb.sv similarity index 57% rename from test/minimal_bus_tb.sv rename to test/bus_fix_tb.sv index 55951ac..d3a8be8 100644 --- a/test/minimal_bus_tb.sv +++ b/test/bus_fix_tb.sv @@ -11,11 +11,11 @@ if (i == 0) tb_urx_rxd = 0; \ else if ((i > 0) & (i < 9)) tb_urx_rxd = char[i-1]; \ else if (i == 9) tb_urx_rxd = 1; \ - #(10*`CP); \ + #(868*`CP); \ end \ end \ -module minimal_bus_tb; +module bus_fix_tb; // https://www.youtube.com/watch?v=WCOAr-96bGc //boilerplate @@ -25,10 +25,11 @@ module minimal_bus_tb; string msg; logic [7:0] char; + logic [7:0] botl; // tb --> uart_rx signals logic tb_urx_rxd; - rx_uart #(.CLOCKS_PER_BAUD(10)) urx ( + rx_uart #(.CLOCKS_PER_BAUD(868)) urx ( .i_clk(clk), .i_uart_rx(tb_urx_rxd), .o_wr(urx_brx_axiv), @@ -67,45 +68,57 @@ module minimal_bus_tb; .rw_i(brx_mem_rw), .valid_i(brx_mem_valid), - .addr_o(mem_btx_addr), - .wdata_o(mem_btx_wdata), + .addr_o(), + .wdata_o(), .rdata_o(mem_btx_rdata), .rw_o(mem_btx_rw), .valid_o(mem_btx_valid)); - // mem --> bridge_tx signals - logic [15:0] mem_btx_addr; - logic [15:0] mem_btx_wdata; + // mem --> frizzle signals, it's frizzle because that's a bus you wanna get off of logic [15:0] mem_btx_rdata; logic mem_btx_rw; logic mem_btx_valid; bridge_tx btx ( .clk(clk), + + .rdata_i(mem_btx_rdata), + .rw_i(mem_btx_rw), + .valid_i(mem_btx_valid), - .res_data(mem_btx_rdata), - .res_valid(mem_btx_valid), - .res_ready(), + .ready_i(utx_btx_ready), + .data_o(btx_utx_data), + .valid_o(btx_utx_valid)); - .axiod(btx_utx_axid), - .axiov(btx_utx_axiv), - .axior(~btx_utx_axib)); + logic utx_btx_ready; + logic btx_utx_valid; + logic [7:0] btx_utx_data; + + uart_tx #(.CLOCKS_PER_BAUD(868)) utx ( + .clk(clk), - // bridge_tx --> uart_tx signals - logic [7:0] btx_utx_axid; - logic btx_utx_axiv; - logic btx_utx_axib; + .data(btx_utx_data), + .valid(btx_utx_valid), + .ready(utx_btx_ready), - tx_uart #(.CLOCKS_PER_BAUD(10)) utx( - .i_clk(clk), - .i_wr(btx_utx_axiv), - .i_data(btx_utx_axid), - - .o_uart_tx(utx_tb_txd), - .o_busy(btx_utx_axib)); + .tx(utx_tb_tx)); // utx --> tb signals - logic utx_tb_txd; + logic utx_tb_tx; + + // decoder for lolz + logic [7:0] tb_decoder_data; + logic [7:0] decoded_uart; + logic tb_decoder_valid; + + rx_uart #(.CLOCKS_PER_BAUD(868)) decoder ( + .i_clk(clk), + + .i_uart_rx(utx_tb_tx), + .o_wr(tb_decoder_valid), + .o_data(tb_decoder_data)); + + always @(posedge clk) if (tb_decoder_valid) decoded_uart <= tb_decoder_data; always begin #`HCP @@ -113,8 +126,8 @@ module minimal_bus_tb; end initial begin - $dumpfile("minimal_bus.vcd"); - $dumpvars(0, minimal_bus_tb); + $dumpfile("bus_fix.vcd"); + $dumpvars(0, bus_fix_tb); // setup and reset clk = 0; @@ -152,18 +165,53 @@ module minimal_bus_tb; /* ==== Test 2 End ==== */ /* ==== Test 3 Begin ==== */ - $display("\n=== test 3: read from 0x0000-0x0007 for baseline functionality ==="); + $display("\n=== test 3: 1k sequential reads, stress test ==="); test_num = 3; - for(logic[15:0] j=0; j<32; j++) begin - $display($sformatf("M%H", j)); - msg = {$sformatf("M%H", j), 8'h0D, 8'h0A}; - `SEND_MSG_BITS(msg) + for(int i=0; i<1000; i++) begin + msg = {"M1234", 8'h0D, 8'h0A}; + `SEND_MSG_BITS(msg); end + + // big reads + // for(logic[15:0] j=0; j<10; j++) begin + // msg = {$sformatf("M%H", j), 8'h0D, 8'h0A}; + // `SEND_MSG_BITS(msg) + // end + + // for(logic[15:0] j=0; j<10; j++) begin + // msg = {$sformatf("M%H", j), 8'h0D, 8'h0A}; + // `SEND_MSG_BITS(msg) + // end + + #(10*`CP); /* ==== Test 3 End ==== */ + /* ==== Test 4 Begin ==== */ + $display("\n=== test 4: 100 sequential writes, stress test ==="); + test_num = 4; + + for(int i=0; i<100; i++) begin + msg = {"M12345678", 8'h0D, 8'h0A}; + `SEND_MSG_BITS(msg); + end + + /* ==== Test 4 End ==== */ + + /* ==== Test 5 Begin ==== */ + $display("\n=== test 5: 100 sequential reads, stress test ==="); + test_num = 5; + + for(int i=0; i<100; i++) begin + msg = {"M1234", 8'h0D, 8'h0A}; + `SEND_MSG_BITS(msg); + end + + /* ==== Test 5 End ==== */ + + #(1000*`CP) diff --git a/test/bus_tb.sv b/test/bus_tb.sv deleted file mode 100644 index 6eb746c..0000000 --- a/test/bus_tb.sv +++ /dev/null @@ -1,233 +0,0 @@ -`default_nettype none -`timescale 1ns/1ps - -`define CP 10 -`define HCP 5 - -`define SEND_MSG_BITS(MSG) \ - for(int j=0; j < $size(msg); j++) begin \ - char = msg[j]; \ - for(int i=0; i < 10; i++) begin \ - if (i == 0) tb_urx_rxd = 0; \ - else if ((i > 0) & (i < 9)) tb_urx_rxd = char[i-1]; \ - else if (i == 9) tb_urx_rxd = 1; \ - #(10*`CP); \ - end \ - end \ - -module bus_tb; - // https://www.youtube.com/watch?v=WCOAr-96bGc - - //boilerplate - logic clk; - logic rst; - integer test_num; - string msg; - logic [7:0] char; - - // tb --> uart_rx signals - logic tb_urx_rxd; - uart_rx #( - .DATA_WIDTH(8), - .CLK_FREQ_HZ(100_000_000), - .BAUDRATE(10_000_000) - ) urx ( - .clk(clk), - .rst(rst), - .rxd(tb_urx_rxd), - - .axiod(urx_brx_axid), - .axiov(urx_brx_axiv)); - - // uart_rx --> bridge_rx signals - logic [7:0] urx_brx_axid; - logic urx_brx_axiv; - - bridge_rx brx ( - .clk(clk), - .axiid(urx_brx_axid), - .axiiv(urx_brx_axiv), - .req_addr(brx_mem_1_addr), - .req_data(brx_mem_1_wdata), - .req_rw(brx_mem_1_rw), - .req_valid(brx_mem_1_valid), - .req_ready(1'b1)); - - // bridge_rx --> mem_1 signals - logic [15:0] brx_mem_1_addr; - logic [15:0] brx_mem_1_wdata; - logic [15:0] brx_mem_1_rdata; - logic brx_mem_1_rw; - logic brx_mem_1_valid; - - assign brx_mem_1_rdata = 0; - - lut_mem #( - .DEPTH(8), - .BASE_ADDR(0) - ) mem_1 ( - .clk(clk), - .addr_i(brx_mem_1_addr), - .wdata_i(brx_mem_1_wdata), - .rdata_i(brx_mem_1_rdata), - .rw_i(brx_mem_1_rw), - .valid_i(brx_mem_1_valid), - - .addr_o(mem_1_mem_2_addr), - .wdata_o(mem_1_mem_2_wdata), - .rdata_o(mem_1_mem_2_rdata), - .rw_o(mem_1_mem_2_rw), - .valid_o(mem_1_mem_2_valid)); - - // mem_1 --> mem_2 signals - logic [15:0] mem_1_mem_2_addr; - logic [15:0] mem_1_mem_2_wdata; - logic [15:0] mem_1_mem_2_rdata; - logic mem_1_mem_2_rw; - logic mem_1_mem_2_valid; - - lut_mem #( - .DEPTH(8), - .BASE_ADDR(8) - ) mem_2 ( - .clk(clk), - .addr_i(mem_1_mem_2_addr), - .wdata_i(mem_1_mem_2_wdata), - .rdata_i(mem_1_mem_2_rdata), - .rw_i(mem_1_mem_2_rw), - .valid_i(mem_1_mem_2_valid), - - .addr_o(mem_2_mem_3_addr), - .wdata_o(mem_2_mem_3_wdata), - .rdata_o(mem_2_mem_3_rdata), - .rw_o(mem_2_mem_3_rw), - .valid_o(mem_2_mem_3_valid)); - - // mem_2 --> mem_3 signals - logic [15:0] mem_2_mem_3_addr; - logic [15:0] mem_2_mem_3_wdata; - logic [15:0] mem_2_mem_3_rdata; - logic mem_2_mem_3_rw; - logic mem_2_mem_3_valid; - - lut_mem #( - .DEPTH(8), - .BASE_ADDR(16) - ) mem_3 ( - .clk(clk), - .addr_i(mem_2_mem_3_addr), - .wdata_i(mem_2_mem_3_wdata), - .rdata_i(mem_2_mem_3_rdata), - .rw_i(mem_2_mem_3_rw), - .valid_i(mem_2_mem_3_valid), - - .addr_o(mem_3_btx_addr), - .wdata_o(mem_3_btx_wdata), - .rdata_o(mem_3_btx_rdata), - .rw_o(mem_3_btx_rw), - .valid_o(mem_3_btx_valid)); - - // mem_3 --> bridge_tx signals - logic [15:0] mem_3_btx_addr; - logic [15:0] mem_3_btx_wdata; - logic [15:0] mem_3_btx_rdata; - logic mem_3_btx_rw; - logic mem_3_btx_valid; - - bridge_tx btx ( - .clk(clk), - .axiod(btx_utx_axid), - .axiov(btx_utx_axiv), - .axior(btx_utx_axir), - - .res_data(mem_3_btx_rdata), - .res_valid(mem_3_btx_valid), - .res_ready()); - - // bridge_tx --> uart_tx signals - logic [7:0] btx_utx_axid; - logic btx_utx_axiv; - logic btx_utx_axir; - - uart_tx #( - .DATA_WIDTH(8), - .CLK_FREQ_HZ(100_000_000), - .BAUDRATE(10_000_000) - ) utx ( - .clk(clk), - .rst(rst), - - .axiid(btx_utx_axid), - .axiiv(btx_utx_axiv), - .axiir(btx_utx_axir), - .txd(utx_tb_txd)); - - // utx --> tb signals - logic utx_tb_txd; - - always begin - #`HCP - clk = !clk; - end - - initial begin - $dumpfile("bus.vcd"); - $dumpvars(0, bus_tb); - - // setup and reset - clk = 0; - rst = 0; - tb_urx_rxd = 1; - test_num = 0; - #`CP - rst = 1; - #`CP - rst = 0; - #`HCP - - // throw some nonzero data in the memories just so we know that we're pulling from the right ones - mem_1.mem[0] = 16'h0000; - mem_1.mem[1] = 16'h0001; - mem_1.mem[2] = 16'h0002; - mem_1.mem[3] = 16'h0003; - mem_1.mem[4] = 16'h0004; - mem_1.mem[5] = 16'h0005; - mem_1.mem[6] = 16'h0006; - mem_1.mem[7] = 16'h0007; - - mem_2.mem[0] = 16'h0008; - mem_2.mem[1] = 16'h0009; - mem_2.mem[2] = 16'h000A; - mem_2.mem[3] = 16'h000B; - mem_2.mem[4] = 16'h000C; - mem_2.mem[5] = 16'h000D; - mem_2.mem[6] = 16'h000E; - mem_2.mem[7] = 16'h000F; - - mem_3.mem[0] = 16'h0010; - mem_3.mem[1] = 16'h0011; - mem_3.mem[2] = 16'h0012; - mem_3.mem[3] = 16'h0013; - mem_3.mem[4] = 16'h0014; - mem_3.mem[5] = 16'h0015; - mem_3.mem[6] = 16'h0016; - mem_3.mem[7] = 16'h0017; - #(10*`CP); - - /* ==== Test 1 Begin ==== */ - $display("\n=== test 1: read from 0x0001 for baseline functionality ==="); - test_num = 1; - - #(10*`CP); - /* ==== Test 1 End ==== */ - - msg = {"M12345678", 8'h0D, 8'h0A}; - `SEND_MSG_BITS(msg) - - #(1000*`CP) - - $finish(); - end -endmodule - -`default_nettype wire \ No newline at end of file diff --git a/test/lut_mem.gtkw b/test/lut_mem.gtkw deleted file mode 100644 index b7a4bf5..0000000 --- a/test/lut_mem.gtkw +++ /dev/null @@ -1,69 +0,0 @@ -[*] -[*] GTKWave Analyzer v3.3.107 (w)1999-2020 BSI -[*] Tue Feb 28 23:16:04 2023 -[*] -[dumpfile] "/Users/fischerm/fpga/manta/lut_mem.vcd" -[dumpfile_mtime] "Tue Feb 28 23:14:40 2023" -[dumpfile_size] 5873 -[savefile] "/Users/fischerm/fpga/manta/lut_mem.gtkw" -[timestart] 96500000000000 -[size] 1710 994 -[pos] -1 -1 -*-46.420933 115000000000000 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -[treeopen] lut_mem_tb. -[sst_width] 193 -[signals_width] 517 -[sst_expanded] 1 -[sst_vpaned_height] 305 -@28 -lut_mem_tb.clk -@420 -lut_mem_tb.test_num -@200 -- --tb --> mem_1 -@29 -lut_mem_tb.tb_mem_1_valid -@22 -lut_mem_tb.tb_mem_1_addr[15:0] -lut_mem_tb.tb_mem_1_wdata[15:0] -lut_mem_tb.tb_mem_1_rdata[15:0] -@28 -lut_mem_tb.tb_mem_1_rw -@200 -- --mem_1 --> mem_2 -@28 -lut_mem_tb.mem_1_mem_2_valid -@22 -lut_mem_tb.mem_1_mem_2_addr[15:0] -lut_mem_tb.mem_1_mem_2_wdata[15:0] -lut_mem_tb.mem_1_mem_2_rdata[15:0] -@28 -lut_mem_tb.mem_1_mem_2_rw -@200 -- -- --mem_2 --> mem_3 -@28 -lut_mem_tb.mem_2_mem_3_valid -@22 -lut_mem_tb.mem_2_mem_3_addr[15:0] -lut_mem_tb.mem_2_mem_3_wdata[15:0] -lut_mem_tb.mem_2_mem_3_rdata[15:0] -@28 -lut_mem_tb.mem_2_mem_3_rw -@200 -- -- --mem_3 --> tb -@28 -lut_mem_tb.mem_3_tb_valid -@22 -lut_mem_tb.mem_3_tb_addr[15:0] -lut_mem_tb.mem_3_tb_wdata[15:0] -lut_mem_tb.mem_3_tb_rdata[15:0] -@28 -lut_mem_tb.mem_3_tb_rw -[pattern_trace] 1 -[pattern_trace] 0 diff --git a/test/uart_tx_tb.sv b/test/uart_tx_tb.sv index f81cb2b..316c54e 100644 --- a/test/uart_tx_tb.sv +++ b/test/uart_tx_tb.sv @@ -1,48 +1,110 @@ `default_nettype none - `timescale 1ns / 1ps +`define CP 10 +`define HCP 5 + module uart_tx_tb(); logic clk; - logic rst; - logic [7:0] data; - logic start; - logic busy; - logic txd; + logic [7:0] tb_utx_data; + logic tb_utx_valid; + logic utx_tb_busy; - uart_tx #( - .DATA_WIDTH(8), - .CLK_FREQ_HZ(100_000_000), - .BAUDRATE(115200)) - uut ( + logic utx_tb_tx; + + uart_tx #(.CLOCKS_PER_BAUD(10)) utx ( .clk(clk), - .rst(rst), - .data(data), - .start(start), - .busy(busy), - .txd(txd)); + .data(tb_utx_data), + .valid(tb_utx_valid), + .busy(utx_tb_busy), + + .tx(utx_tb_tx)); + + + logic zcpu_tb_tx; + logic zcpu_tb_busy; + + tx_uart #(.CLOCKS_PER_BAUD(10)) zcpu_utx ( + .i_clk(clk), + + .i_wr(tb_utx_valid), + .i_data(tb_utx_data), + + .o_uart_tx(zcpu_tb_tx), + .o_busy(zcpu_tb_busy)); + + logic zcpu_urx_valid; + logic[7:0] zcpu_urx_data; + + rx_uart #(.CLOCKS_PER_BAUD(10)) zcpu_urx ( + .i_clk(clk), + + .i_uart_rx(utx_tb_tx), + .o_wr(zcpu_urx_valid), + .o_data(zcpu_urx_data)); always begin - #5; + #`HCP clk = !clk; end initial begin - $dumpfile("uart_tx.vcd"); - $dumpvars(0, uart_tx_tb); + $dumpfile("uart_tx.vcd"); + $dumpvars(0, uart_tx_tb); clk = 0; - rst = 1; - start = 0; - #10; - rst = 0; - data = 'h0F; - #10; - start = 1; - #10; - start = 0; - #150000; + tb_utx_data = 0; + tb_utx_valid = 0; + #`HCP; + + #(10*`CP); + + $display("send a byte"); + tb_utx_data = 8'h69; + tb_utx_valid = 1; + #`CP; + tb_utx_valid = 0; + + #(150*`CP); + + $display("send another byte"); + tb_utx_data = 8'h42; + tb_utx_valid = 1; + #`CP; + tb_utx_valid = 0; + + #(150*`CP); + + $display("send two bytes back to back"); + tb_utx_data = 8'h69; + tb_utx_valid = 1; + #`CP; + tb_utx_valid = 0; + + #(99*`CP); + + tb_utx_data = 8'h42; + tb_utx_valid = 1; + #`CP; + tb_utx_valid = 0; + + #(150*`CP); + + $display("send two bytes back to back, but keep valid asserted"); + tb_utx_data = 8'h69; + tb_utx_valid = 1; + #`CP; + + #(99*`CP); + + tb_utx_data = 8'h42; + tb_utx_valid = 1; + #`CP; + tb_utx_valid = 0; + + #(150*`CP); + $finish(); end endmodule diff --git a/test/yeet_tb.sv b/test/yeet_tb.sv new file mode 100644 index 0000000..b9359c6 --- /dev/null +++ b/test/yeet_tb.sv @@ -0,0 +1,93 @@ +`default_nettype none +`timescale 1ns/1ps + +`define CP 10 +`define HCP 5 + +module yeet_tb(); + logic clk; + + logic [15:0] tb_btx_rdata; + logic tb_btx_rw; + logic tb_btx_valid; + + bridge_tx btx ( + .clk(clk), + + .rdata_i(tb_btx_rdata), + .rw_i(tb_btx_rw), + .valid_i(tb_btx_valid), + + .ready_i(utx_btx_ready), + .data_o(btx_utx_data), + .valid_o(btx_utx_valid)); + + logic [7:0] btx_utx_data; + logic btx_utx_valid; + logic utx_btx_ready; + + uart_tx #(.CLOCKS_PER_BAUD(10)) utx ( + .clk(clk), + + .data(btx_utx_data), + .valid(btx_utx_valid), + .ready(utx_btx_ready), + + .tx(utx_tb_tx)); + + logic utx_tb_tx; + + logic [7:0] decoded_byte; + logic decoder_valid; + logic [7:0] decoder_data; + + always @(posedge clk) if (decoder_valid) decoded_byte <= decoder_data; + + rx_uart #(.CLOCKS_PER_BAUD(10)) urx_decoder( + .i_clk(clk), + + .i_uart_rx(utx_tb_tx), + .o_wr(decoder_valid), + .o_data(decoder_data)); + + always begin + #`HCP + clk = !clk; + end + + initial begin + $dumpfile("yeet.vcd"); + $dumpvars(0, yeet_tb); + clk = 0; + tb_btx_rdata = 0; + tb_btx_valid = 0; + tb_btx_rw = 0; + #`HCP + + #(10*`CP); + + // put some shit on the bus + tb_btx_rdata = 16'h69; + tb_btx_valid = 1; + tb_btx_rw = 0; + #`CP + tb_btx_valid = 0; + + // wait a bit + #(7000 - `CP); + + // put some more shit on the bus + tb_btx_rdata = 16'h42; + tb_btx_valid = 1; + tb_btx_rw = 1; + #`CP + tb_btx_valid = 0; + #(7000 - `CP); + + $finish(); + + end + +endmodule + +`default_nettype wire \ No newline at end of file