diff --git a/src/manta/cli.py b/src/manta/cli.py index cb79be3..e629064 100644 --- a/src/manta/cli.py +++ b/src/manta/cli.py @@ -54,9 +54,11 @@ Usage: def help(): print(usage) + def version(): print(logo) + def wrong_args(): print('Wrong number of arguments, run "manta help" for usage.') diff --git a/src/manta/logic_analyzer/__init__.py b/src/manta/logic_analyzer/__init__.py index 6e38e54..ffce911 100644 --- a/src/manta/logic_analyzer/__init__.py +++ b/src/manta/logic_analyzer/__init__.py @@ -68,98 +68,102 @@ class LogicAnalyzerCore(Elaboratable): warn(f"Ignoring unrecognized option '{option}' in Logic Analyzer.") # Check sample depth is provided and positive - if "sample_depth" not in config: + sample_depth = config.get("sample_depth") + if not sample_depth: raise ValueError("Logic Analyzer must have sample_depth specified.") - if not isinstance(config["sample_depth"], int): - raise ValueError("Logic Analyzer sample_depth must be an integer.") - - if config["sample_depth"] <= 0: - raise ValueError("Logic Analyzer sample_depth must be positive.") + if not isinstance(sample_depth, int) or sample_depth <= 0: + raise ValueError("Logic Analyzer sample_depth must be a positive integer.") # Check probes - if "probes" not in config: - raise ValueError("Logic Analyzer must have at least one probe specified.") - - if len(config["probes"]) == 0: + if "probes" not in config or len(config["probes"]) == 0: raise ValueError("Logic Analyzer must have at least one probe specified.") for name, width in config["probes"].items(): if width < 0: raise ValueError(f"Width of probe {name} must be positive.") - # Check triggers - if "triggers" not in config: - raise ValueError("Logic Analyzer must have at least one trigger specified.") - - if len(config["triggers"]) == 0: - raise ValueError("Logic Analyzer must have at least one trigger specified.") - - # Check trigger location - if "trigger_location" in config: - if not isinstance(config["trigger_location"], int): - raise ValueError("Trigger location must be an integer.") - - if config["trigger_location"] < 0: - raise ValueError("Trigger location must be positive.") - - if config["trigger_location"] > config["sample_depth"]: - raise ValueError("Trigger location cannot exceed sample depth.") - # Check trigger mode, if provided - if "trigger_mode" in config: - valid_modes = ["single_shot", "incremental", "immediate"] - if config["trigger_mode"] not in valid_modes: + trigger_mode = config.get("trigger_mode") + valid_modes = ["single_shot", "incremental", "immediate"] + if trigger_mode and trigger_mode not in valid_modes: + raise ValueError( + f"Unrecognized trigger mode {config['trigger_mode']} provided." + ) + + # Check triggers + if (trigger_mode) and (trigger_mode != "immediate"): + if ("triggers" not in config) or (config["triggers"] == 0): raise ValueError( - f"Unrecognized trigger mode {config['trigger_mode']} provided." + "Logic Analyzer must have at least one trigger specified." ) - if config["trigger_mode"] == "incremental": - if "trigger_location" in config: - warn( - "Ignoring option 'trigger_location', as 'trigger_mode' is set to immediate, and there is no trigger condition to wait for." - ) + # Check trigger location + trigger_location = config.get("trigger_location") + if trigger_location: + if not isinstance(trigger_location, int) or trigger_location < 0: + raise ValueError("Trigger location must be a positive integer.") + + if trigger_location > config["sample_depth"]: + raise ValueError("Trigger location cannot exceed sample depth.") + + if trigger_mode == "immediate": + warn( + "Ignoring option 'trigger_location', as 'trigger_mode' is set to immediate, and there is no trigger condition to wait for." + ) # Check triggers themselves - for trigger in config["triggers"]: - if not isinstance(trigger, str): - raise ValueError("Trigger must be specified with a string.") + if trigger_mode == "immediate": + if "triggers" in config: + warn( + "Ignoring triggers as 'trigger_mode' is set to immediate, and there are no triggers to specify." + ) - # Trigger conditions may be composed of either two or three components, - # depending on the operation specified. In the case of operations that - # don't need an argument (like DISABLE, RISING, FALLING, CHANGING) or - # three statements in + else: + if ("triggers" not in config) or (len(config["triggers"]) == 0): + raise ValueError("At least one trigger must be specified.") - # Check the trigger operations - components = trigger.strip().split(" ") - if len(components) == 2: - name, op = components - if op not in ["DISABLE", "RISING", "FALLING", "CHANGING"]: + for trigger in config.get("triggers"): + if not isinstance(trigger, str): + raise ValueError("Trigger must be specified with a string.") + + # Trigger conditions may be composed of either two or three components, + # depending on the operation specified. In the case of operations that + # don't need an argument (like DISABLE, RISING, FALLING, CHANGING) or + # three statements in + + # Check the trigger operations + components = trigger.strip().split(" ") + if len(components) == 2: + name, op = components + if op not in ["DISABLE", "RISING", "FALLING", "CHANGING"]: + raise ValueError( + f"Unable to interpret trigger condition '{trigger}'." + ) + + elif len(components) == 3: + name, op, arg = components + if op not in ["GT", "LT", "GEQ", "LEQ", "EQ", "NEQ"]: + raise ValueError( + f"Unable to interpret trigger condition '{trigger}'." + ) + + else: raise ValueError( f"Unable to interpret trigger condition '{trigger}'." ) - elif len(components) == 3: - name, op, arg = components - if op not in ["GT", "LT", "GEQ", "LEQ", "EQ", "NEQ"]: - raise ValueError( - f"Unable to interpret trigger condition '{trigger}'." - ) - - else: - raise ValueError(f"Unable to interpret trigger condition '{trigger}'.") - - # Check probe names - if components[0] not in config["probes"]: - raise ValueError(f"Unknown probe name '{components[0]}' specified.") + # Check probe names + if components[0] not in config["probes"]: + raise ValueError(f"Unknown probe name '{components[0]}' specified.") def elaborate(self, platform): m = Module() # Add submodules - m.submodules["fsm"] = fsm = self.fsm - m.submodules["sample_mem"] = sample_mem = self.sample_mem - m.submodules["trig_blk"] = trig_blk = self.trig_blk + m.submodules.fsm = fsm = self.fsm + m.submodules.sample_mem = sample_mem = self.sample_mem + m.submodules.trig_blk = trig_blk = self.trig_blk # Concat all the probes together, and feed to input of sample memory # (it is necessary to reverse the order such that first probe occupies @@ -173,11 +177,10 @@ class LogicAnalyzerCore(Elaboratable): trig_blk.bus_i.eq(self.fsm.bus_o), sample_mem.bus_i.eq(trig_blk.bus_o), self.bus_o.eq(sample_mem.bus_o), - # Non-bus Connections fsm.trigger.eq(trig_blk.trig), sample_mem.user_addr.eq(fsm.r.write_pointer), - sample_mem.user_we.eq(fsm.write_enable) + sample_mem.user_we.eq(fsm.write_enable), ] return m @@ -215,6 +218,7 @@ class LogicAnalyzerCore(Elaboratable): print_if_verbose(" -> Resetting core...") state = self.fsm.r.get_probe("state") if state != self.fsm.states["IDLE"]: + self.fsm.r.set_probe("request_start", 0) self.fsm.r.set_probe("request_stop", 0) self.fsm.r.set_probe("request_stop", 1) self.fsm.r.set_probe("request_stop", 0) @@ -224,12 +228,16 @@ class LogicAnalyzerCore(Elaboratable): # Set triggers print_if_verbose(" -> Setting triggers...") - self.trig_blk.set_triggers(self.config) + self.trig_blk.clear_triggers() + + if self.config["trigger_mode"] != "immediate": + self.trig_blk.set_triggers(self.config) # Set trigger mode, default to single-shot if user didn't specify a mode print_if_verbose(" -> Setting trigger mode...") if "trigger_mode" in self.config: - self.fsm.r.set_probe("trigger_mode", self.config["trigger_mode"]) + mode = self.config["trigger_mode"].upper() + self.fsm.r.set_probe("trigger_mode", self.fsm.trigger_modes[mode]) else: self.fsm.r.set_probe("trigger_mode", self.fsm.trigger_modes["SINGLE_SHOT"]) @@ -244,6 +252,7 @@ class LogicAnalyzerCore(Elaboratable): # Send a start request to the state machine print_if_verbose(" -> Starting capture...") + self.fsm.r.set_probe("request_start", 0) self.fsm.r.set_probe("request_start", 1) self.fsm.r.set_probe("request_start", 0) @@ -362,16 +371,20 @@ class LogicAnalyzerCapture: signals.append(signal) clock = writer.register_var("manta", "clk", "wire", size=1) - trigger = writer.register_var("manta", "trigger", "wire", size=1) + + # include a trigger signal such would be meaningful (ie, we didn't trigger immediately) + if self.config["trigger_mode"] != "immediate": + trigger = writer.register_var("manta", "trigger", "wire", size=1) # add the data to each probe in the vcd file for timestamp in range(0, 2 * len(self.data)): # run the clock writer.change(clock, timestamp, timestamp % 2 == 0) - # set the trigger - triggered = (timestamp // 2) >= self.get_trigger_location() - writer.change(trigger, timestamp, triggered) + # set the trigger (if there is one) + if self.config["trigger_mode"] != "immediate": + triggered = (timestamp // 2) >= self.get_trigger_location() + writer.change(trigger, timestamp, triggered) # add other signals for signal in signals: diff --git a/src/manta/logic_analyzer/fsm.py b/src/manta/logic_analyzer/fsm.py index 4d8583e..d146818 100644 --- a/src/manta/logic_analyzer/fsm.py +++ b/src/manta/logic_analyzer/fsm.py @@ -56,7 +56,7 @@ class LogicAnalyzerFSM(Elaboratable): def elaborate(self, platform): m = Module() - m.submodules["registers"] = self.r + m.submodules.registers = self.r prev_request_start = Signal(1) prev_request_stop = Signal(1) @@ -74,6 +74,7 @@ class LogicAnalyzerFSM(Elaboratable): m.d.sync += self.write_enable.eq(1) with m.If(self.r.trigger_mode == self.trigger_modes["IMMEDIATE"]): m.d.sync += self.r.state.eq(self.states["CAPTURING"]) + m.d.sync += self.r.write_pointer.eq(self.r.write_pointer + 1) with m.Else(): with m.If(self.r.trigger_location == 0): @@ -82,7 +83,7 @@ class LogicAnalyzerFSM(Elaboratable): with m.Else(): m.d.sync += self.r.state.eq(self.states["MOVE_TO_POSITION"]) - m.d.sync += self.r.state.eq(self.states["MOVE_TO_POSITION"]) + # m.d.sync += self.r.state.eq(self.states["MOVE_TO_POSITION"]) with m.Elif(self.r.state == self.states["MOVE_TO_POSITION"]): m.d.sync += self.r.write_pointer.eq(self.r.write_pointer + 1) diff --git a/src/manta/logic_analyzer/playback.py b/src/manta/logic_analyzer/playback.py index a08db8a..50100e6 100644 --- a/src/manta/logic_analyzer/playback.py +++ b/src/manta/logic_analyzer/playback.py @@ -38,7 +38,7 @@ class LogicAnalyzerPlayback(Elaboratable): def elaborate(self, platform): m = Module() - m.submodules["mem"] = self.mem + m.submodules.mem = self.mem m.d.comb += self.read_port.en.eq(1) diff --git a/src/manta/logic_analyzer/trigger_block.py b/src/manta/logic_analyzer/trigger_block.py index 0d0a0bd..0591e2e 100644 --- a/src/manta/logic_analyzer/trigger_block.py +++ b/src/manta/logic_analyzer/trigger_block.py @@ -28,12 +28,13 @@ class LogicAnalyzerTriggerBlock(Elaboratable): def get_max_addr(self): return self.r.get_max_addr() - def set_triggers(self, config): - # reset all triggers to zero + def clear_triggers(self): + # reset all triggers to disabled with no argument for p in self.probes: self.r.set_probe(p.name + "_op", 0) self.r.set_probe(p.name + "_arg", 0) + def set_triggers(self, config): # set triggers for trigger in config["triggers"]: components = trigger.strip().split(" ") @@ -53,7 +54,7 @@ class LogicAnalyzerTriggerBlock(Elaboratable): m = Module() # Add IO Core as submodule - m.submodules["registers"] = self.r + m.submodules.registers = self.r # Add triggers as submodules for t in self.triggers: diff --git a/src/manta/manta.py b/src/manta/manta.py index 63f902b..a86150a 100644 --- a/src/manta/manta.py +++ b/src/manta/manta.py @@ -126,7 +126,7 @@ class Manta(Elaboratable): m = Module() # Add interface as submodule - m.submodules["interface"] = self.interface + m.submodules.interface = self.interface # Add all cores as submodules for name, instance in self.cores.items(): diff --git a/src/manta/memory_core.py b/src/manta/memory_core.py index e74e32d..db54a36 100644 --- a/src/manta/memory_core.py +++ b/src/manta/memory_core.py @@ -61,7 +61,7 @@ class ReadOnlyMemoryCore(Elaboratable): m.d.sync += self.bus_pipe[0].eq(self.bus_i) for i in range(1, 3): - m.d.sync += self.bus_pipe[i].eq(self.bus_pipe[i-1]) + m.d.sync += self.bus_pipe[i].eq(self.bus_pipe[i - 1]) m.d.sync += self.bus_o.eq(self.bus_pipe[2]) diff --git a/src/manta/uart/__init__.py b/src/manta/uart/__init__.py index a6f5c19..7540c93 100644 --- a/src/manta/uart/__init__.py +++ b/src/manta/uart/__init__.py @@ -232,10 +232,10 @@ class UARTInterface(Elaboratable): # fancy submoduling and such goes in here m = Module() - m.submodules["uart_rx"] = uart_rx = UARTReceiver(self.clocks_per_baud) - m.submodules["bridge_rx"] = bridge_rx = ReceiveBridge() - m.submodules["bridge_tx"] = bridge_tx = TransmitBridge() - m.submodules["uart_tx"] = uart_tx = UARTTransmitter(self.clocks_per_baud) + m.submodules.uart_rx = uart_rx = UARTReceiver(self.clocks_per_baud) + m.submodules.bridge_rx = bridge_rx = ReceiveBridge() + m.submodules.bridge_tx = bridge_tx = TransmitBridge() + m.submodules.uart_tx = uart_tx = UARTTransmitter(self.clocks_per_baud) m.d.comb += [ # UART RX -> Internal Bus diff --git a/test/test_io_core_hw.py b/test/test_io_core_hw.py index c463aa6..1e6f31c 100644 --- a/test/test_io_core_hw.py +++ b/test/test_io_core_hw.py @@ -13,7 +13,7 @@ class IOCoreLoopbackTest(Elaboratable): self.port = port self.config = self.platform_specific_config() - self.m = Manta(self.config) + self.manta = Manta(self.config) def platform_specific_config(self): return { @@ -41,17 +41,17 @@ class IOCoreLoopbackTest(Elaboratable): def elaborate(self, platform): m = Module() - m.submodules["manta"] = self.m + m.submodules.manta = self.manta uart_pins = platform.request("uart") m.d.comb += [ - self.m.io_core.probe0.eq(self.m.io_core.probe4), - self.m.io_core.probe1.eq(self.m.io_core.probe5), - self.m.io_core.probe2.eq(self.m.io_core.probe6), - self.m.io_core.probe3.eq(self.m.io_core.probe7), - self.m.interface.rx.eq(uart_pins.rx.i), - uart_pins.tx.o.eq(self.m.interface.tx), + self.manta.io_core.probe0.eq(self.manta.io_core.probe4), + self.manta.io_core.probe1.eq(self.manta.io_core.probe5), + self.manta.io_core.probe2.eq(self.manta.io_core.probe6), + self.manta.io_core.probe3.eq(self.manta.io_core.probe7), + self.manta.interface.rx.eq(uart_pins.rx.i), + uart_pins.tx.o.eq(self.manta.interface.tx), ] return m @@ -71,7 +71,7 @@ class IOCoreLoopbackTest(Elaboratable): outputs = self.config["cores"]["io_core"]["outputs"] for name, attrs in outputs.items(): - actual = self.m.io_core.get_probe(name) + actual = self.manta.io_core.get_probe(name) if isinstance(attrs, dict): if "initial_value" in attrs: @@ -100,8 +100,8 @@ class IOCoreLoopbackTest(Elaboratable): width = self.config["cores"]["io_core"]["inputs"][input] value = randint(0, 2**width - 1) - self.m.io_core.set_probe(output, value) - readback = self.m.io_core.get_probe(input) + self.manta.io_core.set_probe(output, value) + readback = self.manta.io_core.get_probe(input) if readback != value: raise ValueError( diff --git a/test/test_logic_analyzer_hw.py b/test/test_logic_analyzer_hw.py index 5bfd0ca..12e8c41 100644 --- a/test/test_logic_analyzer_hw.py +++ b/test/test_logic_analyzer_hw.py @@ -12,7 +12,7 @@ class LogicAnalyzerCounterTest(Elaboratable): self.port = port self.config = self.platform_specific_config() - self.m = Manta(self.config) + self.manta = Manta(self.config) def platform_specific_config(self): return { @@ -20,9 +20,8 @@ class LogicAnalyzerCounterTest(Elaboratable): "la": { "type": "logic_analyzer", "sample_depth": 1024, - "trigger_location": 500, + "trigger_mode": "immediate", "probes": {"larry": 1, "curly": 3, "moe": 9}, - "triggers": ["moe RISING"], }, }, "uart": { @@ -34,20 +33,20 @@ class LogicAnalyzerCounterTest(Elaboratable): def elaborate(self, platform): m = Module() - m.submodules["manta"] = self.m + m.submodules.manta = self.manta uart_pins = platform.request("uart") - larry = self.m.la.probes[0] - curly = self.m.la.probes[1] - moe = self.m.la.probes[2] + larry = self.manta.la.probes[0] + curly = self.manta.la.probes[1] + moe = self.manta.la.probes[2] m.d.sync += larry.eq(larry + 1) m.d.sync += curly.eq(curly + 1) m.d.sync += moe.eq(moe + 1) m.d.comb += [ - self.m.interface.rx.eq(uart_pins.rx.i), - uart_pins.tx.o.eq(self.m.interface.tx), + self.manta.interface.rx.eq(uart_pins.rx.i), + uart_pins.tx.o.eq(self.manta.interface.tx), ] return m @@ -57,7 +56,7 @@ class LogicAnalyzerCounterTest(Elaboratable): def verify(self): self.build_and_program() - cap = self.m.la.capture() + cap = self.manta.la.capture() # check that VCD export works cap.export_vcd("out.vcd") @@ -66,7 +65,7 @@ class LogicAnalyzerCounterTest(Elaboratable): cap.export_playback_verilog("out.v") # verify that each signal is just a counter modulo the width of the signal - for name, width in self.m.la.config["probes"].items(): + for name, width in self.manta.la.config["probes"].items(): trace = cap.get_trace(name) for i in range(len(trace) - 1): diff --git a/test/test_mem_core_hw.py b/test/test_mem_core_hw.py index 8c7af24..e9c0710 100644 --- a/test/test_mem_core_hw.py +++ b/test/test_mem_core_hw.py @@ -22,7 +22,7 @@ class MemoryCoreLoopbackTest(Elaboratable): self.port = port self.config = self.platform_specific_config() - self.m = Manta(self.config) + self.manta = Manta(self.config) def platform_specific_config(self): return { @@ -50,16 +50,16 @@ class MemoryCoreLoopbackTest(Elaboratable): def elaborate(self, platform): m = Module() - m.submodules["manta"] = self.m + m.submodules.manta = self.manta uart_pins = platform.request("uart") m.d.comb += [ - self.m.mem_core.user_addr.eq(self.m.io_core.addr), - self.m.mem_core.user_data.eq(self.m.io_core.data), - self.m.mem_core.user_we.eq(self.m.io_core.we), - self.m.interface.rx.eq(uart_pins.rx.i), - uart_pins.tx.o.eq(self.m.interface.tx), + self.manta.mem_core.user_addr.eq(self.manta.io_core.addr), + self.manta.mem_core.user_data.eq(self.manta.io_core.data), + self.manta.mem_core.user_we.eq(self.manta.io_core.we), + self.manta.interface.rx.eq(uart_pins.rx.i), + uart_pins.tx.o.eq(self.manta.interface.tx), ] return m @@ -68,14 +68,14 @@ class MemoryCoreLoopbackTest(Elaboratable): self.platform.build(self, do_program=True) def write_user_side(self, addr, data): - self.m.io_core.set_probe("we", 0) - self.m.io_core.set_probe("addr", addr) - self.m.io_core.set_probe("data", data) - self.m.io_core.set_probe("we", 1) - self.m.io_core.set_probe("we", 0) + self.manta.io_core.set_probe("we", 0) + self.manta.io_core.set_probe("addr", addr) + self.manta.io_core.set_probe("data", data) + self.manta.io_core.set_probe("we", 1) + self.manta.io_core.set_probe("we", 0) def verify_register(self, addr, expected_data): - data = self.m.mem_core.read_from_user_addr(addr) + data = self.manta.mem_core.read_from_user_addr(addr) if data != expected_data: raise ValueError(