Source code for hwtLib.amba.datapump.interconnect.wStrictOrder
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
from hwt.code import Or, Switch
from hwt.interfaces.std import Handshaked
from hwt.interfaces.utils import addClkRstn, propagateClkRstn
from hwt.math import log2ceil
from hwt.serializer.mode import serializeParamsUniq
from hwt.synthesizer.hObjList import HObjList
from hwt.synthesizer.param import Param
from hwtLib.amba.axi_comp.interconnect.base import AxiInterconnectBase
from hwtLib.amba.datapump.intf import AxiWDatapumpIntf
from hwtLib.handshaked.fifo import HandshakedFifo
[docs]@serializeParamsUniq
class WStrictOrderInterconnect(AxiInterconnectBase):
"""
Strict order interconnect for AxiWDatapumpIntf (N-to-1)
ensures that response on request is delivered to driver which asked for it
while transactions can overlap
.. hwt-autodoc::
"""
def _config(self):
self.DRIVER_CNT = Param(2)
self.MAX_TRANS_OVERLAP = Param(16)
AxiWDatapumpIntf._config(self)
[docs] def getDpIntf(self, unit):
return unit.wDatapump
def _declr(self):
addClkRstn(self)
with self._paramsShared():
self.drivers = HObjList(
AxiWDatapumpIntf()
for _ in range(int(self.DRIVER_CNT)))
self.wDatapump = AxiWDatapumpIntf()._m()
self.DRIVER_INDEX_WIDTH = log2ceil(self.DRIVER_CNT)
fW = self.orderInfoFifoW = HandshakedFifo(Handshaked)
fAck = self.orderInfoFifoAck = HandshakedFifo(Handshaked)
for f in [fW, fAck]:
f.DEPTH = self.MAX_TRANS_OVERLAP
f.DATA_WIDTH = self.DRIVER_INDEX_WIDTH
[docs] def wHandler(self):
w = self.wDatapump.w
fWOut = self.orderInfoFifoW.dataOut
fAckIn = self.orderInfoFifoAck.dataIn
driversW = [d.w for d in self.drivers]
selectedDriverVld = self._sig("selectedDriverWVld")
selectedDriverVld(Or(*map(lambda d: fWOut.data._eq(d[0]) & d[1].valid,
enumerate(driversW))
))
selectedDriverLast = self._sig("selectedDriverLast")
selectedDriverLast(Or(*map(lambda d: fWOut.data._eq(d[0]) & d[1].last,
enumerate(driversW))
))
Switch(fWOut.data).add_cases(
[(i, w(d, exclude=[d.valid, d.ready]))
for i, d in enumerate(driversW)]
).Default(
w.data(None),
w.strb(None),
w.last(None)
)
fAckIn.data(fWOut.data)
# handshake logic
fWOut.rd(selectedDriverVld & selectedDriverLast & w.ready & fAckIn.rd)
for i, d in enumerate(driversW):
d.ready(fWOut.data._eq(i) & w.ready & fWOut.vld & fAckIn.rd)
w.valid(selectedDriverVld & fWOut.vld & fAckIn.rd)
fAckIn.vld(selectedDriverVld & selectedDriverLast & w.ready & fWOut.vld)
#extraConds = {
# fAckIn: selectedDriverLast
# }
#for i, d in enumerate(driversW):
# extraConds[d] = fWOut.data._eq(i)
#
#StreamNode(masters=[w, fWOut],
# slaves=driversW+[fAckIn],
# extraConds=extraConds).sync()
[docs] def ackHandler(self):
ack = self.wDatapump.ack
fAckOut = self.orderInfoFifoAck.dataOut
driversAck = [d.ack for d in self.drivers]
selectedDriverAckReady = self._sig("selectedDriverAckReady")
selectedDriverAckReady(Or(*map(lambda d: fAckOut.data._eq(d[0]) & d[1].rd,
enumerate(driversAck))
))
ack.rd(fAckOut.vld & selectedDriverAckReady)
fAckOut.rd(ack.vld & selectedDriverAckReady)
for i, d in enumerate(driversAck):
d(ack, exclude=[d.vld, d.rd])
d.vld(ack.vld & fAckOut.vld & fAckOut.data._eq(i))
def _impl(self):
assert int(self.DRIVER_CNT) > 1, "It makes no sense to use interconnect in this case"
propagateClkRstn(self)
self.reqHandler(self.wDatapump.req, self.orderInfoFifoW.dataIn)
self.wHandler()
self.ackHandler()
if __name__ == "__main__":
from hwt.synthesizer.utils import to_rtl_str
u = WStrictOrderInterconnect()
print(to_rtl_str(u))