observerw's picture
download
raw
5.86 kB
AUTO_BUILD_ARGS = []
#!/usr/bin/env python3
"""
Cocotb testbench for Apollo SPI controller module.
Tests basic reset, frequency change, and PTT functionality.
"""
import cocotb
from cocotb.clock import Clock
from cocotb.triggers import RisingEdge, FallingEdge, Timer, ClockCycles
from pathlib import Path
import sys
import os
# Add cocotb to path if needed
sys.path.append(str(Path(__file__).parent))
@cocotb.test()
async def test_reset_sequence(dut):
"""Test that reset properly initializes the module."""
clock = dut.clock
reset = dut.reset
# Start clock
cocotb.start_soon(Clock(clock, 33, unit="ns").start())
# Apply reset
reset.value = 1
await ClockCycles(clock, 2)
# Check reset state
assert dut.ApolloReset.value == 1, "ApolloReset should be high during reset"
assert dut.ApolloEnable.value == 1, "ApolloEnable should be high during reset"
assert dut.SPI_SCK.value == 1, "SPI_SCK should be high during reset"
# Release reset
reset.value = 0
await ClockCycles(clock, 200) # Wait for reset sequence
# Check post-reset state
assert dut.ApolloReset.value == 1, "ApolloReset should be high after reset"
assert dut.state.value == 3, f"State should be WAIT(3) after reset, got {dut.state.value}"
# Check SPI clock is idle
await ClockCycles(clock, 10)
assert dut.SPI_SCK.value == 0, "SPI_SCK should be idle (0) in WAIT state"
@cocotb.test()
async def test_frequency_change(dut):
"""Test that frequency changes trigger SPI transmission."""
clock = dut.clock
reset = dut.reset
# Start clock
cocotb.start_soon(Clock(clock, 33, unit="ns").start())
# Apply and release reset
reset.value = 1
await ClockCycles(clock, 2)
reset.value = 0
await ClockCycles(clock, 200)
# Initial state check
assert dut.state.value == 3, f"Should be in WAIT state, got {dut.state.value}"
# Change frequency
dut.frequency.value = 0x12345678
await ClockCycles(clock, 5)
# Check that state transition occurs
assert dut.state.value == 6, f"Should transition to SET_FREQUENCY(6), got {dut.state.value}"
assert dut.ApolloEnable.value == 0, "ApolloEnable should be low during transmission"
# Wait for message transmission
await ClockCycles(clock, 50)
# Check that SPI clock is toggling
sck_initial = dut.SPI_SCK.value
await ClockCycles(clock, 2)
sck_next = dut.SPI_SCK.value
assert sck_initial != sck_next, "SPI_SCK should be toggling during transmission"
@cocotb.test()
async def test_ptt_control(dut):
"""Test PTT enable/disable functionality."""
clock = dut.clock
reset = dut.reset
# Start clock
cocotb.start_soon(Clock(clock, 33, unit="ns").start())
# Apply and release reset
reset.value = 1
await ClockCycles(clock, 2)
reset.value = 0
await ClockCycles(clock, 200)
# Enable PTT
dut.PTT.value = 1
await ClockCycles(clock, 10)
# Check state transition
assert dut.state.value == 12, f"Should transition to ENABLE_PTT(12), got {dut.state.value}"
assert dut.ApolloEnable.value == 0, "ApolloEnable should be low during PTT enable"
# Wait for transmission to complete
await ClockCycles(clock, 100)
# Disable PTT
dut.PTT.value = 0
await ClockCycles(clock, 10)
# Check state transition for disable
assert dut.state.value == 4, f"Should transition to SIMPLE_MESSAGE(4) for PTT disable, got {dut.state.value}"
@cocotb.test()
async def test_filter_select_alex_mode(dut):
"""Test that FilterSelect high puts module in Alex mode."""
clock = dut.clock
reset = dut.reset
# Start clock
cocotb.start_soon(Clock(clock, 33, unit="ns").start())
# Apply and release reset
reset.value = 1
await ClockCycles(clock, 2)
reset.value = 0
await ClockCycles(clock, 200)
# Set FilterSelect high (Alex mode)
dut.FilterSelect.value = 1
await ClockCycles(clock, 10)
# Check state transition to Alex mode
assert dut.state.value == 31, f"Should be in Alex(31) mode, got {dut.state.value}"
# Try to change frequency - should not trigger transmission in Alex mode
original_state = dut.state.value
dut.frequency.value = 0x87654321
await ClockCycles(clock, 10)
assert dut.state.value == original_state, "State should not change in Alex mode"
@cocotb.test()
async def test_status_available_signal(dut):
"""Test that statusAvailable signal behaves correctly."""
clock = dut.clock
reset = dut.reset
# Start clock
cocotb.start_soon(Clock(clock, 33, unit="ns").start())
# Apply and release reset
reset.value = 1
await ClockCycles(clock, 2)
reset.value = 0
await ClockCycles(clock, 200)
# Initially statusAvailable should be 0
assert dut.statusAvailable.value == 0, "statusAvailable should be 0 initially"
# Check that we can write to status register (simulate status reception)
# Note: In real operation, this would be set by the READ_STATUS state
# We'll just verify the signal exists and can be monitored
if hasattr(dut, 'status'):
# status is 88 bits wide
assert dut.status.value == 0, "status should be 0 initially"
if __name__ == "__main__":
from pathlib import Path
from cocotb_tools.runner import get_runner
project_root = Path(__file__).resolve().parents[1]
sources = [
project_root / "reference" / "top.v"
]
runner = get_runner("icarus")
runner.build(
sources=[str(path) for path in sources],
hdl_toplevel='Apollo',
build_args=AUTO_BUILD_ARGS,
always=True,
)
runner.test(
hdl_toplevel='Apollo',
test_module="tb",
waves=False,
)

Xet Storage Details

Size:
5.86 kB
·
Xet hash:
f44ed572655182333788c849eac1690977c439f93f3417e45424dd89817df897

Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.