Beispiel #1
0
    def test_simpleOp(self):
        DW = self.DW
        u = self.u
        r = self.randomize
        r(u.axi_m.ar)
        r(u.axi_m.r)
        r(u.axi_m.aw)
        r(u.axi_m.w)
        r(u.axi_m.b)

        m = AxiSimRam(u.axi_m)
        tmpl = TransTmpl(frameHeader)
        frameTmpl = list(FrameTmpl.framesFromTransTmpl(tmpl, DW))[0]

        def randFrame():
            rand = self._rand.getrandbits
            data = {
                "eth": {
                    "src": rand(48),
                    "dst": rand(48),
                },
                "ipv4": {
                    "src": rand(32),
                    "dst": rand(32),
                }
            }
            d = list(frameTmpl.packData(data))
            ptr = m.calloc(
                ceil(frameHeader.bit_length() / DW),
                DW // 8,
                initValues=d,
                keepOut=self.OFFSET,
            )
            return ptr, data

        framePtr, frameData = randFrame()
        u.packetAddr._ag.data.append(framePtr)

        self.runSim(100 * CLK_PERIOD)
        updatedFrame = m.getStruct(framePtr, tmpl)
        self.assertValEqual(updatedFrame.eth.src, frameData["eth"]['dst'])
        self.assertValEqual(updatedFrame.eth.dst, frameData["eth"]['src'])
        self.assertValEqual(updatedFrame.ipv4.src, frameData["ipv4"]['dst'])
        self.assertValEqual(updatedFrame.ipv4.dst, frameData["ipv4"]['src'])
