Skip to content

Commit

Permalink
Merge pull request #245 from miek/test_reorg
Browse files Browse the repository at this point in the history
Reorganise tests/CI
  • Loading branch information
miek authored Apr 29, 2024
2 parents b6097ae + c575b0b commit 3cce743
Show file tree
Hide file tree
Showing 61 changed files with 3,755 additions and 3,821 deletions.
19 changes: 12 additions & 7 deletions .github/workflows/simulate.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,17 +15,22 @@ jobs:
strategy:
max-parallel: 5
matrix:
python-version: [3.9]
python-version:
- '3.8'
- '3.9'
- '3.10'
- '3.11'
- '3.12'

name: test (${{ matrix.python-version }})
steps:
- uses: actions/checkout@v1
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v2
- name: Set up PDM
uses: pdm-project/setup-pdm@v4
with:
python-version: ${{ matrix.python-version }}
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install tox tox-gh-actions
- name: Test with tox
run: tox
pdm install
- name: Run tests
run: pdm run test
34 changes: 0 additions & 34 deletions luna/gateware/architecture/car.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
from amaranth import Signal, Module, ClockDomain, ClockSignal, Elaboratable, Instance, ResetSignal

from ..utils.cdc import stretch_strobe_signal
from ..test import LunaGatewareTestCase, usb_domain_test_case, sync_test_case


class PHYResetController(Elaboratable):
Expand Down Expand Up @@ -95,39 +94,6 @@ def elaborate(self, platform):



class PHYResetControllerTest(LunaGatewareTestCase):
FRAGMENT_UNDER_TEST = PHYResetController

def initialize_signals(self):
yield self.dut.trigger.eq(0)

@sync_test_case
def test_power_on_reset(self):

#
# After power-on, the PHY should remain in reset for a while.
#
yield
self.assertEqual((yield self.dut.phy_reset), 1)

yield from self.advance_cycles(30)
self.assertEqual((yield self.dut.phy_reset), 1)

yield from self.advance_cycles(60)
self.assertEqual((yield self.dut.phy_reset), 1)

#
# Then, after the relevant reset time, it should resume being unasserted.
#
yield from self.advance_cycles(31)
self.assertEqual((yield self.dut.phy_reset), 0)
self.assertEqual((yield self.dut.phy_stop), 1)

yield from self.advance_cycles(120)
self.assertEqual((yield self.dut.phy_stop), 0)



class LunaDomainGenerator(Elaboratable, metaclass=ABCMeta):
""" Helper that generates the clock domains used in a LUNA board.
Expand Down
1 change: 0 additions & 1 deletion luna/gateware/debug/console.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@


from amaranth import Signal, Module, Cat, Elaboratable, Array
from ..test.utils import LunaGatewareTestCase, sync_test_case


class DebugConsole(Elaboratable):
Expand Down
208 changes: 1 addition & 207 deletions luna/gateware/debug/ila.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
import os
import sys
import math
import unittest
import tempfile
import subprocess

Expand All @@ -24,8 +23,7 @@

from ..stream import StreamInterface
from ..interface.uart import UARTMultibyteTransmitter
from ..interface.spi import SPIDeviceInterface, SPIBus, SPIGatewareTestCase
from ..test.utils import LunaGatewareTestCase, sync_test_case
from ..interface.spi import SPIDeviceInterface, SPIBus


class IntegratedLogicAnalyzer(Elaboratable):
Expand Down Expand Up @@ -172,105 +170,6 @@ def elaborate(self, platform):
return m


class IntegratedLogicAnalyzerTest(LunaGatewareTestCase):

def instantiate_dut(self):
self.input_a = Signal()
self.input_b = Signal(30)
self.input_c = Signal()

return IntegratedLogicAnalyzer(
signals=[self.input_a, self.input_b, self.input_c],
sample_depth = 32
)


def initialize_signals(self):
yield self.input_a .eq(0)
yield self.input_b .eq(0)
yield self.input_c .eq(0)


def provide_all_signals(self, value):
all_signals = Cat(self.input_a, self.input_b, self.input_c)
yield all_signals.eq(value)


def assert_sample_value(self, address, value):
""" Helper that asserts a ILA sample has a given value. """

yield self.dut.captured_sample_number.eq(address)
yield
# Delay a clock to allow the block ram to latch the new value
yield
try:
self.assertEqual((yield self.dut.captured_sample), value)
return
except AssertionError:
pass

# Generate an appropriate exception.
actual_value = (yield self.dut.captured_sample)
message = "assertion failed: at address 0x{:08x}: {:08x} != {:08x} (expected)".format(address, actual_value, value)
raise AssertionError(message)


@sync_test_case
def test_sampling(self):

# Quick helper that generates simple, repetitive samples.
def sample_value(i):
return i | (i << 8) | (i << 16) | (0xFF << 24)

yield from self.provide_all_signals(0xDEADBEEF)
yield

# Before we trigger, we shouldn't be capturing any samples,
# and we shouldn't be complete.
self.assertEqual((yield self.dut.sampling), 0)
self.assertEqual((yield self.dut.complete), 0)

# Advance a bunch of cycles, and ensure we don't start sampling.
yield from self.advance_cycles(10)
self.assertEqual((yield self.dut.sampling), 0)

# Set a new piece of data for a couple of cycles.
yield from self.provide_all_signals(0x01234567)
yield
yield from self.provide_all_signals(0x89ABCDEF)
yield

# Finally, trigger the capture.
yield from self.provide_all_signals(sample_value(0))
yield from self.pulse(self.dut.trigger, step_after=False)

yield from self.provide_all_signals(sample_value(1))
yield

# After we pulse our trigger strobe, we should be sampling.
self.assertEqual((yield self.dut.sampling), 1)

# Populate the memory with a variety of interesting signals;
# and continue afterwards for a couple of cycles to make sure
# these don't make it into our sample buffer.
for i in range(2, 34):
yield from self.provide_all_signals(sample_value(i))
yield

# We now should be done with our sampling.
self.assertEqual((yield self.dut.sampling), 0)
self.assertEqual((yield self.dut.complete), 1)

# Validate the memory values that were captured.
for i in range(32):
yield from self.assert_sample_value(i, sample_value(i))

# All of those reads shouldn't change our completeness.
self.assertEqual((yield self.dut.sampling), 0)
self.assertEqual((yield self.dut.complete), 1)



class SyncSerialILA(Elaboratable):
""" Super-simple ILA that reads samples out over a simple unidirectional SPI.
Create a receiver for this object by calling apollo_fpga.ila_receiver_for(<this>).
Expand Down Expand Up @@ -430,60 +329,6 @@ def elaborate(self, platform):
return m


