Fix APB PREADY not asserted on invalid address decode errors (#40)
Fix APB PREADY signal to assert during error conditions Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: arnavsacheti <36746504+arnavsacheti@users.noreply.github.com>
This commit is contained in:
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|||||||
|
|
||||||
[project]
|
[project]
|
||||||
name = "peakrdl-busdecoder"
|
name = "peakrdl-busdecoder"
|
||||||
version = "0.6.5"
|
version = "0.6.6"
|
||||||
requires-python = ">=3.10"
|
requires-python = ">=3.10"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"jinja2~=3.1",
|
"jinja2~=3.1",
|
||||||
|
|||||||
@@ -47,11 +47,36 @@ class APB3Cpuif(BaseCpuif):
|
|||||||
|
|
||||||
return "\n".join(f"assign {kv[0]} = {kv[1]};" for kv in fanout.items())
|
return "\n".join(f"assign {kv[0]} = {kv[1]};" for kv in fanout.items())
|
||||||
|
|
||||||
def fanin(self, node: AddressableNode | None = None) -> str:
|
def fanin_wr(self, node: AddressableNode | None = None, *, error: bool = False) -> str:
|
||||||
|
fanin: dict[str, str] = {}
|
||||||
|
if node is None:
|
||||||
|
fanin["cpuif_wr_ack"] = "'0"
|
||||||
|
fanin["cpuif_wr_err"] = "'0"
|
||||||
|
if error:
|
||||||
|
fanin["cpuif_wr_ack"] = "'1"
|
||||||
|
fanin["cpuif_wr_err"] = "cpuif_wr_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_wr_ack"] = f"{node.inst_name}_fanin_ready{array_idx}"
|
||||||
|
fanin["cpuif_wr_err"] = f"{node.inst_name}_fanin_err{array_idx}"
|
||||||
|
else:
|
||||||
|
fanin["cpuif_wr_ack"] = self.signal("PREADY", node, "i")
|
||||||
|
fanin["cpuif_wr_err"] = self.signal("PSLVERR", node, "i")
|
||||||
|
return "\n".join(f"{kv[0]} = {kv[1]};" for kv in fanin.items())
|
||||||
|
|
||||||
|
def fanin_rd(self, node: AddressableNode | None = None, *, error: bool = False) -> str:
|
||||||
fanin: dict[str, str] = {}
|
fanin: dict[str, str] = {}
|
||||||
if node is None:
|
if node is None:
|
||||||
fanin["cpuif_rd_ack"] = "'0"
|
fanin["cpuif_rd_ack"] = "'0"
|
||||||
fanin["cpuif_rd_err"] = "'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:
|
else:
|
||||||
# Use intermediate signals for interface arrays to avoid
|
# Use intermediate signals for interface arrays to avoid
|
||||||
# non-constant indexing of interface arrays in procedural blocks
|
# non-constant indexing of interface arrays in procedural blocks
|
||||||
@@ -60,24 +85,10 @@ class APB3Cpuif(BaseCpuif):
|
|||||||
array_idx = "".join(f"[i{i}]" for i in range(len(node.array_dimensions)))
|
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_ack"] = f"{node.inst_name}_fanin_ready{array_idx}"
|
||||||
fanin["cpuif_rd_err"] = f"{node.inst_name}_fanin_err{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:
|
else:
|
||||||
fanin["cpuif_rd_ack"] = self.signal("PREADY", node, "i")
|
fanin["cpuif_rd_ack"] = self.signal("PREADY", node, "i")
|
||||||
fanin["cpuif_rd_err"] = self.signal("PSLVERR", node, "i")
|
fanin["cpuif_rd_err"] = self.signal("PSLVERR", node, "i")
|
||||||
|
|
||||||
return "\n".join(f"{kv[0]} = {kv[1]};" for kv in fanin.items())
|
|
||||||
|
|
||||||
def readback(self, node: AddressableNode | None = None) -> str:
|
|
||||||
fanin: dict[str, str] = {}
|
|
||||||
if node is None:
|
|
||||||
fanin["cpuif_rd_data"] = "'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_data"] = f"{node.inst_name}_fanin_data{array_idx}"
|
|
||||||
else:
|
|
||||||
fanin["cpuif_rd_data"] = self.signal("PRDATA", node, "i")
|
fanin["cpuif_rd_data"] = self.signal("PRDATA", node, "i")
|
||||||
|
|
||||||
return "\n".join(f"{kv[0]} = {kv[1]};" for kv in fanin.items())
|
return "\n".join(f"{kv[0]} = {kv[1]};" for kv in fanin.items())
|
||||||
|
|||||||
@@ -53,22 +53,32 @@ class APB3CpuifFlat(BaseCpuif):
|
|||||||
|
|
||||||
return "\n".join(f"assign {kv[0]} = {kv[1]};" for kv in fanout.items())
|
return "\n".join(f"assign {kv[0]} = {kv[1]};" for kv in fanout.items())
|
||||||
|
|
||||||
def fanin(self, node: AddressableNode | None = None) -> str:
|
def fanin_wr(self, node: AddressableNode | None = None, *, error: bool = False) -> str:
|
||||||
|
fanin: dict[str, str] = {}
|
||||||
|
if node is None:
|
||||||
|
fanin["cpuif_wr_ack"] = "'0"
|
||||||
|
fanin["cpuif_wr_err"] = "'0"
|
||||||
|
if error:
|
||||||
|
fanin["cpuif_wr_ack"] = "'1"
|
||||||
|
fanin["cpuif_wr_err"] = "cpuif_wr_sel.cpuif_err"
|
||||||
|
else:
|
||||||
|
fanin["cpuif_wr_ack"] = self.signal("PREADY", node, "i")
|
||||||
|
fanin["cpuif_wr_err"] = self.signal("PSLVERR", node, "i")
|
||||||
|
|
||||||
|
return "\n".join(f"{kv[0]} = {kv[1]};" for kv in fanin.items())
|
||||||
|
|
||||||
|
def fanin_rd(self, node: AddressableNode | None = None, *, error: bool = False) -> str:
|
||||||
fanin: dict[str, str] = {}
|
fanin: dict[str, str] = {}
|
||||||
if node is None:
|
if node is None:
|
||||||
fanin["cpuif_rd_ack"] = "'0"
|
fanin["cpuif_rd_ack"] = "'0"
|
||||||
fanin["cpuif_rd_err"] = "'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:
|
else:
|
||||||
fanin["cpuif_rd_ack"] = self.signal("PREADY", node, "i")
|
fanin["cpuif_rd_ack"] = self.signal("PREADY", node, "i")
|
||||||
fanin["cpuif_rd_err"] = self.signal("PSLVERR", node, "i")
|
fanin["cpuif_rd_err"] = self.signal("PSLVERR", node, "i")
|
||||||
|
|
||||||
return "\n".join(f"{kv[0]} = {kv[1]};" for kv in fanin.items())
|
|
||||||
|
|
||||||
def readback(self, node: AddressableNode | None = None) -> str:
|
|
||||||
fanin: dict[str, str] = {}
|
|
||||||
if node is None:
|
|
||||||
fanin["cpuif_rd_data"] = "'0"
|
|
||||||
else:
|
|
||||||
fanin["cpuif_rd_data"] = self.signal("PRDATA", node, "i")
|
fanin["cpuif_rd_data"] = self.signal("PRDATA", node, "i")
|
||||||
|
|
||||||
return "\n".join(f"{kv[0]} = {kv[1]};" for kv in fanin.items())
|
return "\n".join(f"{kv[0]} = {kv[1]};" for kv in fanin.items())
|
||||||
|
|||||||
@@ -19,8 +19,8 @@ assign cpuif_rd_addr = {{cpuif.signal("PADDR")}};
|
|||||||
assign cpuif_wr_data = {{cpuif.signal("PWDATA")}};
|
assign cpuif_wr_data = {{cpuif.signal("PWDATA")}};
|
||||||
|
|
||||||
assign {{cpuif.signal("PRDATA")}} = cpuif_rd_data;
|
assign {{cpuif.signal("PRDATA")}} = cpuif_rd_data;
|
||||||
assign {{cpuif.signal("PREADY")}} = cpuif_rd_ack;
|
assign {{cpuif.signal("PREADY")}} = cpuif_rd_ack | cpuif_wr_ack;
|
||||||
assign {{cpuif.signal("PSLVERR")}} = cpuif_rd_err | cpuif_rd_sel.cpuif_err | cpuif_wr_sel.cpuif_err;
|
assign {{cpuif.signal("PSLVERR")}} = cpuif_rd_err | cpuif_wr_err;
|
||||||
|
|
||||||
//--------------------------------------------------------------------------
|
//--------------------------------------------------------------------------
|
||||||
// Fanout CPU Bus interface signals
|
// Fanout CPU Bus interface signals
|
||||||
|
|||||||
@@ -50,11 +50,37 @@ class APB4Cpuif(BaseCpuif):
|
|||||||
|
|
||||||
return "\n".join(f"assign {kv[0]} = {kv[1]};" for kv in fanout.items())
|
return "\n".join(f"assign {kv[0]} = {kv[1]};" for kv in fanout.items())
|
||||||
|
|
||||||
def fanin(self, node: AddressableNode | None = None) -> str:
|
def fanin_wr(self, node: AddressableNode | None = None, *, error: bool = False) -> str:
|
||||||
|
fanin: dict[str, str] = {}
|
||||||
|
if node is None:
|
||||||
|
fanin["cpuif_wr_ack"] = "'0"
|
||||||
|
fanin["cpuif_wr_err"] = "'0"
|
||||||
|
if error:
|
||||||
|
fanin["cpuif_wr_ack"] = "'1"
|
||||||
|
fanin["cpuif_wr_err"] = "cpuif_wr_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_wr_ack"] = f"{node.inst_name}_fanin_ready{array_idx}"
|
||||||
|
fanin["cpuif_wr_err"] = f"{node.inst_name}_fanin_err{array_idx}"
|
||||||
|
else:
|
||||||
|
fanin["cpuif_wr_ack"] = self.signal("PREADY", node, "i")
|
||||||
|
fanin["cpuif_wr_err"] = self.signal("PSLVERR", node, "i")
|
||||||
|
|
||||||
|
return "\n".join(f"{kv[0]} = {kv[1]};" for kv in fanin.items())
|
||||||
|
|
||||||
|
def fanin_rd(self, node: AddressableNode | None = None, *, error: bool = False) -> str:
|
||||||
fanin: dict[str, str] = {}
|
fanin: dict[str, str] = {}
|
||||||
if node is None:
|
if node is None:
|
||||||
fanin["cpuif_rd_ack"] = "'0"
|
fanin["cpuif_rd_ack"] = "'0"
|
||||||
fanin["cpuif_rd_err"] = "'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:
|
else:
|
||||||
# Use intermediate signals for interface arrays to avoid
|
# Use intermediate signals for interface arrays to avoid
|
||||||
# non-constant indexing of interface arrays in procedural blocks
|
# non-constant indexing of interface arrays in procedural blocks
|
||||||
@@ -63,24 +89,10 @@ class APB4Cpuif(BaseCpuif):
|
|||||||
array_idx = "".join(f"[i{i}]" for i in range(len(node.array_dimensions)))
|
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_ack"] = f"{node.inst_name}_fanin_ready{array_idx}"
|
||||||
fanin["cpuif_rd_err"] = f"{node.inst_name}_fanin_err{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:
|
else:
|
||||||
fanin["cpuif_rd_ack"] = self.signal("PREADY", node, "i")
|
fanin["cpuif_rd_ack"] = self.signal("PREADY", node, "i")
|
||||||
fanin["cpuif_rd_err"] = self.signal("PSLVERR", node, "i")
|
fanin["cpuif_rd_err"] = self.signal("PSLVERR", node, "i")
|
||||||
|
|
||||||
return "\n".join(f"{kv[0]} = {kv[1]};" for kv in fanin.items())
|
|
||||||
|
|
||||||
def readback(self, node: AddressableNode | None = None) -> str:
|
|
||||||
fanin: dict[str, str] = {}
|
|
||||||
if node is None:
|
|
||||||
fanin["cpuif_rd_data"] = "'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_data"] = f"{node.inst_name}_fanin_data{array_idx}"
|
|
||||||
else:
|
|
||||||
fanin["cpuif_rd_data"] = self.signal("PRDATA", node, "i")
|
fanin["cpuif_rd_data"] = self.signal("PRDATA", node, "i")
|
||||||
|
|
||||||
return "\n".join(f"{kv[0]} = {kv[1]};" for kv in fanin.items())
|
return "\n".join(f"{kv[0]} = {kv[1]};" for kv in fanin.items())
|
||||||
|
|||||||
@@ -55,22 +55,31 @@ class APB4CpuifFlat(BaseCpuif):
|
|||||||
|
|
||||||
return "\n".join(f"assign {kv[0]} = {kv[1]};" for kv in fanout.items())
|
return "\n".join(f"assign {kv[0]} = {kv[1]};" for kv in fanout.items())
|
||||||
|
|
||||||
def fanin(self, node: AddressableNode | None = None) -> str:
|
def fanin_wr(self, node: AddressableNode | None = None, *, error: bool = False) -> str:
|
||||||
|
fanin: dict[str, str] = {}
|
||||||
|
if node is None:
|
||||||
|
fanin["cpuif_wr_ack"] = "'0"
|
||||||
|
fanin["cpuif_wr_err"] = "'0"
|
||||||
|
if error:
|
||||||
|
fanin["cpuif_wr_ack"] = "'1"
|
||||||
|
fanin["cpuif_wr_err"] = "cpuif_wr_sel.cpuif_err"
|
||||||
|
else:
|
||||||
|
fanin["cpuif_wr_ack"] = self.signal("PREADY", node, "i")
|
||||||
|
fanin["cpuif_wr_err"] = self.signal("PSLVERR", node, "i")
|
||||||
|
return "\n".join(f"{kv[0]} = {kv[1]};" for kv in fanin.items())
|
||||||
|
|
||||||
|
def fanin_rd(self, node: AddressableNode | None = None, *, error: bool = False) -> str:
|
||||||
fanin: dict[str, str] = {}
|
fanin: dict[str, str] = {}
|
||||||
if node is None:
|
if node is None:
|
||||||
fanin["cpuif_rd_ack"] = "'0"
|
fanin["cpuif_rd_ack"] = "'0"
|
||||||
fanin["cpuif_rd_err"] = "'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:
|
else:
|
||||||
fanin["cpuif_rd_ack"] = self.signal("PREADY", node, "i")
|
fanin["cpuif_rd_ack"] = self.signal("PREADY", node, "i")
|
||||||
fanin["cpuif_rd_err"] = self.signal("PSLVERR", node, "i")
|
fanin["cpuif_rd_err"] = self.signal("PSLVERR", node, "i")
|
||||||
|
|
||||||
return "\n".join(f"{kv[0]} = {kv[1]};" for kv in fanin.items())
|
|
||||||
|
|
||||||
def readback(self, node: AddressableNode | None = None) -> str:
|
|
||||||
fanin: dict[str, str] = {}
|
|
||||||
if node is None:
|
|
||||||
fanin["cpuif_rd_data"] = "'0"
|
|
||||||
else:
|
|
||||||
fanin["cpuif_rd_data"] = self.signal("PRDATA", node, "i")
|
fanin["cpuif_rd_data"] = self.signal("PRDATA", node, "i")
|
||||||
|
|
||||||
return "\n".join(f"{kv[0]} = {kv[1]};" for kv in fanin.items())
|
return "\n".join(f"{kv[0]} = {kv[1]};" for kv in fanin.items())
|
||||||
|
|||||||
@@ -20,8 +20,8 @@ assign cpuif_wr_data = {{cpuif.signal("PWDATA")}};
|
|||||||
assign cpuif_wr_byte_en = {{cpuif.signal("PSTRB")}};
|
assign cpuif_wr_byte_en = {{cpuif.signal("PSTRB")}};
|
||||||
|
|
||||||
assign {{cpuif.signal("PRDATA")}} = cpuif_rd_data;
|
assign {{cpuif.signal("PRDATA")}} = cpuif_rd_data;
|
||||||
assign {{cpuif.signal("PREADY")}} = cpuif_rd_ack;
|
assign {{cpuif.signal("PREADY")}} = cpuif_rd_ack | cpuif_wr_ack;
|
||||||
assign {{cpuif.signal("PSLVERR")}} = cpuif_rd_err | cpuif_rd_sel.cpuif_err | cpuif_wr_sel.cpuif_err;
|
assign {{cpuif.signal("PSLVERR")}} = cpuif_rd_err | cpuif_wr_err;
|
||||||
|
|
||||||
//--------------------------------------------------------------------------
|
//--------------------------------------------------------------------------
|
||||||
// Fanout CPU Bus interface signals
|
// Fanout CPU Bus interface signals
|
||||||
|
|||||||
@@ -63,11 +63,38 @@ class AXI4LiteCpuif(BaseCpuif):
|
|||||||
|
|
||||||
return "\n".join(f"assign {lhs} = {rhs};" for lhs, rhs in fanout.items())
|
return "\n".join(f"assign {lhs} = {rhs};" for lhs, rhs in fanout.items())
|
||||||
|
|
||||||
def fanin(self, node: AddressableNode | None = None) -> str:
|
def fanin_wr(self, node: AddressableNode | None = None, *, error: bool = False) -> str:
|
||||||
|
fanin: dict[str, str] = {}
|
||||||
|
if node is None:
|
||||||
|
fanin["cpuif_wr_ack"] = "'0"
|
||||||
|
fanin["cpuif_wr_err"] = "'0"
|
||||||
|
if error:
|
||||||
|
fanin["cpuif_wr_ack"] = "'1"
|
||||||
|
fanin["cpuif_wr_err"] = "cpuif_wr_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_wr_ack"] = f"{node.inst_name}_fanin_ready{array_idx}"
|
||||||
|
fanin["cpuif_wr_err"] = f"{node.inst_name}_fanin_err{array_idx}"
|
||||||
|
else:
|
||||||
|
# Read side: ack comes from RVALID; err if RRESP[1] is set (SLVERR/DECERR)
|
||||||
|
fanin["cpuif_wr_ack"] = self.signal("BVALID", node, "i")
|
||||||
|
fanin["cpuif_wr_err"] = f"{self.signal('BRESP', node, 'i')}[1]"
|
||||||
|
|
||||||
|
return "\n".join(f"{lhs} = {rhs};" for lhs, rhs in fanin.items())
|
||||||
|
|
||||||
|
def fanin_rd(self, node: AddressableNode | None = None, *, error: bool = False) -> str:
|
||||||
fanin: dict[str, str] = {}
|
fanin: dict[str, str] = {}
|
||||||
if node is None:
|
if node is None:
|
||||||
fanin["cpuif_rd_ack"] = "'0"
|
fanin["cpuif_rd_ack"] = "'0"
|
||||||
fanin["cpuif_rd_err"] = "'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:
|
else:
|
||||||
# Use intermediate signals for interface arrays to avoid
|
# Use intermediate signals for interface arrays to avoid
|
||||||
# non-constant indexing of interface arrays in procedural blocks
|
# non-constant indexing of interface arrays in procedural blocks
|
||||||
@@ -76,25 +103,10 @@ class AXI4LiteCpuif(BaseCpuif):
|
|||||||
array_idx = "".join(f"[i{i}]" for i in range(len(node.array_dimensions)))
|
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_ack"] = f"{node.inst_name}_fanin_ready{array_idx}"
|
||||||
fanin["cpuif_rd_err"] = f"{node.inst_name}_fanin_err{array_idx}"
|
fanin["cpuif_rd_err"] = f"{node.inst_name}_fanin_err{array_idx}"
|
||||||
else:
|
|
||||||
# Read side: ack comes from RVALID; err if RRESP[1] is set (SLVERR/DECERR)
|
|
||||||
fanin["cpuif_rd_ack"] = self.signal("RVALID", node, "i")
|
|
||||||
fanin["cpuif_rd_err"] = f"{self.signal('RRESP', node, 'i')}[1]"
|
|
||||||
|
|
||||||
return "\n".join(f"{lhs} = {rhs};" for lhs, rhs in fanin.items())
|
|
||||||
|
|
||||||
def readback(self, node: AddressableNode | None = None) -> str:
|
|
||||||
fanin: dict[str, str] = {}
|
|
||||||
if node is None:
|
|
||||||
fanin["cpuif_rd_data"] = "'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_data"] = f"{node.inst_name}_fanin_data{array_idx}"
|
fanin["cpuif_rd_data"] = f"{node.inst_name}_fanin_data{array_idx}"
|
||||||
else:
|
else:
|
||||||
|
fanin["cpuif_rd_ack"] = self.signal("RVALID", node, "i")
|
||||||
|
fanin["cpuif_rd_err"] = f"{self.signal('RRESP', node, 'i')}[1]"
|
||||||
fanin["cpuif_rd_data"] = self.signal("RDATA", node, "i")
|
fanin["cpuif_rd_data"] = self.signal("RDATA", node, "i")
|
||||||
|
|
||||||
return "\n".join(f"{lhs} = {rhs};" for lhs, rhs in fanin.items())
|
return "\n".join(f"{lhs} = {rhs};" for lhs, rhs in fanin.items())
|
||||||
|
|||||||
@@ -72,23 +72,33 @@ class AXI4LiteCpuifFlat(BaseCpuif):
|
|||||||
|
|
||||||
return "\n".join(f"assign {lhs} = {rhs};" for lhs, rhs in fanout.items())
|
return "\n".join(f"assign {lhs} = {rhs};" for lhs, rhs in fanout.items())
|
||||||
|
|
||||||
def fanin(self, node: AddressableNode | None = None) -> str:
|
def fanin_wr(self, node: AddressableNode | None = None, *, error: bool = False) -> str:
|
||||||
|
fanin: dict[str, str] = {}
|
||||||
|
if node is None:
|
||||||
|
fanin["cpuif_wr_ack"] = "'0"
|
||||||
|
fanin["cpuif_wr_err"] = "'0"
|
||||||
|
if error:
|
||||||
|
fanin["cpuif_wr_ack"] = "'1"
|
||||||
|
fanin["cpuif_wr_err"] = "cpuif_wr_sel.cpuif_err"
|
||||||
|
else:
|
||||||
|
# Read side: ack comes from RVALID; err if RRESP[1] is set (SLVERR/DECERR)
|
||||||
|
fanin["cpuif_wr_ack"] = self.signal("BVALID", node, "i")
|
||||||
|
fanin["cpuif_wr_err"] = f"{self.signal('BRESP', node, 'i')}[1]"
|
||||||
|
|
||||||
|
return "\n".join(f"{lhs} = {rhs};" for lhs, rhs in fanin.items())
|
||||||
|
|
||||||
|
def fanin_rd(self, node: AddressableNode | None = None, *, error: bool = False) -> str:
|
||||||
fanin: dict[str, str] = {}
|
fanin: dict[str, str] = {}
|
||||||
if node is None:
|
if node is None:
|
||||||
fanin["cpuif_rd_ack"] = "'0"
|
fanin["cpuif_rd_ack"] = "'0"
|
||||||
fanin["cpuif_rd_err"] = "'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:
|
else:
|
||||||
# Read side: ack comes from RVALID; err if RRESP[1] is set (SLVERR/DECERR)
|
|
||||||
fanin["cpuif_rd_ack"] = self.signal("RVALID", node, "i")
|
fanin["cpuif_rd_ack"] = self.signal("RVALID", node, "i")
|
||||||
fanin["cpuif_rd_err"] = f"{self.signal('RRESP', node, 'i')}[1]"
|
fanin["cpuif_rd_err"] = f"{self.signal('RRESP', node, 'i')}[1]"
|
||||||
|
|
||||||
return "\n".join(f"{lhs} = {rhs};" for lhs, rhs in fanin.items())
|
|
||||||
|
|
||||||
def readback(self, node: AddressableNode | None = None) -> str:
|
|
||||||
fanin: dict[str, str] = {}
|
|
||||||
if node is None:
|
|
||||||
fanin["cpuif_rd_data"] = "'0"
|
|
||||||
else:
|
|
||||||
fanin["cpuif_rd_data"] = self.signal("RDATA", node, "i")
|
fanin["cpuif_rd_data"] = self.signal("RDATA", node, "i")
|
||||||
|
|
||||||
return "\n".join(f"{lhs} = {rhs};" for lhs, rhs in fanin.items())
|
return "\n".join(f"{lhs} = {rhs};" for lhs, rhs in fanin.items())
|
||||||
|
|||||||
@@ -110,10 +110,10 @@ class BaseCpuif:
|
|||||||
def fanout(self, node: AddressableNode, array_stack: deque[int]) -> str:
|
def fanout(self, node: AddressableNode, array_stack: deque[int]) -> str:
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
def fanin(self, node: AddressableNode | None = None) -> str:
|
def fanin_wr(self, node: AddressableNode | None = None, *, error: bool = False) -> str:
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
def readback(self, node: AddressableNode | None = None) -> str:
|
def fanin_rd(self, node: AddressableNode | None = None, *, error: bool = False) -> str:
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
def fanin_intermediate_assignments(
|
def fanin_intermediate_assignments(
|
||||||
|
|||||||
@@ -20,8 +20,8 @@ class FaninGenerator(BusDecoderListener):
|
|||||||
|
|
||||||
self._stack: deque[Body] = deque()
|
self._stack: deque[Body] = deque()
|
||||||
cb = CombinationalBody()
|
cb = CombinationalBody()
|
||||||
cb += cpuif.fanin()
|
cb += cpuif.fanin_wr()
|
||||||
cb += cpuif.readback()
|
cb += cpuif.fanin_rd()
|
||||||
self._stack.append(cb)
|
self._stack.append(cb)
|
||||||
|
|
||||||
def enter_AddressableComponent(self, node: AddressableNode) -> WalkerAction | None:
|
def enter_AddressableComponent(self, node: AddressableNode) -> WalkerAction | None:
|
||||||
@@ -48,15 +48,13 @@ class FaninGenerator(BusDecoderListener):
|
|||||||
self._stack.append(fb)
|
self._stack.append(fb)
|
||||||
|
|
||||||
ifb = IfBody()
|
ifb = IfBody()
|
||||||
with ifb.cm(
|
with ifb.cm(f"cpuif_wr_sel.{get_indexed_path(self._cpuif.exp.ds.top_node, node)}") as b:
|
||||||
f"cpuif_rd_sel.{get_indexed_path(self._cpuif.exp.ds.top_node, node)} || cpuif_wr_sel.{get_indexed_path(self._cpuif.exp.ds.top_node, node)}"
|
b += self._cpuif.fanin_wr(node)
|
||||||
) as b:
|
|
||||||
b += self._cpuif.fanin(node)
|
|
||||||
self._stack[-1] += ifb
|
self._stack[-1] += ifb
|
||||||
|
|
||||||
ifb = IfBody()
|
ifb = IfBody()
|
||||||
with ifb.cm(f"cpuif_rd_sel.{get_indexed_path(self._cpuif.exp.ds.top_node, node)}") as b:
|
with ifb.cm(f"cpuif_rd_sel.{get_indexed_path(self._cpuif.exp.ds.top_node, node)}") as b:
|
||||||
b += self._cpuif.readback(node)
|
b += self._cpuif.fanin_rd(node)
|
||||||
self._stack[-1] += ifb
|
self._stack[-1] += ifb
|
||||||
|
|
||||||
return action
|
return action
|
||||||
@@ -72,4 +70,14 @@ class FaninGenerator(BusDecoderListener):
|
|||||||
super().exit_AddressableComponent(node)
|
super().exit_AddressableComponent(node)
|
||||||
|
|
||||||
def __str__(self) -> str:
|
def __str__(self) -> str:
|
||||||
|
wr_ifb = IfBody()
|
||||||
|
with wr_ifb.cm("cpuif_wr_sel.cpuif_err") as b:
|
||||||
|
self._cpuif.fanin_wr(error=True)
|
||||||
|
self._stack[-1] += wr_ifb
|
||||||
|
|
||||||
|
rd_ifb = IfBody()
|
||||||
|
with rd_ifb.cm("cpuif_rd_sel.cpuif_err") as b:
|
||||||
|
self._cpuif.fanin_rd(error=True)
|
||||||
|
self._stack[-1] += rd_ifb
|
||||||
|
|
||||||
return "\n".join(map(str, self._stack))
|
return "\n".join(map(str, self._stack))
|
||||||
|
|||||||
5
uv.lock
generated
5
uv.lock
generated
@@ -311,6 +311,9 @@ dependencies = [
|
|||||||
{ name = "scapy" },
|
{ name = "scapy" },
|
||||||
]
|
]
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/4e/f9/1474d5503af6f8c979a33e3489c0e6886b6ffb1af3d00419d2e0da1dd274/cocotb_bus-0.3.0.tar.gz", hash = "sha256:9762b29273ff062f52160e57274e3cb106d14e7e776515de1372c1d73546b005", size = 29991, upload-time = "2025-11-22T00:19:31.734Z" }
|
sdist = { url = "https://files.pythonhosted.org/packages/4e/f9/1474d5503af6f8c979a33e3489c0e6886b6ffb1af3d00419d2e0da1dd274/cocotb_bus-0.3.0.tar.gz", hash = "sha256:9762b29273ff062f52160e57274e3cb106d14e7e776515de1372c1d73546b005", size = 29991, upload-time = "2025-11-22T00:19:31.734Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/ea/43/8b3f96cf401c2a7f6e907ccc86d3b73433eeaf5525df90b630d8c112474b/cocotb_bus-0.3.0-py3-none-any.whl", hash = "sha256:b4f06cce2462a8f9487b42c46b0ff3afd253f0fa4f67a0c382ebe0ba614229eb", size = 36206, upload-time = "2026-01-15T04:51:43.009Z" },
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "colorama"
|
name = "colorama"
|
||||||
@@ -655,7 +658,7 @@ wheels = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "peakrdl-busdecoder"
|
name = "peakrdl-busdecoder"
|
||||||
version = "0.6.5"
|
version = "0.6.6"
|
||||||
source = { editable = "." }
|
source = { editable = "." }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "jinja2" },
|
{ name = "jinja2" },
|
||||||
|
|||||||
Reference in New Issue
Block a user