Beispiel #2
0
class OooOpExampleCounterHashTable_TC(SimTestCase):
    @classmethod
    def setUpClass(cls):
        u = cls.u = OooOpExampleCounterHashTable()
        # MAIN_STATE_T = HStruct(
        #     (BIT, "item_valid"),
        #     (Bits(32), "key"),
        #     (Bits(self.DATA_WIDTH - 32 - 1), "value"),
        # )
        # # the transaction always just increments the counter
        # # so there is no need for transaction state
        # TRANSACTION_STATE_T = HStruct(
        #     # if true the key was modified during processing
        #     # and we need to recirculate the transaction in pipeline
        #     # (which should be done by parent component and it does not happen automatically)
        #     (BIT, "reset"),
        #     (self.MAIN_STATE_T, "data"),
        #     # for output 1 if key was same as key in lookup transaction
        #     (BIT, "key_match"),
        #     (Bits(2), "operation"), # :see: :class:`~.OPERATION`
        # )

        u.ID_WIDTH = 2
        u.ADDR_WIDTH = u.ID_WIDTH + 3
        cls.compileSim(u)

    def setUp(self):
        SimTestCase.setUp(self)
        u = self.u
        self.m = AxiSimRam(axi=u.m)

    def test_nop(self):
        u = self.u

        self.runSim(10 * CLK_PERIOD)
        self.assertEmpty(u.dataOut._ag.data)
        self.assertEmpty(u.m.aw._ag.data)
        self.assertEmpty(u.m.w._ag.data)
        self.assertEmpty(u.m.ar._ag.data)

    def _test_incr(self, inputs, randomize=False, mem_init={}):
        u = self.u
        ADDR_ITEM_STEP = 2**u.ADDR_OFFSET_W
        for i in range(2**u.ADDR_WIDTH // ADDR_ITEM_STEP):
            v = mem_init.get(i, 0)
            if v != 0:
                item_valid, key, value = v
                v = u.MAIN_STATE_T.from_py({
                    "item_valid": item_valid,
                    "key": key,
                    "value": value
                })
                v = v._reinterpret_cast(u.m.w.data._dtype)
            self.m.data[i] = v

        u.dataIn._ag.data.extend(inputs)

        t = (40 + len(inputs) * 3) * CLK_PERIOD
        if randomize:
            axi_randomize_per_channel(self, u.m)
            self.randomize(u.dataIn)
            self.randomize(u.dataOut)
            t *= 5

        self.runSim(t)

        # check if pipeline registers are empty
        for i in range(u.PIPELINE_CONFIG.WAIT_FOR_WRITE_ACK):
            valid = getattr(self.rtl_simulator.model.io, f"st{i:d}_valid")
            self.assertValEqual(valid.read(), 0, i)

        # check if main state fifo is empty
        ooo_fifo = self.rtl_simulator.model.ooo_fifo_inst.io
        self.assertValEqual(ooo_fifo.item_valid.read(), 0)
        self.assertValEqual(ooo_fifo.read_wait.read(), 1)

        # check if all transactions on AXI are finished
        self.assertEmpty(u.m.b._ag.data)
        self.assertEmpty(u.m.r._ag.data)

        # check output data itself
        dout = u.dataOut._ag.data
        mem = copy(mem_init)
        for _in, _out in zip(inputs, dout):
            (addr, (reset, (key_vld, key, data), _, operation)) = _in
            (
                o_addr,
                (o_found_key_vld, o_found_key, o_found_data),
                (o_reset, (o_key_vld, o_key, o_data), o_match, o_operation),
            ) = _out
            # None or tuple(item_valid, key, data)
            cur = mem.get(addr, None)
            aeq = self.assertValEqual
            aeq(o_addr, addr)
            if operation == OP.LOOKUP:
                # lookup and increment if found
                if cur is not None and cur[0] and int(cur[1]) == key:
                    # lookup sucess
                    aeq(o_reset, 0)
                    aeq(o_match, 1)
                    aeq(o_found_key_vld, 1)
                    aeq(o_found_key, key)
                    aeq(o_found_data, cur[2] + 1)
                    aeq(o_found_key_vld, 1)

                    mem[addr] = (1, key, int(o_found_data))

                else:
                    # lookup fail
                    aeq(o_reset, 0)
                    aeq(o_match, 0)
                    # key remained same
                    aeq(o_key_vld, key_vld)
                    aeq(o_key, key)
                    aeq(o_data, data)
                    # there was nothing so nothig should have been found
                    aeq(o_found_key_vld, int(cur is not None and cur[0]))

            elif operation == OP.LOOKUP_OR_SWAP:
                # lookup and increment or swap if not found
                if cur is not None and cur[0] and int(cur[1]) == key:
                    # lookup sucess
                    aeq(o_reset, 0)
                    aeq(o_match, 1)
                    aeq(o_found_key_vld, 1)
                    aeq(o_found_key, key)
                    aeq(o_found_data, cur[2] + 1)
                    aeq(o_found_key_vld, 1)
                    mem[addr] = (1, key, int(o_found_data))
                else:
                    # swap
                    raise NotImplementedError()
            elif operation == OP.SWAP:
                # swap no matter if the key was found or not, do not increment
                raise NotImplementedError()
            else:
                raise ValueError(operation)

            self.assertValEqual(o_operation, operation)

        self.assertEqual(len(dout), len(inputs))
        # for i in sorted(set(inputs)):
        #    self.assertValEqual(self.m.data[i], inputs.count(i), i)
        for i in range(2**u.ADDR_WIDTH // ADDR_ITEM_STEP):
            v = self.m.getStruct(i * ADDR_ITEM_STEP, u.MAIN_STATE_T)
            ref_v = mem.get(i, None)
            if ref_v is None or not ref_v[0]:
                aeq(v.item_valid, 0)
            else:
                aeq(v.item_valid, 1)
                aeq(v.key, ref_v[1])
                aeq(v.value, ref_v[2])

    def test_1x_not_found(self):
        self._test_incr([
            (0, TState(0, None, OP.LOOKUP)),
        ])

    def test_r_100x_not_found(self):
        index_pool = list(range(2**self.u.ID_WIDTH))
        self._test_incr([(self._rand.choice(index_pool),
                          TState(0, None, OP.LOOKUP)) for _ in range(100)])

    def test_1x_lookup_found(self):
        self._test_incr([
            (1, TState(99, None, OP.LOOKUP)),
        ],
                        mem_init={1: MState(99, 20)})

    def test_r_100x_lookup_found(self):
        item_pool = [(i, MState(i + 1, 20 + i))
                     for i in range(2**self.u.ID_WIDTH)]

        self._test_incr(
            [(i, TState(v[1], None, OP.LOOKUP))
             for i, v in [self._rand.choice(item_pool) for _ in range(100)]],
            mem_init={i: v
                      for i, v in item_pool})

    def test_r_100x_lookup_found_not_found_mix(self):
        N = 100
        max_id = 2**self.u.ID_WIDTH
        item_pool = [(i % max_id, MState(i + 1, 20 + i))
                     for i in range(max_id * 2)]

        self._test_incr(
            [(i, TState(v[1], None, OP.LOOKUP))
             for i, v in [self._rand.choice(item_pool) for _ in range(N)]],
            # :attention: i is modulo mapped that means that
            #     mem_init actually contains only last "n" items from item_pool
            mem_init={i: v
                      for i, v in item_pool})

    def test_1x_lookup_or_swap_found(self):
        self._test_incr([
            (1, TState(99, None, OP.LOOKUP_OR_SWAP)),
        ],
                        mem_init={1: MState(99, 20)})

    def test_no_comb_loops(self):
        s = CombLoopAnalyzer()
        s.visit_Unit(self.u)
        comb_loops = freeze_set_of_sets(s.report())
        # for loop in comb_loops:
        #     print(10 * "-")
        #     for s in loop:
        #         print(s.resolve()[1:])

        self.assertEqual(comb_loops, frozenset())