Example #1
0
    def __init__(self, bus, clock, reset=None, *args, **kwargs):
        self.bus = bus
        self.clock = clock
        self.reset = reset
        self.log = logging.getLogger(f"cocotb.{bus._entity._name}.{bus._name}")

        super().__init__(*args, **kwargs)

        self.active = False
        self.queue = Queue()
        self.dequeue_event = Event()
        self.idle_event = Event()
        self.idle_event.set()
        self.active_event = Event()

        self.pause = False
        self._pause_generator = None
        self._pause_cr = None

        self.queue_occupancy_bytes = 0
        self.queue_occupancy_frames = 0

        self.width = len(self.bus.tdata)
        self.byte_lanes = len(self.bus.tkeep)

        self.byte_size = self.width // self.byte_lanes
        self.byte_mask = 2**self.byte_size - 1

        assert self.width in [64, 128, 256, 512]
        assert self.byte_size == 32
 def __init__(self, scope):
     self.listener_l = []
     self.lock = Lock()
     self.ev = Event()
     self.scope = scope
     cocotb.fork(self.run())
     pass
Example #3
0
async def test_event_set_schedule(dut):
    """
    Test that Event.set() doesn't cause an immediate reschedule.

    The coroutine waiting with Event.wait() will be woken after
    the current coroutine awaits a trigger.
    """

    e = Event()
    waiter_scheduled = False

    async def waiter(event):
        await event.wait()
        nonlocal waiter_scheduled
        waiter_scheduled = True

    cocotb.fork(waiter(e))

    e.set()

    # waiter() shouldn't run until after test awaits a trigger
    assert waiter_scheduled is False

    await NullTrigger()

    assert waiter_scheduled is True
Example #4
0
 def reset(self, wakeup=False):
     if wakeup is True:
         self.m_event.set()
     self.m_event = Event()
     self.num_waiters = 0
     self.set_value("on", False)
     self.trigger_time = 0
Example #5
0
 def __init__(self, dut, name):
     self.valid = dut.__getattr__(name + "_valid")
     self.ready = dut.__getattr__(name + "_ready")
     self.payload = Bundle(dut, name + "_payload")
     # Event
     self.event_ready = Event()
     self.event_valid = Event()
Example #6
0
    def __init__(self, data, ctrl, clock, reset=None, enable=None, mii_select=None, *args, **kwargs):
        self.log = logging.getLogger(f"cocotb.{data._path}")
        self.data = data
        self.ctrl = ctrl
        self.clock = clock
        self.reset = reset
        self.enable = enable
        self.mii_select = mii_select

        self.log.info("RGMII sink")
        self.log.info("cocotbext-eth version %s", __version__)
        self.log.info("Copyright (c) 2020 Alex Forencich")
        self.log.info("https://github.com/alexforencich/cocotbext-eth")

        super().__init__(*args, **kwargs)

        self.active = False
        self.queue = deque()
        self.sync = Event()

        self.mii_mode = False

        self.queue_occupancy_bytes = 0
        self.queue_occupancy_frames = 0

        self.width = 8
        self.byte_width = 1

        assert len(self.data) == 4
        assert len(self.ctrl) == 1

        self._run_cr = None

        self._init_reset(reset)
Example #7
0
class ResponseQueue(UVMQueue):
    """
    Returns either the next response or the item with the id.
    """
    def __init__(self, maxsize: int = 0):
        super().__init__(maxsize=maxsize)
        self.put_event = CocotbEvent("put event")

    def put_nowait(self, item):
        super().put_nowait(item)
        self.put_event.set()
        self.put_event.clear()

    async def get_response(self, txn_id=None):
        if txn_id is None:
            return await self.get()
        else:
            while True:
                item_list = list(self._queue)
                txn_list = [
                    xx for xx in item_list if xx.transaction_id == txn_id
                ]
                if len(txn_list) == 0:
                    await self.put_event.wait()
                else:
                    assert len(txn_list) == 1, \
                        f"Multiple transactionsn have the same ID: {txn_id}"
                    _ = self._queue.index(txn_list[0])
                    self._queue.remove(txn_list[0])
                    return txn_list[0]

    def __str__(self):
        return str([str(xx) for xx in self.queue])
Example #8
0
    def __init__(self):

        self.log = SimLog("cocotb.scheduler")
        if _debug:
            self.log.setLevel(logging.DEBUG)

        # Use OrderedDict here for deterministic behavior (gh-934)

        # A dictionary of pending coroutines for each trigger,
        # indexed by trigger
        self._trigger2coros = _ordered_dict()

        # A dictionary mapping coroutines to the trigger they are waiting for
        self._coro2trigger = _ordered_dict()

        # Our main state
        self._mode = Scheduler._MODE_NORMAL

        # A dictionary of pending writes
        self._writes = _ordered_dict()

        self._pending_coros = []
        self._pending_triggers = []
        self._pending_threads = []
        self._pending_events = []   # Events we need to call set on once we've unwound

        self._terminate = False
        self._test_result = None
        self._entrypoint = None
        self._main_thread = threading.current_thread()

        self._is_reacting = False

        self._write_coro_inst = None
        self._writes_pending = Event()
Example #9
0
    def __init__(self,
                 entity,
                 name,
                 clock,
                 lsb_first=True,
                 tuser_bytewise=False,
                 **kwargs):
        self._init_done = Event(
            "Init Done"
        )  # workaround for scheduler immediately running newly added coroutines
        BusMonitor.__init__(self, entity, name, clock, **kwargs)

        if hasattr(self.bus, 'tdata'):
            self._n_bytes, rem = divmod(len(self.bus.tdata), 8)
            if rem:
                raise AttributeError("tdata width has to be multiple of 8")
        else:
            self._n_bytes = 1

        if hasattr(self.bus, 'tuser'):
            self._tuser_bytewise = tuser_bytewise
            if tuser_bytewise and self._n_bytes:
                self._user_bits, rem = divmod(len(self.bus.tuser),
                                              self._n_bytes)
                if rem:
                    raise AttributeError(
                        "in byte-wise mode tuser width has to be multiple of tdata width"
                    )
            else:
                self._user_bits = len(self.bus.tuser)

        self._lsb_first = lsb_first
        self._init_done.set()
Example #10
0
    def __init__(self):

        self.log = SimLog("cocotb.scheduler")
        if _debug:
            self.log.setLevel(logging.DEBUG)

        # Use OrderedDict here for deterministic behavior (gh-934)

        # A dictionary of pending coroutines for each trigger,
        # indexed by trigger
        self._trigger2coros = _py_compat.insertion_ordered_dict()

        # Our main state
        self._mode = Scheduler._MODE_NORMAL

        # A dictionary of pending (write_func, args), keyed by handle. Only the last scheduled write
        # in a timestep is performed, all the rest are discarded in python.
        self._write_calls = _py_compat.insertion_ordered_dict()

        self._pending_coros = []
        self._pending_triggers = []
        self._pending_threads = []
        self._pending_events = [
        ]  # Events we need to call set on once we've unwound

        self._terminate = False
        self._test = None
        self._main_thread = threading.current_thread()

        self._current_task = None

        self._is_reacting = False

        self._write_coro_inst = None
        self._writes_pending = Event()
Example #11
0
    def __init__(self):
        UVMComponent.__init__(self, "__top__", None)
        #self.m_children = {}
        self.clp = UVMCmdlineProcessor.get_inst()
        self.finish_on_completion = True
        self.m_phase_all_done = False
        self.m_phase_all_done_event = Event('phase_all_done_event')
        # If set, then the entire testbench topology is printed just after completion
        # of the end_of_elaboration phase.
        self.enable_print_topology = False

        self.m_rh.set_name("reporter")
        self.report_header()

        #  // This sets up the global verbosity. Other command line args may
        #  // change individual component verbosity.
        self.m_check_verbosity()

        #  // Variable: top_levels
        #  //
        #  // This variable is a list of all of the top level components in UVM. It
        #  // includes the uvm_test_top component that is created by <run_test> as
        #  // well as any other top level components that have been instantiated
        #  // anywhere in the hierarchy.
        self.top_levels = []
Example #12
0
class Stream:
    def __init__(self, dut, name):
        self.valid = dut.__getattr__(name + "_valid")
        self.ready = dut.__getattr__(name + "_ready")
        self.payload = Bundle(dut, name + "_payload")
        # Event
        self.event_ready = Event()
        self.event_valid = Event()

    def startMonitoringReady(self, clk):
        self.clk = clk
        self.fork_ready = cocotb.fork(self.monitor_ready())

    def startMonitoringValid(self, clk):
        self.clk = clk
        self.fork_valid = cocotb.fork(self.monitor_valid())

    def stopMonitoring(self):
        self.fork_ready.kill()
        self.fork_valid.kill()

    @cocotb.coroutine
    def monitor_ready(self):
        while True:
            yield RisingEdge(self.clk)
            if int(self.ready) == 1:
                self.event_ready.set(self.payload)

    @cocotb.coroutine
    def monitor_valid(self):
        while True:
            yield RisingEdge(self.clk)
            if int(self.valid) == 1:
                self.event_valid.set(self.payload)
Example #13
0
    def __init__(self, driver, index, hw_addr):
        self.driver = driver
        self.log = driver.log
        self.index = index
        self.hw_addr = hw_addr
        self.csr_hw_addr = hw_addr + driver.if_csr_offset
        self.port_up = False

        self.if_id = None
        self.event_queue_count = None
        self.event_queue_offset = None
        self.tx_queue_count = None
        self.tx_queue_offset = None
        self.tx_cpl_queue_count = None
        self.tx_cpl_queue_offset = None
        self.rx_queue_count = None
        self.rx_queue_offset = None
        self.rx_cpl_queue_count = None
        self.rx_cpl_queue_offset = None
        self.port_count = None
        self.port_offset = None
        self.port_stride = None

        self.interrupt_running = False
        self.interrupt_pending = 0

        self.pkt_rx_queue = deque()
        self.pkt_rx_sync = Event()
Example #14
0
    def __init__(self, data, baud=9600, bits=8, stop_bits=1, *args, **kwargs):
        self.log = logging.getLogger(f"cocotb.{data._path}")
        self._data = data
        self._baud = baud
        self._bits = bits
        self._stop_bits = stop_bits

        self.log.info("UART source")
        self.log.info("cocotbext-uart version %s", __version__)
        self.log.info("Copyright (c) 2020 Alex Forencich")
        self.log.info("https://github.com/alexforencich/cocotbext-uart")

        super().__init__(*args, **kwargs)

        self.active = False
        self.queue = deque()
        self.sync = Event()

        self._idle = Event()
        self._idle.set()

        self._data.setimmediatevalue(1)

        self.log.info("UART source configuration:")
        self.log.info("  Baud rate: %d bps", self._baud)
        self.log.info("  Byte size: %d bits", self._bits)
        self.log.info("  Stop bits: %f bits", self._stop_bits)

        self._run_cr = None
        self._restart()
Example #15
0
    def __init__(self, callback=None, event=None):
        """
        Constructor for a monitor instance

        callback will be called with each recovered transaction as the argument

        If the callback isn't used, received transactions will be placed on a
        queue and the event used to notify any consumers.
        """
        self._event = event
        self._wait_event = None
        self._recvQ = deque()
        self._callbacks = []
        self.stats = MonitorStatistics()
        self._wait_event = Event()

        # Subclasses may already set up logging
        if not hasattr(self, "log"):
            self.log = SimLog("cocotb.monitor.%s" % (self.__class__.__name__))

        if callback is not None:
            self.add_callback(callback)

        # Create an independent coroutine which can receive stuff
        self._thread = cocotb.scheduler.add(self._monitor_recv())
Example #16
0
 def __init__(self, name="uvm_sequence"):
     """         
       Function: __init__
      
       The constructor for uvm_sequence_base.
      
     Args:
         name: 
     """
     UVMSequenceItem.__init__(self, name)
     self.m_sequence_state = UVM_CREATED
     self.m_wait_for_grant_semaphore = 0
     self.m_init_phase_daps(1)
     self.m_next_transaction_id = 1
     self.m_priority = -1
     self.m_tr_recorder = None  # uvm_recorder
     #self.m_automatic_phase_objection_dap = None  # uvm_get_to_lock_dap#(bit)
     #self.m_starting_phase_dap = None  # uvm_get_to_lock_dap#(uvm_phase)
     # Each sequencer will assign a sequence id.  When a sequence is talking to multiple
     # sequencers, each sequence_id is managed separately
     self.m_sqr_seq_ids = UVMPool()
     self.children_array = {}  # bit[uvm_sequence_base]
     self.response_queue = UVMQueue()
     self.response_queue_depth = 8
     self.response_queue_error_report_disabled = False
     #  bits to detect if is_relevant()/wait_for_relevant() are implemented
     self.is_rel_default = False
     self.wait_rel_default = False
     self.m_sequence_process = None  # process
     self.m_use_response_handler = False
     #self.m_resp_queue_event = UVMEvent("resp_queue_event")
     self.m_resp_queue_event = Event("resp_queue_event")
     self.m_resp_queue_event.clear()
     self.m_events = {}
     self.m_events[UVM_FINISHED] = Event("UVM_FINISHED")
