Example #1
0
        def master(dut, port, num):
            # Choose operation types based on port mode
            ops_choice = {
                "both":  ["w", "r"],
                "write": ["w"],
                "read":  ["r"],
            }[port.mode]
            driver = NativePortDriver(port)

            for i in range(n_ops):
                bank = prng.randrange(n_banks)
                # We will later distinguish data by its row address
                row = num
                col = 0x20 * num + i
                addr = dut.addr_port(bank=bank, row=row, col=col)
                addr_iface = dut.addr_iface(row=row, col=col)
                if prng.choice(ops_choice) == "w":
                    yield from driver.write(addr, data=i)
                    produced[num].append(self.W(bank, addr_iface, data=i, we=0xff))
                else:
                    yield from driver.read(addr)
                    produced[num].append(self.R(bank, addr_iface, data=None))

            for _ in range(8):
                yield
Example #2
0
    def crossbar_stress_test(self, dut, ports, n_banks, n_ops, clocks=None):
        # Runs simulation with multiple masters writing and reading to multiple banks
        controller = ControllerStub(
            dut.interface,
            write_latency=dut.settings.phy.write_latency,
            read_latency=dut.settings.phy.read_latency)
        # Store data produced per master
        produced = defaultdict(list)
        prng = random.Random(42)

        def master(dut, driver, num):
            # Choose operation types based on port mode
            ops_choice = {
                "both": ["w", "r"],
                "write": ["w"],
                "read": ["r"],
            }[driver.port.mode]

            for i in range(n_ops):
                bank = prng.randrange(n_banks)
                # We will later distinguish data by its row address
                row = num
                col = 0x20 * num + i
                addr = dut.addr_port(bank=bank, row=row, col=col)
                addr_iface = dut.addr_iface(row=row, col=col)
                if prng.choice(ops_choice) == "w":
                    yield from driver.write(addr, data=i)
                    produced[num].append(
                        self.W(bank, addr_iface, data=i, we=0xff))
                else:
                    yield from driver.read(addr)
                    produced[num].append(self.R(bank, addr_iface, data=None))

            yield from driver.wait_all()

        generators = defaultdict(list)
        for i, port in enumerate(ports):
            driver = NativePortDriver(port)
            generators[port.clock_domain].append(master(dut, driver, i))
            generators[port.clock_domain].extend(driver.generators())
        generators["sys"] += controller.generators()
        generators["sys"].append(timeout_generator(80 * n_ops))

        sim_kwargs = {}
        if clocks is not None:
            sim_kwargs["clocks"] = clocks
        run_simulation(dut, generators, **sim_kwargs)

        # Split controller data by master, as this is what we want to compare
        consumed = defaultdict(list)
        for data in controller.data:
            master = data.addr >> (dut.settings.geom.colbits -
                                   dut.address_align)
            if isinstance(data, self.R):
                # Master couldn't know the data when it was sending
                data = data._replace(data=None)
            consumed[master].append(data)

        return produced, consumed, controller.data
Example #3
0
 def producer(dut, port):
     driver = NativePortDriver(port)
     for t in transfers:
         addr = dut.addr_port(bank=t["bank"], row=t["row"], col=t["col"])
         if t["rw"] == self.W:
             yield from driver.write(addr, data=t["data"], we=t.get("we", None))
         elif t["rw"] == self.R:
             data = (yield from driver.read(addr))
             reads.append(data)
         else:
             raise TypeError(t["rw"])
Example #4
0
 def master_a(dut, port):
     driver = NativePortDriver(port)
     adr    = functools.partial(dut.addr_port, row=1, col=1)
     write  = functools.partial(driver.write, wait_data=False)
     yield from write(adr(bank=0), data=0x10)
     yield from write(adr(bank=1), data=0x11)
     yield from write(adr(bank=0), data=0x12, wait_data=True)
Example #5
0
    def test_address_mappings(self):
        # Verify that address is translated correctly.
        reads = []

        def producer(dut, driver):
            for t in transfers:
                addr = dut.addr_port(bank=t["bank"],
                                     row=t["row"],
                                     col=t["col"])
                if t["rw"] == self.W:
                    yield from driver.write(addr,
                                            data=t["data"],
                                            we=t.get("we", None))
                elif t["rw"] == self.R:
                    data = (yield from driver.read(addr))
                    reads.append(data)
                else:
                    raise TypeError(t["rw"])

        geom_settings = dict(colbits=10, rowbits=13, bankbits=2)
        dut = CrossbarDUT(geom_settings=geom_settings)
        port = dut.crossbar.get_port()
        driver = NativePortDriver(port)
        transfers = [
            dict(rw=self.W, bank=2, row=0x30, col=0x03, data=0x20),
            dict(rw=self.W, bank=3, row=0x30, col=0x03, data=0x21),
            dict(rw=self.W, bank=2, row=0xab, col=0x03, data=0x22),
            dict(rw=self.W, bank=2, row=0x30, col=0x13, data=0x23),
            dict(rw=self.R, bank=1, row=0x10, col=0x99),
            dict(rw=self.R, bank=0, row=0x10, col=0x99),
            dict(rw=self.R, bank=1, row=0xcd, col=0x99),
            dict(rw=self.R, bank=1, row=0x10, col=0x77),
        ]
        expected = []
        read_data = ControllerStub.read_data_counter()
        for i, t in enumerate(transfers):
            cls = t["rw"]
            addr = dut.addr_iface(row=t["row"], col=t["col"])
            if cls == self.W:
                kwargs = dict(data=t["data"], we=0xff)
            elif cls == self.R:
                kwargs = dict(data=next(read_data))
            expected.append(cls(bank=t["bank"], addr=addr, **kwargs))

        data = self.crossbar_test(dut, [producer(dut, driver)] +
                                  driver.generators())
        self.assertEqual(data, expected)
