Add UART-WIshbone bridge
Add a basic bridge for debugging. It's around 50% efficient, but this could be increased to 66% with the addition of some FIFOs. The limiting factor is the constant overhead of the request/status bytes. If we used a wider bus, we could get better efficiency. Signed-off-by: Sean Anderson <seanga2@gmail.com>
This commit is contained in:
parent
2c2527e8d9
commit
5f331a403c
1
Makefile
1
Makefile
|
@ -149,6 +149,7 @@ MODULES += pmd_dp83223_rx
|
||||||
MODULES += scramble
|
MODULES += scramble
|
||||||
MODULES += uart_tx
|
MODULES += uart_tx
|
||||||
MODULES += uart_rx
|
MODULES += uart_rx
|
||||||
|
MODULES += uart_wb_bridge
|
||||||
MODULES += wb_mux
|
MODULES += wb_mux
|
||||||
|
|
||||||
.PHONY: test
|
.PHONY: test
|
||||||
|
|
|
@ -220,6 +220,15 @@ A standard UART receive module, outputting AXI-stream. 8n1 only. Supports
|
||||||
115,200 and 4,000,000 baud. Properly detects breaks as (single) frame errors,
|
115,200 and 4,000,000 baud. Properly detects breaks as (single) frame errors,
|
||||||
and ignores runt start bits.
|
and ignores runt start bits.
|
||||||
|
|
||||||
|
=== `uart_wb_bridge`
|
||||||
|
|
||||||
|
This module combines the above UART cores with the AXI-stream bridge from before
|
||||||
|
to allow controlling a Wishbone bus over a UART. There is no internal buffering,
|
||||||
|
but some FIFOs could easily be added to allow more in-flight transactions. At
|
||||||
|
the moment this only supports 16 data busses with 16-bit granularity. Frame
|
||||||
|
errors (breaks) reset the bridge (but not the UARTs), providing an "`out of
|
||||||
|
band`" ability for synchronization.
|
||||||
|
|
||||||
=== `wb_mux`
|
=== `wb_mux`
|
||||||
|
|
||||||
This implements a simple Wishbone mux, allowing a single master to access
|
This implements a simple Wishbone mux, allowing a single master to access
|
||||||
|
|
|
@ -0,0 +1,81 @@
|
||||||
|
// SPDX-License-Identifier: AGPL-3.0-Only
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2023 Sean Anderson <seanga2@gmail.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
`include "common.vh"
|
||||||
|
|
||||||
|
module uart_wb_bridge (
|
||||||
|
input clk,
|
||||||
|
input rst,
|
||||||
|
|
||||||
|
/* UART */
|
||||||
|
input rx,
|
||||||
|
output tx,
|
||||||
|
|
||||||
|
/* Wishbone */
|
||||||
|
output wb_rst,
|
||||||
|
input wb_ack, wb_err,
|
||||||
|
output wb_cyc, wb_stb, wb_we,
|
||||||
|
output [ADDR_WIDTH - 1:0] wb_addr,
|
||||||
|
output [DATA_WIDTH - 1:0] wb_data_write,
|
||||||
|
input [DATA_WIDTH - 1:0] wb_data_read,
|
||||||
|
|
||||||
|
input high_speed
|
||||||
|
);
|
||||||
|
|
||||||
|
parameter ADDR_WIDTH = 16;
|
||||||
|
localparam DATA_WIDTH = 16;
|
||||||
|
|
||||||
|
wire rx_ready, rx_valid;
|
||||||
|
wire [7:0] rx_data;
|
||||||
|
wire overflow;
|
||||||
|
|
||||||
|
uart_rx uart_rx (
|
||||||
|
.clk(clk),
|
||||||
|
.rst(rst),
|
||||||
|
.rx(rx),
|
||||||
|
.ready(rx_ready),
|
||||||
|
.valid(rx_valid),
|
||||||
|
.data(rx_data),
|
||||||
|
.high_speed(high_speed),
|
||||||
|
.overflow(overflow),
|
||||||
|
.frame_error(wb_rst)
|
||||||
|
);
|
||||||
|
|
||||||
|
wire tx_ready, tx_valid;
|
||||||
|
wire [7:0] tx_data;
|
||||||
|
|
||||||
|
axis_wb_bridge #(
|
||||||
|
.ADDR_WIDTH(ADDR_WIDTH)
|
||||||
|
) bridge (
|
||||||
|
.clk(clk),
|
||||||
|
.rst(rst || wb_rst),
|
||||||
|
.s_axis_ready(rx_ready),
|
||||||
|
.s_axis_valid(rx_valid),
|
||||||
|
.s_axis_data(rx_data),
|
||||||
|
.m_axis_ready(tx_ready),
|
||||||
|
.m_axis_valid(tx_valid),
|
||||||
|
.m_axis_data(tx_data),
|
||||||
|
.wb_ack(wb_ack),
|
||||||
|
.wb_err(wb_err),
|
||||||
|
.wb_cyc(wb_cyc),
|
||||||
|
.wb_stb(wb_stb),
|
||||||
|
.wb_we(wb_we),
|
||||||
|
.wb_addr(wb_addr),
|
||||||
|
.wb_data_write(wb_data_write),
|
||||||
|
.wb_data_read(wb_data_read),
|
||||||
|
.overflow(overflow)
|
||||||
|
);
|
||||||
|
|
||||||
|
uart_tx uart_tx (
|
||||||
|
.clk(clk),
|
||||||
|
.rst(rst),
|
||||||
|
.tx(tx),
|
||||||
|
.ready(tx_ready),
|
||||||
|
.valid(tx_valid),
|
||||||
|
.data(tx_data),
|
||||||
|
.high_speed(high_speed)
|
||||||
|
);
|
||||||
|
|
||||||
|
endmodule
|
|
@ -0,0 +1,79 @@
|
||||||
|
# SPDX-License-Identifier: AGPL-3.0-Only
|
||||||
|
# Copyright (C) 2023 Sean Anderson <seanga2@gmail.com>
|
||||||
|
|
||||||
|
import cocotb
|
||||||
|
from cocotb.binary import BinaryValue
|
||||||
|
from cocotb.clock import Clock
|
||||||
|
from cocotb.triggers import Event, FallingEdge, Timer
|
||||||
|
|
||||||
|
from .axis_wb_bridge import Encoder, STATUS_WE
|
||||||
|
from .mdio import wb_read, wb_write, wb_err
|
||||||
|
from .uart_rx import putchar, BIT_STEPS
|
||||||
|
from .uart_tx import getchar
|
||||||
|
|
||||||
|
@cocotb.test(timeout_time=100, timeout_unit='us')
|
||||||
|
async def test_bridge(bridge):
|
||||||
|
bridge.clk.value = BinaryValue('Z')
|
||||||
|
bridge.rst.value = 1
|
||||||
|
bridge.rx.value = 1
|
||||||
|
bridge.wb_ack.value = 0
|
||||||
|
bridge.wb_err.value = 0
|
||||||
|
bridge.high_speed.value = 1
|
||||||
|
|
||||||
|
await Timer(1)
|
||||||
|
bridge.rst.value = 0
|
||||||
|
await cocotb.start(Clock(bridge.clk, 8, units='ns').start())
|
||||||
|
await FallingEdge(bridge.clk)
|
||||||
|
|
||||||
|
wb = {
|
||||||
|
'clk': bridge.clk,
|
||||||
|
'ack': bridge.wb_ack,
|
||||||
|
'err': bridge.wb_err,
|
||||||
|
'cyc': bridge.wb_cyc,
|
||||||
|
'stb': bridge.wb_stb,
|
||||||
|
'we': bridge.wb_we,
|
||||||
|
'addr': bridge.wb_addr,
|
||||||
|
'data_write': bridge.wb_data_write,
|
||||||
|
'data_read': bridge.wb_data_read,
|
||||||
|
}
|
||||||
|
|
||||||
|
e = Encoder()
|
||||||
|
recv_ready = Event()
|
||||||
|
|
||||||
|
async def send_break():
|
||||||
|
bridge.rx.value = 0
|
||||||
|
await Timer(BIT_STEPS * 20)
|
||||||
|
bridge.rx.value = 1
|
||||||
|
await Timer(BIT_STEPS)
|
||||||
|
|
||||||
|
async def send():
|
||||||
|
for c in e.encode(0x0123, 0x4567):
|
||||||
|
await putchar(bridge.rx, c)
|
||||||
|
|
||||||
|
# Start a read
|
||||||
|
await recv_ready.wait()
|
||||||
|
await putchar(bridge.rx, e.encode(0xdead)[0])
|
||||||
|
# Cancel it
|
||||||
|
await send_break()
|
||||||
|
|
||||||
|
# And do another read
|
||||||
|
e.last_addr = None
|
||||||
|
for c in e.encode(0x89ab):
|
||||||
|
await putchar(bridge.rx, c)
|
||||||
|
|
||||||
|
await cocotb.start(send())
|
||||||
|
await cocotb.start(wb_write(wb, 0x0123, 0x4567))
|
||||||
|
|
||||||
|
uart = {
|
||||||
|
'clk': bridge.clk,
|
||||||
|
'tx': bridge.tx,
|
||||||
|
}
|
||||||
|
|
||||||
|
assert await getchar(uart) == STATUS_WE
|
||||||
|
|
||||||
|
recv_ready.set()
|
||||||
|
await cocotb.start(wb_read(wb, 0x89ab, 0xcdef))
|
||||||
|
|
||||||
|
assert await getchar(uart) == 0
|
||||||
|
assert await getchar(uart) == 0xcd
|
||||||
|
assert await getchar(uart) == 0xef
|
Loading…
Reference in New Issue