OBI: Add testcase support. #157

This commit is contained in:
Alex Mykyta
2025-10-24 19:36:36 -07:00
parent f782c656ca
commit dafd693a1d
4 changed files with 261 additions and 0 deletions

View File

@@ -3,6 +3,7 @@ from .apb3 import APB3, FlatAPB3
from .apb4 import APB4, FlatAPB4 from .apb4 import APB4, FlatAPB4
from .axi4lite import AXI4Lite, FlatAXI4Lite from .axi4lite import AXI4Lite, FlatAXI4Lite
from .avalon import Avalon, FlatAvalon from .avalon import Avalon, FlatAvalon
from .obi import OBI, FlatOBI
ALL_CPUIF = [ ALL_CPUIF = [
Passthrough(), Passthrough(),
@@ -14,4 +15,6 @@ ALL_CPUIF = [
FlatAXI4Lite(), FlatAXI4Lite(),
Avalon(), Avalon(),
FlatAvalon(), FlatAvalon(),
OBI(),
FlatOBI(),
] ]

View File

@@ -0,0 +1,18 @@
from ..base import CpuifTestMode
from peakrdl_regblock.cpuif.obi import OBI_Cpuif, OBI_Cpuif_flattened
class OBI(CpuifTestMode):
cpuif_cls = OBI_Cpuif
rtl_files = [
"../../../../hdl-src/obi_intf.sv",
]
tb_files = [
"../../../../hdl-src/obi_intf.sv",
"obi_intf_driver.sv",
]
tb_template = "tb_inst.sv"
class FlatOBI(OBI):
cpuif_cls = OBI_Cpuif_flattened
rtl_files = []

View File

@@ -0,0 +1,199 @@
interface obi_intf_driver #(
parameter DATA_WIDTH = 32,
parameter ADDR_WIDTH = 32,
parameter ID_WIDTH = 1
)(
input wire clk,
input wire rst,
obi_intf.manager m_obi
);
timeunit 1ps;
timeprecision 1ps;
logic req;
logic gnt;
logic [ADDR_WIDTH-1:0] addr;
logic we;
logic [DATA_WIDTH/8-1:0] be;
logic [DATA_WIDTH-1:0] wdata;
logic [ID_WIDTH-1:0] aid;
logic rvalid;
logic rready;
logic [DATA_WIDTH-1:0] rdata;
logic err;
logic [ID_WIDTH-1:0] rid;
assign m_obi.req = req;
assign gnt = m_obi.gnt;
assign m_obi.addr = addr;
assign m_obi.we = we;
assign m_obi.be = be;
assign m_obi.wdata = wdata;
assign m_obi.aid = aid;
assign rvalid = m_obi.rvalid;
assign m_obi.rready = rready;
assign rdata = m_obi.rdata;
assign err = m_obi.err;
assign rid = m_obi.rid;
default clocking cb @(posedge clk);
default input #1step output #1;
output req;
input gnt;
output addr;
output we;
output be;
output wdata;
output aid;
input rvalid;
inout rready;
input rdata;
input err;
input rid;
endclocking
task automatic reset();
cb.req <= '0;
cb.addr <= '0;
cb.we <= '0;
cb.be <= '0;
cb.wdata <= '0;
cb.aid <= '0;
endtask
initial forever begin
cb.rready <= $urandom_range(1, 0);
@cb;
end
//--------------------------------------------------------------------------
typedef struct {
logic [DATA_WIDTH-1:0] rdata;
logic err;
logic [ID_WIDTH-1:0] rid;
} response_t;
class request_t;
mailbox #(response_t) response_mbx;
logic [ID_WIDTH-1:0] aid;
function new();
this.response_mbx = new();
endfunction
endclass
semaphore txn_req_mutex = new(1);
request_t request_queue[$];
// Listen for responses
initial forever begin
@cb;
while(rst || !(cb.rready === 1'b1 && cb.rvalid === 1'b1)) @cb;
if(request_queue.size() != 0) begin
// Can match this response with an existing request.
// Send response to requestor
request_t req;
response_t resp;
req = request_queue.pop_front();
resp.rdata = cb.rdata;
resp.err = cb.err;
resp.rid = cb.rid;
assert(resp.rid == req.aid) else $error("Got incorrect RID! %0d != %0d", resp.rid, req.aid);
req.response_mbx.put(resp);
end else begin
$error("Got unexpected response");
end
end
//--------------------------------------------------------------------------
task automatic read(logic [ADDR_WIDTH-1:0] addr, output logic [DATA_WIDTH-1:0] data);
request_t req;
response_t resp;
logic [ID_WIDTH-1:0] id;
txn_req_mutex.get();
// Issue read request
id = $urandom();
##0;
cb.req <= '1;
cb.we <= '0;
cb.addr <= addr;
cb.aid <= id;
@(cb);
while(cb.gnt !== 1'b1) @(cb);
cb.req <= '0;
// Push new request into queue
req = new();
req.aid = id;
request_queue.push_back(req);
txn_req_mutex.put();
// Wait for response
req.response_mbx.get(resp);
assert(!$isunknown(resp.rdata)) else $error("Read from 0x%0x returned X's on rdata", addr);
assert(!$isunknown(resp.err)) else $error("Read from 0x%0x returned X's on err", addr);
assert(!$isunknown(resp.rid)) else $error("Read from 0x%0x returned X's on rid", addr);
data = resp.rdata;
endtask
task automatic assert_read(logic [ADDR_WIDTH-1:0] addr, logic [DATA_WIDTH-1:0] expected_data, logic [DATA_WIDTH-1:0] mask = '1);
logic [DATA_WIDTH-1:0] data;
read(addr, data);
data &= mask;
assert(data == expected_data) else $error("Read from 0x%x returned 0x%x. Expected 0x%x", addr, data, expected_data);
endtask
//--------------------------------------------------------------------------
task automatic write(logic [ADDR_WIDTH-1:0] addr, logic [DATA_WIDTH-1:0] data, logic [DATA_WIDTH/8-1:0] strb = '1);
request_t req;
response_t resp;
logic [ID_WIDTH-1:0] id;
txn_req_mutex.get();
// Issue write request
id = $urandom();
##0;
cb.req <= '1;
cb.we <= '1;
cb.be <= strb;
cb.wdata <= data;
cb.addr <= addr;
cb.aid <= id;
@(cb);
while(cb.gnt !== 1'b1) @(cb);
cb.req <= '0;
// Push new request into queue
req = new();
req.aid = id;
request_queue.push_back(req);
txn_req_mutex.put();
// Wait for response
req.response_mbx.get(resp);
assert(!$isunknown(resp.err)) else $error("Read from 0x%0x returned X's on err", addr);
assert(!$isunknown(resp.rid)) else $error("Read from 0x%0x returned X's on rid", addr);
endtask
//--------------------------------------------------------------------------
initial begin
reset();
end
initial forever begin
@cb;
if(!rst) assert(!$isunknown(cb.gnt)) else $error("Saw X on gnt!");
if(!rst) assert(!$isunknown(cb.rvalid)) else $error("Saw X on rvalid!");
end
endinterface

View File

@@ -0,0 +1,41 @@
{% sv_line_anchor %}
obi_intf #(
.DATA_WIDTH({{exporter.cpuif.data_width}}),
.ADDR_WIDTH({{exporter.cpuif.addr_width}})
) obi();
obi_intf_driver #(
.DATA_WIDTH({{exporter.cpuif.data_width}}),
.ADDR_WIDTH({{exporter.cpuif.addr_width}})
) cpuif (
.clk(clk),
.rst(rst),
.m_obi(obi)
);
{% if type(cpuif).__name__.startswith("Flat") %}
{% sv_line_anchor %}
wire obi_req;
wire obi_gnt;
wire [{{exporter.cpuif.addr_width - 1}}:0] obi_addr;
wire obi_we;
wire [{{exporter.cpuif.data_width_bytes - 1}}:0] obi_be;
wire [{{exporter.cpuif.data_width - 1}}:0] obi_wdata;
wire [0:0] obi_aid;
wire obi_rvalid;
wire obi_rready;
wire [{{exporter.cpuif.data_width - 1}}:0] obi_rdata;
wire obi_err;
wire [0:0] obi_rid;
assign obi_req = obi.req;
assign obi.gnt = obi_gnt;
assign obi_addr = obi.addr;
assign obi_we = obi.we;
assign obi_be = obi.be;
assign obi_wdata = obi.wdata;
assign obi_aid = obi.aid;
assign obi.rvalid = obi_rvalid;
assign obi_rready = obi.rready;
assign obi.rdata = obi_rdata;
assign obi.err = obi_err;
assign obi.rid = obi_rid;
{% endif %}