class _Sequencer(Circuit): name = 'Sequencer{}'.format(n) IO = [ "addr", In(T), "jump", In(Bit), "we", In(Bit), "O", Out(T), "CLK", In(Clock) ] @classmethod def definition(io): pc = Register(n, has_ce=True) add = Add(n) mux = Mux(2, n) add(pc, bits(1, n=n)) pc(mux) wire(add.O, mux.I0) wire(io.addr, mux.I1) wire(io.jump, mux.S) wire(io.CLK, pc.CLK) wire(io.we, pc.CE) wire(pc.O, io.O)
class _Barrel(Circuit): name = 'Barrel{}'.format(n) IO = ['I', In(T), 'S', In(Bits(logn)), 'SI', In(Bit), "O", Out(T)] @classmethod def definition(io): I = io.I for k in range(logn): I = BarrelShift(n, 1<<k)(I, io.S[k], io.SI) wire(I, io.O)
def Define3to2Op(): Op = DefineCircuit("Op", "I0", In(Bit), "I1", In(Bit), "I2", In(Bit), "O", Out(Bit)) a = And(2)(Op.I0, Op.I1) b = And(2)(Op.I1, Op.I2) c = And(2)(Op.I2, Op.I0) d = Or(3)(a, b, c) wire(d, Op.O) EndDefine() return Op
class _Rotate(Circuit): name = f'Rotate{n}' IO = ['I', In(T), 'S', In(Bits(logn)), "O", Out(T)] @classmethod def definition(io): I = io.I for k in range(logn): I = RotateK(n, 1 << k, op)(I, io.S[k]) wire(I, io.O)
class _Shift(Circuit): name = f'Shift{n}' IO = ['I', In(T), 'S', In(Bits(logn)), 'SI', In(Bit), "O", Out(T)] @classmethod def definition(io): I = io.I for k in range(logn): I = ShiftK(n, 1 << k, op)(I, io.S[k], io.SI) wire(I, io.O)
class _Shift(Circuit): name = f'{op.upper()}{n}' IO = ['I', In(T), 'S', In(Bits[logn]), "O", Out(T)] @classmethod def definition(io): I = io.I for k in range(logn): I = ShiftK(n, 1 << k, op)(I, io.S[k]) wire(I, io.O)
def test_fdce(): main = DefineCircuit('main', 'I', In(Bit), "O", Out(Bit), "CLK", In(Clock)) dff = FDCE() wire(m.enable(1), dff.CE) wire(0, dff.CLR) wire(main.I, dff.D) wire(dff.Q, main.O) EndCircuit() print(compile(main)) print(repr(main))
def DefineMain(self): arrays = {} # form arrays for p in self.pins: if p.used: # find names of the form %s[%d] # these are considered arrays match = re.findall('(.*)\[(\d+)\]', p.name) if match: name, i = match[0] i = int(i) # keep track of the indices if name in arrays: arrays[name].append(i) else: arrays[name] = [i] # collect top level module arguments args = [] for p in self.pins: if p.used: match = re.findall('(.*)\[(\d+)\]', p.name) if match: name, i = match[0] assert name in arrays if len(arrays[name]) == 1: p.rename(name) args.append(name) args.append( In(Bit) if p.direction == INPUT else Out(Bit)) else: i = int(i) if i == max(arrays[name]): args.append(name) T = Bits[i + 1] args.append( In(T) if p.direction == INPUT else Out(T)) else: args.append(p.name) if p.name == 'CLKIN': assert p.direction == INPUT args.append(In(Clock)) else: args.append( In(Bit) if p.direction == INPUT else Out(Bit)) D = DefineCircuit('main', *args, __magma_no_cache__=True) D.fpga = self for p in self.peripherals: if p.used: #print(p) p.setup(D) return D
class _BarrelShift(Circuit): name = 'BarrelShift{}_{}'.format(n, k) IO = ['I', In(T), 'S', In(Bit), 'SI', In(Bit), "O", Out(T)] @classmethod 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)
class _RAM(Circuit): name = f'RAM{height}x{width}' IO = ['RADDR', In(TADDR), 'RDATA', Out(TDATA), 'WADDR', In(TADDR), 'WDATA', In(TDATA), 'WE', In(Bit), 'CLK', In(Clock) ] @classmethod def definition(io): regs = REGs(height, width, has_ce=True) writeport(addr_width, width, regs, io.WADDR, io.WDATA, io.WE) wire( readport(addr_width, width, regs, io.RADDR), io.RDATA )
class Permute(Circuit): name = na IO = ["I", In(Bits(n)), "O", Out(Bits(n))] @classmethod def definition(io): [wire(io.I[permutation[i]], io.O[i]) for i in range(len(io.I))]
def test_coreir_wrap(T): def define_wrap(type_, type_name, in_type): def sim_wrap(self, value_store, state_store): input_val = value_store.get_value(getattr(self, "in")) value_store.set_value(self.out, input_val) return DeclareCircuit( f'coreir_wrap{type_name}', "in", In(in_type), "out", Out(type_), coreir_genargs = {"type": type_}, coreir_name="wrap", coreir_lib="coreir", simulate=sim_wrap ) foo = DefineCircuit("foo", "r", In(T)) EndCircuit() top = DefineCircuit("top", "O", Out(Bit)) foo_inst = foo() wrap = define_wrap(T, "Bit", Bit)() wire(bit(0), wrap.interface.ports["in"]) wire(wrap.out, foo_inst.r) wire(bit(0), top.O) EndCircuit() with tempfile.TemporaryDirectory() as tempdir: filename = f"{tempdir}/top" compile(filename, top, output="coreir") got = open(f"{filename}.json").read() expected_filename = f"tests/test_type/test_coreir_wrap_golden_{T}.json" expected = open(expected_filename).read() assert got == expected
def DefineDehydrate(T: Kind): """ Convert a nested type to a flat array of bits Aetherling Type: {1, T} -> {1, Bit[width(T)]} This returns a circuit definition. Args: cirb: The CoreIR backend currently be used T: The type to dehydrate Returns: A module with the following ports: I : In(T) out : Out(Array[width(T), Bit]) The module also has the following data: size: width(T) """ cirb = GetCoreIRBackend() cirType = cirb.get_type(In(T)) name = "dehydrate_t{}".format(cleanName(str(T))) defToReturn = DefineCircuitFromGeneratorWrapper( cirb, "aetherlinglib", "dehydrate", name, ["commonlib", "mantle", "coreir", "global"], {"hydratedType": cirType}) defToReturn.size = cirType.size #print(f"Current Dehydrate input type {T} and output IO {defToReturn.IO}") return defToReturn
class _1DLinebuffer(Circuit): assert elementType == imgType.T, "For 1D linebuffer, image must be a 1D array of elements" strForValid = "_Valid" if has_valid else "" cirElementType = cirb.get_type(elementType, False) cirImgType = cirb.get_type(imgType, False) name = "linebuffer1d_p{}_w{}_img{}_elm{}".format( pxPerClock, stencilWidth, cleanName(str(imgType)), cleanName(str(elementType)), strForValid) IO = ['I', In(Array(pxPerClock, elementType)), 'O', Out(Array(pxPerClock, Array(stencilWidth, elementType))), "CE", In(Bit)] + \ (['valid', Bit] if has_valid else []) @classmethod def definition(cls): lb = Linebuffer(cirb, Array(pxPerClock, elementType), Array(stencilWidth + pxPerClock - 1, elementType), imgType) overlapPartition = DefineCircuitFromGeneratorWrapper( cirb, "aetherlinglib", "overlapPartition", "overlapPartition_" + cls.name, ["commonlib", "mantle", "coreir", "global"], { "elementType": cls.cirElementType, "numOverlapped": pxPerClock, "arrayLen": stencilWidth })() wire(cls.I, lb.I) wire(lb.out, overlapPartition.I) wire(overlapPartition.out, cls.O) wire(lb.wen, cls.CE) if (has_valid): cls.wire(lb.valid, cls.valid) validChainTerm = Term(cirb, 1) wire(lb.valid_chain, validChainTerm.I[0])
class Clock(Peripheral): name = 'clock' IO = ['I', In(Bit), 'O', Out(Bit)] def __init__(self, fpga, freq=0, name='clock'): super(Clock, self).__init__(fpga, name) self.freq = freq def frequency(self, freq): self.freq = freq return self def on(self): clkin = self.I.getgpio() clkin.input().on() Peripheral.on(self) return self def setup(self, main): clkin = self.I.getgpio() crystal = clkin.I.getinst() assert crystal basefrequency = crystal.frequency if not self.freq: self.freq = basefrequency #print(basefrequency, self.freq) assert basefrequency or self.freq if self.freq == basefrequency: main.CLK = main.CLKIN return assert True
def DefineTerm(width): def simulate_term(self, value_store, state_store): pass return DeclareCoreirCircuit(f"term", "I", In(Bits[ width ]), coreir_name="term", coreir_lib="coreir", coreir_genargs={"width": width}, simulate=simulate_term)
class CorebitTerm(Circuit): name = f"corebit_term" IO = ["in", In(Bit)] @classmethod def definition(io): pass
class Swaps(Circuit): name = 'Swap{}'.format(n) IO = ['I', In(Bits(n)), "O", Out(Bits(n))] @classmethod def definition(io): s = flat(join(map_(Swap, n // 2)), flatargs=['I', 'O']) wire(s(io.I), io.O)
class Swap(Circuit): IO = ['I', In(Bits(2)), "O", Out(Bits(2))] @classmethod def definition(io): swap = uncurry(fork(And(2), Or(2)), prefix="I") #swap = uncurry( fork( And(2), Or(2) ) , prefix="in") wire(swap(io.I), io.O)
class _PopCount(Circuit): name = 'PopCount{}'.format(n) IO = ['I', In(Bits[n]), 'O', Out(Bits[log2(n) + 1])] @classmethod def definition(io): r = compressor([io.I.as_list()]) wire(bits(r), io.O)
class _ROM(Circuit): name = f'ROM{n}x{width}' IO = ['RADDR', In(TADDR), 'RDATA', Out(TDATA)] @classmethod def definition(io): roms = ROM4s(n, width, data) [roms[i](io.RADDR[0:4]) for i in range(n // 16)] wire(readport(height - 4, width, roms, io.RADDR[4:]), io.RDATA)
class Clock(GPIO): IO = ['I', In(Bit), "O", Out(Bit)] def __init__(self, fpga, name): GPIO.__init__(self, fpga, name) def ucf(self): return 'NET %s LOC="%s" | IOSTANDARD = LVCMOS25 | PERIOD = 31.25ns ;' % ( self.name, self.pinname)
def DefineCorebitTerm(): def simulate_corebit_term(self, value_store, state_store): pass return DeclareCoreirCircuit(f"corebit_term", "I", In(Bit), coreir_name="term", coreir_lib="corebit", simulate=simulate_corebit_term)
class EvenOddSwaps(Circuit): name = 'EvenOddSwap{}'.format(n) IO = ['I', In(Bits(n)), "O", Out(Bits(n))] @classmethod def definition(io): s = flat(join(map_(Swap, n // 2 - 1)), flatargs=['I', 'O']) wire(io.I[0], io.O[0]) wire(s(io.I[1:-1]), io.O[1:-1]) wire(io.I[-1], io.O[-1])
class GPIO(Pin): IO = ['I', In(Bit), 'O', Out(Bit)] def __init__(self, fpga, name): Pin.__init__(self, fpga, name) self.fpga.gpios.append(self) self.direction = INPUT self.Z = False
def test_print_ir(): And2 = DeclareCircuit('And2', "I0", In(Bit), "I1", In(Bit), "O", Out(Bit)) AndN2 = DefineCircuit("AndN2", "I", In(Array[2, Bit]), "O", Out(Bit) ) and2 = And2() wire( AndN2.I[0], and2.I0 ) wire( AndN2.I[1], and2.I1 ) wire( and2.O, AndN2.O ) EndCircuit() main = DefineCircuit("main", "I0", In(Bit), "I1", In(Bit), "O", Out(Bit)) and2 = AndN2() main.O( and2(array([main.I0, main.I1])) ) EndCircuit() result = compile(main) #print(result) assert result == """\
def test_bit_flip(): bout = Out(Bit) bin = In(Bit) assert bout == BitOut assert bin == BitIn bin = In(BitIn) bout = Out(BitIn) assert bout == BitOut assert bin == BitIn bin = In(BitOut) bout = Out(BitOut) assert bout == BitOut assert bin == BitIn bin = Flip(BitOut) bout = Flip(BitIn) assert bout == BitOut assert bin == BitIn
class Audio(Part): IO = ["I", In(Bit)] def __init__(self, board): Part.__init__(self, board, 'AUDIO') def on(self): self.I.trace().inst.on() Part.on(self) return self
class _RotateK(Circuit): name = f'Rotate{n}_{k}' IO = ['I', In(T), 'S', In(Bit), "O", Out(T)] @classmethod 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)
class _ShiftK(Circuit): name = f'Shift{n}_{k}' IO = ['I', In(T), 'S', In(Bit), 'SI', In(Bit), "O", Out(T)] @classmethod 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)