class SyncSerialReadoutILATest(SPIGatewareTestCase):

def instantiate_dut(self):
self.input_signal = Signal(12)
return SyncSerialILA(
signals=[self.input_signal],
sample_depth=16,
clock_polarity=1,
clock_phase=0
)

def initialize_signals(self):
yield self.input_signal.eq(0xF00)

@sync_test_case
def test_spi_readout(self):
input_signal = self.input_signal

# Trigger the test while offering our first sample.
yield
yield from self.pulse(self.dut.trigger, step_after=False)

# Provide the remainder of our samples.
for i in range(1, 16):
yield input_signal.eq(0xF00 | i)
yield

# Wait a few cycles to account for delays in
# the sampling pipeline.
yield from self.advance_cycles(5)

# We've now captured a full set of samples.
# We'll test reading them out.
self.assertEqual((yield self.dut.complete), 1)

# Start the transaction, and exchange 16 bytes of data.
yield self.dut.spi.cs.eq(1)
yield

# Read our our result over SPI...
data = yield from self.spi_exchange_data(b"\0" * 32)

# ... and ensure it matches what was sampled.
i = 0
while data:
datum = data[0:4]
del data[0:4]

expected = b"\x00\x00\x0f" + bytes([i])
self.assertEqual(datum, expected)
i += 1




class StreamILA(Elaboratable):
""" Super-simple ILA that outputs its samples over a Stream.
Expand Down Expand Up @@ -674,53 +519,6 @@ def elaborate(self, platform):

return m

class StreamILATest(LunaGatewareTestCase):

def instantiate_dut(self):
self.input_signal = Signal(12)
return StreamILA(
signals=[self.input_signal],
sample_depth=16
)

def initialize_signals(self):
yield self.input_signal.eq(0xF00)

@sync_test_case
def test_stream_readout(self):
input_signal = self.input_signal
stream = self.dut.stream

# Trigger the ILA with the first sample
yield
yield from self.pulse(self.dut.trigger, step_after=False)

# Fill up the ILA with the remaining samples
for i in range(1, 16):
yield input_signal.eq(0xF00 | i)
yield

# Wait a few cycles to allow the ILA to fully finish processing
yield from self.advance_cycles(6)
# Stream should now be presenting valid data
self.assertEqual((yield stream.valid), 1)

# Now we want to stream out the samples from the ILA
yield stream.ready.eq(1)
yield
self.assertEqual((yield stream.first), 1)

# Read out data from the stream until it signals completion
data = []
while not (yield stream.last):
if (yield stream.valid):
data.append((yield stream.payload))
yield

# Match read data to what should have been sampled
for i, datum in enumerate(data):
self.assertEqual(datum, 0xF00 | i)


class AsyncSerialILA(Elaboratable):
""" Super-simple ILA that reads samples out over a UART connection.
Expand Down Expand Up @@ -1031,7 +829,3 @@ def _read_samples(self):
# Fetch all of our samples from the given device.
all_samples = self._port.read(total_to_read)
return list(self._split_samples(all_samples))


if __name__ == "__main__":
unittest.main()
Loading

0 comments on commit 3cce743

Please sign in to comment.