Example #17
0
 def __init__(self, size=0, name='mailbox'):
     self.max_size = size
     self.name = name
     self.m_queue = UVMQueue()
     self.m_read_event = Event('mailbox_read_event')
     self.m_write_event = Event('mailbox_write_event')
     self.debug_enabled = False
Example #18
0
class SfifoMonitor(WrRdDriverMonitor):
    '''
    Monitors the reading interface of a powlib_sfifo.
    '''
    def __init__(self, *args, **kwargs):
        '''
        This constructor simply creates the state and event objects needed
        to implement the read method defined for the monitor.
        '''
        self.__state = "stopped"
        self.__evt = Event()
        WrRdDriverMonitor.__init__(self, *args, **kwargs)

    def start(self):
        '''
        Indicate to the read method it should start its operation.
        '''
        self.__evt.set()

    def stop(self):
        '''
        After one more read, stop further read transactions.
        '''
        self.__state = "stopped"

    @coroutine
    def read(self):
        '''
        Implements the behavior of the monitor's read method. Initially,
        the monitor is in a stopped state, until the user decides to start it.
        Once started, the read method will call the drivers read method that 
        sets the rdrdy signal and set the state of the monitor to started. While
        in its started state, the monitor will call the driver's read method, 
        without any arguments, indicating it should simply read whenever the rdvld 
        is high.
        '''

        if self.__state == "stopped":
            '''
            Stopped state indicates the monitor is waiting.
            '''
            yield self.driver.read(rdrdy=0)
            yield self.__evt.wait()
            self.__evt.clear()
            self.__state = "started"
            yield self.cycle()
            value = yield self.driver.read(rdrdy=1)
            raise ReturnValue(value)

        elif self.__state == "started":
            '''
            Once started, the monitor will continue to read valid data from
            the read interface.
            '''
            value = yield self.driver.read()
            raise ReturnValue(value)

        else:
            raise ValueError("Unknown state occurred.")
Example #19
0
 def __init__(self, dut, num_executions):
     self.dut = dut
     self.num_executions = num_executions
     self.in_vals = Event(
     )  # Event to communicate Driver and ReferenceModel
     self.out_vals = Event(
     )  # Event to communicate ReferenceModel and Checker
     self.ref_equal = 0
Example #20
0
    def __init__(self, dut, name):

        # interface
        self.valid = dut.__getattr__(name + "_valid")
        self.payload = Bundle(dut, name + "_payload")

        # Event
        self.event_valid = Event()
Example #21
0
 def __init__(self, *args, **kwargs):
     '''
     This constructor simply creates the state and event objects needed
     to implement the read method defined for the monitor.
     '''
     self.__state = "stopped"
     self.__evt = Event()
     WrRdDriverMonitor.__init__(self, *args, **kwargs)
Example #22
0
class TestBench:

    ## dut = design under test
    def __init__(self, dut, num_executions):
        self.dut = dut
        self.num_executions = num_executions
        self.in_vals = Event(
        )  # Event to communicate Driver and ReferenceModel
        self.out_vals = Event(
        )  # Event to communicate ReferenceModel and Checker
        self.ref_equal = 0

    @cocotb.coroutine
    def Driver(self):
        self.dut.rst <= 1
        yield RisingEdge(self.dut.clk)
        yield RisingEdge(self.dut.clk)
        self.dut.rst <= 0
        vals = rand_vals(2**SIGNAL_LENGTH)
        for _ in range(self.num_executions):
            vals.randomize()  # Randomize values of the vectors
            self.dut.signal_to_delay <= vals.signal_to_delay
            self.dut.signal_delayed <= vals.signal_delayed
            self.in_vals.set((vals.signal_to_delay, vals.signal_delayed))
            yield RisingEdge(self.dut.clk)
            sample_coverage(vals)

    @cocotb.coroutine
    def ReferenceModel(self):
        ref_signal_to_delay_delayed_1 = 0
        ref_signal_to_delay_delayed_2 = 0
        ref_signal_to_delay_delayed_3 = 0
        for _ in range(self.num_executions):
            yield self.in_vals.wait()
            self.ref_equal = (
                ref_signal_to_delay_delayed_3 == self.in_vals.data[1])
            ref_signal_to_delay_delayed_3 = ref_signal_to_delay_delayed_2
            ref_signal_to_delay_delayed_2 = ref_signal_to_delay_delayed_1
            ref_signal_to_delay_delayed_1 = self.in_vals.data[0]
            self.out_vals.set(self.ref_equal)
            self.in_vals.clear()

    @cocotb.coroutine
    def Checker(self, ref_th):
        last_ref_equal = False
        for _ in range(self.num_executions):
            yield self.out_vals.wait()
            cocotb.log.info(" ref_equal={0}, dut_equal={1}".format(
                last_ref_equal, int(self.dut.equal.value)))
            assert self.dut.equal == last_ref_equal
            last_ref_equal = self.out_vals.data
            self.out_vals.clear()

    @cocotb.coroutine
    def run(self):
        cocotb.fork(self.Driver())
        ref_th = cocotb.fork(self.ReferenceModel())
        yield cocotb.fork(self.Checker(ref_th)).join()
Example #23
0
    def __init__(self, clk, halfPeriod, reset=None, resetActiveLevel=RESET_ACTIVE_LEVEL.LOW):

        self.halfPeriod = halfPeriod

        self.clk       = clk
        self.reset     = reset
        self.typeReset = resetActiveLevel

        self.event_endReset = Event()
Example #24
0
    def __init__(self, bus, clock, reset=None, reset_active_level=True):
        self.bus = bus
        self.clock = clock
        self.reset = reset
        self.log = logging.getLogger(
            f"cocotb.{bus.ar._entity._name}.{bus.ar._name}")

        self.log.info("AXI lite master (read)")
        self.log.info("cocotbext-axi version %s", __version__)
        self.log.info("Copyright (c) 2020 Alex Forencich")
        self.log.info("https://github.com/alexforencich/cocotbext-axi")

        self.ar_channel = AxiLiteARSource(bus.ar, clock, reset,
                                          reset_active_level)
        self.ar_channel.queue_occupancy_limit = 2
        self.r_channel = AxiLiteRSink(bus.r, clock, reset, reset_active_level)
        self.r_channel.queue_occupancy_limit = 2

        self.read_command_queue = Queue()
        self.current_read_command = None

        self.int_read_resp_command_queue = Queue()
        self.current_read_resp_command = None

        self.in_flight_operations = 0
        self._idle = Event()
        self._idle.set()

        self.width = len(self.r_channel.bus.rdata)
        self.byte_size = 8
        self.byte_lanes = self.width // self.byte_size

        self.arprot_present = hasattr(self.bus.ar, "arprot")

        self.log.info("AXI lite master configuration:")
        self.log.info("  Address width: %d bits",
                      len(self.ar_channel.bus.araddr))
        self.log.info("  Byte size: %d bits", self.byte_size)
        self.log.info("  Data width: %d bits (%d bytes)", self.width,
                      self.byte_lanes)

        self.log.info("AXI lite master signals:")
        for bus in (self.bus.ar, self.bus.r):
            for sig in sorted(
                    list(set().union(bus._signals, bus._optional_signals))):
                if hasattr(bus, sig):
                    self.log.info("  %s width: %d bits", sig,
                                  len(getattr(bus, sig)))
                else:
                    self.log.info("  %s: not present", sig)

        assert self.byte_lanes * self.byte_size == self.width

        self._process_read_cr = None
        self._process_read_resp_cr = None

        self._init_reset(reset, reset_active_level)
Example #25
0
    def __init__(self, bus, clock, reset=None, reset_active_level=True, max_burst_len=256):
        self.log = logging.getLogger(f"cocotb.{bus.aw._entity._name}.{bus.aw._name}")

        self.log.info("AXI master (write)")
        self.log.info("cocotbext-axi version %s", __version__)
        self.log.info("Copyright (c) 2020 Alex Forencich")
        self.log.info("https://github.com/alexforencich/cocotbext-axi")

        self.aw_channel = AxiAWSource(bus.aw, clock, reset, reset_active_level)
        self.aw_channel.queue_occupancy_limit = 2
        self.w_channel = AxiWSource(bus.w, clock, reset, reset_active_level)
        self.w_channel.queue_occupancy_limit = 2
        self.b_channel = AxiBSink(bus.b, clock, reset, reset_active_level)
        self.b_channel.queue_occupancy_limit = 2

        self.write_command_queue = Queue()
        self.current_write_command = None

        self.id_count = 2**len(self.aw_channel.bus.awid)
        self.cur_id = 0
        self.active_id = Counter()

        self.int_write_resp_command_queue = [Queue() for k in range(self.id_count)]
        self.current_write_resp_command = [None for k in range(self.id_count)]
        self.int_write_resp_queue_list = [Queue() for k in range(self.id_count)]

        self.in_flight_operations = 0
        self._idle = Event()
        self._idle.set()

        self.width = len(self.w_channel.bus.wdata)
        self.byte_size = 8
        self.byte_width = self.width // self.byte_size
        self.strb_mask = 2**self.byte_width-1

        self.max_burst_len = max(min(max_burst_len, 256), 1)
        self.max_burst_size = (self.byte_width-1).bit_length()

        self.log.info("AXI master configuration:")
        self.log.info("  Address width: %d bits", len(self.aw_channel.bus.awaddr))
        self.log.info("  ID width: %d bits", len(self.aw_channel.bus.awid))
        self.log.info("  Byte size: %d bits", self.byte_size)
        self.log.info("  Data width: %d bits (%d bytes)", self.width, self.byte_width)
        self.log.info("  Max burst size: %d (%d bytes)", self.max_burst_size, 2**self.max_burst_size)
        self.log.info("  Max burst length: %d cycles (%d bytes)",
            self.max_burst_len, self.max_burst_len*self.byte_width)

        assert self.byte_width == len(self.w_channel.bus.wstrb)
        assert self.byte_width * self.byte_size == self.width

        assert len(self.b_channel.bus.bid) == len(self.aw_channel.bus.awid)

        self._process_write_cr = None
        self._process_write_resp_cr = None
        self._process_write_resp_id_cr = None

        self._init_reset(reset, reset_active_level)
Example #26
0
    def __init__(self, entity, name, clock, reset=None, *args, **kwargs):
        super().__init__(entity, name, clock, reset, *args, **kwargs)

        self.drive_obj = None
        self.drive_sync = Event()

        self.active = False

        cocotb.fork(self._run_source())
        cocotb.fork(self._run())
Example #27
0
 def read(self, address, tag=0):
     """ 32 bit read """
     tlp = np.zeros(4, dtype='uint32')
     tlp[0] = 0x00000001
     tlp[1] = 0xbaaa00ff | tag << 8
     tlp[2] = address
     self.read_wait = Event("rw")
     self.txqueue.put(tlp)
     yield self.read_wait.wait()
     raise ReturnValue(self.read_data)
Example #28
0
    def __init__(self):
        """Constructor for a driver instance."""
        self._pending = Event(name="Driver._pending")
        self._sendQ = deque()

        # Subclasses may already set up logging
        if not hasattr(self, "log"):
            self.log = SimLog("cocotb.driver.%s" % (self.__class__.__name__))

        # Create an independent coroutine which can send stuff
        self._thread = cocotb.scheduler.add(self._send_thread())
Example #29
0
    def __init__(self,
                 data,
                 er,
                 dv,
                 clock,
                 reset=None,
                 enable=None,
                 reset_active_level=True,
                 *args,
                 **kwargs):
        self.log = logging.getLogger(f"cocotb.{data._path}")
        self.data = data
        self.er = er
        self.dv = dv
        self.clock = clock
        self.reset = reset
        self.enable = enable

        self.log.info("MII source")
        self.log.info("cocotbext-eth version %s", __version__)
        self.log.info("Copyright (c) 2020 Alex Forencich")
        self.log.info("https://github.com/alexforencich/cocotbext-eth")

        super().__init__(*args, **kwargs)

        self.active = False
        self.queue = Queue()
        self.dequeue_event = Event()
        self.current_frame = None
        self.idle_event = Event()
        self.idle_event.set()

        self.ifg = 12

        self.queue_occupancy_bytes = 0
        self.queue_occupancy_frames = 0

        self.queue_occupancy_limit_bytes = -1
        self.queue_occupancy_limit_frames = -1

        self.width = 4
        self.byte_width = 1

        assert len(self.data) == 4
        self.data.setimmediatevalue(0)
        if self.er is not None:
            assert len(self.er) == 1
            self.er.setimmediatevalue(0)
        assert len(self.dv) == 1
        self.dv.setimmediatevalue(0)

        self._run_cr = None

        self._init_reset(reset, reset_active_level)
Example #30
0
class test_locker(object):
    def __init__(self):
        self.in_event = None
        self.out_event = Event()
        self.result = None

    def set_in(self):
        self.in_event.set()

    def set_out(self):
        self.out_event.set()
