コード例 #1
0
ファイル: uart.py プロジェクト: alexforencich/cocotbext-uart
    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 = Queue()

        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()
コード例 #2
0
async def test_analog_model(digital) -> None:
    """Exercise an Analog Front-end and its digital controller."""

    clock = Clock(digital.clk, 1,
                  units="us")  # create a 1us period clock on port clk
    cocotb.start_soon(clock.start())  # start the clock

    afe_in_queue = Queue()
    afe_out_queue = Queue()
    afe = AFE(in_queue=afe_in_queue,
              out_queue=afe_out_queue)  # instantiate the analog front-end

    cocotb.start_soon(gain_select(digital, afe))

    for in_V in [0.1, 0.1, 0.0, 0.25, 0.25]:
        # set the input voltage
        await afe_in_queue.put(in_V)

        # get the converted digital value
        afe_out = await afe_out_queue.get()

        digital._log.info(
            f"AFE converted input value {in_V}V to {int(afe_out)}")

        # hand digital value over as "meas_val" to digital part (HDL)
        # "meas_val_valid" pulses for one clock cycle
        await RisingEdge(digital.clk)
        digital.meas_val.value = afe_out
        digital.meas_val_valid.value = 1
        await RisingEdge(digital.clk)
        digital.meas_val_valid.value = 0
        await Timer(3.3, "us")
コード例 #3
0
ファイル: axi_master.py プロジェクト: corundum/cocotbext-axi
 def __init__(self, manager):
     self.current_tag = 0
     self._cmd_queue = Queue()
     self._current_cmd = None
     self._resp_queue = Queue()
     self._cr = None
     self._manager = manager
コード例 #4
0
ファイル: test_queues.py プロジェクト: raysalemi/cocotb
async def test_fair_scheduling(dut):
    NUM_PUTTERS = 10
    NUM_PUTS = 10

    q = Queue(maxsize=1)

    async def putter(i):
        for _ in range(NUM_PUTS):
            await q.put(i)

    # fill queue to force contention
    q.put_nowait(None)

    # create NUM_PUTTER contending putters
    putters = [await cocotb.start(putter(i)) for i in range(NUM_PUTTERS)]

    # remove value that forced contention
    assert q.get_nowait() is None, "Popped unexpected value"

    # test fair scheduling by ensuring that each putter is serviced for its first
    # write before the second write on any putter is serviced.
    for _ in range(NUM_PUTS):
        remaining = set(range(NUM_PUTTERS))
        for _ in range(NUM_PUTTERS):
            v = await q.get()
            assert v in remaining, "Unfair scheduling occurred"
            remaining.remove(v)

    assert all(not p for p in putters), "Not all putters finished?"
コード例 #5
0
ファイル: interface.py プロジェクト: psumesh/cocotbext-pcie
    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
コード例 #6
0
async def run_stress_test(dut, idle_inserter=None, backpressure_inserter=None):

    tb = TB(dut)

    byte_lanes = tb.axil_master.read_if.byte_lanes
    counter_size = max(
        int(os.getenv("PARAM_STAT_COUNT_WIDTH")) // 8, byte_lanes)
    stat_inc_width = len(dut.s_axis_stat_tdata)
    stat_id_width = len(dut.s_axis_stat_tid)

    await tb.cycle_reset()

    tb.set_idle_generator(idle_inserter)
    tb.set_backpressure_generator(backpressure_inserter)

    await Timer(4000, 'ns')

    async def worker(source, queue, count=128):
        for k in range(count):
            count = random.randrange(1, 2**stat_inc_width)
            num = random.randrange(0, 2**stat_id_width)

            await source.send(AxiStreamTransaction(tdata=count, tid=num))

            await queue.put((num, count))

            await Timer(random.randint(1, 1000), 'ns')

    workers = []
    queue = Queue()

    for k in range(16):
        workers.append(
            cocotb.start_soon(worker(tb.stat_source, queue, count=128)))

    while workers:
        await workers.pop(0).join()

    await Timer(1000, 'ns')

    data_ref = [0] * 2**stat_id_width

    while not queue.empty():
        num, count = await queue.get()
        data_ref[num] += count

    print(data_ref)

    data = await tb.axil_master.read_words(0,
                                           2**stat_id_width,
                                           ws=counter_size)

    print(data)

    assert data == data_ref

    await RisingEdge(dut.clk)
    await RisingEdge(dut.clk)
コード例 #7
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)
コード例 #8
0
ファイル: axil_master.py プロジェクト: Botnic/cocotbext-axi
    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)
コード例 #9
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)
コード例 #10
0
    def add_switch_port(self, port):
        self.switch_ports.append(port)
        cocotb.start_soon(self._run_routing(port))
        cocotb.start_soon(self._run_arbitration(port))

        for k in range(len(self.switch_ports)-1):
            tx_queue = Queue()
            rx_queue = Queue()
            port.tx_queues.append((self.switch_ports[k], tx_queue))
            port.rx_queues.append(rx_queue)
            self.switch_ports[k].rx_queues.append(tx_queue)
            self.switch_ports[k].tx_queues.append((port, rx_queue))
