class _MAC(m.Circuit): name = "MAC" + str(n) logn = log2(n) + 1 IO = ['CLK', m.In(m.Clock), 'I0', m.In(m.Bits(n)), 'I1', m.In(m.Bits(n)), 'P', m.Out(m.Bits(logn)), 'O', m.Out(m.Bit)] @classmethod def definition(io): # XNOR for binary affine mapped multiplication mul = mantle.NXOr(height=2, width=n) m.wire(mul.I0, io.I0) m.wire(mul.I1, io.I1) pop = PopCount(n) m.wire(mul.O, pop.I) m.wire(pop.O, io.P) width = log2(n)+2 sign = mantle.UGE(width) m.wire(m.zext(pop.O, 1), sign.I0) m.wire(m.bits(n, width), sign.I1) m.wire(sign.O, io.O)
def __init__(self, height, width): super().__init__() self.height = height self.width = width T = magma.Bits(self.width) # In the case that @height <= 1, we make this circuit a simple # pass-through circuit. if self.height <= 1: self.add_ports( I=magma.In(magma.Array(1, T)), O=magma.Out(T), ) self.wire(self.ports.I[0], self.ports.O) self.sel_bits = 0 return MuxCls = mantle.DefineMux(self.height, self.width) self.mux = FromMagma(MuxCls) self.sel_bits = magma.bitutils.clog2(self.height) self.add_ports( I=magma.In(magma.Array(self.height, T)), S=magma.In(magma.Bits(self.sel_bits)), O=magma.Out(T), ) for i in range(self.height): self.wire(self.ports.I[i], self.mux.ports[f"I{i}"]) mux_in = self.ports.S if self.sel_bits > 1 else self.ports.S[0] self.wire(mux_in, self.mux.ports.S) self.wire(self.mux.ports.O, self.ports.O)
def __init__(self, data_width, data_depth): super().__init__() self.data_width = data_width self.data_depth = data_depth TData = magma.Bits(self.data_width) TBit = magma.Bits(1) self.add_ports(data_in=magma.In(TData), addr_in=magma.In(TData), data_out=magma.Out(TData), clk=magma.In(magma.Clock), config=magma.In(ConfigurationType(8, 32)), read_config_data=magma.Out(magma.Bits(32)), reset=magma.In(magma.AsyncReset), flush=magma.In(TBit), wen_in=magma.In(TBit), ren_in=magma.In(TBit), stall=magma.In(magma.Bits(4))) wrapper = memory_core_genesis2.memory_core_wrapper param_mapping = memory_core_genesis2.param_mapping generator = wrapper.generator(param_mapping, mode="declare") circ = generator(data_width=self.data_width, data_depth=self.data_depth) self.underlying = FromMagma(circ) self.wire(self.ports.data_in, self.underlying.ports.data_in) self.wire(self.ports.addr_in, self.underlying.ports.addr_in) self.wire(self.ports.data_out, self.underlying.ports.data_out) self.wire(self.ports.config.config_addr, self.underlying.ports.config_addr[24:32]) self.wire(self.ports.config.config_data, self.underlying.ports.config_data) self.wire(self.ports.config.write[0], self.underlying.ports.config_en) self.wire(self.underlying.ports.read_data, self.ports.read_config_data) self.wire(self.ports.reset, self.underlying.ports.reset) self.wire(self.ports.flush[0], self.underlying.ports.flush) self.wire(self.ports.wen_in[0], self.underlying.ports.wen_in) self.wire(self.ports.ren_in[0], self.underlying.ports.ren_in) # PE core uses clk_en (essentially active low stall) self.stallInverter = FromMagma(mantle.DefineInvert(1)) self.wire(self.stallInverter.ports.I, self.ports.stall[0:1]) self.wire(self.stallInverter.ports.O[0], self.underlying.ports.clk_en) # TODO(rsetaluri): Actually wire these inputs. signals = ( ("config_en_sram", 4), ("config_en_linebuf", 1), ("chain_wen_in", 1), ("config_read", 1), ("config_write", 1), ("chain_in", self.data_width), ) for name, width in signals: val = magma.bits(0, width) if width > 1 else magma.bit(0) self.wire(Const(val), self.underlying.ports[name]) self.wire(Const(magma.bits(0, 24)), self.underlying.ports.config_addr[0:24])
class DFF3(m.Circuit): name = make_name_dff3(array_size_2, array_size_1, width, pipe_depth, retime_status) IO = [ "data_in", m.Array(array_size_2, m.Array(array_size_1, m.In(m.Bits(width)))), "clk", m.In(m.Clock), "reset", m.In(m.Reset), "en", m.In(m.Bit), "data_out", m.Array(array_size_2, m.Array(array_size_1, m.Out(m.Bits(width)))) ] @classmethod def definition(io): dffs = m.braid(m.map_( DefineDFF2(array_size_1, width, pipe_depth, retime_status), array_size_2), joinargs=["data_in", "data_out"], forkargs=["clk", "en", "reset"]) m.wire(dffs.data_in, io.data_in) m.wire(dffs.data_out, io.data_out) m.wire(dffs.clk, io.clk) m.wire(dffs.en, io.en) m.wire(dffs.reset, io.reset)
def test_generator(mode): def _foo(*args, **kwargs): pass generator = WRAPPER.generator(mode=mode) assert inspect.isfunction(generator) assert inspect.signature(generator) == inspect.signature(_foo) # Check that passing non-kwargs fails. try: generator(0) assert False except NotImplementedError as e: pass module = generator(**PARAMS) type_ = m.circuit.DefineCircuitKind if mode == "define" \ else m.circuit.CircuitKind assert isinstance(module, type_) expected_ports = { "clk": m.Out(m.Bit), "reset": m.Out(m.Bit), "in0": m.Out(m.Bits(16)), "in1": m.Out(m.Bits(16)), "sel": m.Out(m.Bit), "out": m.In(m.Bits(16)), } for name, type_ in module.IO.ports.items(): assert type(expected_ports[name]) == type(type_)
def ConfigInterface(config_addr_width, config_data_width): return [ "config_addr", m.In(m.Bits(config_addr_width)), "config_data", m.In(m.Bits(config_data_width)), "config_en", m.In(m.Enable), "read_data", m.Out(m.Bits(config_data_width)) ]
def return_ll_ur(I: m.Bits(3), S: m.Bit) -> (m.Bits(bits), m.Bits(bits) ): if ~I[0]: if ~I[1]: if ~I[2]: ll = io.poly_in[2][S] ur = io.poly_in[0][S] else: ll = io.poly_in[2][S] ur = io.poly_in[0][S] else: if ~I[2]: ll = io.poly_in[1][S] ur = io.poly_in[0][S] else: ll = io.poly_in[1][S] ur = io.poly_in[2][S] else: if ~I[1]: if ~I[2]: ll = io.poly_in[2][S] ur = io.poly_in[1][S] else: ll = io.poly_in[0][S] ur = io.poly_in[1][S] else: if ~I[2]: ll = io.poly_in[0][S] ur = io.poly_in[2][S] else: ll = io.poly_in[0][S] ur = io.poly_in[2][S] return ll, ur
class SwitchBox(m.Circuit): name = 'switch_box' IO = [ "clk", m.In(m.Clock), "rst", m.In(m.Reset), "config_data", m.In(m.Bits(32)), "config_en", m.In(m.Bit), "clb_result", m.In(m.Bits(WireWidth)) ] for side in range(0, 4): for track in range(0, 4): IO.append('side_' + str(side) + '_track_' + str(track) + '_in') IO.append(m.In(m.Bits(WireWidth))) IO.append('side_' + str(side) + '_track_' + str(track) + '_out') IO.append(m.Out(m.Bits(WireWidth))) @classmethod def definition(io): # Configuration data config_reg = mantle.Register(32, init=0, has_ce=True, has_reset=True) m.wire(io.config_data, config_reg.I) m.wire(io.clk, config_reg.CLK) m.wire(io.config_en, config_reg.CE) rst_inv = mantle.Invert(1) m.wire(rst_inv.I[0], io.rst) m.wire(rst_inv.O[0], config_reg.RESET) # switch muxes config_offset = 0 for side in range(0, 4): for track in range(0, 4): switch_mux = mantle.Mux(height=4, width=1) m.wire( switch_mux.O, getattr( io, 'side_' + str(side) + '_track_' + str(track) + '_out')) m.wire(switch_mux.S, config_reg.O[config_offset:(config_offset + 2)]) config_offset += 2 for in_side in range(0, 4): if in_side == side: m.wire(getattr(switch_mux, "I" + str(in_side)), io.clb_result) else: m.wire( getattr(switch_mux, "I" + str(in_side)), getattr( io, 'side_' + str(in_side) + '_track_' + str(track) + '_in'))
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
class ConfigReg(m.Circuit): IO = ["D", m.In(m.Bits(2)), "Q", m.Out(m.Bits(2))] + \ m.ClockInterface(has_ce=True) @classmethod def definition(io): reg = mantle.Register(2, has_ce=True, name="conf_reg") io.Q <= reg(io.D, CE=io.CE)
class CLB(m.Circuit): name = 'configurable_logic_block' IO = [ "operand0", m.In(m.Bits(WireWidth)), "operand1", m.In(m.Bits(WireWidth)), "result", m.Out(m.Bits(WireWidth)), "clk", m.In(m.Clock), "rst", m.In(m.Reset), "config_data", m.In(m.Bits(32)), "config_en", m.In(m.Bit) ] @classmethod def definition(io): # Configuration data config_reg = mantle.Register(32, init=0, has_ce=True, has_reset=True) m.wire(io.config_data, config_reg.I) m.wire(io.clk, config_reg.CLK) m.wire(io.config_en, config_reg.CE) rst_inv = mantle.Invert(1) m.wire(rst_inv.I[0], io.rst) m.wire(rst_inv.O[0], config_reg.RESET) # Operations in CLB and_op = mantle.And(2, 1) m.wire(io.operand0, and_op.I0) m.wire(io.operand1, and_op.I1) or_op = mantle.Or(2, 1) m.wire(io.operand0, or_op.I0) m.wire(io.operand1, or_op.I1) xor_op = mantle.XOr(2, 1) m.wire(io.operand0, xor_op.I0) m.wire(io.operand1, xor_op.I1) not_op = mantle.Invert(1) m.wire(io.operand0, not_op.I) # Config mux config_mux = mantle.Mux(height=4, width=1) m.wire(config_mux.O, io.result) m.wire(config_mux.S, config_reg.O[0:2]) m.wire(and_op.O, config_mux.I0) m.wire(or_op.O, config_mux.I1) m.wire(xor_op.O, config_mux.I2) m.wire(not_op.O, config_mux.I3)
def __init__(self, num_tracks, width): super().__init__() if num_tracks <= 1: raise ValueError("num_tracks must be > 1") self.num_tracks = num_tracks self.width = width sel_bits = magma.bitutils.clog2(self.num_tracks) self.mux = MuxWrapper(self.num_tracks, self.width) T = magma.Bits(self.width) self.add_ports( I=magma.In(magma.Array(self.num_tracks, T)), O=magma.Out(T), clk=magma.In(magma.Clock), reset=magma.In(magma.AsyncReset), config=magma.In(ConfigurationType(8, 32)), read_config_data=magma.Out(magma.Bits(32)), ) self.add_configs(S=sel_bits) # read_config_data output num_config_reg = len(self.registers) if (num_config_reg > 1): self.read_config_data_mux = MuxWrapper(num_config_reg, 32) self.wire(self.ports.config.config_addr, self.read_config_data_mux.ports.S) self.wire(self.read_config_data_mux.ports.O, self.ports.read_config_data) for idx, reg in enumerate(self.registers.values()): self.wire(reg.ports.O, self.read_config_data_mux.ports.I[idx]) # Wire up config register resets self.wire(reg.ports.reset, self.ports.reset) # If we only have 1 config register, we don't need a mux # Wire sole config register directly to read_config_data_output else: reg = list(self.registers.values())[0] zext = ZextWrapper(reg.width, 32) self.wire(reg.ports.O, zext.ports.I) zext_out = zext.ports.O self.wire(zext_out, self.ports.read_config_data) self.wire(self.ports.I, self.mux.ports.I) self.wire(self.registers.S.ports.O, self.mux.ports.S) self.wire(self.mux.ports.O, self.ports.O) for idx, reg in enumerate(self.registers.values()): reg.set_addr(idx) reg.set_addr_width(8) reg.set_data_width(32) self.wire(self.ports.config.config_addr, reg.ports.config_addr) self.wire(self.ports.config.config_data, reg.ports.config_data) # Connect config_en for each config reg self.wire(reg.ports.config_en, self.ports.config.write[0])
def __init__(self, num_inputs, width, sel_bits, default): super().__init__() self.num_inputs = num_inputs self.width = width self.sel_bits = sel_bits self.default = default if 2**self.sel_bits <= self.num_inputs: raise ValueError(f"(2 ^ sel_bits) must be > num_inputs " f"(sel_bits={self.sel_bits}, " f"num_inputs={self.num_inputs})") self.data_mux = MuxWrapper(self.num_inputs, self.width) self.default_mux = MuxWrapper(2, self.width) lt = mantle.DefineULT(self.sel_bits) and_gate = mantle.DefineAnd(2) self.lt = FromMagma(lt) self.and_gate = FromMagma(and_gate) T = magma.Bits(self.width) self.add_ports( I=magma.In(magma.Array(self.num_inputs, T)), S=magma.In(magma.Bits(self.sel_bits)), EN=magma.In(magma.Bits(1)), O=magma.Out(T), ) # Wire data inputs to data mux. for i in range(self.num_inputs): self.wire(self.ports.I[i], self.data_mux.ports.I[i]) # Wire select input to select input of data_mux. Note that we only wire # the first clog2(num_inputs) bits of the select input. self.wire(self.ports.S[:self.data_mux.sel_bits], self.data_mux.ports.S) # Wire default value to first input of default mux, and output of # data_mux to second input of default mux. default_mux_inputs = [ Const(magma.bits(self.default, self.width)), self.data_mux.ports.O, ] for i, mux_in in enumerate(default_mux_inputs): self.wire(mux_in, self.default_mux.ports.I[i]) # Generate select logic for default mux: # sel = (S < num_inputs) & EN self.wire(self.ports.S, self.lt.ports.I0) self.wire(Const(magma.bits(self.num_inputs, self.sel_bits)), self.lt.ports.I1) self.wire(self.lt.ports.O, self.and_gate.ports.I0) self.wire(self.ports.EN[0], self.and_gate.ports.I1) self.wire(self.and_gate.ports.O, self.default_mux.ports.S[0]) self.wire(self.default_mux.ports.O, self.ports.O)
class Configurable(m.Circuit): IO = ["config_addr", m.In(m.Bits(32)), "config_data", m.In(m.Bits(32)), "config_en", m.In(m.Enable), "O", m.Out(m.Bits(32)) ] + m.ClockInterface() @classmethod def definition(io): reg = mantle.Register(32, has_ce=True) reg(io.config_data, CE=(io.config_addr == m.bits(1, 32)) & m.bit(io.config_en)) m.wire(reg.O, io.O)
class ConnectBox(m.Circuit): name = 'connect_box' IO = [ "clk", m.In(m.Clock), "rst", m.In(m.Reset), "config_data", m.In(m.Bits(32)), "config_en", m.In(m.Bit), "track_0_in", m.In(m.Bits(WireWidth)), "track_1_in", m.In(m.Bits(WireWidth)), "track_2_in", m.In(m.Bits(WireWidth)), "track_3_in", m.In(m.Bits(WireWidth)), "track_0_out", m.In(m.Bits(WireWidth)), "track_1_out", m.In(m.Bits(WireWidth)), "track_2_out", m.In(m.Bits(WireWidth)), "track_3_out", m.In(m.Bits(WireWidth)), "out", m.Out(m.Bits(WireWidth)) ] @classmethod def definition(io): # Configuration data config_reg = mantle.Register(32, init=0, has_ce=True, has_reset=True) m.wire(io.config_data, config_reg.I) m.wire(io.clk, config_reg.CLK) m.wire(io.config_en, config_reg.CE) rst_inv = mantle.Invert(1) m.wire(rst_inv.I[0], io.rst) m.wire(rst_inv.O[0], config_reg.RESET) # Config mux config_mux = mantle.Mux(height=8, width=1) m.wire(config_mux.O, io.out) m.wire(config_mux.S, config_reg.O[0:3]) m.wire(io.track_0_in, config_mux.I0) m.wire(io.track_1_in, config_mux.I1) m.wire(io.track_2_in, config_mux.I2) m.wire(io.track_3_in, config_mux.I3) m.wire(io.track_0_out, config_mux.I4) m.wire(io.track_1_out, config_mux.I5) m.wire(io.track_2_out, config_mux.I6) m.wire(io.track_3_out, config_mux.I7)
def __init__(self): super().__init__() # TODO(rsetaluri): Currently we assume the default parameters into the # wrapper. Ideally we should take some arguments into this generator # and pass them to the genesis wrapper. wrapper = pe_core_genesis2.pe_core_wrapper generator = wrapper.generator(mode="declare") circ = generator() self.underlying = FromMagma(circ) TData = magma.Bits(16) TBit = magma.Bits(1) TFlag = magma.Bits(4) self.add_ports( data0=magma.In(TData), data1=magma.In(TData), bit0=magma.In(TBit), bit1=magma.In(TBit), bit2=magma.In(TBit), res=magma.Out(TData), res_p=magma.Out(TFlag), clk=magma.In(magma.Clock), reset=magma.In(magma.AsyncReset), config=magma.In(ConfigurationType(8, 32)), read_config_data=magma.Out(magma.Bits(32)), # TODO: Make number of stall domains paramaterizable stall=magma.In(magma.Bits(4)) ) self.wire(self.ports.data0, self.underlying.ports.data0) self.wire(self.ports.data1, self.underlying.ports.data1) self.wire(self.ports.bit0[0], self.underlying.ports.bit0) self.wire(self.ports.bit1[0], self.underlying.ports.bit1) self.wire(self.ports.bit2[0], self.underlying.ports.bit2) self.wire(self.ports.res, self.underlying.ports.res) self.wire(self.ports.res_p, self.underlying.ports.res_p) self.wire(self.ports.config.config_addr, self.underlying.ports.cfg_a) self.wire(self.ports.config.config_data, self.underlying.ports.cfg_d) self.wire(self.ports.config.write[0], self.underlying.ports.cfg_en) self.wire(self.underlying.ports.read_data, self.ports.read_config_data) # TODO: Make PE core use active high reset self.wire(self.ports.reset, self.underlying.ports.rst_n) # PE core uses clk_en (essentially active low stall) self.stallInverter = FromMagma(mantle.DefineInvert(1)) self.wire(self.stallInverter.ports.I, self.ports.stall[0:1]) self.wire(self.stallInverter.ports.O[0], self.underlying.ports.clk_en)
def create_connect_box(): cb = m.DefineCircuit("connect_box", "operand0", m.In(m.Bits(1)), "operand1", m.In(m.Bits(1)), "result", m.Out(m.Bits(1)), "clk", m.In(m.Clock), "rst", m.In(m.Reset), "config_data", m.In(m.Bits(32)), "config_en", m.In(m.Bit)) # Configuration data config_reg = mantle.Register(32, init=0, has_ce=True, has_reset=True) m.wire(cb.config_data, config_reg.I) m.wire(cb.clk, config_reg.CLK) m.wire(cb.config_en, config_reg.CE) rst_inv = mantle.Invert(1) m.wire(rst_inv.I[0], cb.rst) m.wire(rst_inv.O[0], config_reg.RESET) # Operations in CB and_op = mantle.And(2, 1) m.wire(cb.operand0, and_op.I0) m.wire(cb.operand1, and_op.I1) or_op = mantle.Or(2, 1) m.wire(cb.operand0, or_op.I0) m.wire(cb.operand1, or_op.I1) xor_op = mantle.XOr(2, 1) m.wire(cb.operand0, xor_op.I0) m.wire(cb.operand1, xor_op.I1) not_op = mantle.Invert(1) m.wire(cb.operand0, not_op.I) # Config mux config_mux = mantle.Mux(height=4, width=1) m.wire(config_mux.O, cb.result) m.wire(config_mux.S, config_reg.O[0:2]) m.wire(and_op.O, config_mux.I0) m.wire(or_op.O, config_mux.I1) m.wire(xor_op.O, config_mux.I2) m.wire(not_op.O, config_mux.I3) return cb
def __init__(self, in_width, out_width): super().__init__() if out_width <= in_width: raise ValueError(f"output width must be greater than input width " f"(output width = {out_width}, input width = " f"{in_width})") self.in_width = in_width self.out_width = out_width self.add_ports( I=magma.In(magma.In(magma.Bits(self.in_width))), O=magma.Out(magma.Out(magma.Bits(self.out_width))), )
def __init__(self, width, num_tracks): super().__init__() self.width = width self.num_tracks = num_tracks core = PECoreGenerator(self.width) sb = SBGenerator(self.width, self.num_tracks, len(core.outputs())) self.add_features( core=core, sb=sb, ) for i in range(len(self.features.core.inputs())): cb = CBGenerator(self.width, self.num_tracks) self.add_feature(f"cb{i}", cb) T = magma.Array(self.num_tracks, magma.Bits(self.width)) self.add_ports( I=magma.In(T), O=magma.Out(T), ) self.wire(self.I, self.features.sb.I) for i in range(len(self.features.core.inputs())): cb = getattr(self.features, f"cb{i}") self.wire(self.I, cb.I) for i, core_in in enumerate(self.features.core.inputs()): cb = getattr(self.features, f"cb{i}") self.wire(cb.O, core_in) for i, core_out in enumerate(self.features.core.outputs()): self.wire(core_out, self.features.sb.core_in[i]) self.wire(self.features.sb.O, self.O)
def __init__(self): super().__init__() width = 16 num_tracks = 4 num_tiles = 10 T = magma.Array(num_tracks, magma.Bits(width)) self.tiles = [TileGenerator(width, num_tracks) \ for _ in range(num_tiles)] self.add_ports( I=magma.In(T), O=magma.Out(T), ) # for tile in self.tiles: # self.wire(self.config_addr, tile.config_addr) # self.wire(self.config_data, tile.config_data) self.wire(self.I, self.tiles[0].I) self.wire(self.tiles[-1].O, self.O) for i in range(1, len(self.tiles)): t0 = self.tiles[i - 1] t1 = self.tiles[i] self.wire(t0.O, t1.I)
def __init__(self, width, num_tracks, core_inputs): super().__init__() self.width = width self.num_tracks = num_tracks assert core_inputs == 1 self.core_inputs = core_inputs self.muxs = [MuxWrapper(self.num_tracks, self.width) \ for _ in range(self.num_tracks)] T = magma.Array(self.num_tracks, magma.Bits(self.width)) bits_per_sel = math.ceil(math.log(self.num_tracks, 2)) self.add_ports( I=magma.In(T), core_in=magma.In(magma.Array(self.core_inputs, T.T)), O=magma.Out(T), ) for i in range(self.num_tracks): self.add_config(f"sel_{i}", bits_per_sel) self.selects = [getattr(self, f"sel_{i}") \ for i in range(self.num_tracks)] for i in range(self.num_tracks): mux = self.muxs[i] for j in range(self.num_tracks): mux_in = self.I[j] if i != j else self.core_in[0] self.wire(mux_in, mux.I[j]) self.wire(self.selects[i], mux.S) self.wire(mux.O, self.O[i])
def top_to_tile(top, tile, tile_idx): tile.add_ports(tile_id=magma.In(magma.Bits(16))) top.wire(Const(magma.bits(tile_idx, 16)), tile.tile_id) tile_eq = FromMagma(mantle.DefineEQ(16)) tile.wire(tile.tile_id, tile_eq.I0) tile.wire(tile.config.config_addr[0:16], tile_eq.I1) return tile_eq
def __init__(self): super().__init__() width = 16 num_tracks = 4 num_tiles = 10 T = magma.Array(num_tracks, magma.Bits(width)) self.tiles = [] for i in range(num_tiles): if i % 2 == 0: core = PECoreGenerator(width) else: core = MemCoreGenerator(width) self.tiles.append(TileGenerator(width, num_tracks, core)) self.add_ports( I=magma.In(T), O=magma.Out(T), ) self.wire(self.I, self.tiles[0].I) self.wire(self.tiles[-1].O, self.O) for i in range(1, len(self.tiles)): t0 = self.tiles[i - 1] t1 = self.tiles[i] self.wire(t0.O, t1.I)
def __init__(self, width, num_tracks, core): super().__init__() self.width = width self.num_tracks = num_tracks self.core = core self.sb = SBGenerator(self.width, self.num_tracks, len(self.core.outputs())) self.cbs = [CBGenerator(self.width, self.num_tracks) \ for _ in range(len(self.core.inputs()))] T = magma.Array(self.num_tracks, magma.Bits(self.width)) self.add_ports( I=magma.In(T), O=magma.Out(T), ) self.wire(self.I, self.sb.I) for cb in self.cbs: self.wire(self.I, cb.I) for i, core_in in enumerate(self.core.inputs()): self.wire(self.cbs[i].O, core_in) for i, core_out in enumerate(self.core.outputs()): self.wire(core_out, self.sb.core_in[i]) self.wire(self.sb.O, self.O)
class LinkerTest(m.Circuit): name = "LinkerTest0" IO = [ "I0", m.In(m.Bits(width)), "I1", m.In(m.Bits(width)), "O", m.Out(m.Bits(width)) ] @classmethod def definition(self): Smax = DefineSmax(width=width) smax = Smax() m.wire(self.I0, smax.in0) m.wire(self.I1, smax.in1) m.wire(self.O, smax.out)
def SideType(num_tracks, layers): layers_dict = { f"layer{l}": magma.Array(num_tracks, magma.Bits(l)) for l in layers } T = magma.Tuple(**layers_dict) return magma.Tuple(I=magma.In(T), O=magma.Out(T))
def __init__(self, node: PortNode, config_addr_width: int, config_data_width: int): if not isinstance(node, PortNode): raise ValueError(node, PortNode.__name__) super().__init__(config_addr_width, config_data_width) self.node: PortNode = node self.mux = create_mux(self.node) # lift the port to the top level self.add_ports(I=self.mux.ports.I.base_type(), O=self.mux.ports.O.base_type()) self.wire(self.ports.I, self.mux.ports.I) self.wire(self.ports.O, self.mux.ports.O) if self.mux.height > 1: self.add_ports( config=magma.In( ConfigurationType(config_addr_width, config_data_width)), read_config_data=magma.Out(magma.Bits(config_data_width)), ) config_name = get_mux_sel_name(self.node) self.add_config(config_name, self.mux.sel_bits) self.wire(self.registers[config_name].ports.O, self.mux.ports.S) self._setup_config()
def counter(context, values, module_def): print("Running magma generator") width = values['width'].value has_en = values['has_en'].value IO_ = ["out", m.Out(m.Bits(width)), "clk", m.In(m.Clock)] if has_en: IO_ += ["en", m.In(m.Bit)] class MyCounter(m.Circuit): name = f"MyCounter_{width}_{has_en}" IO = IO_ @classmethod def definition(cls): counter = mantle.Counter(width, has_ce=has_en) m.wire(counter.O, cls.out) m.wire(counter.CLK, cls.clk) if has_en: m.wire(counter.CE, cls.en) import magma.backend.coreir_ as coreir_backend coreir_backend.CoreIRBackend(context).compile_dependencies(MyCounter) coreir_backend.CoreIRBackend( context).compile_definition_to_module_definition( MyCounter, module_def)
def test_shift_register(): N = 4 Register4 = DefineRegister(4) T = m.Bits(N) class ShiftRegister(m.Circuit): name = "ShiftRegister" IO = ["I", m.In(T), "O", m.Out(T), "CLK", m.In(m.Clock)] @classmethod def definition(io): regs = [Register4() for _ in range(N)] m.wire(io.I, regs[0].I) m.fold(regs, foldargs={"I": "O"}) m.wire(regs[-1].O, io.O) simulator = PythonSimulator(ShiftRegister, clock=ShiftRegister.CLK) expected = [0, 0, 0] + list(range(0, 1 << N, 3))[:-3] actual = [] for i in range(0, 1 << N, 3): simulator.set_value(ShiftRegister.I, i) simulator.advance(2) actual.append(simulator.get_value(ShiftRegister.O)) assert actual == expected m.compile("build/ShiftRegister", ShiftRegister, output="coreir") assert m.testing.check_files_equal(__file__, "build/ShiftRegister.json", "gold/ShiftRegister.json")
def __init__(self, columns): super().__init__() assert all([c.height == columns[0].height for c in columns]) self.width = len(columns) self.height = columns[0].height self.columns = columns self.side_type = SideType(5, (1, 16)) self.add_ports( north=magma.Array(self.width, self.side_type), south=magma.Array(self.width, self.side_type), west=magma.Array(self.height, self.side_type), east=magma.Array(self.height, self.side_type), config=magma.In(ConfigurationType(32, 32)), clk=magma.In(magma.Clock), reset=magma.In(magma.AsyncReset), read_config_data=magma.Out(magma.Bits(32)), # TODO: make number of stall domains a param stall=magma.In(magma.Bits(4))) for column in self.columns: self.wire(self.ports.config, column.ports.config) self.wire(self.ports.reset, column.ports.reset) self.wire(self.ports.stall, column.ports.stall) self.wire(self.ports.west, self.columns[0].ports.west) self.wire(self.ports.east, self.columns[-1].ports.east) for i, column in enumerate(self.columns): self.wire(self.ports.north[i], column.ports.north) self.wire(self.ports.south[i], column.ports.south) for i in range(1, self.width): c0 = self.columns[i - 1] c1 = self.columns[i] for j in range(self.height): self.wire(c1.ports.west[j].O, c0.ports.east[j].I) self.wire(c0.ports.east[j].O, c1.ports.west[j].I) # OR together read_data outputs from each column # number of inputs = number of columns self.read_data_OR = FromMagma(mantle.DefineOr(len(self.columns), 32)) for i, col in enumerate(columns): self.wire(self.read_data_OR.ports[f"I{i}"], col.ports.read_config_data) # wire up column number input self.wire(col.ports.column_num, Const(magma.bits(i, 8))) self.wire(self.read_data_OR.ports.O, self.ports.read_config_data)