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 <seanga2@gmail.com>
This commit is contained in:
Sean Anderson 2023-03-06 22:00:41 -05:00
parent db4c225db5
commit 52bc62814e
4 changed files with 126 additions and 0 deletions

View File

@ -154,6 +154,7 @@ MODULES += uart_tx
MODULES += uart_rx MODULES += uart_rx
MODULES += uart_wb_bridge MODULES += uart_wb_bridge
MODULES += wb_mux MODULES += wb_mux
MODULES += wb_reg
.PHONY: test .PHONY: test
test: $(addsuffix .fst,$(MODULES)) $(addsuffix .synth.fst,$(MODULES)) test: $(addsuffix .fst,$(MODULES)) $(addsuffix .synth.fst,$(MODULES))

View File

@ -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 several slaves. The address decoding is greatly simplified by assigning each
slave a (priority-decoded) address bit. 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 == Interfaces
Throughout this project, a variety of interfaces, some standard and some Throughout this project, a variety of interfaces, some standard and some

52
rtl/wb_reg.v Normal file
View File

@ -0,0 +1,52 @@
// SPDX-License-Identifier: AGPL-3.0-Only
/*
* Copyright (C) 2023 Sean Anderson <seanga2@gmail.com>
*/
`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

68
tb/wb_reg.py Normal file
View File

@ -0,0 +1,68 @@
# 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 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