def unpack_us_cc(cls, pkt, check_parity=False): tlp = cls() tlp.fmt_type = TlpType.CPL tlp.lower_address = pkt.data[0] & 0x7f tlp.at = (pkt.data[0] >> 8) & 3 tlp.byte_count = (pkt.data[0] >> 16) & 0x1fff if pkt.data[0] & (1 << 29): tlp.fmt_type = TlpType.CPL_LOCKED tlp.length = pkt.data[1] & 0x7ff if tlp.length > 0: tlp.fmt = TlpFmt.THREE_DW_DATA tlp.status = CplStatus((pkt.data[1] >> 11) & 7) tlp.requester_id = PcieId.from_int(pkt.data[1] >> 16) tlp.completer_id = PcieId.from_int(pkt.data[2] >> 8) tlp.completer_id_enable = pkt.data[2] >> 24 & 1 != 0 tlp.tag = pkt.data[2] & 0xff tlp.completer_id_enable = bool(pkt.data[2] & (1 << 24)) tlp.tc = (pkt.data[2] >> 25) & 0x7 tlp.attr = (pkt.data[2] >> 28) & 0x7 tlp.discontinue = pkt.discontinue if tlp.length > 0: tlp.data = pkt.data[3:3+tlp.length] # check parity if check_parity: assert pkt.check_parity() return tlp
def unpack_us_rc(cls, pkt, check_parity=False): tlp = cls() tlp.fmt_type = TlpType.CPL tlp.lower_address = pkt.data[0] & 0xfff tlp.error_code = (pkt.data[0] >> 12) & 0xf tlp.byte_count = (pkt.data[0] >> 16) & 0x1fff if pkt.data[0] & (1 << 29): tlp.fmt_type = TlpType.CPL_LOCKED tlp.request_completed = pkt.data[0] & (1 << 30) tlp.length = pkt.data[1] & 0x7ff if tlp.length > 0: tlp.fmt = TlpFmt.THREE_DW_DATA tlp.status = CplStatus((pkt.data[1] >> 11) & 7) tlp.ep = bool(pkt.data[1] & 1 << 14) tlp.requester_id = PcieId.from_int(pkt.data[1] >> 16) tlp.completer_id = PcieId.from_int(pkt.data[2] >> 8) tlp.tag = pkt.data[2] & 0xff tlp.tc = TlpTc((pkt.data[2] >> 25) & 0x7) tlp.attr = TlpAttr((pkt.data[2] >> 28) & 0x7) tlp.discontinue = pkt.discontinue if tlp.length > 0: for dw in pkt.data[3:3+tlp.length]: tlp.data.extend(struct.pack('<L', dw)) # compute byte enables byte_en = [0]*3 first_be = (0xf << (tlp.lower_address & 3)) & 0xf if tlp.byte_count+(tlp.lower_address & 3) > tlp.length*4: last_be = 0xf else: last_be = 0xf >> ((4-tlp.byte_count-tlp.lower_address) & 3) if tlp.get_payload_size_dw() == 1: first_be = first_be & last_be last_be = 0 if tlp.get_payload_size_dw() >= 1: byte_en += [first_be] if tlp.get_payload_size_dw() > 2: byte_en += [0xf] * (tlp.get_payload_size_dw()-2) if tlp.get_payload_size_dw() > 1: byte_en += [last_be] # check byte enables assert byte_en == pkt.byte_en # check parity if check_parity: assert pkt.check_parity() return tlp
def unpack_us_rc(cls, pkt, check_parity=False): tlp = cls() tlp.fmt_type = TlpType.CPL tlp.lower_address = pkt.data[0] & 0xfff tlp.error_code = (pkt.data[0] >> 12) & 0xf tlp.byte_count = (pkt.data[0] >> 16) & 0x1fff if pkt.data[0] & (1 << 29): tlp.fmt_type = TlpType.CPL_LOCKED tlp.length = pkt.data[1] & 0x7ff if tlp.length > 0: tlp.fmt = TlpFmt.THREE_DW_DATA tlp.status = (pkt.data[1] >> 11) & 7 tlp.requester_id = PcieId.from_int(pkt.data[1] >> 16) tlp.completer_id = PcieId.from_int(pkt.data[2] >> 8) tlp.tag = pkt.data[2] & 0xff tlp.tc = (pkt.data[2] >> 25) & 0x7 tlp.attr = (pkt.data[2] >> 28) & 0x7 tlp.discontinue = pkt.discontinue if tlp.length > 0: tlp.data = pkt.data[3:3+tlp.length] # compute byte enables byte_en = [0]*3 first_be = (0xf << (tlp.lower_address & 3)) & 0xf if tlp.byte_count+(tlp.lower_address & 3) > tlp.length*4: last_be = 0xf else: last_be = 0xf >> ((4-tlp.byte_count-tlp.lower_address) & 3) if len(tlp.data) == 1: first_be = first_be & last_be last_be = 0 if len(tlp.data) >= 1: byte_en += [first_be] if len(tlp.data) > 2: byte_en += [0xf] * (len(tlp.data)-2) if len(tlp.data) > 1: byte_en += [last_be] # check byte enables assert byte_en == pkt.byte_en # check parity if check_parity: assert pkt.check_parity() return tlp
def unpack_us_cq(cls, pkt, check_parity=False): tlp = cls() req_type = (pkt.data[2] >> 11) & 0xf tlp.fmt_type = req_type_to_tlp_type[req_type] tlp.length = pkt.data[2] & 0x7ff tlp.requester_id = PcieId.from_int(pkt.data[2] >> 16) tlp.tag = pkt.data[3] & 0xff tlp.tc = TlpTc((pkt.data[3] >> 25) & 0x7) tlp.attr = TlpAttr((pkt.data[3] >> 28) & 0x7) if req_type & 8 == 0: # memory, IO, or atomic operation tlp.at = TlpAt(pkt.data[0] & 3) tlp.address = (pkt.data[1] << 32) | (pkt.data[0] & 0xfffffffc) if tlp.address > 0xffffffff: if tlp.fmt == TlpFmt.THREE_DW: tlp.fmt = TlpFmt.FOUR_DW elif tlp.fmt == TlpFmt.THREE_DW_DATA: tlp.fmt = TlpFmt.FOUR_DW_DATA tlp.completer_id = PcieId(0, 0, (pkt.data[3] >> 8) & 0xff) tlp.bar_id = (pkt.data[3] >> 16) & 7 tlp.bar_aperture = (pkt.data[3] >> 19) & 0x3f tlp.first_be = pkt.first_be tlp.last_be = pkt.last_be tlp.discontinue = pkt.discontinue for dw in pkt.data[4:]: tlp.data.extend(struct.pack('<L', dw)) # compute byte enables byte_en = [0]*4 if tlp.get_payload_size_dw() >= 1: byte_en += [tlp.first_be] if tlp.get_payload_size_dw() > 2: byte_en += [0xf] * (tlp.get_payload_size_dw()-2) if tlp.get_payload_size_dw() > 1: byte_en += [tlp.last_be] # check byte enables assert byte_en == pkt.byte_en # check parity if check_parity: assert pkt.check_parity() return tlp
async def dma_mem_write(self, addr, data, timeout=0, timeout_unit='ns'): n = 0 while True: tlp = Tlp() if addr > 0xffffffff: tlp.fmt_type = TlpType.MEM_WRITE_64 else: tlp.fmt_type = TlpType.MEM_WRITE tlp.requester_id = PcieId(self.dev_bus_num, self.dev_device_num, 0) first_pad = addr % 4 byte_length = len(data) - n # max payload size byte_length = min(byte_length, (128 << self.dev_max_payload) - first_pad) # 4k address align byte_length = min(byte_length, 0x1000 - (addr & 0xfff)) tlp.set_addr_be_data(addr, data[n:n + byte_length]) await self.tx_source.send(S10PcieFrame.from_tlp(tlp)) n += byte_length addr += byte_length if n >= len(data): break
async def dma_mem_write(self, addr, data, timeout=0, timeout_unit='ns'): n = 0 while True: tlp = Tlp_us() if addr > 0xffffffff: tlp.fmt_type = TlpType.MEM_WRITE_64 else: tlp.fmt_type = TlpType.MEM_WRITE tlp.requester_id = PcieId(0, 0, 0) first_pad = addr % 4 byte_length = len(data) - n # max payload size byte_length = min(byte_length, (128 << self.dut.cfg_max_payload.value.integer) - first_pad) # 4k address align byte_length = min(byte_length, 0x1000 - (addr & 0xfff)) tlp.set_addr_be_data(addr, data[n:n + byte_length]) await self.rq_source.send(tlp.pack_us_rq()) n += byte_length addr += byte_length if n >= len(data): break
async def dma_io_write(self, addr, data, timeout=0, timeout_unit='ns'): n = 0 while True: tlp = Tlp() tlp.fmt_type = TlpType.IO_WRITE tlp.requester_id = PcieId(self.dev_bus_num, self.dev_device_num, 0) first_pad = addr % 4 byte_length = min(len(data) - n, 4 - first_pad) tlp.set_addr_be_data(addr, data[n:n + byte_length]) tlp.tag = await self.alloc_tag() await self.tx_source.send(S10PcieFrame.from_tlp(tlp)) cpl = await self.recv_cpl(tlp.tag, timeout, timeout_unit) self.release_tag(tlp.tag) if not cpl: raise Exception("Timeout") if cpl.status != CplStatus.SC: raise Exception("Unsuccessful completion") n += byte_length addr += byte_length if n >= len(data): break
async def dma_io_write(self, addr, data, timeout=0, timeout_unit='ns'): n = 0 while True: tlp = Tlp_us() tlp.fmt_type = TlpType.IO_WRITE tlp.requester_id = PcieId(0, 0, 0) first_pad = addr % 4 byte_length = min(len(data) - n, 4 - first_pad) tlp.set_addr_be_data(addr, data[n:n + byte_length]) tlp.tag = await self.alloc_tag() await self.rq_source.send(tlp.pack_us_rq()) pkt = await self.rc_sink.recv() self.release_tag(tlp.tag) if not pkt: raise Exception("Timeout") cpl = Tlp_us.unpack_us_rc(pkt) if cpl.status != CplStatus.SC: raise Exception("Unsuccessful completion") n += byte_length addr += byte_length if n >= len(data): break
async def dma_mem_write(self, addr, data, timeout=0, timeout_unit='ns'): n = 0 while n < len(data): tlp = Tlp_us() if addr > 0xffffffff: tlp.fmt_type = TlpType.MEM_WRITE_64 else: tlp.fmt_type = TlpType.MEM_WRITE tlp.requester_id = PcieId(self.dev.bus_num, self.dev.device_num, 0) first_pad = addr % 4 byte_length = len(data) - n # max payload size byte_length = min(byte_length, (128 << self.dev.functions[0].max_payload_size) - first_pad) # 4k address align byte_length = min(byte_length, 0x1000 - (addr & 0xfff)) tlp.set_addr_be_data(addr, data[n:n + byte_length]) await self.rq_source.send(tlp.pack_us_rq()) n += byte_length addr += byte_length
def unpack_us_rq(cls, pkt, check_parity=False): tlp = cls() req_type = (pkt.data[2] >> 11) & 0xf tlp.fmt_type = req_type_to_tlp_type[req_type] tlp.length = pkt.data[2] & 0x7ff tlp.ep = bool(pkt.data[2] & 1 << 15) tlp.requester_id = PcieId.from_int(pkt.data[2] >> 16) tlp.tag = pkt.data[3] & 0xff tlp.tc = TlpTc((pkt.data[3] >> 25) & 0x7) tlp.attr = TlpAttr((pkt.data[3] >> 28) & 0x7) if req_type < 12: if req_type < 8: # memory, IO, or atomic operation tlp.at = TlpAt(pkt.data[0] & 3) tlp.address = (pkt.data[1] << 32) | (pkt.data[0] & 0xfffffffc) if tlp.address > 0xffffffff: if tlp.fmt == TlpFmt.THREE_DW: tlp.fmt = TlpFmt.FOUR_DW elif tlp.fmt == TlpFmt.THREE_DW_DATA: tlp.fmt = TlpFmt.FOUR_DW_DATA else: # configuration tlp.register_number = (pkt.data[0] >> 2) & 0x3ff tlp.completer_id = PcieId.from_int(pkt.data[3] >> 8) tlp.requester_id_enable = bool(pkt.data[3] & (1 << 24)) tlp.first_be = pkt.first_be tlp.last_be = pkt.last_be tlp.discontinue = pkt.discontinue tlp.seq_num = pkt.seq_num for dw in pkt.data[4:]: tlp.data.extend(struct.pack('<L', dw)) # check parity if check_parity: assert pkt.check_parity() else: raise Exception("TODO") return tlp
async def dma_mem_read(self, addr, length, timeout=0, timeout_unit='ns'): data = b'' n = 0 while True: tlp = Tlp() if addr > 0xffffffff: tlp.fmt_type = TlpType.MEM_READ_64 else: tlp.fmt_type = TlpType.MEM_READ tlp.requester_id = PcieId(self.dev_bus_num, self.dev_device_num, 0) first_pad = addr % 4 byte_length = length - n # max read request size byte_length = min(byte_length, (128 << self.dev_max_read_req) - first_pad) # 4k address align byte_length = min(byte_length, 0x1000 - (addr & 0xfff)) tlp.set_addr_be(addr, byte_length) tlp.tag = await self.alloc_tag() await self.tx_source.send(S10PcieFrame.from_tlp(tlp)) m = 0 while True: cpl = await self.recv_cpl(tlp.tag, timeout, timeout_unit) if not cpl: raise Exception("Timeout") if cpl.status != CplStatus.SC: raise Exception("Unsuccessful completion") else: assert cpl.byte_count + 3 + (cpl.lower_address & 3) >= cpl.length * 4 assert cpl.byte_count == max(byte_length - m, 1) d = cpl.get_data() offset = cpl.lower_address & 3 data += d[offset:offset + cpl.byte_count] m += len(d) - offset if m >= byte_length: break self.release_tag(tlp.tag) n += byte_length addr += byte_length if n >= length: break return data[:length]
async def run_test_config(dut): tb = TB(dut) tb.rc.log.setLevel(logging.DEBUG) tb.log.info("Read complete config space") orig = await tb.rc.config_read(PcieId(0, 1, 0), 0x000, 256, 1000, 'ns') tb.log.info("Read and write IntLine and IntPin") await tb.rc.config_write(PcieId(0, 1, 0), 0x03c, b'\x12\x34', 1000, 'ns') val = await tb.rc.config_read(PcieId(0, 1, 0), 0x03c, 2, 1000, 'ns') assert val == b'\x12\x34' tb.log.info("Write complete config space") await tb.rc.config_write(PcieId(0, 1, 0), 0x000, orig, 1000, 'ns')
async def run_test_config(dut): tb = TB(dut) tb.rc.log.setLevel(logging.DEBUG) tb.log.info("Read complete config space") orig = await tb.rc.config_read(PcieId(0, 1, 0), 0x000, 256, timeout=1000, timeout_unit='ns') tb.log.info("Read and write interrupt line register") await tb.rc.config_write(PcieId(0, 1, 0), 0x03c, b'\x12', timeout=1000, timeout_unit='ns') val = await tb.rc.config_read(PcieId(0, 1, 0), 0x03c, 1, timeout=1000, timeout_unit='ns') assert val == b'\x12' tb.log.info("Write complete config space") await tb.rc.config_write(PcieId(0, 1, 0), 0x000, orig, timeout=1000, timeout_unit='ns')
async def _run_cc_logic(self): while True: tlp = Tlp_us.unpack_us_cc(await self.cc_sink.recv(), self.enable_parity) if not tlp.completer_id_enable: tlp.completer_id = PcieId(self.bus_num, self.device_num, tlp.completer_id.function) if not tlp.discontinue: await self.send(Tlp(tlp))
async def dma_mem_read(self, addr, length, timeout=0, timeout_unit='ns'): data = b'' n = 0 while n < length: tlp = Tlp_us() if addr > 0xffffffff: tlp.fmt_type = TlpType.MEM_READ_64 else: tlp.fmt_type = TlpType.MEM_READ tlp.requester_id = PcieId(self.dev.bus_num, self.dev.device_num, 0) first_pad = addr % 4 byte_length = length - n # max read request size byte_length = min( byte_length, (128 << self.dev.functions[0].max_read_request_size) - first_pad) # 4k address align byte_length = min(byte_length, 0x1000 - (addr & 0xfff)) tlp.set_addr_be(addr, byte_length) tlp.tag = await self.alloc_tag() await self.rq_source.send(tlp.pack_us_rq()) m = 0 while m < byte_length: pkt = await self.rc_sink.recv() if not pkt: raise Exception("Timeout") cpl = Tlp_us.unpack_us_rc(pkt) if cpl.status != CplStatus.SC: raise Exception("Unsuccessful completion") else: d = bytearray() for k in range(cpl.length): d.extend(struct.pack('<L', cpl.data[k])) offset = cpl.lower_address & 3 data += d[offset:offset + cpl.byte_count] m += len(d) - offset self.release_tag(tlp.tag) n += byte_length addr += byte_length return data
async def _run_rq_logic(self): while True: tlp = Tlp_us.unpack_us_rq(await self.rq_sink.recv(), self.enable_parity) if not tlp.requester_id_enable: tlp.requester_id = PcieId(self.bus_num, self.device_num, tlp.requester_id.function) if not tlp.discontinue: if self.functions[tlp.requester_id.function].bus_master_enable: self.rq_seq_num.append(tlp.seq_num) await self.send(Tlp(tlp)) else: self.log.warning("Bus mastering disabled")
async def dma_io_read(self, addr, length, timeout=0, timeout_unit='ns'): data = b'' n = 0 while True: tlp = Tlp_us() tlp.fmt_type = TlpType.IO_READ tlp.requester_id = PcieId(0, 0, 0) first_pad = addr % 4 byte_length = min(length - n, 4 - first_pad) tlp.set_addr_be(addr, byte_length) tlp.tag = await self.alloc_tag() await self.rq_source.send(tlp.pack_us_rq()) pkt = await self.rc_sink.recv() self.release_tag(tlp.tag) if not pkt: raise Exception("Timeout") cpl = Tlp_us.unpack_us_rc(pkt) if cpl.status != CplStatus.SC: raise Exception("Unsuccessful completion") else: d = cpl.get_data() data += d[first_pad:] n += byte_length addr += byte_length if n >= length: break return data[:length]
async def dma_io_read(self, addr, length, timeout=0, timeout_unit='ns'): data = b'' n = 0 while True: tlp = Tlp() tlp.fmt_type = TlpType.IO_READ tlp.requester_id = PcieId(self.dev_bus_num, self.dev_device_num, 0) first_pad = addr % 4 byte_length = min(length - n, 4 - first_pad) tlp.set_addr_be(addr, byte_length) tlp.tag = await self.alloc_tag() await self.tx_source.send(S10PcieFrame.from_tlp(tlp)) cpl = await self.recv_cpl(tlp.tag, timeout, timeout_unit) self.release_tag(tlp.tag) if not cpl: raise Exception("Timeout") if cpl.status != CplStatus.SC: raise Exception("Unsuccessful completion") else: d = cpl.get_data() data += d[first_pad:] n += byte_length addr += byte_length if n >= length: break return data[:length]
def check_dev(dev): tb.log.info("Check device at %s", dev.pcie_id) # ensure ID was assigned to device assert dev.pcie_id != PcieId(0, 0, 0) # get tree item ti = tb.rc.tree.find_child_dev(dev.pcie_id) assert ti is not None # check informational registers tb.log.info("Header type: 0x%02x", ti.header_type) tb.log.info("Vendor ID: 0x%04x", ti.vendor_id) tb.log.info("Device ID: 0x%04x", ti.device_id) tb.log.info("Revision ID: 0x%02x", ti.revision_id) tb.log.info("Class code: 0x%06x", ti.class_code) assert ti.header_type == dev.header_layout | (bool(dev.multifunction_device) << 7) assert ti.class_code == dev.class_code assert ti.revision_id == dev.revision_id assert ti.vendor_id == dev.vendor_id assert ti.device_id == dev.device_id if ti.header_type & 0x7f == 0x01: # bridge bar_cnt = 2 # check bridge registers tb.log.info("Primary bus %d", ti.pri_bus_num) tb.log.info("Secondary bus %d", ti.sec_bus_num) tb.log.info("Subordinate bus %d", ti.sub_bus_num) tb.log.info("IO base 0x%08x", ti.io_base) tb.log.info("IO limit 0x%08x", ti.io_limit) tb.log.info("Mem base 0x%08x", ti.mem_base) tb.log.info("Mem limit 0x%08x", ti.mem_limit) tb.log.info("Prefetchable mem base 0x%016x", ti.prefetchable_mem_base) tb.log.info("Prefetchable mem limit 0x%016x", ti.prefetchable_mem_limit) assert ti.sec_bus_num == dev.sec_bus_num assert ti.sub_bus_num == dev.sub_bus_num assert ti.io_base == dev.io_base assert ti.io_limit == dev.io_limit assert ti.mem_base == dev.mem_base assert ti.mem_limit == dev.mem_limit assert ti.prefetchable_mem_base == dev.prefetchable_mem_base assert ti.prefetchable_mem_limit == dev.prefetchable_mem_limit else: bar_cnt = 6 tb.log.info("Subsystem vendor ID: 0x%04x", ti.subsystem_vendor_id) tb.log.info("Subsystem ID: 0x%04x", ti.subsystem_id) assert ti.subsystem_vendor_id == dev.subsystem_vendor_id assert ti.subsystem_id == dev.subsystem_id # check BARs bar = 0 while bar < bar_cnt: if d.bar_mask[bar] == 0: # unused bar assert ti.bar[bar] is None assert ti.bar_raw[bar] == 0 assert ti.bar_addr[bar] is None assert ti.bar_size[bar] is None bar += 1 elif d.bar[bar] & 1: # IO BAR tb.log.info("BAR%d: IO BAR addr 0x%08x, size %d", bar, ti.bar_addr[bar], ti.bar_size[bar]) assert ti.bar[bar] == d.bar[bar] assert ti.bar_raw[bar] == d.bar[bar] assert ti.bar_addr[bar] == d.bar[bar] & ~0x3 assert ti.bar_size[bar] == (~d.bar_mask[bar] & 0xfffffffc)+0x4 bar += 1 elif d.bar[bar] & 4: # 64 bit BAR tb.log.info("BAR%d: Mem BAR (32 bit) addr 0x%08x, size %d", bar, ti.bar_addr[bar], ti.bar_size[bar]) assert ti.bar[bar] == d.bar[bar] | d.bar[bar+1] << 32 assert ti.bar_raw[bar] == d.bar[bar] assert ti.bar_raw[bar+1] == d.bar[bar+1] assert ti.bar_addr[bar] == (d.bar[bar] | d.bar[bar+1] << 32) & ~0xf assert ti.bar_size[bar] == (~(d.bar_mask[bar] | d.bar_mask[bar+1] << 32) & 0xfffffffffffffff0)+0x10 bar += 2 else: # 32 bit BAR tb.log.info("BAR%d: Mem BAR (64 bit) addr 0x%08x, size %d", bar, ti.bar_addr[bar], ti.bar_size[bar]) assert ti.bar[bar] == d.bar[bar] assert ti.bar_raw[bar] == d.bar[bar] assert ti.bar_addr[bar] == d.bar[bar] & ~0xf assert ti.bar_size[bar] == (~d.bar_mask[bar] & 0xfffffff0)+0x10 bar += 1 if d.expansion_rom_addr_mask == 0: assert ti.expansion_rom_raw == 0 assert ti.expansion_rom_addr is None assert ti.expansion_rom_size is None else: assert ti.expansion_rom_raw & 0xfffff800 == dev.expansion_rom_addr assert ti.expansion_rom_addr == dev.expansion_rom_addr assert ti.expansion_rom_size == (~d.expansion_rom_addr_mask & 0xfffff800)+0x800
def unpack_us_rq(cls, pkt, check_parity=False): tlp = cls() req_type = (pkt.data[2] >> 11) & 0xf if req_type == ReqType.MEM_READ: tlp.fmt_type = TlpType.MEM_READ elif req_type == ReqType.MEM_WRITE: tlp.fmt_type = TlpType.MEM_WRITE elif req_type == ReqType.IO_READ: tlp.fmt_type = TlpType.IO_READ elif req_type == ReqType.IO_WRITE: tlp.fmt_type = TlpType.IO_WRITE elif req_type == ReqType.MEM_FETCH_ADD: tlp.fmt_type = TlpType.FETCH_ADD elif req_type == ReqType.MEM_SWAP: tlp.fmt_type = TlpType.SWAP elif req_type == ReqType.MEM_CAS: tlp.fmt_type = TlpType.CAS elif req_type == ReqType.MEM_READ_LOCKED: tlp.fmt_type = TlpType.MEM_READ_LOCKED elif req_type == ReqType.CFG_READ_0: tlp.fmt_type = TlpType.CFG_READ_0 elif req_type == ReqType.CFG_READ_1: tlp.fmt_type = TlpType.CFG_READ_1 elif req_type == ReqType.CFG_WRITE_0: tlp.fmt_type = TlpType.CFG_WRITE_0 elif req_type == ReqType.CFG_WRITE_1: tlp.fmt_type = TlpType.CFG_WRITE_1 else: raise Exception("Invalid packet type") tlp.length = pkt.data[2] & 0x7ff # TODO poisoned tlp.requester_id = PcieId.from_int(pkt.data[2] >> 16) tlp.tag = pkt.data[3] & 0xff tlp.tc = (pkt.data[3] >> 25) & 0x7 tlp.attr = (pkt.data[3] >> 28) & 0x7 if req_type < 12: if req_type < 8: # memory, IO, or atomic operation tlp.at = pkt.data[0] & 3 tlp.address = (pkt.data[1] << 32) | (pkt.data[0] & 0xfffffffc) if tlp.address > 0xffffffff: if tlp.fmt == TlpFmt.THREE_DW: tlp.fmt = TlpFmt.FOUR_DW elif tlp.fmt == TlpFmt.THREE_DW_DATA: tlp.fmt = TlpFmt.FOUR_DW_DATA else: tlp.register_number = (pkt.data[0] >> 2) & 0x3ff tlp.completer_id = PcieId.from_int(pkt.data[3] >> 8) tlp.requester_id_enable = bool(pkt.data[3] & (1 << 24)) tlp.first_be = pkt.first_be tlp.last_be = pkt.last_be tlp.discontinue = pkt.discontinue tlp.seq_num = pkt.seq_num tlp.data = pkt.data[4:] # check parity if check_parity: assert pkt.check_parity() else: raise Exception("TODO") return tlp
def unpack_us_cq(cls, pkt, check_parity=False): tlp = cls() req_type = (pkt.data[2] >> 11) & 0xf if req_type == ReqType.MEM_READ: tlp.fmt_type = TlpType.MEM_READ elif req_type == ReqType.MEM_WRITE: tlp.fmt_type = TlpType.MEM_WRITE elif req_type == ReqType.IO_READ: tlp.fmt_type = TlpType.IO_READ elif req_type == ReqType.IO_WRITE: tlp.fmt_type = TlpType.IO_WRITE elif req_type == ReqType.MEM_FETCH_ADD: tlp.fmt_type = TlpType.FETCH_ADD elif req_type == ReqType.MEM_SWAP: tlp.fmt_type = TlpType.SWAP elif req_type == ReqType.MEM_CAS: tlp.fmt_type = TlpType.CAS elif req_type == ReqType.MEM_READ_LOCKED: tlp.fmt_type = TlpType.MEM_READ_LOCKED else: raise Exception("Invalid packet type") tlp.length = pkt.data[2] & 0x7ff tlp.requester_id = PcieId.from_int(pkt.data[2] >> 16) tlp.tag = pkt.data[3] & 0xff tlp.tc = (pkt.data[3] >> 25) & 0x7 tlp.attr = (pkt.data[3] >> 28) & 0x7 if req_type & 8 == 0: # memory, IO, or atomic operation tlp.at = pkt.data[0] & 3 tlp.address = (pkt.data[1] << 32) | (pkt.data[0] & 0xfffffffc) if tlp.address > 0xffffffff: if tlp.fmt == TlpFmt.THREE_DW: tlp.fmt = TlpFmt.FOUR_DW elif tlp.fmt == TlpFmt.THREE_DW_DATA: tlp.fmt = TlpFmt.FOUR_DW_DATA tlp.completer_id = PcieId(0, 0, (pkt.data[3] >> 8) & 0xff) tlp.bar_id = (pkt.data[3] >> 16) & 7 tlp.bar_aperture = (pkt.data[3] >> 19) & 0x3f tlp.first_be = pkt.first_be tlp.last_be = pkt.last_be tlp.discontinue = pkt.discontinue tlp.data = pkt.data[4:] # compute byte enables byte_en = [0]*4 if len(tlp.data) >= 1: byte_en += [tlp.first_be] if len(tlp.data) > 2: byte_en += [0xf] * (len(tlp.data)-2) if len(tlp.data) > 1: byte_en += [tlp.last_be] # check byte enables assert byte_en == pkt.byte_en # check parity if check_parity: assert pkt.check_parity() return tlp
async def upstream_recv(self, tlp): self.log.debug("Got downstream TLP: %r", tlp) if tlp.fmt_type in {TlpType.CFG_READ_0, TlpType.CFG_WRITE_0}: # config type 0 # capture address information self.bus_num = tlp.dest_id.bus # pass TLP to function for f in self.functions: if f.pcie_id == tlp.dest_id: await f.upstream_recv(tlp) return tlp.release_fc() self.log.warning( "Function not found: failed to route config type 0 TLP: %r", tlp) elif tlp.fmt_type in {TlpType.CFG_READ_1, TlpType.CFG_WRITE_1}: # config type 1 tlp.release_fc() self.log.warning( "Malformed TLP: endpoint received config type 1 TLP: %r", tlp) elif tlp.fmt_type in { TlpType.CPL, TlpType.CPL_DATA, TlpType.CPL_LOCKED, TlpType.CPL_LOCKED_DATA }: # Completion for f in self.functions: if f.pcie_id == tlp.requester_id: frame = S10PcieFrame.from_tlp(tlp) frame.func_num = tlp.requester_id.function await self.rx_queue.put(frame) tlp.release_fc() return tlp.release_fc() self.log.warning( "Unexpected completion: failed to route completion to function: %r", tlp) return # no UR response for completion elif tlp.fmt_type in {TlpType.IO_READ, TlpType.IO_WRITE}: # IO read/write for f in self.functions: bar = f.match_bar(tlp.address, True) if bar: frame = S10PcieFrame.from_tlp(tlp) frame.bar_range = 6 frame.func_num = tlp.requester_id.function await self.rx_queue.put(frame) tlp.release_fc() return tlp.release_fc() self.log.warning( "No BAR match: IO request did not match any BARs: %r", tlp) elif tlp.fmt_type in { TlpType.MEM_READ, TlpType.MEM_READ_64, TlpType.MEM_WRITE, TlpType.MEM_WRITE_64 }: # Memory read/write for f in self.functions: bar = f.match_bar(tlp.address) if bar: frame = S10PcieFrame.from_tlp(tlp) frame.bar_range = bar[0] frame.func_num = tlp.requester_id.function await self.rx_queue.put(frame) tlp.release_fc() return tlp.release_fc() if tlp.fmt_type in {TlpType.MEM_WRITE, TlpType.MEM_WRITE_64}: self.log.warning( "No BAR match: memory write request did not match any BARs: %r", tlp) return # no UR response for write request else: self.log.warning( "No BAR match: memory read request did not match any BARs: %r", tlp) else: raise Exception("TODO") # Unsupported request cpl = Tlp.create_ur_completion_for_tlp(tlp, PcieId(self.bus_num, 0, 0)) self.log.debug("UR Completion: %r", cpl) await self.upstream_send(cpl)
async def _run_rx_tlp(self): while True: frame = await self.rx_sink.recv() tlp = frame.to_tlp() self.log.debug("RX TLP: %s", repr(tlp)) if tlp.fmt_type in { TlpType.CPL, TlpType.CPL_DATA, TlpType.CPL_LOCKED, TlpType.CPL_LOCKED_DATA }: self.log.info("Completion") self.rx_cpl_queues[tlp.tag].put_nowait(tlp) self.rx_cpl_sync[tlp.tag].set() elif tlp.fmt_type == TlpType.IO_READ: self.log.info("IO read") cpl = Tlp.create_completion_data_for_tlp( tlp, PcieId(self.dev_bus_num, 0, 0)) # region = tlp.bar_id region = 3 addr = tlp.address % len(self.regions[region]) offset = 0 start_offset = None mask = tlp.first_be # perform operation data = bytearray(4) for k in range(4): if mask & (1 << k): if start_offset is None: start_offset = offset else: if start_offset is not None and offset != start_offset: data[start_offset:offset] = self.regions[region][ addr + start_offset:addr + offset] start_offset = None offset += 1 if start_offset is not None and offset != start_offset: data[start_offset:offset] = self.regions[region][ addr + start_offset:addr + offset] cpl.set_data(data) cpl.byte_count = 4 cpl.length = 1 self.log.debug("Completion: %s", repr(cpl)) await self.tx_source.send(S10PcieFrame.from_tlp(cpl)) elif tlp.fmt_type == TlpType.IO_WRITE: self.log.info("IO write") cpl = Tlp.create_completion_for_tlp( tlp, PcieId(self.dev_bus_num, 0, 0)) # region = tlp.bar_id region = 3 addr = tlp.address % len(self.regions[region]) offset = 0 start_offset = None mask = tlp.first_be # perform operation data = tlp.get_data() for k in range(4): if mask & (1 << k): if start_offset is None: start_offset = offset else: if start_offset is not None and offset != start_offset: self.regions[region][addr + start_offset:addr + offset] = data[ start_offset:offset] start_offset = None offset += 1 if start_offset is not None and offset != start_offset: self.regions[region][addr + start_offset:addr + offset] = data[start_offset:offset] self.log.debug("Completion: %s", repr(cpl)) await self.tx_source.send(S10PcieFrame.from_tlp(cpl)) elif tlp.fmt_type in {TlpType.MEM_READ, TlpType.MEM_READ_64}: self.log.info("Memory read") # perform operation region = frame.bar_range addr = tlp.address % len(self.regions[region]) offset = 0 length = tlp.length # perform read data = self.regions[region][addr:addr + length * 4] # prepare completion TLP(s) m = 0 n = 0 addr = tlp.address + tlp.get_first_be_offset() dw_length = tlp.length byte_length = tlp.get_be_byte_count() while m < dw_length: cpl = Tlp.create_completion_data_for_tlp( tlp, PcieId(self.dev_bus_num, 0, 0)) cpl_dw_length = dw_length - m cpl_byte_length = byte_length - n cpl.byte_count = cpl_byte_length if cpl_dw_length > 32 << self.dev_max_payload: # max payload size cpl_dw_length = 32 << self.dev_max_payload # RCB align cpl_dw_length -= (addr & 0x7c) >> 2 cpl.lower_address = addr & 0x7f cpl.set_data(data[m * 4:(m + cpl_dw_length) * 4]) self.log.debug("Completion: %s", repr(cpl)) await self.tx_source.send(S10PcieFrame.from_tlp(cpl)) m += cpl_dw_length n += cpl_dw_length * 4 - (addr & 3) addr += cpl_dw_length * 4 - (addr & 3) elif tlp.fmt_type in {TlpType.MEM_WRITE, TlpType.MEM_WRITE_64}: self.log.info("Memory write") # perform operation region = frame.bar_range addr = tlp.address % len(self.regions[region]) offset = 0 start_offset = None mask = tlp.first_be length = tlp.length # perform write data = tlp.get_data() # first dword for k in range(4): if mask & (1 << k): if start_offset is None: start_offset = offset else: if start_offset is not None and offset != start_offset: self.regions[region][addr + start_offset:addr + offset] = data[ start_offset:offset] start_offset = None offset += 1 if length > 2: # middle dwords if start_offset is None: start_offset = offset offset += (length - 2) * 4 if length > 1: # last dword mask = tlp.last_be for k in range(4): if mask & (1 << k): if start_offset is None: start_offset = offset else: if start_offset is not None and offset != start_offset: self.regions[region][addr + start_offset:addr + offset] = data[ start_offset:offset] start_offset = None offset += 1 if start_offset is not None and offset != start_offset: self.regions[region][addr + start_offset:addr + offset] = data[start_offset:offset]
async def dma_mem_read(self, addr, length, timeout=0, timeout_unit='ns'): data = b'' n = 0 while True: tlp = Tlp_us() if addr > 0xffffffff: tlp.fmt_type = TlpType.MEM_READ_64 else: tlp.fmt_type = TlpType.MEM_READ tlp.requester_id = PcieId(0, 0, 0) first_pad = addr % 4 byte_length = length - n # max read request size byte_length = min( byte_length, (128 << self.dut.cfg_max_read_req.value.integer) - first_pad) # 4k address align byte_length = min(byte_length, 0x1000 - (addr & 0xfff)) tlp.set_addr_be(addr, byte_length) tlp.tag = await self.alloc_tag() await self.rq_source.send(tlp.pack_us_rq()) m = 0 while True: pkt = await self.rc_sink.recv() if not pkt: raise Exception("Timeout") cpl = Tlp_us.unpack_us_rc(pkt) if cpl.status != CplStatus.SC: raise Exception("Unsuccessful completion") else: assert cpl.byte_count + 3 + (cpl.lower_address & 3) >= cpl.length * 4 assert cpl.byte_count == max(byte_length - m, 1) d = cpl.get_data() offset = cpl.lower_address & 3 data += d[offset:offset + cpl.byte_count] m += len(d) - offset if m >= byte_length: break self.release_tag(tlp.tag) n += byte_length addr += byte_length if n >= length: break return data[:length]
async def _run_cq(self): while True: pkt = await self.cq_sink.recv() tlp = Tlp_us.unpack_us_cq(pkt) self.log.debug("CQ TLP: %s", repr(tlp)) if tlp.fmt_type == TlpType.IO_READ: self.log.info("IO read") cpl = Tlp_us.create_completion_data_for_tlp( tlp, PcieId(0, 0, 0)) region = tlp.bar_id addr = tlp.address % len(self.regions[region]) offset = 0 start_offset = None mask = tlp.first_be # perform operation data = bytearray(4) for k in range(4): if mask & (1 << k): if start_offset is None: start_offset = offset else: if start_offset is not None and offset != start_offset: data[start_offset:offset] = self.regions[region][ addr + start_offset:addr + offset] start_offset = None offset += 1 if start_offset is not None and offset != start_offset: data[start_offset:offset] = self.regions[region][ addr + start_offset:addr + offset] cpl.set_data(data) cpl.byte_count = 4 cpl.length = 1 self.log.debug("Completion: %s", repr(cpl)) await self.cc_source.send(cpl.pack_us_cc()) elif tlp.fmt_type == TlpType.IO_WRITE: self.log.info("IO write") cpl = Tlp_us.create_completion_for_tlp(tlp, PcieId(0, 0, 0)) region = tlp.bar_id addr = tlp.address % len(self.regions[region]) offset = 0 start_offset = None mask = tlp.first_be # perform operation data = tlp.get_data() for k in range(4): if mask & (1 << k): if start_offset is None: start_offset = offset else: if start_offset is not None and offset != start_offset: self.regions[region][addr + start_offset:addr + offset] = data[ start_offset:offset] start_offset = None offset += 1 if start_offset is not None and offset != start_offset: self.regions[region][addr + start_offset:addr + offset] = data[start_offset:offset] self.log.debug("Completion: %s", repr(cpl)) await self.cc_source.send(cpl.pack_us_cc()) elif tlp.fmt_type in {TlpType.MEM_READ, TlpType.MEM_READ_64}: self.log.info("Memory read") # perform operation region = tlp.bar_id addr = tlp.address % len(self.regions[region]) offset = 0 length = tlp.length # perform read data = self.regions[region][addr:addr + length * 4] # prepare completion TLP(s) m = 0 n = 0 addr = tlp.address + tlp.get_first_be_offset() dw_length = tlp.length byte_length = tlp.get_be_byte_count() while m < dw_length: cpl = Tlp_us.create_completion_data_for_tlp( tlp, PcieId(0, 0, 0)) cpl_dw_length = dw_length - m cpl_byte_length = byte_length - n cpl.byte_count = cpl_byte_length if cpl_dw_length > 32 << self.dut.cfg_max_payload.value.integer: # max payload size cpl_dw_length = 32 << self.dut.cfg_max_payload.value.integer # RCB align cpl_dw_length -= (addr & 0x7c) >> 2 cpl.lower_address = addr & 0x7f cpl.set_data(data[m * 4:(m + cpl_dw_length) * 4]) self.log.debug("Completion: %s", repr(cpl)) await self.cc_source.send(cpl.pack_us_cc()) m += cpl_dw_length n += cpl_dw_length * 4 - (addr & 3) addr += cpl_dw_length * 4 - (addr & 3) elif tlp.fmt_type in {TlpType.MEM_WRITE, TlpType.MEM_WRITE_64}: self.log.info("Memory write") # perform operation region = tlp.bar_id addr = tlp.address % len(self.regions[region]) offset = 0 start_offset = None mask = tlp.first_be length = tlp.length # perform write data = tlp.get_data() # first dword for k in range(4): if mask & (1 << k): if start_offset is None: start_offset = offset else: if start_offset is not None and offset != start_offset: self.regions[region][addr + start_offset:addr + offset] = data[ start_offset:offset] start_offset = None offset += 1 if length > 2: # middle dwords if start_offset is None: start_offset = offset offset += (length - 2) * 4 if length > 1: # last dword mask = tlp.last_be for k in range(4): if mask & (1 << k): if start_offset is None: start_offset = offset else: if start_offset is not None and offset != start_offset: self.regions[region][addr + start_offset:addr + offset] = data[ start_offset:offset] start_offset = None offset += 1 if start_offset is not None and offset != start_offset: self.regions[region][addr + start_offset:addr + offset] = data[start_offset:offset]
async def upstream_recv(self, tlp): self.log.debug("Got downstream TLP: %s", repr(tlp)) if tlp.fmt_type == TlpType.CFG_READ_0 or tlp.fmt_type == TlpType.CFG_WRITE_0: # config type 0 if not self.config_space_enable: self.log.warning("Configuraion space disabled") cpl = Tlp.create_crs_completion_for_tlp(tlp, PcieId(self.bus_num, self.device_num, 0)) self.log.debug("CRS Completion: %s", repr(cpl)) await self.upstream_send(cpl) return elif tlp.dest_id.device == self.device_num: # capture address information self.bus_num = tlp.dest_id.bus for f in self.functions: f.pci_id = f.pcie_id._replace(bus=self.bus_num) # pass TLP to function for f in self.functions: if f.function_num == tlp.dest_id.function: await f.upstream_recv(tlp) return self.log.info("Function not found") else: self.log.info("Device number mismatch") # Unsupported request cpl = Tlp.create_ur_completion_for_tlp(tlp, PcieId(self.bus_num, self.device_num, 0)) self.log.debug("UR Completion: %s", repr(cpl)) await self.upstream_send(cpl) elif (tlp.fmt_type == TlpType.CPL or tlp.fmt_type == TlpType.CPL_DATA or tlp.fmt_type == TlpType.CPL_LOCKED or tlp.fmt_type == TlpType.CPL_LOCKED_DATA): # Completion if tlp.requester_id.bus == self.bus_num and tlp.requester_id.device == self.device_num: for f in self.functions: if f.function_num == tlp.requester_id.function: tlp = Tlp_us(tlp) tlp.error_code = ErrorCode.NORMAL_TERMINATION if tlp.status != CplStatus.SC: tlp.error = ErrorCode.BAD_STATUS self.rc_queue.append(tlp) return self.log.info("Function not found") else: self.log.info("Device number mismatch") elif (tlp.fmt_type == TlpType.IO_READ or tlp.fmt_type == TlpType.IO_WRITE): # IO read/write for f in self.functions: bar = f.match_bar(tlp.address, True) if len(bar) == 1: tlp = Tlp_us(tlp) tlp.bar_id = bar[0][0] tlp.bar_aperture = (~self.functions[0].bar_mask[bar[0][0]] & 0xffffffff).bit_length() tlp.completer_id = PcieId(self.bus_num, self.device_num, f.function_num) self.cq_queue.append(tlp) return self.log.info("IO request did not match any BARs") # Unsupported request cpl = Tlp.create_ur_completion_for_tlp(tlp, PcieId(self.bus_num, self.device_num, 0)) self.log.debug("UR Completion: %s", repr(cpl)) await self.upstream_send(cpl) elif (tlp.fmt_type == TlpType.MEM_READ or tlp.fmt_type == TlpType.MEM_READ_64 or tlp.fmt_type == TlpType.MEM_WRITE or tlp.fmt_type == TlpType.MEM_WRITE_64): # Memory read/write for f in self.functions: bar = f.match_bar(tlp.address) if len(bar) == 1: tlp = Tlp_us(tlp) tlp.bar_id = bar[0][0] if self.functions[0].bar[bar[0][0]] & 4: tlp.bar_aperture = (~(self.functions[0].bar_mask[bar[0][0]] | (self.functions[0].bar_mask[bar[0][0]+1] << 32)) & 0xffffffffffffffff).bit_length() else: tlp.bar_aperture = (~self.functions[0].bar_mask[bar[0][0]] & 0xffffffff).bit_length() tlp.completer_id = PcieId(self.bus_num, self.device_num, f.function_num) self.cq_queue.append(tlp) return self.log.info("Memory request did not match any BARs") if tlp.fmt_type == TlpType.MEM_READ or tlp.fmt_type == TlpType.MEM_READ_64: # Unsupported request cpl = Tlp.create_ur_completion_for_tlp(tlp, PcieId(self.bus_num, self.device_num, 0)) self.log.debug("UR Completion: %s", repr(cpl)) await self.upstream_send(cpl) else: raise Exception("TODO")