Example #31
0
    def __init__(self, maxsize: int = 0):

        self._maxsize = maxsize

        self._finished = Event()
        self._finished.set()

        self._getters = collections.deque()
        self._putters = collections.deque()

        self._init(maxsize)
Example #32
0
    def __init__(self, callback=None, event=None):
        """
        Constructor for a monitor instance

        callback will be called with each recovered transaction as the argument

        If the callback isn't used, received transactions will be placed on a
        queue and the event used to notify any consumers.
        """
        self._event = event
        self._wait_event = None
        self._recvQ = []
        self._callbacks = []
        self.stats = MonitorStatistics()
        self._wait_event = Event()

        # Subclasses may already set up logging
        if not hasattr(self, "log"):
            self.log = SimLog("cocotb.monitor.%s" % (self.__class__.__name__))

        if callback is not None:
            self.add_callback(callback)

        # Create an independent coroutine which can receive stuff
        self._thread = cocotb.scheduler.add(self._monitor_recv())
Example #33
0
    def __init__(self):

        self.log = SimLog("cocotb.scheduler")
        if _debug:
            self.log.setLevel(logging.DEBUG)

        # Use OrderedDict here for deterministic behavior (gh-934)

        # A dictionary of pending coroutines for each trigger,
        # indexed by trigger
        self._trigger2coros = collections.OrderedDict()

        # A dictionary mapping coroutines to the trigger they are waiting for
        self._coro2trigger = collections.OrderedDict()

        # Our main state
        self._mode = Scheduler._MODE_NORMAL

        # A dictionary of pending writes
        self._writes = collections.OrderedDict()

        self._pending_coros = []
        self._pending_triggers = []
        self._pending_threads = []
        self._pending_events = []   # Events we need to call set on once we've unwound

        self._terminate = False
        self._test_result = None
        self._entrypoint = None
        self._main_thread = threading.current_thread()

        self._is_reacting = False

        self._write_coro_inst = None
        self._writes_pending = Event()
Example #34
0
    def __init__(self, helperSlave, listOperation):
        self.sda = helperSlave.io.sda_rd
        self.scl = helperSlave.io.scl_rd
        self.clk = helperSlave.io.clk

        self.event_RisingEdge  = Event()
        self.event_FallingEdge  = Event()

        self.event_Start = Event()
        self.event_Stop  = Event()

        self.listOp = list()
        self.refListOp = listOperation
        self.dataBinRead = list()

        self.startSeq = 0
Example #35
0
 def __init__(self, entity, name, clock):
     BusDriver.__init__(self, entity, name, clock)
     self.bus.A.setimmediatevalue(5)
     self.bus.B.setimmediatevalue(5)
     self.log.debug("Test DrvM created")
     self.busy_event = Event("%s_busy" % name)
     self.busy = False
Example #36
0
    def __init__(self, helperMaster ): # initMemory = dict()):

        self.startEvent  = Event()
        self.stopEvent   = Event()
        self.dataRxEvent = Event()
        self.dataTXEvent = Event()

        self.sda_rd      = helperMaster.io.sda_wr
        self.sda_wr      = helperMaster.io.sda_rd
        self.scl_rd      = helperMaster.io.scl_wr
        self.scl_wr      = helperMaster.io.scl_rd

        self.resetn      = helperMaster.io.resetn
        self.clk         = helperMaster.io.clk

        self.sda         = 1
        self.scl         = 1
Example #37
0
 def __init__(self, entity, name, clock, timeout=5000):
     Wishbone.__init__(self, entity, name, clock)
     sTo = ", no cycle timeout"        
     if not (timeout is None):
         sTo = ", cycle timeout is %u clockcycles" % timeout
     self.log.info("Wishbone Master created%s" % sTo)
     self.busy_event = Event("%s_busy" % name)
     self.busy = False
     self._timeout = timeout
Example #38
0
    def __init__(self):
        """Constructor for a driver instance."""
        self._pending = Event(name="Driver._pending")
        self._sendQ = deque()

        # Subclasses may already set up logging
        if not hasattr(self, "log"):
            self.log = SimLog("cocotb.driver.%s" % (self.__class__.__name__))

        # Create an independent coroutine which can send stuff
        self._thread = cocotb.scheduler.add(self._send_thread())
Example #39
0
 def __init__(self, dut, rx_channels=1, tx_channels=1,
              tx_clock_half_period=16276, rx_clock_half_period=16276,
              loopback_queue_maxlen=16):
     self.dut = dut
     self.tx_clock_half_period = tx_clock_half_period
     self.rx_clock_half_period = rx_clock_half_period
     self.rx_frame_asserted = False
     self.tx_frame_asserted = False
     self.lbqi = deque()
     self.lbqq = deque()
     cocotb.fork(self._rx_clock())
     self.got_tx = Event("Got tx event")
Example #40
0
    def __init__(self, entity, name, clock, **kwargs):
        AvalonMM.__init__(self, entity, name, clock, **kwargs)
        self.log.debug("AvalonMaster created")
        self.busy_event = Event("%s_busy" % name)
        self.busy = False

        config = kwargs.pop('config', {})
        self.config = AvalonMaster._default_config.copy()

        for configoption, value in config.items():
            self.config[configoption] = value
            self.log.debug("Setting config option %s to %s" %
                           (configoption, str(value)))
Example #41
0
    def __init__(self, helperSlave, clockDivider):

        self.wr_scl   = helperSlave.io.scl_rd
        self.wr_sda   = helperSlave.io.sda_rd
        self.rd_scl   = helperSlave.io.scl_wr
        self.rd_sda   = helperSlave.io.sda_wr
        self.clk      = helperSlave.io.clk

        self.sda       = 1
        self.scl       = 1

        self.clockDivider = clockDivider

        self.scl_en       = 0

        self.trigger     = Event()
        self.sclRising   = Event()
        self.sclFalling  = Event()

        self.dataRead    = Event()

        self.freezeBus   = False
Example #42
0
class test_drv(BusDriver):
    _signals = ["A", "B", "X"]
    _optional_signals= []

    def __init__(self, entity, name, clock):
        BusDriver.__init__(self, entity, name, clock)
        self.bus.A.setimmediatevalue(5)
        self.bus.B.setimmediatevalue(5)
        self.log.debug("Test DrvM created")
        self.busy_event = Event("%s_busy" % name)
        self.busy = False

    @cocotb.coroutine
    def _acquire_lock(self):
        if self.busy:
            yield self.busy_event.wait()
        self.busy_event.clear()
        self.busy = True

    def _release_lock(self):
        self.busy = False
        self.busy_event.set()


    @cocotb.coroutine
    def write(self, value_a, value_b, sync=True):
        """
        """
        yield self._acquire_lock()

        if sync:
            yield RisingEdge(self.clock)
        self.bus.A <= value_a
        self.bus.B <= value_b

        self._release_lock()
Example #43
0
    def __init__(self, callback=None, event=None):
        self._event = event
        self._wait_event = None
        self._recvQ = deque()
        self._callbacks = []
        self.stats = MonitorStatistics()
        self._wait_event = Event()

        # Subclasses may already set up logging
        if not hasattr(self, "log"):
            self.log = SimLog("cocotb.monitor.%s" % (self.__class__.__name__))

        if callback is not None:
            self.add_callback(callback)

        # Create an independent coroutine which can receive stuff
        self._thread = cocotb.scheduler.add(self._monitor_recv())
Example #44
0
 def __init__(self, entity, name, clock):
     BusDriver.__init__(self, entity, name, clock)
     self.bus.select.setimmediatevalue(0)
     self.log.debug("OPBMaster created")
     self.busy_event = Event("%s_busy" % name)
     self.busy = False
Example #45
0
class OPBMaster(BusDriver):
    """
    On-chip peripheral bus master
    """
    _signals = ["xferAck", "errAck", "toutSup", "retry", "DBus_out", "select", "RNW", "BE", "ABus", "DBus_in"]
    _optional_signals = ["seqAddr"]
    _max_cycles = 16

    def __init__(self, entity, name, clock):
        BusDriver.__init__(self, entity, name, clock)
        self.bus.select.setimmediatevalue(0)
        self.log.debug("OPBMaster created")
        self.busy_event = Event("%s_busy" % name)
        self.busy = False

    @cocotb.coroutine
    def _acquire_lock(self):
        if self.busy:
            yield self.busy_event.wait()
        self.busy_event.clear()
        self.busy = True

    def _release_lock(self):
        self.busy = False
        self.busy_event.set()

    @cocotb.coroutine
    def read(self, address, sync=True):
        """
        Issue a request to the bus and block until this
        comes back. Simulation time still progresses
        but syntactically it blocks.
        """
        yield self._acquire_lock()

        # Apply values for next clock edge
        if sync:
            yield RisingEdge(self.clock)
        self.bus.ABus <= address
        self.bus.select <= 1
        self.bus.RNW <= 1
        self.bus.BE <= 0xF

        count = 0
        while not int(self.bus.xferAck.value):
            yield RisingEdge(self.clock)
            yield ReadOnly()
            if int(self.bus.toutSup.value):
                count = 0
            else:
                count += 1
            if count >= self._max_cycles:
                raise OPBException("Read took longer than 16 cycles")
        data = int(self.bus.DBus_out.value)

        # Deassert read
        self.bus.select <= 0
        self._release_lock()
        self.log.info("Read of address 0x%x returned 0x%08x" % (address, data))
        raise ReturnValue(data)

    @cocotb.coroutine
    def write(self, address, value, sync=True):
        """
        """
        yield self._acquire_lock()

        if sync:
            yield RisingEdge(self.clock)
        self.bus.ABus <= address
        self.bus.select <= 1
        self.bus.RNW <= 0
        self.bus.BE <= 0xF
        self.bus.DBus_out <= value

        count = 0
        while not int(self.bus.xferAck.value):
            yield RisingEdge(self.clock)
            yield ReadOnly()
            if int(self.bus.toutSup.value):
                count = 0
            else:
                count += 1
            if count >= self._max_cycles:
                raise OPBException("Write took longer than 16 cycles")

        self.bus.select <= 0
        self._release_lock()
Example #46
0
class I2CHALAnalyser:

    def __init__(self, helperSlave, listOperation):
        self.sda = helperSlave.io.sda_rd
        self.scl = helperSlave.io.scl_rd
        self.clk = helperSlave.io.clk

        self.event_RisingEdge  = Event()
        self.event_FallingEdge  = Event()

        self.event_Start = Event()
        self.event_Stop  = Event()

        self.listOp = list()
        self.refListOp = listOperation
        self.dataBinRead = list()

        self.startSeq = 0


    #==========================================================================
    # Start to analyse the bus
    #==========================================================================
    @cocotb.coroutine
    def start(self):

        self.fork_falling = cocotb.fork(self._FallingEdgeDetection())
        self.fork_rising  = cocotb.fork(self._RisingEdgeDetection())
        self.fork_start   = cocotb.fork(self._startDetection())
        self.fork_stop    = cocotb.fork(self._stopDetection())
        yield self._analyser()


    #==========================================================================
    # Stop all processes
    #==========================================================================
    def stop(self):
        self.fork_falling.kill()
        self.fork_rising.kill()
        self.fork_start.kill()
        self.fork_stop.kill()


    #==========================================================================
    # Store all event appening on the bus
    #==========================================================================
    @cocotb.coroutine
    def _analyser(self):

        self.listOp = list()

        # Start ---------------------------------------------------------------
        yield self.event_Start.wait()
        yield RisingEdge(self.clk)
        self.startSeq = 0

        while True:

            dataBinRead = list()
            index = 0
            # Read data -----------------------------------------------------------
            while index < I2CConfig.dataWdith:
                yield self.event_RisingEdge.wait()
                dataBinRead.append(int(self.sda))
                #print("data ", index, " value " , int(self.sda), "index ", index, "start " , self.startSeq )

                if self.startSeq == 1:
                    index = 0
                    self.startSeq = 0
                    dataBinRead = list()
                    dataBinRead.append(int(self.sda))

                index += 1

            dataInRead = int("".join([str(x) for x in dataBinRead]), 2)
            self.listOp.append(DATA(dataInRead))

            # Read ACK ------------------------------------------------------------
            yield self.event_RisingEdge.wait()
            if int(self.sda) == 0:
                self.listOp.append(ACK())
            else:
                self.listOp.append(NACK())

            #print()

    #==========================================================================
    # Detect the start condition
    #==========================================================================
    @cocotb.coroutine
    def _startDetection(self):
        yield RisingEdge(self.clk)
        while True:
            prev = int(self.sda)
            yield RisingEdge(self.clk)
            if prev == 1 and int(self.sda) == 0:
                if int(self.scl) == 1:
                    self.event_Start.set()
                    self.listOp.append(START())
                    self.startSeq = 1


    #==========================================================================
    # Detect the stop condition
    #==========================================================================
    @cocotb.coroutine
    def _stopDetection(self):
        yield RisingEdge(self.clk)
        while True:
            prev = int(self.sda)
            yield RisingEdge(self.clk)
            if prev == 0 and int(self.sda) == 1:
                if int(self.scl) == 1:
                    self.event_Stop.set()
                    self.listOp.append(STOP())

                    # check sequence...
                    for (op, ref) in zip(self.listOp, self.refListOp):

                        if isinstance(ref, START) and isinstance(op, START):
                            pass
                        elif isinstance(ref, STOP) and isinstance(op, STOP):
                            pass
                        elif isinstance(ref, ACK) and isinstance(op, ACK):
                            pass
                        elif isinstance(ref, NACK) and isinstance(op, NACK):
                            pass
                        elif (isinstance(ref, WRITE) or isinstance(ref, READ)) and isinstance(op, DATA):
                            if ref.data != op.data:
                                print("ref ", hex(ref.data), " op ", hex(op.data))
                                assertEquals(ref.data , op.data , "Analyser data ERROR")

                        else:
                            assertEquals(True , False , "%s is not equal to %s" % (ref, op))


    #==========================================================================
    # Detect a Rising edge of scl
    #==========================================================================
    @cocotb.coroutine
    def _RisingEdgeDetection(self):
        while True:
            yield RisingEdge(self.scl)
            self.event_RisingEdge.set()


    #==========================================================================
    # Detect a Falling edge of scl
    #==========================================================================
    @cocotb.coroutine
    def _FallingEdgeDetection(self):
        while True:
            yield FallingEdge(self.scl)
            self.event_FallingEdge.set()
