def test_non_mergable_no_ack(self, N=10, randomized=False): u = self.u 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) * 2 * CLK_PERIOD * u.BUS_WORDS_IN_CACHE_LINE) SIZE = 2**u.ID_WIDTH aw = u.m.aw._ag self.assertValSequenceEqual(aw.data, [ aw.create_addr_req(addr=u.CACHE_LINE_SIZE * i, _len=u.BUS_WORDS_IN_CACHE_LINE - 1, _id=i) for i in range(min(SIZE, N)) ]) w_ref = [] for i in range(min(SIZE, N)): for last, w_i in iter_with_last(range(u.BUS_WORDS_IN_CACHE_LINE)): d = (10 + i if w_i == 0 else 0, mask(u.DATA_WIDTH // 8), int(last)) w_ref.append(d) # for i, (x0, x1) in enumerate(zip(u.m.w._ag.data, w_ref)): # print(i, allValuesToInts(x0), x1) self.assertValSequenceEqual(u.m.w._ag.data, w_ref) # 1 item is currently handled by agent, 1 item in tmp reg self.assertEqual(len(u.w._ag.data), N - SIZE - 1 - 1)
def bitsArithOp__val(self: Bits3val, other: Union[Bits3val, int], evalFn) -> "Bits3val": """ Apply arithmetic operator """ if isinstance(other, int): other = self._dtype.from_py(other) v = self.__copy__() self_vld = self._is_full_valid() other_vld = other._is_full_valid() v.val = evalFn(self.val, other.val) w = v._dtype.bit_length() if self._dtype.signed: _v = v.val _max = mask(w - 1) _min = -_max - 1 if _v > _max: _v = _min + (_v - _max - 1) elif _v < _min: _v = _max - (_v - _min + 1) v.val = _v else: v.val &= mask(w) if self_vld and other_vld: v.vld_mask = mask(w) else: v.vld_mask = 0 return v
def bitsCmp_detect_useless_cmp(op0, op1, op): v = int(op1) width = op1._dtype.bit_length() if op0._dtype.signed: min_val = -1 if width == 1 else mask(width - 1) - 1 max_val = 0 if width == 1 else mask(width - 1) else: min_val = 0 max_val = mask(width) if v == min_val: # value can not be lower than min_val if op == AllOps.GE: # -> always True return BOOL.from_py(1, 1) elif op == AllOps.LT: # -> always False return BOOL.from_py(0, 1) elif op == AllOps.LE: # convert <= to == to highlight the real function return AllOps.EQ elif v == max_val: # value can not be greater than max_val if op == AllOps.GT: # always False return BOOL.from_py(0, 1) elif op == AllOps.LE: # always True return BOOL.from_py(1, 1) elif op == AllOps.GE: # because value can not be greater than max return AllOps.EQ
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 generateRequests(self, baseAddress, spaceValues): """ Generate reference requests and data data words are containing it's indexes, baseAddresses are multiplies baseAddress :param spaceValues: is iterable of space values """ requests = [] responses = [] wordCntr = 0 inBlockRem = self.ITEMS_IN_BLOCK _baseAddress = baseAddress for space in spaceValues: while space != 0: constraingSpace = min(inBlockRem, space) reqId = self.ID if constraingSpace > self.MAX_LEN + 1: reqLen = self.MAX_LEN elif inBlockRem == 0: reqLen = 0 reqId = self.ID_LAST else: if (constraingSpace <= self.MAX_LEN + 1 and inBlockRem < self.MAX_LEN + 1): # we will download next* as well reqLen = constraingSpace reqId = self.ID_LAST else: # if constraingSpace == inBlockRem: # reqId = self.ID_LAST # reqLen = constraingSpace # else: reqLen = constraingSpace - 1 inBlockIndex = self.ITEMS_IN_BLOCK - inBlockRem req = (reqId, _baseAddress + inBlockIndex * 8, reqLen, 0) requests.append(req) for i in range(reqLen + 1): if i == reqLen and reqId == self.ID_LAST: r = (reqId, baseAddress, mask(8), True) _baseAddress += baseAddress else: r = (reqId, wordCntr + i, mask(8), i == reqLen) responses.append(r) if reqId == self.ID_LAST: inBlockRem = self.ITEMS_IN_BLOCK wordCntr += reqLen space -= reqLen else: inBlockRem -= reqLen + 1 wordCntr += reqLen + 1 space -= reqLen + 1 return requests, responses
def test_noLast(self): u = self.u u.dataIn._ag.data.append((it(16, 1, 2, 3, 4), it(2, mask(2), mask(2), mask(2), mask(2)), 0)) self.runSim(200 * Time.ns) self.assertValSequenceEqual(u.dataOut._ag.data, [(i + 1, mask(2), 0) for i in range(4)])
def test_singleWordPacket(self): u = self.u u.dataIn._ag.data.extend([ (2, mask(8), 1), ]) self.runSim(20 * CLK_PERIOD) self.assertValSequenceEqual(u.sizes._ag.data, [8, ]) self.assertValSequenceEqual(u.dataOut._ag.data, [(2, mask(8), 1), ])
def test_simple(self): u = self.u # (data, strb, user, last) d = [(13, mask(8), 0b01, 0), (14, mask(1), 0b10, 1)] u.dataIn._ag.data.extend(d) self.runSim(200 * Time.ns) self.assertValSequenceEqual(u.dataOut._ag.data, d)
def test_pass(self): u = self.u u.a._ag.data.extend([(11, mask(u.a.strb._dtype.bit_length()), 1), NOP, (12, mask(u.a.strb._dtype.bit_length()), 1) ]) self.runSim(200 * Time.ns) self.assertEqual(len(u.b._ag.data), 2)
def _impl(self): propagateClkRstn(self) dIn = AxiSBuilder(self, self.dataIn).buff().end sb = self.sizesBuff db = self.dataBuff wordCntr = self._reg("wordCntr", Bits(log2ceil(self.MAX_LEN) + 1), def_val=0) overflow = wordCntr._eq(self.MAX_LEN) last = dIn.last | overflow If( StreamNode(masters=[dIn], slaves=[sb.dataIn, db.dataIn]).ack(), If(last, wordCntr(0)).Else(wordCntr(wordCntr + 1))) length = self._sig("length", wordCntr._dtype) BYTE_CNT = dIn.data._dtype.bit_length() // 8 if dIn.USE_STRB: # compress strb mask as binary number rem = self._sig("rem", Bits(log2ceil(BYTE_CNT))) SwitchLogic(cases=[(dIn.strb[i], rem(0 if i == BYTE_CNT - 1 else i + 1)) for i in reversed(range(BYTE_CNT))], default=[ rem(0), ]) if self.EXPORT_ALIGNMENT_ERROR: errorAlignment = self._reg("errorAlignment_reg", def_val=0) self.errorAlignment(errorAlignment) If(dIn.valid & (dIn.strb != mask(BYTE_CNT)) & ~dIn.last, errorAlignment(1)) If(last & (dIn.strb != mask(BYTE_CNT)), length(wordCntr)).Else(length(wordCntr + 1)) else: length(wordCntr + 1) rem = Bits(log2ceil(BYTE_CNT)).from_py(0) sb.dataIn.data(Concat(length, rem)) db.dataIn(dIn, exclude=[dIn.valid, dIn.ready, dIn.last]) db.dataIn.last(last) StreamNode(masters=[dIn], slaves=[sb.dataIn, db.dataIn], extraConds={ sb.dataIn: last }).sync() self.sizes(sb.dataOut) self.dataOut(db.dataOut)
def test_simple_mask_7_outof_8(self): u = self.setUpCrc(CRC_32, use_mask=True) inp = b"abcdefg" u.dataIn._ag.data.extend([(stoi(inp[0:4]), mask(32 // 8), 0), (stoi(inp[4:]), mask(24 // 8), 1)]) # u.dataIn._ag.data.extend([ord("a") for _ in range(4)]) self.runSim(40 * Time.ns) out = int(u.dataOut._ag.data[-1]) ref = crc32(inp) self.assertEqual(out, ref, "0x{:08X} 0x{:08X}".format(out, ref))
def test_onlyPartOfMask(self): u = self.u u.dataIn._ag.data.append( (it(16, 1, 2, 3, 4), it(2, mask(2), 0, 0, 0), 1) ) self.runSim(200 * Time.ns) self.assertValSequenceEqual(u.dataOut._ag.data, [(1, mask(2), 1), ])
def test_u8b_proper_val(self): self.test_8b_proper_val(uint8_t) t = uint8_t with self.assertRaises(ValueError): t.from_py("0b0000000e") v = t.from_py("0b0000000x") self.assertEqual(v.val, 0) self.assertEqual(v.vld_mask, mask(7) << 1) v = t.from_py("0bxx000000") self.assertEqual(v.val, 0) self.assertEqual(v.vld_mask, mask(6))
def test_doubleWordPacket(self): u = self.u sizes = u.sizes._ag.data data = u.dataOut._ag.data goldenData = [(1, mask(8), 0), (2, mask(8), 1) ] u.dataIn._ag.data.extend(goldenData) self.runSim(20 * CLK_PERIOD) self.assertValSequenceEqual(data, goldenData) self.assertValSequenceEqual(sizes, (16,))
def axis_mask_propagate_best_effort(src: AxiStream, dst: AxiStream): res = [] if src.USE_STRB: if not src.USE_KEEP and not dst.USE_STRB and dst.USE_KEEP: res.append(dst.keep(src.strb)) if src.USE_KEEP: if not src.USE_STRB and not dst.USE_KEEP and dst.USE_STRB: res.append(dst.strb(src.keep)) if not src.USE_KEEP and not src.USE_STRB: if dst.USE_KEEP: res.append(dst.keep(mask(dst.keep._dtype.bit_length()))) if dst.USE_STRB: res.append(dst.strb(mask(dst.strb._dtype.bit_length()))) return res
def test_8b_cast(self, t=int8_t): w = t.bit_length() if t.signed: ut = Bits3t(w) else: ut = t t = Bits3t(w, True) self.assertEqual(int(t.from_py(-1).cast(ut)), mask(w)) self.assertEqual(int(t.from_py(-1).cast_sign(False)), mask(w)) self.assertEqual(int(t.from_py(-1).cast_sign(None)), mask(w)) self.assertEqual(int(t.from_py(1).cast(ut)), 1) self.assertEqual(int(t.from_py(0).cast(ut)), 0) self.assertEqual(int(ut.from_py(1).cast(t)), 1) self.assertEqual(int(ut.from_py(mask(w)).cast(t)), -1) self.assertEqual(int(ut.from_py(mask(w)).cast_sign(True)), -1)
def test_multiplePackets(self): u = self.u sizes = u.sizes._ag.data data = u.dataOut._ag.data goldenData = [(1, mask(8), 1), (2, mask(8), 1), (3, mask(8), 1) ] u.dataIn._ag.data.extend(goldenData) self.runSim(20 * CLK_PERIOD) self.assertValSequenceEqual(data, goldenData) self.assertValSequenceEqual(sizes, [8, 8, 8])
def test_noPass(self): u = self.u u.dataIn._ag.data.extend([(1, mask(2), 0) for _ in range(2)]) self.runSim(200 * Time.ns) self.assertEmpty(u.dataOut._ag.data)
def test_passData(self): u = self.u expectedW = [] for i, driver in enumerate(u.drivers): _id = i + 1 _len = i + 1 driver.req._ag.data.append((_id, i + 1, _len, 0)) strb = mask(u.DATA_WIDTH // 8) for i2 in range(_len + 1): _data = i + i2 + 1 last = int(i2 == _len) d = (_data, strb, last) driver.w._ag.data.append(d) expectedW.append(d) self.runSim(80 * Time.ns) req = u.wDatapump.req._ag.data wData = u.wDatapump.w._ag.data for i, _req in enumerate(req): self.assertValSequenceEqual(_req, (i + 1, i + 1, i + 1, 0)) self.assertEqual(len(req), self.DRIVER_CNT) for w, expW in zip(wData, expectedW): self.assertValSequenceEqual(w, expW)
def test_write(self, n=4 * (512 // 32), n2=2, magic=99, randomize=False): u = self.u in_addr_step = u.DATA_WIDTH // 8 out_addr_step = u.OUT_DATA_WIDTH // 8 in_words_in_out_word = out_addr_step // in_addr_step w_data = [] for _ in range(n2): for in_i in range(n): u.s.aw._ag.data.append((in_i * in_addr_step, PROT_DEFAULT)) in_w = magic + in_i w_data.append(in_w) u.s.w._ag.data.extend([(d, mask(in_addr_step)) for d in w_data]) m = Axi4LiteSimRam(u.m) in_t = Bits(u.DATA_WIDTH)[n] out_t = Bits(u.OUT_DATA_WIDTH)[n // in_words_in_out_word] t = n2 * n if randomize: self.randomize_all() t *= 5 self.runSim((t + 10) * CLK_PERIOD) v = m.getArray(0x0, out_addr_step, n // in_words_in_out_word) v = out_t.from_py(v)._reinterpret_cast(in_t) self.assertValSequenceEqual(v, w_data[n * (n2 - 1):])
def test_s2Pading_normal(self): u = self.u = AxiS_frameDeparser(s2Pading) self.DATA_WIDTH = 64 u.USE_STRB = u.USE_KEEP = True u.DATA_WIDTH = self.DATA_WIDTH m = mask(self.DATA_WIDTH // 8) self.compileSimAndStart(self.u) def enDataOut(): u.dataOut._ag.enable = False yield Timer(50 * Time.ns) u.dataOut._ag.enable = True self.procs.append(enDataOut()) MAGIC = 468 u.dataIn.item0_0._ag.data.append(MAGIC) u.dataIn.item0_1._ag.data.append(MAGIC + 1) u.dataIn.item1_0._ag.data.append(MAGIC + 2) u.dataIn.item1_1._ag.data.append(MAGIC + 3) t = 200 self.runSim(t * Time.ns) self.assertValSequenceEqual(u.dataOut._ag.data, [ (MAGIC, m, m, 0), (MAGIC + 1, m, m, 0), (None, 0, m, 0), (MAGIC + 2, m, m, 0), (MAGIC + 3, m, m, 0), (None, 0, m, 1), ])
def test_3Fields_outOccupiedAtStart(self): u = self.u = AxiS_frameDeparser(s3field) u.USE_STRB = u.USE_KEEP = True u.DATA_WIDTH = self.DATA_WIDTH = 64 m = mask(self.DATA_WIDTH // 8) self.compileSimAndStart(self.u) def enDataOut(): u.dataOut._ag.enable = False yield Timer(50 * Time.ns) u.dataOut._ag.enable = True self.procs.append(enDataOut()) MAGIC = 468 u.dataIn.item0._ag.data.append(MAGIC) u.dataIn.item1._ag.data.append(MAGIC + 1) u.dataIn.item2._ag.data.append(MAGIC + 2) t = 200 self.runSim(t * Time.ns) self.assertValSequenceEqual(u.dataOut._ag.data, [ (MAGIC, m, m, 0), (MAGIC + 1, m, m, 0), (MAGIC + 2, m, m, 1), ])
def test_3to1(self): def set_dw_in(intf): intf.DATA_WIDTH = 3 * 32 def set_dw_out(intf): intf.DATA_WIDTH = 32 u = HsResizer(Handshaked, [3, 1], set_dw_in, set_dw_out) self.compileSimAndStart(u) # self.randomize(u.dataIn) # self.randomize(u.dataOut) N = 9 d = [self._rand.getrandbits(3 * 32) for _ in range(N)] u.dataIn._ag.data.extend(d) self.runSim(3 * N * 40 * Time.ns) expected = [] m = mask(32) for a in d: expected.extend([a & m, (a >> 32) & m, (a >> 64) & m]) self.assertValSequenceEqual(u.dataOut._ag.data, expected)
def set_data(self, data): intf = self.intf if data is None: intf.addr.write(None) intf.be.write(None) intf.rd.write(0) intf.wr.write(0) else: rw = data[0] if rw is READ: _, address = data rd, wr = 1, 0 be = mask(intf.DATA_WIDTH // 8) wdata = None elif rw is WRITE: rd, wr = 0, 1 _, address, wdata, be = data elif rw is READ_WRITE: rd, wr = 1, 1 _, address, wdata, be = data else: raise TypeError(f"rw is in invalid format {rw}") intf.addr.write(address) intf.rd.write(rd) intf.wr.write(wr) intf.be.write(be) intf.dwr.write(wdata)
def __lshift__(self, other: Union[int, "Bits3val"]) -> "Bits3val": "Operator <<." try: o = int(other) except ValidityError: o = None v = self.__copy__() if o is None: v.vld_mask = 0 v.val = 0 elif o == 0: return v else: if o < 0: raise ValueError("negative shift count") t = self._dtype m = t.all_mask() v.vld_mask <<= o v.vld_mask |= mask(o) v.vld_mask &= m v.val <<= o v.val &= m if t.signed: v.val = to_signed(v.val, t.bit_length()) return v
def data_transaction(self, id_, data): transactions = [] DW = self.u.s[0].w.DATA_WIDTH m = mask(DW // 8) for is_last, d in iter_with_last(data): transactions.append((d, m, int(is_last))) return transactions
def set_data(self, data): intf = self.intf if data is None: intf.address.write(None) intf.byteEnable.write(None) if intf.MAX_BURST != 0: intf.burstCount.write(None) intf.read.write(0) intf.write.write(0) else: rw, address, burstCount = data if rw is READ: rd, wr = 1, 0 be = mask(intf.readData._dtype.bit_length() // 8) elif rw is WRITE: rd, wr = 0, 1 rw, address, burstCount = data d, be = self.wData.popleft() intf.writeData.write(d) else: raise TypeError(f"rw is in invalid format {rw}") intf.address.write(address) intf.byteEnable.write(be) assert int(burstCount) >= 1, burstCount if intf.MAX_BURST: intf.burstCount.write(burstCount) intf.read.write(rd) intf.write.write(wr)
def test_pass_data(self, N=8): assert N % 2 == 0, N u = self.u m = mask(u.s.DATA_WIDTH // 8) STEP = u.s.DATA_WIDTH // 8 # rw, address, burstCount inAddr = [(READ if (i % 2) == 0 else WRITE, i * STEP, 1) for i in range(N)] u.s._ag.req.extend(inAddr) # d, be inW = [(i + 1, m) for i in range(N // 2)] u.s._ag.wData.extend(inW) # readData, response inR = [(i + 1, RESP_OKAY) for i in range(N // 2)] u.m._ag.rData.extend(inR) inWResp = [RESP_OKAY for _ in range(N // 2)] u.m._ag.wResp.extend(inWResp) t = N + 5 self.runSim(t * CLK_PERIOD) ae = self.assertValSequenceEqual ae(u.m._ag.req, inAddr) ae(u.m._ag.wData, inW) ae(u.s._ag.rData, inR) ae(u.s._ag.wResp, inWResp)
def _count_leading_recurse(cls, data_in: RtlSignal, bit_to_count: int): """ Construct a balanced tree for counter of leading 0/1 :atterntion: result is for """ assert bit_to_count in (0, 1), bit_to_count in_width = data_in._dtype.bit_length() if in_width == 2: if bit_to_count == 0: return ~data_in[1] else: return data_in[1] else: assert in_width > 2, in_width lhs = data_in[:in_width // 2] rhs = data_in[in_width // 2:] if bit_to_count == 0: left_full = lhs._eq(0) else: left_full = lhs._eq(mask(lhs._dtype.bit_length())) in_ = left_full._ternary(rhs, lhs) half_count = cls._count_leading_recurse(in_, bit_to_count) return Concat(left_full, half_count)
def convertBits__val(self: Bits, val: "BitVal", toType: HdlType): if toType == BOOL: return val != self.getValueCls().from_py(self, 0) elif isinstance(toType, Bits): if self.signed != toType.signed: if self.strict_sign and bool(self.signed) != bool(toType.signed): raise TypeConversionErr(self, toType) val = val._convSign__val(toType.signed) w_from, w_to = self.bit_length(), toType.bit_length() if w_from != w_to: if self.strict_width: raise TypeConversionErr(self, toType) if w_from > w_to: # cut off some bits from value new_m = val.vld_mask & toType.all_mask() else: # w_from < w_to, extend the value to some bit length extra_mask_bits = mask(w_to - w_from) new_m = set_bit_range(val.vld_mask, w_from, w_to - w_from, extra_mask_bits) val = toType.from_py(val.val, new_m) if val._dtype != toType: # sign and width checked, only name, strict_* flags can be different val = toType.from_py(val.val, val.vld_mask) return val elif toType == INT: return INT.getValueCls()(INT, val.val, int(val._is_full_valid())) return default_auto_cast_fn(self, val, toType)