def _operand(cls, operand: Union[RtlSignal, Value], operator: OpDefinition, ctx: SerializerCtx): try: isTernaryOp = operand.hidden and operand.drivers[ 0].operator == AllOps.TERNARY except (AttributeError, IndexError): isTernaryOp = False if isTernaryOp: # rewrite ternary operator as if o = ctx.createTmpVarFn("tmpTernary", operand._dtype) cond, ifTrue, ifFalse = operand.drivers[0].operands if_ = If(cond) if_.ifTrue.append( Assignment(ifTrue, o, virtualOnly=True, parentStm=if_)) if_.ifFalse = [] if_.ifFalse.append( Assignment(ifFalse, o, virtualOnly=True, parentStm=if_)) if_._outputs.append(o) for obj in (cond, ifTrue, ifFalse): if isinstance(obj, RtlSignalBase): if_._inputs.append(obj) o.drivers.append(if_) operand = o s = cls.asHdl(operand, ctx) if isinstance(operand, RtlSignalBase): try: o = operand.singleDriver() if o.operator != operator and\ cls.opPrecedence[o.operator] <= cls.opPrecedence[operator]: return "(%s)" % s except Exception: pass return s
def mem_write(mem, port: BramPort_withoutClk): drive = [] if port.HAS_BE: assert port.DATA_WIDTH % 8 == 0, port.DATA_WIDTH # we for each byte separate #drive.append( # mem[port.addr](apply_write_with_mask(mem[port.addr], port.din, port.we)) #) for b_i, be in enumerate(port.we): low = b_i * 8 drive.append( If(be, mem[port.addr][low + 8: low](port.din[low + 8: low]) ) ) elif port.HAS_R and port.HAS_W: # explicit we drive.append( If(port.we, mem[port.addr](port.din) ) ) else: # en used as we drive.append(mem[port.addr](port.din)) return drive
def _impl(self): If( self.a, self.d(self.b), # this two if statements will be merged together If(self.b, self.e(self.c)), If(self.b, self.f(0))).Else(self.d(0))
def _impl_latency(self, inVld, inRd, inData, outVld, outRd, prefix): isOccupied = self._reg(prefix + "isOccupied", defVal=0) regs_we = self._sig(prefix + 'reg_we') outData = [] for iin in inData: r = self._reg(prefix + 'reg_' + iin._name, iin._dtype) If(regs_we, r(iin) ) outData.append(r) If(isOccupied, If(outRd & ~inVld, isOccupied(0) ) ).Else( If(inVld, isOccupied(1) ) ) If(isOccupied, c(outRd, inRd), outVld(1), regs_we(inVld & outRd) ).Else( inRd(1), outVld(0), regs_we(inVld) ) return outData
def stashLoad(self, isIdle, stash, lookupOrigin_out): lookup = self.lookup insert = self.insert delete = self.delete If(isIdle, If(self.clean.vld, stash.vldFlag(0) ).Elif(delete.vld, stash.key(delete.key), lookupOrigin_out(ORIGIN_TYPE.DELETE), stash.vldFlag(0), ).Elif(insert.vld, lookupOrigin_out(ORIGIN_TYPE.INSERT), stash.key(insert.key), stash.data(insert.data), stash.vldFlag(1), ).Elif(lookup.vld, lookupOrigin_out(ORIGIN_TYPE.LOOKUP), stash.key(lookup.key), ) ) priority = [self.clean, self.delete, self.insert, lookup] for i, intf in enumerate(priority): withLowerPrio = priority[:i] intf.rd(And(isIdle, *map(lambda x:~x.vld, withLowerPrio)))
def _impl(self): ITERATIONS = int(self.ITERATIONS) """ Iterates from ITERATIONS -1 to 0 body is enabled by bodyVld and if bodyRd then counter is decremented for next iteration break causes reset of counter """ counter = self._reg("counter", Bits(self.COUNTER_WIDTH), ITERATIONS - 1) If(counter._eq(0), If(self.cntrl.vld, counter(ITERATIONS - 1) ) ).Else( If(self.body.rd, If(self.bodyBreak, counter(0) ).Else( counter(counter - 1) ) ) ) self.cntrl.rd(counter._eq(0)) self.body.vld(counter != 0) self.index(counter[self.COUNTER_WIDTH:0])
def _impl(self): st_t = HEnum("state_t", ["IDLE", "LOAD_SR", "CONVERTING", "DONE"]) st = self._reg("st", st_t, def_val=st_t.IDLE) sr_shift = st.next._eq(st_t.CONVERTING) bcd = self.din bin_ = self.dout bcd_sr = self._reg("bcd_sr", bcd.data._dtype, def_val=0) binary_sr = self._reg("binary_sr", bin_.data._dtype, def_val=0) next_bcd = rename_signal(self, bcd_sr >> 1, "next_bcd") MAX_COUNT = binary_sr._dtype.bit_length() bit_count = self._reg("bit_count", Bits(log2ceil(MAX_COUNT), signed=False), def_val=MAX_COUNT) If(sr_shift, bit_count(bit_count - 1), ).Else( bit_count(MAX_COUNT), ) # dabble the digits digits = [] for i in range(self.BCD_DIGITS): d = next_bcd[(i + 1) * 4:i * 4]._unsigned() d_sig = (d < 7)._ternary(d, d - 3) digits.append(d_sig) If(st.next._eq(st_t.LOAD_SR), bcd_sr(bcd.data), binary_sr(0), ).Elif(sr_shift, # shift right binary_sr(Concat(bcd_sr[0], binary_sr[:1])), bcd_sr(Concat(*reversed(digits))), ) bin_.data(binary_sr) Switch(st)\ .Case(st_t.IDLE, If(bcd.vld, st(st_t.LOAD_SR), # load the shift registers ))\ .Case(st_t.LOAD_SR, # shift right each cycle st(st_t.CONVERTING), )\ .Case(st_t.CONVERTING, If(bit_count._eq(0), # indicate completion st(st_t.DONE), ) )\ .Case(st_t.DONE, If(bcd.vld & bin_.rd, st(st_t.LOAD_SR), ).Elif(bin_.rd, st(st_t.IDLE), ) ) bcd.rd(st._eq(st_t.IDLE) | (st._eq(st_t.DONE) & bin_.rd)) bin_.vld(st._eq(st_t.DONE))
def _impl(self): a = self.a b = self.b out = self.dout st = self._reg("st", Bits(3), 1) If(st._eq(1), If(a & b, st(3)).Elif(b, st(2))).Elif(st._eq(2), If(a & b, st(3)).Elif(a, st(1))).Elif( st._eq(3), If(a & ~b, st(1)).Elif(~a & b, st(2))).Else(st(1)) Switch(st)\ .Case(1, out(1) ).Case(2, out(2) ).Case(3, out(3) ).Default( out(None) )
def _impl(self): output_dtype = Bits(bit_length=self.width * 2 - 1) output_var = self._sig(name="output_var", dtype=output_dtype, def_val=0) If( self.param_a[self.index], output_var[self.width - 1:](self.param_b[self.width - 1:]), If( self.param_b[self.width - 2], output_var[self.width * 2 - 1:self.width - 1](self.pow), ).Else(output_var[self.width * 2 - 1:self.width - 1](0)), ).Else(output_var(0)) if self.index > 0: If( self.param_a[self.index], self.output[self.width * 2 - 1:self.index]( output_var[self.width * 2 - 1 - self.index:]), self.output[self.index:](0), ).Else(self.output(0)) else: If( self.param_a[self.index], self.output[self.width * 2 - 1:self.index]( output_var[self.width * 2 - 1 - self.index:]), ).Else(self.output(0))
def _impl(self): propagateClk(self) PORT_CNT = self.PORT_CNT fa = self.firstA sa = self.secondA If(self.select_sig, self.ram0.port[0](fa), self.ram1.port[0](sa) ).Else( self.ram0.port[0](sa), self.ram1.port[0](fa) ) if PORT_CNT == 2: fb = self.firstB sb = self.secondB If(self.select_sig, self.ram0.port[1](fb), self.ram1.port[1](sb), ).Else( self.ram0.port[1](sb), self.ram1.port[1](fb) ) elif PORT_CNT > 2: raise NotImplementedError()
def lookupResOfTablesDriver(self, resRead, resAck): tables = self.tables # one hot encoded index where item should be stored (where was found # or where is place) targetOH = self._reg("targetOH", Bits(self.TABLE_CNT)) res = list(map(lambda t: t.lookupRes, tables)) # synchronize all lookupRes from all tables StreamNode(masters=res).sync(resAck) insertFinal = self._reg("insertFinal") # select empty space or victim witch which current insert item # should be swapped with lookupResAck = StreamNode(masters=map( lambda t: t.lookupRes, tables)).ack() insertFoundOH = list(map(lambda t: t.lookupRes.found, tables)) isEmptyOH = list(map(lambda t:~t.lookupRes.occupied, tables)) _insertFinal = Or(*insertFoundOH, *isEmptyOH) If(resRead & lookupResAck, If(Or(*insertFoundOH), targetOH(Concat(*reversed(insertFoundOH))) ).Else( SwitchLogic([(empty, targetOH(1 << i)) for i, empty in enumerate(isEmptyOH) ], default=If(targetOH, targetOH(ror(targetOH, 1)) ).Else( targetOH(1 << (self.TABLE_CNT - 1)) )) ), insertFinal(_insertFinal) ) return lookupResAck, insertFinal, insertFoundOH, targetOH
def AxiReaderCore(): n = RtlNetlist() rSt_t = HEnum('rSt_t', ['rdIdle', 'rdData']) rSt = n.sig('rSt', rSt_t) r_idle = n.sig("r_idle") arRd = n.sig('arRd') arVld = n.sig('arVld') rVld = n.sig('rVld') rRd = n.sig('rRd') # ar fsm next If(arRd, # rdIdle If(arVld, rSt(rSt_t.rdData) ).Else( rSt(rSt_t.rdIdle) ) ).Else( # rdData If(rRd & rVld, rSt(rSt_t.rdIdle) ).Else( rSt(rSt_t.rdData) ) ) r_idle(rSt._eq(rSt_t.rdIdle)) return n, { r_idle: DIRECTION.OUT, arRd: DIRECTION.IN, arVld: DIRECTION.IN, rVld: DIRECTION.IN, rRd: DIRECTION.IN }
def _instantiateTimerTickLogic(timer: RtlSignal, period: RtlSignal, enableSig: Optional[RtlSignal], rstSig: Optional[RtlSignal]): """ Instantiate incrementing timer with optional reset and enable signal :param timer: timer main register :param period: signal with actual period :param enableSig: optional enable signal for this timer :param rstSig: optional reset signal for this timer """ r = timer.cntrRegister tick = r._eq(period - 1) if enableSig is None: if rstSig is None: cond = tick else: cond = rstSig | tick, If(cond, r(0)).Else(r(r + 0)) else: if rstSig is None: If(enableSig, If(tick, r(0)).Else(r(r + 1))) else: If(rstSig | (enableSig & tick), r(0)).Elif(enableSig, r(r + 1)) if enableSig is not None: tick = (tick & enableSig) if rstSig is not None: tick = (tick & ~rstSig) return tick
def __init__(self, index, name: str, parent: "OutOfOrderCummulativeOp"): self.index = index self.name = name r = parent._reg self.id = r(f"{name:s}_id", parent.m.ar.id._dtype) self.addr = r(f"{name:s}_addr", Bits(parent.MAIN_STATE_INDEX_WIDTH)) if parent.TRANSACTION_STATE_T is not None: self.transaction_state = r(f"{name:s}_transaction_state", parent.TRANSACTION_STATE_T) self.data = r(f"{name:s}_data", parent.MAIN_STATE_T) vld = self.valid = r(f"{name:s}_valid", def_val=0) inVld = self.in_valid = parent._sig(f"{name:s}_in_valid") outRd = self.out_ready = parent._sig(f"{name:s}_out_ready") inRd = self.in_ready = parent._sig(f"{name:s}_in_ready") regs_we = self.load_en = parent._sig(f"{name:s}_load_en") If(self.valid, inRd(outRd), regs_we(inVld & outRd), If(outRd & ~inVld, vld(0))).Else( inRd(1), regs_we(inVld), vld(inVld), ) # :note: constructed later self.collision_detect = None
def AxiReaderCore(): n = RtlNetlist() rSt_t = HEnum('rSt_t', ['rdIdle', 'rdData']) rSt = n.sig('rSt', rSt_t) arRd = n.sig('arRd') arVld = n.sig('arVld') rVld = n.sig('rVld') rRd = n.sig('rRd') # ar fsm next If(arRd, # rdIdle If(arVld, rSt(rSt_t.rdData) ).Else( rSt(rSt_t.rdIdle) ) ).Else( # rdData If(rRd & rVld, rSt(rSt_t.rdIdle) ).Else( rSt(rSt_t.rdData) ) ) return n, [rSt, arRd, arVld, rVld, rRd]
def _impl(self): signal_width = Bits(bit_length=self.width, force_vector=True) inputs = [ self._sig(name=f"input{i}", dtype=signal_width) for i in range(4) ] for i in range(4): inputs[i](self.input[(i + 1) * self.width:i * self.width]) first_pool0 = self._sig(name="first_pool0", dtype=signal_width) first_pool1 = self._sig(name="first_pool1", dtype=signal_width) pool_result = self._sig(name="pool_result", dtype=signal_width) comparison = self.__bin_comparison if self.binary else self.__comparison comparison(inputs[0], inputs[1], first_pool0) comparison(inputs[2], inputs[3], first_pool1) If(self.rst, pool_result(0)).Else( If( self.clk._onRisingEdge(), If(self.en_pool, comparison(first_pool0, first_pool1, pool_result)), )) self.output(pool_result)
def split_select(self, outputSelSignalOrSequence, noOfOutputs): """ Create a demultiplexer with number of outputs specified by noOfOutputs :param noOfOutputs: number of outputs of multiplexer :param outputSelSignalOrSequence: handshaked interface (onehot encoded) to control selected output or sequence of output indexes which should be used (will be repeated) """ if not self.master_to_slave: assert len(self.end) == noOfOutputs, self.end def setChCnt(u): u.OUTPUTS = noOfOutputs self._genericInstance(self.SplitSelectCls, 'select', setChCnt) if isinstance(outputSelSignalOrSequence, Handshaked): self.lastComp.selectOneHot(outputSelSignalOrSequence) else: seq = outputSelSignalOrSequence t = Bits(self.lastComp.selectOneHot.data._dtype.bit_length()) size = len(seq) ohIndexes = map(lambda x: 1 << x, seq) indexes = self.parent._sig(self.name + "split_seq", t[size], def_val=ohIndexes) actual = self.parent._reg(self.name + "split_seq_index", Bits(size.bit_length()), 0) iin = self.lastComp.selectOneHot iin.data(indexes[actual]) iin.vld(1) If(iin.rd, If(actual._eq(size - 1), actual(0)).Else(actual(actual + 1))) return self
def _impl(self): r = self.r w = self.w ram = self.ram readRegEmpty = self._reg("readRegEmpty", defVal=1) readDataPending = self._reg("readDataPending", defVal=0) readData = self._reg("readData", r.data.data._dtype) rEn = readRegEmpty | r.data.rd readDataPending(r.addr.vld & rEn) If(readDataPending, readData(ram.dout)) If(r.data.rd, readRegEmpty(~readDataPending)).Else( readRegEmpty(~(readDataPending | ~readRegEmpty))) r.addr.rd(rEn) If(rEn & r.addr.vld, ram.we(0), ram.addr(r.addr.data)).Else(ram.we(1), ram.addr(w.addr)) wEn = ~rEn | ~r.addr.vld w.rd(wEn) ram.din(w.data) ram.en((rEn & r.addr.vld) | w.vld) r.data.data(readData) r.data.vld(~readRegEmpty)
def _impl(self): concat_type = Bits(bit_length=self.width * 2 - 1, force_vector=True) concat_inputs = [ self._sig(name=f"concat_inputs_{i}", dtype=concat_type) for i in range(15) ] data_type = Bits(bit_length=15, force_vector=True) data_a = self._sig(name="data_a", dtype=data_type, def_val=0) data_b = self._sig(name="data_b", dtype=data_type, def_val=0) non_zero_a = self._sig(name="non_zero_a", dtype=Bits(1)) non_zero_b = self._sig(name="non_zero_b", dtype=Bits(1)) xor_signal = self._sig(name="xor_signal", dtype=Bits(1)) data_a[self.width - 1:](self.param_a[self.width - 1:]) data_b[self.width - 1:](self.param_b[self.width - 1:]) for i in range(15): self.concat_units[i].param_a(data_a) self.concat_units[i].param_b(data_b) concat_inputs[i](self.concat_units[i].output) fourth_sum = self.__calc_tree_adders(concat_inputs) If(data_a._eq(0), non_zero_a(0)).Else(non_zero_a(1)) If(data_b._eq(0), non_zero_b(0)).Else(non_zero_b(1)) xor_signal(self.param_a[self.width - 1] ^ self.param_b[self.width - 1]) self.product[self.width - 1](xor_signal & non_zero_a & non_zero_b) self.product[self.width - 1:]( fourth_sum[self.lower_output_bit + self.width - 1:self.lower_output_bit])
def read_logic(self, r: RamHsR, ram: BramPort_withoutClk): readDataPending = self._reg("readDataPending", def_val=0) readData = self._reg("readData", HStruct((r.data.data._dtype, "data"), (BIT, "vld")), def_val={"vld": 0}) readDataOverflow = self._reg("readDataOverflow", readData._dtype, def_val={"vld": 0}) rEn = ~readDataOverflow.vld & (~readData.vld | r.data.rd) readDataPending(r.addr.vld & rEn) If( readDataPending, If( ~readData.vld | r.data.rd, # can store directly to readData register readData.data(ram.dout), readData.vld(1), readDataOverflow.vld(0), ).Else( # need to store to overflow register readDataOverflow.data(ram.dout), readDataOverflow.vld(1), ), ).Else( If(r.data.rd, readData.data(readDataOverflow.data), readData.vld(readDataOverflow.vld), readDataOverflow.vld(0))) r.addr.rd(rEn) return rEn, readData
def filter(self, name, sig): """attempt to remove glitches""" filter0 = self._reg(name + "_filter0", dtype=Bits(2), defVal=0) filter0(filter0[0]._concat(sig)) # let filter_cnt to be shared between filters try: filter_clk_cntr = self.filter_clk_cntr except AttributeError: filter_clk_cntr = self.filter_clk_cntr = self._reg("filter_clk_cntr", Bits(self.CLK_CNTR_WIDTH), defVal=self.clk_cnt_initVal) If(filter_clk_cntr._eq(0), filter_clk_cntr(self.clk_cnt_initVal) ).Else( filter_clk_cntr(filter_clk_cntr - 1) ) filter1 = self._reg(name + "_filter1", dtype=Bits(3), defVal=0b111) If(filter_clk_cntr._eq(0), filter1(Concat(filter1[2:], filter0[1])) ) filtered = ((filter1[2] & filter1[1]) | (filter1[2] & filter1[0]) | (filter1[1] & filter1[0])) return filtered
def _impl(self): propagateClkRstn(self) cntr = self._reg("wordCntr", Bits(log2ceil(self.MAX_LEN)), defVal=0) en = self._reg("enable", defVal=0) _len = self._reg("wordCntr", Bits(log2ceil(self.MAX_LEN)), defVal=0) self.conv.bus(self.cntrl) cEn = self.conv.decoded.enable If(cEn.dout.vld, connect(cEn.dout.data, en, fit=True)) connect(en, cEn.din, fit=True) cLen = self.conv.decoded.len If(cLen.dout.vld, connect(cLen.dout.data, _len, fit=True)) connect(_len, cLen.din, fit=True) out = self.axis_out connect(cntr, out.data, fit=True) if self.USE_STRB: out.strb(mask(self.axis_out.strb._dtype.bit_length())) out.last(cntr._eq(0)) out.valid(en) If(cLen.dout.vld, connect(cLen.dout.data, cntr, fit=True)).Else( If(out.ready & en, If(cntr._eq(0), cntr(_len)).Else(cntr(cntr - 1))))
def _downscale(self, factor): inputRegs_cntr = self._reg("inputRegs_cntr", Bits(log2ceil(factor + 1), False), def_val=0) # instantiate HandshakedReg, handshaked builder is not used to avoid dependencies inReg = HandshakedReg(self.intfCls) inReg._updateParamsFrom(self.dataIn) self.inReg = inReg inReg.clk(self.clk) inReg.rst_n(self.rst_n) inReg.dataIn(self.dataIn) dataIn = inReg.dataOut dataOut = self.dataOut # create output mux for din, dout in zip(self.get_data(dataIn), self.get_data(dataOut)): widthOfPart = din._dtype.bit_length() // factor inParts = iterBits(din, bitsInOne=widthOfPart) Switch(inputRegs_cntr).add_cases( [(i, dout(inPart)) for i, inPart in enumerate(inParts)] ) vld = self.get_valid_signal rd = self.get_ready_signal vld(dataOut)(vld(dataIn)) self.get_ready_signal(dataIn)(inputRegs_cntr._eq(factor - 1) & rd(dataOut)) If(vld(dataIn) & rd(dataOut), If(inputRegs_cntr._eq(factor - 1), inputRegs_cntr(0) ).Else( inputRegs_cntr(inputRegs_cntr + 1) ) )
def axiWHandler(self, wErrFlag): w = self.w wIn = self.driver.w wInfo = self.writeInfoFifo.dataOut bInfo = self.bInfoFifo.dataIn if hasattr(w, "id"): # AXI3 has, AXI4 does not w.id(wInfo.id) w.data(wIn.data) w.strb(wIn.strb) if self.useTransSplitting(): wordCntr = self._reg("wWordCntr", self.a.len._dtype, 0) doSplit = wordCntr._eq(self.getAxiLenMax()) | wIn.last If( StreamNode([wInfo, wIn], [bInfo, w]).ack(), If(doSplit, wordCntr(0)).Else(wordCntr(wordCntr + 1))) else: doSplit = wIn.last extraConds = {wInfo: doSplit, bInfo: doSplit, w: ~wErrFlag} w.last(doSplit) bInfo.isLast(wIn.last) StreamNode(masters=[wIn, wInfo], slaves=[bInfo, w], extraConds=extraConds).sync()
def _impl(self): self._parseTemplate() # build read data output mux st_t = HEnum('st_t', ['idle', 'readDelay', 'rdData']) bus = self.bus addr = bus.address addrVld = bus.read | bus.write st = FsmBuilder(self, st_t)\ .Trans(st_t.idle, (addrVld & bus.read, st_t.rdData), (addrVld & bus.write, st_t.idle) ).Trans(st_t.readDelay, st_t.rdData ).Trans(st_t.rdData, st_t.idle ).stateReg wAck = True wr = bus.write & wAck isInAddrRange = (self.isInMyAddrRange(bus.address)) If(isInAddrRange, bus.response(RESP_OKAY) ).Else( bus.response(RESP_SLAVEERROR) ) bus.waitRequest(bus.read & ~st._eq(st_t.rdData)) bus.readDataValid(st._eq(st_t.rdData)) bus.writeResponseValid(wr) ADDR_STEP = self._getAddrStep() dataToBus = bus.readData(None) for (_, _), t in reversed(self._bramPortMapped): # map addr for bram ports _addr = t.bitAddr // ADDR_STEP _isMyAddr = inRange(addr, _addr, t.bitAddrEnd // ADDR_STEP) wasMyAddr = self._reg("wasMyAddr") If(st._eq(st_t.idle), wasMyAddr(_isMyAddr) ) port = self.getPort(t) self.propagateAddr(addr, ADDR_STEP, port.addr, port.dout._dtype.bit_length(), t) port.en(_isMyAddr & addrVld) port.we(_isMyAddr & wr) dataToBus = If(wasMyAddr & st._eq(st_t.rdData), bus.readData(port.dout) ).Else( dataToBus ) port.din(bus.writeData) self.connect_directly_mapped_write(addr, bus.writeData, wr) self.connect_directly_mapped_read(bus.address, bus.readData, dataToBus)
def _impl(self): propagateClkRstn(self) r = self._reg START_BIT = hBit(0) STOP_BIT = hBit(1) BITS_TO_SEND = 1 + 8 + 1 BIT_RATE = self.FREQ // self.BAUD assert BIT_RATE >= 1 din = self.dataIn data = r("data", Bits(BITS_TO_SEND)) # data + start bit + stop bit en = r("en", defVal=False) tick, last = ClkBuilder(self, self.clk).timers( [BIT_RATE, BIT_RATE * BITS_TO_SEND], en) If(~en & din.vld, data(Concat(STOP_BIT, din.data, START_BIT)), en(1)).Elif( tick & en, # srl where 1 is shifted from left data(hBit(1)._concat(data[:1])), If( last, en(0), )) din.rd(~en) txd = r("reg_txd", defVal=1) If(tick & en, txd(data[0])) self.txd(txd)
def _impl(self) -> None: start = self._sig("start") part_res_t = Bits(self.DATA_WIDTH) # High-order n bits of product a = self._reg("a", part_res_t) # multiplicand m = self._reg("m", part_res_t) # Initially holds multiplier, ultimately holds low-order n bits of product q = self._reg("q", part_res_t) # previous bit 0 of q q_1 = self._reg("q_1") din = self.dataIn dout = self.dataOut counter = self._reg( "counter", Bits(log2ceil(self.DATA_WIDTH + 1), signed=False), def_val=0) done = counter._eq(0) waitinOnConsumer = self._reg("waitinOnConsumer", def_val=0) add = rename_signal(self, (a + m)._signed(), "add") sub = rename_signal(self, (a - m)._signed(), "sub") If(start, a(0), m(din.a), q(din.b), q_1(0), counter(self.DATA_WIDTH), ).Elif(~done, Switch(Concat(q[0], q_1)) .Case(0b01, # add multiplicand to left half of product a(add >> 1), q(Concat(add[0], q[:1])), ).Case(0b10, # substract multiplicand from left half of product a(sub >> 1), q(Concat(sub[0], q[:1])), ).Default( a(a._signed() >> 1), q(Concat(a[0], q[:1])), ), q_1(q[0]), counter(counter - 1) ) If(start, waitinOnConsumer(1) ).Elif(done & dout.rd, waitinOnConsumer(0), ) dout.data(Concat(a, q)._vec()) dout.vld(done & waitinOnConsumer) start(din.vld & done & ~waitinOnConsumer) din.rd(done & ~waitinOnConsumer)
def fifo_pointers(self, DEPTH: int, write_en_wait: Tuple[RtlSignal, RtlSignal], read_en_wait_list: List[Tuple[RtlSignal, RtlSignal]])\ -> List[Tuple[RtlSignal, RtlSignal]]: """ Create fifo writer and reader pointers and enable/wait logic This functions supports multiple reader pointers :attention: writer pointer next logic check only last reader pointer :return: list, tule(en, ptr) for writer and each reader """ index_t = Bits(log2ceil(DEPTH), signed=False) # assert isPow2(DEPTH), DEPTH MAX_DEPTH = DEPTH - 1 s = self._sig r = self._reg fifo_write = s("fifo_write") write_ptr = _write_ptr = r("write_ptr", index_t, 0) ack_ptr_list = [ (fifo_write, write_ptr), ] # update writer (head) pointer as needed If( fifo_write, If(write_ptr._eq(MAX_DEPTH), write_ptr(0)).Else(write_ptr(write_ptr + 1))) write_en, _ = write_en_wait # instantiate all read pointers for i, (read_en, read_wait) in enumerate(read_en_wait_list): read_ptr = r(f"read_ptr{i:d}", index_t, 0) fifo_read = s(f"fifo_read{i:d}") ack_ptr_list.append((fifo_read, read_ptr)) # update reader (tail) pointer as needed If( fifo_read, If(read_ptr._eq(MAX_DEPTH), read_ptr(0)).Else(read_ptr(read_ptr + 1))) looped = r(f"looped{i:d}", def_val=False) # looped logic If(write_en & write_ptr._eq(MAX_DEPTH), looped(True)).Elif(read_en & read_ptr._eq(MAX_DEPTH), looped(False)) # Update Empty and Full flags read_wait(write_ptr._eq(read_ptr) & ~looped) fifo_read(read_en & (looped | (write_ptr != read_ptr))) # previous reader is next port writer (producer) as it next reader can continue only if previous reader did consume the item write_en, _ = read_en, read_wait write_ptr = read_ptr write_en, write_wait = write_en_wait write_ptr = _write_ptr # Update Empty and Full flags write_wait(write_ptr._eq(read_ptr) & looped) fifo_write(write_en & (~looped | (write_ptr != read_ptr))) return ack_ptr_list
def _impl(self): START_BIT = 0 STOP_BIT = 1 os = int(self.OVERSAMPLING) baud = int(self.BAUD) freq = int(self.FREQ) assert freq >= baud * os, "Frequency too low for current Baud rate and oversampling" assert os >= 8 and (os & (os - 1)) == 0, "Invalid oversampling value" propagateClkRstn(self) clkBuilder = ClkBuilder(self, self.clk) en = self._reg("en", defVal=0) first = self._reg("first", defVal=1) RxD_data = self._reg("RxD_data", Bits(1 + 8)) startBitWasNotStartbit = self._sig("startBitWasNotStartbit") # it can happen that there is just glitch on wire and bit was not startbit only begin was resolved wrong # eval because otherwise vhdl int overflows sampleTick = clkBuilder.timer( ("sampleTick", self.FREQ // self.BAUD // self.OVERSAMPLING), enableSig=en, rstSig=~en) # synchronize RxD to our clk domain RxD_sync = self._reg("RxD_sync", defVal=1) RxD_sync(self.rxd) rxd, rxd_vld = clkBuilder.oversample(RxD_sync, self.OVERSAMPLING, sampleTick, rstSig=~en) isLastBit = clkBuilder.timer(("isLastBitTick", 10), enableSig=rxd_vld, rstSig=~en) If( en, If( rxd_vld, RxD_data(Concat(rxd, RxD_data[9:1])), # shift data from left If( startBitWasNotStartbit, en(0), first(1), ).Else( en(~isLastBit), first(isLastBit), ))).Elif( RxD_sync._eq(START_BIT), # potential start bit detected, begin scanning sequence en(1), ) startBitWasNotStartbit(first & rxd_vld & (rxd != START_BIT)) self.dataOut.vld(isLastBit & RxD_data[0]._eq(START_BIT) & rxd._eq(STOP_BIT)) self.dataOut.data(RxD_data[9:1])
def _impl(self): r = self._reg("reg_d", Bits(2), def_val=0) If(self.a & self.b, If( self.c, r(0), )).Elif(self.c, r(1)).Else(r(2)) self.d(r)
def test_baicIf(self): a = self.n.sig('a') b = self.n.sig('b') obj = If(a, b(1) ).Else( b(0) ) container, io_change = obj._try_reduce() self.assertFalse(io_change) self.assertEqual(len(container), 1) container = container[0] tmpl = IfContainer(a, ifTrue=[b(1)], ifFalse=[b(0)]) self.compareStructure(tmpl, container)