class Thing: def __init__(self, dut): self.dut = dut self.st_in = AvalonSTDriver(dut, 'st_in', dut.clk) self.st_out = AvalonSTMonitor(dut, 'st_out', dut.clk) self.csr = AvalonMaster(dut, 'csr', dut.clk) self.st_in_recovered = AvalonSTMonitor(dut, 'st_in', dut.clk, callback=self.model) self.expected_output = [] self.scoreboard = Scoreboard(dut) self.scoreboard.add_interface(self.st_out, self.expected_output) def model(self, transaction): """Model the DUT based on the input transaction.""" self.expected_output.append(transaction) self.st_in_recovered.log.info(hexdump(transaction)) async def reset(self): self.dut.reset <= 1 await Timer(50, units='us') self.dut.reset <= 0 self.dut.st_out_ready <= 1 self.dut.reset._log.debug('Reset complete')
class TB(object): def __init__(self, dut): # Some internal state self.dut = dut self.stopped = False # Use the input monitor to reconstruct the transactions from the pins # and send them to our 'model' of the design. self.input_mon = BitMonitor(name="input", signal=dut.Zybo_Example_sw_in, clk=dut.clk, callback=self.model) # Create input driver and output monitor self.input_drv = BitDriver(signal=dut.Zybo_Example_sw_in, clk=dut.clk, generator=input_gen()) self.output_mon = BitMonitor(name="output", signal=dut.Zybo_Example_leds_out, clk=dut.clk) # Create a scoreboard on the outputs self.expected_output = [] self.scoreboard = Scoreboard(dut) self.scoreboard.add_interface(self.output_mon, self.expected_output) def model(self, transaction): if not self.stopped: self.expected_output.append(transaction) def start(self): self.input_drv.start() def stop(self): self.input_drv.stop() self.stopped = True
class Thing: """Commmon test logic for all tests.""" def __init__(self, dut): self.dut = dut # TODO: See https://github.com/cocotb/cocotb/issues/2051 for Verilator freeze bug self.userrx = AvalonSTMonitor(dut, 'userrx', dut.rx_clk) self.tx_csr = AvalonMaster(dut, 'tx_mm', dut.tx_clk) self.rx_csr = AvalonMaster(dut, 'rx_mm', dut.rx_clk) self.expected_output = [] self.scoreboard = Scoreboard(dut) self.scoreboard.add_interface(self.userrx, self.expected_output) @staticmethod async def new(dut): rx_clock = Clock(dut.rx_clk, 10, units='us') tx_clock = Clock(dut.tx_clk, 10, units='us') cocotb.fork(rx_clock.start()) cocotb.fork(tx_clock.start()) # Ensure the bus is in a known and quiet state before starting the monitors await Thing.reset(dut) return Thing(dut) @staticmethod async def reset(dut): dut.reset <= 1 await Timer(30, units='us') dut.reset <= 0 dut.avtx_ready <= 1 dut.reset._log.info('Reset complete')
class AvalonSTTB(object): """Testbench for avalon basic stream""" def __init__(self, dut): self.dut = dut self.clkedge = RisingEdge(dut.clk) self.stream_in = AvalonSTDriver(self.dut, "asi", dut.clk) self.stream_out = AvalonSTMonitor(self.dut, "aso", dut.clk) with warnings.catch_warnings(): warnings.simplefilter("ignore") self.scoreboard = Scoreboard(self.dut, fail_immediately=True) self.expected_output = [] self.scoreboard.add_interface(self.stream_out, self.expected_output) self.backpressure = BitDriver(self.dut.aso_ready, self.dut.clk) @cocotb.coroutine def initialise(self): self.dut.reset <= 0 cocotb.fork(Clock(self.dut.clk, 10).start()) for _ in range(3): yield self.clkedge self.dut.reset <= 1 yield self.clkedge @cocotb.coroutine def send_data(self, data): exp_data = struct.pack("B", data) self.expected_output.append(exp_data) yield self.stream_in.send(data)
async def test_tdata(dut, packets_num=5, packet_size=(10, 100), delay=-1, consecutive_transfers=0): """Test TDATA""" tdata_width = dut.C_S_AXIS_TDATA_WIDTH.value.integer axis_m = Axi4StreamMaster(dut, "s_axis", dut.aclk) axis_s = Axi4StreamSlave(dut, "m_axis", dut.aclk, delay, consecutive_transfers) axis_monitor = Axi4Stream(dut, "m_axis", dut.aclk, data_type="integer", packets=True) await setup_dut(dut) input = [] output = [] # Build the input and output packets for i in range(packets_num): input.append([randint(0, 2**tdata_width - 1) for i in range(randint(*packet_size))]) output.append([word ^ 2**tdata_width - 1 for word in input[-1]]) scoreboard = Scoreboard(dut) scoreboard.add_interface(axis_monitor, output) # Write the input packets for packet in input: await axis_m.write(packet) # Wait until output is empty (so, all the packets have been received) while output: await RisingEdge(dut.aclk) await RisingEdge(dut.aclk)
class DFF_TB(object): def __init__(self, dut, init_val): """ Setup the testbench. *init_val* signifies the ``BinaryValue`` which must be captured by the output monitor with the first rising clock edge. This must match the initial state of the D flip-flop in RTL. """ # Some internal state self.dut = dut self.stopped = False # Create input driver and output monitor self.input_drv = BitDriver(signal=dut.d, clk=dut.c, generator=input_gen()) self.output_mon = BitMonitor(name="output", signal=dut.q, clk=dut.c) # Create a scoreboard on the outputs self.expected_output = [init_val ] # a list with init_val as the first element with warnings.catch_warnings(): warnings.simplefilter("ignore") self.scoreboard = Scoreboard(dut) self.scoreboard.add_interface(self.output_mon, self.expected_output) # Use the input monitor to reconstruct the transactions from the pins # and send them to our 'model' of the design. self.input_mon = BitMonitor(name="input", signal=dut.d, clk=dut.c, callback=self.model) def model(self, transaction): """Model the DUT based on the input *transaction*. For a D flip-flop, what goes in at ``d`` comes out on ``q``, so the value on ``d`` (put into *transaction* by our ``input_mon``) can be used as expected output without change. Thus we can directly append *transaction* to the ``expected_output`` list, except for the very last clock cycle of the simulation (that is, after ``stop()`` has been called). """ if not self.stopped: self.expected_output.append(transaction) def start(self): """Start generating input data.""" self.input_drv.start() def stop(self): """Stop generating input data. Also stop generation of expected output transactions. One more clock cycle must be executed afterwards so that the output of the D flip-flop can be checked. """ self.input_drv.stop() self.stopped = True
class Thing: """Commmon test logic for all tests.""" def __init__(self, dut): self.dut = dut self.st_in = AvalonSTDriver(dut, 'st_in', dut.clk) self.st_out = AvalonSTMonitor(dut, 'st_out', dut.clk) self.csr = AvalonMaster(dut, 'csr', dut.clk) self.st_in_recovered = AvalonSTMonitor(dut, 'st_in', dut.clk, callback=self.model) self.expected_output = [] self.scoreboard = Scoreboard(dut) self.scoreboard.add_interface(self.st_out, self.expected_output) @staticmethod async def new(dut): # Ensure the bus is in a known and quiet state before starting the monitors await Thing.reset(dut) return Thing(dut) @staticmethod async def reset(dut): dut.reset <= 1 await Timer(50, units='us') dut.reset <= 0 dut.st_out_ready <= 1 dut.reset._log.debug('Reset complete') def model(self, transaction): """Model the DUT based on the input transaction.""" self.expected_output.append(transaction) self.st_in_recovered.log.info(hexdump(transaction))
def mean_mdv_test(dut): """ Test using functional coverage measurements and Constrained-Random mechanisms. Generates random transactions until coverage defined in Driver reaches 100% """ dut_out = StreamBusMonitor(dut, "o", dut.clk) dut_in = StreamBusDriver(dut, "i", dut.clk) exp_out = [] scoreboard = Scoreboard(dut) scoreboard.add_interface(dut_out, exp_out) data_width = int(dut.DATA_WIDTH.value) bus_width = int(dut.BUS_WIDTH.value) dut._log.info('Detected DATA_WIDTH = %d, BUS_WIDTH = %d' % (data_width, bus_width)) cocotb.fork(clock_gen(dut.clk, period=clock_period)) dut.rst <= 1 for i in range(bus_width): dut.i_data[i] = 0 dut.i_valid <= 0 yield RisingEdge(dut.clk) yield RisingEdge(dut.clk) dut.rst <= 0 coverage1_hits = [] coverageN_hits = [] #define a constraint function, which prevents from picking already covered data def data_constraint(data): return (not data[0] in coverage1_hits) & (not data[bus_width - 1] in coverageN_hits) coverage = 0 xaction = StreamTransaction(bus_width, data_width) while coverage < 100: #randomize without constraint #xaction.randomize() #randomize with constraint if not "top.data1" in cocotb.coverage.coverage_db: xaction.randomize() else: coverage1_new_bins = cocotb.coverage.coverage_db[ "top.data1"].new_hits coverageN_new_bins = cocotb.coverage.coverage_db[ "top.dataN"].new_hits coverage1_hits.extend(coverage1_new_bins) coverageN_hits.extend(coverageN_new_bins) xaction.randomize_with(data_constraint) yield dut_in.send(xaction) exp_out.append(xaction.mean_value()) coverage = cocotb.coverage.coverage_db[ "top"].coverage * 100 / cocotb.coverage.coverage_db["top"].size dut._log.info("Current Coverage = %d %%", coverage)
class HashEngineTB(object): def __init__(self, dut, codec, debug=False): dut._log.info( f"Preparing tb for hashing-engine, codec={Sha.resolve_name(codec)}" ) self.dut = dut self.codec = codec # sha_type_actual self.sha = Sha.get_method(codec) self.s_axis = AXIS_Driver(dut, "s_axis", dut.axis_aclk) self.backpressure = BitDriver(dut.m_axis_tready, dut.axis_aclk) self.m_axis = AXIS_Monitor(dut, "m_axis", dut.axis_aclk) self.expected_output = [] # Create a scoreboard on the m_axis bus with warnings.catch_warnings(): warnings.simplefilter("ignore") self.scoreboard = Scoreboard(dut) self.scoreboard.add_interface(self.m_axis, self.expected_output) # Reconstrut the input transactions self.s_axis_recovered = AXIS_Monitor(dut, "s_axis", dut.axis_aclk, callback=self.model) level = logging.DEBUG if debug else logging.WARNING self.s_axis.log.setLevel(level) self.s_axis_recovered.log.setLevel(level) async def reset(self, duration=2): self.dut._log.debug("Resetting DUT") self.dut.axis_resetn <= 0 await Timer(duration, units='ns') await RisingEdge(self.dut.axis_aclk) self.dut.axis_resetn <= 1 self.dut._log.debug("Out of reset") def model(self, transaction): message = transaction['data'] self.dut._log.debug(f'Incoming message={message}') self.dut._log.debug(f'Length={len(message)}') # sha = hashlib.sha256() # sha.update(message) # digest = sha.digest() self.sha.init() self.sha.padder(message) self.sha.wt_transaction() digest = self.sha.digest() self.expected_output.append({ 'data': digest, 'user': 80 * '0' + little_endian_codec(self.codec) + 32 * '0' })
class DspBlockTB(object): def __init__(self, dut, debug=False): self.dut = dut self.stream_in = STDriver(dut, "ValNamein_0", dut.clock, name_map=axi4stream_chisel_name_map) self.backpressure = BitDriver(self.dut.out_0_ready, self.dut.clock) self.stream_out = STMonitor(dut, "out_0", dut.clock, name_map=axi4stream_chisel_name_map) self.csr = MemMaster(dut, "ValNameioMem_0", dut.clock, name_map=axi4_chisel_name_map) self.set_rotation(0) # Reconstruct the input transactions from the pins # and send them to our 'model' self.stream_in_recovered = STMonitor( dut, "ValNamein_0", dut.clock, callback=self.model, name_map=axi4stream_chisel_name_map) # Create a scoreboard on the stream_out bus self.pkts_sent = 0 self.expected_output = [] self.scoreboard = Scoreboard(dut) self.scoreboard.add_interface(self.stream_out, self.expected_output) # Set verbosity on our various interfaces level = logging.DEBUG if debug else logging.WARNING self.stream_in.log.setLevel(level) self.stream_in_recovered.log.setLevel(level) def set_rotation(self, rotation): self.rotation = rotation return self.csr.write(0, self.rotation) def model(self, transaction): """Model the DUT based on the input transaction""" ## TODO apply rotation self.expected_output.append(transaction) self.pkts_sent += 1 @cocotb.coroutine def reset(self, duration=10): self.dut._log.debug("Resetting DUT") self.dut.reset <= 1 self.stream_in.bus.TVALID <= 0 yield Timer(duration, units='ns') yield RisingEdge(self.dut.clock) self.dut.reset <= 0 self.dut._log.debug("Out of reset")
class FFTTB: def __init__(self, dut, debug: bool = False): self._dut = dut self._fft_in = DecoupledDriver(self._dut, "in", self._dut.clock) self._fft_mon = FFTMonitor(self._dut, self._dut.clock) self._backpressure = BitDriver(self._dut.out_ready, self._dut.clock) self._scoreboard = Scoreboard(self._dut) self._scoreboard.add_interface(self._fft_mon._mon_out, self._fft_mon._expected_output)
class axistream_fifo_TB(object): def __init__(self, dut): self.dut = dut self.stream_in = AXI4ST_driver(dut, "stream_in", dut.clk) #self.stream_in.log.setLevel(logging.DEBUG) self.stream_out = AXI4STMonitor(dut, "stream_out", dut.clk, callback=self.print_trans) self.expected_output = [] self.overrideModel = False # temp help to differentiate scapy to other send self.scoreboard = Scoreboard(dut, fail_immediately=False) self.scoreboard.add_interface(self.stream_out, self.expected_output) self.stream_in_recovered = AXI4STMonitor(dut, "stream_in", dut.clk, callback=self.model) def print_trans(self, transaction): # pkt = BinaryValue_to_scapy(transaction) print("received transaction {}".format(transaction)) # pkt_buf = scapy_to_BinaryValue(pkt) # print("from packet {}".format(pkt_buf)) # pkt.display() def model(self, transaction): """ Model the expected output based on input """ if not self.overrideModel: self.expected_output.append(transaction) def send(self, pkt): if isinstance(pkt, scapy_pkt): self.overrideModel = True self.expected_output.append(scapy_to_BinaryValue(pkt)) self.stream_in.append(pkt) self.overrideModel = False @cocotb.coroutine def async_rst(self): """ This function execute the reset_n for 40ns it also set all input signals to default value """ self.dut._log.info("begin Rst") self.dut.reset_n <= 0 self.dut.stream_in_tdata <= 0 self.dut.stream_in_tlast <= 0 self.dut.stream_in_tvalid <= 0 self.dut.stream_out_tready <= 0 yield Timer(40, 'ns') self.dut.reset_n <= 1 yield Timer(15, 'ns') self.dut._log.info("end Rst")
class PadderTB(object): def __init__(self, dut, codec, debug=False): dut._log.info("Preparing tb for padder, codec={codec}") self.dut = dut self.codec = codec # sha_type_actual self.sha = Sha.get_method(codec=codec) self.s_axis = AXIS_Driver(dut, "s_axis", dut.axis_aclk) self.backpressure = BitDriver(dut.m_axis_tready, dut.axis_aclk) self.m_axis = AXIS_Monitor(dut, "m_axis", dut.axis_aclk) self.expected_output = [] # Create a scoreboard on the m_axis bus with warnings.catch_warnings(): warnings.simplefilter("ignore") self.scoreboard = Scoreboard(dut) self.scoreboard.add_interface(self.m_axis, self.expected_output) # Reconstrut the input transactions self.s_axis_recovered = AXIS_Monitor(dut, "s_axis", dut.axis_aclk, callback=self.model) level = logging.DEBUG if debug else logging.WARNING self.s_axis.log.setLevel(level) self.s_axis_recovered.log.setLevel(level) async def reset(self, duration=2): self.dut._log.debug("Resetting DUT") self.dut.axis_resetn <= 0 await Timer(duration, units='ns') await RisingEdge(self.dut.axis_aclk) self.dut.axis_resetn <= 1 self.dut._log.debug("Out of reset") def model(self, transaction): message = transaction['data'] self.dut._log.debug(f'Incoming message={message}') self.dut._log.debug(f'Length={len(message)}') self.sha.init() message = self.sha.padder(message) self.expected_output.append({ 'data': message, 'user': 80 * '0' + little_endian_codec(self.codec) + 32 * '0' }) while message: self.dut._log.debug("Message block to be received: {}".format( message[0:DATA_BYTE_WIDTH])) message = message[DATA_BYTE_WIDTH:]
class DigestTB(object): def __init__(self, dut, codec, debug=False): self.dut = dut self.codec = codec self.sha = Sha.get_method(codec) self.dut._log.info("Configure driver, monitors and scoreboard") self.s_axis = AXIS_Driver(dut, "s_axis", dut.axis_aclk, lsb_first=False) self.backpressure = BitDriver(dut.m_axis_tready, dut.axis_aclk) self.m_axis = AXIS_Monitor(dut, "m_axis", dut.axis_aclk) self.expected_output = [] # Create a scoreboard on the m_axis bus with warnings.catch_warnings(): warnings.simplefilter("ignore") self.scoreboard = Scoreboard(dut) self.scoreboard.add_interface(self.m_axis, self.expected_output) # Reconstrut the input transactions self.s_axis_recovered = AXIS_Monitor(dut, "s_axis", dut.axis_aclk, callback=self.model, lsb_first=False) level = logging.DEBUG if debug else logging.WARNING self.s_axis.log.setLevel(level) self.s_axis_recovered.log.setLevel(level) async def reset(self, duration=2): self.dut._log.debug("Resetting DUT") self.dut.axis_resetn <= 0 await Timer(duration, units='ns') await RisingEdge(self.dut.axis_aclk) self.dut.axis_resetn <= 1 self.dut._log.debug("Out of reset") def model(self, transaction): message = transaction['data'] #print(f'Transaction = {transaction}') print(message) self.sha.init() digest = self.sha.digest(message) self.expected_output.append({ 'data': digest, 'user': 80 * '0' + little_endian_codec(self.codec) + 32 * '0' })
class EndianSwapperTB(object): def __init__(self, dut, debug=False): self.dut = dut self.stream_in = AvalonSTDriver(dut, "stream_in", dut.clk) self.backpressure = BitDriver(self.dut.stream_out_ready, self.dut.clk) self.stream_out = AvalonSTMonitor( dut, "stream_out", dut.clk, config={'firstSymbolInHighOrderBits': True}) self.csr = AvalonMaster(dut, "csr", dut.clk) cocotb.fork( stream_out_config_setter(dut, self.stream_out, self.stream_in)) # Create a scoreboard on the stream_out bus self.pkts_sent = 0 self.expected_output = [] with warnings.catch_warnings(): warnings.simplefilter("ignore") self.scoreboard = Scoreboard(dut) self.scoreboard.add_interface(self.stream_out, self.expected_output) # Reconstruct the input transactions from the pins # and send them to our 'model' self.stream_in_recovered = AvalonSTMonitor(dut, "stream_in", dut.clk, callback=self.model) # Set verbosity on our various interfaces level = logging.DEBUG if debug else logging.WARNING self.stream_in.log.setLevel(level) self.stream_in_recovered.log.setLevel(level) def model(self, transaction): """Model the DUT based on the input transaction""" self.expected_output.append(transaction) self.pkts_sent += 1 async def reset(self, duration=20): self.dut._log.debug("Resetting DUT") self.dut.reset_n <= 0 self.stream_in.bus.valid <= 0 await Timer(duration, units='ns') await RisingEdge(self.dut.clk) self.dut.reset_n <= 1 self.dut._log.debug("Out of reset")
class HcuTb(object): def __init__(self, dut, codec, debug=False): dut._log.info(f"Setting up test bench object with codec={codec}") self.dut = dut self.codec = codec self.sha = Sha.get_method(codec=codec) self.dut._log.info(f"Configure driver, monitors and scoreboard for {self.sha.sha_name}") self.s_axis = AXIS_Driver(dut, "s_axis", dut.axis_aclk, lsb_first=False) self.m_axis = AXIS_Monitor(dut, "m_axis", dut.axis_aclk, lsb_first=False) self.expected_output = [] # Create a scoreboard on the m_axis bus with warnings.catch_warnings(): warnings.simplefilter("ignore") self.scoreboard = Scoreboard(dut) self.scoreboard.add_interface(self.m_axis, self.expected_output) # Reconstrut the input transactions self.s_axis_recovered = AXIS_Monitor(dut, "s_axis", dut.axis_aclk, callback=self.model, lsb_first=False) level = logging.DEBUG if debug else logging.WARNING self.s_axis.log.setLevel(level) self.s_axis_recovered.log.setLevel(level) async def reset(self,duration = 2): self.dut._log.debug("Resetting DUT") self.dut.axis_resetn <= 0 await Timer(duration, units='ns') await RisingEdge(self.dut.axis_aclk) self.dut.axis_resetn <= 1 self.dut._log.debug("Out of reset") def model(self, transaction): self.dut._log.debug(f'Transaction = {transaction}') message = transaction['data'] # print(f'Length or received tansaction = {len(message)}') self.sha.init() words_block = self.sha.wt_iters while(message): for i in range(words_block): # print(f'Word to unpack: {message[i*BYTE_WIDTH_WORDS:(i+1)*BYTE_WIDTH_WORDS]}') w_temp, = struct.unpack('!Q', message[i*BYTE_WIDTH_WORDS:(i+1)*BYTE_WIDTH_WORDS]) self.sha.update(w_temp) message = message[BYTE_WIDTH_WORDS*words_block:] self.dut._log.debug(f'Hash Computed = {[hex(reg) for reg in self.sha.get_hash()]}') self.expected_output.append({'data': self.sha.get_bytes_hash(), 'user':80*'0'+little_endian_codec(self.codec)+32*'0'})
class Testbench(object): def __init__(self, dut): self.dut = dut self.stopped = False elements = dut.ELEMENTS.value; self.lru = LeastRecentlyUsedDict(size_limit=elements) # initial state of LRU list for keyin in range(elements-1, -1, -1): self.lru[keyin] = 1 init_val = elements-1 self.input_drv = InputDriver(dut) self.output_mon = OutputMonitor(dut) # Create a scoreboard on the outputs self.expected_output = [ init_val ] self.scoreboard = Scoreboard(dut) self.scoreboard.add_interface(self.output_mon, self.expected_output) # Reconstruct the input transactions from the pins # and send them to our 'model' self.input_mon = InputMonitor(dut, callback=self.model) def model(self, transaction): '''Model the DUT based on the input transaction.''' insert, free, keyin = transaction #print "=== model called with stopped=%r, Insert=%d, Free=%d, KeyIn=%d" % (self.stopped, insert, free, keyin) if not self.stopped: if insert == 1: self.lru[keyin] = 1 elif free == 1: self.lru.moveLRU(keyin) #print "=== model: lru=%s" % self.lru.items() keyout = self.lru.iterkeys().next() #print "=== model: KeyOut=%d" % keyout self.expected_output.append(keyout) def stop(self): """ Stop generation of expected output transactions. One more clock cycle must be executed afterwards, so that, output of D-FF can be checked. """ self.stopped = True
class Testbench(object): def __init__(self, dut): self.dut = dut self.stopped = False elements = dut.ELEMENTS.value self.lru = LeastRecentlyUsedDict(size_limit=elements) # initial state of LRU list for keyin in range(elements - 1, -1, -1): self.lru[keyin] = 1 init_val = elements - 1 self.input_drv = InputDriver(dut) self.output_mon = OutputMonitor(dut) # Create a scoreboard on the outputs self.expected_output = [init_val] self.scoreboard = Scoreboard(dut) self.scoreboard.add_interface(self.output_mon, self.expected_output) # Reconstruct the input transactions from the pins # and send them to our 'model' self.input_mon = InputMonitor(dut, callback=self.model) def model(self, transaction): '''Model the DUT based on the input transaction.''' insert, free, keyin = transaction #print "=== model called with stopped=%r, Insert=%d, Free=%d, KeyIn=%d" % (self.stopped, insert, free, keyin) if not self.stopped: if insert == 1: self.lru[keyin] = 1 elif free == 1: self.lru.moveLRU(keyin) #print "=== model: lru=%s" % self.lru.items() keyout = self.lru.iterkeys().next() #print "=== model: KeyOut=%d" % keyout self.expected_output.append(keyout) def stop(self): """ Stop generation of expected output transactions. One more clock cycle must be executed afterwards, so that, output of D-FF can be checked. """ self.stopped = True
class DFF_TB(object): def __init__(self, dut, init_val): """ Setup testbench. init_val signifies the BinaryValue which must be captured by the output monitor with the first risign edge. This is actually the initial state of the flip-flop. """ # Some internal state self.dut = dut self.stopped = False # Create input driver and output monitor self.input_drv = BitDriver(dut.d, dut.c, input_gen()) self.output_mon = BitMonitor("output", dut.q, dut.c) # Create a scoreboard on the outputs self.expected_output = [ init_val ] self.scoreboard = Scoreboard(dut) self.scoreboard.add_interface(self.output_mon, self.expected_output) # Reconstruct the input transactions from the pins # and send them to our 'model' self.input_mon = BitMonitor("input", dut.d, dut.c, callback=self.model) def model(self, transaction): """Model the DUT based on the input transaction.""" # Do not append an output transaction for the last clock cycle of the # simulation, that is, after stop() has been called. if not self.stopped: self.expected_output.append(transaction) def start(self): """Start generation of input data.""" self.input_drv.start() def stop(self): """ Stop generation of input data. Also stop generation of expected output transactions. One more clock cycle must be executed afterwards, so that, output of D-FF can be checked. """ self.input_drv.stop() self.stopped = True
class axistream_fifo_TB(object): def __init__(self, dut): self.dut = dut self.stream_in = AXI4ST(dut, "stream_in", dut.clk) self.stream_out = AXI4STMonitor(dut, "stream_out", dut.clk, callback=self.print_trans) self.expected_output = [] self.scoreboard = Scoreboard(dut, fail_immediately=True) self.scoreboard.add_interface(self.stream_out, self.expected_output) self.stream_in_recovered = AXI4STMonitor(dut, "stream_in", dut.clk, callback=self.model) self.stream_in_recovered.log.setLevel(30) self.stream_out.log.setLevel(30) def print_trans(self, transaction): # print(transaction) pass def model(self, transaction): """ Model the expected output based on input """ self.expected_output.append(transaction) # print(self.expected_output) def insertContinuousBatch(self, nb, base): """ Insert nb element in the stream_in with base as first value """ for i in range(nb): self.stream_in.append(base+i) @cocotb.coroutine def async_rst(self): """ This function execute the reset_n for 40ns it also set all input signals to default value """ self.dut._log.info("begin Rst") self.dut.reset_n <= 0 self.dut.stream_in_tdata <= 0 self.dut.stream_in_tlast <= 0 self.dut.stream_in_tvalid <= 0 self.dut.stream_out_tready <= 0 yield Timer(40, 'ns') self.dut.reset_n <= 1 yield Timer(15, 'ns') self.dut._log.info("end Rst")
async def mean_randomised_test(dut): """Test mean of random numbers multiple times""" # dut_in = StreamBusMonitor(dut, "i", dut.clk) # this doesn't work: # VPI Error vpi_get_value(): # ERROR - Cannot get a value for an object of type vpiArrayVar. dut_out = StreamBusMonitor(dut, "o", dut.clk) exp_out = [] with warnings.catch_warnings(): warnings.simplefilter("ignore") scoreboard = Scoreboard(dut) scoreboard.add_interface(dut_out, exp_out) DATA_WIDTH = int(dut.DATA_WIDTH.value) BUS_WIDTH = int(dut.BUS_WIDTH.value) dut._log.info('Detected DATA_WIDTH = %d, BUS_WIDTH = %d' % (DATA_WIDTH, BUS_WIDTH)) cocotb.fork(Clock(dut.clk, CLK_PERIOD_NS, units='ns').start()) dut.rst <= 1 for i in range(BUS_WIDTH): dut.i_data[i] = 0 dut.i_valid <= 0 await RisingEdge(dut.clk) await RisingEdge(dut.clk) dut.rst <= 0 for j in range(10): nums = [] for i in range(BUS_WIDTH): x = random.randint(0, 2**DATA_WIDTH - 1) dut.i_data[i] = x nums.append(x) dut.i_valid <= 1 nums_mean = sum(nums) // BUS_WIDTH exp_out.append(nums_mean) await RisingEdge(dut.clk) dut.i_valid <= 0 await RisingEdge(dut.clk) await RisingEdge(dut.clk)
class EndianSwapperTB(object): def __init__(self, dut, debug=False): self.dut = dut self.stream_in = AvalonSTDriver(dut, "stream_in", dut.clk) self.backpressure = BitDriver(self.dut.stream_out_ready, self.dut.clk) self.stream_out = AvalonSTMonitor(dut, "stream_out", dut.clk, config={'firstSymbolInHighOrderBits': True}) self.csr = AvalonMaster(dut, "csr", dut.clk) cocotb.fork(stream_out_config_setter(dut, self.stream_out, self.stream_in)) # Create a scoreboard on the stream_out bus self.pkts_sent = 0 self.expected_output = [] self.scoreboard = Scoreboard(dut) self.scoreboard.add_interface(self.stream_out, self.expected_output) # Reconstruct the input transactions from the pins # and send them to our 'model' self.stream_in_recovered = AvalonSTMonitor(dut, "stream_in", dut.clk, callback=self.model) # Set verbosity on our various interfaces level = logging.DEBUG if debug else logging.WARNING self.stream_in.log.setLevel(level) self.stream_in_recovered.log.setLevel(level) def model(self, transaction): """Model the DUT based on the input transaction""" self.expected_output.append(transaction) self.pkts_sent += 1 @cocotb.coroutine def reset(self, duration=10000): self.dut._log.debug("Resetting DUT") self.dut.reset_n <= 0 self.stream_in.bus.valid <= 0 yield Timer(duration) yield RisingEdge(self.dut.clk) self.dut.reset_n <= 1 self.dut._log.debug("Out of reset")
class BaseTest: """Common test logic and resource for all tests.""" def __init__(self, dut): self.dut = dut self.tlp_tx_st = AvalonSTMonitor(dut, 'tlp_tx_multiplexer_out', dut.clk) self.tlp_tx_recovered = AvalonSTMonitor(dut, 'tlp_tx_multiplexer_out', dut.clk, callback=self.tx_model) self.csr = AvalonMaster(dut, 'csr', dut.clk) self.expected_output = [] self.scoreboard = Scoreboard(dut) self.scoreboard.add_interface(self.tlp_tx_st, self.expected_output) async def reset(self): self.dut.reset <= 1 await Timer(50, units='ns') self.dut.reset <= 0 await Timer(100, units='ns') self.dut.tlp_tx_multiplexer_out_ready <= 1 self.dut.rx_st_bar <= 1 self.dut.reset._log.debug('Reset complete') def expect_memwrite(self, address, data): exp = pcie.TLP() exp.requester_id = pcie.PcieId(bus=0xb3, device=0) exp.set_be(address, len(data)) exp.fmt_type = pcie.TLP_MEM_WRITE exp.set_data(data) exp.byte_count = len(data) self.expected_output.append(exp.intel_pack()) def expect_cmpld(self, address, data): exp = pcie.TLP() exp.completer_id = pcie.PcieId(bus=0xb3, device=0) exp.set_be(address, len(data)) exp.fmt_type = pcie.TLP_CPL_DATA exp.set_data(data) exp.byte_count = len(data) self.expected_output.append(exp.intel_pack()) def tx_model(self, transaction): """Log TLPs received from DUT.""" tlp = pcie.TLP() tlp.intel_unpack(transaction) self.tlp_tx_recovered.log.info("TLP from DUT: " + repr(tlp))
def mean_randomised_test(dut): """ Test mean of random numbers multiple times """ # dut_in = StreamBusMonitor(dut, "i", dut.clk) # this doesn't work: # VPI Error vpi_get_value(): # ERROR - Cannot get a value for an object of type vpiArrayVar. dut_out = StreamBusMonitor(dut, "o", dut.clk) exp_out = [] scoreboard = Scoreboard(dut) scoreboard.add_interface(dut_out, exp_out) data_width = int(dut.DATA_WIDTH.value) bus_width = int(dut.BUS_WIDTH.value) dut._log.info('Detected DATA_WIDTH = %d, BUS_WIDTH = %d' % (data_width, bus_width)) cocotb.fork(clock_gen(dut.clk, period=clock_period)) dut.rst <= 1 for i in range(bus_width): dut.i_data[i] = 0 dut.i_valid <= 0 yield RisingEdge(dut.clk) yield RisingEdge(dut.clk) dut.rst <= 0 for j in range(10): nums = [] for i in range(bus_width): x = random.randint(0, 2**data_width - 1) dut.i_data[i] = x nums.append(x) dut.i_valid <= 1 nums_mean = sum(nums) // bus_width exp_out.append(nums_mean) yield RisingEdge(dut.clk) dut.i_valid <= 0
async def test_multiply(dut, a_data, b_data): """Test multiplication of many matrices.""" cocotb.fork(Clock(dut.clk_i, 10, units='ns').start()) # Configure Scoreboard to compare module results to expected expected_output = [] in_monitor = MatrixInMonitor(dut, callback=expected_output.append) out_monitor = MatrixOutMonitor(dut) scoreboard = Scoreboard(dut) scoreboard.add_interface(out_monitor, expected_output) # Initial values dut.valid_i <= 0 dut.a_i <= create_a(lambda x: 0) dut.b_i <= create_b(lambda x: 0) # Reset DUT dut.reset_i <= 1 for _ in range(3): await RisingEdge(dut.clk_i) dut.reset_i <= 0 # Do multiplication operations for A, B in zip(a_data(), b_data()): await RisingEdge(dut.clk_i) dut.a_i <= A dut.b_i <= B dut.valid_i <= 1 await RisingEdge(dut.clk_i) dut.valid_i <= 0 await RisingEdge(dut.clk_i) raise scoreboard.result
class TB(object): def __init__(self, dut): self.dut = dut # Reconstruct the input transactions from the pins # and send them to our 'model' input_mon = InputMonitor("input", dut.A, dut.B, dut.clk, callback=self.adder_modelD) # Output monitor self.output_mon = OutMonitor("output", dut.X, dut.clk) # Create a scoreboard on the outputs self.expected_output = [] self.scoreboard = Scoreboard(dut) self.scoreboard.add_interface(self.output_mon, self.expected_output) def adder_modelD(self, transaction): result = adder_model(transaction[0], transaction[1]) self.expected_output.append( BinaryValue(value=result, n_bits=int(self.dut.DATA_WIDTH), bigEndian=False))
def value_test(dut): scb = Scoreboard(dut) data_width = int(dut.B) bus_width = int(dut.N) n_test = 100 cocotb.fork(clock_gen(dut.clk, period=clock_period)) exp1 = list() exp2 = list() c1 = VectorCollector([[bus_width]], n_test) c2 = VectorCollector([[]], n_test) master = ValidMaster(dut, 'i', dut.clk, ['i_data']) m1 = ValidMonitor(dut, 'i', dut.clk, ['i_data'], collector=c1) m2 = ValidMonitor(dut, 'o', dut.clk, ['o_data'], collector=c2) scb.add_interface(m1, exp1) scb.add_interface(m2, exp2) for i in range(10): yield RisingEdge(dut.clk) idat = np.random.randint(1<<data_width, size=(n_test,bus_width)).astype(np.int32) odat = np.sum(idat, axis=1)/bus_width exp1.append(CompareWrap((idat,), verbose=True)) # wrong answer # exp2.append(CompareWrap((odat+1,), verbose=True)) exp2.append(CompareWrap((odat,), verbose=True)) ibus = master.create_data() for n in range(n_test): for i in range(bus_width): ibus.i_data[i].integer = idat[n,i] yield master.send(ibus, 3) yield Timer(10) assert c1.clean and c2.clean raise scb.result
class deparser_TB(object): def __init__(self, dut, clkperiod=6.4): self.dut = dut dut._discover_all() # scan all signals on the design dut._log.setLevel(30) fork(Clock(dut.clk, clkperiod, 'ns').start()) self.payload_in = AXI4STPKts(dut, "payload_in", dut.clk) self.stream_out = AXI4STMonitor(dut, "packet_out", dut.clk, callback=self.print_trans) self.scoreboard = Scoreboard(dut, fail_immediately=False) self.expected_output = [] self.scoreboard.add_interface(self.stream_out, self.expected_output) self.nb_frame = 0 self.packet = BinaryValue() """ Dictionnary to convert scapy name to VHDL. structure : scapyName: [VHDLname, length in bits] """ name_to_VHDL = { "Ether": ["ethernet", 112], "IP": ["ipv4", 160], "TCP": ["tcp", 160], "UDP": ["udp", 64], "IPv6": ["ipv6", 320] } @coroutine def async_rst(self): """ This function execute the reset_n for 40ns it also set all input signals to default value """ self.dut._log.info("begin Rst") for n, t in self.dut._sub_handles.items(): if isinstance(t, handle.ModifiableObject): t.value = 0 yield Timer(40, 'ns') self.dut.reset_n <= 1 yield Timer(15, 'ns') self.dut._log.info("end Rst") def print_trans(self, transaction): self.dut._log.info("Frame : {}, {}B:{}".format(self.nb_frame, len(transaction.buff), transaction)) self.packet.buff += transaction.buff self.nb_frame += 1 if self.dut.packet_out_tlast == 1: print(self.packet.buff) if len(self.packet.binstr) < 6 * 8: self.dut._log.warning("received packet lesser than 6Bytes\n" "received :\n{}".format( self.packet.binstr)) else: print("received :\n{}".format( raw(BinaryValue_to_scapy(self.packet)))) self.packet = BinaryValue() # BinaryValue_to_scapy(self.packet).display() # self.dut._log.info("received {}B : {}".format( # len(self.packet.buff), # self.packet.binstr)) def set_PHV(self, pkt, payload=None): """ set PHV for deparser """ scap_to_PHV(self.dut, pkt, self.name_to_VHDL) full_hdr = scapy_to_BinaryValue(pkt) print("emitted {} bytes : \n {}".format(len(raw(pkt)), raw(pkt))) self.dut._log.info("send {}B : {}".format(len(full_hdr.buff), full_hdr.binstr)) new_output = PHVDeparser(len(self.dut.packet_out_tdata), full_hdr) self.expected_output.extend(new_output)
class uart_tx_tb(object): def __init__(self, dut): self.dut = dut self.output_mon = UartTxOMonitor(dut, "o", dut.clk, int(self.dut.BAUD), reset_n=dut.rstn) self.input_mon = UartTxIMonitor(dut, "i", dut.clk, int(self.dut.BAUD), reset_n=dut.rstn, callback=self.tx_model) self.input_drv = UartTxDriver(dut, "i", dut.clk) #initializer only self.etx = BinaryValue(1) self.eready = BinaryValue(0) self.output_expected = [{ 'tx': self.etx, 'ready': self.eready }] #i don't think this should be necessary... self.scoreboard = Scoreboard(dut) #self.output_mon.log.setLevel(logging.DEBUG) #scoreboard is where results are checked. On each transaction of the output_mon, it'll compare against the #next transaction in the list output_expected. Output_expected gets updated by the tx_model. tx_model is the #callback function of the input monitor. So the expected output gets appended to when the input changes. # its not obvious if on the same simulation cycle you can force the tx_model to get called before the # scoreboard gets called on self.scoreboard.add_interface(self.output_mon, self.output_expected) self.baud_rate = int(self.dut.BAUD) - 1 self.baud_count = 0 self.shifter = 0 def tx_model(self, transaction): # shift data (transaction second field) out 1 bit at a time # at the baud rate # adding start and stop bits to the expected values. if self.input_mon.transmitting: #print ("tx model call -- character %d:%d" % (self.input_mon.bits,len(self.output_expected))) #print (self.output_expected) if self.input_mon.bits == 0: self.output_expected.pop( ) #ugh. are we putting in expectations for this cycle, or next? self.etx <= 0 self.eready <= 0 self.output_expected.append({ 'tx': self.etx, 'ready': self.eready }) #start bit self.shifter = self.input_mon.start_data #print ("transaction - %s,%s" %(transaction[0],transaction[1])) if self.input_mon.bits < 8: self.output_expected.append({ 'tx': self.shifter % 2, 'ready': 0 }) self.shifter = self.shifter >> 1 else: self.output_expected.append({'tx': 1, 'ready': 0}) #stop bit else: #print ("tx model call -- idle :%d" % len(self.output_expected)) if self.input_mon.in_reset: self.etx <= 1 self.eready <= 0 self.output_expected.append({ 'tx': self.etx, 'ready': self.eready }) else: self.etx <= 1 self.eready <= 1 self.output_expected.append({ 'tx': self.etx, 'ready': self.eready }) @cocotb.coroutine def reset_dut(self, reset, duration): reset <= 0 yield Timer(duration) reset <= 1 self.dut._log.info("reset complete") @cocotb.coroutine def set_char(self, char): yield RisingEdge(self.dut.clk) self.dut.i_data <= ord(char) self.dut.i_start <= 1 yield RisingEdge(self.dut.clk) self.dut.i_start <= 0 self.dut._log.info("sent char %s" % char)
async def run_test(dut): en_gpio_loopback_test = True en_spi_test = True clk = Clock(dut.clk, 10, units="ns") # Create a 10us period clock on port clk cocotb.fork(clk.start()) # Start the clock dut.uart_txd = 0 await FallingEdge(dut.clk) ### ============================================================================================================= ### GPIO LOOPBACK TEST if en_gpio_loopback_test: dv = DVTest(dut, "GPIO Loopback", msg_lvl="All") dv.info("GPIO Loopback Test") for i in range(20000): await FallingEdge(dut.clk) dut.P2_in <= dut.P1_out.value try: gpio_value = int(dut.P1_out.value.binstr,2) loop_done = True if gpio_value == 0xff else False except ValueError: gpio_value = 0 loop_done = False if (i+1) % 1000 == 0: dv.info("clock = " + str(i+1) +": P1_out = " + str(gpio_value) ) if loop_done: break await Edge(dut.P1_out) gpio_result = int(dut.P1_out.value.binstr,2) dv.eq(gpio_result, 0, "Error count from DUT") dut.P1_in = 0 await ClockCycles(dut.clk,100) dv.done() ### ============================================================================================================= ### SPI TEST spi_peripheral = SPIPeripheralMonitor( dut=dut, cfg = { 'name' : "SPI Monitor", 'size' : 8, # bits 'mode' : 0, 'lsb_first' : False, }, io = { 'sclk' : dut.spi_sclk, 'cs_n' : dut.spi_cs, 'sdi' : dut.spi_mosi, 'sdo' : dut.spi_miso, } ) # spi_peripheral_expect.append( random.randint(0, 127) ) # spi_peripheral_response.append( random.randint(0, 127) ) if en_spi_test: dv.info("SPI Test (random modes and speeds)") spi_n = 15 spi_peripheral_expect = [] spi_scoreboard_expect = [] spi_peripheral_response = [] for i in range(spi_n): val = i spi_peripheral_expect.append( val ) spi_scoreboard_expect.append( val ) spi_peripheral_response.append( val ) spi_peripheral.start(spi_peripheral_expect, spi_peripheral_response) scoreboard = Scoreboard(dut) scoreboard.add_interface(spi_peripheral, spi_scoreboard_expect, strict_type=False) random.seed(42) err_cnt = 0 toggle = 0 for iiii in range(spi_n): # SEND BYTE-VALUE TO SEND OVER SPI TO Z80 USING BPIO p2[7:0] dut.P2_in.value = spi_peripheral_expect[iiii] # SEND MODE AND CLKDIV TO Z80 OVER GPIO P1[7:0] # Bit [1:0] mode # Bit [2] toggle (ensure p1_in changes) # Bit [6:3] clkdiv (div sys clk) # Bit [7] done spi_peripheral.mode = random.randrange(4) # i % 4 clkdiv = random.randrange(0, 16, 2) toggle = (toggle + 4) & 0x04 P1_in = (clkdiv << 3) | toggle | spi_peripheral.mode dut.P1_in.value = P1_in # WAIT FOR Z80 TO SEND SPI MESSAGE AND COMPARE WITH EXPECETD VALUE dv.info("Waiting for SPI Peripheral ({})".format(iiii)) await spi_peripheral.peripheral_monitor() spi_peripheral.stop() dut.P1_in.value = 0x80 if err_cnt == 0: dv.info("SPI Test Passed") else: dv.info("SPI Test Failed - Error Count = " + str(err_cnt) ) await ClockCycles(dut.clk,100) # Print result of scoreboard. dv.is_true(scoreboard.result, "SPI Test Scoreboard")
async def test_aux(dut, packets_num=5, packet_size=(10, 100), delay=-1, consecutive_transfers=0): """Test all the auxiliary AXI4-Stream signals""" tdata_width = dut.C_S_AXIS_TDATA_WIDTH.value.integer tdest_width = dut.C_S_AXIS_TDEST_WIDTH.value.integer tid_width = dut.C_S_AXIS_TID_WIDTH.value.integer tuser_width = dut.C_S_AXIS_TUSER_WIDTH.value.integer axis_m = Axi4StreamMaster(dut, "s_axis", dut.aclk) axis_s = Axi4StreamSlave(dut, "m_axis", dut.aclk, delay, consecutive_transfers) axis_monitor = Axi4Stream(dut, "m_axis", dut.aclk, data_type="integer", packets=True, aux_signals=True) await setup_dut(dut) input = [] output = [] # Build the input and output packets for i in range(packets_num): first_word = { "TDATA": randint(0, 2**tdata_width - 1), "TSTRB": randint(0, 2**(tdata_width // 8) - 1), "TKEEP": 2**(tdata_width // 8) - 1, "TDEST": randint(0, 2**tdest_width - 1), "TID": randint(0, 2**tid_width - 1), "TUSER": randint(0, 2**tuser_width - 1), } second_word = { "TDATA": randint(0, 2**tdata_width - 1), "TSTRB": 2**(tdata_width // 8) - 1 } input.append( [first_word, second_word] + [randint(0, 2**tdata_width - 1) for i in range(randint(*packet_size))]) output.append([]) for input_word in input[-1]: output[-1].append({}) for signal in ("TDATA", "TSTRB", "TKEEP", "TDEST", "TID", "TUSER"): if signal == "TDATA" and isinstance(input_word, int): output[-1][-1]["TDATA"] = input_word else: try: # If input_word has that signal, copy it, ... output[-1][-1][signal] = input_word[signal] except (KeyError, TypeError): # ...if not, use the last value output[-1][-1][signal] = output[-1][-2][signal] for output_word in output[-1]: # Flip TDATA and TUSER output_word["TDATA"] ^= 2**tdata_width - 1 output_word["TUSER"] ^= 2**tuser_width - 1 scoreboard = Scoreboard(dut) scoreboard.add_interface(axis_monitor, output) # Write the input packets for packet in input: await axis_m.write(packet) # Wait until output_tdata is empty (so, all the packets have been received) while output: await RisingEdge(dut.aclk)
def rob_simple_test(dut): # TB_ARGS parser parser = ArgumentParser(description='Arguments for test') parser.add_argument("-len", "--length", dest="length", type=int, default=32) parser.add_argument("-dhreq", "--max_delay_host_req", dest="dhreq", type=int, default=0) parser.add_argument("-dhrsp", "--max_delay_host_rsp", dest="dhrsp", type=int, default=0) parser.add_argument("-dmreq", "--max_delay_mem_req", dest="dmreq", type=int, default=0) parser.add_argument("-dmrsp", "--max_delay_mem_rsp", dest="dmrsp", type=int, default=0) parser.add_argument("-id", "--id_width", dest="id_width", type=int, default=4) argument_list = shlex.split(os.environ["PY_TB_ARGS"]) args = parser.parse_args(argument_list) # Setup CLK and Reset vr_in = vr.vr_master(dut, name="bug_host_req_i", clock=dut.clk, bus_separator=".", valid_max_delay=args.dhreq) vr_out = vr.vr_slave(dut, name="bug_host_rsp_o", clock=dut.clk, bus_separator=".", ready_max_delay=args.dhrsp) mem_req = vr.vr_slave(dut, name="bug_mem_req_o", clock=dut.clk, bus_separator=".", ready_max_delay=args.dmreq) mem_rsp = vr.vr_master(dut, name="bug_mem_rsp_i", clock=dut.clk, bus_separator=".", valid_max_delay=args.dmrsp) vr_out_mon = vr.vr_monitor(dut, name="bug_host_rsp_o", clock=dut.clk, bus_separator=".") setup_clk(dut) dut.rstn <= 0 yield Timer(CLK_PERIOD * 10, units='ns') dut.rstn <= 1 # Init interfaces memory = vr_mem.vr_mem_cl(mem_req, mem_rsp, permutation=True) packet = packet_generate(args, random.randint(1, args.length)) with open("./ref.dat", "w") as f: for i in packet: f.write(str(i) + '\n') scoreboard = Scoreboard(dut) scoreboard.add_interface(vr_out_mon, packet) cocotb.fork(vr_out.receive_packet(len(packet))) cocotb.fork(vr_in.write_packet(packet)) while (vr_in.busy): yield RisingEdge(dut.clk) memory.th = 0 # flush buffer while (vr_out.wait): yield RisingEdge(dut.clk) yield Timer(CLK_PERIOD, units='ns') packet_out = list(map(int, vr_out.get_packet(clean=True))) with open("./out.dat", "w") as f: for i in packet_out: f.write(str(i) + '\n')