diff --git a/tests/lib/cpuifs/__init__.py b/tests/lib/cpuifs/__init__.py index 6ea672d..82ca94b 100644 --- a/tests/lib/cpuifs/__init__.py +++ b/tests/lib/cpuifs/__init__.py @@ -3,6 +3,7 @@ from .apb3 import APB3, FlatAPB3 from .apb4 import APB4, FlatAPB4 from .axi4lite import AXI4Lite, FlatAXI4Lite from .avalon import Avalon, FlatAvalon +from .obi import OBI, FlatOBI ALL_CPUIF = [ Passthrough(), @@ -14,4 +15,6 @@ ALL_CPUIF = [ FlatAXI4Lite(), Avalon(), FlatAvalon(), + OBI(), + FlatOBI(), ] diff --git a/tests/lib/cpuifs/obi/__init__.py b/tests/lib/cpuifs/obi/__init__.py new file mode 100644 index 0000000..dc0d404 --- /dev/null +++ b/tests/lib/cpuifs/obi/__init__.py @@ -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 = [] diff --git a/tests/lib/cpuifs/obi/obi_intf_driver.sv b/tests/lib/cpuifs/obi/obi_intf_driver.sv new file mode 100644 index 0000000..2312ece --- /dev/null +++ b/tests/lib/cpuifs/obi/obi_intf_driver.sv @@ -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 diff --git a/tests/lib/cpuifs/obi/tb_inst.sv b/tests/lib/cpuifs/obi/tb_inst.sv new file mode 100644 index 0000000..f2ab297 --- /dev/null +++ b/tests/lib/cpuifs/obi/tb_inst.sv @@ -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 %}