Example #47
0
 def __init__(self, entity, name, clock, **kwargs):
     AvalonMM.__init__(self, entity, name, clock, **kwargs)
     self.log.debug("AvalonMaster created")
     self.busy_event = Event("%s_busy" % name)
     self.busy = False
Example #48
0
class AvalonMaster(AvalonMM):
    """Avalon Memory Mapped Interface (Avalon-MM) Master"""
    def __init__(self, entity, name, clock, **kwargs):
        AvalonMM.__init__(self, entity, name, clock, **kwargs)
        self.log.debug("AvalonMaster created")
        self.busy_event = Event("%s_busy" % name)
        self.busy = False

    def __len__(self):
        return 2**len(self.bus.address)

    @coroutine
    def _acquire_lock(self):
        if self.busy:
            yield self.busy_event.wait()
        self.busy_event.clear()
        self.busy = True

    def _release_lock(self):
        self.busy = False
        self.busy_event.set()

    @coroutine
    def read(self, address, sync=True):
        """Issue a request to the bus and block until this
        comes back. Simulation time still progresses
        but syntactically it blocks.
        
        Args:
            address (int): The address to read from.
            sync (bool, optional): Wait for rising edge on clock initially.
                Defaults to True.
            
        Returns:
            BinaryValue: The read data value.
            
        Raises:
            :any:`TestError`: If master is write-only.
        """
        if not self._can_read:
            self.log.error("Cannot read - have no read signal")
            raise TestError("Attempt to read on a write-only AvalonMaster")

        yield self._acquire_lock()

        # Apply values for next clock edge
        if sync:
            yield RisingEdge(self.clock)
        self.bus.address <= address
        self.bus.read <= 1
        if hasattr(self.bus, "byteenable"):
            self.bus.byteenable <= int("1"*len(self.bus.byteenable), 2)
        if hasattr(self.bus, "cs"):
            self.bus.cs <= 1

        # Wait for waitrequest to be low
        if hasattr(self.bus, "waitrequest"):
            yield self._wait_for_nsignal(self.bus.waitrequest)
        yield RisingEdge(self.clock)

        # Deassert read
        self.bus.read <= 0
        if hasattr(self.bus, "byteenable"):
            self.bus.byteenable <= 0
        if hasattr(self.bus, "cs"):
            self.bus.cs <= 0
        v = self.bus.address.value
        v.binstr = "x" * len(self.bus.address)
        self.bus.address <= v

        if hasattr(self.bus, "readdatavalid"):
            while True:
                yield ReadOnly()
                if int(self.bus.readdatavalid):
                    break
                yield RisingEdge(self.clock)
        else:
            # Assume readLatency = 1 if no readdatavalid
            # FIXME need to configure this,
            # should take a dictionary of Avalon properties.
            yield ReadOnly()

        # Get the data
        data = self.bus.readdata.value

        self._release_lock()
        raise ReturnValue(data)

    @coroutine
    def write(self, address, value):
        """Issue a write to the given address with the specified
        value.

        Args:
            address (int): The address to write to.
            value (int): The data value to write.

        Raises:
            :any:`TestError`: If master is read-only.
        """
        if not self._can_write:
            self.log.error("Cannot write - have no write signal")
            raise TestError("Attempt to write on a read-only AvalonMaster")

        yield self._acquire_lock()

        # Apply values to bus
        yield RisingEdge(self.clock)
        self.bus.address <= address
        self.bus.writedata <= value
        self.bus.write <= 1
        if hasattr(self.bus, "byteenable"):
            self.bus.byteenable <= int("1"*len(self.bus.byteenable), 2)
        if hasattr(self.bus, "cs"):
            self.bus.cs <= 1

        # Wait for waitrequest to be low
        if hasattr(self.bus, "waitrequest"):
            count = yield self._wait_for_nsignal(self.bus.waitrequest)

        # Deassert write
        yield RisingEdge(self.clock)
        self.bus.write <= 0
        if hasattr(self.bus, "byteenable"):
            self.bus.byteenable <= 0
        if hasattr(self.bus, "cs"):
            self.bus.cs <= 0
        v = self.bus.address.value
        v.binstr = "x" * len(self.bus.address)
        self.bus.address <= v

        v = self.bus.writedata.value
        v.binstr = "x" * len(self.bus.writedata)
        self.bus.writedata <= v
        self._release_lock()
Example #49
0
 def __init__(self):
     self.in_event = None
     self.out_event = Event()
     self.result = None
Example #50
0
class WishboneMaster(Wishbone):
    """Wishbone master
    """
    _acked_ops          = 0  # ack cntr. comp with opbuf len. wait for equality before releasing lock
    _res_buf            = [] # save readdata/ack/err
    _aux_buf            = [] # save read/write order
    _op_cnt             = 0 # number of ops we've been issued
    _clk_cycle_count    = 0
    _timeout            = None

    
    def __init__(self, entity, name, clock, timeout=5000):
        Wishbone.__init__(self, entity, name, clock)
        sTo = ", no cycle timeout"        
        if not (timeout is None):
            sTo = ", cycle timeout is %u clockcycles" % timeout
        self.log.info("Wishbone Master created%s" % sTo)
        self.busy_event = Event("%s_busy" % name)
        self.busy = False
        self._timeout = timeout
        
    @coroutine 
    def _clk_cycle_counter(self):
        """
            Cycle counter to time bus operations
        """
        clkedge = RisingEdge(self.clock)
        self._clk_cycle_count = 0
        while self.busy:
            yield clkedge
            self._clk_cycle_count += 1    
  
    @coroutine
    def _open_cycle(self):
        #Open new wishbone cycle        
        if self.busy:
            self.log.error("Opening Cycle, but WB Driver is already busy. Someting's wrong")
            yield self.busy_event.wait()
        self.busy_event.clear()
        self.busy       = True
        cocotb.fork(self._read())
        cocotb.fork(self._clk_cycle_counter()) 
        self.bus.cyc    <= 1
        self._acked_ops = 0  
        self._res_buf   = [] 
        self._aux_buf   = []
        self.log.debug("Opening cycle, %u Ops" % self._op_cnt)
        
    @coroutine    
    def _close_cycle(self):
        #Close current wishbone cycle  
        clkedge = RisingEdge(self.clock)
        count           = 0
        last_acked_ops  = 0
        #Wait for all Operations being acknowledged by the slave before lowering the cycle line
        #This is not mandatory by the bus standard, but a crossbar might send acks to the wrong master
        #if we don't wait. We don't want to risk that, it could hang the bus
        while self._acked_ops < self._op_cnt:
            if last_acked_ops != self._acked_ops:
                self.log.debug("Waiting for missing acks: %u/%u" % (self._acked_ops, self._op_cnt) )
            last_acked_ops = self._acked_ops    
            #check for timeout when finishing the cycle            
            count += 1
            if (not (self._timeout is None)):
                if (count > self._timeout): 
                    raise TestFailure("Timeout of %u clock cycles reached when waiting for reply from slave" % self._timeout)                
            yield clkedge
            
        self.busy = False
        self.busy_event.set()
        self.bus.cyc <= 0 
        self.log.debug("Closing cycle")
        yield clkedge        

    
    @coroutine
    def _wait_stall(self):
        """Wait for stall to be low before continuing
        """
        clkedge = RisingEdge(self.clock)
        count = 0
        if hasattr(self.bus, "stall"):
            count = 0            
            while self.bus.stall.getvalue():
                yield clkedge
                count += 1
                if (not (self._timeout is None)):
                    if (count > self._timeout): 
                        raise TestFailure("Timeout of %u clock cycles reached when on stall from slave" % self._timeout)                
            self.log.debug("Stalled for %u cycles" % count)
        raise ReturnValue(count)
    
    
    @coroutine
    def _wait_ack(self):
        """Wait for ACK on the bus before continuing
        """
        #wait for acknownledgement before continuing - Classic Wishbone without pipelining
        clkedge = RisingEdge(self.clock)
        count = 0
        if not hasattr(self.bus, "stall"):
            while not self._get_reply():
                yield clkedge
                count += 1
            self.log.debug("Waited %u cycles for ackknowledge" % count)
        raise ReturnValue(count)    
    
    
    def _get_reply(self):
        #helper function for slave acks
        tmpAck = int(self.bus.ack.getvalue())
        tmpErr = 0
        tmpRty = 0
        if hasattr(self.bus, "err"):        
            tmpErr = int(self.bus.err.getvalue())
        if hasattr(self.bus, "rty"):        
            tmpRty = int(self.bus.rty.getvalue())
        #check if more than one line was raised    
        if ((tmpAck + tmpErr + tmpRty)  > 1):
            raise TestFailure("Slave raised more than one reply line at once! ACK: %u ERR: %u RTY: %u" % (tmpAck, tmpErr, tmpRty))
        #return 0 if no reply, 1 for ACK, 2 for ERR, 3 for RTY. use 'replyTypes' Dict for lookup
        return (tmpAck + 2 * tmpErr + 3 * tmpRty)
        
    
    @coroutine 
    def _read(self):
        """
            Reader for slave replies
        """
        count = 0
        clkedge = RisingEdge(self.clock)
        while self.busy:
            reply = self._get_reply()    
            # valid reply?            
            if(bool(reply)):
                datrd = int(self.bus.datrd.getvalue())
                #append reply and meta info to result buffer
                tmpRes =  wbr(ack=reply, sel=None, adr=None, datrd=datrd, datwr=None, waitIdle=None, waitStall=None, waitAck=self._clk_cycle_count)               
                self._res_buf.append(tmpRes)
                self._acked_ops += 1
            yield clkedge
            count += 1    

    
    @coroutine
    def _drive(self, we, adr, datwr, sel, idle):
        """
            Drive the Wishbone Master Out Lines
        """
    
        clkedge = RisingEdge(self.clock)
        if self.busy:
            # insert requested idle cycles            
            if idle != None:
                idlecnt = idle
                while idlecnt > 0:
                    idlecnt -= 1
                    yield clkedge
            # drive outputs    
            self.bus.stb    <= 1
            self.bus.adr    <= adr
            self.bus.sel    <= sel
            self.bus.datwr  <= datwr
            self.bus.we     <= we
            yield clkedge
            #deal with flow control (pipelined wishbone)
            stalled = yield self._wait_stall()
            #append operation and meta info to auxiliary buffer
            self._aux_buf.append(wba(sel, adr, datwr, stalled, idle, self._clk_cycle_count))
            #reset strobe and write enable without advancing time
            self.bus.stb    <= 0
            self.bus.we     <= 0
            # non pipelined wishbone
            yield self._wait_ack()
        else:
           self.log.error("Cannot drive the Wishbone bus outside a cycle!")


  
    @coroutine
    def send_cycle(self, arg):
        """
            The main sending routine        
        
        Args:
            list(WishboneOperations)
            
        """
        cnt = 0
        clkedge = RisingEdge(self.clock)
        yield clkedge
        if is_sequence(arg):
            if len(arg) < 1:
                self.log.error("List contains no operations to carry out")
            else:
         
                self._op_cnt = len(arg)
                firstword = True
                for op in arg:
                    if firstword:
                        firstword = False
                        result = []
                        yield self._open_cycle()
                        
                    if op.dat != None:
                        we  = 1
                        dat = op.dat
                    else:
                        we  = 0
                        dat = 0
                    yield self._drive(we, op.adr, dat, op.sel, op.idle)
                    self.log.debug("#%3u WE: %s ADR: 0x%08x DAT: 0x%08x SEL: 0x%1x IDLE: %3u" % (cnt, we, op.adr, dat, op.sel, op.idle))
                    cnt += 1
                yield self._close_cycle()
                
                #do pick and mix from result- and auxiliary buffer so we get all operation and meta info
                for res, aux in zip(self._res_buf, self._aux_buf):
                    res.datwr       = aux.datwr
                    res.sel         = aux.sel
                    res.adr         = aux.adr
                    res.waitIdle    = aux.waitIdle
                    res.waitStall   = aux.waitStall
                    res.waitack    -= aux.ts
                    result.append(res)
                
            raise ReturnValue(result)
        else:
            self.log.error("Expecting a list")
            raise ReturnValue(None)    
