Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
142 changes: 142 additions & 0 deletions tests/sumi/umi_mux/tb_umi_mux.v
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
module tb_umi_mux
#(parameter DW = 128,
parameter CW = 32,
parameter AW = 32
)
(// controls
input clk,
input nreset,
input [1:0] arbmode,
input [7:0] arbmask,
// UMI input 0
input umi_in0_valid,
input [CW-1:0] umi_in0_cmd,
input [AW-1:0] umi_in0_dstaddr,
input [AW-1:0] umi_in0_srcaddr,
input [DW-1:0] umi_in0_data,
output umi_in0_ready,
// UMI input 1
input umi_in1_valid,
input [CW-1:0] umi_in1_cmd,
input [AW-1:0] umi_in1_dstaddr,
input [AW-1:0] umi_in1_srcaddr,
input [DW-1:0] umi_in1_data,
output umi_in1_ready,
// UMI input 2
input umi_in2_valid,
input [CW-1:0] umi_in2_cmd,
input [AW-1:0] umi_in2_dstaddr,
input [AW-1:0] umi_in2_srcaddr,
input [DW-1:0] umi_in2_data,
output umi_in2_ready,
// UMI input 3
input umi_in3_valid,
input [CW-1:0] umi_in3_cmd,
input [AW-1:0] umi_in3_dstaddr,
input [AW-1:0] umi_in3_srcaddr,
input [DW-1:0] umi_in3_data,
output umi_in3_ready,
// UMI input 4
input umi_in4_valid,
input [CW-1:0] umi_in4_cmd,
input [AW-1:0] umi_in4_dstaddr,
input [AW-1:0] umi_in4_srcaddr,
input [DW-1:0] umi_in4_data,
output umi_in4_ready,
// UMI input 5
input umi_in5_valid,
input [CW-1:0] umi_in5_cmd,
input [AW-1:0] umi_in5_dstaddr,
input [AW-1:0] umi_in5_srcaddr,
input [DW-1:0] umi_in5_data,
output umi_in5_ready,
// UMI input 6
input umi_in6_valid,
input [CW-1:0] umi_in6_cmd,
input [AW-1:0] umi_in6_dstaddr,
input [AW-1:0] umi_in6_srcaddr,
input [DW-1:0] umi_in6_data,
output umi_in6_ready,
// UMI input 7
input umi_in7_valid,
input [CW-1:0] umi_in7_cmd,
input [AW-1:0] umi_in7_dstaddr,
input [AW-1:0] umi_in7_srcaddr,
input [DW-1:0] umi_in7_data,
output umi_in7_ready,
// outgoing UMI
output umi_out_valid,
output [CW-1:0] umi_out_cmd,
output [AW-1:0] umi_out_dstaddr,
output [AW-1:0] umi_out_srcaddr,
output [DW-1:0] umi_out_data,
input umi_out_ready
);

umi_mux #(.N(8),
.DW(DW),
.CW(CW),
.AW(AW))
umi_mux_i (// controls
.clk (clk),
.nreset (nreset),
.arbmode (arbmode[1:0]),
.arbmask (arbmask[7:0]),
// incoming UMI (concatenated, index 0 at LSB)
.umi_in_valid ({umi_in7_valid,
umi_in6_valid,
umi_in5_valid,
umi_in4_valid,
umi_in3_valid,
umi_in2_valid,
umi_in1_valid,
umi_in0_valid}),
.umi_in_cmd ({umi_in7_cmd,
umi_in6_cmd,
umi_in5_cmd,
umi_in4_cmd,
umi_in3_cmd,
umi_in2_cmd,
umi_in1_cmd,
umi_in0_cmd}),
.umi_in_dstaddr ({umi_in7_dstaddr,
umi_in6_dstaddr,
umi_in5_dstaddr,
umi_in4_dstaddr,
umi_in3_dstaddr,
umi_in2_dstaddr,
umi_in1_dstaddr,
umi_in0_dstaddr}),
.umi_in_srcaddr ({umi_in7_srcaddr,
umi_in6_srcaddr,
umi_in5_srcaddr,
umi_in4_srcaddr,
umi_in3_srcaddr,
umi_in2_srcaddr,
umi_in1_srcaddr,
umi_in0_srcaddr}),
.umi_in_data ({umi_in7_data,
umi_in6_data,
umi_in5_data,
umi_in4_data,
umi_in3_data,
umi_in2_data,
umi_in1_data,
umi_in0_data}),
.umi_in_ready ({umi_in7_ready,
umi_in6_ready,
umi_in5_ready,
umi_in4_ready,
umi_in3_ready,
umi_in2_ready,
umi_in1_ready,
umi_in0_ready}),
// outgoing UMI
.umi_out_valid (umi_out_valid),
.umi_out_cmd (umi_out_cmd),
.umi_out_dstaddr(umi_out_dstaddr),
.umi_out_srcaddr(umi_out_srcaddr),
.umi_out_data (umi_out_data),
.umi_out_ready (umi_out_ready));

endmodule
155 changes: 155 additions & 0 deletions tests/sumi/umi_mux/test_umi_mux.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
import os
import random
from pathlib import Path
import pytest

from siliconcompiler import Design
from umi.sumi.umi_mux.umi_mux import Mux

import cocotb
from cocotb.clock import Clock
from cocotb.triggers import ClockCycles, Timer

from cocotb_bus.drivers import BitDriver
from cocotbext.umi.sumi import SumiCmd, SumiCmdType, SumiTransaction
from cocotbext.umi.drivers.sumi_driver import SumiDriver
from cocotbext.umi.monitors.sumi_monitor import SumiMonitor

from cocotbext.umi.utils.generators import (
random_toggle_generator,
wave_generator
)


