manta: fix code generation from config file, update tests
This commit is contained in:
parent
3ba93efd2f
commit
8f45546b5a
|
|
@ -1,16 +1,16 @@
|
||||||
from manta import Manta
|
from manta import *
|
||||||
from time import sleep
|
from time import sleep
|
||||||
|
|
||||||
manta = Manta("manta.yaml")
|
manta = Manta.from_config("manta.yaml")
|
||||||
|
|
||||||
i = 0
|
i = 0
|
||||||
while True:
|
while True:
|
||||||
# Turn each LED off
|
# Turn each LED off
|
||||||
for j in range(5):
|
for j in range(5):
|
||||||
manta.my_io_core.set_probe(f"LED{j}", 0)
|
manta.cores.my_io_core.set_probe(f"LED{j}", 0)
|
||||||
|
|
||||||
# Turn one LED back on
|
# Turn one LED back on
|
||||||
manta.my_io_core.set_probe(f"LED{i}", 1)
|
manta.cores.my_io_core.set_probe(f"LED{i}", 1)
|
||||||
|
|
||||||
i = (i + 1) % 5
|
i = (i + 1) % 5
|
||||||
sleep(0.1)
|
sleep(0.1)
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
from manta import Manta
|
from manta import *
|
||||||
|
|
||||||
m = Manta("manta.yaml")
|
manta = Manta.from_config("manta.yaml")
|
||||||
|
|
||||||
print(m.my_io_core.get_probe("sw"))
|
print(manta.cores.my_io_core.get_probe("sw"))
|
||||||
m.my_io_core.set_probe("led", 4)
|
manta.cores.my_io_core.set_probe("led", 4)
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
from manta import Manta
|
from manta import *
|
||||||
|
|
||||||
m = Manta("manta.yaml")
|
manta = Manta.from_config("manta.yaml")
|
||||||
|
|
||||||
# Memory addresses can be written to in Python, and then be read out by
|
# Memory addresses can be written to in Python, and then be read out by
|
||||||
# flipping the switches on the FPGA, and watching the LEDs update!
|
# flipping the switches on the FPGA, and watching the LEDs update!
|
||||||
|
|
||||||
m.my_memory.write(0, 1)
|
manta.cores.my_memory.write(0, 1)
|
||||||
|
|
|
||||||
|
|
@ -1,25 +1,25 @@
|
||||||
from manta import Manta
|
from manta import *
|
||||||
from time import sleep
|
from time import sleep
|
||||||
from random import randint
|
from random import randint
|
||||||
|
|
||||||
m = Manta("manta.yaml")
|
manta = Manta.from_config("manta.yaml")
|
||||||
|
|
||||||
i = 0
|
i = 0
|
||||||
while True:
|
while True:
|
||||||
i = (i + 1) % 16
|
i = (i + 1) % 16
|
||||||
m.my_io_core.set_probe("led", 2**i)
|
manta.cores.my_io_core.set_probe("led", 2**i)
|
||||||
|
|
||||||
m.my_io_core.set_probe("led16_r", randint(0, 1))
|
manta.cores.my_io_core.set_probe("led16_r", randint(0, 1))
|
||||||
m.my_io_core.set_probe("led16_g", randint(0, 1))
|
manta.cores.my_io_core.set_probe("led16_g", randint(0, 1))
|
||||||
m.my_io_core.set_probe("led16_b", randint(0, 1))
|
manta.cores.my_io_core.set_probe("led16_b", randint(0, 1))
|
||||||
|
|
||||||
print(f'Switches: {m.my_io_core.get_probe("sw")}')
|
print(f'Switches: {manta.cores.my_io_core.get_probe("sw")}')
|
||||||
print(f"Buttons:")
|
print(f"Buttons:")
|
||||||
print(f'btnu: {m.my_io_core.get_probe("btnu")}')
|
print(f'btnu: {manta.cores.my_io_core.get_probe("btnu")}')
|
||||||
print(f'btnd: {m.my_io_core.get_probe("btnd")}')
|
print(f'btnd: {manta.cores.my_io_core.get_probe("btnd")}')
|
||||||
print(f'btnr: {m.my_io_core.get_probe("btnr")}')
|
print(f'btnr: {manta.cores.my_io_core.get_probe("btnr")}')
|
||||||
print(f'btnl: {m.my_io_core.get_probe("btnl")}')
|
print(f'btnl: {manta.cores.my_io_core.get_probe("btnl")}')
|
||||||
print(f'btnc: {m.my_io_core.get_probe("btnc")}')
|
print(f'btnc: {manta.cores.my_io_core.get_probe("btnc")}')
|
||||||
print("")
|
print("")
|
||||||
|
|
||||||
sleep(0.1)
|
sleep(0.1)
|
||||||
|
|
|
||||||
|
|
@ -69,13 +69,13 @@ def wrong_args():
|
||||||
|
|
||||||
|
|
||||||
def gen(config_path, output_path):
|
def gen(config_path, output_path):
|
||||||
m = Manta(config_path)
|
manta = Manta.from_config(config_path)
|
||||||
m.generate_verilog(output_path)
|
manta.generate_verilog(output_path)
|
||||||
|
|
||||||
|
|
||||||
def inst(config_path):
|
def inst(config_path):
|
||||||
m = Manta(config_path)
|
manta = Manta.from_config(config_path)
|
||||||
ports = m.get_top_level_ports()
|
ports = manta.get_top_level_ports()
|
||||||
hdl = ",\n ".join([f".{p.name}({p.name})" for p in ports])
|
hdl = ",\n ".join([f".{p.name}({p.name})" for p in ports])
|
||||||
|
|
||||||
foo = """
|
foo = """
|
||||||
|
|
@ -88,8 +88,8 @@ manta manta_inst(
|
||||||
|
|
||||||
|
|
||||||
def capture(config_path, logic_analyzer_name, export_paths):
|
def capture(config_path, logic_analyzer_name, export_paths):
|
||||||
m = Manta(config_path)
|
manta = Manta.from_config(config_path)
|
||||||
la = getattr(m, logic_analyzer_name)
|
la = getattr(manta.cores, logic_analyzer_name)
|
||||||
cap = la.capture()
|
cap = la.capture()
|
||||||
|
|
||||||
for path in export_paths:
|
for path in export_paths:
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,7 @@ class EthernetInterface(Elaboratable):
|
||||||
self._host_ip_addr = host_ip_addr
|
self._host_ip_addr = host_ip_addr
|
||||||
self._udp_port = udp_port
|
self._udp_port = udp_port
|
||||||
self._phy = phy
|
self._phy = phy
|
||||||
self._clk_freq = clk_freq
|
self._clk_freq = float(clk_freq)
|
||||||
self._additional_config = kwargs
|
self._additional_config = kwargs
|
||||||
self._check_config()
|
self._check_config()
|
||||||
|
|
||||||
|
|
@ -81,6 +81,10 @@ class EthernetInterface(Elaboratable):
|
||||||
if not 0 <= int(byte) <= 255:
|
if not 0 <= int(byte) <= 255:
|
||||||
raise ValueError(f"Invalid byte in FPGA IP: {byte}")
|
raise ValueError(f"Invalid byte in FPGA IP: {byte}")
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_config(cls, config):
|
||||||
|
return EthernetInterface(**config)
|
||||||
|
|
||||||
def to_config(self):
|
def to_config(self):
|
||||||
config = {
|
config = {
|
||||||
"fpga_ip_addr": self._fpga_ip_addr,
|
"fpga_ip_addr": self._fpga_ip_addr,
|
||||||
|
|
|
||||||
|
|
@ -40,7 +40,7 @@ class IOCore(MantaCore):
|
||||||
return self._max_addr
|
return self._max_addr
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_config(cls, config, base_addr, interface):
|
def from_config(cls, config):
|
||||||
inputs = config.get("inputs", {})
|
inputs = config.get("inputs", {})
|
||||||
outputs = config.get("outputs", {})
|
outputs = config.get("outputs", {})
|
||||||
|
|
||||||
|
|
@ -117,7 +117,7 @@ class IOCore(MantaCore):
|
||||||
|
|
||||||
output_signals += [Signal(width, name=name, init=initial_value)]
|
output_signals += [Signal(width, name=name, init=initial_value)]
|
||||||
|
|
||||||
return cls(base_addr, interface, inputs=input_signals, outputs=output_signals)
|
return cls(inputs=input_signals, outputs=output_signals)
|
||||||
|
|
||||||
def to_config(self):
|
def to_config(self):
|
||||||
config = {}
|
config = {}
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,8 @@ from manta.io_core import IOCore
|
||||||
from manta.memory_core import MemoryCore
|
from manta.memory_core import MemoryCore
|
||||||
from manta.logic_analyzer import LogicAnalyzerCore
|
from manta.logic_analyzer import LogicAnalyzerCore
|
||||||
from manta.utils import *
|
from manta.utils import *
|
||||||
|
import yaml
|
||||||
|
import json
|
||||||
|
|
||||||
|
|
||||||
class Manta(Elaboratable):
|
class Manta(Elaboratable):
|
||||||
|
|
@ -25,117 +27,61 @@ class Manta(Elaboratable):
|
||||||
for core in self.cores._cores.values():
|
for core in self.cores._cores.values():
|
||||||
core.interface = value
|
core.interface = value
|
||||||
|
|
||||||
# def __init__(self, config):
|
@classmethod
|
||||||
# # Load config from either a configuration file or a dictionary.
|
def from_config(cls, config_path):
|
||||||
# # Users primarily use the config file, but the dictionary is
|
|
||||||
# # included for internal tests.
|
|
||||||
|
|
||||||
# if isinstance(config, str):
|
# Load config from either YAML or JSON
|
||||||
# self._config = self._read_config_file(config)
|
extension = config_path.split(".")[-1]
|
||||||
|
if extension not in ["yaml", "yml", "json"]:
|
||||||
|
raise ValueError(f"Configuration file {config_path} has unrecognized file type.")
|
||||||
|
|
||||||
# if isinstance(config, dict):
|
with open(config_path, "r") as f:
|
||||||
# self._config = config
|
if extension in ["yaml", "yml"]:
|
||||||
|
config = yaml.safe_load(f)
|
||||||
|
|
||||||
# self._check_config()
|
elif extension in ["json"]:
|
||||||
|
config = json.load(f)
|
||||||
|
|
||||||
# self._get_interface()
|
# Validate config
|
||||||
# self._get_cores()
|
if "cores" not in config:
|
||||||
# self._add_friendly_core_names()
|
raise ValueError("No cores specified in configuration file.")
|
||||||
|
|
||||||
# def _read_config_file(self, path):
|
if not len(config["cores"]) > 0:
|
||||||
# """
|
raise ValueError("Must specify at least one core.")
|
||||||
# Takes a path to configuration file, and return the configuration as a
|
|
||||||
# python dictionary.
|
|
||||||
# """
|
|
||||||
|
|
||||||
# extension = path.split(".")[-1]
|
for name, attrs in config["cores"].items():
|
||||||
|
# Make sure core type is specified
|
||||||
|
if "type" not in attrs:
|
||||||
|
raise ValueError(f"No type specified for core {name}.")
|
||||||
|
|
||||||
# if "json" in extension:
|
if attrs["type"] not in ["logic_analyzer", "io", "memory"]:
|
||||||
# import json
|
raise ValueError(f"Unrecognized core type specified for {name}.")
|
||||||
# with open(path, "r") as f:
|
|
||||||
# return json.load(f)
|
|
||||||
|
|
||||||
# elif "yaml" in extension or "yml" in extension:
|
# Make Manta object, and configure it
|
||||||
# import yaml
|
manta = Manta()
|
||||||
# with open(path, "r") as f:
|
|
||||||
# return yaml.safe_load(f)
|
|
||||||
|
|
||||||
# else:
|
# Add interface
|
||||||
# raise ValueError("Unable to recognize configuration file extension.")
|
if "uart" in config:
|
||||||
|
manta.interface = UARTInterface.from_config(config["uart"])
|
||||||
|
|
||||||
# def _check_config(self):
|
elif "ethernet" in config:
|
||||||
# if "cores" not in self._config:
|
manta.interface = EthernetInterface.from_config(config["ethernet"])
|
||||||
# raise ValueError("No cores specified in configuration file.")
|
|
||||||
|
|
||||||
# if not len(self._config["cores"]) > 0:
|
# Add cores
|
||||||
# raise ValueError("Must specify at least one core.")
|
for name, attrs in config["cores"].items():
|
||||||
|
if attrs["type"] == "io":
|
||||||
|
core = IOCore.from_config(attrs)
|
||||||
|
|
||||||
# for name, attrs in self._config["cores"].items():
|
elif attrs["type"] == "logic_analyzer":
|
||||||
# # Make sure core type is specified
|
core = LogicAnalyzerCore.from_config(attrs)
|
||||||
# if "type" not in attrs:
|
|
||||||
# raise ValueError(f"No type specified for core {name}.")
|
|
||||||
|
|
||||||
# if attrs["type"] not in ["logic_analyzer", "io", "memory"]:
|
elif attrs["type"] == "memory":
|
||||||
# raise ValueError(f"Unrecognized core type specified for {name}.")
|
core = MemoryCore.from_config(attrs)
|
||||||
|
|
||||||
# def _get_interface(self):
|
setattr(manta.cores, name, core)
|
||||||
# """
|
|
||||||
# Returns an instance of an interface object (UARTInterface or
|
|
||||||
# EthernetInterface) configured with the parameters in the
|
|
||||||
# config file.
|
|
||||||
# """
|
|
||||||
# if "uart" in self._config:
|
|
||||||
# self.interface = UARTInterface.from_config(self._config["uart"])
|
|
||||||
|
|
||||||
# elif "ethernet" in self._config:
|
return manta
|
||||||
# self.interface = EthernetInterface(self._config["ethernet"])
|
|
||||||
|
|
||||||
# else:
|
|
||||||
# raise ValueError("No recognized interface specified.")
|
|
||||||
|
|
||||||
# def _get_cores(self):
|
|
||||||
# """
|
|
||||||
# Creates instances of the cores (IOCore, LogicAnalyzerCore, MemoryCore)
|
|
||||||
# specified in the user's configuration, and returns them as a list.
|
|
||||||
# """
|
|
||||||
|
|
||||||
# self._cores = {}
|
|
||||||
# base_addr = 0
|
|
||||||
# for name, attrs in self._config["cores"].items():
|
|
||||||
# if attrs["type"] == "io":
|
|
||||||
# core = IOCore.from_config(attrs, base_addr, self.interface)
|
|
||||||
|
|
||||||
# elif attrs["type"] == "logic_analyzer":
|
|
||||||
# core = LogicAnalyzerCore(attrs, base_addr, self.interface)
|
|
||||||
|
|
||||||
# elif attrs["type"] == "memory":
|
|
||||||
# core = MemoryCore.from_config(attrs, base_addr, self.interface)
|
|
||||||
|
|
||||||
# # Make sure we're not out of address space
|
|
||||||
# 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.max_addr + 1
|
|
||||||
# self._cores[name] = core
|
|
||||||
|
|
||||||
# def _add_friendly_core_names(self):
|
|
||||||
# """
|
|
||||||
# Add cores to the instance under a friendly name - ie, a core named `my_core` belonging
|
|
||||||
# to a Manta instance `m` could be obtained with `m.cores["my_core"]`, but this allows
|
|
||||||
# it to be obtained with `m.my_core`. Which is way nicer.
|
|
||||||
# """
|
|
||||||
|
|
||||||
# for name, instance in self._cores.items():
|
|
||||||
# if not hasattr(self, name):
|
|
||||||
# setattr(self, name, instance)
|
|
||||||
|
|
||||||
# else:
|
|
||||||
# raise ValueError(
|
|
||||||
# "Cannot add object to Manta instance - name is already taken!"
|
|
||||||
# )
|
|
||||||
|
|
||||||
def elaborate(self, platform):
|
def elaborate(self, platform):
|
||||||
m = Module()
|
m = Module()
|
||||||
|
|
|
||||||
|
|
@ -88,7 +88,7 @@ class MemoryCore(MantaCore):
|
||||||
}
|
}
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_config(cls, config, base_addr, interface):
|
def from_config(cls, config):
|
||||||
# Check for unrecognized options
|
# Check for unrecognized options
|
||||||
valid_options = ["type", "depth", "width", "mode"]
|
valid_options = ["type", "depth", "width", "mode"]
|
||||||
for option in config:
|
for option in config:
|
||||||
|
|
@ -125,7 +125,7 @@ class MemoryCore(MantaCore):
|
||||||
if mode not in ["fpga_to_host", "host_to_fpga", "bidirectional"]:
|
if mode not in ["fpga_to_host", "host_to_fpga", "bidirectional"]:
|
||||||
raise ValueError("Unrecognized mode provided to memory core.")
|
raise ValueError("Unrecognized mode provided to memory core.")
|
||||||
|
|
||||||
return cls(mode, width, depth, base_addr, interface)
|
return cls(mode, width, depth)
|
||||||
|
|
||||||
def _tie_mems_to_bus(self, m):
|
def _tie_mems_to_bus(self, m):
|
||||||
for i, mem in enumerate(self._mems):
|
for i, mem in enumerate(self._mems):
|
||||||
|
|
|
||||||
|
|
@ -76,6 +76,10 @@ class CoreContainer:
|
||||||
self._cores[name] = value
|
self._cores[name] = value
|
||||||
value.interface = self._manta.interface
|
value.interface = self._manta.interface
|
||||||
value.base_addr = self._last_used_addr
|
value.base_addr = self._last_used_addr
|
||||||
|
|
||||||
|
if value.max_addr > (2**16)-1:
|
||||||
|
raise ValueError(f"Ran out of address space while allocating core.")
|
||||||
|
|
||||||
self._last_used_addr = value.max_addr + 1
|
self._last_used_addr = value.max_addr + 1
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue