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 PopCount_typegen(context, values): width = values['width'].value typ = { "I": context.Array(width, context.BitIn()), "O": context.Array(log2(width) + 1, context.Bit()) } return context.Record(typ)
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)
def RAMB16(rom, width, init=None): """ Configure a blocked RAM. """ params = OrderedDict() #params['DOA_REG'] = 0 # default=0 #params['DOB_REG'] = 0 params['WRITE_MODE_A'] = '"WRITE_FIRST"' params['WRITE_MODE_B'] = '"WRITE_FIRST"' # initialize RAM register init = (0, width) if init is None else (init, width) params["INIT_A"] = init params["INIT_B"] = init params["SRVAL_A"] = init params["SRVAL_B"] = init # 512X36 512X32 # 1024X18 1024X16 # 2048X9 2048X8 # 4096X4 # 8192X2 # 16384X1 n = len(rom) logn = log2(n) ramb16_init_bits(rom, width, params) ram = RAMB16BWER(**params) A = array([ram.ADDRB[i] for i in range(14)]) I = array([ram.DIB[i] for i in range(ram.DIB.N)]) IP = array([ram.DIPB[i] for i in range(ram.DIPB.N)]) wire(array([0, 0, 0, 0]), ram.WEB) wire(clock(0), ram.CLKB) wire(0, ram.RSTB) wire(0, ram.REGCEB) wire(0, ram.ENB) wire(array([0, 0, 0, 0]), ram.WEA) # WE defaults to active high - inverted wire(0, ram.RSTA) # RST defaults to active high - inverted wire(0, ram.REGCEA) A = config_ramb16_addr_pins(logn, ram, p="A") I, O = config_ramb16_io_pins(width, ram, p="A") args = ['I', I, "A", A, "O", O] args += ['CLK', ram.CLKA, 'CE', ram.ENA] return AnonymousCircuit(*args)
def RAMB16D(rom, width, init = None): """ Configure a dual-port blocked RAM """ params = OrderedDict() params['DOA_REG'] = 0 params['DOB_REG'] = 0 params['WRITE_MODE_A'] = '"WRITE_FIRST"' params['WRITE_MODE_B'] = '"WRITE_FIRST"' # initialize RAM register init = (0, width) if init is None else (init, width) params["INIT_A"] = init params["INIT_B"] = init params["SRVAL_A"] = init params["SRVAL_B"] = init # 512X36 512X32 # 1024X18 1024X16 # 2048X9 2048X8 # 4096X4 # 8192X2 # 16384X1 n = len(rom) logn = log2(n) ramb16_init_bits(rom, width, params) ram = RAMB16BWER(**params) args = ["CLKA", ram.CLKA, "CLKB", ram.CLKB] args += ["ENA", ram.ENA, "ENB", ram.ENB] args += ["WEA", ram.WEA, "WEB", ram.WEB] args += ["REGCEA", ram.REGCEA, "REGCEB", ram.REGCEB] wire(0, ram.RSTA) wire(0, ram.RSTB) AA = config_ramb16_addr_pins(logn, ram, p = "A") IA, OA = config_ramb16_io_pins(width, ram, p = "A") args += ['IA', IA, "AA", AA, "OA", OA] AB = config_ramb16_addr_pins(logn, ram, p = "B") IB, OB = config_ramb16_io_pins(width, ram, p = "B") args += ['IB', IB, "AB", AB, "OB", OB] return AnonymousCircuit(*args)
def DefineBarrel(n): assert n in [2, 4, 8, 16] logn = log2(n) T = Bits(n) 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) return _Barrel
def DefineShift(n, op): assert n in [2, 4, 8, 16] logn = log2(n) T = Bits(n) 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) return _Shift
def DefineRotate(n, op): assert n in [2, 4, 8, 16] logn = log2(n) T = Bits(n) 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) return _Rotate
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 RAM128D(ram): width = 1 n = 128 logn = log2(n) ram = RAM128x1D(INIT=lutinit(ram,128)) args = ['A0', ram.A] args += ['A1', ram.DPRA] args += ['I', ram.D] args += ['O0', ram.SPO] args += ['O1', ram.DPO] args += ["WE", ram.WE] args += ["CLK", ram.WCLK] return AnonymousCircuit(*args)
def DefineEncoder(n): assert n <= 8 logn = log2(n) class _Encoder(Circuit): name = 'Encoder'+str(n) IO = ['I', In(Bits(n)), 'O', Out(Bits(logn))] @classmethod def definition(Enc): def f(y): or_ = uncurry(Or(n//2)) os = [] for i in range(n): if i & (1 << y): os.append(Enc.I[i]) wire(array(os), or_) return AnonymousCircuit("O", or_.O) enc = join( col(f, logn) ) wire(enc.O, Enc.O) return _Encoder
def shift(i, s, si, op): n = len(i) assert log2(n) == len(s) return Shift(n, op)(i, s, si)
def rotate(i, s, op): n = len(i) assert log2(n) == len(s) return Rotate(n, op)(i, s)
def barrel(i, s, si): n = len(i) assert log2(n) == len(s) return Barrel(n)(i, s, si)
def RAMB16D(rom, init=None): """ Configure a dual-port blocked RAM (currently only one setting) """ width = 16 params = OrderedDict() params['WRITE_MODE_A'] = '"WRITE_FIRST"' params['WRITE_MODE_B'] = '"WRITE_FIRST"' # initialize RAM output register if init is None: #init = "%d'h%05X" % (width, 0) init = (0, width) else: #init = "%d'h%05X" % (width, init) init = (init, width) params["INIT_A"] = init params["INIT_B"] = init params["SRVAL_A"] = init params["SRVAL_B"] = init # 512X36 512X32 # 1024X18 1024X16 # 2048X9 2048X8 # 4096X4 # 8192X2 # 16384X1 n = len(rom) logn = log2(n) ramb16_init_bits(rom, width, params) ram = RAMB16_S18_S18(**params) args = ["CLKA", ram.CLKA, "CLKB", ram.CLKB] args += ["ENA", ram.ENA, "ENB", ram.ENB] args += ["WEA", ram.WEA, "WEB", ram.WEB] # Default: We wanted a dual port ram in the first place, # so why not just turn them on all the time? wire(array([0, 0]), ram.DIPA) wire(array([0, 0]), ram.DIPB) # wire(1, ram.ENB) # wire(1, ram.ENA) # wire(1, ram.ENB) wire(0, ram.SSRA) wire(0, ram.SSRB) # reverse the address bits # AA = [ram.ADDRA[logn-1-i] for i in range(logn)] AA = [ram.ADDRA[i] for i in range(logn)] AA = array(AA) # reverse the order DI #IA = [ram.DIA[ram.DIA.N-1-i] for i in range(ram.DIA.N)] IA = [ram.DIA[i] for i in range(ram.DIA.N)] IA = array(IA) OA = [ram.DOA[i] for i in range(ram.DOA.N)] OA = array(OA) args += ['IA', IA, "AA", AA, "OA", OA] # reverse the address bits #AB = [ram.ADDRB[logn-1-i] for i in range(logn)] AB = [ram.ADDRB[i] for i in range(logn)] AB = array(AB) # reverse the order DI #IB = [ram.DIB[ram.DIB.N-1-i] for i in range(ram.DIB.N)] IB = [ram.DIB[i] for i in range(ram.DIB.N)] IB = array(IB) # reverse the order DI #OB = [ram.DOB[ram.DOB.N-1-i] for i in range(ram.DOB.N)] OB = [ram.DOB[i] for i in range(ram.DOB.N)] OB = array(OB) args += ['IB', IB, "AB", AB, "OB", OB] return AnonymousCircuit(args)
def RAMB16(rom, width, init=None): """ Configure a blocked RAM. """ params = OrderedDict() params['WRITE_MODE'] = '"WRITE_FIRST"' # initialize RAM output register if init is None: #init = "%d'h%05X" % (width, rom[0]) init = (rom[0], width) else: #init = "%d'h%05X" % (width, init) init = (init, width) params["INIT"] = init params["SRVAL"] = init # 512X36 512X32 # 1024X18 1024X16 # 2048X9 2048X8 # 4096X4 # 8192X2 # 16384X1 n = len(rom) logn = log2(n) if width == 8 or width == 9: assert n in [256, 512, 1024, 2048] if n != 2048: rom += (2048 - n) * [0] params = romX8(rom, 2048, params) if width == 9: params = romX1P(rom, 2048, params) ram = RAMB16_S9(**params) if width == 16 or width == 18: assert n in [256, 512, 1024] if n != 1024: rom += (1024 - n) * [0] params = romX16(rom, 1024, params) if width == 18: params = romX2P(rom, 1024, params) ram = RAMB16_S18(**params) # reverse the address bits #A = [ram.ADDR[logn-1-i] for i in range(logn)] A = [ram.ADDR[i] for i in range(logn)] A = array(A) # reverse the order DI #I = [ram.DI[ram.DI.N-1-i] for i in range(ram.DI.N)] I = [ram.DI[i] for i in range(ram.DI.N)] # reverse the order DI #O = [ram.DO[ram.DO.N-1-i] for i in range(ram.DO.N)] O = [ram.DO[i] for i in range(ram.DO.N)] if width == 8: wire(0, ram.DIP[0]) elif width == 9: I += [ram.DIP[0]] O += [ram.DOP[0]] elif width == 16: wire(0, ram.DIP[0]) wire(0, ram.DIP[1]) elif width == 18: # reverse #I += [ram.DIP[1], ram.DIP[0]] #O += [ram.DOP[1], ram.DOP[0]] I += [ram.DIP[0], ram.DIP[1]] O += [ram.DOP[0], ram.DOP[1]] I = array(I) O = array(O) wire(0, ram.SSR) # SSR defaults to active high - inverted wire(0, ram.WE) # WE defaults to active high - inverted args = ram.interface.clockargs() + ['CE', ram.EN] args += ['I', I, "A", A, "O", O] return AnonymousCircuit(args)