def _check_pkgs(dut): bypass_reader_signal_aliases = { 'debug_out': 'out_bypass', 'debug_out_ready': 'out_bypass_ready' } bypass_reader = NocDiReader(dut, dut.clk, bypass_reader_signal_aliases) reg_reader_signal_aliases = { 'debug_out': 'out_reg', 'debug_out_ready': 'out_reg_ready' } reg_reader = NocDiReader(dut, dut.clk, reg_reader_signal_aliases) pkg_rcv_cnt = 0 while True: yield RisingEdge(dut.clk) bypass_active = dut.out_bypass.valid.value and dut.out_bypass_ready.value reg_active = dut.out_reg.valid.value and dut.out_reg_ready.value if not (bypass_active or reg_active): continue if bypass_active and reg_active: raise TestFailure( "Both out_*.valid signals are high. Invalid state.") if len(_sent_pkgs) == 0: raise TestFailure( "Got valid signal even though no packet has been sent.") sent_pkg = _sent_pkgs.pop(0) if bypass_active: if sent_pkg.type == DiPacket.TYPE.REG.value: raise TestFailure( "out_bypass.valid signal is high even though " "we have sent a REG packet: Sent packet was " "%s" % str(sent_pkg)) rcv_pkg = yield bypass_reader.receive_packet() if reg_active: if not sent_pkg.type == DiPacket.TYPE.REG.value: raise TestFailure("out_reg.valid signal is high even though " "we have *not* sent a REG packet. Sent " "packet was %s" % str(sent_pkg)) rcv_pkg = yield reg_reader.receive_packet() if not rcv_pkg: raise TestFailure("Packet lost.") if not rcv_pkg.equal_to(dut, sent_pkg): raise TestFailure("Data corruption.") pkg_rcv_cnt += 1 if pkg_rcv_cnt == STRESS_TEST_PKG_COUNT: return
def test_fixedwidth(dut): """Test the generation of two packets with a byte padding""" yield _init_dut(dut) dut.id <= MODULE_DI_ADDRESS dut.dest <= SENDER_DI_ADDRESS data_str = '\xef\x12\x34\xde\xad\xbe\xef\xef\xab\xab\xcd' dut.data.value = BinaryValue(data_str) dut.overflow <= 0 dut.event_available <= 1 # packet 1 exp_pkg = DiPacket() exp_pkg.set_contents(dest=SENDER_DI_ADDRESS, src=MODULE_DI_ADDRESS, type=DiPacket.TYPE.EVENT, type_sub=1, payload=[0xabcd, 0xefab, 0xbeef, 0x0dead, 0x1234]) reader = NocDiReader(dut, dut.clk) rcv_pkg = yield reader.receive_packet(set_ready=True) if not rcv_pkg: raise TestFailure("No packet 1 generated!") if not rcv_pkg.equal_to(dut, exp_pkg): raise TestFailure("Received packet 1 doesn't match expected packet. " "Got %s, expected %s" % (str(rcv_pkg), str(exp_pkg))) # packet 2 yield RisingEdge(dut.clk) exp_pkg = DiPacket() exp_pkg.set_contents(dest=SENDER_DI_ADDRESS, src=MODULE_DI_ADDRESS, type=DiPacket.TYPE.EVENT, type_sub=0, payload=[0x00ef]) reader = NocDiReader(dut, dut.clk) rcv_pkg = yield reader.receive_packet(set_ready=True) if not rcv_pkg: raise TestFailure("No packet 2 generated!") if not rcv_pkg.equal_to(dut, exp_pkg): raise TestFailure("Received packet 2 doesn't match expected packet. " "Got %s, expected %s" % (str(rcv_pkg), str(exp_pkg))) # check if the DUT is ready for the next event transfer if not dut.event_consumed.value: raise TestFailure("DUT does not indicate that the event has been " "consumed.")
def _dem_to_di_rx(dut, num_transfers=500, max_delay=100): reader = NocDiReader(dut, dut.clk) ex_packet = DiPacket() for i in range(num_transfers): delay = random.randint(0, max_delay) for _ in range(delay): yield RisingEdge(dut.clk) rx_packet = yield reader.receive_packet(set_ready=True) data = _dem_to_di_fifo.pop(0) ex_packet.set_contents(dest=SENDER_DI_ADDRESS, src=MODULE_DI_ADDRESS, type=DiPacket.TYPE.EVENT, type_sub=0, payload=[data]) if not rx_packet: raise TestFailure("receive_packet() timed out") if not rx_packet.equal_to(dut, ex_packet, mask=None): raise TestFailure("Unexpected content of " + rx_packet.__str__() + "\n Expected " + ex_packet.__str__()) yield RisingEdge(dut.clk)
def _trigger_reg_wr_req_err(dut, dest, src, word_width, regaddr, value): """ Sends a register write request to the module and checks if an error response gets returned. """ tx_packet = DiPacket() rx_packet = DiPacket() writer = NocDiWriter(dut, dut.clk) reader = NocDiReader(dut, dut.clk) if word_width == 16: type_sub = DiPacket.TYPE_SUB.REQ_WRITE_REG_16.value words = 1 elif word_width == 32: type_sub = DiPacket.TYPE_SUB.REQ_WRITE_REG_32.value words = 2 elif word_width == 64: type_sub = DiPacket.TYPE_SUB.REQ_WRITE_REG_64.value words = 4 elif word_width == 128: type_sub = DiPacket.TYPE_SUB.REQ_WRITE_REG_128.value words = 8 else: raise TestFailure("An invalid register width parameter was chosen! (%d)" %\ word_width) # Assemble payload of REG debug packet payload = [regaddr] for w in range(0, words): payload.append((value >> ((words - 1 - w) * 16)) & 0xFFFF) tx_packet.set_contents(dest=dest, src=src, type=DiPacket.TYPE.REG.value, type_sub=type_sub, payload=payload) yield writer.send_packet(tx_packet) rx_packet = yield reader.receive_packet(set_ready=True) if not rx_packet: raise TestFailure("No response packet received!") if rx_packet.type_sub != DiPacket.TYPE_SUB.RESP_WRITE_REG_ERROR.value: raise TestFailure( "Register write did not return RESP_WRITE_REG_ERROR " "when writing 0x%x to register 0x%x of module 0x%x." % (value, regaddr, dest))
def test_only_regaccess_ready(dut): """ Check if a register access packet passes through, even though the bypass ready signal is tied to 0. """ yield _init_dut(dut) dut.out_reg_ready <= 1 dut.out_bypass_ready <= 0 reg_reader_signal_aliases = { 'debug_out': 'out_reg', 'debug_out_ready': 'out_reg_ready' } reg_reader = NocDiReader(dut, dut.clk, reg_reader_signal_aliases) writer_signal_aliases = {'debug_in': 'in', 'debug_in_ready': 'in_ready'} writer = NocDiWriter(dut, dut.clk, writer_signal_aliases) reg_pkg = DiPacket() reg_pkg.set_contents(dest=1, src=0, type=DiPacket.TYPE.REG.value, type_sub=DiPacket.TYPE_SUB.REQ_WRITE_REG_16.value, payload=[0xdead]) # send a register write packet to the DUT write_thread = cocotb.fork(writer.send_packet(reg_pkg)) # ensure that the bypass valid signal isn't asserted checker_thread = cocotb.fork( _assert_signal_stays_low(dut.clk, dut.out_bypass.valid)) # get packet on reg output rcv_pkg = yield reg_reader.receive_packet() yield write_thread.join() checker_thread.kill() if not rcv_pkg: raise TestFailure("Register access packet not routed to output.") if not rcv_pkg.equal_to(dut, reg_pkg): raise TestFailure("Data corruption.")
def test_event_pkg(dut): """ Check if a register access packet passes through """ yield _init_dut(dut) dut.out_reg_ready <= 1 dut.out_bypass_ready <= 1 bypass_reader_signal_aliases = { 'debug_out': 'out_bypass', 'debug_out_ready': 'out_bypass_ready' } bypass_reader = NocDiReader(dut, dut.clk, bypass_reader_signal_aliases) writer_signal_aliases = {'debug_in': 'in', 'debug_in_ready': 'in_ready'} writer = NocDiWriter(dut, dut.clk, writer_signal_aliases) event_pkg = DiPacket() event_pkg.set_contents(dest=1, src=0, type=DiPacket.TYPE.EVENT.value, type_sub=0, payload=[0xdead]) # send an event packet to the DUT write_thread = cocotb.fork(writer.send_packet(event_pkg)) # ensure that the register output valid signal isn't asserted checker_thread = cocotb.fork( _assert_signal_stays_low(dut.clk, dut.out_reg.valid)) # get packet on bypass output rcv_pkg = yield bypass_reader.receive_packet() yield write_thread.join() checker_thread.kill() if not rcv_pkg: raise TestFailure("Event access packet not routed to output.") if not rcv_pkg.equal_to(dut, event_pkg): raise TestFailure("Data corruption.")
def _trigger_reg_rd_req_err(dut, dest, src, word_width, regaddr): """ Sends a register read request to the module and checks if an error response gets returned. """ tx_packet = DiPacket() rx_packet = DiPacket() writer = NocDiWriter(dut, dut.clk) reader = NocDiReader(dut, dut.clk) if word_width == 16: type_sub = DiPacket.TYPE_SUB.REQ_READ_REG_16.value elif word_width == 32: type_sub = DiPacket.TYPE_SUB.REQ_READ_REG_32.value elif word_width == 64: type_sub = DiPacket.TYPE_SUB.REQ_READ_REG_64.value elif word_width == 128: type_sub = DiPacket.TYPE_SUB.REQ_READ_REG_128.value else: raise TestFailure("An invalid register width parameter was chosen! (%d)" %\ word_width) tx_packet.set_contents(dest=dest, src=src, type=DiPacket.TYPE.REG.value, type_sub=type_sub, payload=[regaddr]) yield writer.send_packet(tx_packet) rx_packet = yield reader.receive_packet(set_ready=True) if not rx_packet: raise TestFailure("No response packet received!") if rx_packet.type_sub != DiPacket.TYPE_SUB.RESP_READ_REG_ERROR.value: raise TestFailure("Register read did not return RESP_READ_REG_ERROR " "when reading from register 0x%x of module 0x%x." % (regaddr, dest))
def _assert_trace_event(dut, trace_id, trace_value): """ Stimuli on the trace port will be generated once to trigger the emission of a new debug event packet which will be read and evaluated. """ generator = StmTraceGenerator() reader = NocDiReader(dut, dut.clk) # Build expected packet expected_packet = DiPacket() exp_payload = [0, 0, trace_id] payload_words = int(dut.VALWIDTH.value.integer / 16) for w in range(0, payload_words): exp_payload.append(trace_value >> (w * 16) & 0xFFFF) expected_packet.set_contents(dest=SENDER_DI_ADDRESS, src=MODULE_DI_ADDRESS, type=DiPacket.TYPE.EVENT.value, type_sub=0, payload=exp_payload) # Build comparison mask for expected packet # Ignore flits 0 and 1 with timestamp exp_payload_mask = [1] * len(exp_payload) exp_payload_mask[0] = 0 exp_payload_mask[1] = 0 yield generator.trigger_event(dut, trace_id, trace_value) rcv_pkg = yield reader.receive_packet(set_ready=True) if not rcv_pkg: raise TestFailure("No response received!") if not rcv_pkg.equal_to(dut, expected_packet, exp_payload_mask): raise TestFailure( "The STM generated an unexpected debug event packet!")
class MamDiDriver: """ MAM memory transfer driver on the Debug Interconnect """ def __init__(self, entity, clock, di_writer=None, di_reader=None, MAX_PKT_LEN=12, MODULE_DI_ADDRESS=1, SENDER_DI_ADDRESS=0): self.entity = entity self.clock = clock self.log = entity._log self.MAX_PKT_LEN = MAX_PKT_LEN self.MODULE_DI_ADDRESS = MODULE_DI_ADDRESS self.SENDER_DI_ADDRESS = SENDER_DI_ADDRESS if di_writer: self.di_writer = di_writer else: self.di_writer = NocDiWriter(entity, clock) if di_reader: self.di_reader = di_reader else: self.di_reader = NocDiReader(entity, clock) def _create_mam_transfer(self, mem_transfer): """ Get MAM transfer bytearray representing the memory transfer """ mam_transfer = bytearray() we = (mem_transfer.operation == 'write') selsize = 0 if mem_transfer.burst: selsize = int(len(mem_transfer.data) / (mem_transfer.DW / 8)) else: selsize = mem_transfer.byteselect if selsize > 0xFF: raise TestFailure("selsize overflow detected") hdr0 = 0 hdr0 |= (we & 0x1) << 7 hdr0 |= (mem_transfer.burst & 0x1) << 6 hdr0 |= (mem_transfer.sync & 0x1) << 5 hdr1 = selsize mam_transfer.append(hdr0) mam_transfer.append(hdr1) mam_transfer.extend(mem_transfer.addr.to_bytes(int(mem_transfer.AW / 8), byteorder='big')) if mem_transfer.operation == 'write' and mem_transfer.data: mam_transfer.extend(mem_transfer.data) return mam_transfer def _create_di_pkgs(self, mam_transfer): """ Get DI packages representing the memory transfer """ pkgs = [] max_payload_bytes = (self.MAX_PKT_LEN - 3) * 2 number_of_pkgs = ceil(len(mam_transfer) / max_payload_bytes) b = 0 for _ in range(number_of_pkgs): pkg = DiPacket() pkg.dest = self.MODULE_DI_ADDRESS pkg.src = self.SENDER_DI_ADDRESS pkg.type = DiPacket.TYPE.EVENT.value pkg.type_sub = 0 for i in range(int(max_payload_bytes / 2)): payload_word = mam_transfer[b] << 8 | mam_transfer[b + 1] pkg.payload.append(payload_word) b += 2 if b >= len(mam_transfer): break pkgs.append(pkg) return pkgs @cocotb.coroutine def drive(self, mem_transfer): """ Drive the Debug Interconnect with a memory transfer and check the results """ # request mam_transfer_request = self._create_mam_transfer(mem_transfer) req_pkgs = self._create_di_pkgs(mam_transfer_request) for pkg in req_pkgs: yield self.di_writer.send_packet(pkg) # response if mem_transfer.operation == 'read': rcv_data = bytearray() while len(rcv_data) < len(mem_transfer.data): yield RisingEdge(self.clock) pkg = yield self.di_reader.receive_packet(set_ready=True) self.log.debug("Received memory read response " + str(pkg)) for payload_word in pkg.payload: rcv_data.extend(payload_word.to_bytes(2, byteorder='big')) # check received data if rcv_data != mem_transfer.data: raise TestFailure("Got invalid data.\nExpected: %s\nReceived: %s" % (mem_transfer.data.hex(), rcv_data.hex())) # for synchronous writes: check if we received a acknowledgement packet if mem_transfer.operation == 'write' and mem_transfer.sync: pkg = yield self.di_reader.receive_packet(set_ready=True) exp_sync_pkg = DiPacket() exp_sync_pkg.set_contents(self.SENDER_DI_ADDRESS, self.MODULE_DI_ADDRESS, DiPacket.TYPE.EVENT.value, 0, []) if not pkg.equal_to(self.entity, exp_sync_pkg): raise TestFailure( "Acknowledgement packet for sync write invalid.")
def test_fixedwidth(dut): """Test the generation of two packets with a byte padding""" yield _init_dut(dut) dut.id <= MODULE_DI_ADDRESS dut.dest <= SENDER_DI_ADDRESS # create data for two packets: one full packet, and one packet with # only a single payload word payload_words_per_pkg = dut.MAX_PKT_LEN.value.integer - 3 # 3 header words payload_bytes = (payload_words_per_pkg + 1) * 2 data_bytes = bytearray(random.getrandbits(8) for _ in range(payload_bytes)) data_int = int.from_bytes(data_bytes, byteorder='little', signed=False) dut.data.value = BinaryValue(data_int) dut.overflow <= 0 dut.event_available <= 1 # packet 1 exp_pkg1_payload = [data_bytes[i+1] << 8 | data_bytes[i] for i in range(0, payload_words_per_pkg * 2, 2)] exp_pkg = DiPacket() exp_pkg.set_contents(dest=SENDER_DI_ADDRESS, src=MODULE_DI_ADDRESS, type=DiPacket.TYPE.EVENT, type_sub=1, payload=exp_pkg1_payload) reader = NocDiReader(dut, dut.clk) rcv_pkg = yield reader.receive_packet(set_ready=True) if not rcv_pkg: raise TestFailure("No packet 1 generated!") if not rcv_pkg.equal_to(dut, exp_pkg): raise TestFailure("Received packet 1 doesn't match expected packet. " "Got %s, expected %s" % (str(rcv_pkg), str(exp_pkg))) # packet 2 yield RisingEdge(dut.clk) exp_pkg2_payload = [data_bytes[i+1] << 8 | data_bytes[i] for i in range(payload_words_per_pkg * 2, payload_bytes, 2)] exp_pkg = DiPacket() exp_pkg.set_contents(dest=SENDER_DI_ADDRESS, src=MODULE_DI_ADDRESS, type=DiPacket.TYPE.EVENT, type_sub=0, payload=exp_pkg2_payload) reader = NocDiReader(dut, dut.clk) rcv_pkg = yield reader.receive_packet(set_ready=True) if not rcv_pkg: raise TestFailure("No packet 2 generated!") if not rcv_pkg.equal_to(dut, exp_pkg): raise TestFailure("Received packet 2 doesn't match expected packet. " "Got %s, expected %s" % (str(rcv_pkg), str(exp_pkg))) # check if the DUT is ready for the next event transfer if not dut.event_consumed.value: raise TestFailure("DUT does not indicate that the event has been " "consumed.")