From f782c656ca564b6caa1c66e85eccbb771ebb22b4 Mon Sep 17 00:00:00 2001 From: Alex Mykyta Date: Mon, 13 Oct 2025 23:32:18 -0700 Subject: [PATCH] OBI: Fix missing intf definition. Adjust coding style. #157 --- docs/cpuif/obi.rst | 18 ++++ docs/index.rst | 1 + hdl-src/obi_intf.sv | 51 +++++++++ src/peakrdl_regblock/cpuif/base.py | 4 +- src/peakrdl_regblock/cpuif/obi/__init__.py | 18 ++-- src/peakrdl_regblock/cpuif/obi/obi_tmpl.sv | 114 +++++++++------------ 6 files changed, 133 insertions(+), 73 deletions(-) create mode 100644 docs/cpuif/obi.rst create mode 100644 hdl-src/obi_intf.sv diff --git a/docs/cpuif/obi.rst b/docs/cpuif/obi.rst new file mode 100644 index 0000000..386d318 --- /dev/null +++ b/docs/cpuif/obi.rst @@ -0,0 +1,18 @@ +Open Bus Interface (OBI) +======================== + +Implements the register block using an `OBI `_ +CPU interface. + +The OBI interface comes in two i/o port flavors: + +SystemVerilog Interface + * Command line: ``--cpuif obi`` + * Interface Definition: :download:`obi_intf.sv <../../hdl-src/obi_intf.sv>` + * Class: :class:`peakrdl_regblock.cpuif.obi.OBI_Cpuif` + +Flattened inputs/outputs + Flattens the interface into discrete input and output ports. + + * Command line: ``--cpuif obi-flat`` + * Class: :class:`peakrdl_regblock.cpuif.obi.OBI_Cpuif_flattened` diff --git a/docs/index.rst b/docs/index.rst index e21236a..2dd445b 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -62,6 +62,7 @@ Links cpuif/apb cpuif/axi4lite cpuif/avalon + cpuif/obi cpuif/passthrough cpuif/internal_protocol cpuif/customizing diff --git a/hdl-src/obi_intf.sv b/hdl-src/obi_intf.sv new file mode 100644 index 0000000..f37b957 --- /dev/null +++ b/hdl-src/obi_intf.sv @@ -0,0 +1,51 @@ +interface obi_intf #( + parameter DATA_WIDTH = 32, + parameter ADDR_WIDTH = 32, + parameter ID_WIDTH = 1 +); + 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; + + modport manager ( + output req, + input gnt, + output addr, + output we, + output be, + output wdata, + output aid, + + input rvalid, + output rready, + input rdata, + input err, + input rid + ); + + modport subordinate ( + input req, + output gnt, + input addr, + input we, + input be, + input wdata, + input aid, + + output rvalid, + input rready, + output rdata, + output err, + output rid + ); +endinterface diff --git a/src/peakrdl_regblock/cpuif/base.py b/src/peakrdl_regblock/cpuif/base.py index 2031a71..c43bdf8 100644 --- a/src/peakrdl_regblock/cpuif/base.py +++ b/src/peakrdl_regblock/cpuif/base.py @@ -37,8 +37,8 @@ class CpuifBase: @property def parameters(self) -> List[str]: """ - Optional list of additional parameters this CPU interface provides to - the module's definition + Optional list of additional parameter declarations this CPU interface + provides to the module's definition """ return [] diff --git a/src/peakrdl_regblock/cpuif/obi/__init__.py b/src/peakrdl_regblock/cpuif/obi/__init__.py index 0beb9d5..98a856e 100644 --- a/src/peakrdl_regblock/cpuif/obi/__init__.py +++ b/src/peakrdl_regblock/cpuif/obi/__init__.py @@ -1,3 +1,5 @@ +from typing import List + from ..base import CpuifBase class OBI_Cpuif(CpuifBase): @@ -32,19 +34,19 @@ class OBI_Cpuif_flattened(OBI_Cpuif): lines = [ # OBI Request Channel (A) "input wire " + self.signal("req"), + "output logic " + self.signal("gnt"), f"input wire [{self.addr_width-1}:0] " + self.signal("addr"), "input wire " + self.signal("we"), f"input wire [{self.data_width//8-1}:0] " + self.signal("be"), f"input wire [{self.data_width-1}:0] " + self.signal("wdata"), - f"input wire [{self.id_width-1}:0] " + self.signal("aid"), - + "input wire [ID_WIDTH-1:0] " + self.signal("aid"), + # OBI Response Channel (R) - "output logic " + self.signal("gnt"), "output logic " + self.signal("rvalid"), - f"output logic [{self.data_width-1}:0] " + self.signal("rdata"), - f"output logic [{self.id_width-1}:0] " + self.signal("rid"), - "output logic " + self.signal("err"), "input wire " + self.signal("rready"), + f"output logic [{self.data_width-1}:0] " + self.signal("rdata"), + "output logic " + self.signal("err"), + "output logic [ID_WIDTH-1:0] " + self.signal("rid"), ] return ",\n".join(lines) @@ -52,5 +54,5 @@ class OBI_Cpuif_flattened(OBI_Cpuif): return "obi_" + name @property - def id_width(self) -> int: - return 1 # Default ID width + def parameters(self) -> List[str]: + return ["parameter ID_WIDTH = 1"] diff --git a/src/peakrdl_regblock/cpuif/obi/obi_tmpl.sv b/src/peakrdl_regblock/cpuif/obi/obi_tmpl.sv index efb6951..7ed3537 100644 --- a/src/peakrdl_regblock/cpuif/obi/obi_tmpl.sv +++ b/src/peakrdl_regblock/cpuif/obi/obi_tmpl.sv @@ -7,85 +7,73 @@ else $error("Interface data width of %0d is incorrect. Shall be %0d bits", $bits({{cpuif.signal("wdata")}}), {{ds.package_name}}::{{ds.module_name.upper()}}_DATA_WIDTH); end `endif + {% endif -%} -// OBI Interface Implementation -// This register block acts as an OBI subordinate - -localparam int unsigned DATA_WIDTH = {{ds.package_name}}::{{ds.module_name.upper()}}_DATA_WIDTH; -localparam int unsigned BYTES = DATA_WIDTH/8; - // State & holding regs -logic is_active; // A request is being served (not yet fully responded) -logic gnt_q; // one-cycle grant for A-channel -logic rsp_pending; // response ready but not yet accepted by manager -logic [DATA_WIDTH-1:0] rsp_rdata_q; -logic rsp_err_q; -logic [$bits({{cpuif.signal("aid")}})-1:0] rid_q; +logic is_active; // A request is being served (not yet fully responded) +logic gnt_q; // one-cycle grant for A-channel +logic rsp_pending; // response ready but not yet accepted by manager +logic [{{cpuif.data_width-1}}:0] rsp_rdata_q; +logic rsp_err_q; +logic [$bits({{cpuif.signal("rid")}})-1:0] rid_q; // Latch AID on accept to echo back the response always_ff {{get_always_ff_event(cpuif.reset)}} begin - if ({{get_resetsignal(cpuif.reset)}}) begin - is_active <= 1'b0; - gnt_q <= 1'b0; - rsp_pending <= 1'b0; - rsp_rdata_q <= '0; - rsp_err_q <= 1'b0; - rid_q <= '0; + if ({{get_resetsignal(cpuif.reset)}}) begin + is_active <= 1'b0; + gnt_q <= 1'b0; + rsp_pending <= 1'b0; + rsp_rdata_q <= '0; + rsp_err_q <= 1'b0; + rid_q <= '0; - cpuif_req <= '0; - cpuif_req_is_wr <= '0; - cpuif_addr <= '0; - cpuif_wr_data <= '0; - cpuif_wr_biten <= '0; - end else begin - // defaults - cpuif_req <= 1'b0; - gnt_q <= {{cpuif.signal("req")}} & ~is_active; + cpuif_req <= '0; + cpuif_req_is_wr <= '0; + cpuif_addr <= '0; + cpuif_wr_data <= '0; + cpuif_wr_biten <= '0; + end else begin + // defaults + cpuif_req <= 1'b0; + gnt_q <= {{cpuif.signal("req")}} & ~is_active; - // Accept new request when idle - if (~is_active) begin - if ({{cpuif.signal("req")}}) begin - is_active <= 1'b1; - cpuif_req <= 1'b1; - cpuif_req_is_wr <= {{cpuif.signal("we")}}; - cpuif_addr <= {{cpuif.signal("addr")}}; - cpuif_wr_data <= {{cpuif.signal("wdata")}}; - rid_q <= {{cpuif.signal("aid")}}; - for (int i = 0; i < BYTES; i++) begin - cpuif_wr_biten[i*8 +: 8] <= {8{ {{cpuif.signal("be")}}[i] }}; + // Accept new request when idle + if (~is_active) begin + if ({{cpuif.signal("req")}}) begin + is_active <= 1'b1; + cpuif_req <= 1'b1; + cpuif_req_is_wr <= {{cpuif.signal("we")}}; + cpuif_addr <= {{cpuif.signal("addr")}}; + cpuif_wr_data <= {{cpuif.signal("wdata")}}; + rid_q <= {{cpuif.signal("aid")}}; + for (int i = 0; i < {{cpuif.data_width_bytes}}; i++) begin + cpuif_wr_biten[i*8 +: 8] <= {8{ {{cpuif.signal("be")}}[i] }}; + end + end end - end - end - // Capture response - if (is_active && (cpuif_rd_ack || cpuif_wr_ack)) begin - rsp_pending <= 1'b1; - rsp_rdata_q <= cpuif_rd_data; - rsp_err_q <= cpuif_rd_err | cpuif_wr_err; - // NOTE: Keep 'is_active' asserted until the external R handshake completes - end + // Capture response + if (is_active && (cpuif_rd_ack || cpuif_wr_ack)) begin + rsp_pending <= 1'b1; + rsp_rdata_q <= cpuif_rd_data; + rsp_err_q <= cpuif_rd_err | cpuif_wr_err; + // NOTE: Keep 'is_active' asserted until the external R handshake completes + end - // Complete external R-channel handshake only if manager ready - if (rsp_pending && {{cpuif.signal("rvalid")}} && {{cpuif.signal("rready")}}) begin - rsp_pending <= 1'b0; - is_active <= 1'b0; // free to accept the next request + // Complete external R-channel handshake only if manager ready + if (rsp_pending && {{cpuif.signal("rvalid")}} && {{cpuif.signal("rready")}}) begin + rsp_pending <= 1'b0; + is_active <= 1'b0; // free to accept the next request + end end - end end // R-channel outputs (held stable while rsp_pending=1) assign {{cpuif.signal("rvalid")}} = rsp_pending; -assign {{cpuif.signal("rdata")}} = rsp_rdata_q; -assign {{cpuif.signal("err")}} = rsp_err_q; -assign {{cpuif.signal("rid")}} = rid_q; +assign {{cpuif.signal("rdata")}} = rsp_rdata_q; +assign {{cpuif.signal("err")}} = rsp_err_q; +assign {{cpuif.signal("rid")}} = rid_q; // A-channel grant (registered one-cycle pulse when we accept a request) assign {{cpuif.signal("gnt")}} = gnt_q; - -// If OBI config RReady is disabled, tie it high in the top-level/TB. -// `ifndef SYNTHESIS -// initial begin -// if (0) $display("RReady supported; tie high if unused."); -// end -// `endif