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_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_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_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_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_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_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 show(Test, width, has_clock=False): top = main(0, width, has_clock=has_clock) test = Test(width) out = test() if isinstance(out, tuple): out = out[0] m.wire(out, top.O) m.EndCircuit() return top
def shift(Test, width): logwidth = clog2(width) print(width, logwidth) top = main(width + logwidth, width) test = Test(width) print(type(test)) m.wire(test(top.I[0:width], top.I[width:width + logwidth]), top.O) m.EndCircuit() return top
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 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_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_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_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 nary(Test, height, width, output_isbits=True): top = main(height * width, width, output_isbits=output_isbits) test = Test(height, width) if width == 1: m.wire(test(*[top.I[i] for i in range(height)]), top.O) else: m.wire( test(*[top.I[i * width:(i + 1) * width] for i in range(height)]), top.O) m.EndCircuit() return top
def test_multi_direction_tuple_instance_bulk(): bar = m.DefineCircuit("bar", "ifc", m.Tuple(I=m.In(m.Bit), O=m.Out(m.Bit))) foo_inst = def_foo()() m.wire(bar.ifc, foo_inst.ifc) m.EndCircuit() m.compile("build/test_multi_direction_tuple_instance_bulk", bar, output="coreir") # NOTE: Should be the same as previous test, so we use that as a check assert check_files_equal( __file__, f"build/test_multi_direction_tuple_instance_bulk.json", f"gold/test_multi_direction_tuple_instance.json")
def test_multi_direction_tuple_instance(): bar = m.DefineCircuit("bar", "ifc", m.Tuple(I=m.In(m.Bit), O=m.Out(m.Bit))) foo_inst = def_foo()() m.wire(bar.ifc.I, foo_inst.ifc.I) m.wire(bar.ifc.O, foo_inst.ifc.O) m.EndCircuit() m.compile("build/test_multi_direction_tuple_instance", bar, output="coreir") assert check_files_equal( __file__, f"build/test_multi_direction_tuple_instance.json", f"gold/test_multi_direction_tuple_instance.json")
def test_uniquify_unequal(): foo = m.DefineCircuit("foo", "I", m.In(m.Bit), "O", m.Out(m.Bit)) m.wire(foo.I, foo.O) m.EndCircuit() bar = m.DefineCircuit("foo", "I", m.In(m.Bits[2]), "O", m.Out(m.Bits[2])) m.wire(bar.I, bar.O) m.EndCircuit() top = m.DefineCircuit("top", "I", m.In(m.Bit), "O", m.Out(m.Bit)) foo_inst = foo() m.wire(top.I, foo_inst.I) bar_inst = bar() m.wire(foo_inst.O, bar_inst.I[0]) m.wire(foo_inst.O, bar_inst.I[1]) m.wire(bar_inst.O[0], top.O) m.EndCircuit() assert hash(repr(foo)) != hash(repr(bar)) m.compile("build/uniquify_unequal", top, output="coreir") assert check_files_equal(__file__, "build/uniquify_unequal.json", "gold/uniquify_unequal.json")
def test_uniquify_equal(): foo = m.DefineCircuit("foo", "I", m.In(m.Bit), "O", m.Out(m.Bit)) m.wire(foo.I, foo.O) m.EndCircuit() bar = m.DefineCircuit("foo", "I", m.In(m.Bit), "O", m.Out(m.Bit)) m.wire(bar.I, bar.O) m.EndCircuit() top = m.DefineCircuit("top", "I", m.In(m.Bit), "O", m.Out(m.Bit)) curr = top.I for circ in (foo, bar): inst = circ() m.wire(inst.I, curr) curr = inst.O m.wire(curr, top.O) m.EndCircuit() assert hash(repr(foo)) == hash(repr(bar)) m.compile("build/uniquify_equal", top, output="coreir") assert check_files_equal(__file__, "build/uniquify_equal.json", "gold/uniquify_equal.json")
def test_compile(caplog): main = m.DefineCircuit("main", "I", m.In(m.Bits(2)), "O", m.Out(m.Bit)) and2 = mantle.And(2) 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_coreir_compile_verilog", main) assert check_files_equal(__file__, "build/test_coreir_compile_verilog.v", "gold/test_coreir_compile_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_coreir_wrap(T): wrapper = CoreirWrap(T, magma.Bit, "Bit") assert wrapper.out_type == T assert wrapper.in_type == magma.Bit assert wrapper.type_name == "Bit" wrapper_circuit = wrapper.circuit() test_circuit = magma.DefineCircuit("TestCircuit", "O", magma.Out(T)) wrapper_inst = wrapper_circuit() magma.wire(magma.bit(0), wrapper_inst.I) magma.wire(wrapper_inst.O, test_circuit.O) magma.EndCircuit() magma.compile("TEST", test_circuit, output="coreir")
def test_unwired_ports_warnings(caplog): caplog.set_level(logging.WARN) 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[1], and2.I1) m.EndCircuit() m.compile("build/test_unwired_output", main) assert check_files_equal(__file__, f"build/test_unwired_output.v", f"gold/test_unwired_output.v") assert caplog.records[-2].msg == "main.And2_inst0.I0 not connected" assert caplog.records[-1].msg == "main.O is unwired"
def binary(Test, width): import magma as m from loam.boards.icestick import IceStick icestick = IceStick() for i in range(2*width): icestick.J1[i].input().on() for i in range(width): icestick.J3[i].output().on() top = icestick.main() if width == 1: top.J3 = [top.J3] test = Test() m.wire( test(top.J1[0:width], top.J1[width:2*width], 0), top.J3 ) m.EndCircuit() return top
def test_ramb(): main = m.DefineCircuit("test_ramb", "RDATA", m.Out(m.Bits[8]), "WDATA", m.In(m.Bits[8]), "WE", m.In(m.Bit), "CLK", m.In(m.Clock)) ram = [i % 256 for i in range(2048)] ramb = ROMB16(ram, 8) m.wire(ramb.A, uint(1, 11)) m.wire(ramb.CLK, main.CLK) m.wire(ramb.RE, 1) m.wire(ramb.WADDR, uint(1, 11)) m.wire(ramb.WCLK, main.CLK) m.wire(ramb.WE, main.WE) m.wire(ramb.RDATA, main.RDATA) m.wire(ramb.WDATA, main.WDATA) m.EndCircuit() com(main, 'romb2048x8')
def main(n): import magma as m m.set_mantle_target('spartan3') from loam.boards.papilioone import PapilioOne from loam.shields.megawing import MegaWing from mantle import LUTN megawing = MegaWing(PapilioOne) megawing.Switch.on(n) megawing.LED.on(1) top = megawing.main() pown = 1 << n lut = LUTN(pown // 2 * [0, 1], pown) I = [top.SWITCH[i] for i in range(n)] if n != 1 else [top.SWITCH] m.wire(lut(*I), top.LED) m.EndCircuit() return top
def test_str_repr_anon(): And2 = m.DeclareCircuit('And2', "I0", m.In(m.Bit), "I1", m.In(m.Bit), "O", m.Out(m.Bit)) circ = m.DefineCircuit("Test", "I0", m.In(m.Bits[3]), "I1", m.In(m.Bits[3]), "O", m.Out(m.Bits[3])) anon = m.join(m.map_(And2, 3)) m.wire(circ.I0, anon.I0) m.wire(circ.I1, anon.I1) m.wire(circ.O, anon.O) m.EndCircuit() string = str(anon) assert string[:len("AnonymousCircuitInst")] == "AnonymousCircuitInst" assert string[-len( "<I0: Array[3, In(Bit)], I1: Array[3, In(Bit)], O: Array[3, Out(Bit)]>" ):] == "<I0: Array[3, In(Bit)], I1: Array[3, In(Bit)], O: Array[3, Out(Bit)]>" assert repr( anon ) == 'AnonymousCircuitType("I0", array([And2_inst0.I0, And2_inst1.I0, And2_inst2.I0]), "I1", array([And2_inst0.I1, And2_inst1.I1, And2_inst2.I1]), "O", array([And2_inst0.O, And2_inst1.O, And2_inst2.O]))'
def test_nesting(): bar = m.DefineCircuit( "bar", "I", m.Tuple(x=m.In(m.Tuple(a=m.Bit, b=m.Bit)), y=m.Out(m.Tuple(a=m.Bit, b=m.Bit)), z=m.Tuple(a=m.In(m.Bit), b=m.Out(m.Bit)))) foo = def_foo() foo_inst0 = foo() foo_inst1 = foo() foo_inst2 = foo() m.wire(foo_inst0.ifc.I, bar.I.x.a) m.wire(foo_inst0.ifc.O, bar.I.y.a) m.wire(foo_inst1.ifc.I, bar.I.x.b) m.wire(foo_inst1.ifc.O, bar.I.y.b) m.wire(foo_inst2.ifc.I, bar.I.z.a) m.wire(foo_inst2.ifc.O, bar.I.z.b) m.EndCircuit() m.compile("build/test_nesting", bar, output="coreir") assert check_files_equal(__file__, f"build/test_nesting.json", f"gold/test_nesting.json")
def unary(Test, width, input_isbits=True, output_isbits=True, split_inputs=False, has_clock=False): top = main(width, width, input_isbits=input_isbits, output_isbits=output_isbits, has_clock=has_clock) test = Test(width) if split_inputs: assert input_isbits m.wire(test(*[top.I[i] for i in range(width)]), top.O) else: m.wire(test(top.I), top.O) m.EndCircuit() return top
def test_2d_array_error(caplog): 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.Array[2, m.Array[3, m.Bit]]), "O", m.Out(m.Bit)) and2 = And2() m.wire(main.I[1][0], and2.I1) m.EndCircuit() try: m.compile("build/test_unwired_output", main) assert False, "Should raise exception" except Exception as e: assert str( e ) == "Argument main.I of type Array[2, Array[3, Out(Bit)]] is not supported, the verilog backend only supports simple 1-d array of bits of the form Array(N, Bit)" # noqa