OBI: Add testcase support. #157
This commit is contained in:
18
tests/lib/cpuifs/obi/__init__.py
Normal file
18
tests/lib/cpuifs/obi/__init__.py
Normal 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 = []
|
||||
199
tests/lib/cpuifs/obi/obi_intf_driver.sv
Normal file
199
tests/lib/cpuifs/obi/obi_intf_driver.sv
Normal 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
|
||||
41
tests/lib/cpuifs/obi/tb_inst.sv
Normal file
41
tests/lib/cpuifs/obi/tb_inst.sv
Normal 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 %}
|
||||
Reference in New Issue
Block a user