Example #51
0
class AD9361(BusDriver):
    """Driver for the AD9361 RF Transceiver."""

    def __init__(self, dut, rx_channels=1, tx_channels=1,
                 tx_clock_half_period=16276, rx_clock_half_period=16276,
                 loopback_queue_maxlen=16):
        self.dut = dut
        self.tx_clock_half_period = tx_clock_half_period
        self.rx_clock_half_period = rx_clock_half_period
        self.rx_frame_asserted = False
        self.tx_frame_asserted = False
        self.lbqi = deque()
        self.lbqq = deque()
        cocotb.fork(self._rx_clock())
        self.got_tx = Event("Got tx event")

    @cocotb.coroutine
    def _rx_clock(self):
        t = Timer(self.rx_clock_half_period)
        while True:
            self.dut.rx_clk_in_p <= 1
            self.dut.rx_clk_in_n <= 0
            yield t
            self.dut.rx_clk_in_p <= 0
            self.dut.rx_clk_in_n <= 1
            yield t

    def send_data(self, i_data, q_data, i_data2=None, q_data2=None,
                  binaryRepresentation=BinaryRepresentation.TWOS_COMPLEMENT):
        """Forks the ``rx_data_to_ad9361`` coroutine to send data.

        Args:
            i_data (int): Data of the I0 channel.
            q_data (int): Data of the Q0 channel.
            i_data2 (int, optional): Data of the I1 channel.
            q_data2 (int, optional): Data of the Q1 channel.
            binaryRepresentation (BinaryRepresentation): The representation of the binary value.
                Default is :any:`TWOS_COMPLEMENT`.
        """
        print(binaryRepresentation)
        cocotb.fork(self.rx_data_to_ad9361(i_data, q_data, i_data2, q_data2,
                    binaryRepresentation))

    @cocotb.coroutine
    def rx_data_to_ad9361(self, i_data, q_data, i_data2=None, q_data2=None,
                          binaryRepresentation=BinaryRepresentation.TWOS_COMPLEMENT):
        """Receive data to AD9361.

        This is a coroutine.

        Args:
            i_data (int): Data of the I0 channel.
            q_data (int): Data of the Q0 channel.
            i_data2 (int, optional): Data of the I1 channel.
            q_data2 (int, optional): Data of the Q1 channel.
            binaryRepresentation (BinaryRepresentation): The representation of the binary value.
                Default is :any:`TWOS_COMPLEMENT`. 
       """
        i_bin_val = BinaryValue(n_bits=12, bigEndian=False,
                                binaryRepresentation=binaryRepresentation)
        q_bin_val = BinaryValue(n_bits=12, bigEndian=False,
                                binaryRepresentation=binaryRepresentation)
        index = 0
        if i_data2 is None and q_data2 is None:
            while True:
                yield RisingEdge(self.dut.rx_clk_in_p)
                if self.rx_frame_asserted:
                    self.dut.rx_data_in_p <= i_bin_val[5:0]
                    self.dut.rx_data_in_n <= ~i_bin_val[5:0]
                    self.rx_frame_asserted = False
                    self.dut.rx_frame_in_p <= 0
                    self.dut.rx_frame_in_n <= 1
                else:
                    if index < len(i_data):
                        i_bin_val.set_value(i_data[index])
                        q_bin_val.set_value(q_data[index])
                        index += 1
                    else:
                        return
                    self.dut.rx_data_in_p <= i_bin_val[11:6]
                    self.dut.rx_data_in_n <= ~i_bin_val[11:6]
                    self.rx_frame_asserted = True
                    self.dut.rx_frame_in_p <= 1
                    self.dut.rx_frame_in_n <= 0
                yield RisingEdge(self.dut.rx_clk_in_n)
                if self.rx_frame_asserted:
                    self.dut.rx_data_in_p <= q_bin_val[11:6]
                    self.dut.rx_data_in_n <= ~q_bin_val[11:6]
                else:
                    self.dut.rx_data_in_p <= q_bin_val[5:0]
                    self.dut.rx_data_in_n <= ~q_bin_val[5:0]
        else:
            I_SEND_HIGH = True
            Q_SEND_HIGH = True
            channel = 1
            while True:
                yield RisingEdge(self.dut.rx_clk_in_p)
                if I_SEND_HIGH:
                    self.dut.rx_data_in_p <= i_bin_val[11:6]
                    self.dut.rx_data_in_n <= ~i_bin_val[11:6]
                    I_SEND_HIGH = False
                    if channel == 1:
                        self.dut.rx_frame_in_p <= 1
                        self.dut.rx_frame_in_n <= 0
                    elif channel == 2:
                        self.dut.rx_frame_in_p <= 0
                        self.dut.rx_frame_in_n <= 1
                else:
                    self.dut.rx_data_in_p <= i_bin_val[5:0]
                    self.dut.rx_data_in_n <= ~i_bin_val[5:0]
                    I_SEND_HIGH = True
                yield RisingEdge(self.dut.rx_clk_in_n)
                if Q_SEND_HIGH:
                    self.dut.rx_data_in_p <= q_bin_val[5:0]
                    self.dut.rx_data_in_n <= ~q_bin_val[5:0]
                    Q_SEND_HIGH = False
                else:
                    self.dut.rx_data_in_p <= q_bin_val[11:6]
                    self.dut.rx_data_in_n <= ~q_bin_val[11:6]
                    Q_SEND_HIGH = True
                    if index < len(i_data):
                        if channel == 1:
                            i_bin_val.set_value(i_data[index])
                            q_bin_val.set_value(q_data[index])
                            channel = 2
                        elif channel == 2:
                            i_bin_val.set_value(i_data2[index])
                            q_bin_val.set_value(q_data2[index])
                            channel = 1
                            index += 1
                    else:
                        return

    @cocotb.coroutine
    def _tx_data_from_ad9361(self):
        i_bin_val = BinaryValue(n_bits=12, bigEndian=False)
        q_bin_val = BinaryValue(n_bits=12, bigEndian=False)
        while True:
            yield RisingEdge(self.dut.tx_clk_out_p)
            if self.dut.tx_frame_out_p.value.integer == 1:
                q_bin_val[11:6] = self.dut.tx_data_out_p.value.get_binstr()
            else:
                q_bin_val[5:0] = self.dut.tx_data_out_p.value.get_binstr()
            yield RisingEdge(self.dut.tx_clk_out_n)
            if self.dut.tx_frame_out_p.value.integer == 1:
                i_bin_val[11:6] = self.dut.tx_data_out_p.value.get_binstr()
            else:
                i_bin_val[5:0] = self.dut.tx_data_out_p.value.get_binstr()
                # print("i_data",i_bin_val.get_value())
                # print("q_data",q_bin_val.get_value())
                self.lbqi.append(i_bin_val)
                self.lbqq.append(q_bin_val)
                self.got_tx.set([i_bin_val, q_bin_val])

    @cocotb.coroutine
    def _ad9361_tx_to_rx_loopback(self):
        cocotb.fork(self._tx_data_from_ad9361())
        i_bin_val = BinaryValue(n_bits=12, bigEndian=False)
        q_bin_val = BinaryValue(n_bits=12, bigEndian=False)
        while True:
            yield RisingEdge(self.dut.rx_clk_in_p)
            if self.rx_frame_asserted:
                self.dut.rx_data_in_p <= i_bin_val[5:0]
                self.dut.rx_data_in_n <= ~i_bin_val[5:0]
                self.rx_frame_asserted = False
                self.dut.rx_frame_in_p <= 0
                self.dut.rx_frame_in_n <= 1
            else:
                if len(self.lbqi) > 0:
                    i_bin_val = self.lbqi.popleft()
                else:
                    i_bin_val.set_value(0)
                if len(self.lbqq) > 0:
                    q_bin_val = self.lbqq.popleft()
                else:
                    q_bin_val.set_value(0)
                self.dut.rx_data_in_p <= i_bin_val[11:6]
                self.dut.rx_data_in_n <= ~i_bin_val[11:6]
                self.rx_frame_asserted = True
                self.dut.rx_frame_in_p <= 1
                self.dut.rx_frame_in_n <= 0
            yield RisingEdge(self.dut.rx_clk_in_n)
            if self.rx_frame_asserted:
                self.dut.rx_data_in_p <= q_bin_val[11:6]
                self.dut.rx_data_in_n <= ~q_bin_val[11:6]
            else:
                self.dut.rx_data_in_p <= q_bin_val[5:0]
                self.dut.rx_data_in_n <= ~q_bin_val[5:0]

    def ad9361_tx_to_rx_loopback(self):
        """Create loopback from tx to rx.

        Forks a coroutine doing the actual task.
        """
        cocotb.fork(self._ad9361_tx_to_rx_loopback())

    def tx_data_from_ad9361(self):
        """Transmit data from AD9361.

        Forks a coroutine doing the actual task.
        """
        cocotb.fork(self._tx_data_from_ad9361())
Example #52
0
class Driver(object):
    """Class defining the standard interface for a driver within a testbench.

    The driver is responsible for serialising transactions onto the physical
    pins of the interface.  This may consume simulation time.
    """
    def __init__(self):
        """Constructor for a driver instance."""
        self._pending = Event(name="Driver._pending")
        self._sendQ = deque()

        # Subclasses may already set up logging
        if not hasattr(self, "log"):
            self.log = SimLog("cocotb.driver.%s" % (self.__class__.__name__))

        # Create an independent coroutine which can send stuff
        self._thread = cocotb.scheduler.add(self._send_thread())

    def kill(self):
        """Kill the coroutine sending stuff."""
        if self._thread:
            self._thread.kill()
            self._thread = None

    def append(self, transaction, callback=None, event=None, **kwargs):
        """Queue up a transaction to be sent over the bus.

        Mechanisms are provided to permit the caller to know when the
        transaction is processed.

        Args:
            transaction (any): The transaction to be sent.
            callback (callable, optional): Optional function to be called 
                when the transaction has been sent.
            event (optional): :class:`~cocotb.triggers.Event` to be set
                when the transaction has been sent.
            **kwargs: Any additional arguments used in child class' 
                :any:`_driver_send` method.
        """
        self._sendQ.append((transaction, callback, event, kwargs))
        self._pending.set()

    def clear(self):
        """Clear any queued transactions without sending them onto the bus."""
        self._sendQ = deque()

    @coroutine
    def send(self, transaction, sync=True, **kwargs):
        """Blocking send call (hence must be "yielded" rather than called).

        Sends the transaction over the bus.

        Args:
            transaction (any): The transaction to be sent.
            sync (bool, optional): Synchronise the transfer by waiting for a rising edge.
            **kwargs (dict): Additional arguments used in child class'
                :any:`_driver_send` method.
        """
        yield self._send(transaction, None, None, sync=sync, **kwargs)

    def _driver_send(self, transaction, sync=True, **kwargs):
        """Actual implementation of the send.

        Subclasses should override this method to implement the actual 
        :meth:`~cocotb.drivers.Driver.send` routine.

        Args:
            transaction (any): The transaction to be sent.
            sync (boolean, optional): Synchronise the transfer by waiting for a rising edge.
            **kwargs: Additional arguments if required for protocol implemented in subclass.
        """
        raise NotImplementedError("Subclasses of Driver should define a "
                                  "_driver_send coroutine")

    @coroutine
    def _send(self, transaction, callback, event, sync=True, **kwargs):
        """Send coroutine.

        Args:
            transaction (any): The transaction to be sent.
            callback (callable, optional): Optional function to be called 
                when the transaction has been sent.
            event (optional): event to be set when the transaction has been sent.
            sync (boolean, optional): Synchronise the transfer by waiting for a rising edge.
            **kwargs: Any additional arguments used in child class' 
                :any:`_driver_send` method.
        """
        yield self._driver_send(transaction, sync=sync, **kwargs)

        # Notify the world that this transaction is complete
        if event:
            event.set()
        if callback:
            callback(transaction)

    @coroutine
    def _send_thread(self):
        while True:

            # Sleep until we have something to send
            while not self._sendQ:
                self._pending.clear()
                yield self._pending.wait()

            synchronised = False

            # Send in all the queued packets,
            # only synchronise on the first send
            while self._sendQ:
                transaction, callback, event, kwargs = self._sendQ.popleft()
                self.log.debug("Sending queued packet...")
                yield self._send(transaction, callback, event,
                                 sync=not synchronised, **kwargs)
                synchronised = True