@cocotb.test(timeout_time=20, timeout_unit="us")
@cocotb.parametrize(
input_valid_gen=[None, random_toggle_generator(), wave_generator()],
output_ready_gen=[None, random_toggle_generator(), wave_generator()],
test_n_transactions=[int(100 * float(os.getenv("RAND_TEST_LEN_SCALER", default=1)))],
arbmode=[0, 1]
)
async def mux_general_test(
dut,
arbmode=0,
test_n_transactions=100,
input_valid_gen=None,
output_ready_gen=None
):

umi_inputs = int(dut.umi_mux_i.N.value)
data_size = int(dut.DW.value)//8
aw = int(dut.AW.value)

dut.clk.value = 0
dut.nreset.value = 0

dut.arbmode.value = arbmode
dut.arbmask.value = 0

####################################
# Create UMI Input Drivers
####################################
umi_drivers = [
SumiDriver(
entity=dut,
name=f"umi_in{i}",
clock=dut.clk,
valid_generator=input_valid_gen
)
for i in range(umi_inputs)
]

####################################
# Create UMI mux output monitor
####################################
umi_monitor = SumiMonitor(
entity=dut,
name="umi_out",
clock=dut.clk
)

# Drive UMI out ready signal
if output_ready_gen is None:
dut.umi_out_ready.value = 1
else:
BitDriver(signal=dut.umi_out_ready, clk=dut.clk).start(generator=output_ready_gen)

# Reset sequence (active-low reset)
dut.nreset.value = 1
await Timer(1, unit="step")
dut.nreset.value = 0
await Timer(10, unit="ns")
dut.nreset.value = 1
await Timer(10, unit="ns")

# Start clock
Clock(dut.clk, 1, unit="ns").start()

expected_trans = []
actual_trans = []

# Monitor appends received transactions to actual_trans
umi_monitor.add_callback(lambda trans: actual_trans.append(trans))

# Callback so that transactions are added to expected_trans
# in the order that they are sent
def transaction_sent_callback(trans: SumiTransaction):
expected_trans.append(trans)

expected_trans_cnt = 0
for umi_driver in umi_drivers:
# Create random transactions
transactions = [
SumiTransaction(
cmd=SumiCmd.from_fields(
cmd_type=int(SumiCmdType.UMI_REQ_WRITE),
size=1,
len=data_size
),
addr_width=aw,
da=random.randint(0, (1 << aw) - 1),
sa=random.randint(0, (1 << aw) - 1),
data=random.randbytes(data_size)
)
for _ in range(test_n_transactions + random.randint(0, 10))
]
for t in transactions:
umi_driver.append(t, callback=transaction_sent_callback)
expected_trans_cnt += len(transactions)

# Wait for all transactions to be received
while len(actual_trans) != expected_trans_cnt:
await ClockCycles(dut.clk, 10)

# Verify expected output equals actual
for expected, actual in zip(expected_trans, actual_trans):
assert expected == actual


class TbDesign(Design):

def __init__(self):
super().__init__()

self.set_name("tb_umi_mux")

self.set_dataroot("tb_umi_mux", __file__)

with self.active_dataroot("tb_umi_mux"):
with self.active_fileset("testbench.cocotb"):
self.set_topmodule("tb_umi_mux")
self.add_file("tb_umi_mux.v")
self.add_file(Path(__file__).name, filetype="python")
self.add_depfileset(Mux(), "rtl")


@pytest.mark.cocotb
@pytest.mark.parametrize("simulator", ["icarus", "verilator"])
def test_umi_mux_cocotb(simulator):
from run_cocotb_sim import load_cocotb_test
load_cocotb_test(
design=TbDesign(),
simulator=simulator,
trace=False,
seed=None
)
30 changes: 8 additions & 22 deletions umi/sumi/umi_mux/rtl/umi_mux.v
Original file line number Diff line number Diff line change
Expand Up @@ -31,12 +31,12 @@ module umi_mux
input [1:0] arbmode, // arbiter mode (0=fixed)
input [N-1:0] arbmask, // arbiter mask (1=input is masked)
// incoming UMI
input [N-1:0] umi_in_valid,
input [N*CW-1:0] umi_in_cmd,
input [N*AW-1:0] umi_in_dstaddr,
input [N*AW-1:0] umi_in_srcaddr,
input [N*DW-1:0] umi_in_data,
output reg [N-1:0] umi_in_ready,
input [N-1:0] umi_in_valid,
input [N*CW-1:0] umi_in_cmd,
input [N*AW-1:0] umi_in_dstaddr,
input [N*AW-1:0] umi_in_srcaddr,
input [N*DW-1:0] umi_in_data,
output [N-1:0] umi_in_ready,
// outgoing UMI
output umi_out_valid,
output [CW-1:0] umi_out_cmd,
Expand Down Expand Up @@ -68,22 +68,8 @@ module umi_mux
// Ready
//##############################


// valid[j] | out_ready[j] | grant[j] | in_ready
//------------------------------------------------
// 0 x x | 1
// 1 0 x | 0
// 1 1 0 | 0
// 1 1 1 | 1

integer j;
always @(*)
begin
umi_in_ready[N-1:0] = {N{1'b1}};
for (j=0;j<N;j=j+1)
umi_in_ready[j] = umi_in_ready[j] & ~(umi_in_valid[j] &
(~grants[j] | ~umi_out_ready));
end
// Allow umi_out_ready to propagate to the umi port currently granted access
assign umi_in_ready[N-1:0] = grants[N-1:0] & {N{umi_out_ready}};
Comment thread
RiceShelley marked this conversation as resolved.

//##############################
// Output Mux
Expand Down
Loading