def _coroutine_yielded(self, coro, trigger): """Prime the trigger and update our internal mappings.""" self._coro2trigger[coro] = trigger trigger_coros = self._trigger2coros.setdefault(trigger, []) if coro is self._write_coro_inst: # Our internal write coroutine always runs before any user coroutines. # This preserves the behavior prior to the refactoring of writes to # this coroutine. trigger_coros.insert(0, coro) else: # Everything else joins the back of the queue trigger_coros.append(coro) if not trigger.primed: if trigger_coros != [coro]: # should never happen raise InternalError( "More than one coroutine waiting on an unprimed trigger") try: trigger.prime(self.react) except Exception as e: # discard the trigger we associated, it will never fire self._trigger2coros.pop(trigger) # replace it with a new trigger that throws back the exception error_trigger = NullTrigger(outcome=outcomes.Error(e)) self._coro2trigger[coro] = error_trigger self._trigger2coros[error_trigger] = [coro] # wake up the coroutines error_trigger.prime(self.react)
def _write_default(self): ''' Writes out the specified default transaction. If no default transaction was specified with the constructor, simply set the unknown signals to zero. ''' # Generate a transaction with all the data signals. Set the # default values. default_dict = {} if self.__default_trans is not None: default_dict = vars(self.__default_trans) trans = self._interface.transaction(**default_dict) # If there are any data signals not assigned, assume their default # value should be zerp. for name, value in vars(trans).items(): if value is None: setattr(trans, name, 0) # Write the transaction to the interface. self._interface.write(trans) # Yielding on a null trigger is necessary since # every coroutine-decorate method needs to yield # on a trigger. yield NullTrigger()
def _read(self): ''' Samples from the interface and writes it out on to the outport. ''' self.outport.write(self._interface.read(), execute_behavior=True) yield NullTrigger()
def _write_default(self): ''' Writes out the default state of the handshake interface. Do not write over the data signals since we're reading from them. ''' self._interface.rdy.value = 0 yield NullTrigger()
def _write(self, data): ''' Writes out the queued data transasction to the interface. ''' self._interface.write(data) yield NullTrigger()
def _resume_coro_upon(self, coro, trigger): """Schedule `coro` to be resumed when `trigger` fires.""" coro._trigger = trigger trigger_coros = self._trigger2coros.setdefault(trigger, []) if coro is self._write_coro_inst: # Our internal write coroutine always runs before any user coroutines. # This preserves the behavior prior to the refactoring of writes to # this coroutine. trigger_coros.insert(0, coro) else: # Everything else joins the back of the queue trigger_coros.append(coro) if not trigger.primed: if trigger_coros != [coro]: # should never happen raise InternalError( "More than one coroutine waiting on an unprimed trigger") try: trigger.prime(self.react) except Exception as e: # discard the trigger we associated, it will never fire self._trigger2coros.pop(trigger) # replace it with a new trigger that throws back the exception self._resume_coro_upon( coro, NullTrigger(name="Trigger.prime() Error", outcome=outcomes.Error(e)))
def flush(self): ''' Do not used this method with read port. ''' raise NotImplementedError( "flush should not be used with the read driver.") yield NullTrigger()
def wait(self): ''' Yield on this method as a way to wait until all resets finish their operation. ''' if not self.__event.fired: yield self.__event.wait() yield NullTrigger()
def flush(self): ''' Blocks until the driver's queue is empty. ''' if self._ready() == True: self.__flushevt.clear() yield self.__flushevt.wait() yield NullTrigger()
def _wait_reset(self, active_mode=1): ''' Wait until reset is in an inactive state. ''' rst = self.rst if str(rst.value) == 'z' or str(rst.value) == 'x' or int( rst.value) == active_mode: yield Edge(rst) yield NullTrigger()
def add_test(self, test_coro): """Called by the regression manager to queue the next test""" if self._test is not None: raise InternalError("Test was added while another was in progress") self._test = test_coro self._resume_coro_upon( test_coro, NullTrigger(name="Start {!s}".format(test_coro), outcome=outcomes.Value(None)))
def _write(self): ''' Writes out the queued data transasction to the interface. ''' # Check the allow to determine if the driver is # allowed to set its ready. while next(self.allow) == False: self._interface.rdy.value = 0 yield RegisterInterface._synchronize(self._interface) # Once it's finally allowed to read, set # the ready and continue. self._interface.rdy.value = 1 yield NullTrigger()
def _drive(self): ''' Implements the behavior of the clock driver. ''' for name, handle in vars(self._interface).items(): params = getattr(self.__param_namespace, name, None) period = getattr(params, "period", None) phase = getattr(params, "phase", None) param_dict = {} if period is not None: param_dict["period"] = period if phase is not None: param_dict["phase"] = phase self.__log.info( "Starting clock {} with period {} and phase {}...".format( name, period, phase)) fork(start_clock(clock=handle, **param_dict)) yield NullTrigger()
def _write(self, data): ''' Writes out the queued data transasction to the interface. ''' # Write out the data. self._interface.write(data) # Check the allow to determine if the driver is # allowed to set its valid. while next(self.allow) == False: self._interface.vld.value = 0 yield RegisterInterface._synchronize(self._interface) # Once it's finally allowed to write data, set # the valid and continue. self._interface.vld.value = 1 yield NullTrigger()
def schedule(self, coroutine, trigger=None): """Schedule a coroutine by calling the send method. Args: coroutine (cocotb.decorators.coroutine): The coroutine to schedule. trigger (cocotb.triggers.Trigger): The trigger that caused this coroutine to be scheduled. """ with self._task_context(coroutine): if trigger is None: send_outcome = outcomes.Value(None) else: send_outcome = trigger._outcome if _debug: self.log.debug("Scheduling with {}".format(send_outcome)) coro_completed = False try: coroutine._trigger = None result = coroutine._advance(send_outcome) if _debug: self.log.debug("Coroutine %s yielded %s (mode %d)" % (coroutine._coro.__qualname__, str(result), self._mode)) except cocotb.decorators.CoroutineComplete: if _debug: self.log.debug("Coroutine {} completed with {}".format( coroutine, coroutine._outcome)) coro_completed = True # this can't go in the else above, as that causes unwanted exception # chaining if coro_completed: self.unschedule(coroutine) # Don't handle the result if we're shutting down if self._terminate: return if not coro_completed: try: result = self._trigger_from_any(result) except TypeError as exc: # restart this coroutine with an exception object telling it that # it wasn't allowed to yield that result = NullTrigger(outcome=outcomes.Error(exc)) self._resume_coro_upon(coroutine, result) # We do not return from here until pending threads have completed, but only # from the main thread, this seems like it could be problematic in cases # where a sim might change what this thread is. if self._main_thread is threading.current_thread(): for ext in self._pending_threads: ext.thread_start() if _debug: self.log.debug( "Blocking from %s on %s" % (threading.current_thread(), ext.thread)) state = ext.thread_wait() if _debug: self.log.debug( "Back from wait on self %s with newstate %d" % (threading.current_thread(), state)) if state == external_state.EXITED: self._pending_threads.remove(ext) self._pending_events.append(ext.event) # Handle any newly queued coroutines that need to be scheduled while self._pending_coros: self.add(self._pending_coros.pop(0))
def schedule(self, coroutine, trigger=None): """Schedule a coroutine by calling the send method. Args: coroutine (cocotb.decorators.coroutine): The coroutine to schedule. trigger (cocotb.triggers.Trigger): The trigger that caused this coroutine to be scheduled. """ if trigger is None: send_outcome = outcomes.Value(None) else: send_outcome = trigger._outcome if _debug: self.log.debug("Scheduling with {}".format(send_outcome)) try: result = coroutine._advance(send_outcome) if _debug: self.log.debug("Coroutine %s yielded %s (mode %d)" % (coroutine.__name__, str(result), self._mode)) # TestComplete indication is game over, tidy up except TestComplete as test_result: # Tag that close down is needed, save the test_result # for later use in cleanup handler self.log.debug("TestComplete received: %s" % test_result.__class__.__name__) self.finish_test(test_result) return # Normal coroutine completion except cocotb.decorators.CoroutineComplete as exc: if _debug: self.log.debug("Coroutine completed: %s" % str(coroutine)) self.unschedule(coroutine) return # Don't handle the result if we're shutting down if self._terminate: return try: result = self._trigger_from_any(result) except TypeError as exc: # restart this coroutine with an exception object telling it that # it wasn't allowed to yield that result = NullTrigger(outcome=outcomes.Error(exc)) self._coroutine_yielded(coroutine, result) # We do not return from here until pending threads have completed, but only # from the main thread, this seems like it could be problematic in cases # where a sim might change what this thread is. def unblock_event(ext): @cocotb.coroutine def wrapper(): ext.event.set() yield PythonTrigger() if self._main_thread is threading.current_thread(): for ext in self._pending_threads: ext.thread_start() if _debug: self.log.debug("Blocking from %s on %s" % (threading.current_thread(), ext.thread)) state = ext.thread_wait() if _debug: self.log.debug("Back from wait on self %s with newstate %d" % (threading.current_thread(), state)) if state == external_state.EXITED: self._pending_threads.remove(ext) self._pending_events.append(ext.event) # Handle any newly queued coroutines that need to be scheduled while self._pending_coros: self.add(self._pending_coros.pop(0))
def _wait_reset(self): ''' Do not wait on reset; immediately start writing out any new value. ''' yield NullTrigger()
def join(self): """Return a trigger that will fire when the wrapped coroutine exits""" if self._finished: return NullTrigger() else: return self._join
def example(): yield NullTrigger()
def generator_test(dut, arg): generator_testfactory_args.add(arg) yield NullTrigger()
def unblock_external(bridge): yield NullTrigger() bridge.set_out()
def null_coroutine(): yield NullTrigger()
def _synchronize(self): ''' Remove synchronization, since the intent is to always write out any new data. ''' yield NullTrigger()