Example #53
0
class AD9361(BusDriver):
    '''
    classdocs
    '''

    def __init__(self, dut, rx_channels=1, tx_channels=1,
                 tx_clock_half_period=16276, rx_clock_half_period=16276,
                 loopback_queue_maxlen=16):
        '''
        Constructor
        '''
        self.dut = dut
        self.tx_clock_half_period = tx_clock_half_period
        self.rx_clock_half_period = rx_clock_half_period
        self.rx_frame_asserted = False
        self.tx_frame_asserted = False
        self.lbqi = deque()
        self.lbqq = deque()
        cocotb.fork(self._rx_clock())
        self.got_tx = Event("Got tx event")

    @cocotb.coroutine
    def _rx_clock(self):
        t = Timer(self.rx_clock_half_period)
        while True:
            self.dut.rx_clk_in_p <= 1
            self.dut.rx_clk_in_n <= 0
            yield t
            self.dut.rx_clk_in_p <= 0
            self.dut.rx_clk_in_n <= 1
            yield t

    def send_data(self, i_data, q_data, i_data2=None, q_data2=None,
                  binaryRepresentation=BinaryRepresentation.TWOS_COMPLEMENT):
        print binaryRepresentation
        cocotb.fork(self.rx_data_to_ad9361(i_data, q_data, i_data2, q_data2,
                    binaryRepresentation))

    @cocotb.coroutine
    def rx_data_to_ad9361(self, i_data, q_data, i_data2=None, q_data2=None,
                          binaryRepresentation=BinaryRepresentation.TWOS_COMPLEMENT):
        i_bin_val = BinaryValue(bits=12, bigEndian=False,
                                binaryRepresentation=binaryRepresentation)
        q_bin_val = BinaryValue(bits=12, bigEndian=False,
                                binaryRepresentation=binaryRepresentation)
        index = 0
        if i_data2 is None and q_data2 is None:
            while True:
                yield RisingEdge(self.dut.rx_clk_in_p)
                if self.rx_frame_asserted:
                    self.dut.rx_data_in_p <= i_bin_val[5:0]
                    self.dut.rx_data_in_n <= ~i_bin_val[5:0]
                    self.rx_frame_asserted = False
                    self.dut.rx_frame_in_p <= 0
                    self.dut.rx_frame_in_n <= 1
                else:
                    if index < len(i_data):
                        i_bin_val.set_value(i_data[index])
                        q_bin_val.set_value(q_data[index])
                        index += 1
                    else:
                        return
                    self.dut.rx_data_in_p <= i_bin_val[11:6]
                    self.dut.rx_data_in_n <= ~i_bin_val[11:6]
                    self.rx_frame_asserted = True
                    self.dut.rx_frame_in_p <= 1
                    self.dut.rx_frame_in_n <= 0
                yield RisingEdge(self.dut.rx_clk_in_n)
                if self.rx_frame_asserted:
                    self.dut.rx_data_in_p <= q_bin_val[11:6]
                    self.dut.rx_data_in_n <= ~q_bin_val[11:6]
                else:
                    self.dut.rx_data_in_p <= q_bin_val[5:0]
                    self.dut.rx_data_in_n <= ~q_bin_val[5:0]
        else:
            I_SEND_HIGH = True
            Q_SEND_HIGH = True
            channel = 1
            while True:
                yield RisingEdge(self.dut.rx_clk_in_p)
                if I_SEND_HIGH:
                    self.dut.rx_data_in_p <= i_bin_val[11:6]
                    self.dut.rx_data_in_n <= ~i_bin_val[11:6]
                    I_SEND_HIGH = False
                    if channel == 1:
                        self.dut.rx_frame_in_p <= 1
                        self.dut.rx_frame_in_n <= 0
                    elif channel == 2:
                        self.dut.rx_frame_in_p <= 0
                        self.dut.rx_frame_in_n <= 1
                else:
                    self.dut.rx_data_in_p <= i_bin_val[5:0]
                    self.dut.rx_data_in_n <= ~i_bin_val[5:0]
                    I_SEND_HIGH = True
                yield RisingEdge(self.dut.rx_clk_in_n)
                if Q_SEND_HIGH:
                    self.dut.rx_data_in_p <= q_bin_val[5:0]
                    self.dut.rx_data_in_n <= ~q_bin_val[5:0]
                    Q_SEND_HIGH = False
                else:
                    self.dut.rx_data_in_p <= q_bin_val[11:6]
                    self.dut.rx_data_in_n <= ~q_bin_val[11:6]
                    Q_SEND_HIGH = True
                    if index < len(i_data):
                        if channel == 1:
                            i_bin_val.set_value(i_data[index])
                            q_bin_val.set_value(q_data[index])
                            channel = 2
                        elif channel == 2:
                            i_bin_val.set_value(i_data2[index])
                            q_bin_val.set_value(q_data2[index])
                            channel = 1
                            index += 1
                    else:
                        return

    @cocotb.coroutine
    def _tx_data_from_ad9361(self):
        i_bin_val = BinaryValue(bits=12, bigEndian=False)
        q_bin_val = BinaryValue(bits=12, bigEndian=False)
        while True:
            yield RisingEdge(self.dut.tx_clk_out_p)
            if self.dut.tx_frame_out_p.value.integer == 1:
                q_bin_val[11:6] = self.dut.tx_data_out_p.value.get_binstr()
            else:
                q_bin_val[5:0] = self.dut.tx_data_out_p.value.get_binstr()
            yield RisingEdge(self.dut.tx_clk_out_n)
            if self.dut.tx_frame_out_p.value.integer == 1:
                i_bin_val[11:6] = self.dut.tx_data_out_p.value.get_binstr()
            else:
                i_bin_val[5:0] = self.dut.tx_data_out_p.value.get_binstr()
                # print "i_data",i_bin_val.get_value()
                # print "q_data",q_bin_val.get_value()
                self.lbqi.append(i_bin_val)
                self.lbqq.append(q_bin_val)
                self.got_tx.set([i_bin_val, q_bin_val])

    @cocotb.coroutine
    def _ad9361_tx_to_rx_loopback(self):
        cocotb.fork(self._tx_data_from_ad9361())
        i_bin_val = BinaryValue(bits=12, bigEndian=False)
        q_bin_val = BinaryValue(bits=12, bigEndian=False)
        while True:
            yield RisingEdge(self.dut.rx_clk_in_p)
            if self.rx_frame_asserted:
                self.dut.rx_data_in_p <= i_bin_val[5:0]
                self.dut.rx_data_in_n <= ~i_bin_val[5:0]
                self.rx_frame_asserted = False
                self.dut.rx_frame_in_p <= 0
                self.dut.rx_frame_in_n <= 1
            else:
                if len(self.lbqi) > 0:
                    i_bin_val = self.lbqi.popleft()
                else:
                    i_bin_val.set_value(0)
                if len(self.lbqq) > 0:
                    q_bin_val = self.lbqq.popleft()
                else:
                    q_bin_val.set_value(0)
                self.dut.rx_data_in_p <= i_bin_val[11:6]
                self.dut.rx_data_in_n <= ~i_bin_val[11:6]
                self.rx_frame_asserted = True
                self.dut.rx_frame_in_p <= 1
                self.dut.rx_frame_in_n <= 0
            yield RisingEdge(self.dut.rx_clk_in_n)
            if self.rx_frame_asserted:
                self.dut.rx_data_in_p <= q_bin_val[11:6]
                self.dut.rx_data_in_n <= ~q_bin_val[11:6]
            else:
                self.dut.rx_data_in_p <= q_bin_val[5:0]
                self.dut.rx_data_in_n <= ~q_bin_val[5:0]

    def ad9361_tx_to_rx_loopback(self):
        cocotb.fork(self._ad9361_tx_to_rx_loopback())

    def tx_data_from_ad9361(self):
        cocotb.fork(self._tx_data_from_ad9361())
