From 52bc62814e877e7715fd7d42d07e2cae448dac34 Mon Sep 17 00:00:00 2001 From: Sean Anderson Date: Mon, 6 Mar 2023 22:00:41 -0500 Subject: [PATCH] Add wishbone register This module registers all signals on a wishbone bus. This increases latency/decreases throughput, but the wishbone cores here are just for management, so that's not really critical. Signed-off-by: Sean Anderson --- Makefile | 1 + README.adoc | 5 ++++ rtl/wb_reg.v | 52 ++++++++++++++++++++++++++++++++++++++++ tb/wb_reg.py | 68 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 126 insertions(+) create mode 100644 rtl/wb_reg.v create mode 100644 tb/wb_reg.py diff --git a/Makefile b/Makefile index 5a4defc..94ece91 100644 --- a/Makefile +++ b/Makefile @@ -154,6 +154,7 @@ MODULES += uart_tx MODULES += uart_rx MODULES += uart_wb_bridge MODULES += wb_mux +MODULES += wb_reg .PHONY: test test: $(addsuffix .fst,$(MODULES)) $(addsuffix .synth.fst,$(MODULES)) diff --git a/README.adoc b/README.adoc index a8fdad6..e30fab0 100644 --- a/README.adoc +++ b/README.adoc @@ -241,6 +241,11 @@ This implements a simple Wishbone mux, allowing a single master to access several slaves. The address decoding is greatly simplified by assigning each slave a (priority-decoded) address bit. +=== `wb_reg` + +Add a register stage to a wishbone bus. This helps improve timing, but will add +a cycle of latency (and decrease throughput). + == Interfaces Throughout this project, a variety of interfaces, some standard and some diff --git a/rtl/wb_reg.v b/rtl/wb_reg.v new file mode 100644 index 0000000..33031a6 --- /dev/null +++ b/rtl/wb_reg.v @@ -0,0 +1,52 @@ +// SPDX-License-Identifier: AGPL-3.0-Only +/* + * Copyright (C) 2023 Sean Anderson + */ + +`include "common.vh" + +module wb_reg ( + input clk, rst, + + output reg s_ack, s_err, + input s_cyc, s_stb, s_we, + input [ADDR_WIDTH - 1:0] s_addr, + input [DATA_WIDTH - 1:0] s_data_write, + output reg [DATA_WIDTH - 1:0] s_data_read, + + input m_ack, m_err, + output reg m_cyc, m_stb, m_we, + output reg [ADDR_WIDTH - 1:0] m_addr, + output reg [DATA_WIDTH - 1:0] m_data_write, + input [DATA_WIDTH - 1:0] m_data_read +); + + parameter ADDR_WIDTH = 16; + parameter DATA_WIDTH = 16; + + initial begin + s_ack = 0; + s_err = 0; + m_cyc = 0; + m_stb = 0; + end + + always @(posedge clk) begin + if (rst) begin + s_ack <= 0; + s_err <= 0; + m_cyc <= 0; + m_stb <= 0; + end else begin + s_ack <= m_ack && s_cyc && s_stb; + s_err <= m_err && s_cyc && s_stb; + m_cyc <= s_cyc && !(m_ack || m_err); + m_stb <= s_stb && !(m_ack || m_err); + end + s_data_read <= m_data_read; + m_we <= s_we; + m_addr <= s_addr; + m_data_write <= s_data_write; + end + +endmodule diff --git a/tb/wb_reg.py b/tb/wb_reg.py new file mode 100644 index 0000000..bfc6df5 --- /dev/null +++ b/tb/wb_reg.py @@ -0,0 +1,68 @@ +# SPDX-License-Identifier: AGPL-3.0-Only +# Copyright (C) 2023 Sean Anderson + +import cocotb +from cocotb.binary import BinaryValue +from cocotb.clock import Clock +from cocotb.triggers import FallingEdge, RisingEdge, Timer + +from .mdio import wb_read, wb_write, wb_err +from .mdio_regs import wb_xfer + +@cocotb.test(timeout_time=50, timeout_unit='us') +async def test_reg(reg): + reg.clk.value = BinaryValue('Z') + reg.rst.value = 0 + reg.s_cyc.value = 1 + reg.s_stb.value = 0 + reg.m_ack.value = 0 + reg.m_err.value = 0 + + await Timer(1) + await cocotb.start(Clock(reg.clk, 8, units='ns').start()) + await FallingEdge(reg.clk) + + master = { + 'clk': reg.clk, + 'ack': reg.m_ack, + 'err': reg.m_err, + 'cyc': reg.m_cyc, + 'stb': reg.m_stb, + 'we': reg.m_we, + 'addr': reg.m_addr, + 'data_write': reg.m_data_write, + 'data_read': reg.m_data_read, + } + + slave = { + 'clk': reg.clk, + 'ack': reg.s_ack, + 'err': reg.s_err, + 'cyc': reg.s_cyc, + 'stb': reg.s_stb, + 'we': reg.s_we, + 'addr': reg.s_addr, + 'data_write': reg.s_data_write, + 'data_read': reg.s_data_read, + } + + async def resp(): + await wb_read(master, 0x0123, 0x4567) + await wb_write(master, 0x89ab, 0xcdef) + await wb_err(master) + + await cocotb.start(resp()) + + assert await wb_xfer(slave, 0x0123) == 0x4567 + await wb_xfer(slave, 0x89ab, 0xcdef) + assert await wb_xfer(slave, 0xdead) is None + + reg.rst.value = 1 + reg.s_cyc.value = 1 + reg.m_ack.value = 1 + reg.m_err.value = 1 + await FallingEdge(reg.clk) + assert not reg.m_cyc.value + assert not reg.m_stb.value + assert not reg.s_ack.value + assert not reg.s_err.value