Initial Commit
This commit is contained in:
20
.gitignore
vendored
Normal file
20
.gitignore
vendored
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
**/__pycache__
|
||||||
|
**/.vscode
|
||||||
|
**/.venv
|
||||||
|
**/.coverage
|
||||||
|
**/*.rpt
|
||||||
|
**/.pytest_cache
|
||||||
|
**/_build
|
||||||
|
**/*.out
|
||||||
|
**/transcript
|
||||||
|
**/htmlcov
|
||||||
|
**/*.log
|
||||||
|
**/*.pb
|
||||||
|
**/.Xil
|
||||||
|
**/.coverage.*
|
||||||
|
coverage.xml
|
||||||
|
|
||||||
|
build/
|
||||||
|
dist/
|
||||||
|
*.egg-info/
|
||||||
|
.eggs/
|
||||||
1
MANIFEST.in
Normal file
1
MANIFEST.in
Normal file
@@ -0,0 +1 @@
|
|||||||
|
recursive-include src/taxi_peakrdl_extensions *.sv
|
||||||
51
pyproject.toml
Normal file
51
pyproject.toml
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
[build-system]
|
||||||
|
requires = ["setuptools", "setuptools-scm"]
|
||||||
|
build-backend = "setuptools.build_meta"
|
||||||
|
|
||||||
|
[project]
|
||||||
|
name = "taxi-peakrdl-extensions"
|
||||||
|
version = "0.0.1"
|
||||||
|
requires-python = ">=3.10"
|
||||||
|
dependencies = [
|
||||||
|
"jinja2~=3.1",
|
||||||
|
"systemrdl-compiler~=1.30",
|
||||||
|
]
|
||||||
|
|
||||||
|
authors = [{ name = "Arnav Sacheti" }]
|
||||||
|
description = "Add Taxi interfaces to peakrdl tools"
|
||||||
|
readme = "README.md"
|
||||||
|
license = { text = "LGPLv3" }
|
||||||
|
keywords = [
|
||||||
|
"SystemRDL",
|
||||||
|
"PeakRDL",
|
||||||
|
"hierarchical addressing",
|
||||||
|
"compiler",
|
||||||
|
"tool",
|
||||||
|
"registers",
|
||||||
|
"generator",
|
||||||
|
"Verilog",
|
||||||
|
"SystemVerilog",
|
||||||
|
"register abstraction layer",
|
||||||
|
"FPGA",
|
||||||
|
"ASIC",
|
||||||
|
]
|
||||||
|
classifiers = [
|
||||||
|
"Development Status :: 5 - Production/Stable",
|
||||||
|
"Programming Language :: Python",
|
||||||
|
"Programming Language :: Python :: 3",
|
||||||
|
"Programming Language :: Python :: 3 :: Only",
|
||||||
|
"Intended Audience :: Developers",
|
||||||
|
"License :: OSI Approved :: GNU Lesser General Public License v3 (LGPLv3)",
|
||||||
|
"Operating System :: OS Independent",
|
||||||
|
"Topic :: Scientific/Engineering :: Electronic Design Automation (EDA)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[project.optional-dependencies]
|
||||||
|
cli = ["peakrdl-cli >= 1.2.3"]
|
||||||
|
|
||||||
|
[project.entry-points."peakrdl_regblock.cpuif"]
|
||||||
|
taxi-apb = "taxi_peakrdl_extensions.cpuif.regblock_taxi_apb:TaxiAPBCpuif"
|
||||||
|
|
||||||
|
[project.entry-points."peakrdl_busdecoder.cpuif"]
|
||||||
|
taxi-apb = "taxi_peakrdl_extensions.cpuif.busdecoder_taxi_apb:TaxiAPBCpuif"
|
||||||
|
|
||||||
119
src/taxi_peakrdl_extensions/cpuif/busdecoder_taxi_apb.py
Normal file
119
src/taxi_peakrdl_extensions/cpuif/busdecoder_taxi_apb.py
Normal file
@@ -0,0 +1,119 @@
|
|||||||
|
from collections import deque
|
||||||
|
from typing import TYPE_CHECKING, overload
|
||||||
|
|
||||||
|
from systemrdl.node import AddressableNode
|
||||||
|
|
||||||
|
from peakrdl_busdecoder.utils import get_indexed_path
|
||||||
|
from peakrdl_busdecoder.cpuif.base_cpuif import BaseCpuif
|
||||||
|
from peakrdl_busdecoder.cpuif.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_"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class TaxiAPBCpuif(BaseCpuif):
|
||||||
|
template_path = "busdecoder_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;",
|
||||||
|
]
|
||||||
@@ -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)}}
|
||||||
12
src/taxi_peakrdl_extensions/cpuif/regblock_taxi_apb.py
Normal file
12
src/taxi_peakrdl_extensions/cpuif/regblock_taxi_apb.py
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
from peakrdl_regblock.cpuif.base import CpuifBase
|
||||||
|
|
||||||
|
class TaxiAPBCpuif(CpuifBase):
|
||||||
|
template_path = "regblock_taxi_apb_tmpl.sv"
|
||||||
|
is_interface = True
|
||||||
|
|
||||||
|
@property
|
||||||
|
def port_declaration(self) -> str:
|
||||||
|
return "taxi_apb_if.slv s_apb"
|
||||||
|
|
||||||
|
def signal(self, name:str) -> str:
|
||||||
|
return "s_apb." + name
|
||||||
51
src/taxi_peakrdl_extensions/cpuif/regblock_taxi_apb_tmpl.sv
Normal file
51
src/taxi_peakrdl_extensions/cpuif/regblock_taxi_apb_tmpl.sv
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
{%- 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
|
||||||
|
`endif
|
||||||
|
|
||||||
|
{% endif -%}
|
||||||
|
|
||||||
|
// Request
|
||||||
|
logic is_active;
|
||||||
|
always_ff {{get_always_ff_event(cpuif.reset)}} begin
|
||||||
|
if({{get_resetsignal(cpuif.reset)}}) begin
|
||||||
|
is_active <= '0;
|
||||||
|
cpuif_req <= '0;
|
||||||
|
cpuif_req_is_wr <= '0;
|
||||||
|
cpuif_addr <= '0;
|
||||||
|
cpuif_wr_data <= '0;
|
||||||
|
cpuif_wr_biten <= '0;
|
||||||
|
end else begin
|
||||||
|
if(~is_active) begin
|
||||||
|
if({{cpuif.signal("psel")}}) begin
|
||||||
|
is_active <= '1;
|
||||||
|
cpuif_req <= '1;
|
||||||
|
cpuif_req_is_wr <= {{cpuif.signal("pwrite")}};
|
||||||
|
{%- if cpuif.data_width_bytes == 1 %}
|
||||||
|
cpuif_addr <= {{cpuif.signal("paddr")}}[{{cpuif.addr_width-1}}:0];
|
||||||
|
{%- else %}
|
||||||
|
cpuif_addr <= { {{-cpuif.signal("paddr")}}[{{cpuif.addr_width-1}}:{{clog2(cpuif.data_width_bytes)}}], {{clog2(cpuif.data_width_bytes)}}'b0};
|
||||||
|
{%- endif %}
|
||||||
|
cpuif_wr_data <= {{cpuif.signal("pwdata")}};
|
||||||
|
for(int i=0; i<{{cpuif.data_width_bytes}}; i++) begin
|
||||||
|
cpuif_wr_biten[i*8 +: 8] <= {8{ {{-cpuif.signal("pstrb")}}[i]}};
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end else begin
|
||||||
|
cpuif_req <= '0;
|
||||||
|
if(cpuif_rd_ack || cpuif_wr_ack) begin
|
||||||
|
is_active <= '0;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
// Response
|
||||||
|
assign {{cpuif.signal("pready")}} = cpuif_rd_ack | cpuif_wr_ack;
|
||||||
|
assign {{cpuif.signal("prdata")}} = cpuif_rd_data;
|
||||||
|
assign {{cpuif.signal("pslverr")}} = cpuif_rd_err | cpuif_wr_err;
|
||||||
Reference in New Issue
Block a user