Example #54
0
class Scheduler(object):
    """The main scheduler.

    Here we accept callbacks from the simulator and schedule the appropriate
    coroutines.

    A callback fires, causing the :any:`react` method to be called, with the
    trigger that caused the callback as the first argument.

    We look up a list of coroutines to schedule (indexed by the trigger) and
    schedule them in turn. NB implementors should not depend on the scheduling
    order!

    Some additional management is required since coroutines can return a list
    of triggers, to be scheduled when any one of the triggers fires.  To
    ensure we don't receive spurious callbacks, we have to un-prime all the
    other triggers when any one fires.

    Due to the simulator nuances and fun with delta delays we have the
    following modes:

    Normal mode
        - Callbacks cause coroutines to be scheduled
        - Any pending writes are cached and do not happen immediately

    ReadOnly mode
        - Corresponds to cbReadOnlySynch (VPI) or vhpiCbLastKnownDeltaCycle
          (VHPI).  In this state we are not allowed to perform writes.

    Write mode
        - Corresponds to cbReadWriteSynch (VPI) or vhpiCbEndOfProcesses (VHPI)
          In this mode we play back all the cached write updates.

    We can legally transition from normal->write by registering a ReadWrite
    callback, however usually once a simulator has entered the ReadOnly phase
    of a given timestep then we must move to a new timestep before performing
    any writes.  The mechanism for moving to a new timestep may not be
    consistent across simulators and therefore we provide an abstraction to
    assist with compatibility.


    Unless a coroutine has explicitly requested to be scheduled in ReadOnly
    mode (for example wanting to sample the finally settled value after all
    delta delays) then it can reasonably be expected to be scheduled during
    "normal mode" i.e. where writes are permitted.
    """

    _MODE_NORMAL   = 1  # noqa
    _MODE_READONLY = 2  # noqa
    _MODE_WRITE    = 3  # noqa
    _MODE_TERM     = 4  # noqa

    # Singleton events, recycled to avoid spurious object creation
    _readonly = ReadOnly()
    _timer1 = Timer(1)

    def __init__(self):

        self.log = SimLog("cocotb.scheduler")
        if _debug:
            self.log.setLevel(logging.DEBUG)

        # Use OrderedDict here for deterministic behavior (gh-934)

        # A dictionary of pending coroutines for each trigger,
        # indexed by trigger
        self._trigger2coros = collections.OrderedDict()

        # A dictionary mapping coroutines to the trigger they are waiting for
        self._coro2trigger = collections.OrderedDict()

        # Our main state
        self._mode = Scheduler._MODE_NORMAL

        # A dictionary of pending writes
        self._writes = collections.OrderedDict()

        self._pending_coros = []
        self._pending_triggers = []
        self._pending_threads = []
        self._pending_events = []   # Events we need to call set on once we've unwound

        self._terminate = False
        self._test_result = None
        self._entrypoint = None
        self._main_thread = threading.current_thread()

        self._is_reacting = False

        self._write_coro_inst = None
        self._writes_pending = Event()

    @cocotb.decorators.coroutine
    def _do_writes(self):
        """ An internal coroutine that performs pending writes """
        while True:
            yield self._writes_pending.wait()
            if self._mode != Scheduler._MODE_NORMAL:
                yield NextTimeStep()

            yield ReadWrite()

            while self._writes:
                handle, value = self._writes.popitem()
                handle.setimmediatevalue(value)
            self._writes_pending.clear()

    def _check_termination(self):
        """
        Handle a termination that causes us to move onto the next test.
        """
        if self._terminate:
            if _debug:
                self.log.debug("Test terminating, scheduling Timer")

            if self._write_coro_inst is not None:
                self._write_coro_inst.kill()
                self._write_coro_inst = None

            for t in self._trigger2coros:
                t.unprime()

            if self._timer1.primed:
                self._timer1.unprime()

            self._timer1.prime(self.begin_test)
            self._trigger2coros = collections.OrderedDict()
            self._coro2trigger = collections.OrderedDict()
            self._terminate = False
            self._writes = collections.OrderedDict()
            self._writes_pending.clear()
            self._mode = Scheduler._MODE_TERM

    def begin_test(self, trigger=None):
        """Called to initiate a test.

        Could be called on start-up or from a callback.
        """
        if _debug:
            self.log.debug("begin_test called with trigger: %s" %
                           (str(trigger)))
        if _profiling:
            ps = pstats.Stats(_profile).sort_stats('cumulative')
            ps.dump_stats("test_profile.pstat")
            ctx = profiling_context()
        else:
            ctx = nullcontext()

        with ctx:
            self._mode = Scheduler._MODE_NORMAL
            if trigger is not None:
                trigger.unprime()

            # Issue previous test result, if there is one
            if self._test_result is not None:
                if _debug:
                    self.log.debug("Issue test result to regression object")
                cocotb.regression_manager.handle_result(self._test_result)
                self._test_result = None
            if self._entrypoint is not None:
                test = self._entrypoint
                self._entrypoint = None
                self.schedule(test)
                self._check_termination()

    def react(self, trigger):
        """
        Called when a trigger fires.

        We ensure that we only start the event loop once, rather than
        letting it recurse.
        """
        if self._is_reacting:
            # queue up the trigger, the event loop will get to it
            self._pending_triggers.append(trigger)
            return

        assert not self._pending_triggers

        # start the event loop
        self._is_reacting = True
        try:
            self._event_loop(trigger)
        finally:
            self._is_reacting = False


    def _event_loop(self, trigger):
        """
        Run an event loop triggered by the given trigger.

        The loop will keep running until no further triggers fire.

        This should be triggered by only:
        * The beginning of a test, when there is no trigger to react to
        * A GPI trigger
        """
        if _profiling:
            ctx = profiling_context()
        else:
            ctx = nullcontext()

        with ctx:
            # When a trigger fires it is unprimed internally
            if _debug:
                self.log.debug("Trigger fired: %s" % str(trigger))
            # trigger.unprime()

            if self._mode == Scheduler._MODE_TERM:
                if _debug:
                    self.log.debug("Ignoring trigger %s since we're terminating" %
                                   str(trigger))
                return

            if trigger is self._readonly:
                self._mode = Scheduler._MODE_READONLY
            # Only GPI triggers affect the simulator scheduling mode
            elif isinstance(trigger, GPITrigger):
                self._mode = Scheduler._MODE_NORMAL

            # work through triggers one by one
            is_first = True
            self._pending_triggers.append(trigger)
            while self._pending_triggers:
                trigger = self._pending_triggers.pop(0)

                if not is_first and isinstance(trigger, GPITrigger):
                    self.log.warning(
                        "A GPI trigger occurred after entering react - this "
                        "should not happen."
                    )
                    assert False

                # this only exists to enable the warning above
                is_first = False

                if trigger not in self._trigger2coros:

                    # GPI triggers should only be ever pending if there is an
                    # associated coroutine waiting on that trigger, otherwise it would
                    # have been unprimed already
                    if isinstance(trigger, GPITrigger):
                        self.log.critical(
                            "No coroutines waiting on trigger that fired: %s" %
                            str(trigger))

                        trigger.log.info("I'm the culprit")
                    # For Python triggers this isn't actually an error - we might do
                    # event.set() without knowing whether any coroutines are actually
                    # waiting on this event, for example
                    elif _debug:
                        self.log.debug(
                            "No coroutines waiting on trigger that fired: %s" %
                            str(trigger))

                    continue

                # Scheduled coroutines may append to our waiting list so the first
                # thing to do is pop all entries waiting on this trigger.
                scheduling = self._trigger2coros.pop(trigger)

                if _debug:
                    debugstr = "\n\t".join([coro.__name__ for coro in scheduling])
                    if len(scheduling):
                        debugstr = "\n\t" + debugstr
                    self.log.debug("%d pending coroutines for event %s%s" %
                                   (len(scheduling), str(trigger), debugstr))

                # This trigger isn't needed any more
                trigger.unprime()

                for coro in scheduling:
                    if _debug:
                        self.log.debug("Scheduling coroutine %s" % (coro.__name__))
                    self.schedule(coro, trigger=trigger)
                    if _debug:
                        self.log.debug("Scheduled coroutine %s" % (coro.__name__))

                # Schedule may have queued up some events so we'll burn through those
                while self._pending_events:
                    if _debug:
                        self.log.debug("Scheduling pending event %s" %
                                       (str(self._pending_events[0])))
                    self._pending_events.pop(0).set()

            # no more pending triggers
            self._check_termination()
            if _debug:
                self.log.debug("All coroutines scheduled, handing control back"
                               " to simulator")


    def unschedule(self, coro):
        """Unschedule a coroutine.  Unprime any pending triggers"""

        # Unprime the trigger this coroutine is waiting on
        try:
            trigger = self._coro2trigger.pop(coro)
        except KeyError:
            # coroutine probably finished
            pass
        else:
            if coro in self._trigger2coros.setdefault(trigger, []):
                self._trigger2coros[trigger].remove(coro)
            if not self._trigger2coros[trigger]:
                trigger.unprime()
                del self._trigger2coros[trigger]

        if Join(coro) in self._trigger2coros:
            self.react(Join(coro))
        else:
            try:
                # throws an error if the background coroutine errored
                # and no one was monitoring it
                coro.retval
            except TestComplete as test_result:
                self.log.debug("TestComplete received: {}".format(test_result.__class__.__name__))
                self.finish_test(test_result)
            except Exception as e:
                self.finish_test(create_error(self, "Forked coroutine {} raised exception: {}".format(coro, e)))

    def save_write(self, handle, value):
        if self._mode == Scheduler._MODE_READONLY:
            raise Exception("Write to object {0} was scheduled during a read-only sync phase.".format(handle._name))

        # TODO: we should be able to better keep track of when this needs to
        # be scheduled
        if self._write_coro_inst is None:
            self._write_coro_inst = self._do_writes()
            self.schedule(self._write_coro_inst)

        self._writes[handle] = value
        self._writes_pending.set()

    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:
            try:
                trigger.prime(self.react)
            except Exception as e:
                # Convert any exceptions into a test result
                self.finish_test(
                    create_error(self, "Unable to prime trigger %s: %s" %
                                 (str(trigger), str(e))))

    def queue(self, coroutine):
        """Queue a coroutine for execution"""
        self._pending_coros.append(coroutine)

    def queue_function(self, coroutine):
        """Queue a coroutine for execution and move the containing thread
        so that it does not block execution of the main thread any longer.
        """
        # We should be able to find ourselves inside the _pending_threads list
        matching_threads = [
            t
            for t in self._pending_threads
            if t.thread == threading.current_thread()
        ]
        if len(matching_threads) == 0:
            raise RuntimeError("queue_function called from unrecognized thread")

        # Raises if there is more than one match. This can never happen, since
        # each entry always has a unique thread.
        t, = matching_threads

        t.thread_suspend()
        self._pending_coros.append(coroutine)
        return t

    def run_in_executor(self, func, *args, **kwargs):
        """Run the coroutine in a separate execution thread
        and return a yieldable object for the caller.
        """
        # Create a thread
        # Create a trigger that is called as a result of the thread finishing
        # Create an Event object that the caller can yield on
        # Event object set when the thread finishes execution, this blocks the
        #   calling coroutine (but not the thread) until the external completes

        def execute_external(func, _waiter):
            _waiter._outcome = outcomes.capture(func, *args, **kwargs)
            if _debug:
                self.log.debug("Execution of external routine done %s" % threading.current_thread())
            _waiter.thread_done()

        waiter = external_waiter()
        thread = threading.Thread(group=None, target=execute_external,
                                  name=func.__name__ + "_thread",
                                  args=([func, waiter]), kwargs={})

        waiter.thread = thread
        self._pending_threads.append(waiter)

        return waiter

    def add(self, coroutine):
        """Add a new coroutine.

        Just a wrapper around self.schedule which provides some debug and
        useful error messages in the event of common gotchas.
        """
        if isinstance(coroutine, cocotb.decorators.coroutine):
            self.log.critical(
                "Attempt to schedule a coroutine that hasn't started")
            coroutine.log.error("This is the failing coroutine")
            self.log.warning(
                "Did you forget to add parentheses to the @test decorator?")
            self._test_result = TestError(
                "Attempt to schedule a coroutine that hasn't started")
            self._terminate = True
            return

        elif not isinstance(coroutine, cocotb.decorators.RunningCoroutine):
            self.log.critical(
                "Attempt to add something to the scheduler which isn't a "
                "coroutine")
            self.log.warning(
                "Got: %s (%s)" % (str(type(coroutine)), repr(coroutine)))
            self.log.warning("Did you use the @coroutine decorator?")
            self._test_result = TestError(
                "Attempt to schedule a coroutine that hasn't started")
            self._terminate = True
            return

        if _debug:
            self.log.debug("Adding new coroutine %s" % coroutine.__name__)

        self.schedule(coroutine)
        self._check_termination()
        return coroutine

    def new_test(self, coroutine):
        self._entrypoint = coroutine

    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

        # convert lists into `First` Waitables.
        if isinstance(result, list):
            result = cocotb.triggers.First(*result)

        # convert waitables into coroutines
        if isinstance(result, cocotb.triggers.Waitable):
            result = result._wait()

        # convert coroutinues into triggers
        if isinstance(result, cocotb.decorators.RunningCoroutine):
            if not result.has_started():
                self.queue(result)
                if _debug:
                    self.log.debug("Scheduling nested coroutine: %s" %
                                   result.__name__)
            else:
                if _debug:
                    self.log.debug("Joining to already running coroutine: %s" %
                                   result.__name__)

            result = result.join()

        if isinstance(result, Trigger):
            if _debug:
                self.log.debug("%s: is instance of Trigger" % result)
            self._coroutine_yielded(coroutine, result)

        else:
            msg = ("Coroutine %s yielded something the scheduler can't handle"
                   % str(coroutine))
            msg += ("\nGot type: %s repr: %s str: %s" %
                    (type(result), repr(result), str(result)))
            msg += "\nDid you forget to decorate with @cocotb.coroutine?"
            try:
                raise_error(self, msg)
            except Exception as e:
                self.finish_test(e)

        # 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 finish_test(self, test_result):
        """Cache the test result and set the terminate flag."""
        self.log.debug("finish_test called with %s" % (repr(test_result)))
        if not self._terminate:
            self._terminate = True
            self._test_result = test_result
            self.cleanup()

    def finish_scheduler(self, test_result):
        """Directly call into the regression manager and end test
           once we return the sim will close us so no cleanup is needed.
        """
        self.log.debug("Issue sim closedown result to regression object")
        cocotb.regression_manager.handle_result(test_result)

    def cleanup(self):
        """Clear up all our state.

        Unprime all pending triggers and kill off any coroutines stop all externals.
        """
        # copy since we modify this in kill
        items = list(self._trigger2coros.items())

        # reversing seems to fix gh-928, although the order is still somewhat
        # arbitrary.
        for trigger, waiting in items[::-1]:
            for coro in waiting:
                if _debug:
                    self.log.debug("Killing %s" % str(coro))
                coro.kill()

        if self._main_thread is not threading.current_thread():
            raise Exception("Cleanup() called outside of the main thread")

        for ext in self._pending_threads:
            self.log.warn("Waiting for %s to exit", ext.thread)
Example #55
0
class I2CSlaveModelHAL:


    def __init__(self, helperMaster ): # initMemory = dict()):

        self.startEvent  = Event()
        self.stopEvent   = Event()
        self.dataRxEvent = Event()
        self.dataTXEvent = Event()

        self.sda_rd      = helperMaster.io.sda_wr
        self.sda_wr      = helperMaster.io.sda_rd
        self.scl_rd      = helperMaster.io.scl_wr
        self.scl_wr      = helperMaster.io.scl_rd

        self.resetn      = helperMaster.io.resetn
        self.clk         = helperMaster.io.clk

        self.sda         = 1
        self.scl         = 1


    ##########################################################################
    # Launch all slave process
    @cocotb.coroutine
    def startSlave(self,listOperations):

        yield RisingEdge(self.clk)

        self.fork_drain = cocotb.fork(self._manageSDA())
        self.fork_start = cocotb.fork(self._startDetection())
        self.fork_stop  = cocotb.fork(self._stopDetection())
        cocotb.fork(self._runSlave(listOperations))


    ##########################################################################
    # Stop all processes
    def stop(self):
        self.fork_drain.kill()
        self.fork_start.kill()
        self.fork_stop.kill()


    ##########################################################################
    # Slave simulation
    @cocotb.coroutine
    def _runSlave(self, listOperations):

        for index in range(0,len(listOperations)):

            operation = listOperations[index]

            if isinstance(operation, START):
                if index != 0:
                    yield FallingEdge(self.scl_wr)
                    yield FallingEdge(self.scl_wr)
                else:
                    yield FallingEdge(self.scl_wr)


            elif isinstance(operation, WRITE):
                yield self._writeData(operation.enCollision)

            elif isinstance(operation, READ):
                yield self._readData(operation.data)

            elif isinstance(operation, ACK):
                prevOperation = listOperations[index-1]

                self.sda = 0 if isinstance(prevOperation, WRITE) else 1
                yield FallingEdge(self.scl_rd)
                self.sda = 1

            elif isinstance(operation, ACK):

                self.sda = 1
                yield FallingEdge(self.scl_wr)
                self.sda = 1

            elif isinstance(operation, STOP):
                pass





    ##########################################################################
    # Simulate an open drain pin
    @cocotb.coroutine
    def _manageSDA(self):
        while True:
            yield RisingEdge(self.clk)

            if int(self.sda_rd) == 0:
                self.sda_wr <= 0
            else:
                self.sda_wr <= self.sda


            if int(self.scl_rd) == 0 :
                self.scl_wr <= 0
            else:
                self.scl_wr <= self.scl



    ##########################################################################
    # Detect the start/restart sequence
    @cocotb.coroutine
    def _startDetection(self):
        while True:
            yield RisingEdge(self.clk)
            prev = int(self.sda_rd)
            yield RisingEdge(self.clk)
            if prev == 1 and int(self.sda_rd) == 0:
                if int(self.scl_rd) == 1:
                    self.startEvent.set()


    ##########################################################################
    # Detect the stop sequence
    @cocotb.coroutine
    def _stopDetection(self):
        while True:
            yield RisingEdge(self.clk)
            prev = int(self.sda_rd)
            yield RisingEdge(self.clk)
            if prev == 0 and int(self.sda_rd) == 1:
                if int(self.scl_rd) == 1:
                    self.stopEvent.set()


    ##########################################################################
    # Read a data comming from the master
    @cocotb.coroutine
    def _writeData(self, enCollision):
        cnt  = 0
        dataRead = list()
        while True:
            if (cnt == 8):
                yield FallingEdge(self.scl_wr)
                dataInt = int("".join([str(x) for x in dataRead]), 2)
                self.dataTXEvent.set(data= dataInt )

                break
            else:
                if enCollision == True:
                    yield FallingEdge(self.scl_wr)
                    if int(self.sda_wr) == 1:
                        self.sda = 0
                yield RisingEdge(self.scl_wr)
                dataRead.append( int(self.sda_wr) )


            cnt += 1

    ##########################################################################
    # Write a data to the master
    @cocotb.coroutine
    def _readData(self, data):

        write = True
        cnt   = 0
        data2Send = bin(data)[2:].zfill(8)

        self.sda = int(data2Send[0])
        cnt += 1

        while write:
            yield FallingEdge(self.scl_rd)
            self.sda = int(data2Send[cnt])

            if (cnt == 7):

                result = dict()
                result["data"] = int("".join([str(x) for x in data2Send]), 2)
                result["ack"]  = int(self.sda_rd)

                self.dataRxEvent.set(result)

                yield FallingEdge(self.scl_rd)
                self.sda = 1


                break

            cnt += 1
