OBI: Fix missing intf definition. Adjust coding style. #157
This commit is contained in:
18
docs/cpuif/obi.rst
Normal file
18
docs/cpuif/obi.rst
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
Open Bus Interface (OBI)
|
||||||
|
========================
|
||||||
|
|
||||||
|
Implements the register block using an `OBI <https://github.com/openhwgroup/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`
|
||||||
@@ -62,6 +62,7 @@ Links
|
|||||||
cpuif/apb
|
cpuif/apb
|
||||||
cpuif/axi4lite
|
cpuif/axi4lite
|
||||||
cpuif/avalon
|
cpuif/avalon
|
||||||
|
cpuif/obi
|
||||||
cpuif/passthrough
|
cpuif/passthrough
|
||||||
cpuif/internal_protocol
|
cpuif/internal_protocol
|
||||||
cpuif/customizing
|
cpuif/customizing
|
||||||
|
|||||||
51
hdl-src/obi_intf.sv
Normal file
51
hdl-src/obi_intf.sv
Normal file
@@ -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
|
||||||
@@ -37,8 +37,8 @@ class CpuifBase:
|
|||||||
@property
|
@property
|
||||||
def parameters(self) -> List[str]:
|
def parameters(self) -> List[str]:
|
||||||
"""
|
"""
|
||||||
Optional list of additional parameters this CPU interface provides to
|
Optional list of additional parameter declarations this CPU interface
|
||||||
the module's definition
|
provides to the module's definition
|
||||||
"""
|
"""
|
||||||
return []
|
return []
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
from typing import List
|
||||||
|
|
||||||
from ..base import CpuifBase
|
from ..base import CpuifBase
|
||||||
|
|
||||||
class OBI_Cpuif(CpuifBase):
|
class OBI_Cpuif(CpuifBase):
|
||||||
@@ -32,19 +34,19 @@ class OBI_Cpuif_flattened(OBI_Cpuif):
|
|||||||
lines = [
|
lines = [
|
||||||
# OBI Request Channel (A)
|
# OBI Request Channel (A)
|
||||||
"input wire " + self.signal("req"),
|
"input wire " + self.signal("req"),
|
||||||
|
"output logic " + self.signal("gnt"),
|
||||||
f"input wire [{self.addr_width-1}:0] " + self.signal("addr"),
|
f"input wire [{self.addr_width-1}:0] " + self.signal("addr"),
|
||||||
"input wire " + self.signal("we"),
|
"input wire " + self.signal("we"),
|
||||||
f"input wire [{self.data_width//8-1}:0] " + self.signal("be"),
|
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.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)
|
# OBI Response Channel (R)
|
||||||
"output logic " + self.signal("gnt"),
|
|
||||||
"output logic " + self.signal("rvalid"),
|
"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"),
|
"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)
|
return ",\n".join(lines)
|
||||||
|
|
||||||
@@ -52,5 +54,5 @@ class OBI_Cpuif_flattened(OBI_Cpuif):
|
|||||||
return "obi_" + name
|
return "obi_" + name
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def id_width(self) -> int:
|
def parameters(self) -> List[str]:
|
||||||
return 1 # Default ID width
|
return ["parameter ID_WIDTH = 1"]
|
||||||
|
|||||||
@@ -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);
|
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
|
end
|
||||||
`endif
|
`endif
|
||||||
|
|
||||||
{% 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
|
// State & holding regs
|
||||||
logic is_active; // A request is being served (not yet fully responded)
|
logic is_active; // A request is being served (not yet fully responded)
|
||||||
logic gnt_q; // one-cycle grant for A-channel
|
logic gnt_q; // one-cycle grant for A-channel
|
||||||
logic rsp_pending; // response ready but not yet accepted by manager
|
logic rsp_pending; // response ready but not yet accepted by manager
|
||||||
logic [DATA_WIDTH-1:0] rsp_rdata_q;
|
logic [{{cpuif.data_width-1}}:0] rsp_rdata_q;
|
||||||
logic rsp_err_q;
|
logic rsp_err_q;
|
||||||
logic [$bits({{cpuif.signal("aid")}})-1:0] rid_q;
|
logic [$bits({{cpuif.signal("rid")}})-1:0] rid_q;
|
||||||
|
|
||||||
// Latch AID on accept to echo back the response
|
// Latch AID on accept to echo back the response
|
||||||
always_ff {{get_always_ff_event(cpuif.reset)}} begin
|
always_ff {{get_always_ff_event(cpuif.reset)}} begin
|
||||||
if ({{get_resetsignal(cpuif.reset)}}) begin
|
if ({{get_resetsignal(cpuif.reset)}}) begin
|
||||||
is_active <= 1'b0;
|
is_active <= 1'b0;
|
||||||
gnt_q <= 1'b0;
|
gnt_q <= 1'b0;
|
||||||
rsp_pending <= 1'b0;
|
rsp_pending <= 1'b0;
|
||||||
rsp_rdata_q <= '0;
|
rsp_rdata_q <= '0;
|
||||||
rsp_err_q <= 1'b0;
|
rsp_err_q <= 1'b0;
|
||||||
rid_q <= '0;
|
rid_q <= '0;
|
||||||
|
|
||||||
cpuif_req <= '0;
|
cpuif_req <= '0;
|
||||||
cpuif_req_is_wr <= '0;
|
cpuif_req_is_wr <= '0;
|
||||||
cpuif_addr <= '0;
|
cpuif_addr <= '0;
|
||||||
cpuif_wr_data <= '0;
|
cpuif_wr_data <= '0;
|
||||||
cpuif_wr_biten <= '0;
|
cpuif_wr_biten <= '0;
|
||||||
end else begin
|
end else begin
|
||||||
// defaults
|
// defaults
|
||||||
cpuif_req <= 1'b0;
|
cpuif_req <= 1'b0;
|
||||||
gnt_q <= {{cpuif.signal("req")}} & ~is_active;
|
gnt_q <= {{cpuif.signal("req")}} & ~is_active;
|
||||||
|
|
||||||
// Accept new request when idle
|
// Accept new request when idle
|
||||||
if (~is_active) begin
|
if (~is_active) begin
|
||||||
if ({{cpuif.signal("req")}}) begin
|
if ({{cpuif.signal("req")}}) begin
|
||||||
is_active <= 1'b1;
|
is_active <= 1'b1;
|
||||||
cpuif_req <= 1'b1;
|
cpuif_req <= 1'b1;
|
||||||
cpuif_req_is_wr <= {{cpuif.signal("we")}};
|
cpuif_req_is_wr <= {{cpuif.signal("we")}};
|
||||||
cpuif_addr <= {{cpuif.signal("addr")}};
|
cpuif_addr <= {{cpuif.signal("addr")}};
|
||||||
cpuif_wr_data <= {{cpuif.signal("wdata")}};
|
cpuif_wr_data <= {{cpuif.signal("wdata")}};
|
||||||
rid_q <= {{cpuif.signal("aid")}};
|
rid_q <= {{cpuif.signal("aid")}};
|
||||||
for (int i = 0; i < BYTES; i++) begin
|
for (int i = 0; i < {{cpuif.data_width_bytes}}; i++) begin
|
||||||
cpuif_wr_biten[i*8 +: 8] <= {8{ {{cpuif.signal("be")}}[i] }};
|
cpuif_wr_biten[i*8 +: 8] <= {8{ {{cpuif.signal("be")}}[i] }};
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
// Capture response
|
// Capture response
|
||||||
if (is_active && (cpuif_rd_ack || cpuif_wr_ack)) begin
|
if (is_active && (cpuif_rd_ack || cpuif_wr_ack)) begin
|
||||||
rsp_pending <= 1'b1;
|
rsp_pending <= 1'b1;
|
||||||
rsp_rdata_q <= cpuif_rd_data;
|
rsp_rdata_q <= cpuif_rd_data;
|
||||||
rsp_err_q <= cpuif_rd_err | cpuif_wr_err;
|
rsp_err_q <= cpuif_rd_err | cpuif_wr_err;
|
||||||
// NOTE: Keep 'is_active' asserted until the external R handshake completes
|
// NOTE: Keep 'is_active' asserted until the external R handshake completes
|
||||||
end
|
end
|
||||||
|
|
||||||
// Complete external R-channel handshake only if manager ready
|
// Complete external R-channel handshake only if manager ready
|
||||||
if (rsp_pending && {{cpuif.signal("rvalid")}} && {{cpuif.signal("rready")}}) begin
|
if (rsp_pending && {{cpuif.signal("rvalid")}} && {{cpuif.signal("rready")}}) begin
|
||||||
rsp_pending <= 1'b0;
|
rsp_pending <= 1'b0;
|
||||||
is_active <= 1'b0; // free to accept the next request
|
is_active <= 1'b0; // free to accept the next request
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
// R-channel outputs (held stable while rsp_pending=1)
|
// R-channel outputs (held stable while rsp_pending=1)
|
||||||
assign {{cpuif.signal("rvalid")}} = rsp_pending;
|
assign {{cpuif.signal("rvalid")}} = rsp_pending;
|
||||||
assign {{cpuif.signal("rdata")}} = rsp_rdata_q;
|
assign {{cpuif.signal("rdata")}} = rsp_rdata_q;
|
||||||
assign {{cpuif.signal("err")}} = rsp_err_q;
|
assign {{cpuif.signal("err")}} = rsp_err_q;
|
||||||
assign {{cpuif.signal("rid")}} = rid_q;
|
assign {{cpuif.signal("rid")}} = rid_q;
|
||||||
|
|
||||||
// A-channel grant (registered one-cycle pulse when we accept a request)
|
// A-channel grant (registered one-cycle pulse when we accept a request)
|
||||||
assign {{cpuif.signal("gnt")}} = gnt_q;
|
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
|
|
||||||
|
|||||||
Reference in New Issue
Block a user