* Initial plan * Add cocotb test infrastructure and testbenches for APB3, APB4, and AXI4-Lite Co-authored-by: arnavsacheti <36746504+arnavsacheti@users.noreply.github.com> * Add integration tests, examples, and documentation for cocotb testbenches Co-authored-by: arnavsacheti <36746504+arnavsacheti@users.noreply.github.com> * Address code review feedback: use relative imports and update installation docs Co-authored-by: arnavsacheti <36746504+arnavsacheti@users.noreply.github.com> * Add implementation summary document Co-authored-by: arnavsacheti <36746504+arnavsacheti@users.noreply.github.com> * Merge cocotb dependencies into test group Co-authored-by: arnavsacheti <36746504+arnavsacheti@users.noreply.github.com> * Add optional cocotb simulation workflow with Icarus Verilog 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>
124 lines
3.3 KiB
Python
124 lines
3.3 KiB
Python
"""APB4 Master Bus Functional Model for cocotb."""
|
|
|
|
import cocotb
|
|
from cocotb.triggers import RisingEdge, Timer
|
|
|
|
|
|
class APB4Master:
|
|
"""APB4 Master Bus Functional Model."""
|
|
|
|
def __init__(self, dut, name, clock):
|
|
"""
|
|
Initialize APB4 Master.
|
|
|
|
Args:
|
|
dut: The device under test
|
|
name: Signal name prefix (e.g., 's_apb')
|
|
clock: Clock signal to use for synchronization
|
|
"""
|
|
self.dut = dut
|
|
self.clock = clock
|
|
self.name = name
|
|
|
|
# Get signals
|
|
self.psel = getattr(dut, f"{name}_PSEL")
|
|
self.penable = getattr(dut, f"{name}_PENABLE")
|
|
self.pwrite = getattr(dut, f"{name}_PWRITE")
|
|
self.paddr = getattr(dut, f"{name}_PADDR")
|
|
self.pwdata = getattr(dut, f"{name}_PWDATA")
|
|
self.pstrb = getattr(dut, f"{name}_PSTRB")
|
|
self.pprot = getattr(dut, f"{name}_PPROT")
|
|
self.prdata = getattr(dut, f"{name}_PRDATA")
|
|
self.pready = getattr(dut, f"{name}_PREADY")
|
|
self.pslverr = getattr(dut, f"{name}_PSLVERR")
|
|
|
|
def reset(self):
|
|
"""Reset the bus to idle state."""
|
|
self.psel.value = 0
|
|
self.penable.value = 0
|
|
self.pwrite.value = 0
|
|
self.paddr.value = 0
|
|
self.pwdata.value = 0
|
|
self.pstrb.value = 0
|
|
self.pprot.value = 0
|
|
|
|
async def write(self, addr, data, strb=None):
|
|
"""
|
|
Perform APB4 write transaction.
|
|
|
|
Args:
|
|
addr: Address to write to
|
|
data: Data to write
|
|
strb: Byte strobe mask (default: all bytes enabled)
|
|
|
|
Returns:
|
|
True if write succeeded, False if error
|
|
"""
|
|
# Calculate strobe if not provided
|
|
if strb is None:
|
|
data_width_bytes = len(self.pwdata) // 8
|
|
strb = (1 << data_width_bytes) - 1
|
|
|
|
# Setup phase
|
|
await RisingEdge(self.clock)
|
|
self.psel.value = 1
|
|
self.penable.value = 0
|
|
self.pwrite.value = 1
|
|
self.paddr.value = addr
|
|
self.pwdata.value = data
|
|
self.pstrb.value = strb
|
|
self.pprot.value = 0
|
|
|
|
# Access phase
|
|
await RisingEdge(self.clock)
|
|
self.penable.value = 1
|
|
|
|
# Wait for ready
|
|
while True:
|
|
await RisingEdge(self.clock)
|
|
if self.pready.value == 1:
|
|
error = self.pslverr.value == 1
|
|
break
|
|
|
|
# Return to idle
|
|
self.psel.value = 0
|
|
self.penable.value = 0
|
|
|
|
return not error
|
|
|
|
async def read(self, addr):
|
|
"""
|
|
Perform APB4 read transaction.
|
|
|
|
Args:
|
|
addr: Address to read from
|
|
|
|
Returns:
|
|
Tuple of (data, error) where error is True if read failed
|
|
"""
|
|
# Setup phase
|
|
await RisingEdge(self.clock)
|
|
self.psel.value = 1
|
|
self.penable.value = 0
|
|
self.pwrite.value = 0
|
|
self.paddr.value = addr
|
|
self.pprot.value = 0
|
|
|
|
# Access phase
|
|
await RisingEdge(self.clock)
|
|
self.penable.value = 1
|
|
|
|
# Wait for ready
|
|
while True:
|
|
await RisingEdge(self.clock)
|
|
if self.pready.value == 1:
|
|
data = self.prdata.value.integer
|
|
error = self.pslverr.value == 1
|
|
break
|
|
|
|
# Return to idle
|
|
self.psel.value = 0
|
|
self.penable.value = 0
|
|
|
|
return data, error
|