Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

switchboard 0.0.17 SB-447 SB-450 SB-451 SB-452 #100

Merged
merged 12 commits into from
Aug 31, 2023
4 changes: 2 additions & 2 deletions examples/dependencies.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
{
"name": "umi",
"url": "git@github.com:zeroasiccorp/umi.git",
"commit": "f85d0cc"
"commit": "55aa6d9c6d7826ac4fea377efedd49a3d8df7fb3"
},
{
"name": "old-umi",
Expand All @@ -12,7 +12,7 @@
{
"name": "lambdalib",
"url": "git@github.com:siliconcompiler/lambdalib.git",
"commit": "ebbcd48"
"commit": "98863b317ab0d038631763dcc66545a26c44f785"
},
{
"name": "libsystemctlm-soc",
Expand Down
2 changes: 1 addition & 1 deletion examples/old_umiram/test.py
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ def python_intf(from_client, to_client, old=True):
def build_testbench(fast=False):
dut = SbDut('testbench')

EX_DIR = Path('..')
EX_DIR = Path('..').resolve()

# Set up inputs
dut.input('testbench.sv')
Expand Down
2 changes: 1 addition & 1 deletion examples/python/test.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ def main(client2rtl='client2rtl.q', rtl2client='rtl2client.q', fast=False):
def build_testbench(fast=False):
dut = SbDut('testbench')

EX_DIR = Path('..')
EX_DIR = Path('..').resolve()

# Set up inputs
dut.input('testbench.sv')
Expand Down
2 changes: 1 addition & 1 deletion examples/router/test.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ def start_router(aq, bq, cq, dq):
def build_testbench(fast=False):
dut = SbDut('testbench')

EX_DIR = Path('..')
EX_DIR = Path('..').resolve()

# Set up inputs
dut.input('testbench.sv')
Expand Down
2 changes: 1 addition & 1 deletion examples/stream/test.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ def main():
def build_testbench():
dut = SbDut('testbench')

EX_DIR = Path('..')
EX_DIR = Path('..').resolve()

# Set up inputs
dut.input('testbench.sv')
Expand Down
2 changes: 1 addition & 1 deletion examples/umi_endpoint/test.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ def main(client2rtl="client2rtl.q", rtl2client="rtl2client.q", fast=False):
def build_testbench(fast=False):
dut = SbDut('testbench')

EX_DIR = Path('..')
EX_DIR = Path('..').resolve()

# Set up inputs
dut.input('testbench.sv')
Expand Down
12 changes: 9 additions & 3 deletions examples/umi_endpoint/testbench.sv
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,9 @@ module testbench (
wire [AW-1:0] udev_resp_srcaddr;
wire [DW-1:0] udev_resp_data;

umi_rx_sim rx_i (
umi_rx_sim #(
.VALID_MODE_DEFAULT(1)
) rx_i (
.clk(clk),
.data(udev_req_data),
.srcaddr(udev_req_srcaddr),
Expand All @@ -32,7 +34,9 @@ module testbench (
.valid(udev_req_valid)
);

umi_tx_sim tx_i (
umi_tx_sim #(
.READY_MODE_DEFAULT(1)
) tx_i (
.clk(clk),
.data(udev_resp_data),
.srcaddr(udev_resp_srcaddr),
Expand All @@ -55,7 +59,9 @@ module testbench (

assign loc_ready = nreset;

umi_endpoint umi_endpoint_i (
umi_endpoint #(
.REG(0)
) umi_endpoint_i (
.*
azaidy marked this conversation as resolved.
Show resolved Hide resolved
);

Expand Down
20 changes: 2 additions & 18 deletions examples/umi_fifo/test.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,33 +43,17 @@ def main(client2rtl='client2rtl.q', rtl2client='rtl2client.q', n=3, fast=False):
if rxp is not None:
print('* RX *')
print(str(rxp))
if not packets_match(rxp, txq[0]):
if rxp != txq[0]:
raise Exception('Mismatch!')
else:
txq.pop(0)
n_recv += 1


def packets_match(txp, rxp):
# compare data in both packets
txbytes = len(txp.data) if txp.data is not None else 0
rxbytes = len(rxp.data) if rxp.data is not None else 0
if rxbytes != txbytes:
data_match = False
elif (rxbytes == 0) and (txbytes == 0):
data_match = True
else:
data_match = (txp.data == rxp.data).all()

# compare the rest of the packets
return ((txp.cmd == rxp.cmd) and (txp.dstaddr == rxp.dstaddr)
and (txp.srcaddr == rxp.srcaddr) and data_match)


def build_testbench(fast=False):
dut = SbDut('testbench')

EX_DIR = Path('..')
EX_DIR = Path('..').resolve()

# Set up inputs
dut.input('testbench.sv')
Expand Down
39 changes: 3 additions & 36 deletions examples/umi_fifo_flex/test.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,9 @@
# Example illustrating how to interact with the umi_fifo_flex module
# Copyright (C) 2023 Zero ASIC

import numpy as np
from pathlib import Path
from argparse import ArgumentParser
from switchboard import SbDut, UmiTxRx, delete_queue, verilator_run, random_umi_packet
from switchboard import SbDut, UmiTxRx, delete_queue, verilator_run, umi_loopback


def main(client2rtl="client2rtl.q", rtl2client="rtl2client.q", n=3, fast=False):
Expand All @@ -24,45 +23,13 @@ def main(client2rtl="client2rtl.q", rtl2client="rtl2client.q", n=3, fast=False):
umi = UmiTxRx(client2rtl, rtl2client)

# randomly write data

q = []
partial = None
num_sent = 0
num_recv = 0

while (num_sent < n) or (num_recv < n):
# send data
if num_sent < n:
txp = random_umi_packet()
if umi.send(txp, blocking=False):
print('*** SENT ***')
print(txp)
q.append(txp.data)
num_sent += 1

# receive data
if num_recv < n:
rxp = umi.recv(blocking=False)
if rxp is not None:
print("*** RECEIVED ***")
print(rxp)

if partial is None:
partial = rxp.data
else:
partial = np.concatenate((partial, rxp.data))

if (len(q) > 0) and (len(q[0]) == len(partial)):
assert (q[0] == partial).all(), "Data mismatch"
q.pop(0)
partial = None
num_recv += 1
umi_loopback(umi, n)


def build_testbench(fast=False):
dut = SbDut('testbench')

EX_DIR = Path('..')
EX_DIR = Path('..').resolve()

# Set up inputs
dut.input('testbench.sv')
Expand Down
2 changes: 1 addition & 1 deletion examples/umi_splitter/test.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ def main(in_="in.q", out0="out0.q", out1="out1.q", n=3, fast=False):
def build_testbench(fast=False):
dut = SbDut('testbench')

EX_DIR = Path('..')
EX_DIR = Path('..').resolve()

# Set up inputs
dut.input('testbench.sv')
Expand Down
2 changes: 1 addition & 1 deletion examples/umiram/test.py
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ def python_intf(from_client, to_client, old=False):
def build_testbench(fast=False):
dut = SbDut('testbench')

EX_DIR = Path('..')
EX_DIR = Path('..').resolve()

# Set up inputs
dut.input('testbench.sv')
Expand Down
150 changes: 149 additions & 1 deletion python/switchboard_pybind.cc
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#include <stdio.h>

#include <pybind11/numpy.h>
#include <pybind11/operators.h>
#include <pybind11/pybind11.h>
#include <pybind11/stl.h>

Expand Down Expand Up @@ -138,6 +139,18 @@ struct PyUmiPacket {
m_allocated = true;
}

void resize(size_t size, size_t len) {
if (!m_storage) {
throw std::runtime_error("There is not storage associated with this UMI transaction.");
} else {
if (data.itemsize() != (1 << size)) {
throw std::runtime_error("Array data type doesn't match SIZE.");
}

data.resize({len + 1});
}
}

bool storage() {
return m_storage;
}
Expand All @@ -157,6 +170,138 @@ struct PyUmiPacket {
uint64_t srcaddr;
py::array data;

bool merge(const PyUmiPacket& other) {
uint32_t opcode = umi_opcode(cmd);

if (!allows_umi_merge(opcode)) {
// merging is not allowed for this kind of transaction
return false;
}

if (umi_ex(cmd) != 0) {
// merging is only allowed when ex == 0
return false;
}

// check that all fields except EOM and LEN match
uint32_t mask = 0xffffffff;
set_umi_eom(&mask, 0);
set_umi_len(&mask, 0);
if ((cmd & mask) != (other.cmd & mask)) {
return false;
}

if (umi_eom(cmd)) {
// when merging a sequence of packets, only the last
// packet can have eom=1
return false;
}

uint32_t size = umi_size(cmd);
uint32_t len = umi_len(cmd);
uint32_t nbytes = (len + 1) << size;

if (other.dstaddr != (dstaddr + nbytes)) {
// new dstaddr must be next sequentially
return false;
}

if (other.srcaddr != (srcaddr + nbytes)) {
// new srcaddr must be next sequentially
return false;
}

if (has_umi_data(opcode)) {
// resize this packet
resize(size, len + umi_len(other.cmd) + 1);

// make sure the data indicated by the command is there
uint32_t other_len = umi_len(other.cmd);
uint32_t other_nbytes = (other_len + 1) << size;
if (other.data.nbytes() < other_nbytes) {
throw std::runtime_error("other packet doesn't contain enough data");
}

// copy in the data
uint8_t* ptr = (uint8_t*)py::buffer(data).request().ptr;
uint8_t* other_ptr = (uint8_t*)py::buffer(other.data).request().ptr;
memcpy(ptr + nbytes, other_ptr, other_nbytes);
}

// set LEN
set_umi_len(&cmd, len + umi_len(other.cmd) + 1);

// set EOM
set_umi_eom(&cmd, umi_eom(other.cmd));

return true;
}

bool friend operator==(const PyUmiPacket& lhs, const PyUmiPacket& rhs) {
if (((lhs.cmd & 0xff) == 0) && ((rhs.cmd & 0xff) == 0)) {
// both are invalid; only the first 8 bits of the command
// have to match in order for the packets to be considered
// equivalent
return true;
}

if (lhs.cmd != rhs.cmd) {
// commands match
return false;
}

// if we get to this point, the commands match, so we can
// just work with the command from the left-hand side

uint32_t cmd = lhs.cmd;
uint32_t opcode = umi_opcode(cmd);

if ((opcode == UMI_REQ_LINK) || (opcode == UMI_RESP_LINK)) {
// link commands have no address or data, so the comparison
// is done at this point
return true;
}

// all other commands have a destination address, which must match
// between lhs and rhs

if (lhs.dstaddr != rhs.dstaddr) {
return false;
}

if (is_umi_req(opcode) && (lhs.srcaddr != rhs.srcaddr)) {
// requests also have a source address, which must match
// between lhs and rhs
return false;
}

if (has_umi_data(opcode)) {
uint32_t len = umi_len(cmd);
uint32_t size = umi_size(cmd);
uint32_t nbytes = (len + 1) << size;

if ((lhs.data.nbytes() < nbytes) || (rhs.data.nbytes() < nbytes)) {
// one packet or both doesn't have enough data to compare
return false;
}

py::buffer_info lhs_info = py::buffer(lhs.data).request();
py::buffer_info rhs_info = py::buffer(rhs.data).request();

if (memcmp(lhs_info.ptr, rhs_info.ptr, nbytes) != 0) {
// note that memcpy returns "0" if the arrays match,
// so we'll only get here if there is a mismatch
return false;
}
}

return true;
}

bool friend operator!=(const PyUmiPacket& lhs, const PyUmiPacket& rhs) {
return !(lhs == rhs);
}

private:
bool m_allocated;
bool m_storage;
Expand Down Expand Up @@ -899,10 +1044,13 @@ PYBIND11_MODULE(_switchboard, m) {
.def(py::init<uint32_t, uint64_t, uint64_t, std::optional<py::array>>(), py::arg("cmd") = 0,
py::arg("dstaddr") = 0, py::arg("srcaddr") = 0, py::arg("data") = py::none())
.def("__str__", &PyUmiPacket::toString)
.def("merge", &PyUmiPacket::merge)
.def_readwrite("cmd", &PyUmiPacket::cmd)
.def_readwrite("dstaddr", &PyUmiPacket::dstaddr)
.def_readwrite("srcaddr", &PyUmiPacket::srcaddr)
.def_readwrite("data", &PyUmiPacket::data);
.def_readwrite("data", &PyUmiPacket::data)
.def(py::self == py::self)
.def(py::self != py::self);

py::class_<OldPyUmiPacket>(m, "OldPyUmiPacket")
.def(py::init<uint32_t, uint32_t, uint32_t, uint64_t, uint64_t,
Expand Down
1 change: 1 addition & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
# lines are added as extras under a group called "<tag>".

numpy
tqdm
siliconcompiler >=0.13.1,<0.15

# Testing dependencies
Expand Down
Loading