Skip to content

Commit

Permalink
Merge pull request #30 from Kev-J/fix-monitor
Browse files Browse the repository at this point in the history
Enqueue wishbone request even if cyc_o is negated after stb_o
  • Loading branch information
Martoni authored Dec 12, 2024
2 parents 9cb49d6 + a8a3c8a commit 04d3acf
Showing 1 changed file with 44 additions and 40 deletions.
84 changes: 44 additions & 40 deletions cocotbext/wishbone/monitor.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
from cocotb_bus.monitors import BusMonitor
from cocotb.triggers import RisingEdge
from cocotb.result import TestFailure
from cocotb.decorators import public
from cocotb.decorators import public
try:
from Queue import Queue # Python 2.x
except ImportError:
Expand All @@ -16,7 +16,7 @@ class WBAux():
"""
def __init__(self, sel=0xf, adr=0, datwr=None, waitStall=0, waitIdle=0, tsStb=0):
self.adr = adr
self.datwr = datwr
self.datwr = datwr
self.sel = sel
self.waitStall = waitStall
self.ts = tsStb
Expand Down Expand Up @@ -52,10 +52,10 @@ def to_dict(self):
class Wishbone(BusMonitor):
"""Wishbone
"""

_signals = ["cyc", "stb", "we", "adr", "datwr", "datrd", "ack"]
_optional_signals = ["sel", "err", "stall", "rty"]
replyTypes = {1 : "ack", 2 : "err", 3 : "rty"}
replyTypes = {1 : "ack", 2 : "err", 3 : "rty"}

def __init__(self, entity, name, clock, signals_dict=None, **kwargs):
if signals_dict is not None:
Expand All @@ -65,22 +65,22 @@ def __init__(self, entity, name, clock, signals_dict=None, **kwargs):
# Drive some sensible defaults (setimmediatevalue to avoid x asserts)
self.bus.ack.setimmediatevalue(0)
self.bus.datrd.setimmediatevalue(0)
if hasattr(self.bus, "err"):
if hasattr(self.bus, "err"):
self.bus.err.setimmediatevalue(0)
if hasattr(self.bus, "stall"):
if hasattr(self.bus, "stall"):
self.bus.stall.setimmediatevalue(0)
if hasattr(self.bus, "rty"):
self.bus.rty.setimmediatevalue(0)
if hasattr(self.bus, "rty"):
self.bus.rty.setimmediatevalue(0)


class WishboneSlave(Wishbone):
"""Wishbone slave
"""

def bitSeqGen(self, tupleGen):
while True:
while True:
[highCnt, lowCnt] = next(tupleGen)
#make sure there's at least one low cycle in here
#make sure there's at least one low cycle in here
if lowCnt < 1:
lowCnt = 1
bits = []
Expand All @@ -90,7 +90,7 @@ def bitSeqGen(self, tupleGen):
bits.append(0)
for bit in bits:
yield bit

def __init__(self, entity, name, clock, **kwargs):
datGen = kwargs.pop('datgen', None)
ackGen = kwargs.pop('ackgen', None)
Expand Down Expand Up @@ -121,9 +121,9 @@ def __init__(self, entity, name, clock, **kwargs):
self._waitStallGen = self.bitSeqGen(waitStallGen)

Wishbone.__init__(self, entity, name, clock, **kwargs)
cocotb.fork(self._stall())
cocotb.fork(self._clk_cycle_counter())
cocotb.fork(self._ack())
cocotb.start_soon(self._stall())
cocotb.start_soon(self._clk_cycle_counter())
cocotb.start_soon(self._ack())

async def _clk_cycle_counter(self):
"""
Expand All @@ -144,8 +144,8 @@ async def _stall(self):
if hasattr(self.bus, "stall"):
tmpStall = next(self._waitStallGen)
self.bus.stall.value = tmpStall
if bool(tmpStall):
self._stallCount += 1
if bool(tmpStall):
self._stallCount += 1
await clkedge
else:
await clkedge
Expand All @@ -154,7 +154,7 @@ async def _stall(self):
break

async def _ack(self):
clkedge = RisingEdge(self.clock)
clkedge = RisingEdge(self.clock)
while True:
#set defaults
self.bus.ack.value = 0
Expand All @@ -163,20 +163,20 @@ async def _ack(self):
self.bus.err.value = 0
if hasattr(self.bus, "rty"):
self.bus.rty.value = 0

if not self._reply_Q.empty():
#get next reply from queue
#get next reply from queue
rep = self._reply_Q.get_nowait()

#wait <waitAck> clock cycles before replying
if rep.waitAck is not None:
waitcnt = rep.waitAck
while waitcnt > 0:
waitcnt -= 1
await clkedge

#check if the signal we want to assign exists and assign
if not hasattr(self.bus, self.replyTypes[rep.ack]):
if not hasattr(self.bus, self.replyTypes[rep.ack]):
raise TestFailure("Tried to assign <%s> (%u) to slave reply, but this slave does not have a <%s> line" % (self.replyTypes[rep.ack], rep.ack, self.replyTypes[rep.ack]))
if self.replyTypes[rep.ack] == "ack":
self.bus.ack.value = 1
Expand All @@ -189,35 +189,35 @@ async def _ack(self):

def _respond(self):
valid = self.bus.cyc.value and self.bus.stb.value
#if there is a stall signal, take it into account
#if there is a stall signal, take it into account
if hasattr(self.bus, "stall"):
valid = valid and not self.bus.stall.value

if valid:
#wait before replying ?
#wait before replying ?
waitAck = next(self._waitAckGen)
#Response: rddata/don't care
#Response: rddata/don't care
if not self.bus.we.value:
rd = next(self._datGen)
else:
rd = 0

#Response: ack/err/rty
reply = next(self._ackGen)
if reply not in self.replyTypes:
raise TestFailure("Tried to assign unknown reply type (%u) to slave reply. Valid is 1-3 (ack, err, rty)" % reply)

wr = None
if self.bus.we.value:
wr = self.bus.datwr.value

#get the time the master idled since the last operation
#TODO: subtract our own stalltime or, if we're not pipelined, time since last ack
idleTime = self._clk_cycle_count - self._lastTime -1
#TODO: subtract our own stalltime or, if we're not pipelined, time since last ack
idleTime = self._clk_cycle_count - self._lastTime -1
_sel = self.bus.sel.value if hasattr(self.bus, "sel") else None
res = WBRes(ack=reply, sel=_sel, adr=self.bus.adr.value, datrd=rd, datwr=wr,
waitIdle=idleTime, waitStall=self._stallCount, waitAck=waitAck)

#add whats going to happen to the result buffer
self._res_buf.append(res)
#add it to the reply queue for assignment. we need to process
Expand All @@ -229,15 +229,19 @@ async def _monitor_recv(self):
clkedge = RisingEdge(self.clock)
#respond and notify the callback function
while True:
try:
if self._cycle == 1 and self.bus.cyc.value == 0:
self._recv(self._res_buf)
self._reply_Q.queue.clear()
self._res_buf = []
except ValueError:
pass

while self.bus.stb.value.binstr != '1':
# Permission 3.05: MASTER interfaces MAY assert [CYC_O] indefinitely.
# i.e after [STB_O] was negated.
try:
if self._cycle == 1 and self.bus.cyc.value == 0:
self._recv(self._res_buf)
self._reply_Q.queue.clear()
self._res_buf = []
self._cycle = 0
except ValueError:
pass

await clkedge
try:
if self._cycle == 0 and self.bus.cyc.value == 1:
Expand Down

0 comments on commit 04d3acf

Please sign in to comment.