コード例 #11
0
ファイル: stream.py プロジェクト: corundum/cocotbext-axi
    def __init__(self,
                 bus,
                 clock,
                 reset=None,
                 reset_active_level=True,
                 *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.ready = None
        self.valid = None

        if self._ready_signal is not None and hasattr(self.bus,
                                                      self._ready_signal):
            self.ready = getattr(self.bus, self._ready_signal)
            if self._ready_init is not None:
                self.ready.setimmediatevalue(self._ready_init)

        if self._valid_signal is not None and hasattr(self.bus,
                                                      self._valid_signal):
            self.valid = getattr(self.bus, self._valid_signal)
            if self._valid_init is not None:
                self.valid.setimmediatevalue(self._valid_init)

        for sig in self._signals + self._optional_signals:
            if hasattr(self.bus, sig):
                if sig in self._signal_widths:
                    assert len(getattr(self.bus,
                                       sig)) == self._signal_widths[sig]
                if self._init_x and sig not in (self._valid_signal,
                                                self._ready_signal):
                    v = getattr(self.bus, sig).value
                    v.binstr = 'x' * len(v)
                    getattr(self.bus, sig).setimmediatevalue(v)

        self._run_cr = None

        self._init_reset(reset, reset_active_level)
コード例 #12
0
    def __init__(self,
                 data,
                 ctrl,
                 clock,
                 reset=None,
                 enable=None,
                 reset_active_level=True,
                 *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.log.info("XGMII 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 = Queue()
        self.active_event = Event()

        self.queue_occupancy_bytes = 0
        self.queue_occupancy_frames = 0

        self.width = len(self.data)
        self.byte_size = 8
        self.byte_lanes = len(self.ctrl)

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

        self.log.info("XGMII sink model configuration")
        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._run_cr = None

        self._init_reset(reset, reset_active_level)
コード例 #13
0
ファイル: baser.py プロジェクト: ylm/verilog-ethernet
    def __init__(self,
                 data,
                 header,
                 clock,
                 enable=None,
                 scramble=True,
                 reverse=False,
                 *args,
                 **kwargs):
        self.log = logging.getLogger(f"cocotb.{data._path}")
        self.data = data
        self.header = header
        self.clock = clock
        self.enable = enable
        self.scramble = scramble
        self.reverse = reverse

        self.log.info("BASE-R serdes sink")
        self.log.info("Copyright (c) 2021 Alex Forencich")
        self.log.info("https://github.com/alexforencich/verilog-ethernet")

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

        self.active = False
        self.queue = Queue()
        self.active_event = Event()

        self.queue_occupancy_bytes = 0
        self.queue_occupancy_frames = 0

        self.width = len(self.data)
        self.byte_size = 8
        self.byte_lanes = 8

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

        self.log.info("BASE-R serdes sink model configuration")
        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("  Enable scrambler: %s", self.scramble)
        self.log.info("  Bit reverse: %s", self.reverse)

        self._run_cr = cocotb.fork(self._run())
コード例 #14
0
    def __init__(self,
                 in_queue: Optional[Queue] = None,
                 out_queue: Optional[Queue] = None) -> None:
        self.in_queue = in_queue
        self.out_queue = out_queue
        self.pga_to_adc_queue = Queue()

        self.pga = PGA(in_queue=self.in_queue, out_queue=self.pga_to_adc_queue)
        self.adc = ADC(in_queue=self.pga_to_adc_queue,
                       out_queue=self.out_queue)
コード例 #15
0
    def __init__(self, bus, clock, reset=None, reset_active_level=True):
        self.log = logging.getLogger(f"cocotb.{bus.aw._entity._name}.{bus.aw._name}")

        self.log.info("AXI lite 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 = AxiLiteAWSource(bus.aw, clock, reset, reset_active_level)
        self.aw_channel.queue_occupancy_limit = 2
        self.w_channel = AxiLiteWSource(bus.w, clock, reset, reset_active_level)
        self.w_channel.queue_occupancy_limit = 2
        self.b_channel = AxiLiteBSink(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.int_write_resp_command_queue = Queue()
        self.current_write_resp_command = None

        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.log.info("AXI lite master configuration:")
        self.log.info("  Address width: %d bits", len(self.aw_channel.bus.awaddr))
        self.log.info("  Byte size: %d bits", self.byte_size)
        self.log.info("  Data width: %d bits (%d bytes)", self.width, self.byte_width)

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

        self._process_write_cr = None
        self._process_write_resp_cr = None

        self._init_reset(reset, reset_active_level)
コード例 #16
0
    def __init__(self, bridge):
        self.bridge = bridge
        self.upstream = False

        self.ingress_queue = Queue(1)

        self.tx_queues = []
        self.rx_queues = []
        self.rx_event = Event()

        self.tx_handler = None
コード例 #17
0
ファイル: port.py プロジェクト: psumesh/cocotbext-pcie
    def __init__(self, fc_init=[[0]*6]*8, *args, **kwargs):
        self.log = logging.getLogger(f"cocotb.pcie.{type(self).__name__}.{id(self)}")
        self.log.name = f"cocotb.pcie.{type(self).__name__}"

        self.parent = None
        self.rx_handler = None

        self.max_link_speed = None
        self.max_link_width = None

        self.tx_queue = Queue(1)
        self.tx_queue_sync = Event()

        self.rx_queue = Queue()

        self.cur_link_speed = None
        self.cur_link_width = None

        self.time_scale = get_sim_steps(1, 'sec')

        # ACK/NAK protocol
        # TX
        self.next_transmit_seq = 0x000
        self.ackd_seq = 0xfff
        self.retry_buffer = Queue()

        # RX
        self.next_recv_seq = 0x000
        self.nak_scheduled = False
        self.ack_nak_latency_timer = 0

        self.max_payload_size = 128
        self.max_latency_timer = 0

        self.send_ack = Event()

        self._ack_latency_timer_cr = None

        # Flow control
        self.send_fc = Event()

        self.fc_state = [FcChannelState(fc_init[k], self.start_fc_update_timer) for k in range(8)]

        self.fc_initialized = False
        self.fc_init_vc = 0
        self.fc_init_type = FcType.P

        self.fc_idle_timer_steps = get_sim_steps(10, 'us')
        self.fc_update_steps = get_sim_steps(30, 'us')

        self._fc_update_timer_cr = None

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

        # VC0 is always active
        self.fc_state[0].active = True

        cocotb.fork(self._run_transmit())
        cocotb.fork(self._run_receive())
        cocotb.fork(self._run_fc_update_idle_timer())
コード例 #18
0
ファイル: gmii.py プロジェクト: corundum/cocotbext-eth
    def __init__(self, data, er, dv, clock, reset=None, enable=None, mii_select=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.mii_select = mii_select

        self.log.info("GMII 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 = Queue()
        self.active_event = 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) == 8
        if self.er is not None:
            assert len(self.er) == 1
        if self.dv is not None:
            assert len(self.dv) == 1

        self._run_cr = None

        self._init_reset(reset, reset_active_level)
コード例 #19
0
ファイル: axi_master.py プロジェクト: corundum/cocotbext-axi
class TagContext:
    def __init__(self, manager):
        self.current_tag = 0
        self._cmd_queue = Queue()
        self._current_cmd = None
        self._resp_queue = Queue()
        self._cr = None
        self._manager = manager

    async def get_resp(self):
        return await self._resp_queue.get()

    def get_resp_nowait(self):
        return self._resp_queue.get_nowait()

    def _start(self):
        if self._cr is None:
            self._cr = cocotb.start_soon(self._process_queue())

    def _flush(self):
        flushed_cmds = []
        if self._cr is not None:
            self._cr.kill()
            self._cr = None
        self._manager._set_idle(self)
        if self._current_cmd is not None:
            flushed_cmds.append(self._current_cmd)
            self._current_cmd = None
        while not self._cmd_queue.empty():
            flushed_cmds.append(self._cmd_queue.get_nowait())
        while not self._resp_queue.empty():
            self._resp_queue.get_nowait()
        return flushed_cmds

    async def _process_queue(self):
        while True:
            cmd = await self._cmd_queue.get()
            self._current_cmd = cmd
            await self._manager._process(self, cmd)
            self._current_cmd = None

            if self._cmd_queue.empty() and self._resp_queue.empty():
                self._manager._set_idle(self)
コード例 #20
0
ファイル: interface.py プロジェクト: psumesh/cocotbext-pcie
class UsPcieBase:

    _signal_widths = {"tvalid": 1, "tready": 1}

    _valid_signal = "tvalid"
    _ready_signal = "tready"

    _transaction_obj = UsPcieTransaction
    _frame_obj = UsPcieFrame

    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):
        pass

    def count(self):
        return self.queue.qsize()

    def empty(self):
        return self.queue.empty()

    def clear(self):
        while not self.queue.empty():
            self.queue.get_nowait()
        self.idle_event.set()
        self.active_event.clear()

    def idle(self):
        raise NotImplementedError()

    async def wait(self):
        raise NotImplementedError()

    def set_pause_generator(self, generator=None):
        if self._pause_cr is not None:
            self._pause_cr.kill()
            self._pause_cr = None

        self._pause_generator = generator

        if self._pause_generator is not None:
            self._pause_cr = cocotb.fork(self._run_pause())

    def clear_pause_generator(self):
        self.set_pause_generator(None)

    async def _run_pause(self):
        for val in self._pause_generator:
            self.pause = val
            await RisingEdge(self.clock)
コード例 #21
0
ファイル: stream.py プロジェクト: corundum/cocotbext-axi
class StreamBase(Reset):

    _signals = ["data", "valid", "ready"]
    _optional_signals = []

    _signal_widths = {"valid": 1, "ready": 1}

    _init_x = False

    _valid_signal = "valid"
    _valid_init = None
    _ready_signal = "ready"
    _ready_init = None

    _transaction_obj = StreamTransaction
    _bus_obj = StreamBus

    def __init__(self,
                 bus,
                 clock,
                 reset=None,
                 reset_active_level=True,
                 *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.ready = None
        self.valid = None

        if self._ready_signal is not None and hasattr(self.bus,
                                                      self._ready_signal):
            self.ready = getattr(self.bus, self._ready_signal)
            if self._ready_init is not None:
                self.ready.setimmediatevalue(self._ready_init)

        if self._valid_signal is not None and hasattr(self.bus,
                                                      self._valid_signal):
            self.valid = getattr(self.bus, self._valid_signal)
            if self._valid_init is not None:
                self.valid.setimmediatevalue(self._valid_init)

        for sig in self._signals + self._optional_signals:
            if hasattr(self.bus, sig):
                if sig in self._signal_widths:
                    assert len(getattr(self.bus,
                                       sig)) == self._signal_widths[sig]
                if self._init_x and sig not in (self._valid_signal,
                                                self._ready_signal):
                    v = getattr(self.bus, sig).value
                    v.binstr = 'x' * len(v)
                    getattr(self.bus, sig).setimmediatevalue(v)

        self._run_cr = None

        self._init_reset(reset, reset_active_level)

    def count(self):
        return self.queue.qsize()

    def empty(self):
        return self.queue.empty()

    def clear(self):
        while not self.queue.empty():
            self.queue.get_nowait()
        self.dequeue_event.set()
        self.idle_event.set()
        self.active_event.clear()

    def _handle_reset(self, state):
        if state:
            self.log.info("Reset asserted")
            if self._run_cr is not None:
                self._run_cr.kill()
                self._run_cr = None

            self.active = False

            if self.queue.empty():
                self.idle_event.set()
        else:
            self.log.info("Reset de-asserted")
            if self._run_cr is None:
                self._run_cr = cocotb.start_soon(self._run())

    async def _run(self):
        raise NotImplementedError()
コード例 #22
0
ファイル: axis.py プロジェクト: qgzln/cocotbext-axi
    def __init__(self,
                 bus,
                 clock,
                 reset=None,
                 reset_active_level=True,
                 byte_size=None,
                 byte_lanes=None,
                 *args,
                 **kwargs):

        self.bus = bus
        self.clock = clock
        self.reset = reset
        self.log = logging.getLogger(f"cocotb.{bus._entity._name}.{bus._name}")

        self.log.info("AXI stream %s", self._type)
        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")

        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.active_event = Event()

        self.queue_occupancy_bytes = 0
        self.queue_occupancy_frames = 0

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

        if self._valid_init is not None and hasattr(self.bus, "tvalid"):
            self.bus.tvalid.setimmediatevalue(self._valid_init)
        if self._ready_init is not None and hasattr(self.bus, "tready"):
            self.bus.tready.setimmediatevalue(self._ready_init)

        for sig in self._signals + self._optional_signals:
            if hasattr(self.bus, sig):
                if self._init_x and sig not in ("tvalid", "tready"):
                    v = getattr(self.bus, sig).value
                    v.binstr = 'x' * len(v)
                    getattr(self.bus, sig).setimmediatevalue(v)

        if hasattr(self.bus, "tkeep"):
            self.byte_lanes = len(self.bus.tkeep)
            if byte_size is not None or byte_lanes is not None:
                raise ValueError(
                    "Cannot specify byte_size or byte_lanes if tkeep is connected"
                )
        else:
            if byte_lanes is not None:
                self.byte_lanes = byte_lanes
                if byte_size is not None:
                    raise ValueError(
                        "Cannot specify both byte_size and byte_lanes")
            elif byte_size is not None:
                self.byte_lanes = self.width // byte_size

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

        self.log.info("AXI stream %s configuration:", self._type)
        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(
            "  tvalid: %s",
            "present" if hasattr(self.bus, "tvalid") else "not present")
        self.log.info(
            "  tready: %s",
            "present" if hasattr(self.bus, "tready") else "not present")
        self.log.info(
            "  tlast: %s",
            "present" if hasattr(self.bus, "tlast") else "not present")
        if hasattr(self.bus, "tkeep"):
            self.log.info("  tkeep width: %d bits", len(self.bus.tkeep))
        else:
            self.log.info("  tkeep: not present")
        if hasattr(self.bus, "tid"):
            self.log.info("  tid width: %d bits", len(self.bus.tid))
        else:
            self.log.info("  tid: not present")
        if hasattr(self.bus, "tdest"):
            self.log.info("  tdest width: %d bits", len(self.bus.tdest))
        else:
            self.log.info("  tdest: not present")
        if hasattr(self.bus, "tuser"):
            self.log.info("  tuser width: %d bits", len(self.bus.tuser))
        else:
            self.log.info("  tuser: not present")

        if self.byte_lanes * self.byte_size != self.width:
            raise ValueError(
                f"Bus does not evenly divide into byte lanes "
                f"({self.byte_lanes} * {self.byte_size} != {self.width})")

        self._run_cr = None

        self._init_reset(reset, reset_active_level)
コード例 #23
0
ファイル: interface.py プロジェクト: corundum/cocotbext-pcie
    def __init__(self,
                 bus,
                 clock,
                 reset=None,
                 ready_latency=0,
                 *args,
                 **kwargs):
        self.bus = bus
        self.clock = clock
        self.reset = reset
        self.ready_latency = ready_latency
        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.data)
        self.byte_size = 32
        self.byte_lanes = self.width // self.byte_size
        self.byte_mask = 2**self.byte_size - 1

        self.seg_count = len(self.bus.valid)
        self.seg_width = self.width // self.seg_count
        self.seg_mask = 2**self.seg_width - 1
        self.seg_par_width = self.seg_width // 8
        self.seg_par_mask = 2**self.seg_par_width - 1
        self.seg_byte_lanes = self.byte_lanes // self.seg_count
        self.seg_empty_width = (self.seg_byte_lanes - 1).bit_length()
        self.seg_empty_mask = 2**self.seg_empty_width - 1

        assert self.width in {256, 512}

        assert len(self.bus.data) == self.seg_count * self.seg_width
        assert len(self.bus.sop) == self.seg_count
        assert len(self.bus.eop) == self.seg_count
        assert len(self.bus.valid) == self.seg_count

        if hasattr(self.bus, "empty"):
            assert len(self.bus.empty) == self.seg_count * self.seg_empty_width

        if hasattr(self.bus, "err"):
            assert len(self.bus.err) == self.seg_count
        if hasattr(self.bus, "bar_range"):
            assert len(self.bus.bar_range) == self.seg_count * 3

        if hasattr(self.bus, "vf_active"):
            assert len(self.bus.vf_active) == self.seg_count
        if hasattr(self.bus, "func_num"):
            assert len(self.bus.func_num) == self.seg_count * 2
        if hasattr(self.bus, "vf_num"):
            assert len(self.bus.vf_num) == self.seg_count * 11

        if hasattr(self.bus, "parity"):
            assert len(self.bus.parity) == self.seg_count * self.seg_width // 8
コード例 #24
0
ファイル: interface.py プロジェクト: corundum/cocotbext-pcie
class S10PcieBase:

    _signal_widths = {"ready": 1}

    _valid_signal = "valid"
    _ready_signal = "ready"

    _transaction_obj = S10PcieTransaction
    _frame_obj = S10PcieFrame

    def __init__(self,
                 bus,
                 clock,
                 reset=None,
                 ready_latency=0,
                 *args,
                 **kwargs):
        self.bus = bus
        self.clock = clock
        self.reset = reset
        self.ready_latency = ready_latency
        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.data)
        self.byte_size = 32
        self.byte_lanes = self.width // self.byte_size
        self.byte_mask = 2**self.byte_size - 1

        self.seg_count = len(self.bus.valid)
        self.seg_width = self.width // self.seg_count
        self.seg_mask = 2**self.seg_width - 1
        self.seg_par_width = self.seg_width // 8
        self.seg_par_mask = 2**self.seg_par_width - 1
        self.seg_byte_lanes = self.byte_lanes // self.seg_count
        self.seg_empty_width = (self.seg_byte_lanes - 1).bit_length()
        self.seg_empty_mask = 2**self.seg_empty_width - 1

        assert self.width in {256, 512}

        assert len(self.bus.data) == self.seg_count * self.seg_width
        assert len(self.bus.sop) == self.seg_count
        assert len(self.bus.eop) == self.seg_count
        assert len(self.bus.valid) == self.seg_count

        if hasattr(self.bus, "empty"):
            assert len(self.bus.empty) == self.seg_count * self.seg_empty_width

        if hasattr(self.bus, "err"):
            assert len(self.bus.err) == self.seg_count
        if hasattr(self.bus, "bar_range"):
            assert len(self.bus.bar_range) == self.seg_count * 3

        if hasattr(self.bus, "vf_active"):
            assert len(self.bus.vf_active) == self.seg_count
        if hasattr(self.bus, "func_num"):
            assert len(self.bus.func_num) == self.seg_count * 2
        if hasattr(self.bus, "vf_num"):
            assert len(self.bus.vf_num) == self.seg_count * 11

        if hasattr(self.bus, "parity"):
            assert len(self.bus.parity) == self.seg_count * self.seg_width // 8

    def count(self):
        return self.queue.qsize()

    def empty(self):
        return self.queue.empty()

    def clear(self):
        while not self.queue.empty():
            self.queue.get_nowait()
        self.idle_event.set()
        self.active_event.clear()

    def idle(self):
        raise NotImplementedError()

    async def wait(self):
        raise NotImplementedError()

    def set_pause_generator(self, generator=None):
        if self._pause_cr is not None:
            self._pause_cr.kill()
            self._pause_cr = None

        self._pause_generator = generator

        if self._pause_generator is not None:
            self._pause_cr = cocotb.start_soon(self._run_pause())

    def clear_pause_generator(self):
        self.set_pause_generator(None)

    async def _run_pause(self):
        clock_edge_event = RisingEdge(self.clock)

        for val in self._pause_generator:
            self.pause = val
            await clock_edge_event
コード例 #25
0
ファイル: uart.py プロジェクト: alexforencich/cocotbext-uart
class UartSource:
    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 = Queue()

        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()

    def _restart(self):
        if self._run_cr is not None:
            self._run_cr.kill()
        self._run_cr = cocotb.fork(
            self._run(self._data, self._baud, self._bits, self._stop_bits))

    @property
    def baud(self):
        return self._baud

    @baud.setter
    def baud(self, value):
        self.baud = value
        self._restart()

    @property
    def bits(self):
        return self._bits

    @bits.setter
    def bits(self, value):
        self.bits = value
        self._restart()

    @property
    def stop_bits(self):
        return self._stop_bits

    @stop_bits.setter
    def stop_bits(self, value):
        self.stop_bits = value
        self._restart()

    async def write(self, data):
        for b in data:
            await self.queue.put(int(b))
            self._idle.clear()

    def write_nowait(self, data):
        for b in data:
            self.queue.put_nowait(int(b))
        self._idle.clear()

    def count(self):
        return self.queue.qsize()

    def empty(self):
        return self.queue.empty()

    def idle(self):
        return self.empty() and not self.active

    def clear(self):
        while not self.queue.empty():
            frame = self.queue.get_nowait()

    async def wait(self):
        await self._idle.wait()

    async def _run(self, data, baud, bits, stop_bits):
        self.active = False

        bit_t = Timer(int(1e9 / self.baud), 'ns')
        stop_bit_t = Timer(int(1e9 / self.baud * stop_bits), 'ns')

        while True:
            if self.empty():
                self.active = False
                self._idle.set()

            b = await self.queue.get()
            self.active = True

            self.log.info("Write byte 0x%02x", b)

            # start bit
            data.value = 0
            await bit_t

            # data bits
            for k in range(self.bits):
                data.value = b & 1
                b >>= 1
                await bit_t

            # stop bit
            data.value = 1
            await stop_bit_t
コード例 #26
0
ファイル: tinyalu_utils.py プロジェクト: pyuvm/pyuvm
class TinyAluBfm(metaclass=utility_classes.Singleton):
    def __init__(self):
        self.dut = cocotb.top
        self.driver_queue = Queue(maxsize=1)
        self.cmd_mon_queue = Queue(maxsize=0)
        self.result_mon_queue = Queue(maxsize=0)

    async def send_op(self, aa, bb, op):
        command_tuple = (aa, bb, op)
        await self.driver_queue.put(command_tuple)

    async def get_cmd(self):
        cmd = await self.cmd_mon_queue.get()
        return cmd

    async def get_result(self):
        result = await self.result_mon_queue.get()
        return result

    async def reset(self):
        await FallingEdge(self.dut.clk)
        self.dut.reset_n.value = 0
        self.dut.A.value = 0
        self.dut.B.value = 0
        self.dut.op.value = 0
        await FallingEdge(self.dut.clk)
        self.dut.reset_n.value = 1
        await FallingEdge(self.dut.clk)

    async def driver_bfm(self):
        self.dut.start.value = 0
        self.dut.A.value = 0
        self.dut.B.value = 0
        self.dut.op.value = 0
        while True:
            await FallingEdge(self.dut.clk)
            start = get_int(self.dut.start)
            done = get_int(self.dut.done)
            if start == 0 and done == 0:
                try:
                    (aa, bb, op) = self.driver_queue.get_nowait()
                    self.dut.A.value = aa
                    self.dut.B.value = bb
                    self.dut.op.value = op
                    self.dut.start.value = 1
                except QueueEmpty:
                    pass
            elif start == 1:
                if done == 1:
                    self.dut.start.value = 0

    async def cmd_mon_bfm(self):
        prev_start = 0
        while True:
            await FallingEdge(self.dut.clk)
            start = get_int(self.dut.start)
            if start == 1 and prev_start == 0:
                cmd_tuple = (get_int(self.dut.A),
                             get_int(self.dut.B),
                             get_int(self.dut.op))
                self.cmd_mon_queue.put_nowait(cmd_tuple)
            prev_start = start

    async def result_mon_bfm(self):
        prev_done = 0
        while True:
            await FallingEdge(self.dut.clk)
            done = get_int(self.dut.done)
            if prev_done == 0 and done == 1:
                result = get_int(self.dut.result)
                self.result_mon_queue.put_nowait(result)
            prev_done = done

    def start_bfm(self):
        cocotb.start_soon(self.driver_bfm())
        cocotb.start_soon(self.cmd_mon_bfm())
        cocotb.start_soon(self.result_mon_bfm())
コード例 #27
0
ファイル: tinyalu_utils.py プロジェクト: pyuvm/pyuvm
 def __init__(self):
     self.dut = cocotb.top
     self.driver_queue = Queue(maxsize=1)
     self.cmd_mon_queue = Queue(maxsize=0)
     self.result_mon_queue = Queue(maxsize=0)
コード例 #28
0
class MiiSource(Reset):
    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)

    async def send(self, frame):
        while self.full():
            self.dequeue_event.clear()
            await self.dequeue_event.wait()
        frame = GmiiFrame(frame)
        await self.queue.put(frame)
        self.idle_event.clear()
        self.queue_occupancy_bytes += len(frame)
        self.queue_occupancy_frames += 1

    def send_nowait(self, frame):
        if self.full():
            raise QueueFull()
        frame = GmiiFrame(frame)
        self.queue.put_nowait(frame)
        self.idle_event.clear()
        self.queue_occupancy_bytes += len(frame)
        self.queue_occupancy_frames += 1

    def count(self):
        return self.queue.qsize()

    def empty(self):
        return self.queue.empty()

    def full(self):
        if self.queue_occupancy_limit_bytes > 0 and self.queue_occupancy_bytes > self.queue_occupancy_limit_bytes:
            return True
        elif self.queue_occupancy_limit_frames > 0 and self.queue_occupancy_frames > self.queue_occupancy_limit_frames:
            return True
        else:
            return False

    def idle(self):
        return self.empty() and not self.active

    def clear(self):
        while not self.queue.empty():
            frame = self.queue.get_nowait()
            frame.sim_time_end = None
            frame.handle_tx_complete()
        self.dequeue_event.set()
        self.idle_event.set()
        self.queue_occupancy_bytes = 0
        self.queue_occupancy_frames = 0

    async def wait(self):
        await self.idle_event.wait()

    def _handle_reset(self, state):
        if state:
            self.log.info("Reset asserted")
            if self._run_cr is not None:
                self._run_cr.kill()
                self._run_cr = None

            self.active = False
            self.data.value = 0
            if self.er is not None:
                self.er.value = 0
            self.dv.value = 0

            if self.current_frame:
                self.log.warning("Flushed transmit frame during reset: %s",
                                 self.current_frame)
                self.current_frame.handle_tx_complete()
                self.current_frame = None

            if self.queue.empty():
                self.idle_event.set()
        else:
            self.log.info("Reset de-asserted")
            if self._run_cr is None:
                self._run_cr = cocotb.start_soon(self._run())

    async def _run(self):
        frame = None
        frame_offset = 0
        frame_data = None
        frame_error = None
        ifg_cnt = 0
        self.active = False

        clock_edge_event = RisingEdge(self.clock)

        while True:
            await clock_edge_event

            if self.enable is None or self.enable.value:
                if ifg_cnt > 0:
                    # in IFG
                    ifg_cnt -= 1

                elif frame is None and not self.queue.empty():
                    # send frame
                    frame = self.queue.get_nowait()
                    self.dequeue_event.set()
                    self.queue_occupancy_bytes -= len(frame)
                    self.queue_occupancy_frames -= 1
                    self.current_frame = frame
                    frame.sim_time_start = get_sim_time()
                    frame.sim_time_sfd = None
                    frame.sim_time_end = None
                    self.log.info("TX frame: %s", frame)
                    frame.normalize()

                    # convert to MII
                    frame_data = []
                    frame_error = []
                    for b, e in zip(frame.data, frame.error):
                        frame_data.append(b & 0x0F)
                        frame_data.append(b >> 4)
                        frame_error.append(e)
                        frame_error.append(e)

                    self.active = True
                    frame_offset = 0

                if frame is not None:
                    d = frame_data[frame_offset]
                    if frame.sim_time_sfd is None and d == 0xD:
                        frame.sim_time_sfd = get_sim_time()
                    self.data.value = d
                    if self.er is not None:
                        self.er.value = frame_error[frame_offset]
                    self.dv.value = 1
                    frame_offset += 1

                    if frame_offset >= len(frame_data):
                        ifg_cnt = max(self.ifg, 1)
                        frame.sim_time_end = get_sim_time()
                        frame.handle_tx_complete()
                        frame = None
                        self.current_frame = None
                else:
                    self.data.value = 0
                    if self.er is not None:
                        self.er.value = 0
                    self.dv.value = 0
                    self.active = False
                    self.idle_event.set()
コード例 #29
0
class MiiSink(Reset):
    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 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 = Queue()
        self.active_event = Event()

        self.queue_occupancy_bytes = 0
        self.queue_occupancy_frames = 0

        self.width = 4
        self.byte_width = 1

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

        self._run_cr = None

        self._init_reset(reset, reset_active_level)

    def _recv(self, frame, compact=True):
        if self.queue.empty():
            self.active_event.clear()
        self.queue_occupancy_bytes -= len(frame)
        self.queue_occupancy_frames -= 1
        if compact:
            frame.compact()
        return frame

    async def recv(self, compact=True):
        frame = await self.queue.get()
        return self._recv(frame, compact)

    def recv_nowait(self, compact=True):
        frame = self.queue.get_nowait()
        return self._recv(frame, compact)

    def count(self):
        return self.queue.qsize()

    def empty(self):
        return self.queue.empty()

    def idle(self):
        return not self.active

    def clear(self):
        while not self.queue.empty():
            self.queue.get_nowait()
        self.active_event.clear()
        self.queue_occupancy_bytes = 0
        self.queue_occupancy_frames = 0

    async def wait(self, timeout=0, timeout_unit=None):
        if not self.empty():
            return
        if timeout:
            await First(self.active_event.wait(), Timer(timeout, timeout_unit))
        else:
            await self.active_event.wait()

    def _handle_reset(self, state):
        if state:
            self.log.info("Reset asserted")
            if self._run_cr is not None:
                self._run_cr.kill()
                self._run_cr = None

            self.active = False
        else:
            self.log.info("Reset de-asserted")
            if self._run_cr is None:
                self._run_cr = cocotb.start_soon(self._run())

    async def _run(self):
        frame = None
        self.active = False

        clock_edge_event = RisingEdge(self.clock)

        while True:
            await clock_edge_event

            if self.enable is None or self.enable.value:
                d_val = self.data.value.integer
                dv_val = self.dv.value.integer
                er_val = 0 if self.er is None else self.er.value.integer

                if frame is None:
                    if dv_val:
                        # start of frame
                        frame = GmiiFrame(bytearray(), [])
                        frame.sim_time_start = get_sim_time()
                else:
                    if not dv_val:
                        # end of frame
                        odd = True
                        sync = False
                        b = 0
                        be = 0
                        data = bytearray()
                        error = []
                        for n, e in zip(frame.data, frame.error):
                            odd = not odd
                            b = (n & 0x0F) << 4 | b >> 4
                            be |= e
                            if not sync and b == EthPre.SFD:
                                odd = True
                                sync = True
                            if odd:
                                data.append(b)
                                error.append(be)
                                be = 0
                        frame.data = data
                        frame.error = error

                        frame.compact()
                        frame.sim_time_end = get_sim_time()
                        self.log.info("RX frame: %s", frame)

                        self.queue_occupancy_bytes += len(frame)
                        self.queue_occupancy_frames += 1

                        self.queue.put_nowait(frame)
                        self.active_event.set()

                        frame = None

                if frame is not None:
                    if frame.sim_time_sfd is None and d_val == 0xD:
                        frame.sim_time_sfd = get_sim_time()

                    frame.data.append(d_val)
                    frame.error.append(er_val)
コード例 #30
0
ファイル: port.py プロジェクト: psumesh/cocotbext-pcie
class Port:
    """Base port"""
    def __init__(self, fc_init=[[0]*6]*8, *args, **kwargs):
        self.log = logging.getLogger(f"cocotb.pcie.{type(self).__name__}.{id(self)}")
        self.log.name = f"cocotb.pcie.{type(self).__name__}"

        self.parent = None
        self.rx_handler = None

        self.max_link_speed = None
        self.max_link_width = None

        self.tx_queue = Queue(1)
        self.tx_queue_sync = Event()

        self.rx_queue = Queue()

        self.cur_link_speed = None
        self.cur_link_width = None

        self.time_scale = get_sim_steps(1, 'sec')

        # ACK/NAK protocol
        # TX
        self.next_transmit_seq = 0x000
        self.ackd_seq = 0xfff
        self.retry_buffer = Queue()

        # RX
        self.next_recv_seq = 0x000
        self.nak_scheduled = False
        self.ack_nak_latency_timer = 0

        self.max_payload_size = 128
        self.max_latency_timer = 0

        self.send_ack = Event()

        self._ack_latency_timer_cr = None

        # Flow control
        self.send_fc = Event()

        self.fc_state = [FcChannelState(fc_init[k], self.start_fc_update_timer) for k in range(8)]

        self.fc_initialized = False
        self.fc_init_vc = 0
        self.fc_init_type = FcType.P

        self.fc_idle_timer_steps = get_sim_steps(10, 'us')
        self.fc_update_steps = get_sim_steps(30, 'us')

        self._fc_update_timer_cr = None

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

        # VC0 is always active
        self.fc_state[0].active = True

        cocotb.fork(self._run_transmit())
        cocotb.fork(self._run_receive())
        cocotb.fork(self._run_fc_update_idle_timer())

    def classify_tlp_vc(self, tlp):
        return 0

    async def send(self, pkt):
        pkt.release_fc()
        await self.fc_state[self.classify_tlp_vc(pkt)].tx_tlp_fc_gate(pkt)
        await self.tx_queue.put(pkt)
        self.tx_queue_sync.set()

    async def _run_transmit(self):
        await NullTrigger()
        while True:
            while self.tx_queue.empty() and not self.send_ack.is_set() and not self.send_fc.is_set() and self.fc_initialized:
                self.tx_queue_sync.clear()
                await First(self.tx_queue_sync.wait(), self.send_ack.wait(), self.send_fc.wait())

            pkt = None

            if self.send_ack.is_set():
                # Send ACK or NAK DLLP
                # Runs when
                #  - ACK timer expires
                #  - ACK/NAK transmit requested
                self.send_ack.clear()
                if self.nak_scheduled:
                    pkt = Dllp.create_nak((self.next_recv_seq-1) & 0xfff)
                else:
                    pkt = Dllp.create_ack((self.next_recv_seq-1) & 0xfff)
            elif self.send_fc.is_set() or (not self.fc_initialized and self.tx_queue.empty()):
                # Send FC DLLP
                # Runs when
                #  - FC timer expires
                #  - FC update DLLP transmit requested
                #  - FC init is not done AND no TLPs are queued for transmit
                if self.send_fc.is_set():
                    # Send FC update DLLP
                    for fc_ch in self.fc_state:
                        if not fc_ch.active or not fc_ch.fi2:
                            continue

                        sim_time = get_sim_time()
                        if fc_ch.next_fc_p_tx <= sim_time:
                            pkt = Dllp()
                            pkt.vc = self.fc_init_vc
                            pkt.type = DllpType.UPDATE_FC_P
                            pkt.hdr_fc = fc_ch.ph.rx_credits_allocated
                            pkt.data_fc = fc_ch.pd.rx_credits_allocated
                            fc_ch.next_fc_p_tx = sim_time + self.fc_update_steps
                            break
                        if fc_ch.next_fc_np_tx <= sim_time:
                            pkt = Dllp()
                            pkt.vc = self.fc_init_vc
                            pkt.type = DllpType.UPDATE_FC_NP
                            pkt.hdr_fc = fc_ch.nph.rx_credits_allocated
                            pkt.data_fc = fc_ch.npd.rx_credits_allocated
                            fc_ch.next_fc_np_tx = sim_time + self.fc_update_steps
                            break
                        if fc_ch.next_fc_cpl_tx <= sim_time:
                            pkt = Dllp()
                            pkt.vc = self.fc_init_vc
                            pkt.type = DllpType.UPDATE_FC_CPL
                            pkt.hdr_fc = fc_ch.cplh.rx_credits_allocated
                            pkt.data_fc = fc_ch.cpld.rx_credits_allocated
                            fc_ch.next_fc_cpl_tx = sim_time + self.fc_update_steps
                            break

                if not self.fc_initialized and not pkt:
                    # Send FC init DLLP
                    fc_ch = self.fc_state[self.fc_init_vc]
                    pkt = Dllp()
                    pkt.vc = self.fc_init_vc
                    if self.fc_init_type == FcType.P:
                        pkt.type = DllpType.INIT_FC1_P if not fc_ch.fi1 else DllpType.INIT_FC2_P
                        pkt.hdr_fc = fc_ch.ph.rx_credits_allocated
                        pkt.data_fc = fc_ch.pd.rx_credits_allocated
                        self.fc_init_type = FcType.NP
                    elif self.fc_init_type == FcType.NP:
                        pkt.type = DllpType.INIT_FC1_NP if not fc_ch.fi1 else DllpType.INIT_FC2_NP
                        pkt.hdr_fc = fc_ch.nph.rx_credits_allocated
                        pkt.data_fc = fc_ch.npd.rx_credits_allocated
                        self.fc_init_type = FcType.CPL
                    elif self.fc_init_type == FcType.CPL:
                        pkt.type = DllpType.INIT_FC1_CPL if not fc_ch.fi1 else DllpType.INIT_FC2_CPL
                        pkt.hdr_fc = fc_ch.cplh.rx_credits_allocated
                        pkt.data_fc = fc_ch.cpld.rx_credits_allocated
                        self.fc_init_type = FcType.P
                        # find next active VC that hasn't finished FC init
                        for k in range(8):
                            vc = (self.fc_init_vc+1+k) % 8
                            if self.fc_state[vc].active and not self.fc_state[vc].fi2:
                                self.fc_init_vc = vc
                                break

                    # check all active VC and report FC not initialized if any are not complete
                    self.fc_initialized = True
                    for vc in range(8):
                        if self.fc_state[vc].active and not self.fc_state[vc].fi2:
                            self.fc_initialized = False

                if not pkt:
                    # no more DLLPs to send, clear event
                    self.send_fc.clear()

            if pkt is not None:
                self.log.debug("Send DLLP %s", pkt)
            elif not self.tx_queue.empty():
                pkt = self.tx_queue.get_nowait()
                pkt.seq = self.next_transmit_seq
                self.log.debug("Send TLP %s", pkt)
                self.next_transmit_seq = (self.next_transmit_seq + 1) & 0xfff
                self.retry_buffer.put_nowait(pkt)

            if pkt:
                await self.handle_tx(pkt)

    async def handle_tx(self, pkt):
        raise NotImplementedError()

    async def ext_recv(self, pkt):
        if isinstance(pkt, Dllp):
            # DLLP
            self.log.debug("Receive DLLP %s", pkt)
            self.handle_dllp(pkt)
        else:
            # TLP
            self.log.debug("Receive TLP %s", pkt)
            if pkt.seq == self.next_recv_seq:
                # expected seq
                self.next_recv_seq = (self.next_recv_seq + 1) & 0xfff
                self.nak_scheduled = False
                self.start_ack_latency_timer()
                pkt = Tlp(pkt)
                self.fc_state[self.classify_tlp_vc(pkt)].rx_process_tlp_fc(pkt)
                self.rx_queue.put_nowait(pkt)
            elif (self.next_recv_seq - pkt.seq) & 0xfff < 2048:
                self.log.warning("Received duplicate TLP, discarding (seq %d, expecting %d)", pkt.seq, self.next_recv_seq)
                self.stop_ack_latency_timer()
                self.send_ack.set()
            else:
                self.log.warning("Received out-of-sequence TLP, sending NAK (seq %d, expecting %d)", pkt.seq, self.next_recv_seq)
                if not self.nak_scheduled:
                    self.nak_scheduled = True
                    self.stop_ack_latency_timer()
                    self.send_ack.set()

    async def _run_receive(self):
        while True:
            tlp = await self.rx_queue.get()
            if self.rx_handler is None:
                raise Exception("Receive handler not set")
            await self.rx_handler(tlp)

    def handle_dllp(self, dllp):
        if dllp.type == DllpType.NOP:
            # discard NOP
            pass
        elif dllp.type in {DllpType.ACK, DllpType.NAK}:
            # ACK or NAK
            if (((self.next_transmit_seq-1) & 0xfff) - dllp.seq) & 0xfff > 2048:
                self.log.warning("Received ACK/NAK DLLP for future TLP, discarding (seq %d, next TX %d, ACK %d)",
                    dllp.seq, self.next_transmit_seq, self.ackd_seq)
            elif (dllp.seq - self.ackd_seq) & 0xfff > 2048:
                self.log.warning("Received ACK/NAK DLLP for previously-ACKed TLP, discarding (seq %d, next TX %d, ACK %d)",
                    dllp.seq, self.next_transmit_seq, self.ackd_seq)
            else:
                while dllp.seq != self.ackd_seq:
                    # purge TLPs from retry buffer
                    self.retry_buffer.get_nowait()
                    self.ackd_seq = (self.ackd_seq + 1) & 0xfff
                    self.log.debug("ACK TLP seq %d", self.ackd_seq)
                if dllp.type == DllpType.NAK:
                    # retransmit
                    self.log.warning("Got NAK DLLP, start TLP replay")
                    raise Exception("TODO")
        elif dllp.type in {DllpType.INIT_FC1_P, DllpType.INIT_FC1_NP, DllpType.INIT_FC1_CPL,
                DllpType.INIT_FC2_P, DllpType.INIT_FC2_NP, DllpType.INIT_FC2_CPL,
                DllpType.UPDATE_FC_P, DllpType.UPDATE_FC_NP, DllpType.UPDATE_FC_CPL}:
            # Flow control
            self.fc_state[dllp.vc].handle_fc_dllp(dllp)
        else:
            raise Exception("TODO")

    def start_ack_latency_timer(self):
        if self._ack_latency_timer_cr is not None:
            if not self._ack_latency_timer_cr._finished:
                # already running
                return
        self._ack_latency_timer_cr = cocotb.fork(self._run_ack_latency_timer())

    def stop_ack_latency_timer(self):
        if self._ack_latency_timer_cr is not None:
            self._ack_latency_timer_cr.kill()
            self._ack_latency_timer_cr = None

    async def _run_ack_latency_timer(self):
        d = int(self.time_scale * self.max_latency_timer)
        await Timer(max(d, 1), 'step')
        if not self.nak_scheduled:
            self.send_ack.set()

    def start_fc_update_timer(self):
        if self._fc_update_timer_cr is not None:
            if not self._fc_update_timer_cr._finished:
                # already running
                return
        self._fc_update_timer_cr = cocotb.fork(self._run_fc_update_timer())

    def stop_fc_update_timer(self):
        if self._fc_update_timer_cr is not None:
            self._fc_update_timer_cr.kill()
            self._fc_update_timer_cr = None

    async def _run_fc_update_timer(self):
        d = int(self.time_scale * self.max_latency_timer)
        await Timer(max(d, 1), 'step')
        self.send_fc.set()

    async def _run_fc_update_idle_timer(self):
        while True:
            await Timer(self.fc_idle_timer_steps, 'step')
            self.send_fc.set()