class _ConfigRegister(magma.Circuit): name = f"ConfigRegister_{width}_{addr_width}_{data_width}_{addr}" ports = { "clk": magma.In(magma.Clock), "reset": magma.In(magma.AsyncReset), "O": magma.Out(T), "config_addr": magma.In(magma.Bits[addr_width]), "config_data": magma.In(magma.Bits[data_width]), } if use_config_en: ports["config_en"] = magma.In(magma.Bit) io = magma.IO(**ports) reg = magma.Register(magma.Bits[width], has_enable=True, reset_type=magma.AsyncReset)() magma.wire(io.clk, reg.CLK) ce = (io.config_addr == magma.bits(addr, addr_width)) magma.wire(io.reset, reg.ASYNCRESET) if use_config_en: ce = ce & io.config_en magma.wire(io.config_data[0:width], reg.I) magma.wire(magma.enable(ce), reg.CE) magma.wire(reg.O, io.O)
def __init__(self, length: int, fanout: int = 0): self.io = m.IO(I=m.In(m.Bit), O=m.Out(m.Bit)) self.io += m.IO( **{f"fanout_{i}": m.Out(m.Bit) for i in range(length * fanout)}) index = 0 curr = self.io.I for _ in range(length): curr = ~curr for _ in range(fanout): out = getattr(self.io, f"fanout_{index}") out @= curr index += 1 self.io.O @= curr
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.Bits[self.in_width]), O=magma.Out(magma.Bits[self.out_width]), )
class SimpleALU(m.Circuit): name = "SimpleALU" IO = [ "a", m.In(m.UInt(4)), "b", m.In(m.UInt(4)), "opcode", m.In(m.UInt(2)), "out", m.Out(m.UInt(4)) ] @classmethod def definition(io): is_op0 = io.opcode == m.uint(0, n=2) is_op1 = io.opcode == m.uint(1, n=2) is_op2 = io.opcode == m.uint(2, n=2) is_op3 = io.opcode == m.uint(3, n=2) op0_out = io.a + io.b op1_out = io.a - io.b op2_out = io.a op3_out = io.b m.wire( io.out, one_hot_mux([is_op0, is_op1, is_op2, is_op3], [op0_out, op1_out, op2_out, op3_out]))
def test_ram(): main = m.DefineCircuit("main", "rdata", m.Out(m.Bit), "CLKIN", m.In(m.Clock)) ram = mantle.RAM(4, 1) waddr = mantle.Counter(4) wdata = mantle.Counter(1) we = 1 raddr = mantle.FF()(mantle.Counter(4)) ram(raddr, waddr, wdata, we, CLK=main.CLKIN) m.wire(ram.RDATA, main.rdata) m.EndDefine() m.compile("build/test_common_ram", main)
def __init__(self, width): super().__init__() self.width = width self.impl = FromVerilog("experimental/simple_cgra/tiny_mem_core.v") T = magma.Bits(self.width) self.add_ports( I=magma.In(T), O=magma.Out(T), ) self.add_configs(wr_en=1, ) self.wire(self.I, self.impl.in_) self.wire(self.wr_en, self.impl.wr_en) self.wire(self.impl.out, self.O)
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)
class TestNestedClockTuple(m.Circuit): IO = [ "I", m.In(m.Tuple(clk1=m.Clock, clk2=m.Clock, i=m.Bit)), "O", m.Out(m.Bits(2)) ] @classmethod def definition(io): ff0 = mantle.FF() ff1 = mantle.FF() m.wire(io.I.clk1, ff0.CLK) m.wire(io.I.clk2, ff1.CLK) m.wire(io.I.i, ff0.I) m.wire(io.I.i, ff1.I) m.wire(m.bits([ff0.O, ff1.O]), io.O)
def clk_physical(interconnect: Interconnect): for (x, y) in interconnect.tile_circuits: tile = interconnect.tile_circuits[(x, y)] tile_core = tile.core # We only want to do this on PE and memory tiles if tile_core is None or isinstance(tile_core, IOCoreBase): continue elif isinstance(tile_core, MemCore): if (x, y + 1) in interconnect.tile_circuits: tile_below = interconnect.tile_circuits[(x, y + 1)] if "clk" in tile_below.ports: interconnect.remove_wire(tile.ports.clk_out, tile_below.ports.clk) # Get the PE tile to the left of this mem tile tile_left = interconnect.tile_circuits[(x - 1, y)] # Connect the clk input of this mem tile to the right clk # output of the neighboring PE tile interconnect.wire(tile_left.ports.clk_pass_through_out_right, tile.ports.clk) else: orig_in_port = tile.ports.clk orig_out_port = tile.ports.clk_out # Remove the pass through connection that already exists tile.remove_wire(orig_in_port, orig_out_port) # Create a new pass through clock input tile.add_port("clk_pass_through", magma.In(magma.Clock)) pass_through_input = tile.ports.clk_pass_through # Create 2 new clk pass through outputs (bottom and right) tile.add_port("clk_pass_through_out_bot", magma.Out(magma.Clock)) tile.add_port("clk_pass_through_out_right", magma.Out(magma.Clock)) tile.wire(tile.ports.clk_pass_through, tile.ports.clk_pass_through_out_bot) tile.wire(tile.ports.clk_pass_through, tile.ports.clk_pass_through_out_right) # Connect new clk pass through input to old pass through output tile.wire(pass_through_input, orig_out_port) # For top row tiles, connect new clk input to global clock if y < 2: interconnect.wire(interconnect.ports.clk, pass_through_input) # For other tiles, connect new clk input to # pass through output of tile above. else: tile_above = interconnect.tile_circuits[(x, y - 1)] interconnect.wire(tile_above.ports.clk_pass_through_out_bot, pass_through_input)
def __init__(self, wordWidth: int, metricWidth: int, idx: int): self.io = io = m.IO( inputFeatureOne=m.In(m.UInt[wordWidth]), inputFeatureTwo=m.In(m.UInt[wordWidth]), inputMetric=m.In(m.UInt[metricWidth]), inputValid=m.In(m.Bit), shiftMode=m.In( m.Bit ), # one cycle pause required between last inputValid and start of shiftMode doShift=m.In(m.Bit), neighborOutputIn=m.In(m.UInt[64]), out=m.Out(m.UInt[64])) + m.ClockIO(has_reset=True) ram_size = 1 << (2 * wordWidth) bram = PairMem(ram_size)() lastFeatureOne = reg_next(io.inputFeatureOne) lastFeatureTwo = reg_next(io.inputFeatureTwo) lastMetric = reg_next(io.inputMetric) lastInputValid = reg_next_init(io.inputValid, False) if idx >= 800 and idx < 2479: # BRAM lastWrite = reg_next(bram.WDATA) collision = reg_next((bram.RADDR == bram.WADDR) & bram.WEN) readData = m.mux([bram.RDATA, lastWrite], collision) else: readData = bram.RDATA outputCounter = reg_init(m.UInt[2 * wordWidth], 0) io.out @= bram.RDATA @m.inline_combinational() def logic(): if io.doShift: outputCounter.I @= outputCounter.O + 1 # wraps around else: outputCounter.I @= outputCounter.O # default required if io.shiftMode: bram.RADDR @= outputCounter.O + 1 if io.doShift else outputCounter.O bram.WDATA @= io.neighborOutputIn bram.WADDR @= outputCounter.O bram.WE @= io.doShift else: bram.RADDR @= io.inputFeatureTwo.concat(io.inputFeatureOne) bram.WDATA @= ( readData[:32] + m.zext_to(lastMetric, 32)).concat(readData[32:] + 1) bram.WADDR @= lastFeatureTwo.concat(lastFeatureOne) bram.WE @= lastInputValid
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") 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() 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)
class Register(m.Circuit): name = f"Register__has_ce_{has_ce}__has_reset_{has_reset}__" \ f"has_async_reset__{has_async_reset}__" \ f"type_{_type.__name__}__n_{n}" IO = ["I", m.In(T), "O", m.Out(T)] IO += m.ClockInterface(has_ce=has_ce, has_reset=has_reset, has_async_reset=has_async_reset) @classmethod def definition(io): reg = DefineCoreirReg(n, init, has_async_reset, _type)() I = io.I if has_reset: I = mantle.mux([io.I, m.bits(init, n)], io.RESET) if has_ce: I = mantle.mux([reg.O, I], io.CE) m.wire(I, reg.I) m.wire(io.O, reg.O)
def __init__(self, peak_generator): super().__init__(8, 32) self.wrapper = _PeakWrapper(peak_generator) # Generate core RTL (as magma). self.peak_circuit = FromMagma(self.wrapper.rtl()) # Add input/output ports and wire them. inputs = self.wrapper.inputs() outputs = self.wrapper.outputs() for ports, dir_ in ( (inputs, magma.In), (outputs, magma.Out), ): for i, (name, typ) in enumerate(ports.items()): magma_type = _convert_type(typ) self.add_port(name, dir_(magma_type)) my_port = self.ports[name] if magma_type is magma.Bits[1]: my_port = my_port[0] magma_name = name if dir_ is magma.In else f"O{i}" self.wire(my_port, self.peak_circuit.ports[magma_name]) self.add_ports(config=magma.In(ConfigurationType(8, 32)), ) # TODO(rsetaluri): Figure out stall signals. # Set up configuration for PE instruction. Currently, we perform a naive # partitioning of the large instruction into 32-bit config registers. config_width = self.wrapper.instruction_width() num_config = math.ceil(config_width / 32) instr_name = self.wrapper.instruction_name() for i in range(num_config): name = f"{instr_name}_{i}" self.add_config(name, 32) lb = i * 32 ub = min(i * 32 + 32, config_width) len_ = ub - lb self.wire(self.registers[name].ports.O[:len_], self.peak_circuit.ports[instr_name][lb:ub]) self._setup_config()
def test_spice_bus(target, simulator, vsup=1.5): # declare circuit dut = m.DeclareCircuit('mybus', 'a', m.In(m.Bits[2]), 'b', m.Out(m.Bits[3]), 'vdd', m.BitIn, 'vss', m.BitIn) # define the test tester = fault.Tester(dut) tester.poke(dut.vdd, 1) tester.poke(dut.vss, 0) # step through all possible inputs tester.poke(dut.a, 0b000) tester.expect(dut.b, 0b101) tester.poke(dut.a, 0b001) tester.expect(dut.b, 0b100) tester.poke(dut.a, 0b010) tester.expect(dut.b, 0b111) tester.poke(dut.a, 0b011) tester.expect(dut.b, 0b110) # test one bit of the bus at a time tester.poke(dut.a[0], 0) tester.expect(dut.b[0], 1) tester.poke(dut.a[0], 1) tester.expect(dut.b[0], 0) tester.expect(dut.b[2], 1) tester.poke(dut.a[1], 0) tester.expect(dut.b[1], 0) tester.poke(dut.a[1], 1) tester.expect(dut.b[1], 1) tester.expect(dut.b[2], 1) # set options kwargs = dict(target=target, simulator=simulator, model_paths=[Path('tests/spice/mybus.sp').resolve()], vsup=vsup, tmp_dir=True) # run the simulation tester.compile_and_run(**kwargs)
def DefineCounter(n, cin=False, cout=True, incr=1, has_ce=False, has_reset=False): """ Create an n-bit counter with a given increment. O : m.Out(m.UInt(n)), COUT : m.Out(m.Bit) """ name_ = counter_name(f'Counter{n}', incr, has_ce, has_reset, cin, cout) args = {} if cin: args["CIN"] = m.In(m.Bit) args["O"] = m.Out(m.UInt[n]) if cout: args["COUT"] = m.Out(m.Bit) class _Counter(m.Circuit): name = name_ io = m.IO(**args) io += m.ClockIO(has_ce, has_reset) add = DefineAdd(n, cin=cin, cout=cout)() reg = Register(n, has_ce=has_ce, has_reset=has_reset) m.wire(reg.O, add.I0) m.wire(m.array(incr, n), add.I1) reg(add.O) next = False if next: m.wire(add.O, io.O) else: m.wire(reg.O, io.O) if cin: m.wire(io.CIN, add.CIN) if cout: m.wire(add.COUT, io.COUT) return _Counter
def test_ram(): main = m.DefineCircuit("main", "rdata", m.Out(m.Bit), "CLKIN", m.In(m.Clock)) ram = mantle.RAM(4, 1) waddr = mantle.Counter(4, cout=False) wdata = mantle.Counter(1, cout=False) we = 1 raddr = mantle.Counter(4, 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" else: output = "verilog" m.compile("build/test_common_ram", main, output)
class TestCircuit(m.Circuit): name = _name IO = ["I", m.In(in_T), "O0", out_T, "O1", out_T] @classmethod def definition(io): # Test using the method directly res = getattr(mantle, op.name)(io.I) assert isinstance(res, expected_res_type), type(res) m.wire(res, io.O0) # Test using the operator if it exists, otherwise wire 0 to O1 if op.operator is None or (op.name in ["sub", "add"] + comparisons and T == m.Bits): if op.name in comparisons: m.wire(0, io.O1) else: m.wire(m.bits(0, N), io.O1) else: res_operator = eval(f"{op.operator} io.I") m.wire(res_operator, io.O1)
def test_ext_vlog(target, simulator): # declare circuit mybuf_inc_test = m.DeclareCircuit( 'mybuf_inc_test', 'in_', m.In(m.Bit), 'out', m.Out(m.Bit) ) # define the test tester = fault.BufTester(mybuf_inc_test) # run the test tester.compile_and_run( target=target, simulator=simulator, ext_libs=[Path('tests/verilog/mybuf_inc_test.v').resolve()], inc_dirs=[Path('tests/verilog').resolve()], ext_model_file=True, tmp_dir=True )
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, node: PortNode, config_addr_width: int, config_data_width: int, double_buffer: bool = False): if not isinstance(node, PortNode): raise ValueError(node, PortNode.__name__) self.node: PortNode = node super().__init__(config_addr_width, config_data_width, double_buffer=double_buffer) 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)), ) 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) else: # remove clk and reset ports from the base class since it's going # to be a pass through wire anyway self.ports.pop("clk") self.ports.pop("reset") self.ports.pop("read_config_data") if self.double_buffer: self.ports.pop("use_db") self.ports.pop("config_db") self._setup_config() self.instance_name = self.name()
def wrap_with_disassembler(PE, disassembler, width, layout, inst_type): WrappedIO = [] for key, value in PE.interface.ports.items(): WrappedIO.append(key) if type(value) == m.Out(inst_type): WrappedIO.append(m.In(m.Bits[width])) else: WrappedIO.append(m.Flip(type(value))) def wire_inst_fields(wrapper_inst, pe_inst, layout): if isinstance(wrapper_inst, m.Product): for key, value in layout.items(): begin = value[0] end = value[1] wire_inst_fields(wrapper_inst[begin:end], getattr(pe_inst, key), value[2]) else: for key, value in layout.items(): begin = value[0] end = value[1] region = wrapper_inst[begin:end] field = getattr(pe_inst, key) if isinstance(type(field), m._BitKind): region = m.bit(region) m.wire(region, field) class WrappedPE(m.Circuit): IO = WrappedIO @classmethod def definition(io): pe = PE() for key, value in PE.interface.ports.items(): if type(value) == m.Out(inst_type): wire_inst_fields(getattr(io, key), getattr(pe, key), layout) elif value.isoutput(): getattr(pe, key) <= getattr(io, key) else: getattr(io, key) <= getattr(pe, key) return WrappedPE
def __init__(self, width, num_tracks): super().__init__() self.width = width self.num_tracks = num_tracks is_power_of_two = lambda x: x != 0 and ((x & (x - 1)) == 0) assert is_power_of_two(self.num_tracks) self.mux = MuxWrapper(self.num_tracks, self.width) T = magma.Bits(self.width) sel_bits = magma.bitutils.clog2(self.num_tracks) self.add_ports( I=magma.In(magma.Array(self.num_tracks, T)), O=magma.Out(T), ) self.add_configs(sel=sel_bits, ) self.wire(self.I, self.mux.I) self.wire(self.sel, self.mux.S) self.wire(self.mux.O, self.O)
def __init__(self, width, num_tracks): super().__init__() self.width = width self.num_tracks = num_tracks is_power_of_two = lambda x: x != 0 and ((x & (x - 1)) == 0) assert is_power_of_two(self.num_tracks) self.mux = FromMagma(mantle.DefineMux(self.num_tracks, self.width)) T = magma.Bits(self.width) sel_bits = math.ceil(math.log(self.num_tracks, 2)) self.add_ports( I=magma.In(magma.Array(self.num_tracks, T)), O=magma.Out(T), ) self.add_configs(sel=sel_bits, ) for i in range(self.num_tracks): self.wire(self.I[i], getattr(self.mux, f"I{i}")) self.wire(self.sel, self.mux.S) self.wire(self.mux.O, self.O)
def test_vams_wrap(): # declare the circuit class myblk(m.Circuit): io = m.IO(a=RealIn, b=RealOut, c=m.In(m.Bit), d=m.Out(m.Bits[2]), e=ElectIn, f=ElectOut) wrap_circ = VAMSWrap(myblk) # check magma representation of wrapped circuit assert wrap_circ.IO.ports['a'] is RealIn assert wrap_circ.IO.ports['b'] is RealOut assert wrap_circ.IO.ports['c'] is m.In(m.Bit) assert wrap_circ.IO.ports['d'] is m.Out(m.Bits[2]) assert wrap_circ.IO.ports['e'] is ElectIn assert wrap_circ.IO.ports['f'] is ElectOut # check Verilog-AMS code itself assert wrap_circ.vams_code == '''\
def wrap_with_disassembler(PE, disassembler, width, layout, inst_type): WrappedIO = OrderedDict() for key, value in PE.interface.ports.items(): if isinstance(value, m.Out(inst_type)): vtype = m.In(m.Bits[width]) else: vtype = m.Flip(type(value)) WrappedIO[key] = vtype def wire_inst_fields(wrapper_inst, pe_inst, layout): if isinstance(wrapper_inst, m.Product): for key, value in layout.items(): begin = value[0] end = value[1] wire_inst_fields(wrapper_inst[begin:end], getattr(pe_inst, key), value[2]) else: for key, value in layout.items(): begin = value[0] end = value[1] region = wrapper_inst[begin:end] field = getattr(pe_inst, key) if issubclass(type(field), m.Digital): region = m.bit(region) m.wire(region, field) class WrappedPE(m.Circuit): io = m.IO(**WrappedIO) pe = PE() for key, value in PE.interface.ports.items(): if type(value) == m.Out(inst_type): wire_inst_fields(getattr(io, key), getattr(pe, key), layout) elif value.is_output(): m.wire(getattr(pe, key), getattr(io, key)) else: m.wire(getattr(io, key), getattr(pe, key)) return WrappedPE
class dut(m.Circuit): name = 'test_analog_slice' io = m.IO( chunk=m.In(m.Bits[CFG['chunk_width']]), chunk_idx=m.In(m.Bits[int(ceil(log2(CFG['num_chunks'])))]), pi_ctl=m.In(m.Bits[CFG['pi_ctl_width']]), slice_offset=m.In(m.Bits[int(ceil(log2(CFG['slices_per_bank'])))]), sample_ctl=m.BitIn, incr_sum=m.BitIn, write_output=m.BitIn, out_sgn=m.BitOut, out_mag=m.Out(m.Bits[CFG['n_adc']]), clk=m.BitIn, rst=m.BitIn, jitter_rms=fault.RealIn, noise_rms=fault.RealIn, wdata0=m.In(m.Bits[func_widths[0]]), wdata1=m.In(m.Bits[func_widths[1]]), waddr=m.In(m.Bits[9]), we=m.BitIn )
def test_val(): """ Test instances of Bits[4] work correctly """ bits_4_in = m.In(m.Bits[4]) bits_4_out = m.Out(m.Bits[4]) assert m.Flip(bits_4_in) == bits_4_out assert m.Flip(bits_4_out) == bits_4_in a_0 = bits_4_out(name='a0') print(a_0) a_1 = bits_4_in(name='a1') print(a_1) a_1.wire(a_0) b_0 = a_1[0] assert b_0 is a_1[0], "getitem failed" a_3 = a_1[0:2] assert a_3 == a_1[0:2], "getitem of slice failed"
def AXI4SlaveType(addr_width, data_width): """ This function returns a axi4-slave class (parameterized by @addr_width and @data_width) which can be used as the magma ports with these inputs and outputs Below is AXI4-Lite interface ports in verilog input logic [`$cfg_addr_width-1`:0] AWADDR, input logic AWVALID, output logic AWREADY, input logic [`$cfg_bus_width-1`:0] WDATA, input logic WVALID, output logic WREADY, input logic [`$cfg_bus_width-1`:0] ARADDR, input logic ARVALID, output logic ARREADY, output logic [`$cfg_bus_width-1`:0] RDATA, output logic [1:0] RRESP, output logic RVALID, input logic RREADY, output logic interrupt, """ _AXI4SlaveType = magma.Tuple(awaddr=magma.In(magma.Bits[addr_width]), awvalid=magma.In(magma.Bit), awready=magma.Out(magma.Bit), wdata=magma.In(magma.Bits[data_width]), wvalid=magma.In(magma.Bit), wready=magma.Out(magma.Bit), araddr=magma.In(magma.Bits[addr_width]), arvalid=magma.In(magma.Bit), arready=magma.Out(magma.Bit), rdata=magma.Out(magma.Bits[data_width]), rresp=magma.Out(magma.Bits[2]), rvalid=magma.Out(magma.Bit), rready=magma.In(magma.Bit), interrupt=magma.Out(magma.Bit)) return _AXI4SlaveType
class RAM(m.Circuit): io = m.IO( RADDR=m.In(m.Bits[addr_width]), RDATA=m.Out(m.Bits[data_width]), WADDR=m.In(m.Bits[addr_width]), WDATA=m.In(m.Bits[data_width]), WE=m.In(m.Bit), CLK=m.In(m.Clock), RESET=m.In(m.Reset) ) regs = [mantle.Register(data_width, init=int(init[i]), has_ce=True, has_reset=True) for i in range(1 << addr_width)] for i, reg in enumerate(regs): reg.I <= io.WDATA reg.CE <= (io.WADDR == m.bits(i, addr_width)) & io.WE io.RDATA <= mantle.mux([reg.O for reg in regs], io.RADDR)
def apply_global_parallel_meso_wiring(interconnect: Interconnect, io_sides: IOSide, num_cfg: int = 1): interconnect_read_data_or = apply_global_meso_wiring(interconnect, io_sides) # interconnect must have config port assert "config" in interconnect.ports # there must be at least one configuration path assert num_cfg >= 1 interconnect.remove_port("config") # this is not a typo. Total number of bits in configuration address # is same as config_data config_data_width = interconnect.config_data_width interconnect.add_port( "config", magma.In(magma.Array[num_cfg, ConfigurationType(config_data_width, config_data_width)])) cgra_width = interconnect.x_max - interconnect.x_min + 1 # number of CGRA columns one configuration controller is in charge of col_per_config = math.ceil(cgra_width / num_cfg) # looping through on a per-column bases for x_coor in range(interconnect.x_min, interconnect.x_max + 1): column = interconnect.get_column(x_coor) # skip tiles with no config column = [entry for entry in column if "config" in entry.ports] # select which configuration controller is connected to that column config_sel = int(x_coor/col_per_config) # wire configuration ports to first tile in column interconnect.wire(interconnect.ports.config[config_sel], column[0].ports.config) return interconnect_read_data_or