diff --git a/examples/verilog/icestick/uart_io_core/blinky.py b/examples/verilog/icestick/uart_io_core/blinky.py index 95d3dec..e66579e 100644 --- a/examples/verilog/icestick/uart_io_core/blinky.py +++ b/examples/verilog/icestick/uart_io_core/blinky.py @@ -1,16 +1,16 @@ -from manta import Manta +from manta import * from time import sleep -manta = Manta("manta.yaml") +manta = Manta.from_config("manta.yaml") i = 0 while True: # Turn each LED off 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 - 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 sleep(0.1) diff --git a/examples/verilog/nexys4_ddr/ether_logic_analyzer_io_core/test.py b/examples/verilog/nexys4_ddr/ether_logic_analyzer_io_core/test.py index 06ab14a..dd4aad7 100644 --- a/examples/verilog/nexys4_ddr/ether_logic_analyzer_io_core/test.py +++ b/examples/verilog/nexys4_ddr/ether_logic_analyzer_io_core/test.py @@ -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")) -m.my_io_core.set_probe("led", 4) +print(manta.cores.my_io_core.get_probe("sw")) +manta.cores.my_io_core.set_probe("led", 4) diff --git a/examples/verilog/nexys4_ddr/uart_host_to_fpga_mem/write.py b/examples/verilog/nexys4_ddr/uart_host_to_fpga_mem/write.py index 3c62506..6672bb6 100644 --- a/examples/verilog/nexys4_ddr/uart_host_to_fpga_mem/write.py +++ b/examples/verilog/nexys4_ddr/uart_host_to_fpga_mem/write.py @@ -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 # flipping the switches on the FPGA, and watching the LEDs update! -m.my_memory.write(0, 1) +manta.cores.my_memory.write(0, 1) diff --git a/examples/verilog/nexys4_ddr/uart_io_core/blinky.py b/examples/verilog/nexys4_ddr/uart_io_core/blinky.py index e4c4920..1612555 100644 --- a/examples/verilog/nexys4_ddr/uart_io_core/blinky.py +++ b/examples/verilog/nexys4_ddr/uart_io_core/blinky.py @@ -1,25 +1,25 @@ -from manta import Manta +from manta import * from time import sleep from random import randint -m = Manta("manta.yaml") +manta = Manta.from_config("manta.yaml") i = 0 while True: 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)) - m.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_r", randint(0, 1)) + manta.cores.my_io_core.set_probe("led16_g", 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'btnu: {m.my_io_core.get_probe("btnu")}') - print(f'btnd: {m.my_io_core.get_probe("btnd")}') - print(f'btnr: {m.my_io_core.get_probe("btnr")}') - print(f'btnl: {m.my_io_core.get_probe("btnl")}') - print(f'btnc: {m.my_io_core.get_probe("btnc")}') + print(f'btnu: {manta.cores.my_io_core.get_probe("btnu")}') + print(f'btnd: {manta.cores.my_io_core.get_probe("btnd")}') + print(f'btnr: {manta.cores.my_io_core.get_probe("btnr")}') + print(f'btnl: {manta.cores.my_io_core.get_probe("btnl")}') + print(f'btnc: {manta.cores.my_io_core.get_probe("btnc")}') print("") sleep(0.1) diff --git a/src/manta/cli.py b/src/manta/cli.py index 1a1f8fb..0f8eeab 100644 --- a/src/manta/cli.py +++ b/src/manta/cli.py @@ -69,13 +69,13 @@ def wrong_args(): def gen(config_path, output_path): - m = Manta(config_path) - m.generate_verilog(output_path) + manta = Manta.from_config(config_path) + manta.generate_verilog(output_path) def inst(config_path): - m = Manta(config_path) - ports = m.get_top_level_ports() + manta = Manta.from_config(config_path) + ports = manta.get_top_level_ports() hdl = ",\n ".join([f".{p.name}({p.name})" for p in ports]) foo = """ @@ -88,8 +88,8 @@ manta manta_inst( def capture(config_path, logic_analyzer_name, export_paths): - m = Manta(config_path) - la = getattr(m, logic_analyzer_name) + manta = Manta.from_config(config_path) + la = getattr(manta.cores, logic_analyzer_name) cap = la.capture() for path in export_paths: diff --git a/src/manta/ethernet/__init__.py b/src/manta/ethernet/__init__.py index 74f0e4b..3cb82f2 100644 --- a/src/manta/ethernet/__init__.py +++ b/src/manta/ethernet/__init__.py @@ -22,7 +22,7 @@ class EthernetInterface(Elaboratable): self._host_ip_addr = host_ip_addr self._udp_port = udp_port self._phy = phy - self._clk_freq = clk_freq + self._clk_freq = float(clk_freq) self._additional_config = kwargs self._check_config() @@ -81,6 +81,10 @@ class EthernetInterface(Elaboratable): if not 0 <= int(byte) <= 255: raise ValueError(f"Invalid byte in FPGA IP: {byte}") + @classmethod + def from_config(cls, config): + return EthernetInterface(**config) + def to_config(self): config = { "fpga_ip_addr": self._fpga_ip_addr, diff --git a/src/manta/io_core.py b/src/manta/io_core.py index aae8c7d..19b36eb 100644 --- a/src/manta/io_core.py +++ b/src/manta/io_core.py @@ -40,7 +40,7 @@ class IOCore(MantaCore): return self._max_addr @classmethod - def from_config(cls, config, base_addr, interface): + def from_config(cls, config): inputs = config.get("inputs", {}) outputs = config.get("outputs", {}) @@ -117,7 +117,7 @@ class IOCore(MantaCore): 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): config = {} diff --git a/src/manta/manta.py b/src/manta/manta.py index 7ead3c7..1ecfc0d 100644 --- a/src/manta/manta.py +++ b/src/manta/manta.py @@ -5,6 +5,8 @@ from manta.io_core import IOCore from manta.memory_core import MemoryCore from manta.logic_analyzer import LogicAnalyzerCore from manta.utils import * +import yaml +import json class Manta(Elaboratable): @@ -25,117 +27,61 @@ class Manta(Elaboratable): for core in self.cores._cores.values(): core.interface = value - # def __init__(self, config): - # # Load config from either a configuration file or a dictionary. - # # Users primarily use the config file, but the dictionary is - # # included for internal tests. + @classmethod + def from_config(cls, config_path): - # if isinstance(config, str): - # self._config = self._read_config_file(config) + # Load config from either YAML or JSON + 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): - # self._config = config + with open(config_path, "r") as f: + if extension in ["yaml", "yml"]: + config = yaml.safe_load(f) - # self._check_config() + elif extension in ["json"]: + config = json.load(f) - # self._get_interface() - # self._get_cores() - # self._add_friendly_core_names() + # Validate config + if "cores" not in config: + raise ValueError("No cores specified in configuration file.") - # def _read_config_file(self, path): - # """ - # Takes a path to configuration file, and return the configuration as a - # python dictionary. - # """ + if not len(config["cores"]) > 0: + raise ValueError("Must specify at least one core.") - # 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: - # import json - # with open(path, "r") as f: - # return json.load(f) + if attrs["type"] not in ["logic_analyzer", "io", "memory"]: + raise ValueError(f"Unrecognized core type specified for {name}.") - # elif "yaml" in extension or "yml" in extension: - # import yaml - # with open(path, "r") as f: - # return yaml.safe_load(f) + # Make Manta object, and configure it + manta = Manta() - # else: - # raise ValueError("Unable to recognize configuration file extension.") + # Add interface + if "uart" in config: + manta.interface = UARTInterface.from_config(config["uart"]) - # def _check_config(self): - # if "cores" not in self._config: - # raise ValueError("No cores specified in configuration file.") + elif "ethernet" in config: + manta.interface = EthernetInterface.from_config(config["ethernet"]) - # if not len(self._config["cores"]) > 0: - # raise ValueError("Must specify at least one core.") + # Add cores + for name, attrs in config["cores"].items(): + if attrs["type"] == "io": + core = IOCore.from_config(attrs) - # for name, attrs in self._config["cores"].items(): - # # Make sure core type is specified - # if "type" not in attrs: - # raise ValueError(f"No type specified for core {name}.") + elif attrs["type"] == "logic_analyzer": + core = LogicAnalyzerCore.from_config(attrs) - # if attrs["type"] not in ["logic_analyzer", "io", "memory"]: - # raise ValueError(f"Unrecognized core type specified for {name}.") + elif attrs["type"] == "memory": + core = MemoryCore.from_config(attrs) - # def _get_interface(self): - # """ - # 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"]) + setattr(manta.cores, name, core) - # elif "ethernet" in self._config: - # self.interface = EthernetInterface(self._config["ethernet"]) + return manta - # 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): m = Module() diff --git a/src/manta/memory_core.py b/src/manta/memory_core.py index ed8fa14..e9e86a3 100644 --- a/src/manta/memory_core.py +++ b/src/manta/memory_core.py @@ -88,7 +88,7 @@ class MemoryCore(MantaCore): } @classmethod - def from_config(cls, config, base_addr, interface): + def from_config(cls, config): # Check for unrecognized options valid_options = ["type", "depth", "width", "mode"] for option in config: @@ -125,7 +125,7 @@ class MemoryCore(MantaCore): if mode not in ["fpga_to_host", "host_to_fpga", "bidirectional"]: 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): for i, mem in enumerate(self._mems): diff --git a/src/manta/utils.py b/src/manta/utils.py index 47922c7..5b5bfb5 100644 --- a/src/manta/utils.py +++ b/src/manta/utils.py @@ -76,6 +76,10 @@ class CoreContainer: self._cores[name] = value value.interface = self._manta.interface 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