def issue_588_coroutine_list(dut): """ Yield a list of triggers and coroutines.""" # Record simulation time. current_time = utils.get_sim_time("ns") # Yield a list, containing a RisingEdge trigger and a coroutine. yield [sample_coroutine(dut), triggers.Timer(100, "ns")] # Make sure that only 5 ns passed, because the sample coroutine # terminated first. new_time = utils.get_sim_time("ns") if int(new_time - current_time) != 5: raise result.TestFailure("Did not yield coroutine in list.")
def test_time_in_external(dut): """Test that the simulation time does no advance if the wrapped external routine does not its self yield""" clk_gen = cocotb.fork(Clock(dut.clk, 100).start()) yield Timer(10, 'ns') time = get_sim_time('ns') dut._log.info("Time at start of test = %d" % time) for i in range(1000): dut._log.info("Loop call %d" % i) yield external(test_print_sim_time)(dut, time) time_now = get_sim_time('ns') yield Timer(10, 'ns') if time != time_now: raise TestFailure("Time has elapsed over external call")
def _advance(self, outcome): if not self.started: self.error_messages = [] self.log.info("Starting test: \"%s\"\nDescription: %s" % (self.funcname, self.__doc__)) self.start_time = time.time() self.start_sim_time = get_sim_time('ns') self.started = True try: self.log.debug("Sending {}".format(outcome)) return outcome.send(self._coro) except TestComplete as e: if isinstance(e, TestFailure): self.log.warning(str(e)) else: self.log.info(str(e)) buff = StringIO() for message in self.error_messages: print(message, file=buff) e.stderr.write(buff.getvalue()) raise except StopIteration: raise TestSuccess() except Exception as e: raise raise_error(self, "Send raised exception:")
def send(self, value): if not self.started: self.error_messages = [] self.log.info("Starting test: \"%s\"\nDescription: %s" % (self.funcname, self.__doc__)) self.start_time = time.time() self.start_sim_time = get_sim_time('ns') self.started = True try: if isinstance(value, ExternalException): self.log.debug("Injecting ExternalException(%s)" % (repr(value))) return self._coro.throw(value.exception) self.log.debug("Sending trigger %s" % (str(value))) return self._coro.send(value) except TestComplete as e: if isinstance(e, TestFailure): self.log.warning(str(e)) else: self.log.info(str(e)) buff = StringIO() for message in self.error_messages: print(message, file=buff) e.stderr.write(buff.getvalue()) raise except StopIteration: raise TestSuccess() except Exception as e: raise raise_error(self, "Send raised exception: %s" % (str(e)))
def test_print_sim_time(dut, base_time): # We are not calling out here so time should not advance # And should also remain consistent for _ in range(10): _t = get_sim_time('ns') dut._log.info("Time reported = %d", _t) if _t != base_time: raise TestFailure("Time reported does not match base_time %f != %f" % (_t, base_time)) dut._log.info("external function has ended")
def test_timer_with_units(dut): time_fs = get_sim_time(units='fs') # Yield for one simulation time step yield Timer(1) time_step = get_sim_time(units='fs') - time_fs try: # Yield for 2.5 timesteps, should throw exception yield Timer(2.5*time_step, units='fs') raise TestFailure("Timers should throw exception if time cannot be achieved with simulator resolution") except ValueError: dut._log.info("As expected, unable to create a timer of 2.5 simulator time steps") time_fs = get_sim_time(units='fs') yield Timer(3, "ns") if get_sim_time(units='fs') != time_fs+3000000.0: raise TestFailure("Expected a delay of 3 ns") time_fs = get_sim_time(units='fs') yield Timer(1.5, "ns") if get_sim_time(units='fs') != time_fs+1500000.0: raise TestFailure("Expected a delay of 1.5 ns") time_fs = get_sim_time(units='fs') yield Timer(10.0, "ps") if get_sim_time(units='fs') != time_fs+10000.0: raise TestFailure("Expected a delay of 10 ps") time_fs = get_sim_time(units='fs') yield Timer(1.0, "us") if get_sim_time(units='fs') != time_fs+1000000000.0: raise TestFailure("Expected a delay of 1 us")
def _format(self, level, record, msg, coloured=False): time_ns = get_sim_time('ns') simtime = "%6.2fns" % (time_ns) prefix = simtime.rjust(10) + ' ' + level + ' ' if not _suppress: prefix += self.ljust(record.name, _RECORD_CHARS) + \ self.rjust(os.path.split(record.filename)[1], _FILENAME_CHARS) + \ ':' + self.ljust(str(record.lineno), _LINENO_CHARS) + \ ' in ' + self.ljust(str(record.funcName), _FUNCNAME_CHARS) + ' ' prefix_len = len(prefix) if coloured: prefix_len -= (len(level) - _LEVEL_CHARS) pad = "\n" + " " * (prefix_len) return prefix + pad.join(msg.split('\n'))
def test_clock_with_units(dut): clk_1mhz = Clock(dut.clk, 1.0, units='us') clk_250mhz = Clock(dut.clk, 4.0, units='ns') if str(clk_1mhz) != "Clock(1.0 MHz)": raise TestFailure("{} != 'Clock(1.0 MHz)'".format(str(clk_1mhz))) else: dut._log.info('Created clock >{}<'.format(str(clk_1mhz))) if str(clk_250mhz) != "Clock(250.0 MHz)": raise TestFailure("{} != 'Clock(250.0 MHz)'".format(str(clk_250mhz))) else: dut._log.info('Created clock >{}<'.format(str(clk_250mhz))) clk_gen = cocotb.fork(clk_1mhz.start()) start_time_ns = get_sim_time(units='ns') yield Timer(1) yield RisingEdge(dut.clk) edge_time_ns = get_sim_time(units='ns') if not isclose(edge_time_ns, start_time_ns + 1000.0): raise TestFailure("Expected a period of 1 us") start_time_ns = edge_time_ns yield RisingEdge(dut.clk) edge_time_ns = get_sim_time(units='ns') if not isclose(edge_time_ns, start_time_ns + 1000.0): raise TestFailure("Expected a period of 1 us") clk_gen.kill() clk_gen = cocotb.fork(clk_250mhz.start()) start_time_ns = get_sim_time(units='ns') yield Timer(1) yield RisingEdge(dut.clk) edge_time_ns = get_sim_time(units='ns') if not isclose(edge_time_ns, start_time_ns + 4.0): raise TestFailure("Expected a period of 4 ns") start_time_ns = edge_time_ns yield RisingEdge(dut.clk) edge_time_ns = get_sim_time(units='ns') if not isclose(edge_time_ns, start_time_ns + 4.0): raise TestFailure("Expected a period of 4 ns") clk_gen.kill()
def _log_sim_summary(self): real_time = time.time() - self.start_time sim_time_ns = get_sim_time('ns') ratio_time = sim_time_ns / real_time summary = "" summary += "*************************************************************************************\n" summary += "** ERRORS : {0:<39}**\n".format(self.failures) summary += "*************************************************************************************\n" summary += "** SIM TIME : {0:<39}**\n".format('{0:.2f} NS'.format(sim_time_ns)) summary += "** REAL TIME : {0:<39}**\n".format('{0:.2f} S'.format(real_time)) summary += "** SIM / REAL TIME : {0:<39}**\n".format('{0:.2f} NS/S'.format(ratio_time)) summary += "*************************************************************************************\n" self.log.info(summary)
def _log_sim_summary(self): real_time = time.time() - self.start_time sim_time_ns = get_sim_time('ns') ratio_time = self._safe_divide(sim_time_ns, real_time) summary = "" summary += "*************************************************************************************\n" summary += "** ERRORS : {0:<39}**\n".format( self.failures) summary += "*************************************************************************************\n" summary += "** SIM TIME : {0:<39}**\n".format( '{0:.2f} NS'.format(sim_time_ns)) summary += "** REAL TIME : {0:<39}**\n".format( '{0:.2f} S'.format(real_time)) summary += "** SIM / REAL TIME : {0:<39}**\n".format( '{0:.2f} NS/S'.format(ratio_time)) summary += "*************************************************************************************\n" self.log.info(summary)
async def test_clock_with_units(dut): clk_1mhz = Clock(dut.clk, 1.0, units='us') clk_250mhz = Clock(dut.clk, 4.0, units='ns') assert str(clk_1mhz) == "Clock(1.0 MHz)" dut._log.info('Created clock >{}<'.format(str(clk_1mhz))) assert str(clk_250mhz) == "Clock(250.0 MHz)" dut._log.info('Created clock >{}<'.format(str(clk_250mhz))) clk_gen = cocotb.fork(clk_1mhz.start()) start_time_ns = get_sim_time(units='ns') await Timer(1, "ns") await RisingEdge(dut.clk) edge_time_ns = get_sim_time(units='ns') assert isclose(edge_time_ns, start_time_ns + 1000.0), "Expected a period of 1 us" start_time_ns = edge_time_ns await RisingEdge(dut.clk) edge_time_ns = get_sim_time(units='ns') assert isclose(edge_time_ns, start_time_ns + 1000.0), "Expected a period of 1 us" clk_gen.kill() clk_gen = cocotb.fork(clk_250mhz.start()) start_time_ns = get_sim_time(units='ns') await Timer(1, "ns") await RisingEdge(dut.clk) edge_time_ns = get_sim_time(units='ns') assert isclose(edge_time_ns, start_time_ns + 4.0), "Expected a period of 4 ns" start_time_ns = edge_time_ns await RisingEdge(dut.clk) edge_time_ns = get_sim_time(units='ns') assert isclose(edge_time_ns, start_time_ns + 4.0), "Expected a period of 4 ns" clk_gen.kill()
def _start_test(self) -> None: # Want this to stand out a little bit start = "" end = "" if want_color_output(): start = ANSI.COLOR_TEST end = ANSI.COLOR_DEFAULT self.log.info( "{start}running{end} {name} ({i}/{total}){description}".format( start=start, i=self.count, total=self.ntests, end=end, name=self._test.__qualname__, description=_trim(self._test.__doc__), )) self._test_start_time = time.time() self._test_start_sim_time = get_sim_time("ns") cocotb.scheduler._add_test(self._test_task)
def _monitor_recv(self): """Capture all DUT to Host IRQ requests""" irq = self.dut.reg_host_irq # Wait for the logic to be reset yield ReadOnly() yield RisingEdge(self.dut.reset_n) while True: # Wait on the regfile to assert the IRQ while irq.value.integer != 1: yield RisingEdge(irq) # Signal any subscribers that the IRQ has fired self._recv({'time': get_sim_time('ns')}) # Wait for the interrupt(s) to be cleared while irq.value.integer == 1: yield FallingEdge(irq)
def handle_result(self, test: RunningTask) -> None: """Handle a test completing. Dump result to XML and schedule the next test (if any). Entered by the scheduler. Args: test: The test that completed """ assert test is self._test_task real_time = time.time() - self._test_start_time sim_time_ns = get_sim_time("ns") - self._test_start_sim_time self._record_result( test=self._test, outcome=self._test_task._outcome, wall_time_s=real_time, sim_time_ns=sim_time_ns, ) self.execute()
def rx_model(self, transaction): rx = transaction["vec"] in_reset = transaction["reset"] self.dut._log.debug( "model called at time %s with transaction %s %s in reset" % (get_sim_time("ns"), rx, in_reset)) if in_reset: self.dut._log.debug("output expected length: %d" % len(self.output_expected)) self.output_expected.append({"rcv": 0, "data": 0}) self.bits = 0 self.shift = 0 self.last_reset = True else: self.shift = self.shift + (int(rx) << self.bits) self.dut._log.debug("bits %d, shift %x, rx %d" % (self.bits, self.shift, rx)) self.bits = (self.bits + 1) % 10 if self.bits == 0: len_oe = len(self.output_expected) if len_oe == 1 and self.last_reset: self.last_reset = False popped = self.output_expected.pop() #ugh self.dut._log.warning( "popping data from output expected: %r" % popped) elif len_oe > 1: self.dut._log.error( "some nonsense with output expected happened") self.dut._log.debug("expected output len: %d" % len(self.output_expected)) if self.shift >= (1 << 9): expected = (self.shift >> 1) % (1 << 8) self.output_expected.append({"rcv": 1, "data": expected}) self.dut._log.debug("model expects uart output %s" % (bin(expected))) else: self.dut._log.info("break mode detected") self.shift = 0
def handle_result(self, test: RunningTask) -> None: """Handle a test completing. Dump result to XML and schedule the next test (if any). Entered by the scheduler. Args: test: The test that completed """ assert test is self._test_task real_time = time.time() - self._test_start_time sim_time_ns = get_sim_time('ns') - self._test_start_sim_time # stop capturing log output cocotb.log.removeHandler(test.handler) self._record_result(test=self._test, outcome=self._test_task._outcome, wall_time_s=real_time, sim_time_ns=sim_time_ns) self.execute()
def host_expect_packet(self, packet, msg=None): self.monitor.prime() result = yield self.monitor.wait_for_recv(1e9) # 1 ms max if result is None: current = get_sim_time("us") raise TestFailure(f"No full packet received @{current}") yield RisingEdge(self.dut.clk48_host) self.dut.usb_d_p = 1 self.dut.usb_d_n = 0 # Check the packet received matches expected = pp_packet(wrap_packet(packet)) actual = pp_packet(result) nak = pp_packet(wrap_packet(handshake_packet(PID.NAK))) if (actual == nak) and (expected != nak): self.dut._log.warning("Got NAK, retry") yield Timer(self.RETRY_INTERVAL, 'us') return else: self.retry = False assertEqual(expected, actual, msg)
def handle_result(self, test): """Handle a test completing. Dump result to XML and schedule the next test (if any). Entered by the scheduler. Args: test: The test that completed """ assert test is self._running_test real_time = time.time() - test.start_time sim_time_ns = get_sim_time('ns') - test.start_sim_time ratio_time = self._safe_divide(sim_time_ns, real_time) self.xunit.add_testcase(name=test.funcname, classname=test.module, time=repr(real_time), sim_time_ns=repr(sim_time_ns), ratio_time=repr(ratio_time)) # score test result_pass, sim_failed = self._score_test(test, test._outcome) # stop capturing log output cocotb.log.removeHandler(test.handler) # Save results self._store_test_result(test.__module__, test.__name__, result_pass, sim_time_ns, real_time, ratio_time) if not result_pass: self.xunit.add_failure() self.failures += 1 # Fail if required if sim_failed: self.tear_down() return self.execute()
def push_input(self, data): self.stop_clk_cnt = False if re.search('[x,X,z,Z]', data[0].binstr) is not None: self.inputs_good['data'].append(0) else: self.inputs_good['data'].append(1) if re.search('[x,X,z,Z]', data[1].binstr) is not None: self.inputs_good['flush'].append(0) else: self.inputs_good['flush'].append(1) self.inputs['data'].append(data[0]) self.inputs['flush'].append(data[1]) self.input_times.append(get_sim_time()) if len(self.inputs['data']) == self.block_size: self.dut._log.info("Block {} has been fed".format(self.curr_block)) block = [el.signed_integer for el in self.inputs['data']] block_flush = [el.integer for el in self.inputs['flush']] self.input_blocks['data'].append(block) self.input_blocks['flush'].append(block_flush) self.push_expresp(block, block_flush) self.inputs['data'], self.inputs['flush'] = [], [] self.curr_block += 1
def push_output(self, data): assert len( self.outputs_act ) == self.curr_output, "Scoreboard: len(outputs_act) != curr_output - something is wrong!" if re.search('[x,X,z,Z]', data.binstr) is not None: self.outputs_good['data'].append(0) else: self.outputs_good['data'].append(1) self.outputs_act.append(data) t = get_sim_time() self.output_times.append(t) try: if self.outputs_exp[ self. curr_output].integer != data.integer or self.outputs_good[ 'data'][-1] != 1: if not self.silence_mismatch_warnings: self.dut._log.warning( "Output Mismatch! Expected: {} Got: {}".format( self.outputs_exp[self.curr_output].binstr, data.binstr)) self.mismatch_positions['output'].append(self.curr_output) self.mismatch_times['output'].append(t) if len(self.mismatch_positions['output'] ) == self.max_mismatches: self.dut._log.warning( "{} output Mismatches - silencing output".format( len(self.mismatch_positions['output']))) self.silence_mismatch_warnings = True except IndexError: self.dut._log.warning( "Trying to push output for which there is no ExpResp yet - skipped!" ) pass self.curr_output += 1 if self.curr_output == len(self.outputs_exp) and self.last_block: self.stop_clk_cnt = True
async def _run(self): clock_edge_event = RisingEdge(self.clock) while True: await clock_edge_event self.ts_64_fns, self.ts_64_ns = math.modf(get_sim_time('ns')) self.ts_64_ns = int(self.ts_64_ns) self.ts_64_fns = int(self.ts_64_fns*0x10000) self.ts_96_s, self.ts_96_ns = divmod(self.ts_64_ns, 1000000000) self.ts_96_fns = self.ts_64_fns if self.ts_96 is not None: self.ts_96.value = (self.ts_96_s << 48) | (self.ts_96_ns << 16) | self.ts_96_fns if self.ts_64 is not None: self.ts_64.value = (self.ts_64_ns << 16) | self.ts_64_fns if self.pps is not None: self.pps.value = int(self.last_ts_96_s != self.ts_96_s) self.last_ts_96_s = self.ts_96_s
async def test_div_int_simple(dut): log = cocotb.logging.getLogger("cocotb.test") log.info("Starting sqrt testbench") analyzer_root = eaAnalyzer("Analyzer root", 8, False, get_sim_time()) analyzer_remainder = eaAnalyzer("Analyzer remainder", 8, False, get_sim_time()) analyzer_valid = eaAnalyzer("Analyzer valid", 1, False, get_sim_time()) clock = Clock(dut.clk, 10, units="ns") # Create a 10ns period clock on port clk cocotb.fork(clock.start()) # Start the clock await ClockCycles(dut.clk, 10) radicand = [0, 1, 121, 81, 90, 255] for i in range(len(radicand)): dut.rad <= radicand[i] # Set start for one clk cycle dut.start <= 1 await ClockCycles(dut.clk, 1) dut.start <= 0 await cocotb.triggers.RisingEdge(dut.valid) await ClockCycles(dut.clk, 1) log.info("{}:\tsqrt({}) = {} (rem = {})".format(get_sim_time(), dut.rad.value, dut.root.value, dut.rem.value)); #assert dut.valid.value == 1 analyzer_valid.add_sample(dut.valid.value, 1, get_sim_time()) #assert dut.root.value == int(math.sqrt(radicand[i])) analyzer_root.add_sample(dut.root.value, int(math.sqrt(radicand[i])), get_sim_time()) #assert dut.rem.value == (radicand[i] - int(math.sqrt(radicand[i]))**2) analyzer_remainder.add_sample(dut.rem.value, (radicand[i] - int(math.sqrt(radicand[i]))**2), get_sim_time()) eaAnalyzersFinal()
def check_phase(self): assert get_sim_time(units="ms") > 10
def _log_test_summary(self) -> None: real_time = time.time() - self.start_time sim_time_ns = get_sim_time("ns") ratio_time = self._safe_divide(sim_time_ns, real_time) if len(self.test_results) == 0: return TEST_FIELD = "TEST" RESULT_FIELD = "STATUS" SIM_FIELD = "SIM TIME (ns)" REAL_FIELD = "REAL TIME (s)" RATIO_FIELD = "RATIO (ns/s)" TOTAL_NAME = f"TESTS={self.ntests} PASS={self.passed} FAIL={self.failures} SKIP={self.skipped}" TEST_FIELD_LEN = max( len(TEST_FIELD), len(TOTAL_NAME), len(max([x["test"] for x in self.test_results], key=len)), ) RESULT_FIELD_LEN = len(RESULT_FIELD) SIM_FIELD_LEN = len(SIM_FIELD) REAL_FIELD_LEN = len(REAL_FIELD) RATIO_FIELD_LEN = len(RATIO_FIELD) header_dict = dict( a=TEST_FIELD, b=RESULT_FIELD, c=SIM_FIELD, d=REAL_FIELD, e=RATIO_FIELD, a_len=TEST_FIELD_LEN, b_len=RESULT_FIELD_LEN, c_len=SIM_FIELD_LEN, d_len=REAL_FIELD_LEN, e_len=RATIO_FIELD_LEN, ) LINE_LEN = (3 + TEST_FIELD_LEN + 2 + RESULT_FIELD_LEN + 2 + SIM_FIELD_LEN + 2 + REAL_FIELD_LEN + 2 + RATIO_FIELD_LEN + 3) LINE_SEP = "*" * LINE_LEN + "\n" summary = "" summary += LINE_SEP summary += "** {a:<{a_len}} {b:^{b_len}} {c:>{c_len}} {d:>{d_len}} {e:>{e_len}} **\n".format( **header_dict) summary += LINE_SEP test_line = "** {a:<{a_len}} {start}{b:^{b_len}}{end} {c:>{c_len}.2f} {d:>{d_len}.2f} {e:>{e_len}} **\n" for result in self.test_results: hilite = "" lolite = "" if result["pass"] is None: ratio = "-.--" pass_fail_str = "SKIP" if want_color_output(): hilite = ANSI.COLOR_SKIPPED lolite = ANSI.COLOR_DEFAULT elif result["pass"]: ratio = format(result["ratio"], "0.2f") pass_fail_str = "PASS" if want_color_output(): hilite = ANSI.COLOR_PASSED lolite = ANSI.COLOR_DEFAULT else: ratio = format(result["ratio"], "0.2f") pass_fail_str = "FAIL" if want_color_output(): hilite = ANSI.COLOR_FAILED lolite = ANSI.COLOR_DEFAULT test_dict = dict( a=result["test"], b=pass_fail_str, c=result["sim"], d=result["real"], e=ratio, a_len=TEST_FIELD_LEN, b_len=RESULT_FIELD_LEN, c_len=SIM_FIELD_LEN - 1, d_len=REAL_FIELD_LEN - 1, e_len=RATIO_FIELD_LEN - 1, start=hilite, end=lolite, ) summary += test_line.format(**test_dict) summary += LINE_SEP summary += test_line.format( a=TOTAL_NAME, b="", c=sim_time_ns, d=real_time, e=format(ratio_time, "0.2f"), a_len=TEST_FIELD_LEN, b_len=RESULT_FIELD_LEN, c_len=SIM_FIELD_LEN - 1, d_len=REAL_FIELD_LEN - 1, e_len=RATIO_FIELD_LEN - 1, start="", end="", ) summary += LINE_SEP self.log.info(summary)
async def run_seconds_increment(dut): tb = TB(dut) await tb.reset() await RisingEdge(dut.clk) dut.input_ts_96.value = 999990000 * 2**16 dut.input_ts_96_valid.value = 1 dut.input_ts_64.value = 999990000 * 2**16 dut.input_ts_64_valid.value = 1 await RisingEdge(dut.clk) dut.input_ts_96_valid.value = 0 dut.input_ts_64_valid.value = 0 await RisingEdge(dut.clk) await RisingEdge(dut.clk) start_time = get_sim_time('sec') start_ts_96 = (dut.output_ts_96.value.integer >> 48) + ( (dut.output_ts_96.value.integer & 0xffffffffffff) / 2**16 * 1e-9) start_ts_64 = dut.output_ts_64.value.integer / 2**16 * 1e-9 saw_pps = False for k in range(3000): await RisingEdge(dut.clk) if dut.output_pps.value.integer: saw_pps = True assert dut.output_ts_96.value.integer >> 48 == 1 assert dut.output_ts_96.value.integer & 0xffffffffffff < 10 * 2**16 assert saw_pps stop_time = get_sim_time('sec') stop_ts_96 = (dut.output_ts_96.value.integer >> 48) + ( (dut.output_ts_96.value.integer & 0xffffffffffff) / 2**16 * 1e-9) stop_ts_64 = dut.output_ts_64.value.integer / 2**16 * 1e-9 time_delta = stop_time - start_time ts_96_delta = stop_ts_96 - start_ts_96 ts_64_delta = stop_ts_64 - start_ts_64 ts_96_diff = time_delta - ts_96_delta ts_64_diff = time_delta - ts_64_delta tb.log.info("sim time delta : %g s", time_delta) tb.log.info("96 bit ts delta : %g s", ts_96_delta) tb.log.info("64 bit ts delta : %g s", ts_64_delta) tb.log.info("96 bit ts diff : %g s", ts_96_diff) tb.log.info("64 bit ts diff : %g s", ts_64_diff) assert abs(ts_96_diff) < 1e-12 assert abs(ts_64_diff) < 1e-12 await RisingEdge(dut.clk) await RisingEdge(dut.clk)
async def _run(self): frame = None self.active = False while True: await RisingEdge(self.clock) # read handshake signals tready_sample = (not hasattr(self.bus, "tready")) or self.bus.tready.value tvalid_sample = (not hasattr(self.bus, "tvalid")) or self.bus.tvalid.value if (tready_sample and tvalid_sample) or not tvalid_sample: if frame is None and not self.queue.empty(): frame = self.queue.get_nowait() self.dequeue_event.set() self.queue_occupancy_bytes -= len(frame) self.queue_occupancy_frames -= 1 self.current_frame = frame frame.sim_time_start = get_sim_time() frame.sim_time_end = None self.log.info("TX frame: %s", frame) frame.normalize() self.active = True if frame and not self.pause: tdata_val = 0 tlast_val = 0 tkeep_val = 0 tid_val = 0 tdest_val = 0 tuser_val = 0 for offset in range(self.byte_lanes): tdata_val |= (frame.tdata.pop(0) & self.byte_mask) << ( offset * self.byte_size) tkeep_val |= (frame.tkeep.pop(0) & 1) << offset tid_val = frame.tid.pop(0) tdest_val = frame.tdest.pop(0) tuser_val = frame.tuser.pop(0) if len(frame.tdata) == 0: tlast_val = 1 frame.sim_time_end = get_sim_time() frame.handle_tx_complete() frame = None self.current_frame = None break self.bus.tdata <= tdata_val if hasattr(self.bus, "tvalid"): self.bus.tvalid <= 1 if hasattr(self.bus, "tlast"): self.bus.tlast <= tlast_val if hasattr(self.bus, "tkeep"): self.bus.tkeep <= tkeep_val if hasattr(self.bus, "tid"): self.bus.tid <= tid_val if hasattr(self.bus, "tdest"): self.bus.tdest <= tdest_val if hasattr(self.bus, "tuser"): self.bus.tuser <= tuser_val else: if hasattr(self.bus, "tvalid"): self.bus.tvalid <= 0 if hasattr(self.bus, "tlast"): self.bus.tlast <= 0 self.active = bool(frame) if not frame and self.queue.empty(): self.idle_event.set()
async def _run(self): frame = None ifg_cnt = 0 deficit_idle_cnt = 0 self.active = False while True: await RisingEdge(self.clock) if self.enable is None or self.enable.value: if ifg_cnt + deficit_idle_cnt > self.byte_width - 1 or ( not self.enable_dic and ifg_cnt > 4): # in IFG ifg_cnt = ifg_cnt - self.byte_width if ifg_cnt < 0: if self.enable_dic: deficit_idle_cnt = max(deficit_idle_cnt + ifg_cnt, 0) ifg_cnt = 0 elif frame is None: # idle if self.queue: # send frame frame = self.queue.popleft() self.queue_occupancy_bytes -= len(frame) self.queue_occupancy_frames -= 1 frame.sim_time_start = get_sim_time() frame.sim_time_sfd = None frame.sim_time_end = None self.log.info("TX frame: %s", frame) frame.normalize() frame.start_lane = 0 assert frame.data[0] == EthPre.PRE assert frame.ctrl[0] == 0 frame.data[0] = XgmiiCtrl.START frame.ctrl[0] = 1 frame.data.append(XgmiiCtrl.TERM) frame.ctrl.append(1) # offset start if self.enable_dic: min_ifg = 3 - deficit_idle_cnt else: min_ifg = 0 if self.byte_width > 4 and (ifg_cnt > min_ifg or self.force_offset_start): ifg_cnt = ifg_cnt - 4 frame.start_lane = 4 frame.data = bytearray( [XgmiiCtrl.IDLE] * 4) + frame.data frame.ctrl = [1] * 4 + frame.ctrl if self.enable_dic: deficit_idle_cnt = max(deficit_idle_cnt + ifg_cnt, 0) ifg_cnt = 0 self.active = True else: # clear counters deficit_idle_cnt = 0 ifg_cnt = 0 if frame is not None: d_val = 0 c_val = 0 for k in range(self.byte_width): if frame is not None: d = frame.data.pop(0) if frame.sim_time_sfd is None and d == EthPre.SFD: frame.sim_time_sfd = get_sim_time() d_val |= d << k * 8 c_val |= frame.ctrl.pop(0) << k if not frame.data: ifg_cnt = max(self.ifg - (self.byte_width - k), 0) frame.sim_time_end = get_sim_time() frame.handle_tx_complete() frame = None else: d_val |= XgmiiCtrl.IDLE << k * 8 c_val |= 1 << k self.data <= d_val self.ctrl <= c_val else: self.data <= self.idle_d self.ctrl <= self.idle_c self.active = False
def handle_result(self, result): """Handle a test result Dumps result to XML and schedules the next test (if any) Args: result (TestComplete exception) """ real_time = time.time() - self._running_test.start_time sim_time_ns = get_sim_time('ns') - self._running_test.start_sim_time ratio_time = sim_time_ns / real_time self.xunit.add_testcase(name=self._running_test.funcname, classname=self._running_test.module, time=repr(real_time), sim_time_ns=repr(sim_time_ns), ratio_time=repr(ratio_time)) running_test_funcname = self._running_test.funcname # Helper for logging result def _result_was(): result_was = ("%s (result was %s)" % (running_test_funcname, result.__class__.__name__)) return result_was result_pass = True if (isinstance(result, TestSuccess) and not self._running_test.expect_fail and not self._running_test.expect_error): self.log.info("Test Passed: %s" % running_test_funcname) elif (isinstance(result, TestFailure) and self._running_test.expect_fail): self.log.info("Test failed as expected: " + _result_was()) elif (isinstance(result, TestSuccess) and self._running_test.expect_error): self.log.error("Test passed but we expected an error: " + _result_was()) self._add_failure(result) result_pass = False elif isinstance(result, TestSuccess): self.log.error("Test passed but we expected a failure: " + _result_was()) self._add_failure(result) result_pass = False elif isinstance(result, TestError) and self._running_test.expect_error: self.log.info("Test errored as expected: " + _result_was()) elif isinstance(result, SimFailure): if self._running_test.expect_error: self.log.info("Test errored as expected: " + _result_was()) else: self.log.error("Test error has lead to simulator shuttting us " "down") self._add_failure(result) self._store_test_result(self._running_test.module, self._running_test.funcname, False, sim_time_ns, real_time, ratio_time) self.tear_down() return else: self.log.error("Test Failed: " + _result_was()) self._add_failure(result) result_pass = False self._store_test_result(self._running_test.module, self._running_test.funcname, result_pass, sim_time_ns, real_time, ratio_time) self.execute()
async def _run(self): frame = None self.active = False clock_edge_event = RisingEdge(self.clock) while True: await clock_edge_event if self.enable is None or self.enable.value: d_val = self.data.value.integer dv_val = self.dv.value.integer er_val = 0 if self.er is None else self.er.value.integer if frame is None: if dv_val: # start of frame frame = GmiiFrame(bytearray(), []) frame.sim_time_start = get_sim_time() else: if not dv_val: # end of frame if self.mii_select is not None: self.mii_mode = bool(self.mii_select.value.integer) if self.mii_mode: odd = True sync = False b = 0 be = 0 data = bytearray() error = [] for n, e in zip(frame.data, frame.error): odd = not odd b = (n & 0x0F) << 4 | b >> 4 be |= e if not sync and b == EthPre.SFD: odd = True sync = True if odd: data.append(b) error.append(be) be = 0 frame.data = data frame.error = error frame.compact() frame.sim_time_end = get_sim_time() self.log.info("RX frame: %s", frame) self.queue_occupancy_bytes += len(frame) self.queue_occupancy_frames += 1 self.queue.put_nowait(frame) self.active_event.set() frame = None if frame is not None: if frame.sim_time_sfd is None and d_val in (EthPre.SFD, 0xD): frame.sim_time_sfd = get_sim_time() frame.data.append(d_val) frame.error.append(er_val)
async def _run(self): frame = None self.active = False d_val = 0 dv_val = 0 er_val = 0 while True: await RisingEdge(self.clock) # capture low nibble on rising edge d_val = self.data.value.integer dv_val = self.ctrl.value.integer await FallingEdge(self.clock) # capture high nibble on falling edge d_val |= self.data.value.integer << 4 er_val = dv_val ^ self.ctrl.value.integer if self.enable is None or self.enable.value: if frame is None: if dv_val: # start of frame frame = GmiiFrame(bytearray(), []) frame.sim_time_start = get_sim_time() else: if not dv_val: # end of frame if self.mii_select is not None: self.mii_mode = bool(self.mii_select.value.integer) if self.mii_mode: odd = True sync = False b = 0 be = 0 data = bytearray() error = [] for n, e in zip(frame.data, frame.error): odd = not odd b = (n & 0x0F) << 4 | b >> 4 be |= e if not sync and b == EthPre.SFD: odd = True sync = True if odd: data.append(b) error.append(be) be = 0 frame.data = data frame.error = error frame.compact() frame.sim_time_end = get_sim_time() self.log.info("RX frame: %s", frame) self.queue_occupancy_bytes += len(frame) self.queue_occupancy_frames += 1 self.queue.append(frame) self.sync.set() frame = None if frame is not None: if frame.sim_time_sfd is None and d_val in (EthPre.SFD, 0xD, 0xDD): frame.sim_time_sfd = get_sim_time() frame.data.append(d_val) frame.error.append(er_val)
def handle_result(self, test): """Handle a test completing. Dump result to XML and schedule the next test (if any). Args: test: The test that completed """ assert test is self._running_test real_time = time.time() - test.start_time sim_time_ns = get_sim_time('ns') - test.start_sim_time ratio_time = self._safe_divide(sim_time_ns, real_time) self.xunit.add_testcase(name=test.funcname, classname=test.module, time=repr(real_time), sim_time_ns=repr(sim_time_ns), ratio_time=repr(ratio_time)) # Helper for logging result def _result_was(): result_was = ("{} (result was {})".format( test.funcname, result.__class__.__name__)) return result_was result_pass = True # check what exception the test threw try: test._outcome.get() except Exception as e: if sys.version_info >= (3, 5): result = remove_traceback_frames(e, ['handle_result', 'get']) # newer versions of the `logging` module accept plain exception objects exc_info = result elif sys.version_info >= (3, ): result = remove_traceback_frames(e, ['handle_result', 'get']) # newer versions of python have Exception.__traceback__ exc_info = (type(result), result, result.__traceback__) else: # Python 2 result = e exc_info = remove_traceback_frames(sys.exc_info(), ['handle_result', 'get']) else: result = TestSuccess() if (isinstance(result, TestSuccess) and not test.expect_fail and not test.expect_error): self.log.info("Test Passed: %s" % test.funcname) elif (isinstance(result, AssertionError) and test.expect_fail): self.log.info("Test failed as expected: " + _result_was()) elif (isinstance(result, TestSuccess) and test.expect_error): self.log.error("Test passed but we expected an error: " + _result_was()) self._add_failure(result) result_pass = False elif isinstance(result, TestSuccess): self.log.error("Test passed but we expected a failure: " + _result_was()) self._add_failure(result) result_pass = False elif isinstance(result, SimFailure): if isinstance(result, test.expect_error): self.log.info("Test errored as expected: " + _result_was()) else: self.log.error( "Test error has lead to simulator shutting us " "down", exc_info=exc_info) self._add_failure(result) self._store_test_result(test.module, test.funcname, False, sim_time_ns, real_time, ratio_time) self.tear_down() return elif test.expect_error: if isinstance(result, test.expect_error): self.log.info("Test errored as expected: " + _result_was()) else: self.log.info("Test errored with unexpected type: " + _result_was()) self._add_failure(result) result_pass = False else: self.log.error("Test Failed: " + _result_was(), exc_info=exc_info) self._add_failure(result) result_pass = False self._store_test_result(test.module, test.funcname, result_pass, sim_time_ns, real_time, ratio_time) self.execute()
def uvm_sim_time(units='NS'): if simulator is not None: return get_sim_time(units=units) return 0
async def _run(self): frame = None ifg_cnt = 0 self.active = False d = 0 er = 0 en = 0 while True: await RisingEdge(self.clock) # send high nibble after rising edge, leading in to falling edge self.data <= d >> 4 self.ctrl <= en ^ er if self.enable is None or self.enable.value: if ifg_cnt > 0: # in IFG ifg_cnt -= 1 elif frame is None and self.queue: # send frame frame = self.queue.popleft() self.queue_occupancy_bytes -= len(frame) self.queue_occupancy_frames -= 1 frame.sim_time_start = get_sim_time() frame.sim_time_sfd = None frame.sim_time_end = None self.log.info("TX frame: %s", frame) frame.normalize() if self.mii_select is not None: self.mii_mode = bool(self.mii_select.value.integer) if self.mii_mode: mii_data = [] mii_error = [] for b, e in zip(frame.data, frame.error): mii_data.append((b & 0x0F)*0x11) mii_data.append((b >> 4)*0x11) mii_error.append(e) mii_error.append(e) frame.data = mii_data frame.error = mii_error self.active = True if frame is not None: d = frame.data.pop(0) er = frame.error.pop(0) en = 1 if frame.sim_time_sfd is None and d in (EthPre.SFD, 0xD, 0xDD): frame.sim_time_sfd = get_sim_time() if not frame.data: ifg_cnt = max(self.ifg, 1) frame.sim_time_end = get_sim_time() frame.handle_tx_complete() frame = None else: d = 0 er = 0 en = 0 self.active = False await FallingEdge(self.clock) # send low nibble after falling edge, leading in to rising edge self.data <= d & 0x0F self.ctrl <= en
def run_phase(self, phase): phase.raise_objection(self) yield Timer(10) print("{}: {} HI".format(get_sim_time(), self.get_full_name())) phase.drop_objection(self)
async def _run(self): frame = None frame_offset = 0 frame_data = None frame_error = None ifg_cnt = 0 self.active = False d = 0 er = 0 en = 0 clock_rising_edge_event = RisingEdge(self.clock) clock_falling_edge_event = FallingEdge(self.clock) while True: await clock_rising_edge_event # send high nibble after rising edge, leading in to falling edge self.data.value = d >> 4 self.ctrl.value = en ^ er if self.enable is None or self.enable.value: if ifg_cnt > 0: # in IFG ifg_cnt -= 1 elif frame is None and not self.queue.empty(): # send frame frame = self.queue.get_nowait() self.dequeue_event.set() self.queue_occupancy_bytes -= len(frame) self.queue_occupancy_frames -= 1 self.current_frame = frame frame.sim_time_start = get_sim_time() frame.sim_time_sfd = None frame.sim_time_end = None self.log.info("TX frame: %s", frame) frame.normalize() if self.mii_select is not None: self.mii_mode = bool(self.mii_select.value.integer) if self.mii_mode: # convert to MII frame_data = [] frame_error = [] for b, e in zip(frame.data, frame.error): frame_data.append((b & 0x0F)*0x11) frame_data.append((b >> 4)*0x11) frame_error.append(e) frame_error.append(e) else: frame_data = frame.data frame_error = frame.error self.active = True frame_offset = 0 if frame is not None: d = frame_data[frame_offset] er = frame_error[frame_offset] en = 1 frame_offset += 1 if frame.sim_time_sfd is None and d in (EthPre.SFD, 0xD, 0xDD): frame.sim_time_sfd = get_sim_time() if frame_offset >= len(frame_data): ifg_cnt = max(self.ifg, 1) frame.sim_time_end = get_sim_time() frame.handle_tx_complete() frame = None self.current_frame = None else: d = 0 er = 0 en = 0 self.active = False self.idle_event.set() await clock_falling_edge_event # send low nibble after falling edge, leading in to rising edge self.data.value = d & 0x0F self.ctrl.value = en
def Heartbeat(): while beat: yield Timer(1, units="ms") ct = get_sim_time("us") self.dut._log.info("Waiting, current time {:.0f}".format(ct))
def test_tree(dut): """Testing APBI2C core""" log = cocotb.logging.getLogger("cocotb.test") cocotb.fork(Clock(dut.PCLK, 1000).start()) #instantiate the APB agent (monitor and driver) (see apb.py) apb = APBSlave(dut, name=None, clock=dut.PCLK) #instantiate the I2C monitor and driver (see i2c.py) i2c_monitor = I2CMonitor(dut, name="", clock=dut.PCLK) i2c_driver = I2CDriver(dut, name=None, clock=dut.PCLK) #write to config register via APB @cocotb.coroutine def config_write(addr, data): xaction = APBTransaction(addr, data, write=True) xaction.randomize() yield apb.send(xaction) #store observed I2C transactions received_i2c_xactions = [] #the catcher for observerd I2C transaction on the interfece @I2CCoverage def i2c_xaction_catcher(i2c_xaction): if LOG_XACTION_ENABLE: log.info("I2C Monitor: Transaction 0x%08X" % i2c_xaction.data) received_i2c_xactions.append(i2c_xaction) #callback to the monitor to call the catcher when I2C transaction observed i2c_monitor.add_callback(i2c_xaction_catcher) #the catcher for observerd APB transaction on the interfece @APBCoverage def apb_xaction_catcher(apb_xaction): if LOG_XACTION_ENABLE: try: log.info("APB Transaction %s 0x%08X -> 0x%08X" % ("Write" if apb_xaction.write else "Read ", int(apb_xaction.addr), int(apb_xaction.data))) except: log.info("APB Transaction %s 0x%08X -> 0x%08s" % ("Write" if apb_xaction.write else "Read ", int(apb_xaction.addr), int(apb_xaction.data))) #callback to the monitor to call the catcher when APB transaction observed apb.add_callback(apb_xaction_catcher) #define "I2C Operation" as a bunch of r/ws with defined number of data #and a specific clock divider #this is the main stuff to be tested - we want to know if controller #correctly processes transfers with different directions, amount of #data and SCK period class I2C_Operation(Randomized): def __init__(self, direction='write', repeat=1, divider=1): Randomized.__init__(self) self.direction = direction self.repeat = repeat self.divider = divider self.repeat_range = (1, 3) self.divider_range = (1, 3) #I2C_Operation objects may be fully randomized self.addRand("direction", ["write", "read"]) self.addRand("repeat_range", [(1, 3), (4, 7), (8, 11), (12, 15), (16, 23), (24, 31)]) self.addRand("divider_range", [(1, 3), (4, 7), (8, 11), (12, 15), (16, 23), (24, 31)]) #post_randomize to pick random values from already randomized ranges def post_randomize(self): self.repeat = random.randint(self.repeat_range[0], self.repeat_range[1]) self.divider = random.randint(self.divider_range[0], self.divider_range[1]) #list of completed operations for the summary operations_completed = [] #function sampling operations order coverage (see coverage.py) @OperationsOrderCoverage def sample_operations_order_coverage(prev_operation, operation): pass #function sampling operations coverage (see coverage.py) @OperationsCoverage def sample_operation(operation, ok): operations_completed.append((operation, ok)) if (len(operations_completed) > 1): sample_operations_order_coverage(operations_completed[-2][0], operations_completed[-1][0]) if ok: log.info( "Operation %s of %d words, divider %d - OK!" % (operation.direction, operation.repeat, operation.divider)) else: log.error( "Operation %s of %d words, divider %d - error!" % (operation.direction, operation.repeat, operation.divider)) #a test sequence - complete I2C Write Operation @cocotb.coroutine def segment_i2c_write_operation(operation): expected_out = [] yield config_write(8, 0x0001 | (operation.divider << 2)) #create xaction objects and fill FIFO up via APB with data to be send apb_xaction = APBTransaction(0, 0, write=True) for i in range(operation.repeat): i2c_xaction = I2CTransaction(0, write=False) i2c_xaction.randomize() apb_xaction.data = i2c_xaction.data apb_xaction.randomize() yield apb.send(apb_xaction) expected_out.append(i2c_xaction) #wait for FIFO empty - meaning all data sent out guard_int = 0 while not dut.INT_TX.value: guard_int = guard_int + 1 yield RisingEdge(dut.PCLK) if guard_int == 50000: raise TestFailure("Controller hang-up!") #a simple scoreboarding... #compare data written to APB with catched on I2C interface ok = True received_xactions = received_i2c_xactions[-operation.repeat:] if len(received_xactions) < operation.repeat: ok = False else: for i in range(operation.repeat): if (received_xactions[i] != expected_out[i]): ok = False break #call sampling at the and of the sequence sample_operation(operation, ok) #a test sequence - complete I2C Read Operation @cocotb.coroutine def segment_i2c_read_operation(operation): expected_in = [] yield config_write(8, 0x0002 | (operation.divider << 2)) #create I2C xaction objects and send on the interface for i in range(operation.repeat): i2c_xaction = I2CTransaction(0, write=True) i2c_xaction.randomize() expected_in.append(i2c_xaction) yield i2c_driver.send(i2c_xaction) #a simple scoreboarding... #compare data written on I2C interface with read from FIFO ok = True apb_xaction = APBTransaction(0x04, 0, write=False) for i in range(operation.repeat): try: apb_xaction.randomize() rdata = yield apb.send(xaction) if (rdata != expected_in[i].data): ok = False except: if LOG_XACTION_ENABLE: log.error("APB read data from FIFO is 'X'") ok = False #call sampling at the and of the sequence sample_operation(operation, ok) #a test sequence - APB registers operation (sort of UVM_REG :) ) @cocotb.coroutine def segment_apb_rw(repeat=1, addr=0xC): apb_xaction_wr = APBTransaction(addr, 0, write=True) apb_xaction_rd = APBTransaction(addr, 0, write=False) #just do some APB/RW for i in range(repeat): data = random.randint(0, 0xFFFFFFFF) apb_xaction_wr.randomize() apb_xaction_wr.data = data yield apb.send(apb_xaction_wr) apb_xaction_rd.randomize() rdata = yield apb.send(apb_xaction_rd) if LOG_XACTION_ENABLE: try: if rdata != data: log.error( "APB read data @ 0x%08X does not match written value" % addr) except: log.error("APB read data @ 0x%08X is 'X'" % addr) #reset the DUT dut.PRESETn <= 0 yield Timer(2000) dut.PRESETn <= 1 yield config_write(12, 0x0100) #if checkpoints used, store them in the map, (see checkpoint.py) if ENABLE_CHECKPOINTS: checkpoints = {} get_checkpoint_hier(dut) #the fist checkpoint is just after reset checkpoints['init'] = (checkpoint(), None) #list of already covered operations, used to constraint the randomization already_covered = [] #constraint for the operation randomization - do not use already #covered combinations def op_constraint(direction, divider_range, repeat_range): return not (direction, repeat_range, divider_range) in already_covered apb_cover_item = coverage_db["top.apb.writeXdelay"] top_cover_item = coverage_db["top"] #we define test end condition as reaching 99% coverage at the #top cover item cov_op = 0 while cov_op < 90: #restore randomly selected checkpoint if ENABLE_CHECKPOINTS: if CHECKPOINTS_TREE_STRUCTURE: chkp_to_restore = random.choice(list(checkpoints.keys())) else: chkp_to_restore = 'init' log.info("Restoring a simulation checkpoint: " + chkp_to_restore) current_chceckpoint = checkpoints[chkp_to_restore] restore(current_chceckpoint[0]) #create I2C operation object to be executed i2c_op = I2C_Operation() #if there is no tree structure, knowledge about already covered #cases cannot be used if ENABLE_CHECKPOINTS & CHECKPOINTS_TREE_STRUCTURE: try: i2c_op.randomize_with(op_constraint) except: i2c_op.randomize() else: i2c_op.randomize() already_covered.append( (i2c_op.direction, i2c_op.repeat_range, i2c_op.divider_range)) #call test sequence if i2c_op.direction == "read": yield segment_i2c_read_operation(i2c_op) else: yield segment_i2c_write_operation(i2c_op) if ENABLE_CHECKPOINTS: #if status is OK, add this simulation point to the checkpoints list if operations_completed[-1][1]: chkp_name = str(get_sim_time('ns')) log.info("Creating a simulation checkpoint: " + chkp_name) checkpoints[chkp_name] = (checkpoint(), i2c_op) #call APB test sequence as long as cover item apb.writeXdelay #coverage level is below 100% if apb_cover_item.coverage * 100 / apb_cover_item.size < 100: yield segment_apb_rw(repeat=random.randint(1, 5)) #update the coverage level cov_op_prev = cov_op cov_op = top_cover_item.coverage * 100.0 / top_cover_item.size log.info("Current overall coverage level = %f %%", cov_op) #print summary log.info("Opertions finished succesfully:") for elem in operations_completed: if elem[1]: log.info(" %s of %d words with divider %d" % (elem[0].direction, elem[0].repeat, elem[0].divider)) log.info("Opertions finished with error:") for elem in operations_completed: if not elem[1]: log.info(" %s of %d words with divider %d" % (elem[0].direction, elem[0].repeat, elem[0].divider)) log.info("Functional coverage details:") reportCoverage(log.info, bins=False)
async def _run(self): frame = None frame_offset = 0 frame_data = None frame_error = None ifg_cnt = 0 self.active = False clock_edge_event = RisingEdge(self.clock) while True: await clock_edge_event if self.enable is None or self.enable.value: if ifg_cnt > 0: # in IFG ifg_cnt -= 1 elif frame is None and not self.queue.empty(): # send frame frame = self.queue.get_nowait() self.dequeue_event.set() self.queue_occupancy_bytes -= len(frame) self.queue_occupancy_frames -= 1 self.current_frame = frame frame.sim_time_start = get_sim_time() frame.sim_time_sfd = None frame.sim_time_end = None self.log.info("TX frame: %s", frame) frame.normalize() # convert to MII frame_data = [] frame_error = [] for b, e in zip(frame.data, frame.error): frame_data.append(b & 0x0F) frame_data.append(b >> 4) frame_error.append(e) frame_error.append(e) self.active = True frame_offset = 0 if frame is not None: d = frame_data[frame_offset] if frame.sim_time_sfd is None and d == 0xD: frame.sim_time_sfd = get_sim_time() self.data.value = d if self.er is not None: self.er.value = frame_error[frame_offset] self.dv.value = 1 frame_offset += 1 if frame_offset >= len(frame_data): ifg_cnt = max(self.ifg, 1) frame.sim_time_end = get_sim_time() frame.handle_tx_complete() frame = None self.current_frame = None else: self.data.value = 0 if self.er is not None: self.er.value = 0 self.dv.value = 0 self.active = False self.idle_event.set()
def handle_result(self, result): """Handle a test result Dumps result to XML and schedules the next test (if any) Args: result (TestComplete exception) """ real_time = time.time() - self._running_test.start_time sim_time_ns = get_sim_time('ns') - self._running_test.start_sim_time ratio_time = sim_time_ns / real_time self.xunit.add_testcase(name=self._running_test.funcname, classname=self._running_test.module, time=repr(real_time), sim_time_ns=repr(sim_time_ns), ratio_time=repr(ratio_time)) running_test_funcname = self._running_test.funcname # Helper for logging result def _result_was(): result_was = ("%s (result was %s)" % (running_test_funcname, result.__class__.__name__)) return result_was result_pass = True if (isinstance(result, TestSuccess) and not self._running_test.expect_fail and not self._running_test.expect_error): self.log.info("Test Passed: %s" % running_test_funcname) elif (isinstance(result, TestFailure) and self._running_test.expect_fail): self.log.info("Test failed as expected: " + _result_was()) elif (isinstance(result, TestSuccess) and self._running_test.expect_error): self.log.error("Test passed but we expected an error: " + _result_was()) self._add_failure(result) result_pass = False elif isinstance(result, TestSuccess): self.log.error("Test passed but we expected a failure: " + _result_was()) self._add_failure(result) result_pass = False elif isinstance(result, TestError) and self._running_test.expect_error: self.log.info("Test errored as expected: " + _result_was()) elif isinstance(result, SimFailure): if self._running_test.expect_error: self.log.info("Test errored as expected: " + _result_was()) else: self.log.error("Test error has lead to simulator shutting us " "down") self._add_failure(result) self._store_test_result(self._running_test.module, self._running_test.funcname, False, sim_time_ns, real_time, ratio_time) self.tear_down() return else: self.log.error("Test Failed: " + _result_was()) self._add_failure(result) result_pass = False self._store_test_result(self._running_test.module, self._running_test.funcname, result_pass, sim_time_ns, real_time, ratio_time) self.execute()
async def _run_transmit(self): await NullTrigger() while True: while self.tx_queue.empty() and not self.send_ack.is_set() and not self.send_fc.is_set() and self.fc_initialized: self.tx_queue_sync.clear() await First(self.tx_queue_sync.wait(), self.send_ack.wait(), self.send_fc.wait()) pkt = None if self.send_ack.is_set(): # Send ACK or NAK DLLP # Runs when # - ACK timer expires # - ACK/NAK transmit requested self.send_ack.clear() if self.nak_scheduled: pkt = Dllp.create_nak((self.next_recv_seq-1) & 0xfff) else: pkt = Dllp.create_ack((self.next_recv_seq-1) & 0xfff) elif self.send_fc.is_set() or (not self.fc_initialized and self.tx_queue.empty()): # Send FC DLLP # Runs when # - FC timer expires # - FC update DLLP transmit requested # - FC init is not done AND no TLPs are queued for transmit if self.send_fc.is_set(): # Send FC update DLLP for fc_ch in self.fc_state: if not fc_ch.active or not fc_ch.fi2: continue sim_time = get_sim_time() if fc_ch.next_fc_p_tx <= sim_time: pkt = Dllp() pkt.vc = self.fc_init_vc pkt.type = DllpType.UPDATE_FC_P pkt.hdr_fc = fc_ch.ph.rx_credits_allocated pkt.data_fc = fc_ch.pd.rx_credits_allocated fc_ch.next_fc_p_tx = sim_time + self.fc_update_steps break if fc_ch.next_fc_np_tx <= sim_time: pkt = Dllp() pkt.vc = self.fc_init_vc pkt.type = DllpType.UPDATE_FC_NP pkt.hdr_fc = fc_ch.nph.rx_credits_allocated pkt.data_fc = fc_ch.npd.rx_credits_allocated fc_ch.next_fc_np_tx = sim_time + self.fc_update_steps break if fc_ch.next_fc_cpl_tx <= sim_time: pkt = Dllp() pkt.vc = self.fc_init_vc pkt.type = DllpType.UPDATE_FC_CPL pkt.hdr_fc = fc_ch.cplh.rx_credits_allocated pkt.data_fc = fc_ch.cpld.rx_credits_allocated fc_ch.next_fc_cpl_tx = sim_time + self.fc_update_steps break if not self.fc_initialized and not pkt: # Send FC init DLLP fc_ch = self.fc_state[self.fc_init_vc] pkt = Dllp() pkt.vc = self.fc_init_vc if self.fc_init_type == FcType.P: pkt.type = DllpType.INIT_FC1_P if not fc_ch.fi1 else DllpType.INIT_FC2_P pkt.hdr_fc = fc_ch.ph.rx_credits_allocated pkt.data_fc = fc_ch.pd.rx_credits_allocated self.fc_init_type = FcType.NP elif self.fc_init_type == FcType.NP: pkt.type = DllpType.INIT_FC1_NP if not fc_ch.fi1 else DllpType.INIT_FC2_NP pkt.hdr_fc = fc_ch.nph.rx_credits_allocated pkt.data_fc = fc_ch.npd.rx_credits_allocated self.fc_init_type = FcType.CPL elif self.fc_init_type == FcType.CPL: pkt.type = DllpType.INIT_FC1_CPL if not fc_ch.fi1 else DllpType.INIT_FC2_CPL pkt.hdr_fc = fc_ch.cplh.rx_credits_allocated pkt.data_fc = fc_ch.cpld.rx_credits_allocated self.fc_init_type = FcType.P # find next active VC that hasn't finished FC init for k in range(8): vc = (self.fc_init_vc+1+k) % 8 if self.fc_state[vc].active and not self.fc_state[vc].fi2: self.fc_init_vc = vc break # check all active VC and report FC not initialized if any are not complete self.fc_initialized = True for vc in range(8): if self.fc_state[vc].active and not self.fc_state[vc].fi2: self.fc_initialized = False if not pkt: # no more DLLPs to send, clear event self.send_fc.clear() if pkt is not None: self.log.debug("Send DLLP %s", pkt) elif not self.tx_queue.empty(): pkt = self.tx_queue.get_nowait() pkt.seq = self.next_transmit_seq self.log.debug("Send TLP %s", pkt) self.next_transmit_seq = (self.next_transmit_seq + 1) & 0xfff self.retry_buffer.put_nowait(pkt) if pkt: await self.handle_tx(pkt)