def test_write(self, N=20, randomize=False): u = self.u s_w = u.s_w axi = u.m m = AxiSimRam(axi=axi) M_DW = axi.DATA_WIDTH FRAME_WORD_CNT = ceil((u.S_ADDR_STEP) / M_DW) w_data = [ i # self._rand.getrandbits(M_DW) for i in range(N * FRAME_WORD_CNT) ] # create data words for P4AppPort wr_data = self.pack_words(w_data, M_DW, s_w.DATA_WIDTH) for addr, frame in enumerate(wr_data): s_w._ag.data.append((addr, frame)) if randomize: axi_randomize_per_channel(self, axi) self.runSim(N * FRAME_WORD_CNT * 10 * CLK_PERIOD) w_m = mask( s_w.DATA_WIDTH) if s_w.DATA_WIDTH < axi.DATA_WIDTH else mask( axi.DATA_WIDTH) addr = u.M_ADDR_OFFSET inMem = m.getArray(addr, M_DW // 8, FRAME_WORD_CNT * N) inMem = [None if v is None else v & w_m for v in inMem] self.assertValSequenceEqual(inMem, w_data)
def test_read(self, N=10, randomize=False): u = self.u s_r = u.s_r axi = u.m m = AxiSimRam(axi=axi) M_DW = axi.DATA_WIDTH FRAME_WORD_CNT = ceil(u.S_ADDR_STEP / M_DW) r_data = [ i # self._rand.getrandbits(M_DW) for i in range(N * FRAME_WORD_CNT) ] # create data words for P4AppPort rd_data = self.pack_words(r_data, M_DW, s_r.DATA_WIDTH) for index, d in enumerate(r_data): index = (u.M_ADDR_OFFSET * 8 // M_DW) + index m.data[index] = d for addr, _ in enumerate(rd_data): s_r.addr._ag.data.append(addr) if randomize: axi_randomize_per_channel(self, axi) self.runSim(N * FRAME_WORD_CNT * 12 * CLK_PERIOD) readed = s_r.data._ag.data self.assertEqual(len(readed), len(rd_data)) for addr, (d_ref, d) in enumerate(zip(rd_data, readed)): self.assertValEqual(d, d_ref, addr)
def _test_read(self, id_addr_tuples, randomize=False, REF_DATA=0x1000, time_multiplier=2): u = self.u mem = AxiSimRam(u.m) WORD_SIZE = self.WORD_SIZE trans_len = ceil(u.CACHE_LINE_SIZE / WORD_SIZE) for trans_id, addr in id_addr_tuples: for i in range(trans_len): mem.data[addr // WORD_SIZE + i] = addr + i + REF_DATA trans = u.s._ag.create_addr_req(addr, trans_len - 1, _id=trans_id) u.s.ar._ag.data.append(trans) t = ceil((len(id_addr_tuples) * trans_len + 10) * time_multiplier * CLK_PERIOD ) if randomize: self.randomize_all() t *= 3 self.runSim(t) ref_data = sorted(flatten([ [(_id, addr + i + REF_DATA, RESP_OKAY, int(i == trans_len - 1)) for i in range(trans_len)] for _id, addr in id_addr_tuples], level=1)) data = sorted(allValuesToInts(u.s.r._ag.data)) # print("") # print(ref_data) # print(data) self.assertSequenceEqual(data, ref_data)
def test_randomized(self, N=24): u = self.u if u.AXI_CLS in (Axi3Lite, Axi4Lite): m = Axi4LiteSimRam(axi=u.axi) else: m = AxiSimRam(axi=u.axi) MAGIC = 99 self.randomize(u.driver.r) self.randomize(u.driver.req) self.randomize(u.axi.ar) self.randomize(u.axi.r) r_ref = [] for _ in range(N): size = int(self._rand.random() * self.LEN_MAX_VAL) + 1 data = [MAGIC + i2 for i2 in range(size)] a = m.calloc(size, u.DATA_WIDTH // 8, initValues=data) _, _r_ref = self.spotReadMemcpyTransactions(a, size - 1, None, data=data) r_ref.extend(_r_ref) MAGIC += size self.runSim(len(r_ref) * 5 * CLK_PERIOD) self.assertEmpty(u.driver.req._ag.data) self.assertValSequenceEqual(u.driver.r._ag.data, r_ref)
def test_mergable(self, N=10, ADDRESSES=[ 0, ], randomized=False): u = self.u mem = AxiSimRam(u.m) expected = {} for a in ADDRESSES: for i in range(N): B_i = i % (u.CACHE_LINE_SIZE) d = i << (B_i * 8) m = 1 << B_i u.w._ag.data.append((a, d, m)) v = expected.get(a, 0) v = set_bit_range(v, B_i * 8, 8, i) expected[a] = v t = (N * len(ADDRESSES) + 10) * 3 * \ u.BUS_WORDS_IN_CACHE_LINE * CLK_PERIOD if randomized: #t *= 2 self.randomize_all() self.runSim(t) data = mem.getArray(0, u.CACHE_LINE_SIZE, max(ADDRESSES) + 1) for a in ADDRESSES: self.assertValEqual( data[a], expected[a], "%d: expected 0x%08x got 0x%08x, 0x%08x" % (a, expected[a], data[a].val, data[a].vld_mask))
def test_with_mem(self, N=10, randomized=False): u = self.u mem = AxiSimRam(u.m) u.w._ag.data.extend( (i, 10 + i, mask(u.CACHE_LINE_SIZE)) for i in range(N)) if randomized: self.randomize_all() self.runSim((N + 10) * 3 * CLK_PERIOD * u.BUS_WORDS_IN_CACHE_LINE) mem_val = mem.getArray(0, u.CACHE_LINE_SIZE, N) self.assertValSequenceEqual(mem_val, [10 + i for i in range(N)])
def test_3x128(self, N=128): u = self.u m = AxiSimRam(axiAW=u.aw, axiW=u.w, axiB=u.b) _mask = mask(self.DATA_WIDTH // 8) data = [[self._rand.getrandbits(self.DATA_WIDTH) for _ in range(N)] for _ in range(self.DRIVER_CNT)] dataAddress = [ m.malloc(N * self.DATA_WIDTH // 8) for _ in range(self.DRIVER_CNT) ] for di, _data in enumerate(data): req = u.drivers[di].req._ag wIn = u.drivers[di].w._ag dataIt = iter(_data) addr = dataAddress[di] end = False while True: frameSize = self._rand.getrandbits(4) + 1 frame = [] try: for _ in range(frameSize): frame.append(next(dataIt)) except StopIteration: end = True if frame: req.data.append( Axi_datapumpTC.mkReq(self, addr, len(frame) - 1)) wIn.data.extend([(d, _mask, i == len(frame) - 1) for i, d in enumerate(frame)]) addr += len(frame) * self.DATA_WIDTH // 8 if end: break r = self.randomize for d in u.drivers: r(d.req) r(d.w) r(d.ack) r(u.aw) r(u.w) r(u.b) self.runSim(self.DRIVER_CNT * N * 40 * Time.ns) for i, baseAddr in enumerate(dataAddress): inMem = m.getArray(baseAddr, self.DATA_WIDTH // 8, N) self.assertValSequenceEqual(inMem, data[i], f"driver:{i:d}")
def test_mergable2(self, N=10, ADDRESSES=[ 0, ], randomized=False): """ same as test_mergable just the inner cycle is reversed """ u = self.u mem = AxiSimRam(u.m) expected = {} for i in range(N): offset = i * N for a in ADDRESSES: B_i = (i % 4) _i = ((offset + i) % 0xff) d = _i << (B_i * 8) m = 1 << B_i u.w._ag.data.append((a, d, m)) v = expected.get(a, 0) v = set_bit_range(v, B_i * 8, 8, _i) expected[a] = v if randomized: self.randomize_all() self.runSim((N * len(ADDRESSES) + 10) * 3 * u.BUS_WORDS_IN_CACHE_LINE * CLK_PERIOD) for a in ADDRESSES: self.assertValEqual(mem.data[a], expected[a], "%d: 0x%08x" % (a, expected[a]))
def test_write(self): N = self.TRANSACTION_CNT u = self.u m = AxiSimRam(u.m) expected_data = [] allocated_wods = list(range(N)) shuffle(allocated_wods, random=self._rand.random) for word_i in allocated_wods: rand_data = self._rand.getrandbits(u.DATA_WIDTH) a_t = self.addr_trans(word_i) u.s.aw._ag.data.append(a_t) w_t = self.w_trans(rand_data) u.s.w._ag.data.append(w_t) expected_data.append((word_i, rand_data)) self.runSim(N * 3 * CLK_PERIOD) for word_i, expected in expected_data: d = m.data.get(word_i, None) self.assertValEqual(d, expected)
def setUp(self): SimTestCase.setUp(self) u = self.u self.m = AxiSimRam(axi=u.m) # clear counters for i in range(2 ** u.ADDR_WIDTH // (u.DATA_WIDTH // 8)): self.m.data[i] = 0
def test_1024random(self): u = self.u req = u.driver._ag.req wIn = u.driver.w._ag dataMask = mask(u.DATA_WIDTH // 8) m = AxiSimRam(axi=u.axi) N = 1024 data = [self._rand.getrandbits(u.DATA_WIDTH) for _ in range(N)] buff = m.malloc(N * (u.DATA_WIDTH // 8)) dataIt = iter(data) end = False addr = 0 while True: frameSize = self._rand.getrandbits( self.LEN_MAX_VAL.bit_length()) + 1 frame = [] try: for _ in range(frameSize): frame.append(next(dataIt)) except StopIteration: end = True if frame: req.data.append(self.mkReq(addr, len(frame) - 1)) wIn.data.extend([(d, dataMask, i == len(frame) - 1) for i, d in enumerate(frame)]) addr += len(frame) * u.DATA_WIDTH // 8 if end: break ra = self.randomize ra(u.axi.aw) ra(u.axi.b) ra(u.driver.req) ra(u.driver.ack) ra(u.axi.w) ra(u.driver.w) self.runSim(N * 5 * CLK_PERIOD) inMem = m.getArray(buff, u.DATA_WIDTH // 8, N) self.assertValSequenceEqual(inMem, data)
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'])
def test_read(self): N = self.TRANSACTION_CNT u = self.u m = AxiSimRam(u.m) expected_data = [] allocated_wods = list(range(N)) shuffle(allocated_wods, random=self._rand.random) for word_i in allocated_wods: rand_data = self._rand.getrandbits(u.DATA_WIDTH) a_t = self.addr_trans(word_i) m.data[word_i] = rand_data u.s.ar._ag.data.append(a_t) expected_data.append((rand_data, RESP_OKAY)) self.runSim(N * 3 * CLK_PERIOD) self.assertValSequenceEqual(u.s.r._ag.data, expected_data)
def test_simpleTransfer(self): u = self.u regs = self.regs N = 33 sampleData = [ self._rand.getrandbits(self.DATA_WIDTH) for _ in range(N) ] m = AxiSimRam(u.axi) blockPtr = m.malloc(self.DATA_WIDTH // 8 * N) u.dataIn._ag.data.extend(sampleData) regs.baseAddr.write(blockPtr) regs.control.write(1) self.runSim(N * 3 * CLK_PERIOD) self.assertValSequenceEqual( m.getArray(blockPtr, self.DATA_WIDTH // 8, N), sampleData)
def setUp(self): super(AxiTesterTC, self).setUp() u = self.u self.m = AxiSimRam(u.m_axi)
def test_simpleUnalignedWithData(self, N=1, WORDS=1, OFFSET_B=None, randomize=False): u = self.u req = u.driver._ag.req if randomize: self.randomize(u.driver.req) self.randomize(u.driver.r) self.randomize(u.axi.ar) self.randomize(u.axi.r) if u.AXI_CLS in (Axi3Lite, Axi4Lite): m = Axi4LiteSimRam(axi=u.axi) else: m = AxiSimRam(axi=u.axi) if OFFSET_B is None: if self.ALIGNAS == self.DATA_WIDTH: # to trigger an alignment error OFFSET_B = 1 else: OFFSET_B = self.ALIGNAS // 8 addr_step = u.DATA_WIDTH // 8 offset = 8 ref_r_frames = [] for i in range(N): data = [ (i + i2) & 0xff for i2 in range((WORDS + 1) * addr_step)] a = m.calloc((WORDS + 1) * addr_step, 1, initValues=data) rem = (self.CHUNK_WIDTH % self.DATA_WIDTH) // 8 req.data.append(self.mkReq(a + OFFSET_B, WORDS - 1, rem=rem)) if rem == 0: rem = self.DATA_WIDTH ref_r_frames.append(data[OFFSET_B:((WORDS - 1) * addr_step) + rem + OFFSET_B]) t = (10 + N) * CLK_PERIOD if randomize: t *= 6 self.runSim(t) if u.ALIGNAS == u.DATA_WIDTH: # unsupported alignment check if error is set self.assertValEqual(u.errorAlignment._ag.data[-1], 1) else: if u.ALIGNAS != 8: # if alignment is on 1B the but the errorAlignment can not happen self.assertValEqual(u.errorAlignment._ag.data[-1], 0) ar_ref = [] if u.axi.LEN_WIDTH == 0: for i in range(N): for w_i in range(WORDS + 1): ar_ref.append( self.aTrans(0x100 + (i + w_i) * addr_step, WORDS, 0) ) else: for i in range(N): ar_ref.append( self.aTrans(0x100 + i * addr_step, WORDS, 0) ) driver_r = u.driver.r._ag.data for ref_frame in ref_r_frames: offset = None r_data = [] for w_i in range(WORDS): data, strb, last = driver_r.popleft() self.assertValEqual(last, int(w_i == WORDS - 1)) for B_i in range(addr_step): if strb[B_i]: if offset is None: offset = B_i + (addr_step * w_i) B = int(data[(B_i + 1) * 8: B_i * 8]) r_data.append(B) self.assertEqual(offset, 0) self.assertSequenceEqual(r_data, ref_frame) self.assertEmpty(u.axi.ar._ag.data) self.assertEmpty(u.axi.r._ag.data)
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())
def setUp(self): SimTestCase.setUp(self) u = self.u self.memory = [AxiSimRam(axi=s) for s in u.m]
def setUp(self): SimTestCase.setUp(self) u = self.u self.m = AxiSimRam(axi=u.m)