Example #56
0
class Monitor(object):
    """Base class for Monitor objects. 

    Monitors are passive 'listening' objects that monitor pins going in or out of a DUT. 
    This class should not be used
    directly, but should be subclassed and the internal :any:`_monitor_recv` method
    should be overridden and decorated as a :any:`coroutine`.  This :any:`_monitor_recv`
    method should capture some behavior of the pins, form a transaction, and
    pass this transaction to the internal :any:`_recv` method.  The :any:`_monitor_recv`
    method is added to the cocotb scheduler during the ``__init__`` phase, so it
    should not be yielded anywhere.

    The primary use of a Monitor is as an interface for a
    :class:`~cocotb.scoreboard.Scoreboard`.

    Args:
        callback (callable): Callback to be called with each recovered transaction 
            as the argument. If the callback isn't used, received transactions will 
            be placed on a queue and the event used to notify any consumers.
        event (event): Object that supports a ``set`` method that will be called when
            a transaction is received through the internal :any:`_recv` method.
    """

    def __init__(self, callback=None, event=None):
        self._event = event
        self._wait_event = None
        self._recvQ = deque()
        self._callbacks = []
        self.stats = MonitorStatistics()
        self._wait_event = Event()

        # Subclasses may already set up logging
        if not hasattr(self, "log"):
            self.log = SimLog("cocotb.monitor.%s" % (self.__class__.__name__))

        if callback is not None:
            self.add_callback(callback)

        # Create an independent coroutine which can receive stuff
        self._thread = cocotb.scheduler.add(self._monitor_recv())

    def kill(self):
        """Kill the monitor coroutine."""
        if self._thread:
            self._thread.kill()
            self._thread = None

    def __len__(self):
        return len(self._recvQ)

    def __getitem__(self, idx):
        return self._recvQ[idx]

    def add_callback(self, callback):
        """Add function as a callback.

        Args:
            callback (callable): The function to call back.
        """
        self.log.debug("Adding callback of function %s to monitor" %
                       (callback.__name__))
        self._callbacks.append(callback)

    @coroutine
    def wait_for_recv(self, timeout=None):
        """With *timeout*, :meth:`.wait` for transaction to arrive on monitor 
        and return its data.

        Args:
            timeout (optional): The timeout value for :class:`~.triggers.Timer`.
                Defaults to ``None``.

        Returns: Data of received transaction.
        """
        if timeout:
            t = Timer(timeout)
            fired = yield [self._wait_event.wait(), t]
            if fired is t:
                raise ReturnValue(None)
        else:
            yield self._wait_event.wait()

        pkt = self._wait_event.data
        raise ReturnValue(pkt)

    @coroutine
    def _monitor_recv(self):
        """Actual implementation of the receiver.

        Subclasses should override this method to implement the actual receive
        routine and call :any:`_recv` with the recovered transaction.
        """
        raise NotImplementedError("Attempt to use base monitor class without "
                                  "providing a ``_monitor_recv`` method")

    def _recv(self, transaction):
        """Common handling of a received transaction."""

        self.stats.received_transactions += 1

        # either callback based consumer
        for callback in self._callbacks:
            callback(transaction)

        # Or queued with a notification
        if not self._callbacks:
            self._recvQ.append(transaction)

        if self._event is not None:
            self._event.set()

        # If anyone was waiting then let them know
        if self._wait_event is not None:
            self._wait_event.set(data=transaction)
            self._wait_event.clear()
Example #57
0
class AvalonMaster(AvalonMM):
    """Avalon-MM master
    """
    def __init__(self, entity, name, clock):
        AvalonMM.__init__(self, entity, name, clock)
        self.log.debug("AvalonMaster created")
        self.busy_event = Event("%s_busy" % name)
        self.busy = False

    def __len__(self):
        return 2**len(self.bus.address)

    @coroutine
    def _acquire_lock(self):
        if self.busy:
            yield self.busy_event.wait()
        self.busy_event.clear()
        self.busy = True

    def _release_lock(self):
        self.busy = False
        self.busy_event.set()

    @coroutine
    def read(self, address, sync=True):
        """
        Issue a request to the bus and block until this
        comes back. Simulation time still progresses
        but syntactically it blocks.
        See http://www.altera.com/literature/manual/mnl_avalon_spec_1_3.pdf
        """
        if not self._can_read:
            self.log.error("Cannot read - have no read signal")
            raise TestError("Attempt to read on a write-only AvalonMaster")

        yield self._acquire_lock()

        # Apply values for next clock edge
        if sync:
            yield RisingEdge(self.clock)
        self.bus.address <= address
        self.bus.read <= 1
        if hasattr(self.bus, "byteenable"):
            self.bus.byteenable <= int("1"*len(self.bus.byteenable), 2)
        if hasattr(self.bus, "cs"):
            self.bus.cs <= 1

        # Wait for waitrequest to be low
        if hasattr(self.bus, "waitrequest"):
            yield self._wait_for_nsignal(self.bus.waitrequest)
        yield RisingEdge(self.clock)
        # Get the data
        data = self.bus.readdata.value
        # Deassert read
        self.bus.read <= 0
        if hasattr(self.bus, "byteenable"):
            self.bus.byteenable <= 0
        if hasattr(self.bus, "cs"):
            self.bus.cs <= 0
        v = self.bus.address.value
        v.binstr = "x" * len(self.bus.address)
        self.bus.address <= v

        if hasattr(self.bus, "readdatavalid"):
            while True:
                yield ReadOnly()
                # Get the data
                if int(self.bus.readdatavalid):
                    data = self.bus.readdata.value
                    break
                yield RisingEdge(self.clock)
        else:
            # Assume readLatency = 1 if no readdatavalid
            # FIXME need to configure this,
            # should take a dictionary of Avalon properties.
            yield ReadOnly()

        self._release_lock()
        raise ReturnValue(data)

    @coroutine
    def write(self, address, value):
        """
        Issue a write to the given address with the specified
        value.
        See http://www.altera.com/literature/manual/mnl_avalon_spec_1_3.pdf
        """
        if not self._can_write:
            self.log.error("Cannot write - have no write signal")
            raise TestError("Attempt to write on a read-only AvalonMaster")

        yield self._acquire_lock()

        # Apply valuse to bus
        yield RisingEdge(self.clock)
        self.bus.address <= address
        self.bus.writedata <= value
        self.bus.write <= 1
        if hasattr(self.bus, "byteenable"):
            self.bus.byteenable <= int("1"*len(self.bus.byteenable), 2)
        if hasattr(self.bus, "cs"):
            self.bus.cs <= 1

        # Wait for waitrequest to be low
        if hasattr(self.bus, "waitrequest"):
            count = yield self._wait_for_nsignal(self.bus.waitrequest)

        # Deassert write
        yield RisingEdge(self.clock)
        self.bus.write <= 0
        if hasattr(self.bus, "byteenable"):
            self.bus.byteenable <= 0
        if hasattr(self.bus, "cs"):
            self.bus.cs <= 0
        v = self.bus.address.value
        v.binstr = "x" * len(self.bus.address)
        self.bus.address <= v

        v = self.bus.writedata.value
        v.binstr = "x" * len(self.bus.writedata)
        self.bus.writedata <= v
        self._release_lock()
Example #58
0
class Monitor(object):

    def __init__(self, callback=None, event=None):
        """
        Constructor for a monitor instance

        callback will be called with each recovered transaction as the argument

        If the callback isn't used, received transactions will be placed on a
        queue and the event used to notify any consumers.
        """
        self._event = event
        self._wait_event = None
        self._recvQ = []
        self._callbacks = []
        self.stats = MonitorStatistics()
        self._wait_event = Event()

        # Subclasses may already set up logging
        if not hasattr(self, "log"):
            self.log = SimLog("cocotb.monitor.%s" % (self.__class__.__name__))

        if callback is not None:
            self.add_callback(callback)

        # Create an independent coroutine which can receive stuff
        self._thread = cocotb.scheduler.add(self._monitor_recv())

    def kill(self):
        if self._thread:
            self._thread.kill()
            self._thread = None

    def __len__(self):
        return len(self._recvQ)

    def __getitem__(self, idx):
        return self._recvQ[idx]

    def add_callback(self, callback):
        self.log.debug("Adding callback of function %s to monitor" %
                       (callback.__name__))
        self._callbacks.append(callback)

    @coroutine
    def wait_for_recv(self, timeout=None):
        if timeout:
            t = Timer(timeout)
            fired = yield [self._wait_event.wait(), t]
            if fired is t:
                raise ReturnValue(None)
        else:
            yield self._wait_event.wait()

        pkt = self._wait_event.data
        raise ReturnValue(pkt)

    @coroutine
    def _monitor_recv(self):
        """
        actual impementation of the receiver

        subclasses should override this method to implement the actual receive
        routine and call self._recv() with the recovered transaction
        """
        raise NotImplementedError("Attempt to use base monitor class without "
                                  "providing a _monitor_recv method")

    def _recv(self, transaction):
        """Common handling of a received transaction."""

        self.stats.received_transactions += 1

        # either callback based consumer
        for callback in self._callbacks:
            callback(transaction)

        # Or queued with a notification
        if not self._callbacks:
            self._recvQ.append(transaction)

        if self._event is not None:
            self._event.set()

        # If anyone was waiting then let them know
        if self._wait_event is not None:
            self._wait_event.set(data=transaction)
            self._wait_event.clear()
Example #59
0
class Driver(object):
    """

    Class defining the standard interface for a driver within a testbench

    The driver is responsible for serialising transactions onto the physical
    pins of the interface.  This may consume simulation time.
    """
    def __init__(self):
        """
        Constructor for a driver instance
        """
        # self._busy = Lock()
        self._pending = Event(name="Driver._pending")
        self._sendQ = deque()

        # Subclasses may already set up logging
        if not hasattr(self, "log"):
            self.log = SimLog("cocotb.driver.%s" % (self.__class__.__name__))

        # Create an independent coroutine which can send stuff
        self._thread = cocotb.scheduler.add(self._send_thread())

    def kill(self):
        if self._thread:
            self._thread.kill()
            self._thread = None

    def append(self, transaction, callback=None, event=None):
        """
        Queue up a transaction to be sent over the bus.

        Mechanisms are provided to permit the caller to know when the
        transaction is processed

        callback: optional function to be called when the transaction has been
        sent

        event: event to be set when the tansaction has been sent
        """
        self._sendQ.append((transaction, callback, event))
        self._pending.set()

    def clear(self):
        """
        Clear any queued transactions without sending them onto the bus
        """
        self._sendQ = deque()

    @coroutine
    def send(self, transaction, sync=True):
        """
        Blocking send call (hence must be "yielded" rather than called)

        Sends the transaction over the bus

        Args:
            transaction (any): the transaction to send

        Kwargs:
            sync (boolean): synchronise the transfer by waiting for risingedge
        """
        yield self._send(transaction, None, None, sync=sync)

    def _driver_send(self, transaction, sync=True):
        """
        actual impementation of the send.

        subclasses should override this method to implement the actual send
        routine
        """
        raise NotImplementedError("Subclasses of Driver should define a "
                                  "_driver_send coroutine")

    @coroutine
    def _send(self, transaction, callback, event, sync=True):
        """
        assumes the caller has already acquired the busy lock

        releases busy lock once sending is complete
        """
        yield self._driver_send(transaction, sync=sync)

        # Notify the world that this transaction is complete
        if event:
            event.set()
        if callback:
            callback(transaction)

        # No longer hogging the bus
        # self.busy.release()

    @coroutine
    def _send_thread(self):
        while True:

            # Sleep until we have something to send
            while not self._sendQ:
                self._pending.clear()
                yield self._pending.wait()

            synchronised = False

            # Send in all the queued packets,
            # only synchronise on the first send
            while self._sendQ:
                transaction, callback, event = self._sendQ.popleft()
                self.log.debug("Sending queued packet...")
                yield self._send(transaction, callback, event,
                                 sync=not synchronised)
                synchronised = True