add working example for macOS bug
This commit is contained in:
parent
a70ba2d0a8
commit
e022696b31
|
|
@ -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()
|
||||
|
||||
|
|
@ -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}")
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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}")
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
);
|
||||
*/
|
||||
|
||||
|
||||
|
|
@ -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
|
||||
101
test/bus.gtkw
101
test/bus.gtkw
|
|
@ -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
|
||||
|
|
@ -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)
|
||||
|
||||
233
test/bus_tb.sv
233
test/bus_tb.sv
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
Loading…
Reference in New Issue