def _impl(self): self._parseTemplate() # build read data output mux st_t = HEnum('st_t', ['idle', "writeAck", 'readDelay', 'rdData']) ipif = self.bus addr = ipif.bus2ip_addr ipif.ip2bus_error(0) addrVld = ipif.bus2ip_cs isInMyAddrSpace = self.isInMyAddrRange(addr) st = FsmBuilder(self, st_t)\ .Trans(st_t.idle, (addrVld & isInMyAddrSpace & ipif.bus2ip_rnw, st_t.rdData), (addrVld & isInMyAddrSpace & ~ipif.bus2ip_rnw, st_t.writeAck) ).Trans(st_t.writeAck, st_t.idle ).Trans(st_t.readDelay, st_t.rdData ).Trans(st_t.rdData, st_t.idle ).stateReg wAck = st._eq(st_t.writeAck) ipif.ip2bus_rdack(st._eq(st_t.rdData)) ipif.ip2bus_wrack(wAck) ADDR_STEP = self._getAddrStep() dataToBus = ipif.ip2bus_data(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) port = self.getPort(t) self.propagateAddr(addr, ADDR_STEP, port.addr, port.dout._dtype.bit_length(), t) port.en(_isMyAddr & ipif.bus2ip_cs) port.we(_isMyAddr & wAck) dataToBus = If(_isMyAddr, ipif.ip2bus_data(port.dout)).Else(dataToBus) port.din(ipif.bus2ip_data) self.connect_directly_mapped_write(ipif.bus2ip_addr, ipif.bus2ip_data, ~ipif.bus2ip_rnw & wAck) self.connect_directly_mapped_read(ipif.bus2ip_addr, ipif.ip2bus_data, dataToBus)
def baseAddrLogic(self, nextBlockTransition_in): """ Logic for downloading address of next block :param nextBlockTransition_in: signal which means that baseIndex should be changed to nextBaseIndex if nextBaseAddrReady is not high this signal has no effect (= regular handshake) :return: (baseIndex, nextBaseIndex, nextBaseReady is ready and nextBlockTransition_in can be used) """ r = self._reg rIn = self.rDatapump.r rReq = self.rDatapump.req addr_index_t = Bits(self.ADDR_WIDTH - self.ALIGN_BITS) baseIndex = r("baseIndex_backup", addr_index_t) nextBaseIndex = r("nextBaseIndex", addr_index_t) t = HEnum("nextBaseFsm_t", ["uninitialized", "required", "pending", "prepared"]) isNextBaseAddr = rIn.valid & rIn.id._eq(self.ID) nextBaseFsm = FsmBuilder(self, t, "baseAddrLogic_fsm")\ .Trans(t.uninitialized, (self.baseAddr.dout.vld, t.required) ).Trans(t.required, (rReq.rd, t.pending) ).Trans(t.pending, (isNextBaseAddr, t.prepared) ).Trans(t.prepared, (nextBlockTransition_in, t.required) ).stateReg If(self.baseAddr.dout.vld, baseIndex(self.addrToIndex(self.baseAddr.dout.data)), ).Elif(nextBlockTransition_in, baseIndex(nextBaseIndex) ) self.baseAddr.din(self.indexToAddr(baseIndex)) If(isNextBaseAddr, nextBaseIndex(self.addrToIndex(fitTo(rIn.data, rReq.addr))) ) rIn.ready(1) self.rReqHandler(baseIndex, nextBaseFsm._eq(t.required)) nextBaseReady = nextBaseFsm._eq(t.prepared) return baseIndex, nextBaseIndex, nextBaseReady
def writePart(self): sig = self._sig reg = self._reg wSt_t = HEnum('wSt_t', ['wrIdle', 'wrData', 'wrResp']) aw = self.bus.aw w = self.bus.w b = self.bus.b # write fsm wSt = FsmBuilder(self, wSt_t, "wSt")\ .Trans(wSt_t.wrIdle, (aw.valid, wSt_t.wrData) ).Trans(wSt_t.wrData, (w.valid, wSt_t.wrResp) ).Trans(wSt_t.wrResp, (b.ready, wSt_t.wrIdle) ).stateReg awAddr = reg('awAddr', aw.addr._dtype) w_hs = sig('w_hs') awRd = wSt._eq(wSt_t.wrIdle) aw.ready(awRd) aw_hs = awRd & aw.valid wRd = wSt._eq(wSt_t.wrData) w.ready(wRd) w_hs(w.valid & wRd) # save aw addr If(aw_hs, awAddr(aw.addr) ).Else( awAddr(awAddr) ) self.connect_directly_mapped_write(awAddr, w.data, w_hs) for (_, _), t in self._bramPortMapped: # en, we handled in readPart din = self.getPort(t).din din(w.data, fit=True) self.writeRespPart(awAddr, wSt._eq(wSt_t.wrResp)) return awAddr, w_hs
def baseAddrLogic(self, nextBlockTransition_in): """ Logic for downloading address of next block :param nextBlockTransition_in: signal which means that baseIndex should be changed to nextBaseIndex if nextBaseAddrReady is not high this signal has no effect (= regular handshake) :return: (baseIndex, nextBaseIndex, nextBaseReady is ready and nextBlockTransition_in can be used) """ r = self._reg rIn = self.rDatapump.r rReq = self.rDatapump.req addr_index_t = Bits(self.ADDR_WIDTH - self.ALIGN_BITS) baseIndex = r("baseIndex_backup", addr_index_t) nextBaseIndex = r("nextBaseIndex", addr_index_t) t = HEnum("nextBaseFsm_t", ["uninitialized", "required", "pending", "prepared"]) isNextBaseAddr = rIn.valid & rIn.id._eq(self.ID) nextBaseFsm = FsmBuilder(self, t, "baseAddrLogic_fsm")\ .Trans(t.uninitialized, (self.baseAddr.dout.vld, t.required) ).Trans(t.required, (rReq.rd, t.pending) ).Trans(t.pending, (isNextBaseAddr, t.prepared) ).Trans(t.prepared, (nextBlockTransition_in, t.required) ).stateReg If( self.baseAddr.dout.vld, baseIndex(self.addrToIndex(self.baseAddr.dout.data)), ).Elif(nextBlockTransition_in, baseIndex(nextBaseIndex)) self.baseAddr.din(self.indexToAddr(baseIndex)) If(isNextBaseAddr, nextBaseIndex(self.addrToIndex(fitTo(rIn.data, rReq.addr)))) rIn.ready(1) self.rReqHandler(baseIndex, nextBaseFsm._eq(t.required)) nextBaseReady = nextBaseFsm._eq(t.prepared) return baseIndex, nextBaseIndex, nextBaseReady
def _io_core( self, data_in: Hd44780CmdIntf, cmd_timer_rst, lcd_clk_en: RtlSignal, delay_cmd_half_done: RtlSignal, delay_cmd_done: RtlSignal, delay_cmd_long_done: RtlSignal): st_t = HEnum("st_t", [ "init_delay_after_powerup", "idle", "write", # cmd/data ]) is_long_cmd = self._reg("is_long_cmd") st = FsmBuilder(self, st_t, "st")\ .Trans(st_t.init_delay_after_powerup, (delay_cmd_long_done, st_t.idle))\ .Trans(st_t.idle, (data_in.vld, st_t.write))\ .Trans(st_t.write, ((is_long_cmd & delay_cmd_long_done) | (~is_long_cmd & delay_cmd_done), st_t.idle))\ .stateReg cmd_timer_rst(st._eq(st_t.idle)) data_in.rd(st._eq(st_t.write) & ((delay_cmd_done & ~is_long_cmd) | (delay_cmd_long_done & is_long_cmd))) data_out = self.dataOut data_out.d(data_in.d) data_out.rw(data_in.rw) data_out.rs(data_in.rs) en_in_first_half_period = self._reg("en_in_first_half_period", def_val=1) If(st._eq(st_t.idle), is_long_cmd(data_in.long_wait), en_in_first_half_period(1), ).Elif(en_in_first_half_period & delay_cmd_half_done, en_in_first_half_period(0), ) en_delay = self._reg("en_delay", def_val=0) If(lcd_clk_en, en_delay((st != st_t.idle) & en_in_first_half_period) ) data_out.en(en_delay)
def _impl(self): self._parseTemplate() # build read data output mux def isMyAddr(addrSig, addr, end): return (addrSig >= addr) & (addrSig < end) 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 = isMyAddr(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) for t in self._directlyMapped: _addr = t.bitAddr // ADDR_STEP port = self.getPort(t) port.dout.vld(addr._eq(_addr) & wr) port.dout.data(bus.writeData) _isInBramFlags = [] Switch(bus.address)\ .addCases( [(t.bitAddr // ADDR_STEP, bus.readData(self.getPort(t).din)) for t in self._directlyMapped] ).Default( dataToBus )
def _impl(self): propagateClkRstn(self) lookupRes = self.lookupRes tables = self.tables # stash is storage for item which is going to be swapped with actual stash_t = HStruct( (Bits(self.KEY_WIDTH), "key"), (Bits(self.DATA_WIDTH), "data"), (BIT, "vldFlag") ) stash = self._reg("stash", stash_t) lookupOrigin = self._reg("lookupOrigin", Bits(2)) cleanAck = self._sig("cleanAck") cleanAddr, cleanLast = self.cleanUpAddrIterator(cleanAck) lookupResRead = self._sig("lookupResRead") lookupResNext = self._sig("lookupResNext") (lookupResAck, insertFinal, insertFound, targetOH) = self.lookupResOfTablesDriver(lookupResRead, lookupResNext) lookupAck = StreamNode(slaves=map(lambda t: t.lookup, tables)).ack() insertAck = StreamNode(slaves=map(lambda t: t.insert, tables)).ack() fsm_t = HEnum("insertFsm_t", ["idle", "cleaning", "lookup", "lookupResWaitRd", "lookupResAck"]) isExternLookup = lookupOrigin._eq(ORIGIN_TYPE.LOOKUP) state = FsmBuilder(self, fsm_t, "insertFsm")\ .Trans(fsm_t.idle, (self.clean.vld, fsm_t.cleaning), # before each insert suitable place has to be searched first (self.insert.vld | self.lookup.vld | self.delete.vld, fsm_t.lookup) ).Trans(fsm_t.cleaning, # walk all items and clean it's vldFlags (cleanLast, fsm_t.idle) ).Trans(fsm_t.lookup, # search and resolve in which table item # should be stored (lookupAck, fsm_t.lookupResWaitRd) ).Trans(fsm_t.lookupResWaitRd, # process result of lookup and # write data stash to tables if # required (lookupResAck, fsm_t.lookupResAck) ).Trans(fsm_t.lookupResAck, # process lookupRes, if we are going to insert on place where # valid item is, it has to # be stored (lookupOrigin._eq( ORIGIN_TYPE.DELETE), fsm_t.idle), (isExternLookup & lookupRes.rd, fsm_t.idle), # insert into specified # table (~isExternLookup & insertAck & insertFinal, fsm_t.idle), (~isExternLookup & insertAck & ~insertFinal, fsm_t.lookup) ).stateReg cleanAck(StreamNode(slaves=[t.insert for t in tables]).ack() & state._eq(fsm_t.cleaning)) lookupResRead(state._eq(fsm_t.lookupResWaitRd)) lookupResNext(And(state._eq(fsm_t.lookupResAck), Or(lookupOrigin != ORIGIN_TYPE.LOOKUP, lookupRes.rd))) isIdle = state._eq(fsm_t.idle) self.stashLoad(isIdle, stash, lookupOrigin) insertIndex = self.insertAddrSelect(targetOH, state, cleanAddr) self.insetOfTablesDriver( state, targetOH, insertIndex, stash, isExternLookup) self.lookupResDriver(state, lookupOrigin, lookupAck, insertFound) self.lookupOfTablesDriver(state, stash.key)
def _impl(self): self._parseTemplate() # build read data output mux def isMyAddr(addrSig, addr, end): return (addrSig >= addr) & (addrSig < end) 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 = isMyAddr(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) for t in self._directlyMapped: _addr = t.bitAddr // ADDR_STEP port = self.getPort(t) port.dout.vld(addr._eq(_addr) & wr) port.dout.data(bus.writeData) _isInBramFlags = [] Switch(bus.address)\ .addCases( [(t.bitAddr // ADDR_STEP, bus.readData(self.getPort(t).din)) for t in self._directlyMapped] ).Default( dataToBus )
def _impl(self): self._parseTemplate() # build read data output mux def isMyAddr(addrSig, addr, end): return (addrSig >= addr) & (addrSig < end) st_t = HEnum('st_t', ['idle', "writeAck", 'readDelay', 'rdData']) ipif = self.bus addr = ipif.bus2ip_addr ipif.ip2bus_error(0) addrVld = ipif.bus2ip_cs isInMyAddrSpace = self.isInMyAddrRange(addr) st = FsmBuilder(self, st_t)\ .Trans(st_t.idle, (addrVld & isInMyAddrSpace & ipif.bus2ip_rnw, st_t.rdData), (addrVld & isInMyAddrSpace & ~ipif.bus2ip_rnw, st_t.writeAck) ).Trans(st_t.writeAck, st_t.idle ).Trans(st_t.readDelay, st_t.rdData ).Trans(st_t.rdData, st_t.idle ).stateReg wAck = st._eq(st_t.writeAck) ipif.ip2bus_rdack(st._eq(st_t.rdData)) ipif.ip2bus_wrack(wAck) ADDR_STEP = self._getAddrStep() dataToBus = ipif.ip2bus_data(None) for t in reversed(self._bramPortMapped): # map addr for bram ports _addr = t.bitAddr // ADDR_STEP _isMyAddr = isMyAddr(addr, _addr, t.bitAddrEnd // ADDR_STEP) port = self.getPort(t) self.propagateAddr(addr, ADDR_STEP, port.addr, port.dout._dtype.bit_length(), t) port.en(_isMyAddr & ipif.bus2ip_cs) port.we(_isMyAddr & wAck) dataToBus = If(_isMyAddr, ipif.ip2bus_data(port.dout) ).Else( dataToBus ) port.din(ipif.bus2ip_data) for t in self._directlyMapped: _addr = t.bitAddr // ADDR_STEP port = self.getPort(t) port.dout.vld(addr._eq(_addr) & ~ipif.bus2ip_rnw & wAck) port.dout.data(ipif.bus2ip_data) _isInBramFlags = [] Switch(ipif.bus2ip_addr)\ .addCases( [(t.bitAddr // ADDR_STEP, ipif.ip2bus_data(self.getPort(t).din)) for t in self._directlyMapped] ).Default( dataToBus )
def _impl(self): self._parseTemplate() # build read data output mux def isMyAddr(addrSig, addr, end): return (addrSig >= addr) & (addrSig < end) st_t = HEnum('st_t', ['idle', "writeAck", 'readDelay', 'rdData']) ipif = self.bus addr = ipif.bus2ip_addr ipif.ip2bus_error(0) addrVld = ipif.bus2ip_cs isInMyAddrSpace = self.isInMyAddrRange(addr) st = FsmBuilder(self, st_t)\ .Trans(st_t.idle, (addrVld & isInMyAddrSpace & ipif.bus2ip_rnw, st_t.rdData), (addrVld & isInMyAddrSpace & ~ipif.bus2ip_rnw, st_t.writeAck) ).Trans(st_t.writeAck, st_t.idle ).Trans(st_t.readDelay, st_t.rdData ).Trans(st_t.rdData, st_t.idle ).stateReg wAck = st._eq(st_t.writeAck) ipif.ip2bus_rdack(st._eq(st_t.rdData)) ipif.ip2bus_wrack(wAck) ADDR_STEP = self._getAddrStep() dataToBus = ipif.ip2bus_data(None) for t in reversed(self._bramPortMapped): # map addr for bram ports _addr = t.bitAddr // ADDR_STEP _isMyAddr = isMyAddr(addr, _addr, t.bitAddrEnd // ADDR_STEP) port = self.getPort(t) self.propagateAddr(addr, ADDR_STEP, port.addr, port.dout._dtype.bit_length(), t) port.en(_isMyAddr & ipif.bus2ip_cs) port.we(_isMyAddr & wAck) dataToBus = If(_isMyAddr, ipif.ip2bus_data(port.dout)).Else(dataToBus) port.din(ipif.bus2ip_data) for t in self._directlyMapped: _addr = t.bitAddr // ADDR_STEP port = self.getPort(t) port.dout.vld(addr._eq(_addr) & ~ipif.bus2ip_rnw & wAck) port.dout.data(ipif.bus2ip_data) _isInBramFlags = [] Switch(ipif.bus2ip_addr)\ .addCases( [(t.bitAddr // ADDR_STEP, ipif.ip2bus_data(self.getPort(t).din)) for t in self._directlyMapped] ).Default( dataToBus )
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 _impl(self): propagateClkRstn(self) # stash is storage for item which is going to be swapped with actual stash_t = HStruct( (Bits(self.KEY_WIDTH), "key"), (Bits(self.DATA_WIDTH), "data"), (Bits(log2ceil(self.MAX_REINSERT + 1)), "reinsert_cntr"), (BIT, "item_vld"), (ORIGIN_TYPE, "origin_op"), ) stash = self._reg("stash", stash_t, def_val={"origin_op": ORIGIN_TYPE.DELETE}) cleanAck = self._sig("cleanAck") cleanAddr, cleanLast = self.clean_addr_iterator(cleanAck) lookupResRead = self._sig("lookupResRead") (lookupResVld, insertFinal, lookupFoundOH, insertTargetOH) = self.tables_lookupRes_resolver(lookupResRead) lookupAck = StreamNode(slaves=[t.lookup for t in self.tables]).ack() insertAck = StreamNode(slaves=[t.insert for t in self.tables]).ack() lookup_in_progress = self.lookup_trans_cntr() lookup_not_in_progress = rename_signal(self, lookup_in_progress._eq(0) & (stash.origin_op != ORIGIN_TYPE.LOOKUP), "lookup_not_in_progress") isDelete = stash.origin_op._eq(ORIGIN_TYPE.DELETE) isInsert = stash.origin_op._eq(ORIGIN_TYPE.INSERT) # lookup is not blocking and does not use FSM bellow # this FSM handles only lookup for insert/delete fsm_t = HEnum("insertFsm_t", ["idle", "cleaning", "lookup", "lookupResWaitRd", "lookupResAck"]) state = FsmBuilder(self, fsm_t, "insertFsm")\ .Trans(fsm_t.idle, # wait before lookup_in_progress reaches 0 # (new transactions should not be allowed if command has vld) (lookup_not_in_progress & self.clean.vld, fsm_t.cleaning), # before each insert suitable place has to be searched first (lookup_not_in_progress & (self.insert.vld | self.delete.vld), fsm_t.lookup) ).Trans(fsm_t.cleaning, # walk all items and clean it's item_vlds (insertAck & cleanLast, fsm_t.idle), ).Trans(fsm_t.lookup, # insert timeout (stash.reinsert_cntr._eq(0) & isInsert & self.insertRes.rd, fsm_t.idle), # search and resolve in which table item # should be stored (((stash.reinsert_cntr != 0) | ~isInsert) & lookupAck, fsm_t.lookupResWaitRd) ).Trans(fsm_t.lookupResWaitRd, # process result of lookup and (lookupResVld, fsm_t.lookupResAck) ).Trans(fsm_t.lookupResAck, # process lookupRes, if we are going to insert on place where # valid item is, this item has to be stored to stash (isDelete, fsm_t.idle), # insert into specified table (insertAck & insertFinal & (isDelete | self.insertRes.rd), fsm_t.idle), # insert and swap with some valid item from the table # which we need to store somewhere as well (insertAck & ~insertFinal, fsm_t.lookup) ).stateReg cleanAck(insertAck & state._eq(fsm_t.cleaning)) lookupResRead(state._eq(fsm_t.lookupResWaitRd)) lookupResNext = rename_signal( self, (state._eq(fsm_t.idle) & self.lookupRes.rd) | (state._eq(fsm_t.lookupResAck) & (state.next != fsm_t.lookupResAck)), "lookupResNext") # synchronize all lookupRes from all tables StreamNode(masters=[t.lookupRes for t in self.tables]).sync(lookupResNext) self.stash_load( state._eq(fsm_t.idle), lookupResNext, insertTargetOH, stash, lookup_not_in_progress, lookup_in_progress != self.MAX_LOOKUP_OVERLAP - 1) insertIndex = self.insert_addr_select(insertTargetOH, state, cleanAddr) self.insertRes_driver(state, stash, insertAck, insertFinal, isDelete) self.tables_insert_driver(state, insertTargetOH, insertIndex, stash) self.lookupRes_driver(state, lookupFoundOH) lookup_en =rename_signal( self, (state._eq(fsm_t.lookup) & ((stash.reinsert_cntr != 0) | isDelete)) | (state._eq(fsm_t.idle) & stash.origin_op._eq(ORIGIN_TYPE.LOOKUP)), "lookup_en" ) self.tables_lookup_driver(state, stash.key, lookup_en)
def _impl(self): propagateClkRstn(self) self.axi_ep.bus(self.cntrl) ep = self.axi_ep.decoded id_reg_val = int.from_bytes("test".encode(), byteorder="little") ep.id_reg.din(id_reg_val) def connected_reg(name, input_=None, inputEn=None, fit=False): if input_ is not None: assert inputEn is not None port = getattr(ep, name) reg = self._reg(name, port.din._dtype) e = If(port.dout.vld, connect(port.dout.data, reg, fit=fit)) if input_ is not None: e.Elif(inputEn, connect(input_, reg, fit=fit)) port.din(reg) return reg cmdIn = ep.cmd_and_status.dout cmd = self._reg("reg_cmd", cmdIn.data._dtype, defVal=0) cmdVld = self._reg("reg_cmd_vld", defVal=0) If(cmdIn.vld, connect(cmdIn.data, cmd, fit=True)) partDone = self._sig("partDone") If(partDone, cmdVld(0)).Elif(cmdIn.vld, cmdVld(1)) def cmd_en(cmd_code): return cmdVld & cmd._eq(cmd_code) state_t = HEnum( "state_t", ["ready", "wait_ar", "wait_aw", "wait_w", "wait_b", "wait_r"]) axi = self.m_axi st = FsmBuilder(self, state_t)\ .Trans(state_t.ready, (cmd_en(SEND_AW), state_t.wait_aw), (cmd_en(SEND_AR), state_t.wait_ar), (cmd_en(SEND_W), state_t.wait_w), (cmd_en(RECV_R), state_t.wait_r), (cmd_en(RECV_B), state_t.wait_b), ).Trans(state_t.wait_aw, (axi.aw.ready, state_t.ready) ).Trans(state_t.wait_ar, (axi.ar.ready, state_t.ready) ).Trans(state_t.wait_w, (axi.w.ready, state_t.ready) ).Trans(state_t.wait_r, (axi.r.valid, state_t.ready) ).Trans(state_t.wait_b, (axi.b.valid, state_t.ready) ).stateReg partDone((st._eq(state_t.wait_aw) & axi.aw.ready) | (st._eq(state_t.wait_ar) & axi.ar.ready) | (st._eq(state_t.wait_w) & axi.w.ready) | (st._eq(state_t.wait_r) & axi.r.valid) | (st._eq(state_t.wait_b) & axi.b.valid)) ready = st._eq(state_t.ready) tmp = self._sig("tmp") tmp(ready & ~ep.cmd_and_status.dout.vld) connect(tmp, ep.cmd_and_status.din, fit=True) a_w_id = connected_reg("ar_aw_w_id") addr = connected_reg("addr") burst = connected_reg("burst") cache = connected_reg("cache") len_ = connected_reg("len") lock = connected_reg("lock") prot = connected_reg("prot") size = connected_reg("size") qos = connected_reg("qos") # aw/ar for p in [axi.aw, axi.ar]: p.id(a_w_id) p.addr(addr) p.burst(burst) p.cache(cache) p.len(len_) p.lock(lock) p.prot(prot) p.size(size) if hasattr(p, "qos"): p.qos(qos) aw_vld = st._eq(state_t.wait_aw) axi.aw.valid(aw_vld) ar_vld = st._eq(state_t.wait_ar)._reinterpret_cast(BIT) axi.ar.valid(ar_vld) r = axi.r r_rd = st._eq(state_t.wait_r) r_en = r.valid & r_rd connected_reg("r_id", r.id, r_en) connected_reg("r_data", r.data, r_en, fit=True) connected_reg("r_resp", r.resp, r_en) connected_reg("r_last", r.last, r_en) r.ready(r_rd) w = axi.w w_data = connected_reg("w_data", fit=True) w_last = connected_reg("w_last") w_strb = connected_reg("w_strb") if hasattr(w, "id"): w.id(a_w_id) connect(w_data, w.data, fit=True) w.strb(w_strb) w.last(w_last) w_vld = st._eq(state_t.wait_w) w.valid(w_vld) b = axi.b b_rd = st._eq(state_t.wait_b) connected_reg("b_id", b.id, b.valid & b_rd) connected_reg("b_resp") b.ready(b_rd) ep.hs.din( Concat(ar_vld, axi.ar.ready, aw_vld, axi.aw.ready, r.valid, r_rd, b.valid, b_rd, w_vld, w.ready))
def _impl(self): propagateClkRstn(self) self.axi_ep.bus(self.cntrl) ep = self.axi_ep.decoded id_reg_val = int.from_bytes("test".encode(), byteorder="little") ep.id_reg.din(id_reg_val) def connected_reg(name, input_=None, inputEn=None, fit=False): if input_ is not None: assert inputEn is not None port = getattr(ep, name) reg = self._reg(name, port.din._dtype) e = If(port.dout.vld, connect(port.dout.data, reg, fit=fit) ) if input_ is not None: e.Elif(inputEn, connect(input_, reg, fit=fit) ) port.din(reg) return reg cmdIn = ep.cmd_and_status.dout cmd = self._reg("reg_cmd", cmdIn.data._dtype, defVal=0) cmdVld = self._reg("reg_cmd_vld", defVal=0) If(cmdIn.vld, connect(cmdIn.data, cmd, fit=True) ) partDone = self._sig("partDone") If(partDone, cmdVld(0) ).Elif(cmdIn.vld, cmdVld(1) ) def cmd_en(cmd_code): return cmdVld & cmd._eq(cmd_code) state_t = HEnum("state_t", ["ready", "wait_ar", "wait_aw", "wait_w", "wait_b", "wait_r"]) axi = self.m_axi st = FsmBuilder(self, state_t)\ .Trans(state_t.ready, (cmd_en(SEND_AW), state_t.wait_aw), (cmd_en(SEND_AR), state_t.wait_ar), (cmd_en(SEND_W), state_t.wait_w), (cmd_en(RECV_R), state_t.wait_r), (cmd_en(RECV_B), state_t.wait_b), ).Trans(state_t.wait_aw, (axi.aw.ready, state_t.ready) ).Trans(state_t.wait_ar, (axi.ar.ready, state_t.ready) ).Trans(state_t.wait_w, (axi.w.ready, state_t.ready) ).Trans(state_t.wait_r, (axi.r.valid, state_t.ready) ).Trans(state_t.wait_b, (axi.b.valid, state_t.ready) ).stateReg partDone((st._eq(state_t.wait_aw) & axi.aw.ready) | (st._eq(state_t.wait_ar) & axi.ar.ready) | (st._eq(state_t.wait_w) & axi.w.ready) | (st._eq(state_t.wait_r) & axi.r.valid) | (st._eq(state_t.wait_b) & axi.b.valid)) ready = st._eq(state_t.ready) tmp = self._sig("tmp") tmp(ready & ~ep.cmd_and_status.dout.vld) connect(tmp, ep.cmd_and_status.din, fit=True) a_w_id = connected_reg("ar_aw_w_id") addr = connected_reg("addr") burst = connected_reg("burst") cache = connected_reg("cache") len_ = connected_reg("len") lock = connected_reg("lock") prot = connected_reg("prot") size = connected_reg("size") qos = connected_reg("qos") # aw/ar for p in [axi.aw, axi.ar]: p.id(a_w_id) p.addr(addr) p.burst(burst) p.cache(cache) p.len(len_) p.lock(lock) p.prot(prot) p.size(size) if hasattr(p, "qos"): p.qos(qos) aw_vld = st._eq(state_t.wait_aw) axi.aw.valid(aw_vld) ar_vld = st._eq(state_t.wait_ar)._reinterpret_cast(BIT) axi.ar.valid(ar_vld) r = axi.r r_rd = st._eq(state_t.wait_r) r_en = r.valid & r_rd connected_reg("r_id", r.id, r_en) connected_reg("r_data", r.data, r_en, fit=True) connected_reg("r_resp", r.resp, r_en) connected_reg("r_last", r.last, r_en) r.ready(r_rd) w = axi.w w_data = connected_reg("w_data", fit=True) w_last = connected_reg("w_last") w_strb = connected_reg("w_strb") if hasattr(w, "id"): w.id(a_w_id) connect(w_data, w.data, fit=True) w.strb(w_strb) w.last(w_last) w_vld = st._eq(state_t.wait_w) w.valid(w_vld) b = axi.b b_rd = st._eq(state_t.wait_b) connected_reg("b_id", b.id, b.valid & b_rd) connected_reg("b_resp") b.ready(b_rd) ep.hs.din(Concat(ar_vld, axi.ar.ready, aw_vld, axi.aw.ready, r.valid, r_rd, b.valid, b_rd, w_vld, w.ready))
def writePart(self): DW = int(self.DATA_WIDTH) sig = self._sig reg = self._reg addrWidth = int(self.ADDR_WIDTH) ADDR_STEP = self._getAddrStep() wSt_t = HEnum('wSt_t', ['wrIdle', 'wrData', 'wrResp']) aw = self.bus.aw w = self.bus.w b = self.bus.b # write fsm wSt = FsmBuilder(self, wSt_t, "wSt")\ .Trans(wSt_t.wrIdle, (aw.valid, wSt_t.wrData) ).Trans(wSt_t.wrData, (w.valid, wSt_t.wrResp) ).Trans(wSt_t.wrResp, (b.ready, wSt_t.wrIdle) ).stateReg awAddr = reg('awAddr', aw.addr._dtype) w_hs = sig('w_hs') awRd = wSt._eq(wSt_t.wrIdle) aw.ready(awRd) aw_hs = awRd & aw.valid wRd = wSt._eq(wSt_t.wrData) w.ready(wRd) w_hs(w.valid & wRd) # save aw addr If(aw_hs, awAddr(aw.addr)).Else(awAddr(awAddr)) # output vld for t in self._directlyMapped: out = self.getPort(t).dout try: width = t.getItemWidth() except TypeError: width = t.bitAddrEnd - t.bitAddr if width > DW: raise NotImplementedError( "Fields wider than DATA_WIDTH not supported yet", t) offset = t.bitAddr % DW out.data(w.data[(offset + width):offset]) out.vld(w_hs & ( awAddr._eq(vec(t.bitAddr // DW * (DW // ADDR_STEP), addrWidth)))) for t in self._bramPortMapped: din = self.getPort(t).din connect(w.data, din, fit=True) self.writeRespPart(awAddr, wSt._eq(wSt_t.wrResp)) return awAddr, w_hs
def _impl(self): # timers and other registers CLK_HALF_PERIOD_DIV = ceil(self.clk.FREQ / (self.MDIO_FREQ * 2)) mdio_clk = self._reg("mdio_clk", def_val=0) r_data_vld = self._reg("r_data_vld", def_val=0) req = self.req clk_half_period_en = ClkBuilder(self, self.clk).timer( ("clk_half_period_en", CLK_HALF_PERIOD_DIV)) If( clk_half_period_en, mdio_clk(~mdio_clk), ) mdio_clk_rising = clk_half_period_en & ~mdio_clk mdio_clk_falling = clk_half_period_en & mdio_clk idle = self._sig("idle") preamble_last, addr_block_last, turnarround_last_en, data_last =\ self._packet_sequence_timer( mdio_clk_rising, mdio_clk_falling, ~idle) is_rx = self._reg("is_rx", def_val=0) # protocol FSM st_t = HEnum("st_t", ["idle", "pre", "addr_block", "ta", "data"]) st = FsmBuilder(self, st_t)\ .Trans(st_t.idle, (req.vld & ~r_data_vld, st_t.pre))\ .Trans(st_t.pre, (preamble_last, st_t.addr_block))\ .Trans(st_t.addr_block, (addr_block_last, st_t.ta))\ .Trans(st_t.ta, (turnarround_last_en & ( (is_rx & mdio_clk_falling) | (~is_rx & mdio_clk_rising)), st_t.data))\ .Trans(st_t.data, (data_last, st_t.idle)).stateReg idle(st._eq(st_t.idle)) req.rd(idle & ~r_data_vld) If(idle, is_rx(req.opcode._eq(Mdio.OP.READ))) # TX logic md = self.md TX_W = md.ST_W + md.OP_W + md.PA_W + md.RA_W + md.TA_W + md.D_W tx_reg = self._reg("tx_reg", Bits(TX_W)) If( idle & req.vld, tx_reg( Concat( Mdio.ST, req.opcode, req.addr.phy, req.addr.reg, Mdio.TA, req.wdata))).Elif( mdio_clk_falling & In(st, [st_t.addr_block, st_t.data, st_t.ta, st_t.data]), tx_reg(tx_reg << 1)) md.c(mdio_clk) # because MDIO uses open-drain, this means that if t=0 the value of the signal is 1 md.io.o(0) tx_bit = tx_reg[tx_reg._dtype.bit_length() - 1] md.io.t(~idle & ~tx_bit & (st._eq(st_t.addr_block) | (In(st, [st_t.data, st_t.ta]) & ~is_rx))) # RX logic rx_reg = self._reg("rx_reg", Bits(md.D_W)) If( st._eq(st_t.data) & is_rx & mdio_clk_rising, shift_in_msb_first(rx_reg, self.md.io.i)) If(idle & self.rdata.rd, r_data_vld(0)).Elif(addr_block_last, r_data_vld(is_rx)) self.rdata.vld(idle & r_data_vld) self.rdata.data(rx_reg)
def itemUploadLogic(self, baseIndex, nextBaseIndex, nextBaseReady, nextBlockTransition_out): r, s = self._reg, self._sig f = self.dataFifo w = self.wDatapump BURST_LEN = self.BUFFER_CAPACITY // 2 bufferHasData = s("bufferHasData") bufferHasData(f.size > (BURST_LEN - 1)) # we are counting base next addr as item as well addr_index_t = Bits(self.ADDR_WIDTH - self.ALIGN_BITS) baseIndex = r("baseIndex", addr_index_t) dataCntr_t = Bits(log2ceil(BURST_LEN + 1), signed=False) dataCntr = r("dataCntr", dataCntr_t, defVal=0) # counter of uploading data reqLen_backup = r("reqLen_backup", w.req.len._dtype, defVal=0) gotWriteAck = w.ack.vld & w.ack.data._eq(self.ID) queueHasSpace, lenByPtrs = self.queuePtrLogic(fitTo(reqLen_backup, self.wrPtr.din) + 1, gotWriteAck) timeout = s("timeout") fsm_t = HEnum("itemUploadingFsm_t", ["idle", "reqPending", "dataPending_prepare", "dataPending_send", "waitForAck"]) fsm = FsmBuilder(self, fsm_t, "itemUploadLogic_fsm")\ .Trans(fsm_t.idle, (timeout | (bufferHasData & queueHasSpace), fsm_t.reqPending) ).Trans(fsm_t.reqPending, (w.req.rd, fsm_t.dataPending_prepare) ).Trans(fsm_t.dataPending_prepare, fsm_t.dataPending_send ).Trans(fsm_t.dataPending_send, ((~nextBlockTransition_out | nextBaseReady) & dataCntr._eq(0), fsm_t.waitForAck) ).Trans(fsm_t.waitForAck, (gotWriteAck, fsm_t.idle) ).stateReg timeout(self.timeoutHandler(fsm != fsm_t.idle, (f.size != 0) & queueHasSpace)) inBlock_t = Bits(log2ceil(self.ITEMS_IN_BLOCK + 1)) inBlockRemain = r("inBlockRemain_reg", inBlock_t, defVal=self.ITEMS_IN_BLOCK) wReqEn = fsm._eq(fsm_t.reqPending) reqLen = self.wReqDriver(wReqEn, baseIndex, lenByPtrs, inBlockRemain) If(wReqEn & w.req.rd, reqLen_backup(reqLen) ) dataMoveEn = fsm._eq(fsm_t.dataPending_send) prepareEn = fsm._eq(fsm_t.dataPending_prepare) self.mvDataToW(prepareEn, dataMoveEn, reqLen_backup, inBlockRemain, nextBlockTransition_out, dataCntr) If(self.baseAddr.dout.vld, baseIndex(self.addrToIndex(self.baseAddr.dout.data)), ).Elif(prepareEn, baseIndex(baseIndex + fitTo(reqLen_backup, baseIndex) + 1) ).Elif(nextBlockTransition_out, baseIndex(nextBaseIndex) ) w.ack.rd(fsm._eq(fsm_t.waitForAck))
def itemUploadLogic(self, baseIndex, nextBaseIndex, nextBaseReady, nextBlockTransition_out): r, s = self._reg, self._sig f = self.dataFifo w = self.wDatapump BURST_LEN = self.BUFFER_CAPACITY // 2 bufferHasData = s("bufferHasData") bufferHasData(f.size > (BURST_LEN - 1)) # we are counting base next addr as item as well addr_index_t = Bits(self.ADDR_WIDTH - self.ALIGN_BITS) baseIndex = r("baseIndex", addr_index_t) dataCntr_t = Bits(log2ceil(BURST_LEN + 1), signed=False) # counter of uploading data dataCntr = r("dataCntr", dataCntr_t, def_val=0) reqLen_backup = r("reqLen_backup", w.req.len._dtype, def_val=0) gotWriteAck = w.ack.vld & w.ack.data._eq(self.ID) queueHasSpace, lenByPtrs = self.queuePtrLogic( fitTo(reqLen_backup, self.wrPtr.din) + 1, gotWriteAck) timeout = s("timeout") fsm_t = HEnum("itemUploadingFsm_t", [ "idle", "reqPending", "dataPending_prepare", "dataPending_send", "waitForAck" ]) fsm = FsmBuilder(self, fsm_t, "itemUploadLogic_fsm")\ .Trans(fsm_t.idle, (timeout | (bufferHasData & queueHasSpace), fsm_t.reqPending) ).Trans(fsm_t.reqPending, (w.req.rd, fsm_t.dataPending_prepare) ).Trans(fsm_t.dataPending_prepare, fsm_t.dataPending_send ).Trans(fsm_t.dataPending_send, ((~nextBlockTransition_out | nextBaseReady) & dataCntr._eq(0), fsm_t.waitForAck) ).Trans(fsm_t.waitForAck, (gotWriteAck, fsm_t.idle) ).stateReg timeout( self.timeoutHandler(fsm != fsm_t.idle, (f.size != 0) & queueHasSpace)) inBlock_t = Bits(log2ceil(self.ITEMS_IN_BLOCK + 1)) inBlockRemain = r("inBlockRemain_reg", inBlock_t, def_val=self.ITEMS_IN_BLOCK) wReqEn = fsm._eq(fsm_t.reqPending) reqLen = self.wReqDriver(wReqEn, baseIndex, lenByPtrs, inBlockRemain) If(wReqEn & w.req.rd, reqLen_backup(reqLen)) dataMoveEn = fsm._eq(fsm_t.dataPending_send) prepareEn = fsm._eq(fsm_t.dataPending_prepare) self.mvDataToW(prepareEn, dataMoveEn, reqLen_backup, inBlockRemain, nextBlockTransition_out, dataCntr) If( self.baseAddr.dout.vld, baseIndex(self.addrToIndex(self.baseAddr.dout.data)), ).Elif(prepareEn, baseIndex(baseIndex + fitTo(reqLen_backup, baseIndex) + 1)).Elif(nextBlockTransition_out, baseIndex(nextBaseIndex)) w.ack.rd(fsm._eq(fsm_t.waitForAck))
def _impl(self): ALIGN_BITS = log2ceil(self.DATA_WIDTH // 8 - 1) TIMEOUT_MAX = self.TIMEOUT - 1 ITEMS = self.ITEMS buff = self.buff reqAck = self.wDatapump.ack req = self.wDatapump.req w = self.wDatapump.w propagateClkRstn(self) sizeOfitems = self._reg("sizeOfItems", Bits( buff.size._dtype.bit_length())) # aligned base addr baseAddr = self._reg("baseAddrReg", Bits(self.ADDR_WIDTH - ALIGN_BITS)) If(self.baseAddr.dout.vld, baseAddr(self.baseAddr.dout.data[:ALIGN_BITS]) ) self.baseAddr.din(Concat(baseAddr, Bits(ALIGN_BITS).from_py(0))) # offset in buffer and its complement offset_t = Bits(log2ceil(ITEMS + 1), signed=False) offset = self._reg("offset", offset_t, def_val=0) remaining = self._reg("remaining", Bits( log2ceil(ITEMS + 1), signed=False), def_val=ITEMS) self.buff_remain(remaining, fit=True) addrTmp = self._sig("baseAddrTmp", baseAddr._dtype) addrTmp(baseAddr + fitTo(offset, baseAddr)) # req values logic req.id(self.ID) req.addr(Concat(addrTmp, Bits(ALIGN_BITS).from_py(0))) req.rem(0) sizeTmp = self._sig("sizeTmp", buff.size._dtype) assert (req.len._dtype.bit_length() == buff.size._dtype.bit_length() - 1), ( req.len._dtype.bit_length(), buff.size._dtype.bit_length()) buffSizeAsLen = self._sig("buffSizeAsLen", buff.size._dtype) buffSizeAsLen(buff.size - 1) buffSize_tmp = self._sig("buffSize_tmp", remaining._dtype) buffSize_tmp(buff.size, fit=True) endOfLenBlock = (remaining - 1) < buffSize_tmp remainingAsLen = self._sig("remainingAsLen", remaining._dtype) remainingAsLen(remaining - 1) If(endOfLenBlock, req.len(remainingAsLen, fit=True), sizeTmp(remaining, fit=True) ).Else( req.len(buffSizeAsLen, fit=True), sizeTmp(buff.size) ) lastWordCntr = self._reg("lastWordCntr", buff.size._dtype, 0) w_last = lastWordCntr._eq(1) w_ack = w.ready & buff.dataOut.vld # timeout logic timeoutCntr = self._reg("timeoutCntr", Bits(log2ceil(self.TIMEOUT), False), def_val=TIMEOUT_MAX) # buffer is full or timeout beginReq = buff.size._eq(self.BUFF_DEPTH) | timeoutCntr._eq(0) reqAckHasCome = self._sig("reqAckHasCome") reqAckHasCome(reqAck.vld & reqAck.data._eq(self.ID)) st = FsmBuilder(self, stT)\ .Trans(stT.waitOnInput, (beginReq & req.rd, stT.waitOnDataTx) ).Trans(stT.waitOnDataTx, (w_last & w_ack, stT.waitOnAck) ).Trans(stT.waitOnAck, (reqAckHasCome, stT.waitOnInput) ).stateReg If(st._eq(stT.waitOnInput) & beginReq, # timeout is counting only when there is pending data # start new request req.vld(1), If(req.rd, If(endOfLenBlock, offset(0), remaining(ITEMS) ).Else( offset(offset + fitTo(buff.size, offset)), remaining(remaining - fitTo(buff.size, remaining)) ), sizeOfitems(sizeTmp), timeoutCntr(TIMEOUT_MAX) ) ).Else( req.vld(0), If(buff.dataOut.vld & st._eq(stT.waitOnInput) & (timeoutCntr != 0), timeoutCntr(timeoutCntr - 1) ) ) reqAck.rd(st._eq(stT.waitOnAck)) self.uploadedCntrHandler(st, reqAckHasCome, sizeOfitems) # it does not matter when lastWordCntr is changing when there is no # request startSendingData = st._eq(stT.waitOnInput) & beginReq & req.rd If(startSendingData, lastWordCntr(sizeTmp) ).Elif((lastWordCntr != 0) & w_ack, lastWordCntr(lastWordCntr - 1) ) buff.dataIn(self.items) w.data(buff.dataOut.data, fit=True) StreamNode( masters=[buff.dataOut], slaves=[w] ).sync(st._eq(stT.waitOnDataTx)) w.strb(mask(w.strb._dtype.bit_length())) w.last(w_last)
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 writePart(self): DW = int(self.DATA_WIDTH) sig = self._sig reg = self._reg addrWidth = int(self.ADDR_WIDTH) ADDR_STEP = self._getAddrStep() wSt_t = HEnum('wSt_t', ['wrIdle', 'wrData', 'wrResp']) aw = self.bus.aw w = self.bus.w b = self.bus.b # write fsm wSt = FsmBuilder(self, wSt_t, "wSt")\ .Trans(wSt_t.wrIdle, (aw.valid, wSt_t.wrData) ).Trans(wSt_t.wrData, (w.valid, wSt_t.wrResp) ).Trans(wSt_t.wrResp, (b.ready, wSt_t.wrIdle) ).stateReg awAddr = reg('awAddr', aw.addr._dtype) w_hs = sig('w_hs') awRd = wSt._eq(wSt_t.wrIdle) aw.ready(awRd) aw_hs = awRd & aw.valid wRd = wSt._eq(wSt_t.wrData) w.ready(wRd) w_hs(w.valid & wRd) # save aw addr If(aw_hs, awAddr(aw.addr) ).Else( awAddr(awAddr) ) # output vld for t in self._directlyMapped: out = self.getPort(t).dout try: width = t.getItemWidth() except TypeError: width = t.bitAddrEnd - t.bitAddr if width > DW: raise NotImplementedError("Fields wider than DATA_WIDTH not supported yet", t) offset = t.bitAddr % DW out.data(w.data[(offset + width): offset]) out.vld(w_hs & (awAddr._eq(vec(t.bitAddr // DW * (DW // ADDR_STEP), addrWidth)))) for t in self._bramPortMapped: din = self.getPort(t).din connect(w.data, din, fit=True) self.writeRespPart(awAddr, wSt._eq(wSt_t.wrResp)) return awAddr, w_hs
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 _impl(self): ALIGN_BITS = log2ceil(self.DATA_WIDTH // 8 - 1).val TIMEOUT_MAX = self.TIMEOUT - 1 ITEMS = self.ITEMS buff = self.buff reqAck = self.wDatapump.ack req = self.wDatapump.req w = self.wDatapump.w propagateClkRstn(self) sizeOfitems = self._reg("sizeOfItems", Bits( buff.size._dtype.bit_length())) # aligned base addr baseAddr = self._reg("baseAddrReg", Bits(self.ADDR_WIDTH - ALIGN_BITS)) If(self.baseAddr.dout.vld, baseAddr(self.baseAddr.dout.data[:ALIGN_BITS]) ) self.baseAddr.din(Concat(baseAddr, vec(0, ALIGN_BITS))) # offset in buffer and its complement offset_t = Bits(log2ceil(ITEMS + 1), signed=False) offset = self._reg("offset", offset_t, defVal=0) remaining = self._reg("remaining", Bits( log2ceil(ITEMS + 1), signed=False), defVal=ITEMS) connect(remaining, self.buff_remain, fit=True) addrTmp = self._sig("baseAddrTmp", baseAddr._dtype) addrTmp(baseAddr + fitTo(offset, baseAddr)) # req values logic req.id(self.ID) req.addr(Concat(addrTmp, vec(0, ALIGN_BITS))) req.rem(0) sizeTmp = self._sig("sizeTmp", buff.size._dtype) assert req.len._dtype.bit_length() == buff.size._dtype.bit_length() - 1, ( req.len._dtype.bit_length(), buff.size._dtype.bit_length()) buffSizeAsLen = self._sig("buffSizeAsLen", buff.size._dtype) buffSizeAsLen(buff.size - 1) buffSize_tmp = self._sig("buffSize_tmp", remaining._dtype) connect(buff.size, buffSize_tmp, fit=True) endOfLenBlock = (remaining - 1) < buffSize_tmp remainingAsLen = self._sig("remainingAsLen", remaining._dtype) remainingAsLen(remaining - 1) If(endOfLenBlock, connect(remainingAsLen, req.len, fit=True), connect(remaining, sizeTmp, fit=True) ).Else( connect(buffSizeAsLen, req.len, fit=True), sizeTmp(buff.size) ) lastWordCntr = self._reg("lastWordCntr", buff.size._dtype, 0) w_last = lastWordCntr._eq(1) w_ack = w.ready & buff.dataOut.vld # timeout logic timeoutCntr = self._reg("timeoutCntr", Bits(log2ceil(self.TIMEOUT), False), defVal=TIMEOUT_MAX) # buffer is full or timeout beginReq = buff.size._eq(self.BUFF_DEPTH) | timeoutCntr._eq(0) reqAckHasCome = self._sig("reqAckHasCome") reqAckHasCome(reqAck.vld & reqAck.data._eq(self.ID)) st = FsmBuilder(self, stT)\ .Trans(stT.waitOnInput, (beginReq & req.rd, stT.waitOnDataTx) ).Trans(stT.waitOnDataTx, (w_last & w_ack, stT.waitOnAck) ).Trans(stT.waitOnAck, (reqAckHasCome, stT.waitOnInput) ).stateReg If(st._eq(stT.waitOnInput) & beginReq, # timeout is counting only when there is pending data # start new request req.vld(1), If(req.rd, If(endOfLenBlock, offset(0), remaining(ITEMS) ).Else( offset(offset + fitTo(buff.size, offset)), remaining(remaining - fitTo(buff.size, remaining)) ), sizeOfitems(sizeTmp), timeoutCntr(TIMEOUT_MAX) ) ).Else( req.vld(0), If(buff.dataOut.vld & st._eq(stT.waitOnInput) & (timeoutCntr != 0), timeoutCntr(timeoutCntr - 1) ) ) reqAck.rd(st._eq(stT.waitOnAck)) self.uploadedCntrHandler(st, reqAckHasCome, sizeOfitems) # it does not matter when lastWordCntr is changing when there is no # request startSendingData = st._eq(stT.waitOnInput) & beginReq & req.rd If(startSendingData, lastWordCntr(sizeTmp) ).Elif((lastWordCntr != 0) & w_ack, lastWordCntr(lastWordCntr - 1) ) buff.dataIn(self.items) connect(buff.dataOut.data, w.data, fit=True) StreamNode(masters=[buff.dataOut], slaves=[w] ).sync(st._eq(stT.waitOnDataTx)) w.strb(mask(w.strb._dtype.bit_length())) w.last(w_last)