* Initial plan * Fix nonconstant index error by using unpacked structs and arrays Co-authored-by: arnavsacheti <36746504+arnavsacheti@users.noreply.github.com> * Add comprehensive tests for Questa compatibility with instance arrays Co-authored-by: arnavsacheti <36746504+arnavsacheti@users.noreply.github.com> * Add intermediate signals for interface array fanin to fix Questa compatibility Questa simulator rejects indexing interface arrays with non-constant variables in procedural blocks (always_comb). This fix creates intermediate unpacked array signals that are assigned from interface arrays using generate loops (with genvar), then references those intermediates in the fanin logic. Changes: - Added fanin_intermediate_gen.py to generate intermediate signals - Modified APB3/APB4/AXI4-Lite cpuif classes to use intermediates for interface arrays - Updated templates to include intermediate signal section - Intermediate signals use genvar indexing (legal) instead of variable indexing (illegal in Questa) Co-authored-by: arnavsacheti <36746504+arnavsacheti@users.noreply.github.com> * Fix type checking and formatting issues in fanin intermediate generator - Added proper null checks for node.array_dimensions to avoid type errors - Used getattr() to safely access is_interface and _interface attributes - Added early returns when interface is None to prevent errors - Fixed formatting issues in fanin_intermediate_gen.py - All type checks now pass (only pre-existing errors remain in other files) - All 67 tests still pass Co-authored-by: arnavsacheti <36746504+arnavsacheti@users.noreply.github.com> * Fix test collection when cocotb is not installed The cocotb test files (test_runner.py) have imports that fail at module level when cocotb is not installed, causing pytest collection to fail. This prevents running tests in environments without cocotb dependencies. Solution: Updated conftest.py to conditionally ignore cocotb tests when cocotb is not available, allowing tests to pass in both environments (with and without cocotb). - When cocotb is available: only ignore test_register_access.py files (existing behavior) - When cocotb is not available: ignore all files under cocotb/** directories This allows CI to run all 67 non-simulation tests successfully without requiring cocotb/verilator dependencies for basic testing. Co-authored-by: arnavsacheti <36746504+arnavsacheti@users.noreply.github.com> * add default for unpacked struct * cocotb is test dependancy * Refactor fanin intermediate signal logic to cpuif level Moved the interface-specific signal assignment logic from fanin_intermediate_gen.py to individual cpuif classes (APB3Cpuif, APB4Cpuif, AXI4LiteCpuif). This follows better architecture principles where each cpuif knows which signals it needs. Changes: - Added fanin_intermediate_assignments() method to BaseCpuif - Implemented fanin_intermediate_assignments() in APB3Cpuif, APB4Cpuif, and AXI4LiteCpuif - Updated FaninIntermediateGenerator to call the cpuif method instead of checking interface type - Removed interface type checking logic from fanin_intermediate_gen.py This makes the code more maintainable and follows the single responsibility principle - each cpuif class knows its own signal requirements. Co-authored-by: arnavsacheti <36746504+arnavsacheti@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: arnavsacheti <36746504+arnavsacheti@users.noreply.github.com>
85 lines
3.6 KiB
Python
85 lines
3.6 KiB
Python
"""AXI4-Lite-specific interface implementations."""
|
|
|
|
from systemrdl.node import AddressableNode
|
|
|
|
from ..interface import FlatInterface, SVInterface
|
|
|
|
|
|
class AXI4LiteSVInterface(SVInterface):
|
|
"""AXI4-Lite SystemVerilog interface."""
|
|
|
|
def get_interface_type(self) -> str:
|
|
return "axi4lite_intf"
|
|
|
|
def get_slave_name(self) -> str:
|
|
return "s_axil"
|
|
|
|
def get_master_prefix(self) -> str:
|
|
return "m_axil_"
|
|
|
|
|
|
class AXI4LiteFlatInterface(FlatInterface):
|
|
"""AXI4-Lite flat signal interface."""
|
|
|
|
def get_slave_prefix(self) -> str:
|
|
return "s_axil_"
|
|
|
|
def get_master_prefix(self) -> str:
|
|
return "m_axil_"
|
|
|
|
def _get_slave_port_declarations(self, slave_prefix: str) -> list[str]:
|
|
return [
|
|
# Write address channel
|
|
f"input logic {slave_prefix}AWVALID",
|
|
f"output logic {slave_prefix}AWREADY",
|
|
f"input logic [{self.cpuif.addr_width - 1}:0] {slave_prefix}AWADDR",
|
|
f"input logic [2:0] {slave_prefix}AWPROT",
|
|
# Write data channel
|
|
f"input logic {slave_prefix}WVALID",
|
|
f"output logic {slave_prefix}WREADY",
|
|
f"input logic [{self.cpuif.data_width - 1}:0] {slave_prefix}WDATA",
|
|
f"input logic [{self.cpuif.data_width // 8 - 1}:0] {slave_prefix}WSTRB",
|
|
# Write response channel
|
|
f"output logic {slave_prefix}BVALID",
|
|
f"input logic {slave_prefix}BREADY",
|
|
f"output logic [1:0] {slave_prefix}BRESP",
|
|
# Read address channel
|
|
f"input logic {slave_prefix}ARVALID",
|
|
f"output logic {slave_prefix}ARREADY",
|
|
f"input logic [{self.cpuif.addr_width - 1}:0] {slave_prefix}ARADDR",
|
|
f"input logic [2:0] {slave_prefix}ARPROT",
|
|
# Read data channel
|
|
f"output logic {slave_prefix}RVALID",
|
|
f"input logic {slave_prefix}RREADY",
|
|
f"output logic [{self.cpuif.data_width - 1}:0] {slave_prefix}RDATA",
|
|
f"output logic [1:0] {slave_prefix}RRESP",
|
|
]
|
|
|
|
def _get_master_port_declarations(self, child: AddressableNode, master_prefix: str) -> list[str]:
|
|
return [
|
|
# Write address channel
|
|
f"output logic {self.signal('AWVALID', child)}",
|
|
f"input logic {self.signal('AWREADY', child)}",
|
|
f"output logic [{self.cpuif.addr_width - 1}:0] {self.signal('AWADDR', child)}",
|
|
f"output logic [2:0] {self.signal('AWPROT', child)}",
|
|
# Write data channel
|
|
f"output logic {self.signal('WVALID', child)}",
|
|
f"input logic {self.signal('WREADY', child)}",
|
|
f"output logic [{self.cpuif.data_width - 1}:0] {self.signal('WDATA', child)}",
|
|
f"output logic [{self.cpuif.data_width // 8 - 1}:0] {self.signal('WSTRB', child)}",
|
|
# Write response channel
|
|
f"input logic {self.signal('BVALID', child)}",
|
|
f"output logic {self.signal('BREADY', child)}",
|
|
f"input logic [1:0] {self.signal('BRESP', child)}",
|
|
# Read address channel
|
|
f"output logic {self.signal('ARVALID', child)}",
|
|
f"input logic {self.signal('ARREADY', child)}",
|
|
f"output logic [{self.cpuif.addr_width - 1}:0] {self.signal('ARADDR', child)}",
|
|
f"output logic [2:0] {self.signal('ARPROT', child)}",
|
|
# Read data channel
|
|
f"input logic {self.signal('RVALID', child)}",
|
|
f"output logic {self.signal('RREADY', child)}",
|
|
f"input logic [{self.cpuif.data_width - 1}:0] {self.signal('RDATA', child)}",
|
|
f"input logic [1:0] {self.signal('RRESP', child)}",
|
|
]
|