diff --git a/magma/simulator/__init__.py b/magma/simulator/__init__.py deleted file mode 100644 index 79cd17e51..000000000 --- a/magma/simulator/__init__.py +++ /dev/null @@ -1,2 +0,0 @@ -import magma.simulator.mdb -from .python_simulator import PythonSimulator diff --git a/magma/simulator/coreir_simulator.py b/magma/simulator/coreir_simulator.py deleted file mode 100644 index af08233c2..000000000 --- a/magma/simulator/coreir_simulator.py +++ /dev/null @@ -1,299 +0,0 @@ -import os -from tempfile import NamedTemporaryFile - -from .simulator import CircuitSimulator, ExecutionState -from magma.backend.coreir import coreir_backend, coreir_utils -from ..frontend.coreir_ import GetMagmaContext -from ..scope import Scope -from ..ref import DefnRef, ArrayRef, TupleRef -from ..array import Array -from ..tuple import Tuple -from ..bit import Bit -from ..bitutils import int2seq -from ..clock import Clock -from ..transforms import flatten -from ..circuit import CircuitType -from ..uniquification import uniquification_pass, UniquificationMode -from ..passes.clock import WireClockPass - -import coreir - -__all__ = ['CoreIRSimulator'] - -def is_defn_bit(bit): - name = bit.name - if isinstance(name, ArrayRef): - name = name.array.name - - return isinstance(name, DefnRef) - -def convert_to_coreir_path(bit, scope): - insts = [] - - # Handle bits attached to nested definitions - if scope.inst is not None and is_defn_bit(bit): - defn_bit = bit - cur_inst = scope.inst - scope = scope.parent - if isinstance(defn_bit.name, ArrayRef): - bit = cur_inst.interface[defn_bit.name.array.name.name] - bit = bit[defn_bit.name.index] - else: - bit = cur_inst.interface[defn_bit.name.name] - - # Build instance path to this bit - while scope.inst is not None: - assert(isinstance(scope.inst, CircuitType)) - inst_name = scope.inst.name - insts.insert(0, inst_name) - scope = scope.parent - - last_component = coreir_utils.magma_port_to_coreir_port(bit) - last_inst, port = last_component.split('.', 1) - insts.append(last_inst) - - # Handle renaming due to flatten types - def flattened_name(name): - if isinstance(name, DefnRef): - return str(name) - if isinstance(name, ArrayRef): - array_name = flattened_name(name.array.name) - # CoreIR simulator doesn't flatten array of bits - if issubclass(name.array.T, Bit): - return f"{array_name}.{name.index}" - else: - return f"{array_name}_{name.index}" - if isinstance(name, TupleRef): - tuple_name = flattened_name(name.tuple.name) - index = name.index - try: - int(index) - # If it's an int, insert `_` prefix because coreir doesn't - # allow fields to start with an int - index = f"_{index}" - except ValueError: - pass - return f"{tuple_name}_{index}" - raise NotImplementedError(name, type(name)) - port = flattened_name(bit.name) - - ports = [port] - - return insts, ports - -# This exists because things like clocks and setting values doesn't have the new API -# so convert from what the new API expects to what the old API expects -def old_style_path(insts, ports): - last_inst = insts[-1] - return insts[:-1] + [last_inst + '.' + ports[0]] - -class WatchPoint: - idx = 0 - def __init__(self, bit, scope, simulator, value): - self.bit = bit - self.scope = scope - self.simulator = simulator - self.value = value - self.old_val = self.simulator.get_value(self.bit, self.scope) - - WatchPoint.idx += 1 - self.idx = WatchPoint.idx - - def was_triggered(self): - new_val = self.simulator.get_value(self.bit, self.scope) - triggered = new_val != self.old_val - if self.value: - if self.value != new_val: - triggered = False - self.old_val = new_val - - return triggered - -class CoreIRSimulator(CircuitSimulator): - def __get_cur_cycles(self): - instpath, port_selects = convert_to_coreir_path(self.clock, Scope()) - steps = self.simulator_state.get_clock_cycles(old_style_path(instpath, port_selects)) - return steps - - def __get_clock_value(self): - if self.clock is None: - return None - return self.get_value(self.clock, Scope()) - - def __get_triggered_points(self): - triggered = [] - for watch in self.watchpoints: - if watch.was_triggered(): - triggered.append(watch) - - return triggered - - def __init__(self, circuit, clock, coreir_filename=None, context=None, - namespaces=["global"], opts={}): - uniquification_mode_str = opts.get("uniquify", "UNIQUIFY") - uniquification_mode = getattr(UniquificationMode, - uniquification_mode_str, None) - if uniquification_mode is None: - raise ValueError(f"Invalid uniquification mode " - f"{uniquification_mode_str}") - uniquification_pass(circuit, uniquification_mode) - self.watchpoints = [] - self.default_scope = Scope() - - need_cleanup = False - if not coreir_filename: - coreir_file = NamedTemporaryFile(delete=False, suffix='.json') - coreir_file.close() - coreir_filename = coreir_file.name - need_cleanup = True - - self.clock = clock - WireClockPass(circuit).run() - - if context is None: - self.ctx = GetMagmaContext() - else: - self.ctx = context - output = dict() - coreir_backend.compile(circuit, coreir_filename, context=self.ctx, output=output) - - # Initialize interpreter, get handle back to interpreter state - self.ctx.get_lib("commonlib") - self.ctx.enable_symbol_table() - coreir_circuit = output["coreir_module"] - self.ctx.run_passes(["rungenerators", "wireclocks-clk", "verifyconnectivity --noclkrst", - "flattentypes", "flatten", "verifyconnectivity --noclkrst", "deletedeadinstances"], - namespaces=namespaces) - self.simulator_state = coreir.SimulatorState.make(coreir_circuit) - - if need_cleanup: - os.remove(coreir_filename) - - def create_zeros_init(arrOrTuple): - if isinstance(arrOrTuple, Array): - return [create_zeros_init(el) for el in arrOrTuple.ts] - elif isinstance(arrOrTuple, Tuple): - return {k: create_zeros_init(v) for k,v in zip(arrOrTuple.keys(), arrOrTuple.values())} - else: - return 0 - - # Need to set values for all circuit inputs or interpreter crashes - for topin in circuit.interface.outputs(): - if not isinstance(topin, Clock): - arr = topin - init = create_zeros_init(arr) - - self.set_value(topin, init, Scope()) - - if clock is not None: - insts, ports = convert_to_coreir_path(clock, Scope()) - self.simulator_state.set_main_clock(old_style_path(insts, ports)) - - self.simulator_state.reset_circuit() - - for topin in circuit.interface.outputs(): - if isinstance(topin, Clock): - insts, ports = convert_to_coreir_path(topin, Scope()) - self.simulator_state.set_clock_value(old_style_path(insts, ports), True, False) - - self.evaluate() - - def get_capabilities(self): - # TBD - pass - - def get_value(self, bit, scope=None): - if scope is None: - scope = self.default_scope - if bit.const(): - return True if bit == VCC else False - - # Symbol table doesn't support arrays of arrays - if isinstance(bit, Array) and (isinstance(bit[0], Array) or isinstance(bit[0], Tuple)): - r = [] - for arr in bit: - r.append(self.get_value(arr, scope)) - return r - elif isinstance(bit, Tuple): - r = {} - for k,v in zip(bit.keys(), bit.values()): - r[k] = self.get_value(v, scope) - return r - else: - insts, ports = convert_to_coreir_path(bit, scope) - - bools = self.simulator_state.get_value(insts, ports) - if len(bools) == 1: - return bools[0] - return bools - - def set_value(self, bit, newval, scope=None): - if scope is None: - scope = self.default_scope - if isinstance(bit, Array) and len(newval) != len(bit): - raise ValueError(f"Excepted a value of lengh {len(bit)} not" - f" {len(newval)}") - if isinstance(bit, Array) and (isinstance(bit[0], Array) or isinstance(bit[0], Tuple)): - for i, arr in enumerate(bit): - self.set_value(arr, newval[i], scope) - elif isinstance(bit, Tuple): - for k,v in zip(bit.keys(), bit.values()): - self.set_value(v, newval[k], scope) - else: - insts, ports = convert_to_coreir_path(bit, scope) - self.simulator_state.set_value(old_style_path(insts, ports), newval) - - def evaluate(self, no_update=False): - clkvalue = self.__get_clock_value() - if clkvalue is not None: - insts, ports = convert_to_coreir_path(self.clock, Scope()) - self.simulator_state.set_clock_value(old_style_path(insts, ports), False, False) - self.simulator_state.execute() - if clkvalue is not None: - self.simulator_state.set_clock_value(old_style_path(insts, ports), not clkvalue, clkvalue) - - return ExecutionState(triggered_points=self.__get_triggered_points(), clock=clkvalue, cycles=0) - - def advance(self, halfcycles=1): - cycles = self.__get_cur_cycles() - # TODO add a function to interpreter to avoid doing this for loop in python - watchpoints = [] - for i in range(0, halfcycles): - self.simulator_state.run_half_cycle() - watchpoints = self.__get_triggered_points() - if len(watchpoints) > 0: - break - - post_cycles = self.__get_cur_cycles() - return ExecutionState(triggered_points=watchpoints, clock=self.__get_clock_value(), cycles=post_cycles - cycles) - - def rewind(self, halfcycles): - self.simulator_state.rewind(halfcycles) - return ExecutionState(triggered_points=self.__get_triggered_points(), clock=self.__get_clock_value(), cycles=0) - - def cont(self): - pre_cycles = self.__get_cur_cycles() - self.simulator_state.run() - post_cycles = self.__get_cur_cycles() - return ExecutionState(triggered_points=self.__get_triggered_points(), clock=self.__get_clock_value(), cycles=(post_cycles - pre_cycles)) - - def add_watchpoint(self, bit, scope, value=None): - if value is None: - raise Exception("CoreIR Simulator does not support watching for value change") - - insts, ports = convert_to_coreir_path(bit, scope) - self.simulator_state.set_watchpoint(insts, ports, value) - - self.watchpoints.append(WatchPoint(bit, scope, self, value)) - - return self.watchpoints[-1].idx - - def delete_watchpoint(self, num): - for i, w in enumerate(self.watchpoints): - if w.idx == num: - insts, ports = convert_to_coreir_path(w.bit, w.scope) - self.simulator_state.delete_watchpoint(insts, ports) - del self.watchpoints[i] - return True - - return False diff --git a/magma/simulator/mdb.py b/magma/simulator/mdb.py deleted file mode 100644 index 199c8f2b0..000000000 --- a/magma/simulator/mdb.py +++ /dev/null @@ -1,663 +0,0 @@ -from __future__ import print_function -from .python_simulator import PythonSimulator -from ..passes.debug_name import DebugNamePass -from ..is_definition import isdefinition -from ..circuit import CircuitType, EndCircuit -from ..scope import * -from ..array import Array -from ..bit import Bit -from ..bitutils import seq2int, int2seq -from ..ref import InstRef, DefnRef -from ..compatibility import builtins -from magma.waveform import waveform -from code import compile_command -import re -import sys -if sys.platform == "linux" or sys.platform == "linux2" or sys.platform == "darwin": - import readline -import cmd - -__all__ = ['simulate', 'SimulationConsole'] - -class DisplayExpr: - idx = 0 - def __init__(self, bit, string, scope): - self.object = bit - self.scope = scope - self.string = string - - DisplayExpr.idx += 1 - self.idx = DisplayExpr.idx - - def display(self, value): - print("\t{}: {} = {}".format(self.idx, self.string, value)) - -def print_err(str): - print(str, file=sys.stderr) - -def split_index(str): - r = re.compile(r"^([a-zA-Z]+)((?:\[[0-9]+\])+)$") - match = r.match(str) - if match is None: - return None - - idxr = re.compile(r"\[([0-9]+)\]") - idx_match = idxr.findall(match[2]) - - return match[1], [int(i) for i in idx_match] - -def convert_to_bools(val, bit): - if isinstance(val, int): - return int2seq(val, len(bit)) - elif isinstance(val, bool): - return val - elif isinstance(val, list): - newval = [] - for i,v in enumerate(val): - newval.append(convert_to_bools(v, bit[i])) - return newval - -def describe_instance(inst): - desc_str = type(inst).__name__ + ": " - if inst.decl is not None: - desc_str += inst.decl.varname + " @ " + inst.decl.filename + ":" + str(inst.decl.lineno) - - desc_str += " (" + inst.name + ")" - return desc_str - -def describe_interface(interface): - print("\nInterface Inputs:") - for name, bit in interface.ports.items(): - if bit.is_output(): - if isinstance(bit, Array): - print(" Bit[" + str(len(bit)) + "]:" + name) - else: - print(" Bit: " + name) - - print("\nInterface Outputs:") - for name, bit in interface.ports.items(): - if bit.is_input(): - if isinstance(bit, Array): - print(" Bit[" + str(len(bit)) + "]:" + name) - else: - print(" Bit: " + name) - - print("") - -def get_bit_full_name(bit): - name = bit.name - if isinstance(name, InstRef): - return name.inst.name + "." + name.name - elif isinstance(name, DefnRef): - return str(name.defn) + '.' + name.name - elif isinstance(name, ArrayRef): - arrayname = get_bit_full_name(name.array) - return arrayname + "[" + str(name.index) + "]" - else: - return "" - -def format_val(val, bit, raw): - # Is an array of arrays? - if isinstance(val, list) and len(val) > 0 and isinstance(val[0], list): - s = '[' - for i, v in enumerate(val): - s += str(format_val(v, bit[i], raw)) - if i < len(val) - 1: - s += ", " - s += ']' - return s - else: - if raw: - return "".join(['1' if e else '0' for e in reversed(val)]) - else: - if not isinstance(bit, Array) or isinstance(val, bool): - val = [val] - return seq2int(val) - -class SimulationConsoleException(Exception): - pass - -class SimulationConsole(cmd.Cmd): - def __init__(self, circuit, simulator): - cmd.Cmd.__init__(self, completekey=None) - - self.scope = Scope() - self.top_circuit = circuit - self.simulator = simulator - self.vars = {} - self.update_vars() - - self.display_exprs = [] - - self.cycles = 0 - self.clock_high = False - - self.aliases = { 'x' : self.do_examine, - 'd' : self.do_descend, - 'rn' : self.do_reverse_cycle, - 'rs' : self.do_reverse_step } - - self.update_prompt() - - def print_watchpoints(self, points): - print("Watchpoint hit:") - for watchpoint in points: - print(" " + get_bit_full_name(watchpoint.bit) + ": ", end='') - self.log_val(watchpoint.bit, watchpoint.scope) - - def update_prompt(self): - self.prompt = str(self.cycles) + ': ' + self.scope.value() + ' >>> ' - - def default(self, line): - if line == 'EOF': - print() - return True - - cmd, arg, line = self.parseline(line) - if cmd in self.aliases: - func = [self.aliases[cmd]] - else: - func = [getattr(self, n) for n in self.get_names() if n.startswith('do_' + cmd)] - - if len(func) == 1: - return func[0](arg) - elif len(func) > 1: - print_err("Ambiguous command") - else: - self.console_evaluate(line) - - def precmd(self, line): - self.advance_clock = False - self.reeval = False - self.skip_half = False - self.skip_next = 0 - self.stepping = True - self.reversing = False - - return line - - def reverse_simulator(self): - if self.clock_high and self.cycles == 0: return - - reversecount = self.skip_next - if self.skip_half: - reversecount *= 2 - if not self.clock_high: - reversecount -= 1 - - for i in range(reversecount): - state = self.simulator.rewind(1) - self.clock_high = state.clock - if self.clock_high: - self.cycles -= 1 - - if state.triggered_points: - self.print_watchpoints(state.triggered_points) - return False - - def step_simulator(self): - n = self.skip_next - if self.skip_half: - n *= 2 - if self.clock_high: - n -= 1 - - state = self.simulator.advance(n) - self.clock_high = state.clock - self.cycles += state.cycles - if state.triggered_points: - self.print_watchpoints(state.triggered_points) - - def continue_simulator(self): - state = self.simulator.cont() - self.print_watchpoints(state.triggered_points) - self.clock_high = state.clock - self.cycles += state.cycles - - def postcmd(self, stop, line): - if self.reversing: - self.reverse_simulator() - - elif self.advance_clock: - if self.stepping: - self.step_simulator() - else: - self.continue_simulator() - - if self.reeval: - self.simulator.evaluate(True) - - self.update_prompt() - - for e in self.display_exprs: - e.display(self.get_formatted_val(e.object, e.scope)) - - return stop - - def get_formatted_val(self, bit, scope, raw=False): - val = self.simulator.get_value(bit, scope) - if val is None: - return "Doesn't exist" - - return format_val(val, bit, raw) - - def log_val(self, bit, scope, raw=False): - print(self.get_formatted_val(bit, scope, raw)) - - def update_vars(self): - self.vars.clear() - self.vars['top'] = self.top_circuit - - if self.scope.inst is None: - self.vars['self'] = self.top_circuit - else: - self.vars['self'] = type(self.scope.inst) - - instances = self.vars['self'].instances - for inst in instances: - self.vars[inst.name] = inst - if inst.decl is not None: - self.vars[inst.decl.varname] = inst - - def console_evaluate(self, line): - buf = line - while True: - try: - code = compile_command(buf) - except Exception as e: - print_err("Invalid python: {}".format(e)) - return - - if code is None: - buf += '\n' + builtins.input("."*(len(self.prompt) - 1) + " ") - else: - break - - try: - exec(code, None, self.vars) - except Exception as e: - print_err("Failed to execute: {}".format(e)) - - - def parse_circuit(self, name): - components = name.split('.') - if len(components) < 1: - raise SimulationConsoleException("Need at least instance name") - - topname = components.pop(0) - cur = eval(topname, None, self.vars) - - scope = Scope() if cur == self.top_circuit else self.scope - - for idx, comp_name in enumerate(components): - defn = type(cur) if isinstance(cur, CircuitType) else cur - index_match = split_index(comp_name) - bit_idx = None - if index_match is not None: - comp_name = index_match[0] - bit_idx = index_match[1] - - # Last iteration, check for bit first - if idx == len(components) - 1 and comp_name in cur.interface.ports: - if bit_idx is None: - return cur.interface.ports[comp_name], scope - else: - port = cur.interface.ports[comp_name] - for i in bit_idx: - port = port[i] - return port, scope - - found = False - for inst in defn.instances: - if inst.name == comp_name or (inst.decl is not None and inst.decl.varname == comp_name): - # Descend into previous instance's scope - if cur != self.top_circuit: - scope = Scope(parent=scope, instance=cur) - - cur = inst - found = True - break - - if not found: - raise SimulationConsoleException("Invalid name component '{}'".format(comp_name)) - - return cur, scope - - def safe_parse_inst(self, name): - inst, scope = self.parse_circuit(name) - if not isinstance(inst, CircuitType): - raise SimulationConsoleException("not an instance") - - return inst - - def parse_next(self, num): - self.advance_clock = True - self.stepping = True - - if num: - try: - self.skip_next = int(num) - except: - print_err("Please provide an integer") - self.skip_next = 0 - - else: - self.skip_next = 1 - - def parse_print(self, arg, raw): - if not arg: - print_err('Please provide an argument') - return - - try: - printme, scope = self.parse_circuit(arg) - except Exception as e: - print_err("Failed to print: {}".format(e)) - return - - if isinstance(printme, Bit) or isinstance(printme, Array): - self.log_val(printme, scope, raw) - elif isinstance(printme, CircuitType): - inst_desc = describe_instance(printme) + ": " - print(inst_desc) - for name, bit in printme.interface.ports.items(): - print(" " + name + ": ", end='') - self.log_val(bit, scope, raw) - else: - print_err("Can only print Bits and circuit instances") - - def do_quit(self, arg): - 'quit: Exit the simulator' - return True - - def do_next(self, arg): - 'next [N]: Advance the clock for N cycles. N defaults to 1 if not provided.' - self.skip_half = True - self.parse_next(arg) - - def do_step(self, arg): - 'step [N]: Toggle the clock N times. N defaults to 1 if not provided.' - self.skip_half = False - self.parse_next(arg) - - def do_reverse_step(self, arg): - 'reverse_step N: rewinds the circuit N half cycles' - self.reversing = True - self.skip_half = False - self.parse_next(arg) - - def do_reverse_cycle(self, arg): - 'reverse_cycle N: rewinds the circuit N cycles' - self.reversing = True - self.skip_half = True - self.parse_next(arg) - - def do_examine(self, arg): - 'examine BIT: prints the current value of BIT as an array of booleans. Shortcut: x BIT.' - self.parse_print(arg, True) - - def do_print(self, arg): - 'print BIT: prints the current value of BIT interpreted as an unsigned integer.' - self.parse_print(arg, False) - - def do_watch(self, arg): - 'watch BIT [VALUE]: sets a watchpoint on BIT.\nThe simulator will interrupt and return to the console when BIT changes value.\nIf the optional argument VALUE is passed in, the simulator will interrupt only when BIT is equal to VALUE.' - if not arg: - print_err('Provide a bit to watch') - return - - args = arg.split() - bitname = args[0] - - try: - watchme, scope = self.parse_circuit(bitname) - except Exception as e: - print_err("Failed to watch: {}".format(e)) - return - - if len(args) == 2: - try: - value = eval(args[1], None, self.vars) - if isinstance(value, int): - value = [bool(i) for i in int2seq(value, len(watchme))] - - if not isinstance(value, list) or not isinstance(value[0], bool): - raise SimulationConsoleException("Invalid watch value") - except Exception as e: - print_err("Cannot watch for value {}: {}".format(args[1], e)) - return - else: - value = None - - if not isinstance(watchme, Bit) and not isinstance(watchme, Array): - print_err("Can only watch bits or arrays") - - watch_num = self.simulator.add_watchpoint(watchme, scope, value) - print('Watchpoint {} on {}'.format(watch_num, arg)) - - def do_delete(self, arg): - 'delete N: deletes watchpoint N.' - if not arg: - print_err('Please provide a watchpoint number') - return - - try: - watch_num = int(arg) - except: - print_err("delete requires an integer") - return - - found = self.simulator.delete_watchpoint(watch_num) - if not found: - print_err('No watchpoint number {}'.format(watch_num)) - - def do_display(self, arg): - 'display BIT: repeatedly prints the value of BIT each time the simulator stops.' - - if not arg: - print_err('Provide an expression to display') - return - - try: - bit, scope = self.parse_circuit(arg) - if not isinstance(bit, Bit) and not isinstance(bit, Array): - raise SimulationConsoleException("Can only display bits or arrays") - - display_expr = DisplayExpr(bit, arg, scope) - except Exception as e: - print_err("Invalid argument to display: {}".format(e)) - return - - self.display_exprs.append(display_expr) - - def do_undisplay(self, arg): - 'undisplay N: stops displaying the bit at index N.' - if not arg: - print_err('Provide an index to stop displaying') - return - - try: - idx = int(arg) - except: - print_err("undisplay requires an integer") - return - - for i,e in enumerate(self.display_exprs): - if e.idx == idx: - del self.display_exprs[i] - return - print_err('No display number {}'.format(idx)) - - def do_up(self, arg): - "up: Change to the parent circuit's scope." - if self.scope.parent is not None: - self.scope = self.scope.parent - self.update_vars() - else: - print_err("Cannot go up") - - def do_descend(self, arg): - "descend INSTANCE: update the current scope to be inside INSTANCE." - try: - inst, scope = self.parse_circuit(arg) - - if not isdefinition(type(inst)): - print_err("Cannot descend into primitives") - return - except Exception as e: - print_err("Cannot switch scope to '{}': {}".format(arg, e)) - return - - if isinstance(inst, CircuitType): - self.scope = Scope(parent=scope, instance=inst) - self.update_vars() - elif inst == self.top_circuit: - self.scope = Scope() - self.update_vars() - else: - print_err("You must provide an instance to descend into") - - def do_info(self, arg): - """info instances|interface|watchpoints: - instances [INSTANCE]: Display all the instances in the current scope or in INSTANCE if provided - interface [INSTANCE]: Display the interface bits of the current scope's circuit or in INSTANE if provided - watchpoints: Display currently active watchpoints""" - args = arg.split() - action = args[0] - instname = args[1] if len(args) == 2 else None - if action == 'instances': - defn = self.vars['self'] - if instname: - try: - inst = self.safe_parse_inst(instname) - except Exception as e: - print_err("Cannot get info on '{}': {}".format(instname, e)) - return - defn = type(inst) - - if not isdefinition(defn): - print_err("Cannot get instances in '{}' because it is a primitive".format(instname)) - return - - print("") - for inst in defn.instances: - desc_str = " " + describe_instance(inst) - print(desc_str) - print("") - - elif action == 'interface': - defn = self.vars['self'] - if instname: - try: - inst = self.safe_parse_inst(instname) - except Exception as e: - print_err("Cannot get info on '{}': {}".format(instname, e)) - return - defn = type(inst) - - describe_interface(defn.interface) - elif arg == 'watchpoints': - print("TODO") - else: - print_err("I don't know how to give you info on that") - - def do_continue(self, arg): - "continue: continue cycling the simulator's clock and evaluating until a watchpoint is hit." - self.advance_clock = True - self.stepping = False - - def do_location(self, arg): - "location: Print the trace of parent scopes of the current scope." - scopes = [] - curscope = self.scope - while curscope is not None: - scopes.insert(0, curscope) - curscope = curscope.parent - - print("Scope stack: ") - for s in scopes: - print(" " + s.value()) - - def do_assign(self, arg): - "assign BIT NEWVAL: sets BIT to NEWVAL. BIT must be an input to the top level circuit." - if arg is None: - print_err('Provide a top level input to change') - return - - args = arg.split(' ', 1) - - try: - bit = eval(args[0], None, self.vars) - except Exception as e: - print_err("Invalid bit for assignment: {}".format(e)) - return - - if bit not in self.top_circuit.interface.outputs(): - print_err("Can only assign values to inputs in the top level circuit") - return - - try: - newval = eval(args[1], None, self.vars) - except Exception as e: - print_err("Invalid new value".format(e)) - return - - newval = convert_to_bools(newval, bit) - - self.simulator.set_value(bit, newval, self.scope) - self.reeval = True - - def do_waveform(self, arg): - if not arg: - print_err('Please a provide wire') - return - - try: - waveme, scope = self.parse_circuit(arg) - except Exception as e: - print_err("Invalid argument for waveform: {}".format(e)) - return - - if not isinstance(waveme, Bit) and not isinstance(waveme, Array): - print_err("Can only provide waveforms for wires") - return - - labels = [arg] - signals = [] - - for i in range(self.cycles - 1): - val = self.simulator.get_value(waveme, scope) - signals.insert(0, [seq2int(val)]) - self.simulator.rewind(2) - - for i in range(self.cycles - 1): - self.simulator.step() - self.simulator.step() - - waveform(signals, labels) - - def run(self): - self.simulator.evaluate() - - print('Magma Interactive Simulator. Type help or ? to list commands.') - while True: - try: - self.cmdloop() - break; - except KeyboardInterrupt: - print_err('\nKeyboardInterrupt') - - # For test infra - def runcmd(self, line): - line = self.precmd(line) - stop = self.onecmd(line) - self.postcmd(stop, line) - -def simulate(main, simulator_type=PythonSimulator): - EndCircuit() - simulator = simulator_type(main, main.CLK) - - DebugNamePass(main).run() - - console = SimulationConsole(main, simulator) - console.run() diff --git a/magma/simulator/python_simulator.py b/magma/simulator/python_simulator.py deleted file mode 100644 index b4a165be6..000000000 --- a/magma/simulator/python_simulator.py +++ /dev/null @@ -1,405 +0,0 @@ -import sys -from abc import abstractmethod -if sys.version_info < (3, 4): - import abc - ABC = abc.ABCMeta('ABC', (object,), {}) -else: - from abc import ABC -from collections import namedtuple -from itertools import product -from .simulator import CircuitSimulator, ExecutionState -from ..transforms import flatten -from ..circuit import * -from ..scope import * -from ..bit import Bit, Digital -from ..array import Array -from ..tuple import Tuple -from ..bits import SInt, Bits, UInt -from hwtypes import BitVector -import hwtypes -from ..bitutils import seq2int -from ..clock import Clock -from ..passes.clock import WireClockPass - -__all__ = ['PythonSimulator'] - -ExecutionOrder = namedtuple('ExecutionOrder', ['stateful', 'combinational']) - - -class PythonSimulatorException(Exception): - pass - - -class SimPrimitive: - def __init__(self, primitive, value_store): - if primitive.simulate is None: - raise ValueError("Cannot simulate {} of type {} because it does not have a Python simulate method".format(primitive, type(primitive))) - self.primitive = primitive - self.inputs = [] - self.outputs = [] - self.value_store = value_store - self.state_store = {} - - for bit in self.primitive.interface.ports.values(): - if not isinstance(bit, Array): - bit = [bit] - for b in bit: - if b.is_input(): - self.inputs.append(b) - else: - self.outputs.append(b) - - def stateful(self): - return self.primitive.stateful - - def inputs_satisfied(self): - for i in self.inputs: - if not self.value_store.value_initialized(i): - return False - - return True - - def initialize_outputs(self): - # Initializes all outputs to False, should perhaps - # initialize based on starting inputs? - for o in self.outputs: - self.value_store.set_value(o, False) - - def simulate(self): - self.primitive.simulate(self.value_store, self.state_store) - -class WatchPoint: - idx = 0 - def __init__(self, bit, scope, simulator, value): - self.bit = bit - self.scope = scope - self.simulator = simulator - self.value = value - self.old_val = self.simulator.get_value(self.bit, self.scope) - - WatchPoint.idx += 1 - self.idx = WatchPoint.idx - - def was_triggered(self): - new_val = self.simulator.get_value(self.bit, self.scope) - triggered = new_val != self.old_val - if self.value: - if self.value != new_val: - triggered = False - self.old_val = new_val - - return triggered - -class ValueStore: - def __init__(self): - self.value_map = {} - - def value_initialized(self, bit): - if isinstance(bit, (Array, Tuple)): - for b in bit: - if not self.value_initialized(b): - return False - - return True - - if bit.is_input(): - bit = bit.value() - - if bit.const(): - return True - - return bit in self.value_map - - def get_value(self, bit): - if isinstance(bit, Array): - value = [self.get_value(b) for b in bit] - if isinstance(bit, SInt): - return BitVector[len(bit)](value).as_sint() - elif isinstance(bit, UInt): - return BitVector[len(bit)](value).as_uint() - elif isinstance(bit, Bits): - return BitVector[len(bit)](value) - return value - - if bit.is_input(): - bit = bit.value() - - if bit.const(): - return bool(bit) - - return self.value_map[bit] - - def set_value(self, bit, newval): - if not bit.is_output(): - raise TypeError("Can only call set value on an input") - - if isinstance(bit, Array): - if isinstance(newval, BitVector): - newval = newval.as_bool_list() - elif isinstance(newval, Bits): - if not newval.const(): - raise ValueError("Calling set_value with a Bits only works with a constant") - newval = newval.bits() - elif isinstance(bit, Bits) and isinstance(newval, int): - if not isinstance(bit, SInt) and newval < 0: - raise ValueError(f"Can only set {bit} of type {type(bit)} with positive integer, not {newval}") - newval = BitVector[len(bit)](newval).as_bool_list() - elif not isinstance(newval, list): - raise TypeError(f"Calling set_value with {bit} of type {type(bit)} only works with a list of values or a BitVector") - - for b,v in zip(bit, newval): - self.set_value(b, v) - return - - if isinstance(newval, int) and newval in {0, 1}: - newval = bool(newval) - if isinstance(newval, hwtypes.Bit): - newval = bool(newval) - if not isinstance(newval, bool): - raise TypeError(f"Can only set Bit {bit} with a boolean value or 0 or 1, not {newval} (type={type(newval)})") - - self.value_map[bit] = newval - -class PythonSimulator(CircuitSimulator): - def __setup_primitives(self): - wrapped = [] - for primitive in self.circuit.instances: - wrapped.append(SimPrimitive(primitive, self.value_store)) - - return wrapped - - def initialize(self, bit): - if isinstance(bit, (Array, Tuple)): - for b in bit: - self.initialize(b) - else: - if bit.is_output(): - self.circuit_inputs.append(bit) - self.value_store.set_value(bit, False) - else: - self.circuit_outputs.append(bit) - - def __setup_circuit(self, clock): - if clock is not None: - clock = self.txfm.get_new_bit(clock, self.default_scope) - self.clock = clock - - self.circuit_inputs = [] - self.circuit_outputs = [] - for name, bit in self.circuit.interface.ports.items(): - self.initialize(bit) - - def __outputs_initialized(self): - for bit in self.circuit_outputs: - assert bit.is_input() - if not self.value_store.value_initialized(bit): - return False - - return True - - def __sort_state_primitives(self, state_primitives): - """ - State primitives should be sorted in reversed topological order. - This ensures that the simulation order of the stateful elements - is correct. - Intuition: - If the output value of a state element `x` feeds into the input of - another state element `y`, - `y` should perform it's simulation before `x` because it will use - the value of the signal on the previous clock cycle. - """ - sorted_state_primitives = [] - for primitive_1 in state_primitives: - inserted = False - for index, primitive_2 in enumerate(sorted_state_primitives): - for output in primitive_1.inputs: - if any(output.value() is x for x in primitive_2.inputs): - sorted_state_primitives.insert(index, primitive_1) - inserted = True - break - if inserted: - break - if not inserted: - sorted_state_primitives.append(primitive_1) - sorted_state_primitives.reverse() - return sorted_state_primitives - - def __get_ordered_primitives(self, unordered_primitives): - state_primitives = [] - after_state = [] - - state_primitives = [] - for primitive in unordered_primitives: - if primitive.stateful(): - primitive.initialize_outputs() - state_primitives.append(primitive) - - sorted_state_primitives = self.__sort_state_primitives(state_primitives) - - unordered_primitives[:] = [u for u in unordered_primitives if not u.stateful()] - - combinational = [] - while len(unordered_primitives) > 0: - found = False - for primitive in unordered_primitives: - if primitive.inputs_satisfied(): - primitive.initialize_outputs() - combinational.append(primitive) - unordered_primitives.remove(primitive) - found = True - break - assert found, "Some circuits have unsatisfied inputs" - - return ExecutionOrder(stateful=sorted_state_primitives, combinational=combinational) - - def __step(self): - if self.clock is None: - raise PythonSimulatorException("Cannot step a simulated circuit " - "without a clock, did you pass a clock during " - "initialization?") - cur_clock_val = self.value_store.get_value(self.clock) - self.value_store.set_value(self.clock, not cur_clock_val) - - def __init__(self, main_circuit, clock=None): - if isinstance(main_circuit, CircuitType): - raise ValueError("PythonSimulator must be called with a Circuit definition, not an instance") - if clock is not None and not isinstance(clock, Clock): - raise ValueError("clock must be a Clock or None") - WireClockPass(main_circuit).run() - self.main_circuit = main_circuit - self.txfm = flatten(main_circuit) - self.circuit = self.txfm.circuit - self.value_store = ValueStore() - self.default_scope = Scope() - self.__setup_circuit(clock) - self.watchpoints = [] - - primitives = self.__setup_primitives() - - self.execution_order = self.__get_ordered_primitives(primitives) - - assert self.__outputs_initialized(), "All circuit outputs not initialized." - - def get_capabilities(self): - return [] - - def get_value(self, bit, scope=None): - if scope is None: - scope = self.default_scope - newbit = self.txfm.get_new_bit(bit, scope) - if newbit is None: - return None - - try: - return self.value_store.get_value(newbit) - except KeyError: - return None - - def set_value(self, bit, newval, scope=None): - if scope is None: - scope = self.default_scope - newbit = self.txfm.get_new_bit(bit, scope) - if not self.is_circuit_input(newbit): - message = "Only setting main's inputs is supported (Trying to set: {})".format(bit) - raise PythonSimulatorException(message) - else: - self.value_store.set_value(newbit, newval) - - def is_circuit_input(self, value): - """ - Checks if `value` is in `self.circuit_inputs`. - If `value` is an `Array`, it recursively checks the elements - """ - if isinstance(value, Digital): - return any(value is x for x in self.circuit_inputs) - elif isinstance(value, Array): - return all(self.is_circuit_input(elem) for elem in value) - else: - raise NotImplementedError(type(value)) - - def advance(self, n=1): - cycles = 0 - for i in range(0, n): - self.__step() - state = self.evaluate() - - if not state.clock: - cycles += 1 - if state.triggered_points: - return ExecutionState(triggered_points=state.triggered_points, clock=state.clock, cycles=cycles) - - return ExecutionState(triggered_points=[], clock=self.get_clock_value(), cycles=cycles) - - def evaluate(self, no_update=False): - for primitive in self.execution_order.stateful: - primitive.simulate() - for primitive in self.execution_order.combinational: - primitive.simulate() - - triggered = [] - for watch in self.watchpoints: - if watch.was_triggered(): - triggered.append(watch) - - return ExecutionState(triggered_points=triggered, clock=self.get_clock_value(), cycles=0) - - def get_clock_value(self): - """ - Looks up the value of `self.clock` in `self.value_store` - Returns None if self.clock is None (circuit doesn't have a clock) - """ - if self.clock is not None: - return self.value_store.get_value(self.clock) - return None - - def rewind(self, halfcycles): - raise PythonSimulatorException("Reversing not currently supported") - - def cont(self): - cycles = 0 - while True: - self.__step() - state = self.evaluate() - if not state.clock: - cycles += 1 - - if state.triggered_points: - return ExecutionState(triggered_points=state.triggered_points, clock=state.clock, cycles=cycles) - - def add_watchpoint(self, bit, scope, value=None): - self.watchpoints.append(WatchPoint(bit, scope, self, value)) - return self.watchpoints[-1].idx - - def delete_watchpoint(self, num): - for w in self.watchpoints: - if w.idx == num: - del w - return True - - return False - - def __call__(self, *largs): - circuit = self.main_circuit - - j = 0 - for name, port in circuit.interface.ports.items(): - if port.is_output(): - val = largs[j] - if isinstance(port, Array): - n = type(port).N - val = BitVector[n](val) - self.set_value(getattr(circuit, name), val) - j += 1 - - self.evaluate() - - outs = [] - for name, port in circuit.interface.ports.items(): - if port.is_input(): - val = self.get_value(getattr(circuit, name)) - val = seq2int(val) if isinstance(val, list) else int(val) - outs.append(val) - - if len(outs) == 1: - return outs[0] - return tuple(outs) diff --git a/magma/simulator/simulator.py b/magma/simulator/simulator.py deleted file mode 100644 index b166f733d..000000000 --- a/magma/simulator/simulator.py +++ /dev/null @@ -1,58 +0,0 @@ -import sys -from abc import abstractmethod -from collections import namedtuple -if sys.version_info < (3, 4): - import abc - ABC = abc.ABCMeta('ABC', (object,), {}) -else: - from abc import ABC - -ExecutionState = namedtuple('ExecutionState', ['cycles', 'clock', 'triggered_points']) - -class CircuitSimulator(ABC): - @abstractmethod - def __init__(self, circuit, clock): - pass - - @abstractmethod - def get_capabilities(self): - pass - - @abstractmethod - def get_value(self, bit, scope): - pass - - @abstractmethod - def set_value(self, bit, scope, newval): - pass - - @abstractmethod - def advance(self, halfcycles): - pass - - def advance_cycle(self, cycles=1): - self.advance(cycles * 2) - - @abstractmethod - def evaluate(self_): - pass - - @abstractmethod - def rewind(self, halfcycles): - pass - - def rewind_cycle(self, cycles=1): - self.rewind(cycles * 2) - - @abstractmethod - def cont(self): - pass - - @abstractmethod - def add_watchpoint(self, bit, scope, value=None): - pass - - @abstractmethod - def delete_watchpoint(self, num): - pass - diff --git a/setup.cfg b/setup.cfg index b9ac5145d..03f272897 100644 --- a/setup.cfg +++ b/setup.cfg @@ -12,4 +12,4 @@ max-line-length = 80 ignore = E741,W503,W504 # Start with all files blacklisted from pycodestyle. -exclude = magma/port.py,magma/waveform.py,magma/transforms.py,magma/bits.py,magma/tuple.py,magma/compatibility.py,magma/frontend/coreir.py,magma/frontend/__init__.py,magma/frontend/coreir_.py,magma/util.py,magma/conversions.py,magma/clock.py,magma/interface.py,magma/bitutils.py,magma/__init__.py,magma/backend/util.py,magma/backend/__init__.py,magma/backend/firrtl.py,magma/backend/verilog.py,magma/backend/dot.py,magma/backend/blif.py,magma/ir.py,magma/wire.py,magma/testing/__init__.py,magma/testing/coroutine.py,magma/testing/utils.py,magma/testing/compile.py,magma/generator.py,magma/ssa/__init__.py,magma/ssa/ssa.py,magma/is_primitive.py,magma/simulator/__init__.py,magma/simulator/coreir_simulator.py,magma/simulator/simulator.py,magma/simulator/python_simulator.py,magma/simulator/mdb.py,magma/debug.py,magma/ast_utils.py,magma/compile.py,magma/bit.py,magma/product.py,magma/math.py,magma/braid.py,magma/enum.py,magma/backend/verilog.py,magma/operators.py,magma/syntax/util.py,magma/syntax/combinational.py,magma/syntax/__init__.py,magma/syntax/sequential.py,magma/uniquification.py,magma/is_definition.py,magma/scope.py,magma/t.py +exclude = magma/port.py,magma/waveform.py,magma/transforms.py,magma/bits.py,magma/tuple.py,magma/compatibility.py,magma/frontend/coreir.py,magma/frontend/__init__.py,magma/frontend/coreir_.py,magma/util.py,magma/conversions.py,magma/clock.py,magma/interface.py,magma/bitutils.py,magma/__init__.py,magma/backend/util.py,magma/backend/__init__.py,magma/backend/firrtl.py,magma/backend/verilog.py,magma/backend/dot.py,magma/backend/blif.py,magma/ir.py,magma/wire.py,magma/testing/__init__.py,magma/testing/coroutine.py,magma/testing/utils.py,magma/testing/compile.py,magma/generator.py,magma/ssa/__init__.py,magma/ssa/ssa.py,magma/is_primitive.py,magma/debug.py,magma/ast_utils.py,magma/compile.py,magma/bit.py,magma/product.py,magma/math.py,magma/braid.py,magma/enum.py,magma/backend/verilog.py,magma/operators.py,magma/syntax/util.py,magma/syntax/combinational.py,magma/syntax/__init__.py,magma/syntax/sequential.py,magma/uniquification.py,magma/is_definition.py,magma/scope.py,magma/t.py diff --git a/setup.py b/setup.py index ae7ff1c03..b49638f30 100644 --- a/setup.py +++ b/setup.py @@ -21,7 +21,6 @@ "magma.passes", "magma.primitives", "magma.smart", - "magma.simulator", "magma.syntax", "magma.syntax.transforms", "magma.ssa", diff --git a/tests/test_primitives/test_reduce.py b/tests/test_primitives/test_reduce.py index 406d5fa40..5d01666ca 100644 --- a/tests/test_primitives/test_reduce.py +++ b/tests/test_primitives/test_reduce.py @@ -1,13 +1,11 @@ -import os import operator - +import os import pytest +import fault + import magma as m from magma.testing import check_files_equal -from magma.simulator import PythonSimulator - -import fault @pytest.mark.parametrize('op, method', [ @@ -28,47 +26,32 @@ class test_reduce(m.Circuit): assert check_files_equal(__file__, f"build/test_reduce_{op.__name__}.v", f"gold/test_reduce_{op.__name__}.v") - sim = PythonSimulator(test_reduce) tester = fault.Tester(test_reduce) tester.circuit.I = 2 - sim.set_value(test_reduce.I, 2) tester.eval() - sim.evaluate() if op == operator.and_: tester.circuit.O0.expect(0) tester.circuit.O1.expect(0) - assert sim.get_value(test_reduce.O0) == 0 - assert sim.get_value(test_reduce.O1) == 0 else: tester.circuit.O0.expect(1) tester.circuit.O1.expect(1) - assert sim.get_value(test_reduce.O0) == 1 - assert sim.get_value(test_reduce.O1) == 1 tester.circuit.I = (1 << 5) - 1 - sim.set_value(test_reduce.I, (1 << 5) - 1) tester.eval() - sim.evaluate() tester.circuit.O0.expect(1) tester.circuit.O1.expect(1) - assert sim.get_value(test_reduce.O0) == 1 - assert sim.get_value(test_reduce.O1) == 1 tester.circuit.I = 0 - sim.set_value(test_reduce.I, 0) tester.eval() - sim.evaluate() tester.circuit.O0.expect(0) tester.circuit.O1.expect(0) - assert sim.get_value(test_reduce.O0) == 0 - assert sim.get_value(test_reduce.O1) == 0 tester.compile_and_run("verilator", skip_compile=True, directory=os.path.join(os.path.dirname(__file__), diff --git a/tests/test_simulator/__init__.py b/tests/test_simulator/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tests/test_simulator/test_counter.py b/tests/test_simulator/test_counter.py deleted file mode 100644 index b3227149f..000000000 --- a/tests/test_simulator/test_counter.py +++ /dev/null @@ -1,110 +0,0 @@ -from .test_primitives import * -from magma.simulator import PythonSimulator -from magma import * -from magma.passes.clock import drive_undriven_other_clock_types_in_inst -from magma.scope import * - -def test(): - def FFs(n): - return [PRIM_FF() for i in range(n)] - - def Register(n): - args = ["I", In(Array[n, Bit]), "O", Out(Array[n, Bit])] + ClockInterface(False, False, False) - - class RegCircuit(Circuit): - name = 'Register' + str(n) - io = m.IO(**dict(zip(args[::2], args[1::2]))) - ffs = join(FFs(n)) - wire(io.I, ffs.D) - wire(ffs.Q, io.O) - - return RegCircuit() - - def IncOne(n): - def sim_inc_one(self, value_store, state_store): - I = value_store.get_value(self.I) - n = len(I) - val = seq2int(I) + 1 - - cout = val > ((1 << n) - 1) - val = val % (1 << n) - - seq = int2seq(val, len(I)) - seq = [bool(s) for s in seq] - value_store.set_value(self.O, seq) - value_store.set_value(self.COUT, cout) - - args = ["I", In(Array[n, Bit]), "O", Out(Array[n, Bit]), "COUT", Out(Bit)] - - class _Circuit(Circuit): - name = 'IncOne' + str(n) - io = IO(**dict(zip(args[::2], args[1::2]))) - stateful = False - primitive = True - simulate = sim_inc_one - - return _Circuit() - - def TestCounter(n): - args = [] - - args += ["O", Array[n, Out(Bit)]] - args += ["COUT", Out(Bit)] - - args += ClockInterface(False, False, False) - - class Counter(m.Circuit): - name = 'Counter' + str(n) - io = m.IO(**dict(zip(args[::2], args[1::2]))) - - inc = IncOne(n) - reg = Register(n) - - wire(reg.O, inc.I) - wire(inc.O, reg.I) - wire(reg.O, io.O) - - wire(inc.COUT, io.COUT) - - drive_undriven_other_clock_types_in_inst(Counter, Counter.reg) - - return Counter() - - args = ['O', Array[5, Out(Bit)], 'COUT', Out(Bit)] - args += ClockInterface(False, False, False) - - class testcircuit(Circuit): - name = "Test" - io = IO(**dict(zip(args[::2], args[1::2]))) - counter = TestCounter(5) - wire(counter.O, io.O) - wire(counter.COUT, io.COUT) - - sim = PythonSimulator(testcircuit, testcircuit.CLK) - - for i in range((1 << 5) - 1): - sim.advance() - val = sim.get_value(testcircuit.O) - num = seq2int(val) - assert num == i - cout = sim.get_value(testcircuit.COUT) - assert not cout - - sim.advance() - - val = sim.get_value(testcircuit.O) - num = seq2int(val) - assert num == 31 - cout = sim.get_value(testcircuit.COUT) - assert cout - - - sim.advance() - sim.advance() - - val = sim.get_value(testcircuit.O) - num = seq2int(val) - assert num == 0 - - cout = sim.get_value(testcircuit.COUT) - assert not cout diff --git a/tests/test_simulator/test_error.py b/tests/test_simulator/test_error.py deleted file mode 100644 index 7b75bdbd0..000000000 --- a/tests/test_simulator/test_error.py +++ /dev/null @@ -1,22 +0,0 @@ -from magma import * -from magma.simulator import PythonSimulator - - -def test_instance(): - N = 4 - T = Bits[N] - - class Test(Circuit): - name = "Test" - io = IO(I=In(T), O=Out(T), CLK=In(Bit)) - wire(io.I, io.O) - - class _Top(Circuit): - io = IO() - test = Test() - - try: - simulator = PythonSimulator(_Top.test) - assert False, "Should raise a ValueError when passing an instance to the Python Simulator" - except ValueError as e: - pass diff --git a/tests/test_simulator/test_ff.py b/tests/test_simulator/test_ff.py deleted file mode 100644 index 03f2a4a30..000000000 --- a/tests/test_simulator/test_ff.py +++ /dev/null @@ -1,33 +0,0 @@ -from .test_primitives import PRIM_FF -import magma as m -from magma.simulator import PythonSimulator -from magma.scope import * - - -def test_sim_ff(): - class TestCircuit(m.Circuit): - io = m.IO(I=m.In(m.Bit), O=m.Out(m.Bit)) + m.ClockIO() - ff = PRIM_FF() - m.wire(io.I, ff.D) - m.wire(ff.Q, io.O) - - sim = PythonSimulator(TestCircuit, TestCircuit.CLK) - sim.evaluate() - val = sim.get_value(TestCircuit.O) - assert(val is False) - sim.advance() - val = sim.get_value(TestCircuit.O) - assert(val is False) - - sim.set_value(TestCircuit.I, True) - sim.evaluate() - val = sim.get_value(TestCircuit.O) - assert(val is False) - - sim.advance() - val = sim.get_value(TestCircuit.O) - assert(val is True) - - sim.advance() - val = sim.get_value(TestCircuit.O) - assert(val is True) diff --git a/tests/test_simulator/test_logic.py b/tests/test_simulator/test_logic.py deleted file mode 100644 index aa9985a8f..000000000 --- a/tests/test_simulator/test_logic.py +++ /dev/null @@ -1,41 +0,0 @@ -from .test_primitives import * -import magma as m -from magma.simulator import PythonSimulator -from magma.scope import * - - -def test_sim_logic(): - class TestCircuit(m.Circuit): - io = m.IO(I0=m.In(m.Bit), I1=m.In(m.Bit), O=m.Out(m.Bit)) + m.ClockIO() - andy = PRIM_AND() - ori = PRIM_OR() - ori2 = PRIM_OR() - n = PRIM_NOT() - - m.wire(io.I0, andy.I0) - m.wire(io.I1, andy.I1) - m.wire(io.I0, ori.I0) - m.wire(io.I1, n.I) - m.wire(n.O, ori.I1) - - m.wire(ori.O, ori2.I0) - m.wire(andy.O, ori2.I1) - - m.wire(ori2.O, io.O) - - sim = PythonSimulator(TestCircuit) - sim.evaluate() - v = sim.get_value(TestCircuit.O) - assert v is True - - sim.set_value(TestCircuit.I1, True) - sim.evaluate() - v = sim.get_value(TestCircuit.O) - assert v is False - - sim.set_value(TestCircuit.I0, True) - sim.evaluate() - v = sim.get_value(TestCircuit.O) - assert v == True - - diff --git a/tests/test_simulator/test_mdb.py b/tests/test_simulator/test_mdb.py deleted file mode 100644 index 55f5d2e41..000000000 --- a/tests/test_simulator/test_mdb.py +++ /dev/null @@ -1,126 +0,0 @@ -from .test_primitives import * -import magma as m -from magma.simulator import PythonSimulator -from magma.simulator.mdb import SimulationConsole -from magma import * -from magma.scope import * -from magma.passes.debug_name import DebugNamePass -from magma.passes.clock import drive_undriven_other_clock_types_in_inst - -def test(capsys): - m.config.set_debug_mode(True) - def get_out(capsys): - out, err = capsys.readouterr() - assert(err == "") - return out.rstrip() - - def FFs(n): - return [PRIM_FF() for i in range(n)] - - def Register(n): - args = ["I", In(Array[n, Bit]), "O", Out(Array[n, Bit])] + ClockInterface(False, False, False) - - class RegCircuit(m.Circuit): - name = 'Register' + str(n) - io = m.IO(**dict(zip(args[::2], args[1::2]))) - ffs = join(FFs(n)) - wire(io.I, ffs.D) - wire(ffs.Q, io.O) - - return RegCircuit() - - def IncOne(n): - def sim_inc_one(self, value_store, state_store): - I = value_store.get_value(self.I) - n = len(I) - val = seq2int(I) + 1 - - cout = val > ((1 << n) - 1) - val = val % (1 << n) - - seq = int2seq(val, len(I)) - seq = [bool(s) for s in seq] - value_store.set_value(self.O, seq) - value_store.set_value(self.COUT, cout) - - args = ["I", In(Array[n, Bit]), "O", Out(Array[n, Bit]), "COUT", Out(Bit)] - class _Circuit(Circuit): - name = 'IncOne' + str(n) - io = IO(**dict(zip(args[::2], args[1::2]))) - stateful = False - primitive = True - simulate = sim_inc_one - - return _Circuit() - - def TestCounter(n): - args = [] - - args += ["O", Array[n, Out(Bit)]] - args += ["COUT", Out(Bit)] - - args += ClockInterface(False, False, False) - - class Counter(m.Circuit): - name = 'Counter' + str(n) - io = m.IO(**dict(zip(args[::2], args[1::2]))) - - inc = IncOne(n) - reg = Register(n) - reg.name = "reg" - - wire(reg.O, inc.I) - wire(inc.O, reg.I) - wire(reg.O, io.O) - - wire(inc.COUT, io.COUT) - - drive_undriven_other_clock_types_in_inst(Counter, Counter.reg) - - return Counter() - - args = ['O', Array[5, Out(Bit)], 'COUT', Out(Bit)] - args += ClockInterface(False, False, False) - - class testcircuit(Circuit): - name = "Test" - io = IO(**dict(zip(args[::2], args[1::2]))) - counter = TestCounter(5) - counter.name = "counter" - wire(counter.O, io.O) - wire(counter.COUT, io.COUT) - - sim = PythonSimulator(testcircuit, testcircuit.CLK) - - DebugNamePass(testcircuit).run() - - console = SimulationConsole(testcircuit, sim); - sim.evaluate() - - console.runcmd("p self.O") - out, err = capsys.readouterr() - assert(out.rstrip() == "0") - - console.runcmd("p self.idontexist") - out, err = capsys.readouterr() - assert(err != "") - assert(out == "") - - console.runcmd("next") - out, err = capsys.readouterr() - assert(err == "") - assert(out == "") - - console.runcmd("p self.O") - assert get_out(capsys) == "1" - - console.runcmd("next") - console.runcmd("p self.O") - assert get_out(capsys) == "2" - - console.runcmd("p self.counter.O") - assert get_out(capsys) == "2" - - console.runcmd("p self.counter.reg.O") - assert get_out(capsys) == "2" - m.config.set_debug_mode(False) diff --git a/tests/test_simulator/test_mux_tuple.py b/tests/test_simulator/test_mux_tuple.py deleted file mode 100644 index d08849fcc..000000000 --- a/tests/test_simulator/test_mux_tuple.py +++ /dev/null @@ -1,46 +0,0 @@ -import magma as m -from magma.bitutils import clog2 -from hwtypes import BitVector -from magma.simulator import PythonSimulator - - -def _declare_muxn(height, width): - def _simulate(self, value_store, state_store): - sel = BitVector[clog2(height)](value_store.get_value(self.I.sel)) - out = BitVector[width](value_store.get_value(self.I.data[int(sel)])) - value_store.set_value(self.O, out) - - I_fields = dict(data=m.Array[height, m.Bits[width]], - sel=m.Bits[clog2(height)]) - - class _Mux(m.Circuit): - name = f"mux{height}x{width}" - io = m.IO(I=m.In(m.Product.from_fields("anon", I_fields)), - O=m.Out(m.Bits[width])) - primitive = True - stateful = False - simulate = _simulate - - return _Mux - - -def test_muxn(): - class Main(m.Circuit): - io = m.IO(I0=m.In(m.Bits[5]), - I1=m.In(m.Bits[5]), - S=m.In(m.Bits[1]), - O=m.Out(m.Bits[5])) - - in_ = m.product(data=m.array([io.I0, io.I1]), sel=io.S) - io.O @= _declare_muxn(2, 5)()(in_) - - sim = PythonSimulator(Main) - for i in range(5): - I0 = BitVector.random(5) - I1 = BitVector.random(5) - S = BitVector.random(1) - sim.set_value(Main.I0, I0) - sim.set_value(Main.I1, I1) - sim.set_value(Main.S, S) - sim.evaluate() - assert sim.get_value(Main.O) == (I1 if S else I0) diff --git a/tests/test_simulator/test_nested.py b/tests/test_simulator/test_nested.py deleted file mode 100644 index 022272f96..000000000 --- a/tests/test_simulator/test_nested.py +++ /dev/null @@ -1,69 +0,0 @@ -import magma as m -from magma import * -from magma.clock import * -from magma.backend.coreir.coreir_backend import CoreIRBackend -from magma.bitutils import * -from coreir.context import * -from magma.simulator.coreir_simulator import CoreIRSimulator -from magma.simulator.python_simulator import PythonSimulator -import coreir -from magma.scope import Scope - -def simulator_nested(simple): - width = 8 - testValInt = 80 - testValBits = int2seq(testValInt) - c = coreir.Context() - cirb = CoreIRBackend(c) - scope = Scope() - inDims = [4, 3, width] - toNest = Array[inDims[1], Array[inDims[2], Bit]] - inType = In(Array[inDims[0], toNest]) - if simple: - outType = Out(Array[inDims[0], toNest]) - else: - outType = Out(Array[2, Array[2, toNest]]) - args = ['I', inType, 'O', outType] + ClockInterface(False, False) - - class testcircuit(Circuit): - name = 'test_simulator_nested_simple{}'.format(str(simple)) - io = IO(**dict(zip(args[::2], args[1::2]))) - if simple: - wire(io.I, io.O) - else: - wire(io.I[:2], io.O[0]) - wire(io.I[2:4], io.O[1]) - - sim = CoreIRSimulator(testcircuit, testcircuit.CLK, context=cirb.context, - namespaces=["aetherlinglib", "commonlib", "mantle", "coreir", "global"]) - - for i in range(inDims[0]): - for j in range(inDims[1]): - get = sim.get_value(testcircuit.I[i][j], scope) - assert(len(get) == width) - sim.set_value(testcircuit.I[i][j], int2seq((((i*inDims[1])+j)*inDims[2]), width), scope) - - sim.evaluate() - sim.get_value(testcircuit.I, scope) - sim.get_value(testcircuit.O, scope) - -def test_simulator_nested_simple(): - simulator_nested(True) - -def test_simulator_nested_complex(): - simulator_nested(False) - - -def test_simulator_nested_array(): - class Main(m.Circuit): - io = m.IO(I=m.In(m.Array[3, m.Bits[4]]), O=m.Out(m.Array[2, m.Bits[4]])) - io += m.ClockIO() - reg = m.Register(m.Array[2, m.Bits[4]])() - io.O @= reg(io.I[:2]) - io.I[2].unused() - - sim = PythonSimulator(Main, Main.CLK) - sim.set_value(Main.I, [3, 4]) - sim.evaluate() - sim.advance_cycle(1) - assert sim.get_value(Main.O) == [3, 4] diff --git a/tests/test_simulator/test_primitives.py b/tests/test_simulator/test_primitives.py deleted file mode 100644 index 7e56ecb32..000000000 --- a/tests/test_simulator/test_primitives.py +++ /dev/null @@ -1,62 +0,0 @@ -import magma as m - - -class PRIM_AND(m.Circuit): - io = m.IO(I0=m.In(m.Bit), I1=m.In(m.Bit), O=m.Out(m.Bit)) - stateful = False - primitive = True - - def simulate(self, value_store, state_store): - I0 = value_store.get_value(self.I0) - I1 = value_store.get_value(self.I1) - val = I0 and I1 - value_store.set_value(self.O, val) - - -class PRIM_OR(m.Circuit): - io = m.IO(I0=m.In(m.Bit), I1=m.In(m.Bit), O=m.Out(m.Bit)) - stateful = False - primitive = True - - def simulate(self, value_store, state_store): - I0 = value_store.get_value(self.I0) - I1 = value_store.get_value(self.I1) - val = I0 or I1 - value_store.set_value(self.O, val) - - -class PRIM_NOT(m.Circuit): - io = m.IO(I=m.In(m.Bit), O=m.Out(m.Bit)) - stateful = False - primitive = True - - def simulate(self, value_store, state_store): - I = value_store.get_value(self.I) - value_store.set_value(self.O, not I) - - -class PRIM_FF(m.Circuit): - io = m.IO(CLK=m.In(m.Clock), D=m.In(m.Bit), Q=m.Out(m.Bit)) - stateful = True - primitive = True - - def simulate(self, value_store, state_store): - cur_clock = value_store.get_value(self.CLK) - - if not state_store: - state_store['prev_clock'] = cur_clock - state_store['cur_val'] = False - - prev_clock = state_store['prev_clock'] - - clock_edge = not cur_clock and prev_clock - - new_val = state_store['cur_val'] - - if clock_edge: - input_val = value_store.get_value(self.D) - new_val = input_val - - state_store['prev_clock'] = cur_clock - state_store['cur_val'] = new_val - value_store.set_value(self.Q, new_val) diff --git a/tests/test_simulator/test_product.py b/tests/test_simulator/test_product.py deleted file mode 100644 index 5cf1e0aeb..000000000 --- a/tests/test_simulator/test_product.py +++ /dev/null @@ -1,20 +0,0 @@ -import magma as m -from magma.simulator import PythonSimulator - - -def test_product_python_sim_basic(): - class T(m.Product): - a = m.Bits[4] - b = m.Bits[4] - - class Main(m.Circuit): - io = m.IO(I=m.In(T), O=m.Out(T)) - - io.O @= io.I - - simulator = PythonSimulator(Main) - simulator.set_value(Main.I.a, 5) - simulator.set_value(Main.I.b, 11) - simulator.evaluate() - assert simulator.get_value(Main.I.a) == 5 - assert simulator.get_value(Main.I.b) == 11 diff --git a/tests/test_simulator/test_register.py b/tests/test_simulator/test_register.py deleted file mode 100644 index 7ec81751c..000000000 --- a/tests/test_simulator/test_register.py +++ /dev/null @@ -1,16 +0,0 @@ -import magma as m -import fault as f - - -def test_register(): - class Foo(m.Circuit): - io = m.IO(I=m.In(m.Bits[4]), O=m.Out(m.Bits[4])) - io += m.ClockIO(has_reset=True) - io.O @= m.Register( - m.Bits[4], reset_type=m.Reset - )()(io.I) - - tester = f.PythonTester(Foo, Foo.CLK) - tester.circuit.I = 3 - tester.step(2) - tester.circuit.O.expect(3) diff --git a/tests/test_simulator/test_tuple.py b/tests/test_simulator/test_tuple.py deleted file mode 100644 index ae94f3e60..000000000 --- a/tests/test_simulator/test_tuple.py +++ /dev/null @@ -1,45 +0,0 @@ -from magma import * -from magma.clock import * -from magma.backend.coreir.coreir_backend import CoreIRBackend -from magma.bitutils import * -from coreir.context import * -from magma.simulator.coreir_simulator import CoreIRSimulator -import coreir -from magma.scope import Scope - -def test_simulator_tuple(): - width = 8 - testValInt = 80 - c = coreir.Context() - cirb = CoreIRBackend(c) - scope = Scope() - inDims = [2, width] - tupleEl = Array[inDims[1], Bit] - class T(Product): - sel = tupleEl - data = tupleEl - nestedTuples = Array[inDims[0], T] - tupleValues = {'sel':int2seq(testValInt, width), 'data':int2seq(testValInt+20, width)} - inType = In(nestedTuples) - outType = Out(Array[2*inDims[0], tupleEl]) - args = ['I', inType, 'O', outType] + ClockInterface(False, False) - - class testcircuit(Circuit): - name = "test_simulator_tuple" - io = IO(**dict(zip(args[::2], args[1::2]))) - wire(io.I[0].data, io.O[0]) - wire(io.I[0].sel, io.O[1]) - wire(io.I[1].data, io.O[2]) - wire(io.I[1].sel, io.O[3]) - - - sim = CoreIRSimulator(testcircuit, testcircuit.CLK, context=cirb.context, - namespaces=["aetherlinglib", "commonlib", "mantle", "coreir", "global"]) - - sim.set_value(testcircuit.I, [tupleValues, tupleValues], scope) - getArrayInTuple = sim.get_value(testcircuit.I[0].data, scope) - getTuples = sim.get_value(testcircuit.I, scope) - assert getArrayInTuple == tupleValues['data'] - assert getTuples[0] == tupleValues - assert getTuples[1] == tupleValues - diff --git a/tests/test_simulator/test_values.py b/tests/test_simulator/test_values.py deleted file mode 100644 index 1f19a410c..000000000 --- a/tests/test_simulator/test_values.py +++ /dev/null @@ -1,97 +0,0 @@ -from magma.simulator.python_simulator import PythonSimulator -import magma as m -from hwtypes import BitVector -import pytest - - -def test_bit(): - class Main(m.Circuit): - io = m.IO(I=m.In(m.Bit), O=m.Out(m.Bit)) - - m.wire(io.I, io.O) - - sim = PythonSimulator(Main) - for value in [False, True]: - sim.set_value(Main.I, value) - sim.evaluate() - assert sim.get_value(Main.O) == value - - try: - sim.set_value(Main.I, 22) - assert False, "Should throw type error" - except TypeError as e: - assert str( - e) == "Can only set Bit I with a boolean value or 0 or 1, not 22 (type=)" - - -def test_array(): - class Main(m.Circuit): - io = m.IO(I=m.In(m.Array[2, m.Bit]), O=m.Out(m.Array[2, m.Bit])) - - m.wire(io.I, io.O) - - sim = PythonSimulator(Main) - for value in range(0, 4): - bv = BitVector[2](value) - bools = bv.as_bool_list() - sim.set_value(Main.I, bools) - sim.evaluate() - assert sim.get_value(Main.O) == bools - - sim.set_value(Main.I, bv) - sim.evaluate() - assert sim.get_value(Main.O) == bools - - try: - sim.set_value(Main.I, 22) - assert False, "Should throw type error" - except TypeError as e: - assert str( - e) == "Calling set_value with I of type Array[(2, Out(Bit))] only works with a list of values or a BitVector" - - -@pytest.mark.parametrize('T', [m.Bits, m.UInt]) -def test_uint(T): - class Main(m.Circuit): - io = m.IO(I=m.In(T[2]), O=m.Out(T[2])) - - m.wire(io.I, io.O) - - sim = PythonSimulator(Main) - for value in range(0, 4): - bv = BitVector[2](value) - bools = bv.as_bool_list() - sim.set_value(Main.I, bools) - sim.evaluate() - assert sim.get_value(Main.O) == value - - sim.set_value(Main.I, bv) - sim.evaluate() - assert sim.get_value(Main.O) == value - - sim.set_value(Main.I, value) - sim.evaluate() - assert sim.get_value(Main.O) == value - - -def test_sint(): - class Main(m.Circuit): - io = m.IO(I=m.In(m.SInt[2]), O=m.Out(m.SInt[2])) - - m.wire(io.I, io.O) - - sim = PythonSimulator(Main) - for value in range(-2, 2): - bv = BitVector[2](value) - bools = bv.as_bool_list() - sim.set_value(Main.I, bools) - sim.evaluate() - assert sim.get_value(Main.O) == value - - sim.set_value(Main.I, bv) - sim.evaluate() - assert sim.get_value(Main.O) == value - - sim.set_value(Main.I, value) - sim.evaluate() - assert sim.get_value(Main.O) == value diff --git a/tests/test_syntax/test_counter.py b/tests/test_syntax/test_counter.py deleted file mode 100644 index bb5cba8cc..000000000 --- a/tests/test_syntax/test_counter.py +++ /dev/null @@ -1,46 +0,0 @@ -import magma as m -from magma.simulator import PythonSimulator -from magma.simulator.coreir_simulator import CoreIRSimulator -from hwtypes import BitVector as BV - - -def test_counter(): - @m.sequential2() - class Counter: - def __init__(self): - self.count = m.Register(m.UInt[16])() - - def __call__(self, inc : m.Bit) -> m.UInt[16]: - if inc: - self.count = self.count + 1 - - O = self.count - return O - print(repr(Counter)) - - sim = PythonSimulator(Counter, Counter.CLK) - sim.set_value(Counter.inc, True) - sim.evaluate() - for i in range(4): - assert sim.get_value(Counter.O) == i + 1 - sim.advance_cycle() - sim.set_value(Counter.inc, False) - sim.evaluate() - for i in range(4): - assert sim.get_value(Counter.O) == 4 - sim.advance_cycle() - - sim = CoreIRSimulator(Counter, Counter.CLK) - sim.set_value(Counter.inc, 1) - sim.evaluate() - for i in range(4): - assert sim.get_value(Counter.O) == BV[16](i + 1) - sim.advance_cycle() - sim.set_value(Counter.inc, 0) - sim.evaluate() - for i in range(4): - assert sim.get_value(Counter.O) == BV[16](4) - sim.advance_cycle() - -if __name__ == "__main__": - test_counter() diff --git a/tests/test_type/test_bit.py b/tests/test_type/test_bit.py index 1c1fa56a7..7e640b2c2 100644 --- a/tests/test_type/test_bit.py +++ b/tests/test_type/test_bit.py @@ -1,11 +1,13 @@ import itertools +import operator import pytest + import magma as m from magma import In, Out, Flip -from magma.testing import check_files_equal from magma.bit import Bit, VCC, GND, Digital -from magma.simulator import PythonSimulator -import operator +from magma.testing import check_files_equal + + BitIn = In(Bit) BitOut = Out(Bit) @@ -255,12 +257,6 @@ class TestInvert(m.Circuit): assert check_files_equal(__file__, f"build/TestBitInvert.v", f"gold/TestBitInvert.v") - sim = PythonSimulator(TestInvert) - for I in [0, 1]: - sim.set_value(TestInvert.I, I) - sim.evaluate() - assert sim.get_value(TestInvert.O) == (0 if I else 1) - @pytest.mark.parametrize("op", ["and_", "or_", "xor"]) def test_binary(op): @@ -282,13 +278,6 @@ class TestBinary(m.Circuit): assert check_files_equal(__file__, f"build/TestBit{clean_op}.v", f"gold/TestBit{clean_op}.v") - sim = PythonSimulator(TestBinary) - for I0, I1 in zip([0, 1], [0, 1]): - sim.set_value(TestBinary.I0, I0) - sim.set_value(TestBinary.I1, I1) - sim.evaluate() - assert sim.get_value(TestBinary.O) == getattr(operator, op)(I0, I1) - def test_eq(): class TestBinary(m.Circuit): @@ -311,13 +300,6 @@ class TestBinary(m.Circuit): assert check_files_equal(__file__, f"build/TestBiteq.v", f"gold/TestBiteq.v") - sim = PythonSimulator(TestBinary) - for I0, I1 in zip([0, 1], [0, 1]): - sim.set_value(TestBinary.I0, I0) - sim.set_value(TestBinary.I1, I1) - sim.evaluate() - assert sim.get_value(TestBinary.O) == (I0 == I1) - def test_ne(): class TestBinary(m.Circuit): @@ -338,13 +320,6 @@ class TestBinary(m.Circuit): assert check_files_equal(__file__, f"build/TestBitne.v", f"gold/TestBitne.v") - sim = PythonSimulator(TestBinary) - for I0, I1 in zip([0, 1], [0, 1]): - sim.set_value(TestBinary.I0, I0) - sim.set_value(TestBinary.I1, I1) - sim.evaluate() - assert sim.get_value(TestBinary.O) == (I0 != I1) - def test_ite(): class TestITE(m.Circuit): @@ -367,14 +342,6 @@ class TestITE(m.Circuit): assert check_files_equal(__file__, f"build/TestBitite.v", f"gold/TestBitite.v") - sim = PythonSimulator(TestITE) - for I0, I1, S in zip([0, 1], [0, 1], [0, 1]): - sim.set_value(TestITE.I0, I0) - sim.set_value(TestITE.I1, I1) - sim.set_value(TestITE.S, S) - sim.evaluate() - assert sim.get_value(TestITE.O) == (I1 if S else I0) - @pytest.mark.parametrize("op", [int, bool]) def test_errors(op): diff --git a/tests/test_type/test_bits.py b/tests/test_type/test_bits.py index 36cf79182..205214112 100644 --- a/tests/test_type/test_bits.py +++ b/tests/test_type/test_bits.py @@ -1,14 +1,12 @@ -""" -Test the `m.Bits` type -""" - import operator import pytest + +from hwtypes import BitVector + import magma as m from magma import Bits from magma.testing import check_files_equal -from magma.simulator import PythonSimulator -from hwtypes import BitVector + ARRAY2 = m.Array[2, m.Bit] ARRAY4 = m.Array[4, m.Bit] @@ -198,13 +196,6 @@ class TestInvert(m.Circuit): assert check_files_equal(__file__, f"build/TestBits{n}Invert.v", f"gold/TestBits{n}Invert.v") - sim = PythonSimulator(TestInvert) - for _ in range(2): - I = BitVector.random(n) - sim.set_value(TestInvert.I, I) - sim.evaluate() - assert sim.get_value(TestInvert.O) == ~I - @pytest.mark.parametrize("n", [1, 3]) @pytest.mark.parametrize("op", ["and_", "or_", "xor", "lshift", "rshift"]) @@ -230,15 +221,6 @@ class TestBinary(m.Circuit): assert check_files_equal(__file__, f"build/TestBits{n}{magma_op}.v", f"gold/TestBits{n}{magma_op}.v") - sim = PythonSimulator(TestBinary) - for _ in range(2): - I0 = BitVector.random(n) - I1 = BitVector.random(n) - sim.set_value(TestBinary.I0, I0) - sim.set_value(TestBinary.I1, I1) - sim.evaluate() - assert sim.get_value(TestBinary.O) == getattr(operator, op)(I0, I1) - @pytest.mark.parametrize("n", [1, 3]) def test_ite(n): @@ -266,16 +248,6 @@ class TestITE(m.Circuit): assert check_files_equal(__file__, f"build/TestBits{n}ITE.v", f"gold/TestBits{n}ITE.v") - sim = PythonSimulator(TestITE) - for S in [0, 1]: - I0 = BitVector.random(n) - I1 = BitVector.random(n) - sim.set_value(TestITE.I0, I0) - sim.set_value(TestITE.I1, I1) - sim.set_value(TestITE.S, S) - sim.evaluate() - assert sim.get_value(TestITE.O) == (I1 if S else I0) - @pytest.mark.parametrize("n", [1, 3]) def test_eq(n): @@ -296,15 +268,6 @@ class TestBinary(m.Circuit): assert check_files_equal(__file__, f"build/TestBits{n}eq.v", f"gold/TestBits{n}eq.v") - sim = PythonSimulator(TestBinary) - for i in range(2): - I0 = BitVector.random(n) - I1 = BitVector.random(n) - sim.set_value(TestBinary.I0, I0) - sim.set_value(TestBinary.I1, I1) - sim.evaluate() - assert sim.get_value(TestBinary.O) == (I0 == I1) - @pytest.mark.parametrize("n", [1, 3]) def test_zext(n): @@ -328,13 +291,6 @@ class TestExt(m.Circuit): assert check_files_equal(__file__, f"build/TestBits{n}ext.v", f"gold/TestBits{n}ext.v") - sim = PythonSimulator(TestExt) - for i in range(2): - I = BitVector.random(n) - sim.set_value(TestExt.I, I) - sim.evaluate() - assert sim.get_value(TestExt.O) == I.zext(3) - @pytest.mark.parametrize("n", [1, 3]) def test_bvcomp(n): @@ -356,15 +312,6 @@ class TestBinary(m.Circuit): assert check_files_equal(__file__, f"build/TestBits{n}bvcomp.v", f"gold/TestBits{n}bvcomp.v") - sim = PythonSimulator(TestBinary) - for i in range(2): - I0 = BitVector.random(n) - I1 = BitVector.random(n) - sim.set_value(TestBinary.I0, I0) - sim.set_value(TestBinary.I1, I1) - sim.evaluate() - assert sim.get_value(TestBinary.O) == (I0 == I1) - @pytest.mark.parametrize("n", [1, 3]) @pytest.mark.parametrize("x", [4, 7]) @@ -390,13 +337,6 @@ class TestRepeat(m.Circuit): assert check_files_equal(__file__, f"build/TestBits{n}x{x}Repeat.v", f"gold/TestBits{n}x{x}Repeat.v") - sim = PythonSimulator(TestRepeat) - for i in range(2): - I = BitVector.random(n) - sim.set_value(TestRepeat.I, I) - sim.evaluate() - assert sim.get_value(TestRepeat.O) == I.repeat(x) - @pytest.mark.parametrize("op", [operator.and_, operator.or_, operator.xor, operator.lshift, operator.rshift, operator.add, @@ -408,12 +348,6 @@ class Main(m.Circuit): io = m.IO(I=m.In(m.Bits[5]), O=m.Out(m.Bits[5])) io.O @= op(x, io.I) - sim = PythonSimulator(Main) - I = BitVector.random(5) - sim.set_value(Main.I, I) - sim.evaluate() - assert sim.get_value(Main.O) == op(x, I) - @pytest.mark.parametrize("op, op_str", [ (operator.and_, "&"), diff --git a/tests/test_type/test_sint.py b/tests/test_type/test_sint.py index 2f6522d79..34518e61a 100644 --- a/tests/test_type/test_sint.py +++ b/tests/test_type/test_sint.py @@ -1,11 +1,12 @@ -import magma as m import operator import pytest -from magma.testing import check_files_equal -from magma import * -from magma.simulator import PythonSimulator + from hwtypes import SIntVector +import magma as m +from magma import * +from magma.testing import check_files_equal + Array2 = Array[2, Bit] Array4 = Array[4, Bit] @@ -109,15 +110,6 @@ class TestBinary(Circuit): io = IO(I0=In(SInt[n]), I1=In(SInt[n]), O=Out(Bit)) io.O <= getattr(operator, op)(io.I0, io.I1) - sim = PythonSimulator(TestBinary) - for _ in range(2): - I0 = SIntVector.random(n) - I1 = SIntVector.random(n) - sim.set_value(TestBinary.I0, I0) - sim.set_value(TestBinary.I1, I1) - sim.evaluate() - assert sim.get_value(TestBinary.O) == getattr(operator, op)(I0, I1) - op = { "eq": "eq", "le": "sle", @@ -145,18 +137,6 @@ class TestBinary(Circuit): io = IO(I0=In(SInt[n]), I1=In(SInt[n]), O=Out(SInt[n])) io.O <= getattr(operator, op)(io.I0, io.I1) - sim = PythonSimulator(TestBinary) - for _ in range(2): - I0 = SIntVector.random(n) - I1 = SIntVector.random(n) - if op in ["floordiv", "mod"]: - while I1 == 0: - I1 = SIntVector.random(n) - sim.set_value(TestBinary.I0, I0) - sim.set_value(TestBinary.I1, I1) - sim.evaluate() - assert sim.get_value(TestBinary.O) == getattr(operator, op)(I0, I1) - if op == "floordiv": op = "sdiv" elif op == "mod": @@ -224,16 +204,6 @@ class TestBinary(Circuit): assert check_files_equal(__file__, f"build/TestSInt{n}adc.v", f"gold/TestSInt{n}adc.v") - sim = PythonSimulator(TestBinary) - for _ in range(2): - I0 = SIntVector.random(n) - I1 = SIntVector.random(n) - sim.set_value(TestBinary.I0, I0) - sim.set_value(TestBinary.I1, I1) - sim.evaluate() - assert sim.get_value(TestBinary.O) == I0 + I1 - assert sim.get_value(TestBinary.COUT) == (I0.sext(1) + I1.sext(1))[-1] - @pytest.mark.parametrize("n", [7, 3]) def test_negate(n): @@ -252,13 +222,6 @@ class TestNegate(Circuit): assert check_files_equal(__file__, f"build/TestSInt{n}neg.v", f"gold/TestSInt{n}neg.v") - sim = PythonSimulator(TestNegate) - for _ in range(2): - I = SIntVector.random(n) - sim.set_value(TestNegate.I, I) - sim.evaluate() - assert sim.get_value(TestNegate.O) == -I - @pytest.mark.parametrize("op", [operator.floordiv, operator.mod]) def test_rops(op): @@ -268,16 +231,6 @@ class Main(m.Circuit): io = m.IO(I=m.In(m.SInt[5]), O=m.Out(m.SInt[5])) io.O @= op(x, io.I) - sim = PythonSimulator(Main) - I = SIntVector.random(5) - while I == 0: - # Avoid divide by 0 - I = SIntVector.random(5) - - sim.set_value(Main.I, I) - sim.evaluate() - assert sim.get_value(Main.O) == op(x, I) - @pytest.mark.parametrize("op, op_str", [ (operator.floordiv, "//"), diff --git a/tests/test_type/test_uint.py b/tests/test_type/test_uint.py index 4aae6a9bb..8a706acda 100644 --- a/tests/test_type/test_uint.py +++ b/tests/test_type/test_uint.py @@ -1,11 +1,13 @@ -import magma as m -from magma.testing import check_files_equal import operator import pytest -from magma import * -from magma.simulator import PythonSimulator + from hwtypes import UIntVector +import magma as m +from magma import * +from magma.testing import check_files_equal + + Array2 = Array[2, Bit] Array4 = Array[4, Bit] @@ -109,15 +111,6 @@ class TestBinary(Circuit): io = IO(I0=In(UInt[n]), I1=In(UInt[n]), O=Out(Bit)) io.O <= getattr(operator, op)(io.I0, io.I1) - sim = PythonSimulator(TestBinary) - for _ in range(2): - I0 = UIntVector.random(n) - I1 = UIntVector.random(n) - sim.set_value(TestBinary.I0, I0) - sim.set_value(TestBinary.I1, I1) - sim.evaluate() - assert sim.get_value(TestBinary.O) == getattr(operator, op)(I0, I1) - op = { "eq": "eq", "le": "ule", @@ -145,18 +138,6 @@ class TestBinary(Circuit): io = IO(I0=In(UInt[n]), I1=In(UInt[n]), O=Out(UInt[n])) io.O <= getattr(operator, op)(io.I0, io.I1) - sim = PythonSimulator(TestBinary) - for _ in range(2): - I0 = UIntVector.random(n) - I1 = UIntVector.random(n) - if op in ["floordiv", "mod"]: - while I1 == 0: - I1 = UIntVector.random(n) - sim.set_value(TestBinary.I0, I0) - sim.set_value(TestBinary.I1, I1) - sim.evaluate() - assert sim.get_value(TestBinary.O) == getattr(operator, op)(I0, I1) - if op == "floordiv": op = "udiv" elif op == "mod": @@ -218,16 +199,6 @@ class TestBinary(Circuit): assert check_files_equal(__file__, f"build/TestUInt{n}adc.v", f"gold/TestUInt{n}adc.v") - sim = PythonSimulator(TestBinary) - for _ in range(2): - I0 = UIntVector.random(n) - I1 = UIntVector.random(n) - sim.set_value(TestBinary.I0, I0) - sim.set_value(TestBinary.I1, I1) - sim.evaluate() - assert sim.get_value(TestBinary.O) == I0 + I1 - assert sim.get_value(TestBinary.COUT) == (I0.zext(1) + I1.zext(1))[-1] - @pytest.mark.parametrize("op", [operator.floordiv, operator.mod]) def test_rops(op): @@ -237,16 +208,6 @@ class Main(m.Circuit): io = m.IO(I=m.In(m.UInt[5]), O=m.Out(m.UInt[5])) io.O @= op(x, io.I) - sim = PythonSimulator(Main) - I = UIntVector.random(5) - while I == 0: - # Avoid divide by 0 - I = UIntVector.random(5) - - sim.set_value(Main.I, I) - sim.evaluate() - assert sim.get_value(Main.O) == op(x, I) - @pytest.mark.parametrize("op, op_str", [ (operator.floordiv, "//"),