Example #6
0
 def master_b(dut, port):
     driver = NativePortDriver(port)
     adr = functools.partial(dut.addr_port, row=2, col=2)
     read = functools.partial(driver.read, wait_data=False)
     yield from read(adr(bank=1))
     yield from read(adr(bank=1))
     yield from read(adr(bank=1))
     yield from read(adr(bank=1))
     yield from read(adr(bank=1))
Example #7
0
 def master_b(dut, port):
     driver = NativePortDriver(port)
     adr    = functools.partial(dut.addr_port, row=2, col=2)
     write  = functools.partial(driver.write, wait_data=False)
     yield from write(adr(bank=1), data=0x20)
     yield from write(adr(bank=1), data=0x21)
     yield from write(adr(bank=1), data=0x22)
     yield from write(adr(bank=1), data=0x23)
     yield from write(adr(bank=1), data=0x24)
Example #8
0
 def master_a(dut, port):
     driver = NativePortDriver(port)
     adr = functools.partial(dut.addr_port, row=1, col=1)
     read = functools.partial(driver.read, wait_data=False)
     yield from read(adr(bank=0))
     yield from read(adr(bank=1))
     yield from read(adr(bank=0))
     # Wait for read data to show up
     for _ in range(16):
         yield
Example #9
0
    def test_arbitration(self):
        # Create multiple masters that write to the same bank at the same time and verify that all
        # the requests have been sent correctly.
        def producer(dut, driver, num):
            addr = dut.addr_port(bank=3, row=0x10 + num, col=0x20 + num)
            yield from driver.write(addr, data=0x30 + num)

        dut = CrossbarDUT()
        ports = [dut.crossbar.get_port() for _ in range(4)]
        drivers = [NativePortDriver(port) for port in ports]
        masters = [
            producer(dut, driver, i) for i, driver in enumerate(drivers)
        ]
        generators = masters
        for driver in drivers:
            generators.extend(driver.generators())
        data = self.crossbar_test(dut, generators)
        expected = {
            self.W(bank=3,
                   addr=dut.addr_iface(row=0x10, col=0x20),
                   data=0x30,
                   we=0xff),
            self.W(bank=3,
                   addr=dut.addr_iface(row=0x11, col=0x21),
                   data=0x31,
                   we=0xff),
            self.W(bank=3,
                   addr=dut.addr_iface(row=0x12, col=0x22),
                   data=0x32,
                   we=0xff),
            self.W(bank=3,
                   addr=dut.addr_iface(row=0x13, col=0x23),
                   data=0x33,
                   we=0xff),
        }
        self.assertEqual(set(data), expected)
Example #10
0
    def test_lock_write(self):
        # Verify that the locking mechanism works
        # Create a situation when one master A wants to write to banks 0 then 1, but master B is
        # continuously writing to bank 1 (bank is locked) so that master A is blocked. We use
        # wait_data=False because we are only concerned about sending commands fast enough for
        # the lock to be held continuously.
        def master_a(dut, driver):
            adr = functools.partial(dut.addr_port, row=1, col=1)
            write = functools.partial(driver.write, wait_data=False)
            yield from write(adr(bank=0), data=0x10)
            yield from write(adr(bank=1), data=0x11)
            yield from write(adr(bank=0), data=0x12, wait_data=True)

        def master_b(dut, driver):
            adr = functools.partial(dut.addr_port, row=2, col=2)
            write = functools.partial(driver.write, wait_data=False)
            yield from write(adr(bank=1), data=0x20)
            yield from write(adr(bank=1), data=0x21)
            yield from write(adr(bank=1), data=0x22)
            yield from write(adr(bank=1), data=0x23)
            yield from write(adr(bank=1), data=0x24)

        dut = CrossbarDUT()
        ports = [dut.crossbar.get_port() for _ in range(2)]
        drivers = [NativePortDriver(port) for port in ports]
        masters = [master_a(dut, drivers[0]), master_b(dut, drivers[1])]
        data = self.crossbar_test(
            dut, masters + drivers[0].generators() + drivers[1].generators())
        expected = [
            self.W(bank=0,
                   addr=dut.addr_iface(row=1, col=1),
                   data=0x10,
                   we=0xff),  # A
            self.W(bank=1,
                   addr=dut.addr_iface(row=2, col=2),
                   data=0x20,
                   we=0xff),  #  B
            self.W(bank=1,
                   addr=dut.addr_iface(row=2, col=2),
                   data=0x21,
                   we=0xff),  #  B
            self.W(bank=1,
                   addr=dut.addr_iface(row=2, col=2),
                   data=0x22,
                   we=0xff),  #  B
            self.W(bank=1,
                   addr=dut.addr_iface(row=2, col=2),
                   data=0x23,
                   we=0xff),  #  B
            self.W(bank=1,
                   addr=dut.addr_iface(row=2, col=2),
                   data=0x24,
                   we=0xff),  #  B
            self.W(bank=1,
                   addr=dut.addr_iface(row=1, col=1),
                   data=0x11,
                   we=0xff),  # A
            self.W(bank=0,
                   addr=dut.addr_iface(row=1, col=1),
                   data=0x12,
                   we=0xff),  # A
        ]
        self.assertEqual(data, expected)
Example #11
0
 def producer(dut, port, num):
     driver = NativePortDriver(port)
     addr = dut.addr_port(bank=3, row=0x10 + num, col=0x20 + num)
     yield from driver.write(addr, data=0x30 + num)