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:
Copilot
2026-02-02 23:34:09 -08:00
committed by GitHub
parent 2abf7cf7f2
commit 1e09da6dbf
12 changed files with 168 additions and 93 deletions

View File

@@ -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",

View File

@@ -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())

View File

@@ -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())

View File

@@ -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

View File

@@ -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())

View File

@@ -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())

View File

@@ -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

View File

@@ -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())

View File

@@ -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())

View File

@@ -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(

View File

@@ -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
View File

@@ -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" },