def _impl(self): self._parseTemplate() bus = self.bus def connectRegIntfAlways(regIntf, _addr): return ( c(bus.din, regIntf.dout.data) + c(bus.we & bus.en & bus.addr._eq(_addr), regIntf.dout.vld) ) ADDR_STEP = self._getAddrStep() if self._directlyMapped: readReg = self._reg("readReg", dtype=bus.dout._dtype) # tuples (condition, assign statements) readRegInputs = [] for t in self._directlyMapped: port = self.getPort(t) _addr = t.bitAddr // ADDR_STEP connectRegIntfAlways(port, _addr) readRegInputs.append((bus.addr._eq(_addr), readReg(port.din) )) SwitchLogic(readRegInputs) else: readReg = None if self._bramPortMapped: BRAMS_CNT = len(self._bramPortMapped) bramIndxCases = [] readBramIndx = self._reg("readBramIndx", Bits( log2ceil(BRAMS_CNT + 1), False)) outputSwitch = Switch(readBramIndx) for i, t in enumerate(self._bramPortMapped): # if we can use prefix instead of addr comparing do it _addr = t.bitAddr // ADDR_STEP _addrEnd = t.bitAddrEnd // ADDR_STEP port = self.getPort(t) _addrVld, _ = self.propagateAddr(bus.addr, ADDR_STEP, port.addr, port.dout._dtype.bit_length(), t) port.we(bus.we & _addrVld & bus.en) port.en(bus.en & _addrVld & bus.en) port.din(bus.din) bramIndxCases.append((_addrVld, readBramIndx(i))) outputSwitch.Case(i, bus.dout(port.dout)) outputSwitch.Default(bus.dout(readReg)) SwitchLogic(bramIndxCases, default=readBramIndx(BRAMS_CNT)) else: bus.dout(readReg)
def generate_output_byte_mux(self, regs): out_mux_values = [set() for _ in range(self.word_bytes)] for st in self.state_trans_table.state_trans: for stt in st: for o_mux_val, out_mux_val_set in zip(stt.out_byte_mux_sel, out_mux_values): if o_mux_val is not None: out_mux_val_set.add(o_mux_val) out_mux_values = [sorted(x) for x in out_mux_values] def index_byte(sig, byte_i): return sig[(byte_i+1)*8:byte_i*8] def get_in_byte(input_i, time_offset, byte_i): return index_byte(regs[input_i][time_offset].data, byte_i) def data_drive(out_B, out_strb_b, input_i, time_offset, byte_i): res = [ out_B(get_in_byte(input_i, time_offset, byte_i)) ] if self.USE_STRB: res.append( out_strb_b(regs[input_i][time_offset].strb[byte_i]) ) return res out_byte_sel = [] for out_B_i, out_byte_mux_vals in enumerate(out_mux_values): # +1 because last value is used to invalidate data sel_w = log2ceil(len(out_byte_mux_vals) + 1) sel = self._sig(f"out_byte{out_B_i:d}_sel", Bits(sel_w)) out_byte_sel.append(sel) out_B = self._sig(f"out_byte{out_B_i:d}", Bits(8)) index_byte(self.dataOut.data, out_B_i)(out_B) if self.USE_STRB: out_strb_b = self._sig(f"out_strb{out_B_i:d}") self.dataOut.strb[out_B_i](out_strb_b) else: out_strb_b = None sw = Switch(sel).add_cases( (i, data_drive(out_B, out_strb_b, *val)) for i, val in enumerate(out_byte_mux_vals)) # :note: default case is threre for the case of faulire where # sel has non predicted value default_case = [out_B(None)] if self.USE_STRB: default_case.append(out_strb_b(0)) sw.Default(*default_case) return out_byte_sel, out_mux_values
def _impl(self): self._parseTemplate() bus = self.bus ADDR_STEP = self._getAddrStep() if self._directly_mapped_words: readReg = self._reg("readReg", dtype=bus.dout._dtype) # tuples (condition, assign statements) If(bus.en, self.connect_directly_mapped_read(bus.addr, readReg, []) ) self.connect_directly_mapped_write(bus.addr, bus.din, bus.en & bus.we) else: readReg = None if self._bramPortMapped: BRAMS_CNT = len(self._bramPortMapped) bramIndxCases = [] readBramIndx = self._reg("readBramIndx", Bits( log2ceil(BRAMS_CNT + 1), False)) outputSwitch = Switch(readBramIndx) for i, ((_, _), t) in enumerate(self._bramPortMapped): # if we can use prefix instead of addr comparing do it _addr = t.bitAddr // ADDR_STEP _addrEnd = t.bitAddrEnd // ADDR_STEP port = self.getPort(t) _addrVld, _ = self.propagateAddr(bus.addr, ADDR_STEP, port.addr, port.dout._dtype.bit_length(), t) port.we(bus.en & bus.we & _addrVld) port.en(bus.en & _addrVld) port.din(bus.din) bramIndxCases.append((_addrVld, readBramIndx(i))) outputSwitch.Case(i, bus.dout(port.dout)) outputSwitch.Default(bus.dout(readReg)) SwitchLogic(bramIndxCases, default=readBramIndx(BRAMS_CNT)) else: bus.dout(readReg)
def connect_directly_mapped_read(self, ar_addr: RtlSignal, r_data: RtlSignal, default_r_data_drive): """ Connect the RegCntrl.din interfaces to a bus """ DW = int(self.DATA_WIDTH) ADDR_STEP = self._getAddrStep() directlyMappedWords = [] for (w_i, items) in self._directly_mapped_words: w_data = [] last_end = w_i * DW for tpart in items: assert last_end == tpart.startOfPart, (last_end, tpart.startOfPart) if tpart.tmpl is None: # padding din = Bits(tpart.bit_length()).from_py(None) else: din = self.getPort(tpart.tmpl) if isinstance(din, RegCntrl): din = din.din if din._dtype.bit_length() > 1: fr = tpart.getFieldBitRange() din = din[fr[0]:fr[1]] w_data.append(din) last_end = tpart.endOfPart end_of_word = (w_i + 1) * DW assert last_end == end_of_word, (last_end, end_of_word) word_val = Concat(*reversed(w_data)) assert word_val._dtype.bit_length() == DW, (items, word_val) directlyMappedWords.append((w_i * (DW // ADDR_STEP), word_val)) mux = Switch(ar_addr).add_cases([ (word_i, r_data(val)) for (word_i, val) in directlyMappedWords ]) if default_r_data_drive: mux.Default(default_r_data_drive) return mux
def readPart(self, awAddr, w_hs): ADDR_STEP = self._getAddrStep() # build read data output mux r = self.bus.r ar = self.bus.ar rSt_t = HEnum('rSt_t', ['rdIdle', 'bramRd', 'rdData']) isBramAddr = self._sig("isBramAddr") rSt = FsmBuilder(self, rSt_t, stateRegName='rSt')\ .Trans(rSt_t.rdIdle, (ar.valid & ~isBramAddr & ~w_hs, rSt_t.rdData), (ar.valid & isBramAddr & ~w_hs, rSt_t.bramRd) ).Trans(rSt_t.bramRd, (~w_hs, rSt_t.rdData) ).Trans(rSt_t.rdData, (r.ready, rSt_t.rdIdle) ).stateReg arRd = rSt._eq(rSt_t.rdIdle) ar.ready(arRd & ~w_hs) # save ar addr arAddr = self._reg('arAddr', ar.addr._dtype) If(ar.valid & arRd, arAddr(ar.addr)) isInAddrRange = self.isInMyAddrRange(arAddr) r.valid(rSt._eq(rSt_t.rdData)) self.driveResp(isInAddrRange, r.resp) if self._bramPortMapped: rdataReg = self._reg("rdataReg", r.data._dtype) _isInBramFlags = [] # list of tuples (cond, rdataReg assignment) rregCases = [] # index of bram from where we reads from bramRdIndx = self._reg("bramRdIndx", Bits(log2ceil(len(self._bramPortMapped)))) bramRdIndxSwitch = Switch(bramRdIndx) for bramIndex, ((base, end), t) in enumerate(self._bramPortMapped): port = self.getPort(t) # map addr for bram ports dstAddrStep = port.dout._dtype.bit_length() (_isMyArAddr, arAddrConnect) = self.propagateAddr(ar.addr, ADDR_STEP, port.addr, dstAddrStep, t) (_, ar2AddrConnect) = self.propagateAddr(arAddr, ADDR_STEP, port.addr, dstAddrStep, t) (_isMyAwAddr, awAddrConnect) = self.propagateAddr(awAddr, ADDR_STEP, port.addr, dstAddrStep, t) prioritizeWrite = w_hs & _isMyAwAddr If(prioritizeWrite, awAddrConnect).Elif(rSt._eq(rSt_t.rdIdle), arAddrConnect).Else(ar2AddrConnect) _isInBramFlags.append(_isMyArAddr) port.en((ar.valid & _isMyArAddr) | prioritizeWrite) port.we(prioritizeWrite) rregCases.append((_isMyArAddr, bramRdIndx(bramIndex))) bramRdIndxSwitch.Case(bramIndex, rdataReg(port.dout)) bramRdIndxSwitch.Default(rdataReg(rdataReg)) If(arRd, SwitchLogic(rregCases)) isBramAddr(Or(*_isInBramFlags)) else: rdataReg = None isBramAddr(0) self.connect_directly_mapped_read(arAddr, r.data, r.data(rdataReg))
def readPart(self, awAddr, w_hs): ADDR_STEP = self._getAddrStep() DW = int(self.DATA_WIDTH) # build read data output mux r = self.bus.r ar = self.bus.ar rSt_t = HEnum('rSt_t', ['rdIdle', 'bramRd', 'rdData']) isBramAddr = self._sig("isBramAddr") rSt = FsmBuilder(self, rSt_t, stateRegName='rSt')\ .Trans(rSt_t.rdIdle, (ar.valid & ~isBramAddr & ~w_hs, rSt_t.rdData), (ar.valid & isBramAddr & ~w_hs, rSt_t.bramRd) ).Trans(rSt_t.bramRd, (~w_hs, rSt_t.rdData) ).Trans(rSt_t.rdData, (r.ready, rSt_t.rdIdle) ).stateReg arRd = rSt._eq(rSt_t.rdIdle) ar.ready(arRd & ~w_hs) # save ar addr arAddr = self._reg('arAddr', ar.addr._dtype) If(ar.valid & arRd, arAddr(ar.addr)) isInAddrRange = self.isInMyAddrRange(arAddr) r.valid(rSt._eq(rSt_t.rdData)) If(isInAddrRange, r.resp(RESP_OKAY)).Else(r.resp(RESP_SLVERR)) if self._bramPortMapped: rdataReg = self._reg("rdataReg", r.data._dtype) _isInBramFlags = [] # list of tuples (cond, rdataReg assignment) rregCases = [] # index of bram from where we reads from bramRdIndx = self._reg("bramRdIndx", Bits(log2ceil(len(self._bramPortMapped)))) bramRdIndxSwitch = Switch(bramRdIndx) for bramIndex, t in enumerate(self._bramPortMapped): port = self.getPort(t) # map addr for bram ports dstAddrStep = port.dout._dtype.bit_length() (_isMyArAddr, arAddrConnect) = self.propagateAddr(ar.addr, ADDR_STEP, port.addr, dstAddrStep, t) (_, ar2AddrConnect) = self.propagateAddr(arAddr, ADDR_STEP, port.addr, dstAddrStep, t) (_isMyAwAddr, awAddrConnect) = self.propagateAddr(awAddr, ADDR_STEP, port.addr, dstAddrStep, t) prioritizeWrite = _isMyAwAddr & w_hs If(prioritizeWrite, awAddrConnect).Elif(rSt._eq(rSt_t.rdIdle), arAddrConnect).Else(ar2AddrConnect) _isInBramFlags.append(_isMyArAddr) port.en((_isMyArAddr & ar.valid) | prioritizeWrite) port.we(prioritizeWrite) rregCases.append((_isMyArAddr, bramRdIndx(bramIndex))) bramRdIndxSwitch.Case(bramIndex, rdataReg(port.dout)) bramRdIndxSwitch.Default(rdataReg(rdataReg)) If(arRd, SwitchLogic(rregCases)) isBramAddr(Or(*_isInBramFlags)) else: rdataReg = None isBramAddr(0) directlyMappedWors = [] for w, items in sorted(groupedby( self._directlyMapped, lambda t: t.bitAddr // DW * (DW // ADDR_STEP)), key=lambda x: x[0]): lastBit = 0 res = [] items.sort(key=lambda t: t.bitAddr) for t in items: b = t.bitAddr % DW if b > lastBit: # add padding pad_w = b - lastBit pad = Bits(pad_w).fromPy(None) res.append(pad) lastBit += pad_w din = self.getPort(t).din res.append(din) lastBit += din._dtype.bit_length() if lastBit != DW: # add at end padding pad = Bits(DW - lastBit).fromPy(None) res.append(pad) directlyMappedWors.append((w, Concat(*reversed(res)))) Switch(arAddr).addCases([ (w[0], r.data(w[1])) for w in directlyMappedWors ]).Default(r.data(rdataReg))
def _create_frame_build_logic(self): self.byteOrderCare = get_byte_order_modifier(self.dataOut) STRB_ALL = mask(int(self.DATA_WIDTH // 8)) words = list(self.chainFrameWords()) dout = self.dataOut maxWordIndex = words[-1][0] multipleWords = maxWordIndex > 0 if multipleWords: # multiple word frame wordCntr_inversed = self._reg("wordCntr_inversed", Bits(log2ceil(maxWordIndex + 1), False), def_val=maxWordIndex) wcntrSw = Switch(wordCntr_inversed) # inversed indexes of ends of frames endsOfFrames = [] extra_strbs = [] extra_keeps = [] for i, transParts, isLast in words: inversedIndx = maxWordIndex - i # input ports for value of this output word inPorts = [] # input ports which value should be consumed on this word lastInPorts = [] if multipleWords: wordData = self._sig(f"word{i:d}", dout.data._dtype) else: wordData = self.dataOut.data sk_stash = StrbKeepStash() for tPart in transParts: strb, keep = self.connectPartsOfWord(wordData, tPart, inPorts, lastInPorts) sk_stash.push(strb, keep) sk_stash.pop(inversedIndx, extra_strbs, extra_keeps, STRB_ALL) if multipleWords: en = wordCntr_inversed._eq(inversedIndx) else: en = True en = self.dataOut.ready & en ack = self.handshakeLogicForWord(inPorts, lastInPorts, en) inStreamLast = True for p in inPorts: if isinstance(p, AxiStream): inStreamLast = p.last & inStreamLast if multipleWords: # word cntr next logic if i == maxWordIndex: nextWordIndex = maxWordIndex else: nextWordIndex = wordCntr_inversed - 1 _ack = dout.ready & ack & inStreamLast a = [ If(_ack, wordCntr_inversed(nextWordIndex)), ] else: a = [] a.append(dout.valid(ack)) # frame with multiple words (using wordCntr_inversed) if multipleWords: # data out logic a.append(dout.data(wordData)) wcntrSw.Case(inversedIndx, a) # is last word in frame if isLast: endsOfFrames.append((inversedIndx, inStreamLast)) # to prevent latches if not multipleWords: pass elif not isPow2(maxWordIndex + 1): default = [ wordCntr_inversed(maxWordIndex), ] default.append(dout.valid(0)) default.append(dout.data(None)) wcntrSw.Default(default) if multipleWords: last = False last_last = last for indexOrTuple in endsOfFrames: i, en = indexOrTuple last_last = wordCntr_inversed._eq(i) & en last = (last_last) | last selectRegLoad = last_last & dout.ready & ack else: last = endsOfFrames[0][1] selectRegLoad = dout.ready & ack for r in self._tmpRegsForSelect.values(): r.rd(selectRegLoad) dout.last(last) if multipleWords: if self.USE_STRB: strb = dout.strb Switch(wordCntr_inversed).add_cases([ (i, strb(v)) for i, v in extra_strbs ]).Default(strb(STRB_ALL)) if self.USE_KEEP: keep = dout.keep Switch(wordCntr_inversed).add_cases([ (i, keep(v)) for i, v in extra_keeps ]).Default(keep(STRB_ALL)) else: if extra_strbs: m = extra_strbs[0][1] else: m = STRB_ALL if self.USE_STRB: dout.strb(m) if extra_keeps: m = extra_keeps[0][1] else: m = STRB_ALL if self.USE_KEEP: dout.keep(m)
def _impl(self) -> None: _string_rom, strings_offset_and_size, max_chars_per_format, max_bcd_digits = self.build_string_rom( ) if self.DATA_WIDTH != 8: # it self.DATA_WIDTH != 1B we need to handle all possible alignments and shifts, precompute some strings # because number of string memory ports is limited etc. raise NotImplementedError() # instanciate bin_to_bcd if required if max_bcd_digits > 0: bin_to_bcd = BinToBcd() bin_to_bcd.INPUT_WIDTH = log2ceil(10**max_bcd_digits - 1) self.bin_to_bcd = bin_to_bcd # tuples (cond, input) to_bcd_inputs = [] string_rom = self._sig("string_rom", Bits(8)[len(_string_rom)], def_val=[int(c) for c in _string_rom]) char_i = self._reg("char_i", Bits(log2ceil(max_chars_per_format), signed=False), def_val=0) # create an iterator over all characters element_cnt = len(self.FORMAT) dout = self.data_out if element_cnt == 1: en = 1 f_i = 0 f = self.FORMAT[f_i] _, out_vld, out_last = self.connect_single_format_group( f_i, f, strings_offset_and_size, string_rom, char_i, to_bcd_inputs, en) char_i_rst = out_last else: main_st = self._reg("main_st", Bits(log2ceil(element_cnt), signed=False), def_val=0) char_i_rst = out_last = out_vld = BIT.from_py(0) main_st_fsm = Switch(main_st) for is_last_f, (f_i, f) in iter_with_last(enumerate(self.FORMAT)): en = main_st._eq(f_i) data_drive, in_vld, in_last = self.connect_single_format_group( f_i, f, strings_offset_and_size, string_rom, char_i, to_bcd_inputs, en) # build out vld from all input valids out_vld = out_vld | (en & in_vld) # keep only last of the last part out_last = en & in_last char_i_rst = char_i_rst | out_last main_st_fsm.Case( f_i, If(dout.ready & in_vld & in_last, main_st(0) if is_last_f else main_st(main_st + 1)), *data_drive) main_st_fsm.Default(main_st(None), dout.data(None)) dout.valid(out_vld) dout.last(out_last) If(dout.ready & out_vld, If(char_i_rst, char_i(0)).Else(char_i(char_i + 1))) if to_bcd_inputs: in_ = bin_to_bcd.din SwitchLogic( # actual value may be smaller, because bcd is shared among # multiple input formats [(c, in_.data(fitTo(v, in_.data, shrink=False))) for c, v in to_bcd_inputs], default=in_.data(None)) in_.vld(char_i._eq(0) & Or(*(c for c, _ in to_bcd_inputs))) propagateClkRstn(self)
def _impl(self): """ Iterate over words in template and create stream output mux and fsm. Frame specifier can contains unions/streams/padding/unaligned items and other features which makes code below complex. Frame specifier can also describe multiple frames. """ if self.IS_BIGENDIAN: byteOrderCare = reverseByteOrder else: def byteOrderCare(sig): return sig self.byteOrderCare = byteOrderCare words = list(self.chainFrameWords()) dout = self.dataOut self.parseTemplate() maxWordIndex = words[-1][0] multipleWords = maxWordIndex > 0 if multipleWords: # multiple word frame wordCntr_inversed = self._reg("wordCntr_inversed", Bits(log2ceil(maxWordIndex + 1), False), defVal=maxWordIndex) wcntrSw = Switch(wordCntr_inversed) # inversed indexes of ends of frames endsOfFrames = [] extra_strbs = [] for i, transParts, isLast in words: inversedIndx = maxWordIndex - i # input ports for value of this output word inPorts = [] # input ports witch value should be consumed on this word lastInPorts = [] if multipleWords: wordData = self._sig("word%d" % i, dout.data._dtype) else: wordData = self.dataOut.data for tPart in transParts: extra_strb = self.connectPartsOfWord(wordData, tPart, inPorts, lastInPorts) if extra_strb is not None: if len(transParts) > 1: raise NotImplementedError( "Construct rest of the strb signal") extra_strbs.append((inversedIndx, extra_strb)) if multipleWords: en = wordCntr_inversed._eq(inversedIndx) else: en = True en = self.dataOut.ready & en ack = self.handshakeLogicForWord(inPorts, lastInPorts, en) inStreamLast = True for p in inPorts: if isinstance(p, AxiStream): inStreamLast = p.last & inStreamLast if multipleWords: # word cntr next logic if i == maxWordIndex: nextWordIndex = maxWordIndex else: nextWordIndex = wordCntr_inversed - 1 _ack = dout.ready & ack & inStreamLast a = [ If(_ack, wordCntr_inversed(nextWordIndex)), ] else: a = [] a.append(dout.valid(ack)) # frame with multiple words (using wordCntr_inversed) if multipleWords: # data out logic a.append(dout.data(wordData)) wcntrSw.Case(inversedIndx, a) # is last word in frame if isLast: endsOfFrames.append((inversedIndx, inStreamLast)) # to prevent latches if not multipleWords: pass elif not isPow2(maxWordIndex + 1): default = wordCntr_inversed(maxWordIndex) default.append(dout.valid(0)) default.append(dout.data(None)) wcntrSw.Default(default) if multipleWords: last = False last_last = last for indexOrTuple in endsOfFrames: i, en = indexOrTuple last_last = wordCntr_inversed._eq(i) & en last = (last_last) | last selectRegLoad = last_last & dout.ready & ack else: last = endsOfFrames[0][1] selectRegLoad = dout.ready & ack for r in self._tmpRegsForSelect.values(): r.rd(selectRegLoad) dout.last(last) strb = dout.strb STRB_ALL = mask(int(self.DATA_WIDTH // 8)) if multipleWords: Switch(wordCntr_inversed).addCases([ (i, strb(v)) for i, v in extra_strbs ]).Default(strb(STRB_ALL)) else: if extra_strbs: strb(extra_strbs[0][1]) else: strb(STRB_ALL)