def test_prio2(dut): global messages global cnt_plan ##### Test Global Parameters messages = 20 cnt_plan = 8*messages dut.log.setLevel(logging.INFO) #Setup Clocks cocotb.fork(Clock(dut.clk, clkref_period).start()) cocotb.fork(Clock(dut.clk2, clksys_period).start()) clkedge = RisingEdge(dut.clk) # Reset the DUT dut.log.debug("Resetting DUT") dut.reset_n <= 0 dut.reset_n2 <= 0 dut.en_in <= 0 yield Timer(50*clksys_period) dut.log.debug("Out of reset") dut.reset_n <= 1 dut.reset_n2 <= 1 yield Timer(50*clksys_period) #Timestamp capture routine. Save TSs to compare later against expected values cocotb.fork(tscheck(dut)) #Data/Signal Generators for WB Slave replyWaitGen = genw.random_data(1, 3) ackGen = genw.random_data(0, 1) stallGen = genb.bit_toggler(genw.random_data(0, 10), genw.random_data(1, 50)) #Callback for WB SLave output = rec(dut) #instantiate WB Slave wbs = WishboneSlave(entity=dut, name="wbm", clock=dut.clk, callback=output.receive, stallwaitgen=stallGen, replywaitgen=replyWaitGen) wbs.log.setLevel(logging.INFO) #instantiate WB Master wbm = WishboneMaster(dut, "wbs", dut.clk, 500) wbm.log.setLevel(logging.INFO) #Stimulus routine. Generate Cycles for WB Master yield datagen(dut, wbm, messages) ##### TEST Evaluation ###### #wait for all ops to finish cnt_timeout = cnt_plan*20 while (cnt_timeout) and ((cnt_recv < cnt_plan) and (len(tsList) < len(tsExpList))): yield clkedge cnt_timeout -= 1 #either timeout or all operations complete. Continue yield Timer(50*clksys_period) print "" print "%s%s" % (" "*117, "*"*40) print "" #check for timeout if cnt_timeout <= 0: raise TestFailure("Timeout: Not all Operations made it through. Planned: %u Sent: %u Received: %u" % (cnt_plan, cnt_send, cnt_recv)) #check if we got too many sent ops for some reason if (cnt_send > cnt_plan): raise TestFailure("There were more replies than sent operations. Planned: %u Sent: %u Received: %u" % (cnt_plan, cnt_send, cnt_recv)) #check if we got too replies many for some reason if (cnt_recv > cnt_plan): raise TestFailure("There were more replies than sent operations. Planned: %u Sent: %u Received: %u" % (cnt_plan, cnt_send, cnt_recv)) #check timestamps against expected values s = set(tsList) result = [x for x in tsExpList if x not in s] if len(result): raise TestFailure("Expected Timestamps missing from actual result: %s\n Expected: %s\n Got: %s" % (result, tsExpList, tsList)) #all okay, test passed print ("Expected Timestamps missing from actual result: %s\n Expected: %s\n Got: %s" % (result, tsExpList, tsList)) raise TestSuccess("All operations processed, all expected timestamps present.\nPlanned: %u Sent: %u Received: %u\nMessages: %u Timestamps: %u" % (cnt_plan, cnt_send, cnt_recv, output.cntcyc-1, messages - len(result))) print "*"*80 # L = [] # thread.start_new_thread(input_thread, (L,)) # print "Press Any key to close" # while True: # if L: # print L # break # yield RisingEdge(dut.clk2) print "DONE *****"
async def fir_filter_test(dut): """ Load test data from files and send them through the DUT. Compare input and output afterwards. """ EnablePlots = True timestamp_start = time.time() # -------------------------------------------------------------------------- # Constants # -------------------------------------------------------------------------- # Number of seconds to process n_sec = 0.001 # Derived constants num_samples = int(n_sec * fm_global.fs_rx_c) # -------------------------------------------------------------------------- # Load data from files # -------------------------------------------------------------------------- filename = "../../../../../../sim/matlab/verification_data/rx_fm_channel_data.txt" data_i = [] with open(filename) as fd: val_count = 0 for line in fd: data_i.append(float(line.strip('\n'))) val_count += 1 # Stop after required number of samples if val_count >= num_samples: break # Convert to fixed point and back to int data_i_fp = to_fixed_point(data_i, fm_global.fp_width_c, fm_global.fp_width_frac_c) data_i_int = fixed_to_int(data_i_fp) filename = "../../../../../../sim/matlab/verification_data/rx_pilot.txt" gold_data_o = [] with open(filename) as fd: val_count = 0 for line in fd: gold_data_o.append(float(line.strip('\n'))) val_count += 1 # Stop after required number of samples if val_count >= num_samples: break # Convert to fixed point gold_data_o_fp = to_fixed_point(gold_data_o, fm_global.fp_width_c, fm_global.fp_width_frac_c) # -------------------------------------------------------------------------- # Prepare environment # -------------------------------------------------------------------------- tb = FM_TB(dut, num_samples) # Generate clock clk_period_ns = round(1 / tb.CLOCK_FREQ_MHZ * 1e3) clk = Clock(dut.iClk, period=clk_period_ns, units='ns') clk_gen = cocotb.fork(clk.start()) # Generate FIR input strobe strobe_num_cycles_high = 1 strobe_num_cycles_low = tb.CLOCK_FREQ_MHZ * 1e6 // fm_global.fs_rx_c - strobe_num_cycles_high tb.fir_in_strobe.start( bit_toggler(repeat(strobe_num_cycles_high), repeat(strobe_num_cycles_low))) N_FIR = 73 # see filter_bp_pilot_coeffs_c in DUT (DspFir) assert strobe_num_cycles_low >= N_FIR, \ "The FIR filter takes N_FIR clock cycles to produce a result! Use a lower sampling frequency!!" print("strobe_num_cycles_high : %d" % strobe_num_cycles_high) print("strobe_num_cycles_low : %d" % strobe_num_cycles_low) # -------------------------------------------------------------------------- # Run test on DUT # -------------------------------------------------------------------------- # Reset the DUT before any tests begin await tb.assign_defaults() await tb.reset() # Fork the 'receiving part' fir_out_fork = cocotb.fork( tb.read_fir_result(fm_global.pilot_output_scale_c, num_samples)) # Send input data through filter dut._log.info("Sending input data through filter ...") for i, sample in enumerate(data_i_int): await RisingEdge(dut.iValDry) dut.iDdry <= int(sample) await RisingEdge(dut.iValDry) # Await forked routines to stop await fir_out_fork # Measure time timestamp_end = time.time() dut._log.info("Execution took {:.2f} seconds.".format(timestamp_end - timestamp_start)) num_received = len(tb.data_out) num_expected = len(gold_data_o_fp) # -------------------------------------------------------------------------- # Plots # -------------------------------------------------------------------------- if EnablePlots: dut._log.info("Plots ...") fig = plt.figure() plt.plot(np.arange(0, num_expected) / fm_global.fs_rx_c, from_fixed_point(gold_data_o_fp), "b", label="gold_data_o_fp") plt.plot(np.arange(0, num_received) / fm_global.fs_rx_c, tb.data_out, "r", label="data_out") plt.title("Pilot") plt.grid(True) plt.legend() fig.tight_layout() plt.xlim([0, num_samples / fm_global.fs_rx_c]) plt.show() # -------------------------------------------------------------------------- # Compare results # -------------------------------------------------------------------------- # Sanity check if num_received < num_expected: raise cocotb.result.TestError( "Did not capture enough output values: {} actual, {} expected.". format(num_received, num_expected)) # Skip first N samples skip_N = 10 dut._log.info(f"Skipping first N={skip_N} samples.") gold_data_o_fp = gold_data_o_fp[skip_N:] tb.data_out = tb.data_out[skip_N:] max_diff = 2**-5 for i, res in enumerate(tb.data_out): diff = gold_data_o_fp[i] - res if abs(from_fixed_point(diff)) > max_diff: msg = "FIR output [{}] is not matching the expected values: {}>{}.".format( i, abs(from_fixed_point(diff)), max_diff) raise cocotb.result.TestError(msg) # dut._log.info(msg) norm_res = np.linalg.norm( np.array(from_fixed_point(gold_data_o_fp[0:num_received])) - np.array(tb.data_out), 2) dut._log.info("2-Norm = {}".format(norm_res)) dut._log.info("Done.")
def test_wb_looback(dut): clkref_period = 8 clksys_period = 16 # """Example of a test using TUN/TAP over WB.""" cocotb.fork(Clock(dut.clk, clkref_period).start()) cocotb.fork(Clock(dut.clk2, clksys_period).start()) # Reset the DUT dut.log.debug("Resetting DUT") dut.reset_n <= 0 dut.reset_n2 <= 0 yield Timer(50*clksys_period) dut.log.debug("Out of reset") dut.log.setLevel(logging.INFO) tsGen = genw.random_data(0, 1000, 64) idleGenWord = genw.random_data(0, 5) replyWaitGen = genw.random_data(1, 10) idleGenBlock = genw.random_data(0, 50) stallGen = genb.bit_toggler(genw.random_data(1, 10), genw.random_data(1, 10)) cntGenX1000 = genw.incrementing_data(0x1000) cntGen = genw.incrementing_data(1) stdExp = WBR(True, None, 6, 5, 5) datGen = genw.incrementing_data(1) errGen = genb.bit_toggler(genw.random_data(0, 1), genw.random_data(1, 10)) adrGen = genw.random_data(0, 50) datwrGen = genw.random_data() wordRepeatGen = genw.random_data(1, 50) weGen = genw.random_data(0, 1) output = rec(dut) wbm = WishboneMaster(dut, "wbm", dut.clk) wbm.log.setLevel(logging.INFO) wbs = WishboneSlave(entity=dut, name="wbmo", clock=dut.clk, callback=output.receive, errgen=None, datgen=datGen, stallwaitgen=stallGen, replywaitgen=replyWaitGen) wbs.log.setLevel(logging.INFO) oplist = [] explist = [] reslist = [] #oplist.append([WBO(0x0, 0xDEADBEEF, 123)]) # for i in range(1, 3): # tmpOplist = [] # tmpExplist = [] # ts = tsGen.next() # # tmpOplist.append(WBO(0x0, ts >> 32, idleGenWord.next())) # tmpExplist.append(stdExp) # tmpOplist.append(WBO(0x0, ts & 0xffffffff, idleGenWord.next())) # tmpOplist.append(WBO(0x0, None, idleGenWord.next())) # tmpExplist.append(stdExp) # n = cntGenX1000.next() # tmpOplist.append(WBO(0x0, n + cntGen.next(), idleGenWord.next())) # tmpExplist.append(stdExp) # tmpOplist.append(WBO(0x0, n + cntGen.next(), idleGenWord.next())) # tmpExplist.append(stdExp) # tmpOplist.append(WBO(0x0, n + cntGen.next(), idleGenWord.next())) # tmpExplist.append(stdExp) # tmpOplist.append(WBO(0x0, n + cntGen.next(), idleGenWord.next())) # tmpExplist.append(stdExp) # tmpOplist.append(WBO(0x0, n + cntGen.next(), idleGenWord.next())) # tmpExplist.append(stdExp) # tmpOplist.append(WBO(0x0, None, idleGenBlock.next())) # # tmpExplist.append(stdExp) # oplist += [tmpOplist] # explist.append(tmpExplist) for i in range(0, 10): tmpOplist = [] words = wordRepeatGen.next() for i in range(0, words): dat = None if weGen.next(): dat = datwrGen.next() tmpOplist.append(WBO(adrGen.next()*4, dat, idleGenWord.next())) oplist += [tmpOplist] for cycle in oplist: tmp = yield wbm.send_cycle(cycle) reslist.append(tmp) dut.log.info("***** Master - Received Replies:") cyccnt = 0 for cycle in reslist: dut.log.info("WBM Cycle #%3u, %3u Ops" % (cyccnt,len(cycle))) cyccnt += 1 cnt = 0 for res in cycle: dat = " None" if res.dat is not None: dat = "0x%08x" % res.dat ackerr = "ERR" if res.ack: ackerr = "ACK" dut.log.debug("#%3u ACK/ERR: %s RD: %s IDLW: %3u STLW: %3u ACKW: %3u" % (cnt, ackerr, dat, res.waitidle, res.waitstall, res.waitack)) cnt += 1 # yield RisingEdge(dut.clk) #cocotb.fork(lifesign(dut, 5000000)) # L = [] # thread.start_new_thread(input_thread, (L,)) # print "Press Any key to close" # while True: # if L: # print L # break # yield RisingEdge(dut.clk2) print "DONE *****"
async def axi_stream_dsp_test(dut): """ Load test data from files and send them through the DUT. Compare input and output afterwards. """ # -------------------------------------------------------------------------- # Constants # -------------------------------------------------------------------------- # Number of seconds to process n_sec = 0.0025 # -------------------------------------------------------------------------- # Prepare environment # -------------------------------------------------------------------------- timestamp_start = time.time() tb = FM_TB(dut, n_sec) # Generate clock clk_period_ns = round(1 / tb.CLOCK_FREQ_MHZ * 1e3) clk = Clock(dut.clk_i, period=clk_period_ns, units='ns') clk_gen = cocotb.fork(clk.start()) # -------------------------------------------------------------------------- # Load data from files # -------------------------------------------------------------------------- dut._log.info("Loading input data ...") filename = "../../../../../sim/matlab/verification_data/rx_fm_bb.txt" data_fp = helper.loadDataFromFile(filename, tb.model.num_samples_fs_c * 2, fm_global.fp_width_c, fm_global.fp_width_frac_c) # Get interleaved I/Q samples (take every other) data_in_i_fp = data_fp[0::2] # start:end:step data_in_q_fp = data_fp[1::2] # start:end:step # Combine IQ samples data_in_iq = [] for i in range(0, len(data_in_i_fp)): in_i = int(fixed_to_int(data_in_i_fp[i])) in_q = int(fixed_to_int(data_in_q_fp[i])) value = (in_q << 16) + in_i data_in_iq.append(value) # -------------------------------------------------------------------------- # Run test on DUT # -------------------------------------------------------------------------- # Reset the DUT before any tests begin await tb.assign_defaults() await tb.reset() # Generate backpressure signal (AXI stream tready) for IPs' stream output # NOTE: # This is not generating the actual ~40 kHz output frequency (as defined by fm_global.fs_audio_c). # It generates a much faster output, to speed up the testbench (see "output_speedup_factor"). # NOTE: # This speedup factor needs to be chosen carefully. The IP needs to complete the calculation for one sample, # before the next sample can be taken from the input. Therefore, set the factor small, to ensure enough # low-cycles, to allow the IP to complete one entire calculation. output_speedup_factor = 120 strobe_num_cycles_high = 1 strobe_num_cycles_low = tb.CLOCK_FREQ_MHZ * 1e6 // fm_global.fs_audio_c // output_speedup_factor - strobe_num_cycles_high ratio = strobe_num_cycles_low // strobe_num_cycles_high tb.backpressure_i2s.start(bit_toggler(repeat(strobe_num_cycles_high), repeat(strobe_num_cycles_low))) assert ratio >= 9, f"output_speedup_factor is set too high ({ratio}<9)! --> IP won't have enough time to calculate a sample, before the next one arrives" # Fork the 'receiving parts' fm_demod_output_fork = cocotb.fork(tb.read_fm_demod_output()) fm_channel_data_output_fork = cocotb.fork(tb.read_fm_channel_data_output()) audio_mono_output_fork = cocotb.fork(tb.read_audio_mono_output()) pilot_output_fork = cocotb.fork(tb.read_pilot_output()) carrier_38k_output_fork = cocotb.fork(tb.read_carrier_38k_output()) audio_lrdiff_output_fork = cocotb.fork(tb.read_audio_lrdiff_output()) audio_L_output_fork = cocotb.fork(tb.read_audio_L_output()) audio_R_output_fork = cocotb.fork(tb.read_audio_R_output()) audio_output_fork = cocotb.fork(tb.read_audio_output()) # Send input data to IP dut._log.info("Sending IQ samples to FM Receiver IP ...") for i, value in enumerate(data_in_iq): await tb.axis_m.write(value) dut._log.info("Waiting to receive enough samples ...") # Await forked routines to stop. # They stop, when the expected number of samples were read. await fm_demod_output_fork await fm_channel_data_output_fork await audio_mono_output_fork await pilot_output_fork await carrier_38k_output_fork await audio_lrdiff_output_fork await audio_L_output_fork await audio_R_output_fork await audio_output_fork # Measure time duration_s = int(time.time() - timestamp_start) mins, secs = divmod(duration_s, 60) dut._log.info("Execution took {:02d}:{:02d} minutes.".format(mins, secs)) # -------------------------------------------------------------------------- # Compare results # -------------------------------------------------------------------------- dut._log.info("Comparing data ...") tb.compareData() # -------------------------------------------------------------------------- # Write data to file # -------------------------------------------------------------------------- dut._log.info("Writing data to file ...") tb.writeDataToFile() # -------------------------------------------------------------------------- # Plots # -------------------------------------------------------------------------- # NOTE: Only showing plots, if results are NOT okay. dut._log.info("Plots ...") tb.generatePlots() dut._log.info("Done.")