define ABC for cores to inherit from

This commit is contained in:
Fischer Moseley 2024-03-03 18:53:08 -08:00
parent b729deb144
commit be79ba28b5
9 changed files with 77 additions and 59 deletions

View File

@ -3,7 +3,7 @@ from manta.utils import *
from math import ceil
class IOCore(Elaboratable):
class IOCore(MantaCore):
"""
A module for setting and getting the values of registers of arbitrary size
on a FPGA.
@ -34,6 +34,14 @@ class IOCore(Elaboratable):
self._make_memory_map()
@property
def top_level_ports(self):
return self._inputs + self._outputs
@property
def max_addr(self):
return self._max_addr
@classmethod
def from_config(cls, config, base_addr, interface):
inputs = config.get("inputs", {})
@ -173,21 +181,6 @@ class IOCore(Elaboratable):
return m
def get_top_level_ports(self):
"""
Return the Amaranth signals that should be included as ports in the
top-level Manta module.
"""
return self._inputs + self._outputs
def get_max_addr(self):
"""
Return the maximum addresses in memory used by the core. The address
space used by the core extends from `base_addr` to the number returned
by this function (including the endpoints).
"""
return self._max_addr
def set_probe(self, name, value):
"""
Set the value of an output probe on the FPGA. The value may be either

View File

@ -6,7 +6,7 @@ from manta.logic_analyzer.fsm import LogicAnalyzerFSM, States, TriggerModes
from manta.logic_analyzer.playback import LogicAnalyzerPlayback
class LogicAnalyzerCore(Elaboratable):
class LogicAnalyzerCore(MantaCore):
"""
A module for generating a logic analyzer on the FPGA, with configurable
triggers, trigger position, and trigger modes.
@ -44,6 +44,14 @@ class LogicAnalyzerCore(Elaboratable):
interface=interface,
)
@property
def max_addr(self):
return self._sample_mem.max_addr
@property
def top_level_ports(self):
return self._probes
def _check_config(self):
# Check for unrecognized options
valid_options = [
@ -176,21 +184,6 @@ class LogicAnalyzerCore(Elaboratable):
return m
def get_top_level_ports(self):
"""
Return the Amaranth signals that should be included as ports in the
top-level Manta module.
"""
return self._probes
def get_max_addr(self):
"""
Return the maximum addresses in memory used by the core. The address
space used by the core extends from `base_addr` to the number returned
by this function (including the endpoints).
"""
return self._sample_mem.get_max_addr()
def capture(self, verbose=False):
"""
Performs a capture, recording the state of all input probes to the

View File

@ -66,7 +66,7 @@ class LogicAnalyzerFSM(Elaboratable):
space used by the core extends from `base_addr` to the number returned
by this function (including the endpoints).
"""
return self.registers.get_max_addr()
return self.registers.max_addr
def elaborate(self, platform):
m = Module()

View File

@ -34,7 +34,7 @@ class LogicAnalyzerTriggerBlock(Elaboratable):
space used by the core extends from `base_addr` to the number returned
by this function (including the endpoints).
"""
return self.registers.get_max_addr()
return self.registers.max_addr
def clear_triggers(self):
# Reset all triggers to disabled with no argument

View File

@ -97,13 +97,13 @@ class Manta(Elaboratable):
core = MemoryCore.from_config(attrs, base_addr, self.interface)
# Make sure we're not out of address space
if core.get_max_addr() > (2**16) - 1:
if core.max_addr > (2**16) - 1:
raise ValueError(
f"Ran out of address space to allocate to core {name}."
)
# Make the next core's base address start one address after the previous one's
base_addr = core.get_max_addr() + 1
base_addr = core.max_addr + 1
self._cores[name] = core
def _add_friendly_core_names(self):

View File

@ -3,7 +3,7 @@ from manta.utils import *
from math import ceil
class MemoryCore(Elaboratable):
class MemoryCore(MantaCore):
"""
A module for generating a memory on the FPGA, with a port tied to Manta's
internal bus, and a port provided to user logic.
@ -60,6 +60,14 @@ class MemoryCore(Elaboratable):
self.user_write_enable,
]
@property
def top_level_ports(self):
return self._top_level_ports
@property
def max_addr(self):
return self._max_addr
@classmethod
def from_config(cls, config, base_addr, interface):
# Check for unrecognized options
@ -251,21 +259,6 @@ class MemoryCore(Elaboratable):
self._tie_mems_to_user_logic(m)
return m
def get_top_level_ports(self):
"""
Return the Amaranth signals that should be included as ports in the
top-level Manta module.
"""
return self._top_level_ports
def get_max_addr(self):
"""
Return the maximum addresses in memory used by the core. The address
space used by the core extends from `base_addr` to the number returned
by this function (including the endpoints).
"""
return self._max_addr
def _convert_user_to_bus_addr(self, addrs):
"""
Convert user address space to bus address space. For instance, for a

View File

@ -1,9 +1,40 @@
from amaranth import *
from amaranth.sim import Simulator
from amaranth.lib import data, enum
from math import ceil
from amaranth.lib import data
from abc import ABC, abstractmethod
import os
class MantaCore(ABC, Elaboratable):
@property
@abstractmethod
def max_addr(self):
"""
Return the maximum addresses in memory used by the core. The address
space used by the core extends from `base_addr` to the number returned
by this function (including the endpoints).
"""
pass
@property
@abstractmethod
def top_level_ports(self):
"""
Return the Amaranth signals that should be included as ports in the
top-level Manta module.
"""
pass
@abstractmethod
def elaborate(self, platform):
pass
# @abstractclassmethod
# def from_config(cls):
# pass
class InternalBus(data.StructLayout):
"""
Describes the layout of Manta's internal bus, such that signals of

View File

@ -96,5 +96,5 @@ def test_single_shot_capture():
yield from write_register(la, 0, 1)
yield from write_register(la, 0, 0)
for addr in range(la.get_max_addr()):
for addr in range(la.max_addr):
yield from print_data_at_addr(addr)

View File

@ -2,15 +2,18 @@ from manta.memory_core import MemoryCore
from manta.utils import *
from random import randint, sample, choice
class MemoryCoreTests():
class MemoryCoreTests:
def __init__(self, mem_core):
self.mem_core = mem_core
self.base_addr = mem_core._base_addr
self.max_addr = mem_core.get_max_addr()
self.max_addr = mem_core.max_addr
self.width = self.mem_core._width
self.depth = self.mem_core._depth
self.bus_addrs = list(range(self.base_addr, self.max_addr)) # include the endpoint!
self.bus_addrs = list(
range(self.base_addr, self.max_addr)
) # include the endpoint!
self.user_addrs = list(range(self.mem_core._depth))
self.model = {}
@ -86,7 +89,10 @@ class MemoryCoreTests():
data = yield (self.mem_core.user_data_out)
if data != expected_data:
raise ValueError(f"Read from {addr} yielded {data} instead of {expected_data}")
raise ValueError(
f"Read from {addr} yielded {data} instead of {expected_data}"
)
mem_core = MemoryCore(
mode="bidirectional",
@ -98,6 +104,7 @@ mem_core = MemoryCore(
tests = MemoryCoreTests(mem_core)
@simulate(mem_core)
def test_bidirectional_testbench():
yield from tests.check_each_address_on_bus_side_contains_zero()
@ -106,6 +113,7 @@ def test_bidirectional_testbench():
yield from tests.check_multiple_writes_then_multiple_reads()
yield from tests.check_random_reads_random_writes_random_orders()
# def test_sweep_core_widths():
# for i in range(1, 64):
# verify_mem_core(i, 128, 0)