Compare commits
6 Commits
7d88b26a65
...
fe47aee26b
| Author | SHA1 | Date | |
|---|---|---|---|
| fe47aee26b | |||
| 094d38ff92 | |||
| b2923f4c7b | |||
|
|
953e36c812 | ||
|
|
951a00f66b | ||
|
|
c7b6c9e5ef |
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|||||||
|
|
||||||
[project]
|
[project]
|
||||||
name = "peakrdl-busdecoder"
|
name = "peakrdl-busdecoder"
|
||||||
version = "0.6.7"
|
version = "0.6.9"
|
||||||
requires-python = ">=3.10"
|
requires-python = ">=3.10"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"jinja2~=3.1",
|
"jinja2~=3.1",
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ from peakrdl.config import schema
|
|||||||
from peakrdl.plugins.entry_points import get_entry_points
|
from peakrdl.plugins.entry_points import get_entry_points
|
||||||
from peakrdl.plugins.exporter import ExporterSubcommandPlugin
|
from peakrdl.plugins.exporter import ExporterSubcommandPlugin
|
||||||
|
|
||||||
from .cpuif import BaseCpuif, apb3, apb4, axi4lite
|
from .cpuif import BaseCpuif, apb3, apb4, axi4lite, taxi_apb
|
||||||
from .exporter import BusDecoderExporter
|
from .exporter import BusDecoderExporter
|
||||||
from .udps import ALL_UDPS
|
from .udps import ALL_UDPS
|
||||||
|
|
||||||
@@ -26,6 +26,7 @@ def get_cpuifs(config: list[tuple[str, Any]]) -> dict[str, type[BaseCpuif]]:
|
|||||||
"apb3-flat": apb3.APB3CpuifFlat,
|
"apb3-flat": apb3.APB3CpuifFlat,
|
||||||
"apb4": apb4.APB4Cpuif,
|
"apb4": apb4.APB4Cpuif,
|
||||||
"apb4-flat": apb4.APB4CpuifFlat,
|
"apb4-flat": apb4.APB4CpuifFlat,
|
||||||
|
"taxi-apb": taxi_apb.TaxiAPBCpuif,
|
||||||
"axi4-lite": axi4lite.AXI4LiteCpuif,
|
"axi4-lite": axi4lite.AXI4LiteCpuif,
|
||||||
"axi4-lite-flat": axi4lite.AXI4LiteCpuifFlat,
|
"axi4-lite-flat": axi4lite.AXI4LiteCpuifFlat,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,6 +15,7 @@
|
|||||||
$bits({{cpuif.signal("WDATA")}}), {{ds.package_name}}::{{ds.module_name|upper}}_DATA_WIDTH);
|
$bits({{cpuif.signal("WDATA")}}), {{ds.package_name}}::{{ds.module_name|upper}}_DATA_WIDTH);
|
||||||
end
|
end
|
||||||
|
|
||||||
|
`ifdef PEAKRDL_ASSERTIONS
|
||||||
// Simple handshake sanity (one-cycle implication; relax/adjust as needed)
|
// Simple handshake sanity (one-cycle implication; relax/adjust as needed)
|
||||||
assert_rd_resp_enc: assert property (@(posedge {{cpuif.signal("ACLK")}})
|
assert_rd_resp_enc: assert property (@(posedge {{cpuif.signal("ACLK")}})
|
||||||
{{cpuif.signal("RVALID")}} |-> (^{{cpuif.signal("RRESP")}} !== 1'bx))
|
{{cpuif.signal("RVALID")}} |-> (^{{cpuif.signal("RRESP")}} !== 1'bx))
|
||||||
@@ -24,6 +25,7 @@
|
|||||||
{{cpuif.signal("BVALID")}} |-> (^{{cpuif.signal("BRESP")}} !== 1'bx))
|
{{cpuif.signal("BVALID")}} |-> (^{{cpuif.signal("BRESP")}} !== 1'bx))
|
||||||
else $error("BRESP must be a legal AXI response when BVALID is high");
|
else $error("BRESP must be a legal AXI response when BVALID is high");
|
||||||
`endif
|
`endif
|
||||||
|
`endif
|
||||||
{% endif -%}
|
{% endif -%}
|
||||||
|
|
||||||
logic axi_wr_valid;
|
logic axi_wr_valid;
|
||||||
|
|||||||
@@ -64,17 +64,20 @@ class Interface(ABC):
|
|||||||
class SVInterface(Interface):
|
class SVInterface(Interface):
|
||||||
"""SystemVerilog interface-based signal handling."""
|
"""SystemVerilog interface-based signal handling."""
|
||||||
|
|
||||||
|
slave_modport_name = "slave"
|
||||||
|
master_modport_name = "master"
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def is_interface(self) -> bool:
|
def is_interface(self) -> bool:
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def get_port_declaration(self, slave_name: str, master_prefix: str) -> str:
|
def get_port_declaration(self, slave_name: str, master_prefix: str) -> str:
|
||||||
"""Generate SystemVerilog interface port declarations."""
|
"""Generate SystemVerilog interface port declarations."""
|
||||||
slave_ports: list[str] = [f"{self.get_interface_type()}.slave {slave_name}"]
|
slave_ports: list[str] = [f"{self.get_interface_type()}.{self.slave_modport_name} {slave_name}"]
|
||||||
master_ports: list[str] = []
|
master_ports: list[str] = []
|
||||||
|
|
||||||
for child in self.cpuif.addressable_children:
|
for child in self.cpuif.addressable_children:
|
||||||
base = f"{self.get_interface_type()}.master {master_prefix}{child.inst_name}"
|
base = f"{self.get_interface_type()}.{self.master_modport_name} {master_prefix}{child.inst_name}"
|
||||||
|
|
||||||
# When unrolled, current_idx is set - append it to the name
|
# When unrolled, current_idx is set - append it to the name
|
||||||
if child.current_idx is not None:
|
if child.current_idx is not None:
|
||||||
|
|||||||
3
src/peakrdl_busdecoder/cpuif/taxi_apb/__init__.py
Normal file
3
src/peakrdl_busdecoder/cpuif/taxi_apb/__init__.py
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
from .taxi_apb_cpuif import TaxiAPBCpuif
|
||||||
|
|
||||||
|
__all__ = ["TaxiAPBCpuif"]
|
||||||
109
src/peakrdl_busdecoder/cpuif/taxi_apb/taxi_apb_cpuif.py
Normal file
109
src/peakrdl_busdecoder/cpuif/taxi_apb/taxi_apb_cpuif.py
Normal file
@@ -0,0 +1,109 @@
|
|||||||
|
from collections import deque
|
||||||
|
from typing import TYPE_CHECKING, overload
|
||||||
|
|
||||||
|
from systemrdl.node import AddressableNode
|
||||||
|
|
||||||
|
from ...utils import get_indexed_path
|
||||||
|
from ..base_cpuif import BaseCpuif
|
||||||
|
from .taxi_apb_interface import TaxiAPBSVInterface
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from ...exporter import BusDecoderExporter
|
||||||
|
|
||||||
|
|
||||||
|
class TaxiAPBCpuif(BaseCpuif):
|
||||||
|
template_path = "taxi_apb_tmpl.sv"
|
||||||
|
|
||||||
|
def __init__(self, exp: "BusDecoderExporter") -> None:
|
||||||
|
super().__init__(exp)
|
||||||
|
self._interface = TaxiAPBSVInterface(self)
|
||||||
|
self._interface.master_modport_name = "mst"
|
||||||
|
self._interface.slave_modport_name = "slv"
|
||||||
|
|
||||||
|
@property
|
||||||
|
def is_interface(self) -> bool:
|
||||||
|
return self._interface.is_interface
|
||||||
|
|
||||||
|
@property
|
||||||
|
def port_declaration(self) -> str:
|
||||||
|
"""Returns the port declaration for the APB4 interface."""
|
||||||
|
return self._interface.get_port_declaration("s_apb", "m_apb_")
|
||||||
|
|
||||||
|
@overload
|
||||||
|
def signal(self, signal: str, node: None = None, indexer: None = None) -> str: ...
|
||||||
|
@overload
|
||||||
|
def signal(self, signal: str, node: AddressableNode, indexer: str) -> str: ...
|
||||||
|
def signal(self, signal: str, node: AddressableNode | None = None, indexer: str | None = None) -> str:
|
||||||
|
return self._interface.signal(signal, node, indexer)
|
||||||
|
|
||||||
|
def fanout(self, node: AddressableNode, array_stack: deque[int]) -> str:
|
||||||
|
fanout: dict[str, str] = {}
|
||||||
|
fanout[self.signal("psel", node, "gi")] = (
|
||||||
|
f"cpuif_wr_sel.{get_indexed_path(self.exp.ds.top_node, node, 'gi')}|cpuif_rd_sel.{get_indexed_path(self.exp.ds.top_node, node, 'gi')}"
|
||||||
|
)
|
||||||
|
fanout[self.signal("penable", node, "gi")] = self.signal("penable")
|
||||||
|
fanout[self.signal("pwrite", node, "gi")] = (
|
||||||
|
f"cpuif_wr_sel.{get_indexed_path(self.exp.ds.top_node, node, 'gi')}"
|
||||||
|
)
|
||||||
|
fanout[self.signal("paddr", node, "gi")] = self.signal("paddr")
|
||||||
|
fanout[self.signal("pprot", node, "gi")] = self.signal("pprot")
|
||||||
|
fanout[self.signal("pwdata", node, "gi")] = "cpuif_wr_data"
|
||||||
|
fanout[self.signal("pstrb", node, "gi")] = "cpuif_wr_byte_en"
|
||||||
|
# no user?
|
||||||
|
|
||||||
|
return "\n".join(map(lambda kv: f"assign {kv[0]} = {kv[1]};", fanout.items()))
|
||||||
|
|
||||||
|
def fanin_wr(self, node: AddressableNode | None = None, *, error: bool = False) -> str:
|
||||||
|
fanin: dict[str, str] = {}
|
||||||
|
if node is None:
|
||||||
|
fanin["cpuif_rd_ack"] = "'0"
|
||||||
|
fanin["cpuif_rd_err"] = "'0"
|
||||||
|
else:
|
||||||
|
# Use intermediate signals for interface arrays to avoid
|
||||||
|
# non-constant indexing of interface arrays in procedural blocks
|
||||||
|
if self.is_interface and node.is_array and node.array_dimensions:
|
||||||
|
# Generate array index string [i0][i1]... for the intermediate signal
|
||||||
|
array_idx = "".join(f"[i{i}]" for i in range(len(node.array_dimensions)))
|
||||||
|
fanin["cpuif_rd_ack"] = f"{node.inst_name}_fanin_ready{array_idx}"
|
||||||
|
fanin["cpuif_rd_err"] = f"{node.inst_name}_fanin_err{array_idx}"
|
||||||
|
else:
|
||||||
|
fanin["cpuif_rd_ack"] = self.signal("pready", node, "i")
|
||||||
|
fanin["cpuif_rd_err"] = self.signal("pslverr", node, "i")
|
||||||
|
|
||||||
|
# no user?
|
||||||
|
return "\n".join(map(lambda kv: f"{kv[0]} = {kv[1]};", fanin.items()))
|
||||||
|
|
||||||
|
def fanin_rd(self, node: AddressableNode | None = None, *, error: bool = False) -> str:
|
||||||
|
fanin: dict[str, str] = {}
|
||||||
|
if node is None:
|
||||||
|
fanin["cpuif_rd_ack"] = "'0"
|
||||||
|
fanin["cpuif_rd_err"] = "'0"
|
||||||
|
fanin["cpuif_rd_data"] = "'0"
|
||||||
|
if error:
|
||||||
|
fanin["cpuif_rd_ack"] = "'1"
|
||||||
|
fanin["cpuif_rd_err"] = "cpuif_rd_sel.cpuif_err"
|
||||||
|
else:
|
||||||
|
# Use intermediate signals for interface arrays to avoid
|
||||||
|
# non-constant indexing of interface arrays in procedural blocks
|
||||||
|
if self.is_interface and node.is_array and node.array_dimensions:
|
||||||
|
# Generate array index string [i0][i1]... for the intermediate signal
|
||||||
|
array_idx = "".join(f"[i{i}]" for i in range(len(node.array_dimensions)))
|
||||||
|
fanin["cpuif_rd_ack"] = f"{node.inst_name}_fanin_ready{array_idx}"
|
||||||
|
fanin["cpuif_rd_err"] = f"{node.inst_name}_fanin_err{array_idx}"
|
||||||
|
fanin["cpuif_rd_data"] = f"{node.inst_name}_fanin_data{array_idx}"
|
||||||
|
else:
|
||||||
|
fanin["cpuif_rd_ack"] = self.signal("prdata", node, "i")
|
||||||
|
fanin["cpuif_rd_err"] = self.signal("pslverr", node, "i")
|
||||||
|
fanin["cpuif_rd_data"] = self.signal("prdata", node, "i")
|
||||||
|
|
||||||
|
return "\n".join(map(lambda kv: f"{kv[0]} = {kv[1]};", fanin.items()))
|
||||||
|
|
||||||
|
def fanin_intermediate_assignments(
|
||||||
|
self, node: AddressableNode, inst_name: str, array_idx: str, master_prefix: str, indexed_path: str
|
||||||
|
) -> list[str]:
|
||||||
|
"""Generate intermediate signal assignments for APB4 interface arrays."""
|
||||||
|
return [
|
||||||
|
f"assign {inst_name}_fanin_ready{array_idx} = {master_prefix}{indexed_path}.pready;",
|
||||||
|
f"assign {inst_name}_fanin_err{array_idx} = {master_prefix}{indexed_path}.pslverr;",
|
||||||
|
f"assign {inst_name}_fanin_data{array_idx} = {master_prefix}{indexed_path}.prdata;",
|
||||||
|
]
|
||||||
16
src/peakrdl_busdecoder/cpuif/taxi_apb/taxi_apb_interface.py
Normal file
16
src/peakrdl_busdecoder/cpuif/taxi_apb/taxi_apb_interface.py
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
"""Taxi APB-specific interface implementations."""
|
||||||
|
|
||||||
|
from ..interface import SVInterface
|
||||||
|
|
||||||
|
|
||||||
|
class TaxiAPBSVInterface(SVInterface):
|
||||||
|
"""Taxi APB SystemVerilog interface."""
|
||||||
|
|
||||||
|
def get_interface_type(self) -> str:
|
||||||
|
return "taxi_apb_if"
|
||||||
|
|
||||||
|
def get_slave_name(self) -> str:
|
||||||
|
return "s_apb"
|
||||||
|
|
||||||
|
def get_master_prefix(self) -> str:
|
||||||
|
return "m_apb_"
|
||||||
44
src/peakrdl_busdecoder/cpuif/taxi_apb/taxi_apb_tmpl.sv
Normal file
44
src/peakrdl_busdecoder/cpuif/taxi_apb/taxi_apb_tmpl.sv
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
{%- if cpuif.is_interface %}
|
||||||
|
`ifndef SYNTHESIS
|
||||||
|
initial begin
|
||||||
|
assert_bad_addr_width: assert($bits({{cpuif.signal("paddr")}}) >= {{ds.package_name}}::{{ds.module_name|upper}}_MIN_ADDR_WIDTH)
|
||||||
|
else $error("Interface address width of %0d is too small. Shall be at least %0d bits", $bits({{cpuif.signal("paddr")}}), {{ds.package_name}}::{{ds.module_name|upper}}_MIN_ADDR_WIDTH);
|
||||||
|
assert_bad_data_width: assert($bits({{cpuif.signal("pwdata")}}) == {{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("pwdata")}}), {{ds.package_name}}::{{ds.module_name|upper}}_DATA_WIDTH);
|
||||||
|
end
|
||||||
|
`ifdef PEAKRDL_ASSERTIONS
|
||||||
|
assert_wr_sel: assert property (@(posedge {{cpuif.signal("PCLK")}}) {{cpuif.signal("psel")}} && {{cpuif.signal("pwrite")}} |-> ##1 ({{cpuif.signal("pready")}} || {{cpuif.signal("pslverr")}}))
|
||||||
|
else $error("APB4 Slave port SEL implies that cpuif_wr_sel must be one-hot encoded");
|
||||||
|
`endif
|
||||||
|
`endif
|
||||||
|
{%- endif %}
|
||||||
|
|
||||||
|
assign cpuif_req = {{cpuif.signal("psel")}};
|
||||||
|
assign cpuif_wr_en = {{cpuif.signal("pwrite")}};
|
||||||
|
assign cpuif_rd_en = !{{cpuif.signal("pwrite")}};
|
||||||
|
|
||||||
|
assign cpuif_wr_addr = {{cpuif.signal("paddr")}};
|
||||||
|
assign cpuif_rd_addr = {{cpuif.signal("paddr")}};
|
||||||
|
|
||||||
|
assign cpuif_wr_data = {{cpuif.signal("pwdata")}};
|
||||||
|
assign cpuif_wr_byte_en = {{cpuif.signal("pstrb")}};
|
||||||
|
|
||||||
|
assign {{cpuif.signal("prdata")}} = cpuif_rd_data;
|
||||||
|
assign {{cpuif.signal("pready")}} = cpuif_rd_ack | cpuif_wr_ack;
|
||||||
|
assign {{cpuif.signal("pslverr")}} = cpuif_rd_err | cpuif_wr_err;
|
||||||
|
//--------------------------------------------------------------------------
|
||||||
|
// Fanout CPU Bus interface signals
|
||||||
|
//--------------------------------------------------------------------------
|
||||||
|
{{fanout|walk(cpuif=cpuif)}}
|
||||||
|
{%- if cpuif.is_interface %}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------
|
||||||
|
// Intermediate signals for interface array fanin
|
||||||
|
//--------------------------------------------------------------------------
|
||||||
|
{{fanin_intermediate|walk(cpuif=cpuif)}}
|
||||||
|
{%- endif %}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------
|
||||||
|
// Fanin CPU Bus interface signals
|
||||||
|
//--------------------------------------------------------------------------
|
||||||
|
{{fanin|walk(cpuif=cpuif)}}
|
||||||
@@ -44,3 +44,14 @@ class DesignScanner(RDLListener):
|
|||||||
self.ds.has_external_addressable = True
|
self.ds.has_external_addressable = True
|
||||||
if not isinstance(node, RegNode):
|
if not isinstance(node, RegNode):
|
||||||
self.ds.has_external_block = True
|
self.ds.has_external_block = True
|
||||||
|
|
||||||
|
def enter_Reg(self, node: RegNode) -> None:
|
||||||
|
if node.external and node != self.top_node:
|
||||||
|
return
|
||||||
|
|
||||||
|
accesswidth = node.get_property("accesswidth")
|
||||||
|
if accesswidth is None:
|
||||||
|
return
|
||||||
|
|
||||||
|
if accesswidth > self.ds.cpuif_data_width:
|
||||||
|
self.ds.cpuif_data_width = accesswidth
|
||||||
|
|||||||
@@ -5,6 +5,8 @@ RDL_CASES: list[tuple[str, str]] = [
|
|||||||
("multiple_reg.rdl", "multi_reg"),
|
("multiple_reg.rdl", "multi_reg"),
|
||||||
("deep_hierarchy.rdl", "deep_hierarchy"),
|
("deep_hierarchy.rdl", "deep_hierarchy"),
|
||||||
("wide_status.rdl", "wide_status"),
|
("wide_status.rdl", "wide_status"),
|
||||||
|
("wide_access_64.rdl", "wide_access_64"),
|
||||||
|
("wide_access_128.rdl", "wide_access_128"),
|
||||||
("variable_layout.rdl", "variable_layout"),
|
("variable_layout.rdl", "variable_layout"),
|
||||||
("asymmetric_bus.rdl", "asymmetric_bus"),
|
("asymmetric_bus.rdl", "asymmetric_bus"),
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -73,6 +73,7 @@ addrmap asymmetric_bus {
|
|||||||
|
|
||||||
reg {
|
reg {
|
||||||
regwidth = 64;
|
regwidth = 64;
|
||||||
|
accesswidth = 32;
|
||||||
field {
|
field {
|
||||||
sw = rw;
|
sw = rw;
|
||||||
hw = rw;
|
hw = rw;
|
||||||
@@ -88,11 +89,18 @@ addrmap asymmetric_bus {
|
|||||||
|
|
||||||
reg {
|
reg {
|
||||||
regwidth = 128;
|
regwidth = 128;
|
||||||
|
accesswidth = 32;
|
||||||
field {
|
field {
|
||||||
sw = rw;
|
sw = rw;
|
||||||
hw = rw;
|
hw = rw;
|
||||||
reset = 0x0;
|
reset = 0x0;
|
||||||
} extended_id[63:0];
|
} extended_id_low[31:0];
|
||||||
|
|
||||||
|
field {
|
||||||
|
sw = rw;
|
||||||
|
hw = rw;
|
||||||
|
reset = 0x0;
|
||||||
|
} extended_id_high[63:32];
|
||||||
|
|
||||||
field {
|
field {
|
||||||
sw = rw;
|
sw = rw;
|
||||||
|
|||||||
@@ -69,6 +69,7 @@ regfile slice_rf {
|
|||||||
|
|
||||||
reg {
|
reg {
|
||||||
regwidth = 64;
|
regwidth = 64;
|
||||||
|
accesswidth = 32;
|
||||||
field {
|
field {
|
||||||
sw = r;
|
sw = r;
|
||||||
hw = w;
|
hw = w;
|
||||||
|
|||||||
75
tests/cocotb_lib/rdl/wide_access_128.rdl
Normal file
75
tests/cocotb_lib/rdl/wide_access_128.rdl
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
reg payload128_reg_t {
|
||||||
|
regwidth = 128;
|
||||||
|
accesswidth = 128;
|
||||||
|
desc = "128-bit payload register.";
|
||||||
|
|
||||||
|
field {
|
||||||
|
sw = rw;
|
||||||
|
hw = rw;
|
||||||
|
reset = 0x0;
|
||||||
|
} word0[31:0];
|
||||||
|
|
||||||
|
field {
|
||||||
|
sw = rw;
|
||||||
|
hw = rw;
|
||||||
|
reset = 0x0;
|
||||||
|
} word1[63:32];
|
||||||
|
|
||||||
|
field {
|
||||||
|
sw = rw;
|
||||||
|
hw = rw;
|
||||||
|
reset = 0x0;
|
||||||
|
} word2[95:64];
|
||||||
|
|
||||||
|
field {
|
||||||
|
sw = rw;
|
||||||
|
hw = rw;
|
||||||
|
reset = 0x0;
|
||||||
|
} word3[127:96];
|
||||||
|
};
|
||||||
|
|
||||||
|
regfile block128_rf {
|
||||||
|
payload128_reg_t payload @ 0x0;
|
||||||
|
|
||||||
|
reg {
|
||||||
|
regwidth = 128;
|
||||||
|
accesswidth = 128;
|
||||||
|
field {
|
||||||
|
sw = r;
|
||||||
|
hw = w;
|
||||||
|
reset = 0x0;
|
||||||
|
} status0[31:0];
|
||||||
|
|
||||||
|
field {
|
||||||
|
sw = r;
|
||||||
|
hw = w;
|
||||||
|
reset = 0x0;
|
||||||
|
} status1[63:32];
|
||||||
|
|
||||||
|
field {
|
||||||
|
sw = r;
|
||||||
|
hw = w;
|
||||||
|
reset = 0x0;
|
||||||
|
} status2[95:64];
|
||||||
|
|
||||||
|
field {
|
||||||
|
sw = r;
|
||||||
|
hw = w;
|
||||||
|
reset = 0x0;
|
||||||
|
} status3[127:96];
|
||||||
|
} status @ 0x10;
|
||||||
|
};
|
||||||
|
|
||||||
|
addrmap wide_access_128 {
|
||||||
|
block128_rf blocks[2] @ 0x0 += 0x40;
|
||||||
|
|
||||||
|
reg {
|
||||||
|
regwidth = 64;
|
||||||
|
accesswidth = 64;
|
||||||
|
field {
|
||||||
|
sw = rw;
|
||||||
|
hw = rw;
|
||||||
|
reset = 0x0;
|
||||||
|
} id[63:0];
|
||||||
|
} id @ 0x100;
|
||||||
|
};
|
||||||
56
tests/cocotb_lib/rdl/wide_access_64.rdl
Normal file
56
tests/cocotb_lib/rdl/wide_access_64.rdl
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
reg status64_reg_t {
|
||||||
|
regwidth = 64;
|
||||||
|
accesswidth = 64;
|
||||||
|
desc = "64-bit status register.";
|
||||||
|
|
||||||
|
field {
|
||||||
|
sw = r;
|
||||||
|
hw = w;
|
||||||
|
reset = 0x0;
|
||||||
|
} status_lo[31:0];
|
||||||
|
|
||||||
|
field {
|
||||||
|
sw = r;
|
||||||
|
hw = w;
|
||||||
|
reset = 0x0;
|
||||||
|
} status_hi[63:32];
|
||||||
|
};
|
||||||
|
|
||||||
|
regfile channel64_rf {
|
||||||
|
status64_reg_t status @ 0x0;
|
||||||
|
|
||||||
|
reg {
|
||||||
|
regwidth = 64;
|
||||||
|
accesswidth = 64;
|
||||||
|
field {
|
||||||
|
sw = rw;
|
||||||
|
hw = rw;
|
||||||
|
reset = 0x1;
|
||||||
|
} enable[0:0];
|
||||||
|
|
||||||
|
field {
|
||||||
|
sw = rw;
|
||||||
|
hw = rw;
|
||||||
|
reset = 0x0;
|
||||||
|
} mode[2:1];
|
||||||
|
|
||||||
|
field {
|
||||||
|
sw = rw;
|
||||||
|
hw = rw;
|
||||||
|
reset = 0x0;
|
||||||
|
} threshold[63:3];
|
||||||
|
} control @ 0x8;
|
||||||
|
};
|
||||||
|
|
||||||
|
addrmap wide_access_64 {
|
||||||
|
channel64_rf channels[4] @ 0x0 += 0x20;
|
||||||
|
|
||||||
|
reg {
|
||||||
|
regwidth = 32;
|
||||||
|
field {
|
||||||
|
sw = rw;
|
||||||
|
hw = rw;
|
||||||
|
reset = 0x0;
|
||||||
|
} flags[31:0];
|
||||||
|
} flags @ 0x100;
|
||||||
|
};
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
reg status_reg_t {
|
reg status_reg_t {
|
||||||
regwidth = 64;
|
regwidth = 64;
|
||||||
|
accesswidth = 32;
|
||||||
desc = "Status register capturing wide flags and sticky bits.";
|
desc = "Status register capturing wide flags and sticky bits.";
|
||||||
|
|
||||||
field {
|
field {
|
||||||
@@ -7,7 +8,14 @@ reg status_reg_t {
|
|||||||
hw = w;
|
hw = w;
|
||||||
onread = rclr;
|
onread = rclr;
|
||||||
reset = 0x0;
|
reset = 0x0;
|
||||||
} flags[62:0];
|
} flags_low[31:0];
|
||||||
|
|
||||||
|
field {
|
||||||
|
sw = r;
|
||||||
|
hw = w;
|
||||||
|
onread = rclr;
|
||||||
|
reset = 0x0;
|
||||||
|
} flags_high[62:32];
|
||||||
|
|
||||||
field {
|
field {
|
||||||
sw = rw;
|
sw = rw;
|
||||||
@@ -18,6 +26,7 @@ reg status_reg_t {
|
|||||||
|
|
||||||
reg metrics_reg_t {
|
reg metrics_reg_t {
|
||||||
regwidth = 64;
|
regwidth = 64;
|
||||||
|
accesswidth = 32;
|
||||||
desc = "Metrics register pairing counters with thresholds.";
|
desc = "Metrics register pairing counters with thresholds.";
|
||||||
|
|
||||||
field {
|
field {
|
||||||
@@ -40,11 +49,30 @@ addrmap wide_status {
|
|||||||
|
|
||||||
reg {
|
reg {
|
||||||
regwidth = 128;
|
regwidth = 128;
|
||||||
|
accesswidth = 32;
|
||||||
field {
|
field {
|
||||||
sw = rw;
|
sw = rw;
|
||||||
hw = rw;
|
hw = rw;
|
||||||
reset = 0x0;
|
reset = 0x0;
|
||||||
} configuration[127:0];
|
} configuration_0[31:0];
|
||||||
|
|
||||||
|
field {
|
||||||
|
sw = rw;
|
||||||
|
hw = rw;
|
||||||
|
reset = 0x0;
|
||||||
|
} configuration_1[63:32];
|
||||||
|
|
||||||
|
field {
|
||||||
|
sw = rw;
|
||||||
|
hw = rw;
|
||||||
|
reset = 0x0;
|
||||||
|
} configuration_2[95:64];
|
||||||
|
|
||||||
|
field {
|
||||||
|
sw = rw;
|
||||||
|
hw = rw;
|
||||||
|
reset = 0x0;
|
||||||
|
} configuration_3[127:96];
|
||||||
} configuration @ 0x800;
|
} configuration @ 0x800;
|
||||||
|
|
||||||
reg {
|
reg {
|
||||||
|
|||||||
@@ -122,3 +122,43 @@ class TestDesignState:
|
|||||||
|
|
||||||
# Should infer 32-bit data width from field
|
# Should infer 32-bit data width from field
|
||||||
assert ds.cpuif_data_width == 32
|
assert ds.cpuif_data_width == 32
|
||||||
|
|
||||||
|
def test_design_state_accesswidth_64(self, compile_rdl: Callable[..., AddrmapNode]) -> None:
|
||||||
|
"""Test DesignState with explicit 64-bit access width."""
|
||||||
|
rdl_source = """
|
||||||
|
addrmap test {
|
||||||
|
reg {
|
||||||
|
regwidth = 64;
|
||||||
|
accesswidth = 64;
|
||||||
|
field {
|
||||||
|
sw=rw;
|
||||||
|
hw=r;
|
||||||
|
} data[63:0];
|
||||||
|
} my_reg @ 0x0;
|
||||||
|
};
|
||||||
|
"""
|
||||||
|
top = compile_rdl(rdl_source, top="test")
|
||||||
|
|
||||||
|
ds = DesignState(top, {})
|
||||||
|
|
||||||
|
assert ds.cpuif_data_width == 64
|
||||||
|
|
||||||
|
def test_design_state_accesswidth_128(self, compile_rdl: Callable[..., AddrmapNode]) -> None:
|
||||||
|
"""Test DesignState with explicit 128-bit access width."""
|
||||||
|
rdl_source = """
|
||||||
|
addrmap test {
|
||||||
|
reg {
|
||||||
|
regwidth = 128;
|
||||||
|
accesswidth = 128;
|
||||||
|
field {
|
||||||
|
sw=rw;
|
||||||
|
hw=r;
|
||||||
|
} data[127:0];
|
||||||
|
} my_reg @ 0x0;
|
||||||
|
};
|
||||||
|
"""
|
||||||
|
top = compile_rdl(rdl_source, top="test")
|
||||||
|
|
||||||
|
ds = DesignState(top, {})
|
||||||
|
|
||||||
|
assert ds.cpuif_data_width == 128
|
||||||
|
|||||||
2
uv.lock
generated
2
uv.lock
generated
@@ -526,7 +526,7 @@ wheels = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "peakrdl-busdecoder"
|
name = "peakrdl-busdecoder"
|
||||||
version = "0.6.7"
|
version = "0.6.8"
|
||||||
source = { editable = "." }
|
source = { editable = "." }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "jinja2" },
|
{ name = "jinja2" },
|
||||||
|
|||||||
Reference in New Issue
Block a user