def test_hash_verilog(): [foo0] = m.DefineFromVerilog(""" module foo(input I, output O); assign O = I; endmodule""") foo1 = m.DefineCircuit("foo", "I", m.In(m.Bit), "O", m.Out(m.Bit)) m.EndCircuit() top = m.DefineCircuit("top", "I", m.In(m.Bit), "O", m.Out(m.Bit)) foo0_inst = foo0() foo1_inst = foo1() m.wire(top.I, foo0_inst.I) m.wire(foo0_inst.O, foo1_inst.I) m.wire(foo1_inst.O, top.O) m.EndDefine() assert repr(foo0) == repr(foo1) # Run the uniquification pass as a mechanism to check that foo0 and foo1 # hash to two different things even though they have the same repr. pass_ = m.UniquificationPass(top, None) pass_._run(top) foo_seen = pass_.seen["foo"] assert len(foo_seen) == 2 for v in foo_seen.values(): assert len(v) == 1 expected_ids_ = {id(v[0]) for v in foo_seen.values()} ids_ = {id(foo0), id(foo1)} assert expected_ids_ == ids_
def test_str_repr(): And2 = m.DeclareCircuit('And2', "I0", m.In(m.Bit), "I1", m.In(m.Bit), "O", m.Out(m.Bit)) XOr2 = m.DeclareCircuit('XOr2', "I0", m.In(m.Bit), "I1", m.In(m.Bit), "O", m.Out(m.Bit)) Logic2 = m.DefineCircuit('Logic2', 'I0', m.In(m.Bit), 'I1', m.In(m.Bit), 'O', m.Out(m.Bit)) m.wire(XOr2()(And2()(Logic2.I0, Logic2.I1), 1), Logic2.O) m.EndCircuit() assert str(Logic2) == "Logic2(I0: In(Bit), I1: In(Bit), O: Out(Bit))" print(repr(Logic2)) assert repr(Logic2) == """\ Logic2 = DefineCircuit("Logic2", "I0", In(Bit), "I1", In(Bit), "O", Out(Bit)) And2_inst0 = And2() XOr2_inst0 = XOr2() wire(Logic2.I0, And2_inst0.I0) wire(Logic2.I1, And2_inst0.I1) wire(And2_inst0.O, XOr2_inst0.I0) wire(1, XOr2_inst0.I1) wire(XOr2_inst0.O, Logic2.O) EndCircuit()\ """ expected = [ "XOr2_inst0<XOr2(I0: In(Bit), I1: In(Bit), O: Out(Bit))>", "And2_inst0<And2(I0: In(Bit), I1: In(Bit), O: Out(Bit))>" ] for inst, expected in zip(Logic2.instances, expected): assert str(inst) == expected
def test_include_verilog(target, simulator): SB_DFF = m.DeclareCircuit('SB_DFF', "D", m.In(m.Bit), "Q", m.Out(m.Bit), "C", m.In(m.Clock)) main = m.DefineCircuit('main', "I", m.In(m.Bit), "O", m.Out(m.Bit), *m.ClockInterface()) ff = SB_DFF() m.wire(ff.D, main.I) m.wire(ff.Q, main.O) m.EndDefine() tester = fault.Tester(main, main.CLK) tester.poke(main.CLK, 0) tester.poke(main.I, 1) tester.eval() tester.expect(main.O, 0) tester.step(2) tester.expect(main.O, 1) sb_dff_filename = pathlib.Path("tests/sb_dff_sim.v").resolve() kwargs = {} if simulator is not None: kwargs["simulator"] = simulator with tempfile.TemporaryDirectory() as tmp_dir: tester.compile_and_run(target=target, directory=tmp_dir, include_verilog_libraries=[sb_dff_filename], **kwargs) if target in ["verilator"]: # Should work by including the tests/ directory which contains the # verilog file SB_DFF.v dir_path = os.path.dirname(os.path.realpath(__file__)) with tempfile.TemporaryDirectory() as tmp_dir: tester.compile_and_run(target=target, directory=tmp_dir, include_directories=[dir_path], **kwargs)
def test_multiple_assign(target): EQ = m.DefineCircuit("eq", "I0", m.In(m.Bit), "I1", m.In(m.Bit), "O", m.Out(m.Bit)) m.wire(0, EQ.O) m.EndDefine() @m.circuit.combinational def logic(a: m.Bit) -> (m.Bit,): if EQ()(a, m.bit(0)): c = m.bit(1) c = m.bit(0) else: c = m.bit(0) c = m.bit(1) return (c,) class Foo(m.Circuit): IO = ["a", m.In(m.Bit), "c", m.Out(m.Bit)] @classmethod def definition(io): c = logic(io.a) m.wire(c, io.c) compile_and_check("multiple_assign", Foo, target)
def create_io1out_pad(): cb = m.DefineCircuit("io1out_pad", "clk", m.In(m.Clock), "rst", m.In(m.Reset), "config_data", m.In(m.Bits(32)), "config_addr", m.In(m.Bits(32)), "tile_id", m.In(m.Bits(16)), "pin_0", m.In(m.Bit), "pin_1", m.In(m.Bit), "pin_2", m.In(m.Bit), "pin_3", m.In(m.Bit), "top_pin", m.Out(m.Bits(1))) # Configuration data config_reg = mantle.Register(32, init=0, has_ce=True, has_reset=True) addr_match = mantle.EQ(16) m.wire(addr_match.I0, cb.config_addr[0:16]) m.wire(addr_match.I1, cb.tile_id) m.wire(addr_match.O, config_reg.CE) m.wire(cb.config_data, config_reg.I) m.wire(cb.clk, config_reg.CLK) rst_inv = mantle.Invert(1) m.wire(rst_inv.I[0], cb.rst) m.wire(rst_inv.O[0], config_reg.RESET) # Config mux config_mux = mantle.Mux(height=4, width=1) m.wire(config_mux.O, cb.top_pin) m.wire(config_mux.S, config_reg.O[0:2]) m.wire(cb.pin_0, config_mux.I0[0]) m.wire(cb.pin_1, config_mux.I1[0]) m.wire(cb.pin_2, config_mux.I2[0]) m.wire(cb.pin_3, config_mux.I3[0]) m.EndDefine() return cb
def test_optional_assignment(target): EQ = m.DefineCircuit("eq", "I0", m.In(m.Bit), "I1", m.In(m.Bit), "O", m.Out(m.Bit)) m.wire(0, EQ.O) m.EndDefine() @m.circuit.combinational def logic(a: m.Bit) -> (m.Bit, m.Bit): d = m.bit(1) if EQ()(a, m.bit(0)): c = m.bit(1) else: c = m.bit(0) d = m.bit(1) return (c, d) class Foo(m.Circuit): IO = ["a", m.In(m.Bit), "c", m.Out(m.Bit), "d", m.Out(m.Bit)] @classmethod def definition(io): c, d = logic(io.a) m.wire(c, io.c) m.wire(d, io.d) compile_and_check("optional_assignment", Foo, target)
def test_for_loop_def(target, suffix): m.set_codegen_debug_info(True) And2 = m.DeclareCircuit('And2', "I0", m.In(m.Bit), "I1", m.In(m.Bit), "O", m.Out(m.Bit)) main = m.DefineCircuit("main", "I", m.In(m.Bits[2]), "O", m.Out(m.Bit)) and2_prev = None for i in range(0, 4): and2 = And2() if i == 0: m.wire(main.I[0], and2.I0) m.wire(main.I[1], and2.I1) else: m.wire(and2_prev.O, and2.I0) m.wire(main.I[1], and2.I1) and2_prev = and2 m.wire(and2.O, main.O) m.EndCircuit() m.compile("build/test_for_loop_def", main, output=target) m.set_codegen_debug_info(False) assert check_files_equal(__file__, f"build/test_for_loop_def.{suffix}", f"gold/test_for_loop_def.{suffix}")
def test_interleaved_instance_wiring(target, suffix): m.set_codegen_debug_info(True) And2 = m.DeclareCircuit('And2', "I0", m.In(m.Bit), "I1", m.In(m.Bit), "O", m.Out(m.Bit)) main = m.DefineCircuit("main", "I", m.In(m.Bits[2]), "O", m.Out(m.Bit)) and2_0 = And2() and2_1 = And2() m.wire(main.I[0], and2_0.I0) m.wire(main.I[1], and2_0.I1) m.wire(and2_0.O, and2_1.I0) m.wire(main.I[1], and2_1.I1) and2_2 = And2() m.wire(and2_1.O, and2_2.I0) m.wire(main.I[0], and2_2.I1) m.wire(and2_2.O, main.O) m.EndCircuit() m.compile("build/test_interleaved_instance_wiring", main, output=target) m.set_codegen_debug_info(False) assert check_files_equal( __file__, f"build/test_interleaved_instance_wiring.{suffix}", f"gold/test_interleaved_instance_wiring.{suffix}")
def test_simple_def(target, suffix): m.set_codegen_debug_info(True) And2 = m.DeclareCircuit('And2', "I0", m.In(m.Bit), "I1", m.In(m.Bit), "O", m.Out(m.Bit)) main = m.DefineCircuit("main", "I", m.In(m.Bits[2]), "O", m.Out(m.Bit)) and2 = And2() m.wire(main.I[0], and2.I0) m.wire(main.I[1], and2.I1) m.wire(and2.O, main.O) m.EndCircuit() m.compile("build/test_simple_def", main, output=target) assert check_files_equal(__file__, f"build/test_simple_def.{suffix}", f"gold/test_simple_def.{suffix}") # Check that the subclassing pattern produces the same annotations class Main(m.Circuit): IO = ["I", m.In(m.Bits[2]), "O", m.Out(m.Bit)] @classmethod def definition(io): and2 = And2() m.wire(io.I[0], and2.I0) m.wire(io.I[1], and2.I1) m.wire(and2.O, io.O) # Create a fresh context for second compilation. m.compile("build/test_simple_def_class", Main, output=target) m.set_codegen_debug_info(False) assert check_files_equal(__file__, f"build/test_simple_def_class.{suffix}", f"gold/test_simple_def_class.{suffix}")
def test_ram(): main = m.DefineCircuit("main", "rdata", m.Out(m.Bit), "CLKIN", m.In(m.Clock)) ram = mantle.RAM(4, 1, name="ram") waddr = mantle.Counter(2, cout=False) wdata = mantle.Counter(1, cout=False) we = 1 raddr = mantle.Counter(2, cout=False) ram(raddr, waddr, wdata, we, CLK=main.CLKIN) m.wire(ram.RDATA[0], main.rdata) m.EndDefine() if m.mantle_target == "coreir": output = "coreir" suffix = "json" else: output = "verilog" suffix = "v" m.compile(f"build/test_common_ram_{m.mantle_target}", main, output) assert check_files_equal( __file__, f"build/test_common_ram_{m.mantle_target}.{suffix}", f"gold/test_common_ram_{m.mantle_target}.{suffix}")
def test_binary_primitive(binary_primitive, width): primitive_name, primitive_op, signed = binary_primitive prim = m.DeclareCircuit(f"primitive_name", "in0", m.In(m.Array(width, m.Bit)), "in1", m.In(m.Array(width, m.Bit)), "out", m.Out(m.Array(width, m.Bit)), coreir_lib="coreir", coreir_name=primitive_name, coreir_genargs={"width": width}) circ = m.DefineCircuit(f"DesignTop", "I0", m.In(m.Array(width, m.Bit)), "I1", m.In(m.Array(width, m.Bit)), "O", m.Out(m.Array(width, m.Bit))) inst = prim() m.wire(circ.I0, inst.in0) m.wire(circ.I1, inst.in1) m.wire(circ.O, inst.out) m.EndDefine() m.compile(f"build/{primitive_name}", circ, output="coreir") dir_path = os.path.dirname(os.path.realpath(__file__)) result = delegator.run( f"CGRAMapper/bin/cgra-mapper build/{primitive_name}.json build/{primitive_name}_mapped.json", cwd=dir_path) assert not result.return_code, result.out + "\n" + result.err result = delegator.run(f"./CGRAGenerator/bin/generate.csh") assert not result.return_code, result.out + "\n" + result.err result = delegator.run( f"CGRAGenerator/bitstream/bsbuilder/serpent.csh build/{primitive_name}_mapped.json -cgra_info CGRAGenerator/hardware/generator_z/top/cgra_info.txt -o build/{primitive_name}_mapped_annotated" ) assert not result.return_code, result.out + "\n" + result.err
def test_compile(caplog): And2 = m.DeclareCircuit('And2', "I0", m.In(m.Bit), "I1", m.In(m.Bit), "O", m.Out(m.Bit)) # Make it a mock mantle module class MockMantle: pass MockMantle.__name__ = "mantle.coreir.arith" And2.debug_info = m.debug.debug_info(And2.debug_info.filename, And2.debug_info.lineno, MockMantle) main = m.DefineCircuit("main", "I", m.In(m.Bits[2]), "O", m.Out(m.Bit)) and2 = And2() m.wire(main.I[0], and2.I0) m.wire(main.I[1], and2.I1) m.wire(and2.O, main.O) m.EndCircuit() m.compile("build/test_compile_coreir_verilog", main) assert check_files_equal(__file__, "build/test_compile_coreir_verilog.v", "gold/test_compile_coreir_verilog.v") assert caplog.records[ 0].msg == "`m.compile` called with `output == verilog` and `m.mantle_target == \"coreir\"` and mantle has been imported, When generating verilog from circuits from the \"coreir\" mantle target, you should set `output=\"coreir-verilog\"`. Doing this automatically."
def test_inv(): Test = m.DefineCircuit("INV", "I", m.In(m.Bit), "O", m.Out(m.Bit)) inv = greenpak4.GP_INV() m.wire(Test.I, inv.IN) m.wire(inv.OUT, Test.O) com(Test, 'inv')
def test_two_ops(): Top = m.DefineCircuit("test_two_ops", "I0", m.In(m.UInt(8)), "I1", m.In(m.UInt(8)), "O", m.Out(m.UInt(8))) result = Top.I0 + Top.I1 - Top.I0 m.wire(result, Top.O) m.EndCircuit() m.compile("test_two_ops", Top, output="coreir-verilog", inline=True) # assert check_files_equal(__file__, "build/test_two_ops.v", # "gold/test_two_ops.v") # Roundabout way to do this since we can't pass the --inline flag through # fault's tester interface yet tester = fault.Tester(Top) for i in range(0, 16): I0 = fault.random.random_bv(8) I1 = fault.random.random_bv(8) tester.poke(Top.I0, I0) tester.poke(Top.I1, I1) tester.eval() tester.expect(Top.O, I0 + I1 - I0) tester.compile_and_run(target="verilator", skip_compile=True, directory=".")
def test_env_mod(target, simulator): myinv = m.DefineCircuit('myinv', 'a', m.In(m.Bit), 'y', m.Out(m.Bit)) m.wire(~myinv.a, myinv.y) m.EndDefine() tester = fault.InvTester(myinv, in_='a', out='y') tester.compile_and_run(target=target, simulator=simulator, tmp_dir=True)
def test_simple_top(): Top = m.DefineCircuit("Top", "I0", m.In(m.UInt(8)), "I1", m.In(m.UInt(8)), "O", m.Out(m.UInt(8))) sum_ = Top.I0 + Top.I1 m.wire(sum_, Top.O) m.EndCircuit() m.compile("test_simple_top", Top, output="coreir-verilog", inline=True)
def test_declare_interface_polarity(): And2Decl = m.DeclareCircuit("And2", "I0", m.In(m.Bit), "I1", m.In(m.Bit), "O", m.Out(m.Bit)) And2Defn = m.DefineCircuit("And2", "I0", m.In(m.Bit), "I1", m.In(m.Bit), "O", m.Out(m.Bit)) assert And2Decl.interface.ports["I0"].isinput() == \ And2Defn.interface.ports["I0"].isinput()
def test_error(): circ = m.DefineCircuit("test", "a", m.In(m.Bits[4]), "b", m.Out(m.Bits[4])) try: ~circ.a assert False, \ "Operator should throw an error since mantle is not imported" except MantleImportError: pass
def test_tester_verilog_wrapped(target, simulator): SimpleALU = m.DefineFromVerilogFile("tests/simple_alu.v", type_map={"CLK": m.In(m.Clock)}, target_modules=["SimpleALU"])[0] circ = m.DefineCircuit("top", "a", m.In(m.Bits[16]), "b", m.In(m.Bits[16]), "c", m.Out(m.Bits[16]), "config_data", m.In(m.Bits[2]), "config_en", m.In(m.Bit), "CLK", m.In(m.Clock)) simple_alu = SimpleALU() m.wire(simple_alu.a, circ.a) m.wire(simple_alu.b, circ.b) m.wire(simple_alu.c, circ.c) m.wire(simple_alu.config_data, circ.config_data) m.wire(simple_alu.config_en, circ.config_en) m.wire(simple_alu.CLK, circ.CLK) m.EndDefine() tester = fault.Tester(circ, circ.CLK) tester.verilator_include("SimpleALU") tester.verilator_include("ConfigReg") tester.circuit.CLK = 0 for i in range(0, 4): tester.poke( fault.WrappedVerilogInternalPort("SimpleALU_inst0.config_reg.Q", m.Bits[2]), i) tester.step(2) tester.expect( fault.WrappedVerilogInternalPort("SimpleALU_inst0.opcode", m.Bits[2]), i) signal = tester.peek( fault.WrappedVerilogInternalPort("SimpleALU_inst0.opcode", m.Bits[2])) tester.expect( fault.WrappedVerilogInternalPort("SimpleALU_inst0.opcode", m.Bits[2]), signal) tester.expect( fault.WrappedVerilogInternalPort( "SimpleALU_inst0.config_reg.Q", m.Bits[2]), i) signal = tester.peek( fault.WrappedVerilogInternalPort( "SimpleALU_inst0.config_reg.Q", m.Bits[2])) tester.expect( fault.WrappedVerilogInternalPort( "SimpleALU_inst0.config_reg.Q", m.Bits[2]), signal) with tempfile.TemporaryDirectory(dir=".") as _dir: if target == "verilator": tester.compile_and_run(target, directory=_dir, flags=["-Wno-fatal"]) else: tester.compile_and_run(target, directory=_dir, simulator=simulator)
def test_lut2(): Test = m.DefineCircuit("LUT2", "I0", m.In(m.Bit), "I1", m.In(m.Bit), "O", m.Out(m.Bit)) lut = greenpak4.GP_LUT2(INIT="4'h8") m.wire(Test.I0, lut.IN0) m.wire(Test.I1, lut.IN1) m.wire(lut.OUT, Test.O) com(Test, 'lut2')
def build_modules_from_magma(modlist): dummy_top = m.DefineCircuit("dummy_top") for mod_info in modlist: mod_name = mod_info[0] mod = mod_info[1] mod() m.compile("dummy_top", dummy_top, output="coreir") os_cmd("coreir -i " + mod_name + ".json" + " -o " + mod_name + ".v")
def visit_List(self, node): assert len(node.elts) == 1, "Expected only list literatals that " \ "contain a single expression" # FIXME: Hack to prevent instancing logic from polluting currently open # definition m.DefineCircuit("tmp") result = eval(astor.to_source(node.elts[0]).rstrip(), self.defn_env) m.EndCircuit() return EscapedExpression(result, node)
def test_array_nesting(): T = m.Array[10, m.Tuple(I=m.In(m.Bit), O=m.Out(m.Bit))] Foo = m.DefineCircuit("Foo", "IFC", T) for i in range(10): m.wire(Foo.IFC[i].I, Foo.IFC[i].O) m.EndCircuit() m.compile("build/test_array_nesting", Foo, output="coreir") assert check_files_equal(__file__, f"build/test_array_nesting.json", f"gold/test_array_nesting.json")
def test_romb(): main = m.DefineCircuit("test_romb", "O", m.Out(m.Bits[8]), "CLK", m.In(m.Clock)) rom = [i % 256 for i in range(2048)] romb = ROMB16(rom, 8) m.wire(romb(m.bits(1, 11), clk=main.CLK), main.O) m.EndCircuit() com(main, 'romb2048x8')
def test_lut3(): Test = m.DefineCircuit("LUT3", "I0", m.In(m.Bit), "I1", m.In(m.Bit), "I2", m.In(m.Bit), "O", m.Out(m.Bit)) lut = greenpak4.GP_LUT3(INIT="8'h80") m.wire(Test.I0, lut.IN0) m.wire(Test.I1, lut.IN1) m.wire(Test.I2, lut.IN2) m.wire(lut.OUT, Test.O) com(Test, 'lut3')
def test_verilog_field_uniquify(): # https://github.com/phanrahan/magma/issues/330 HalfAdder = m.DefineCircuit('HalfAdder', 'A', m.In(m.Bit), 'B', m.In(m.Bit), 'S', m.Out(m.Bit), 'C', m.Out(m.Bit)) HalfAdder.verilog = '''\ assign S = A ^ B; assign C = A & B;\ ''' m.EndCircuit()
def test_dff(): main = m.DefineCircuit('main', 'I', m.In(m.Bit), "O", m.Out(m.Bit), "CLK", m.In(m.Clock)) dff = SB_DFF() m.wire(main.I, dff.D) m.wire(dff.Q, main.O) m.EndCircuit() print(compile(main)) # compile will wire up the CLK print(repr(main))
def test_ff(ff): Test = m.DefineCircuit(ff, "I", m.In(m.Bit), "CLK", m.In(m.Clock), "O", m.Out(m.Bit)) DFF = getattr(greenpak4, 'GP_' + ff) dff = DFF() m.wire(Test.I, dff.D) m.wire(Test.CLK, dff.CLK) m.wire(dff.Q if ff == 'DFF' else dff.nQ, Test.O) com(Test, ff)
def test_compile_coreir(): width = 16 numInputs = 4 doubleT = magma.Bits[width] double = magma.DefineCircuit("double", "I", magma.In(doubleT), "O", magma.Out(doubleT)) shift_amount = 2 output = magma.concat(double.I[shift_amount:width], magma.bits(0, shift_amount)) magma.wire(output, double.O) coreir_double = magma.backend.coreir.coreir_.compile(double) c = coreir_double.context def get_lib(lib): if lib in {"coreir", "mantle", "corebit"}: return c.get_namespace(lib) elif lib == "global": return c.global_namespace else: return c.load_library(lib) def import_(lib, name): return get_lib(lib).generators[name] mapParallelParams = c.new_values({ "numInputs": numInputs, "operator": coreir_double }) test_module_typ = c.Record({ "in": c.Array(numInputs, c.Array(width, c.BitIn())), "out": c.Array(numInputs, c.Array(width, c.Bit())) }) test_module = c.global_namespace.new_module("test_module", test_module_typ) test_module_def = test_module.new_definition() mapParallel = import_("aetherlinglib", "mapParallel") mapMod = mapParallel(numInputs=numInputs, operator=coreir_double) mapDouble = test_module_def.add_module_instance("mapDouble", mapMod) test_module_def.connect(test_module_def.interface.select("in"), mapDouble.select("I")) test_module_def.connect(mapDouble.select("O"), test_module_def.interface.select("out")) test_module_def.print_() test_module.definition = test_module_def test_module.print_() dir_path = os.path.dirname(os.path.realpath(__file__)) test_module.save_to_file(os.path.join(dir_path, "mapParallel_test.json")) with open(os.path.join(dir_path, "mapParallel_test.json"), "r") as actual: with open(os.path.join(dir_path, "mapParallel_test_gold.json"), "r") as gold: assert actual.read() == gold.read() mod = c.load_from_file(os.path.join(dir_path, "mapParallel_test.json")) mod.print_()
def test_lut4(): Test = m.DefineCircuit("LUT4", "I0", m.In(m.Bit), "I1", m.In(m.Bit), "I2", m.In(m.Bit), "I3", m.In(m.Bit), "O", m.Out(m.Bit)) lut = greenpak4.GP_LUT4(INIT="16'h8000") m.wire(Test.I0, lut.IN0) m.wire(Test.I1, lut.IN1) m.wire(Test.I2, lut.IN2) m.wire(Test.I3, lut.IN3) m.wire(lut.OUT, Test.O) com(Test, 'lut4')