Search code examples
pythoncocotb

yielding a coroutine in a list with cocotb


I have a coroutine which wait for an event to be set :

@cocotb.coroutine
def wb_RXDR_read(self):
    """ waiting util RXDR is read """
    if not self._RXDR_read_flag:
        while True:
            yield self._RXDR_read_event.wait()
            break

I want to «yield» on it with a timeout. Then to do that I did this :

        RXDR_timeout = Timer(250, units="us")
        ret = yield [RXDR_timeout, self.wb_RXDR_read()]
        if ret == RXDR_timeout:
            self._dut._log.error("Timeout on waiting RXDR to be read")
            raise TestError()

But I get this error :

2ns ERROR    Coroutine i2c_write yielded something the scheduler can't handle
                      Got type: <type 'list'> repr: [<cocotb.triggers.Timer object at 0x7f2098cb1350>, <cocotb.decorators.RunningCoroutine object at 0x7f2098cb1610>] str: [<cocotb.triggers.Timer object at 0x7f2098cb1350>, <cocotb.decorators.RunningCoroutine object at 0x7f2098cb1610>]
                      Did you forget to decorate with @cocotb.coroutine?

My coroutine is decorated with @cocotb.coroutine. If I yield it alone that works :

yield self.wb_RXDR_read() # <- that works

But I can't put it in a list. Is it possible to put coroutine in a list to block like unix select() ? Or is it reserved to Trigger class ?


Solution

  • Ok I found the solution. In fact Coroutine can't be triggered in select like fashion itself. It should be started as a thread first, and to detect the end of the coroutine the .join() method must be put in the yield list:

        RXDR_timeout = Timer(250, units="us")
        RXDR_readth = cocotb.fork(self.wb_RXDR_read())
        ret = yield [RXDR_timeout, RXDR_readth.join()]
        if ret == RXDR_timeout:
            self._dut._log.error("Timeout on waiting RXDR to be read")
            raise TestError()
    

    The thing to remember is :

    • We can yield one coroutine
    • To yield several coroutine we have to fork() and join()