def main(ninputs, noutputs, input_isbits=True, output_isbits=True, has_clock=False): assert 0 <= ninputs <= 8 assert 0 <= noutputs <= 8 print(m.mantle_target) if m.mantle_target == 'ice40': from loam.boards.icestick import IceStick icestick = IceStick() if has_clock: icestick.Clock.on() for i in range(ninputs): icestick.J1[i].input().on() for i in range(noutputs): icestick.J3[i].output().on() top = icestick.main() if ninputs: top.I = top.J1 if noutputs: top.O = top.J3 elif m.mantle_target == 'spartan3' or m.mantle_target == 'spartan6': from loam.boards.papilioone import PapilioOne from loam.boards.papiliopro import PapilioPro from loam.shields.megawing import MegaWing Papilio = PapilioOne if m.mantle_target == 'spartan3' else PapilioPro megawing = MegaWing(Papilio) if has_clock: megawing.Clock.on() megawing.Switch.on(ninputs) megawing.LED.on(noutputs) top = megawing.main() if ninputs: top.I = top.SWITCH if noutputs: top.O = top.LED else: raise ValueError(m.mantle_target) if ninputs == 1 and input_isbits: top.I = m.bits([top.I]) if noutputs == 1 and output_isbits: top.O = m.bits([top.O]) return top
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 Register(m.Circuit): name = f"Register_has_ce_{has_ce}_has_reset_{has_reset}_" \ f"has_async_reset_{has_async_reset}_" \ f"has_async_resetn_{has_async_resetn}_" \ f"type_{_type.__name__}_n_{n}" io = m.IO(I=m.In(T), O=m.Out(T)) io += m.ClockIO(has_ce=has_ce, has_reset=has_reset, has_async_reset=has_async_reset, has_async_resetn=has_async_resetn) reg = DefineCoreirReg(n, init, has_async_reset, has_async_resetn, _type)(name="value") I = io.I O = reg.O if n is None: O = O[0] if has_reset and has_ce: if reset_priority: I = mantle.mux([O, I], io.CE, name="enable_mux") I = mantle.mux([I, m.bits(init, n)], io.RESET) else: I = mantle.mux([I, m.bits(init, n)], io.RESET) I = mantle.mux([O, I], io.CE, name="enable_mux") elif has_ce: I = mantle.mux([O, I], io.CE, name="enable_mux") elif has_reset: I = mantle.mux([I, m.bits(init, n)], io.RESET) if n is None: m.wire(I, reg.I[0]) else: m.wire(I, reg.I) m.wire(io.O, O)
def _data_gate_inst(inst, make_gate=None): if make_gate is None: def make_gate(_): out_insts = _get_connected(inst.O) if len(out_insts) == 0 or not all(map(_is_mux, out_insts)): return None selects = [inst.S.value() for inst in out_insts] assert all(isinstance(s, m.Bit) for s in selects) return functools.reduce(operator.or_, selects[1:], selects[0]) a = inst.I0.value() b = inst.I1.value() if a is None or b is None: return defn = inst.defn with defn.open(): gate = make_gate(defn) if gate is None: return assert isinstance(gate, m.Bit) inst.I0.unwire(a) inst.I1.unwire(b) inst.I0 @= a & m.bits(len(a) * [gate]) inst.I1 @= b & m.bits(len(b) * [gate])
def __init__(self, x_len): super().__init__(x_len) inst = self.io.inst Iimm = m.sext_to(m.sint(inst[20:32]), x_len) Simm = m.sext_to(m.sint(m.concat(inst[7:12], inst[25:32])), x_len) Bimm = m.sext_to( m.sint( m.concat(m.bits(0, 1), inst[8:12], inst[25:31], inst[7], inst[31])), x_len) Uimm = m.concat(m.bits(0, 12), inst[12:32]) Jimm = m.sext_to( m.sint( m.concat(m.bits(0, 1), inst[21:25], inst[25:31], inst[20], inst[12:20], inst[31])), x_len) Zimm = m.sint(m.zext_to(inst[15:20], x_len)) self.io.O @= m.uint( m.dict_lookup( { IMM_I: Iimm, IMM_S: Simm, IMM_B: Bimm, IMM_U: Uimm, IMM_J: Jimm, IMM_Z: Zimm }, self.io.sel, Iimm & -2))
def definition(io): edge_r = rising(io.SCK) edge_f = falling(io.SCK) # pixels come 16 bits (high and low byte) at a time bit_counter = mantle.Counter(4, has_ce=True, has_reset=True) m.wire(edge_r, bit_counter.CE) # find when the high and low byte are valid low = mantle.Decode(15, 4)(bit_counter.O) high = mantle.Decode(7, 4)(bit_counter.O) # shift registers to store high and low byte low_byte = mantle.PIPO(8, has_ce=True) high_byte = mantle.PIPO(8, has_ce=True) low_byte(0, io.DATA, low) high_byte(0, io.DATA, high) m.wire(low, low_byte.CE) m.wire(high, high_byte.CE) # assemble the 16-bit RGB565 value px_bits = (m.uint(mantle.LSL(16)((m.uint(m.concat(high_byte.O, zeros))), m.bits(8, 4))) + m.uint(m.concat(low_byte.O, zeros))) # extract the values for each color r_val = m.uint(mantle.LSR(16)((px_bits & RMASK), m.bits(11, 4))) g_val = m.uint(mantle.LSR(16)((px_bits & GMASK), m.bits(5, 4))) b_val = m.uint(px_bits & BMASK) # sum them to get grayscale (0 to 125) px_val = (r_val + g_val + b_val) # --------------------------UART OUTPUT---------------------------- # # run 16-bit UART at 2x speed baud = edge_r | edge_f # reset at start of pixel transfer ff1 = mantle.FF(has_ce=True) m.wire(baud, ff1.CE) u_reset = mantle.LUT2(I0 & ~I1)(io.VALID, ff1(io.VALID)) m.wire(u_reset, bit_counter.RESET) # generate load signal ff2 = mantle.FF(has_ce=True) m.wire(baud, ff2.CE) load = mantle.LUT3(I0 & I1 & ~I2)(io.VALID, high, ff2(high)) uart = UART(16) uart(CLK=io.CLK, BAUD=baud, DATA=px_val, LOAD=load) m.wire(px_val, io.PXV) m.wire(uart, io.UART) m.wire(load, io.LOAD)
def __init__(self, T, entries, pipe=False, flow=False): assert entries >= 0 self.io = m.IO( # Flipped since enq/deq is from perspective of the client enq=m.DeqIO[T], deq=m.EnqIO[T], count=m.Out(m.UInt[m.bitutils.clog2(entries + 1)])) + m.ClockIO() ram = m.Memory(entries, T)() enq_ptr = mantle.CounterModM(entries, entries.bit_length(), has_ce=True, cout=False) deq_ptr = mantle.CounterModM(entries, entries.bit_length(), has_ce=True, cout=False) maybe_full = m.Register(init=False, has_enable=True)() ptr_match = enq_ptr.O == deq_ptr.O empty = ptr_match & ~maybe_full.O full = ptr_match & maybe_full.O self.io.deq.valid @= ~empty self.io.enq.ready @= ~full do_enq = self.io.enq.fired() do_deq = self.io.deq.fired() ram.write(self.io.enq.data, enq_ptr.O[:-1], m.enable(do_enq)) enq_ptr.CE @= m.enable(do_enq) deq_ptr.CE @= m.enable(do_deq) maybe_full.I @= m.enable(do_enq) maybe_full.CE @= m.enable(do_enq != do_deq) self.io.deq.data @= ram[deq_ptr.O[:-1]] if flow: raise NotImplementedError() if pipe: raise NotImplementedError() def ispow2(n): return (n & (n - 1) == 0) and n != 0 count_len = len(self.io.count) if ispow2(entries): self.io.count @= m.mux([m.bits(0, count_len), entries], maybe_full.O & ptr_match) else: ptr_diff = enq_ptr.O - deq_ptr.O self.io.count @= m.mux([ m.mux([m.bits(0, count_len), entries], maybe_full.O), m.mux([ptr_diff, entries + ptr_diff], deq_ptr.O > enq_ptr.O) ], ptr_match)
def definition(io): Is = [io.I[i] for i in range(n)] muxes = map_(Mux(2), n) for i in range(n): shifti = i - k I = bits([Is[i], Is[shifti] if shifti >= 0 else io.SI]) muxes[i]( I, io.S ) for i in range(n): Is[i] = muxes[i].O wire(bits(Is), io.O)
def execute_alu(a: m.UInt(16), b: m.UInt(16), config: m.Bits(2)) -> (m.UInt(16),): if config == m.bits(0, 2): c = a + b elif config == m.bits(1, 2): c = a - b elif config == m.bits(2, 2): c = a * b else: c = m.bits(0, 16) return (c,)
def txmod_logic( data: m.Bits(8), writing: m.Bit, valid: m.Bit, dataStore: m.Bits(11), writeClock: m.Bits(14), writeBit: m.Bits(4), ) -> ( m.Bit, m.Bits(11), m.Bits(14), m.Bits(4), m.Bit, ): if (writing == m.bit(0)) & (valid == m.bit(1)): writing_out = m.bit(1) dataStore_out = m.concat(dataStore[0:1], data, dataStore[9:]) writeClock_out = m.bits(100, 14) writeBit_out = m.bits(0, 4) TXReg_out = dataStore[0] elif (writing == m.bit(1)) & \ (writeClock == m.bits(0, 14)) & \ (writeBit == m.bits(9, 4)): dataStore_out = dataStore writeClock_out = writeClock writeBit_out = writeBit TXReg_out = m.bit(1) writing_out = m.bit(0) elif (writing == m.bit(1)) & (writeClock == m.bits(0, 14)): writing_out = writing dataStore_out = dataStore TXReg_out = dataStore[writeBit] writeBit_out = m.bits(m.uint(writeBit) + m.bits(1, 4)) writeClock_out = m.bits(100, 14) elif writing == m.bit(1): writing_out = writing dataStore_out = dataStore writeBit_out = writeBit TXReg_out = dataStore[writeBit] writeClock_out = m.bits(m.uint(writeClock) - m.bits(1, 14)) else: writing_out = writing dataStore_out = dataStore writeClock_out = writeClock writeBit_out = writeBit TXReg_out = m.bit(1) return ( writing_out, dataStore_out, writeClock_out, writeBit_out, TXReg_out, )
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 = magma.Bits[self.sel_bits]._declare_compare_op("ult") and_gate = magma.Bit._declare_binary_op("and") 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[:self.data_mux.sel_bits]) # 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)
def execute_alu(a: m.UInt[16], b: m.UInt[16], config_: m.Bits[2]) -> \ m.UInt[16]: if config_ == m.bits(0, 2): c = a + b elif config_ == m.bits(1, 2): c = a - b elif config_ == m.bits(2, 2): c = a * b else: c = m.bits(0, 16) return c
def __call__(self, mode: m.Bits[2], const_: T, value: T, clk_en: m.Bit, config_we: m.Bit, config_data: T) -> (T, T): if config_we == m.Bit(1): reg_val = self.register(config_data, m.Bit(1)) return reg_val, reg_val elif mode == m.bits(0, 2): reg_val = self.register(value, m.Bit(False)) return const_, reg_val elif mode == m.bits(1, 2): reg_val = self.register(value, m.Bit(False)) return value, reg_val elif mode == m.bits(2, 2): reg_val = self.register(value, clk_en) return reg_val, reg_val
def bytes_to_x_size(self, bytes_): return m.dict_lookup({ 1: m.bits(0, 3), 2: m.bits(1, 3), 4: m.bits(2, 3), 8: m.bits(3, 3), 16: m.bits(4, 3), 32: m.bits(5, 3), 64: m.bits(6, 3), 128: m.bits(7, 3), }, bytes_, m.bits(0b111, 3))
def definition(io): # Swap this line with the commented code in the following line # to induce a failure in the behavioral test O = io.I0.zext(1) + io.I1.zext(1) + m.bits(io.CIN, 1).zext(N) # O = io.I0.zext(1) - io.I1.zext(1) - m.bits(io.CIN, 1).zext(N) m.wire(O[:N], io.O) m.wire(O[-1], io.COUT)
def test_const(): """ Test constant constructor interface """ data = m.Bits[16] zero = data(0) assert zero == m.bits(0, 16)
def definition(io): Is = [io.I[i] for i in range(n)] muxes = map_(Mux2, n) for i in range(n): if op == 'rol': shifti = (i - k + n) % n I = bits([Is[i], Is[shifti]]) elif op == 'ror': shifti = (i + k) % n I = bits([Is[i], Is[shifti]]) else: assert False muxes[i](I, io.S) for i in range(n): Is[i] = muxes[i].O wire(bits(Is), io.O)
def definition(io): config_reg_reset_bit_vector = \ generate_reset_value(constant_bit_count, default_value, reset_val, mux_sel_bit_count) config_cb = mantle.Register(config_reg_width, init=config_reg_reset_bit_vector, has_ce=True, has_async_reset=True) config_addr_zero = m.bits(0, 8) == io.config_addr[24:32] config_cb(io.config_data, CE=m.bit(io.config_en) & config_addr_zero) # if the top 8 bits of config_addr are 0, then read_data is equal # to the value of the config register, otherwise it is 0 m.wire(io.read_data, mantle.mux([m.uint(0, 32), config_cb.O], config_addr_zero)) output_mux = generate_output_mux(num_tracks, feedthrough_outputs, has_constant, width, mux_sel_bit_count, constant_bit_count, io, config_cb) # NOTE: This is a dummy! fix it later! m.wire(output_mux.O, io.out) return
def test_construct(): """ Test `m.bits` interface """ a_1 = m.bits([1, 1]) print(type(a_1)) assert isinstance(a_1, m.BitsType)
def definition(io): Is = [io.I[i] for i in range(n)] muxes = map_(Mux2, n) for i in range(n): if op == 'lsl': shifti = i - k I = bits([Is[i], Is[shifti] if shifti >= 0 else io.SI]) elif op == 'lsr' or op == 'asr': shifti = i + k I = bits([Is[i], Is[shifti] if shifti < n else io.SI]) else: assert False muxes[i](I, io.S) for i in range(n): Is[i] = muxes[i].O wire(bits(Is), io.O)
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 test_config_register(): WIDTH = 32 ADDR_WIDTH = 8 ADDR_VALUE = 4 # Check that compilation to CoreIR works. Delete JSON file afterwards. cr = define_config_register(WIDTH, m.bits(ADDR_VALUE, ADDR_WIDTH), True) m.compile("config_register", cr, output='coreir') gold_check = check_files_equal("config_register.json", "test_common/gold/config_register.json") assert gold_check res = os.system("\\rm config_register.json") assert res == 0 # Check the module against a simple simulation. simulator = CoreIRSimulator(cr, clock=cr.CLK) def reg_value(): return simulator.get_value(cr.O) def step(I, addr): simulator.set_value(cr.I, I) simulator.set_value(cr.addr, addr) simulator.set_value(cr.CE, 1) simulator.advance(2) return reg_value() assert BitVector(reg_value()) == BitVector(0, WIDTH) sequence = [(0, 0, 0), (12, 4, 12), (0, 0, 12), (9, 4, 9)] for (I, addr, out_expected) in sequence: out = step(BitVector(I, WIDTH), BitVector(addr, ADDR_WIDTH)) assert BitVector(out) == BitVector(out_expected, WIDTH)
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 test_tuple(): assert isinstance(tuple_(OrderedDict(x=0, y=1)), TupleType) assert isinstance(tuple_([0, 1]), TupleType) assert isinstance(tuple_(VCC), TupleType) assert isinstance(tuple_(array(1, 4)), TupleType) assert isinstance(tuple_(bits(1, 4)), TupleType) assert isinstance(tuple_(sint(1, 4)), TupleType) assert isinstance(tuple_(uint(1, 4)), TupleType)
class Adder(AdderNDecl): io = AdderNDecl.io # Swap this line with the commented code in the following line # to induce a failure in the behavioral test O = io.I0.zext(1) + io.I1.zext(1) + m.bits(io.CIN, 1).zext(N) # O = io.I0.zext(1) - io.I1.zext(1) - m.bits(io.CIN, 1).zext(N) m.wire(O[:N], io.O) m.wire(O[-1], io.COUT)
def definition(io): reg = mantle.Register(self.width, has_ce=True) ce = (io.addr_in == magma.bits(self.addr, self.addr_width)) if self.config_en: ce = ce & io.ce magma.wire(io.data_in[0:self.width], reg.I) magma.wire(ce, reg.CE) magma.wire(reg.O, io.O)
def __init__(self): super().__init__() self.add_ports( O=magma.Out(magma.Bits(16)), ) self.wire(Const(magma.bits(0, 16)), self.O)
def tile_to_feature(tile, tile_eq, feature, feature_idx): feature.add_ports(config_en=magma.In(magma.Bit)) feature_eq = FromMagma(mantle.DefineEQ(8)) tile.wire(tile.config.config_addr[16:24], feature_eq.I0) tile.wire(Const(magma.bits(feature_idx, 8)), feature_eq.I1) feature_en = FromMagma(mantle.DefineAnd()) tile.wire(feature_eq.O, feature_en.I0) tile.wire(tile_eq.O, feature_en.I1) tile.wire(feature_en.O, feature.config_en)
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 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')