def rx_data_to_ad9361( self, i_data, q_data, i_data2=None, q_data2=None, binaryRepresentation=BinaryRepresentation.TWOS_COMPLEMENT): i_bin_val = BinaryValue(bits=12, bigEndian=False, binaryRepresentation=binaryRepresentation) q_bin_val = BinaryValue(bits=12, bigEndian=False, binaryRepresentation=binaryRepresentation) index = 0 if i_data2 == None and q_data2 == None: while True: yield RisingEdge(self.dut.rx_clk_in_p) if self.rx_frame_asserted: self.dut.rx_data_in_p <= i_bin_val[5:0] self.dut.rx_data_in_n <= ~i_bin_val[5:0] self.rx_frame_asserted = False self.dut.rx_frame_in_p <= 0 self.dut.rx_frame_in_n <= 1 else: if index < len(i_data): i_bin_val.set_value(i_data[index]) q_bin_val.set_value(q_data[index]) index += 1 else: return self.dut.rx_data_in_p <= i_bin_val[11:6] self.dut.rx_data_in_n <= ~i_bin_val[11:6] self.rx_frame_asserted = True self.dut.rx_frame_in_p <= 1 self.dut.rx_frame_in_n <= 0 yield RisingEdge(self.dut.rx_clk_in_n) if self.rx_frame_asserted: self.dut.rx_data_in_p <= q_bin_val[11:6] self.dut.rx_data_in_n <= ~q_bin_val[11:6] else: self.dut.rx_data_in_p <= q_bin_val[5:0] self.dut.rx_data_in_n <= ~q_bin_val[5:0] else: I_SEND_HIGH = True Q_SEND_HIGH = True channel = 1 while True: yield RisingEdge(self.dut.rx_clk_in_p) if I_SEND_HIGH: self.dut.rx_data_in_p <= i_bin_val[11:6] self.dut.rx_data_in_n <= ~i_bin_val[11:6] I_SEND_HIGH = False if channel == 1: self.dut.rx_frame_in_p <= 1 self.dut.rx_frame_in_n <= 0 elif channel == 2: self.dut.rx_frame_in_p <= 0 self.dut.rx_frame_in_n <= 1 else: self.dut.rx_data_in_p <= i_bin_val[5:0] self.dut.rx_data_in_n <= ~i_bin_val[5:0] I_SEND_HIGH = True yield RisingEdge(self.dut.rx_clk_in_n) if Q_SEND_HIGH: self.dut.rx_data_in_p <= q_bin_val[5:0] self.dut.rx_data_in_n <= ~q_bin_val[5:0] Q_SEND_HIGH = False else: self.dut.rx_data_in_p <= q_bin_val[11:6] self.dut.rx_data_in_n <= ~q_bin_val[11:6] Q_SEND_HIGH = True if index < len(i_data): if channel == 1: i_bin_val.set_value(i_data[index]) q_bin_val.set_value(q_data[index]) channel = 2 elif channel == 2: i_bin_val.set_value(i_data2[index]) q_bin_val.set_value(q_data2[index]) channel = 1 index += 1 else: return
def wait_for(clk, cycles): rising_edge = RisingEdge(clk) for _ in range(cycles): yield rising_edge return 3
async def _monitor_recv(self): """Watch the pins and reconstruct transactions.""" # Avoid spurious object creation by recycling clkedge = RisingEdge(self.clock) rdonly = ReadOnly() pkt = b"" in_pkt = False invalid_cyclecount = 0 channel = None def valid(): if hasattr(self.bus, 'ready'): return self.bus.valid.value and self.bus.ready.value return self.bus.valid.value while True: await clkedge await rdonly if self.in_reset: continue if valid(): invalid_cyclecount = 0 if self.bus.startofpacket.value: if pkt: raise AvalonProtocolError( "Duplicate start-of-packet received on %s" % str(self.bus.startofpacket)) pkt = b"" in_pkt = True if not in_pkt: raise AvalonProtocolError("Data transfer outside of " "packet") # Handle empty and X's in empty / data vec = BinaryValue() if not self.bus.endofpacket.value: vec = self.bus.data.value else: value = self.bus.data.value.get_binstr() if self.config["useEmpty"] and self.bus.empty.value.integer: empty = self.bus.empty.value.integer * self.config[ "dataBitsPerSymbol"] if self.config["firstSymbolInHighOrderBits"]: value = value[:-empty] else: value = value[empty:] vec.assign(value) if not vec.is_resolvable: raise AvalonProtocolError( "After empty masking value is still bad? " "Had empty {:d}, got value {:s}".format( empty, self.bus.data.value.get_binstr())) vec.big_endian = self.config['firstSymbolInHighOrderBits'] pkt += vec.buff if hasattr(self.bus, 'channel'): if channel is None: channel = self.bus.channel.value.integer if channel > self.config["maxChannel"]: raise AvalonProtocolError( "Channel value (%d) is greater than maxChannel (%d)" % (channel, self.config["maxChannel"])) elif self.bus.channel.value.integer != channel: raise AvalonProtocolError( "Channel value changed during packet") if self.bus.endofpacket.value: self.log.info("Received a packet of %d bytes", len(pkt)) self.log.debug(hexdump(pkt)) self.channel = channel if self.report_channel: self._recv({"data": pkt, "channel": channel}) else: self._recv(pkt) pkt = b"" in_pkt = False channel = None else: if in_pkt: invalid_cyclecount += 1 if self.config["invalidTimeout"]: if invalid_cyclecount >= self.config["invalidTimeout"]: raise AvalonProtocolError( "In-Packet Timeout. Didn't receive any valid data for %d cycles!" % invalid_cyclecount)
async def wait_for(clk, cycles): rising_edge = RisingEdge(clk) for _ in range(cycles): await rising_edge return 3
def do_test_afterdelay_in_readonly(dut, delay): global exited yield RisingEdge(dut.clk) yield ReadOnly() yield Timer(delay) exited = True
def _send_string(self, string, sync=True, channel=None): """Args: string (str): A string of bytes to send over the bus. channel (int): Channel to send the data on. """ # Avoid spurious object creation by recycling clkedge = RisingEdge(self.clock) firstword = True # FIXME: buses that aren't an integer numbers of bytes bus_width = int(len(self.bus.data) / 8) word = BinaryValue(n_bits=len(self.bus.data), bigEndian=self.config["firstSymbolInHighOrderBits"]) single = BinaryValue(n_bits=1, bigEndian=False) if self.use_empty: empty = BinaryValue(n_bits=len(self.bus.empty), bigEndian=False) # Drive some defaults since we don't know what state we're in if self.use_empty: self.bus.empty <= 0 self.bus.startofpacket <= 0 self.bus.endofpacket <= 0 self.bus.valid <= 0 if hasattr(self.bus, 'error'): self.bus.error <= 0 if hasattr(self.bus, 'channel'): self.bus.channel <= 0 elif channel is not None: raise TestError("%s does not have a channel signal" % self.name) while string: if not firstword or (firstword and sync): yield clkedge # Insert a gap where valid is low if not self.on: self.bus.valid <= 0 for _ in range(self.off): yield clkedge # Grab the next set of on/off values self._next_valids() # Consume a valid cycle if self.on is not True and self.on: self.on -= 1 self.bus.valid <= 1 if hasattr(self.bus, 'channel'): if channel is None: self.bus.channel <= 0 elif channel > self.config['maxChannel'] or channel < 0: raise TestError( "%s: Channel value %d is outside range 0-%d" % (self.name, channel, self.config['maxChannel'])) else: self.bus.channel <= channel if firstword: self.bus.startofpacket <= 1 firstword = False else: self.bus.startofpacket <= 0 nbytes = min(len(string), bus_width) data = string[:nbytes] word.buff = data if len(string) <= bus_width: self.bus.endofpacket <= 1 if self.use_empty: self.bus.empty <= bus_width - len(string) string = "" else: string = string[bus_width:] self.bus.data <= word # If this is a bus with a ready signal, wait for this word to # be acknowledged if hasattr(self.bus, "ready"): yield self._wait_ready() yield clkedge self.bus.valid <= 0 self.bus.endofpacket <= 0 word.binstr = "x" * len(self.bus.data) single.binstr = "x" self.bus.data <= word self.bus.startofpacket <= single self.bus.endofpacket <= single if self.use_empty: empty.binstr = "x" * len(self.bus.empty) self.bus.empty <= empty if hasattr(self.bus, 'channel'): channel_value = BinaryValue(n_bits=len(self.bus.channel), bigEndian=False, value="x" * len(self.bus.channel)) self.bus.channel <= channel_value
def _send_string(self, string, sync=True): """ Args: string (str): A string of bytes to send over the bus """ # Avoid spurious object creation by recycling clkedge = RisingEdge(self.clock) firstword = True # FIXME busses that aren't integer numbers of bytes bus_width = int(len(self.bus.data) / 8) word = BinaryValue(bits=len(self.bus.data), bigEndian=self.config['firstSymbolInHighOrderBits']) empty = BinaryValue(bits=len(self.bus.empty), bigEndian=False) single = BinaryValue(bits=1, bigEndian=False) # Drive some defaults since we don't know what state we're in # self.bus.empty <= 0 self.bus.startofpacket <= 0 self.bus.endofpacket <= 0 self.bus.valid <= 0 if hasattr(self.bus, 'error'): self.bus.error <= 0 while string: if not firstword or (firstword and sync): yield clkedge # Insert a gap where valid is low if not self.on: self.bus.valid <= 0 for i in range(self.off): yield clkedge # Grab the next set of on/off values self._next_valids() # Consume a valid cycle if self.on is not True and self.on: self.on -= 1 self.bus.valid <= 1 if firstword: #self.bus.empty <= 0 self.bus.startofpacket <= 1 firstword = False else: self.bus.startofpacket <= 0 nbytes = min(len(string), bus_width) data = string[:nbytes] word.buff = data if len(string) <= bus_width: self.bus.endofpacket <= 1 self.bus.empty <= bus_width - len(string) string = "" else: string = string[bus_width:] self.bus.data <= word # If this is a bus with a ready signal, wait for this word to # be acknowledged if hasattr(self.bus, "ready"): yield self._wait_ready() yield clkedge self.bus.valid <= 0 self.bus.endofpacket <= 0 word.binstr = ("x" * len(self.bus.data)) empty.binstr = ("x" * len(self.bus.empty)) single.binstr = ("x") self.bus.data <= word self.bus.empty <= empty self.bus.startofpacket <= single self.bus.endofpacket <= single
def write_reg(dut, addr, val): dut.addr_i <= addr dut.we_i <= 1 dut.data_i <= val yield RisingEdge(dut.clk_i)
def scan_in(self, val, T = None, scan_clk = None, scan_in = None, scan_out = None, scan_en = None, scan_wen = None, fromMSB = None, verbosity = None, clk_running = None, clk_b = None, read_func = None): if T is None: T = self.T halfT = self.halfT quarterT = self.quarterT else: halfT = int(T/2) quarterT = int(T/4) if scan_clk is None: scan_clk = self._scan_clk if scan_in is None: scan_in = self._scan_in if scan_out is None: scan_out = self._scan_out if scan_en is None: scan_en = self._scan_en if scan_wen is None: scan_wen = self._scan_wen if fromMSB is None: fromMSB = self.fromMSB if verbosity is None: verbosity = self.verbosity if clk_running is None: clk_running = self.clk_running if clk_b is None: clk_b = self.clk_b if read_func is None: read_func = self.read_func if self.length is not None and len(val) != self.length: print(f'Warning: number of scanned bits ({len(val)}) is not equal to the scan chain length ({self.length})') if fromMSB: val = val[::-1] if Config.running_cocotb: if clk_running: if clk_b: yield RisingEdge(scan_clk) else: yield FallingEdge(scan_clk) else: yield Timer(halfT) if scan_en is not None: if Config.running_cocotb and read_func(scan_en) == '1': print('ERROR: scan enable is high, another chain might be using the scan ports') return None else: write_signal(scan_en, 1) outstr = '' for i, v in enumerate(val): if scan_out is not None: outstr = outstr + read_func(scan_out) if (verbosity == 1 and i%100 == 0) or (verbosity == 2 and i%10 == 0) or (verbosity > 2): print(f"Scanning bit {i} out of {len(val)-1}...") write_signal(scan_in, int(v, 2)) if Config.running_cocotb: yield cycle(scan_clk, T, clk_running) else: cycle(scan_clk, T, clk_running) if fromMSB: outstr = outstr[::-1] if scan_en is not None: write_signal(scan_en, 0) if scan_wen is not None: write_signal(scan_wen, 1) if Config.running_cocotb: yield cycle(scan_clk, T, clk_running) else: cycle(scan_clk, T, clk_running) write_signal(scan_wen, 0) if Config.inv_outs: outstr = inv(outstr) return outstr
def write(self, address, value, byte_enable=0xf, address_latency=0, data_latency=0, sync=True): """ Write a value to an address. Args: address (int): The address to write to value (int): The data value to write byte_enable (int, optional): Which bytes in value to actually write. Default is to write all bytes. address_latency (int, optional): Delay before setting the address (in clock cycles). Default is no delay. data_latency (int, optional): Delay before setting the data value (in clock cycles). Default is no delay. sync (bool, optional): Wait for rising edge on clock initially. Defaults to True. Returns: BinaryValue: The write response value Raises: AXIProtocolError: If write response from AXI is not ``OKAY`` """ if sync: yield RisingEdge(self.clock) c_addr = cocotb.fork( self._send_write_address(address, delay=address_latency)) c_data = cocotb.fork( self._send_write_data(value, byte_enable=byte_enable, delay=data_latency)) if c_addr: yield c_addr.join() if c_data: yield c_data.join() # Wait for the response while True: yield ReadOnly() if self.bus.BVALID.value and self.bus.BREADY.value: result = self.bus.BRESP.value self.log.debug("Writing to address 0x%08x with 0x%08x" % (address, value)) break yield RisingEdge(self.clock) yield RisingEdge(self.clock) if int(result): raise AXIProtocolError( "Write to address 0x%08x failed with BRESP: %d" % (address, int(result))) raise ReturnValue(result)
def read_reg(dut, addr): dut.addr_i <= addr yield RisingEdge(dut.clk_i) raise ReturnValue(dut.data_o.value)
def test(dut): print "------------------------------------------- ONE -------------------------------------------" si_rx = SI_Master(dut.clk, dut.rst, dut.rx_data, dut.rx_rdy, dut.rx_ack) reg_10 = REG_SI_Slave(dut.clk, dut.rst, dut.register_addr, dut.register_data, dut.register_rdy, 10) reg_13 = REG_SI_Slave(dut.clk, dut.rst, dut.register_addr, dut.register_data, dut.register_rdy, 13) reg_200 = REG_SI_Slave(dut.clk, dut.rst, dut.register_addr, dut.register_data, dut.register_rdy, 200) reg_mon = REG_SI_MON(dut.clk, dut.rst, dut.register_addr, dut.register_data, dut.register_rdy) print "------------------------------------------- TWO -------------------------------------------" cocotb.fork(Clock(dut.clk, 10, units='ns').start()) print "------------------------------------------- THREE -------------------------------------------" yield Reset(dut) print "------------------------------------------- FOUR -------------------------------------------" print "I'm writing the fifo" si_rx.write(13) si_rx.write(0xFF) si_rx.write(0xEE) si_rx.write(10) si_rx.write(0xDD) si_rx.write(0xCC) si_rx.write(200) si_rx.write(0xBB) si_rx.write(0xAA) si_rx.write(9) si_rx.write(0x99) si_rx.write(0x88) # requests_handler (addr=0x00) si_rx.write(0) si_rx.write(0x01) si_rx.write(0x00) cocotb.fork(si_rx.driver()) cocotb.fork(reg_10.monitor()) cocotb.fork(reg_13.monitor()) cocotb.fork(reg_200.monitor()) cocotb.fork(reg_mon.bus_monitor()) print "I'm starting to send the data" for i in range(100): yield RisingEdge(dut.clk) # requests_handler (addr=12) si_rx.write(12) si_rx.write(0x02) si_rx.write(0x00) for i in range(10): yield RisingEdge(dut.clk) si_rx.write(12) si_rx.write(0x04) si_rx.write(0x00) for i in range(10): yield RisingEdge(dut.clk) si_rx.write(12) si_rx.write(0x08) si_rx.write(0x00) for i in range(10): yield RisingEdge(dut.clk) si_rx.write(12) si_rx.write(0xFF) si_rx.write(0xFF) for i in range(10): yield RisingEdge(dut.clk) print "Reg_10: " + repr(reg_10.fifo) print "Reg_13: " + repr(reg_13.fifo) print "Reg_200: " + repr(reg_200.fifo) print "Data: " + repr(reg_mon.fifo_addr) print "Addr: " + repr(reg_mon.fifo_data) print "I'm at the end"
def cycleCounterAgent(dut, counter): while True: yield RisingEdge(dut.clk) counter[0] += 1
def test_controlLoop(dut): # Set up the clock fs = 2e6 # Hz # Generate the test waveforms sineFrq = 50e3 # Hz The frequency of the excitation wave cycles = 3 # The number of waves to use # timebase = np.arange(0, (cycles * (1 / sineFrq)), (1 / fs)) # Stimulus = (2 ** 17) * (np.sin(2 * np.pi * sineFrq * timebase)) # START Test dut.controlInput_i.value = 0 dut.kp_i = 24 dut.ki_i = 26 # Create a clock from which we start everything c = Clock(dut.clock_i, 500, "ns") cocotb.fork(c.start()) clkedge = RisingEdge(dut.clock_i) timebase = [] stimulus = [] inputSignal = [] controllerError = [] feedback = [] plantOut = [] Output = [] controllerError.append(0) feedback.append(0) plantOut.append(0) controllerError.append(0) feedback.append(0) plantOut.append(0) # open file and read the content in a list with open("timebase.txt", "r") as filehandle: for line in filehandle: # remove linebreak which is the last character of the string currentPlace = line[:-1] # add item to the list timebase.append(currentPlace) with open("input.txt", "r") as filehandle: for line in filehandle: # remove linebreak which is the last character of the string currentPlace = line[:-1] # add item to the list stimulus.append(currentPlace) yield clkedge yield clkedge for i in range(1, len(timebase)): yield clkedge inputSignal.append(stimulus[i]) controllerError.append(float(stimulus[i]) - float(feedback[i - 1])) # The plant is a sine wave plantOut.append(math.sin(controllerError[i]) * (2**17)) dut.controlInput_i.value = int(plantOut[i]) Output.append(dut.feedback_o.value.signed_integer) feedback.append((dut.feedback_o.value.signed_integer) / (2**17)) controllerErrorList = list(controllerError) feedbackList = list(feedback) plantOutList = list(plantOut) with open("controllerError.txt", "w") as filehandle: for listitem in controllerErrorList: filehandle.write("%s\n" % listitem) with open("feedback.txt", "w") as filehandle: for listitem in feedbackList: filehandle.write("%s\n" % listitem) with open("plantOut.txt", "w") as filehandle: for listitem in plantOutList: filehandle.write("%s\n" % listitem)
def n_cycles_clock(dut, n): for i in range(0, n): yield RisingEdge(dut.clk) yield FallingEdge(dut.clk)
def drive_high(self): yield RisingEdge(self.clock) self.bus.SCL <= 1 self.bus.SDA <= 1
def read(self, address, sync=True): """Issue a request to the bus and block until this comes back. Simulation time still progresses but syntactically it blocks. Args: address (int): The address to read from. sync (bool, optional): Wait for rising edge on clock initially. Defaults to True. Returns: BinaryValue: The read data value. Raises: :any:`TestError`: If master is write-only. """ if not self._can_read: self.log.error("Cannot read - have no read signal") raise TestError("Attempt to read on a write-only AvalonMaster") yield self._acquire_lock() # Apply values for next clock edge if sync: yield RisingEdge(self.clock) self.bus.address <= address self.bus.read <= 1 if hasattr(self.bus, "byteenable"): self.bus.byteenable <= int("1" * len(self.bus.byteenable), 2) if hasattr(self.bus, "cs"): self.bus.cs <= 1 # Wait for waitrequest to be low if hasattr(self.bus, "waitrequest"): yield self._wait_for_nsignal(self.bus.waitrequest) yield RisingEdge(self.clock) # Deassert read self.bus.read <= 0 if hasattr(self.bus, "byteenable"): self.bus.byteenable <= 0 if hasattr(self.bus, "cs"): self.bus.cs <= 0 v = self.bus.address.value v.binstr = "x" * len(self.bus.address) self.bus.address <= v if hasattr(self.bus, "readdatavalid"): while True: yield ReadOnly() if int(self.bus.readdatavalid): break yield RisingEdge(self.clock) else: # Assume readLatency = 1 if no readdatavalid # FIXME need to configure this, # should take a dictionary of Avalon properties. yield ReadOnly() # Get the data data = self.bus.readdata.value self._release_lock() return data
async def await_all_clocks(self): trigs = [] for clk in self.multiclock.clocks: trigs.append(RisingEdge(clk.clk)) await Combine(*trigs)
def _respond(self): """ Coroutine to response to the actual requests """ edge = RisingEdge(self.clock) while True: yield edge self._do_response() yield ReadOnly() if self._readable and self.bus.read.value: if not self._burstread: self._pad() addr = self.bus.address.value.integer if addr not in self._mem: self.log.warning("Attempt to read from uninitialised " "address 0x%x" % addr) self._responses.append(True) else: self.log.debug( "Read from address 0x%x returning 0x%x" % (addr, self._mem[addr])) self._responses.append(self._mem[addr]) else: addr = self.bus.address.value.integer if addr % self.dataByteSize != 0: self.log.error( "Address must be aligned to data width" + "(addr = " + hex(addr) + ", width = " + str(self._width)) addr = addr / self.dataByteSize burstcount = self.bus.burstcount.value.integer byteenable = self.bus.byteenable.value if byteenable != int("1" * len(self.bus.byteenable), 2): self.log.error("Only full word access is supported " + "for burst read (byteenable must be " + "0b" + "1" * len(self.bus.byteenable) + ")") if burstcount == 0: self.log.error("Burstcount must be 1 at least") # toggle waitrequest # TODO: configure waitrequest time with avalon properties yield NextTimeStep() # can't write during read-only phase self.bus.waitrequest <= 1 yield edge yield edge self.bus.waitrequest <= 0 # wait for read data for i in range(self._avalon_properties["readLatency"]): yield edge for count in range(burstcount): if (addr + count) * self.dataByteSize not in self._mem: self.log.warning( "Attempt to burst read from uninitialised " + "address 0x%x (addr 0x%x count 0x%x)" % ((addr + count) * self.dataByteSize, addr, count)) self._responses.append(True) else: value = 0 for i in range(self.dataByteSize): rvalue = self._mem[(addr + count) * self.dataByteSize + i] value += rvalue << i * 8 self.log.debug( "Read from address 0x%x returning 0x%x" % ((addr + count) * self.dataByteSize, value)) self._responses.append(value) yield edge self._do_response() if self._writeable and self.bus.write.value: if not self._burstwrite: addr = self.bus.address.value.integer data = self.bus.writedata.value.integer if hasattr(self.bus, "byteenable"): byteenable = int(self.bus.byteenable.value) mask = 0 oldmask = 0 olddata = 0 if (addr in self._mem): olddata = self._mem[addr] self.log.debug("Old Data : %x" % olddata) self.log.debug("Data in : %x" % data) self.log.debug("Width : %d" % self._width) self.log.debug("Byteenable: %x" % byteenable) for i in xrange(self._width / 8): if (byteenable & 2**i): mask |= 0xFF << (8 * i) else: oldmask |= 0xFF << (8 * i) self.log.debug("Data mask : %x" % mask) self.log.debug("Old mask : %x" % oldmask) data = (data & mask) | (olddata & oldmask) self.log.debug("Data out : %x" % data) self.log.debug("Write to address 0x%x -> 0x%x" % (addr, data)) self._mem[addr] = data else: self.log.debug("writing burst") # maintain waitrequest high randomly yield self._waitrequest() addr, byteenable, burstcount = self._write_burst_addr() count = 0 for count in range(burstcount): while self.bus.write.value == 0: yield NextTimeStep() # self._mem is aligned on 8 bits words yield self._writing_byte_value(addr + count * self.dataByteSize) self.log.debug("writing %016X @ %08X" % (self.bus.writedata.value.integer, addr + count * self.dataByteSize)) yield edge # generate waitrequest randomly yield self._waitrequest() if self._avalon_properties.get("WriteBurstWaitReq", True): self.bus.waitrequest <= 1
def assertions(dut): for i in range(2500000): yield RisingEdge(dut.uut.io_vgaClk)
def _monitor_recv(self): clk = RisingEdge(self.clock) self._pkt = bytearray() while True: yield clk ctrl, bytes = self._get_bytes() if ctrl[0] and bytes[0] == _XGMII_START: ctrl, bytes = ctrl[1:], bytes[1:] while self._add_payload(ctrl, bytes): yield clk ctrl, bytes = self._get_bytes() elif self.bytes == 8: if ctrl[4] and bytes[4] == _XGMII_START: ctrl, bytes = ctrl[5:], bytes[5:] while self._add_payload(ctrl, bytes): yield clk ctrl, bytes = self._get_bytes() if self._pkt: self.log.debug("Received:\n%s" % (hexdump(self._pkt))) if len(self._pkt) < 64 + 7: self.log.error("Received a runt frame!") if len(self._pkt) < 12: self.log.error("No data to extract") self._pkt = bytearray() continue preamble_sfd = self._pkt[0:7] crc32 = self._pkt[-4:] payload = self._pkt[7:-4] if preamble_sfd != _PREAMBLE_SFD: self.log.error("Got a frame with unknown preamble/SFD") self.log.error(hexdump(preamble_sfd)) self._pkt = bytearray() continue expected_crc = struct.pack("<I", (zlib.crc32(payload) & 0xFFFFFFFF)) if crc32 != expected_crc: self.log.error("Incorrect CRC on received packet") self.log.info("Expected: %s" % (hexdump(expected_crc))) self.log.info("Received: %s" % (hexdump(crc32))) # Use scapy to decode the packet if _have_scapy: p = Ether(payload) self.log.debug("Received decoded packet:\n%s" % p.show2()) else: p = payload self._recv(p) self._pkt = bytearray()
def rx_data_to_ad9361(self, i_data, q_data, i_data2=None, q_data2=None, binaryRepresentation=BinaryRepresentation.TWOS_COMPLEMENT): """Receive data to AD9361. This is a coroutine. Args: i_data (int): Data of the I0 channel. q_data (int): Data of the Q0 channel. i_data2 (int, optional): Data of the I1 channel. q_data2 (int, optional): Data of the Q1 channel. binaryRepresentation (BinaryRepresentation): The representation of the binary value. Default is :any:`TWOS_COMPLEMENT`. """ i_bin_val = BinaryValue(n_bits=12, bigEndian=False, binaryRepresentation=binaryRepresentation) q_bin_val = BinaryValue(n_bits=12, bigEndian=False, binaryRepresentation=binaryRepresentation) index = 0 if i_data2 is None and q_data2 is None: while True: yield RisingEdge(self.dut.rx_clk_in_p) if self.rx_frame_asserted: self.dut.rx_data_in_p <= i_bin_val[5:0] self.dut.rx_data_in_n <= ~i_bin_val[5:0] self.rx_frame_asserted = False self.dut.rx_frame_in_p <= 0 self.dut.rx_frame_in_n <= 1 else: if index < len(i_data): i_bin_val.set_value(i_data[index]) q_bin_val.set_value(q_data[index]) index += 1 else: return self.dut.rx_data_in_p <= i_bin_val[11:6] self.dut.rx_data_in_n <= ~i_bin_val[11:6] self.rx_frame_asserted = True self.dut.rx_frame_in_p <= 1 self.dut.rx_frame_in_n <= 0 yield RisingEdge(self.dut.rx_clk_in_n) if self.rx_frame_asserted: self.dut.rx_data_in_p <= q_bin_val[11:6] self.dut.rx_data_in_n <= ~q_bin_val[11:6] else: self.dut.rx_data_in_p <= q_bin_val[5:0] self.dut.rx_data_in_n <= ~q_bin_val[5:0] else: I_SEND_HIGH = True Q_SEND_HIGH = True channel = 1 while True: yield RisingEdge(self.dut.rx_clk_in_p) if I_SEND_HIGH: self.dut.rx_data_in_p <= i_bin_val[11:6] self.dut.rx_data_in_n <= ~i_bin_val[11:6] I_SEND_HIGH = False if channel == 1: self.dut.rx_frame_in_p <= 1 self.dut.rx_frame_in_n <= 0 elif channel == 2: self.dut.rx_frame_in_p <= 0 self.dut.rx_frame_in_n <= 1 else: self.dut.rx_data_in_p <= i_bin_val[5:0] self.dut.rx_data_in_n <= ~i_bin_val[5:0] I_SEND_HIGH = True yield RisingEdge(self.dut.rx_clk_in_n) if Q_SEND_HIGH: self.dut.rx_data_in_p <= q_bin_val[5:0] self.dut.rx_data_in_n <= ~q_bin_val[5:0] Q_SEND_HIGH = False else: self.dut.rx_data_in_p <= q_bin_val[11:6] self.dut.rx_data_in_n <= ~q_bin_val[11:6] Q_SEND_HIGH = True if index < len(i_data): if channel == 1: i_bin_val.set_value(i_data[index]) q_bin_val.set_value(q_data[index]) channel = 2 elif channel == 2: i_bin_val.set_value(i_data2[index]) q_bin_val.set_value(q_data2[index]) channel = 1 index += 1 else: return
def init_test(dut): dut.rst <= 1 cocotb.fork(Clock(dut.clk, 10, 'ns').start()) yield RisingEdge(dut.clk) dut.rst <= 0 yield RisingEdge(dut.clk)
def __init__(self, itf: BaseSynchronousInterface, *args, **kwargs) -> None: self.re = RisingEdge(itf.clock) self.ro = ReadOnly() super().__init__(itf, *args, **kwargs)
def clock_one(dut): count = 0 while count is not 50: yield RisingEdge(dut.clk) yield Timer(1000) count += 1
def wait_cycles(dut, n): for _ in range(n): yield RisingEdge(dut.clk)
def clock_two(dut): count = 0 while count != 50: yield RisingEdge(dut.clk) yield Timer(10000) count += 1
def pkt_switch_test(dut): """ PKT_SWITCH Test """ log = cocotb.logging.getLogger("cocotb.test") # logger instance cocotb.fork(clock_gen(dut.clk, period=100)) # start clock running # reset & init dut.rst_n <= 1 dut.datain_data <= 0 dut.datain_valid <= 0 dut.ctrl_addr <= 0 dut.ctrl_data <= 0 dut.ctrl_wr <= 0 yield Timer(1000) dut.rst_n <= 0 yield Timer(1000) dut.rst_n <= 1 # procedure of writing configuration registers @cocotb.coroutine def write_config(addr, data): for [a, d] in zip(addr, data): dut.ctrl_addr <= a dut.ctrl_data <= d dut.ctrl_wr <= 1 yield RisingEdge(dut.clk) dut.ctrl_wr <= 0 enable_transmit_both = lambda: write_config([0], [4]) disable_filtering = lambda: write_config([0], [0]) @cocotb.coroutine def enable_addr_filtering(addr, mask): yield write_config([0, 2, 3], [1, addr, mask]) @cocotb.coroutine def enable_len_filtering(low_limit, up_limit): yield write_config([0, 4, 5], [2, low_limit, up_limit]) driver = PacketIFDriver(dut, name="datain", clock=dut.clk) monitor0 = PacketIFMonitor(dut, name="dataout0", clock=dut.clk) monitor1 = PacketIFMonitor(dut, name="dataout1", clock=dut.clk) expected_data0 = [] # queue of expeced packet at interface 0 expected_data1 = [] # queue of expeced packet at interface 1 def scoreboarding(pkt, queue_expected): assert pkt.addr == queue_expected[0].addr assert pkt.len == queue_expected[0].len assert pkt.payload == queue_expected[0].payload queue_expected.pop() monitor0.add_callback(lambda _ : scoreboarding(_, expected_data0)) monitor1.add_callback(lambda _ : scoreboarding(_, expected_data1)) monitor0.add_callback(lambda _ : log.info("Receiving packet on interface 0 (packet not filtered)")) monitor1.add_callback(lambda _ : log.info("Receiving packet on interface 1 (packet filtered)")) # functional coverage - check received packet @CoverPoint( "top.packet_length", xf = lambda pkt, event, addr, mask, ll, ul: pkt.len, # packet length bins = list(range(3,32)) # may be 3 ... 31 bytes ) @CoverPoint("top.event", vname="event", bins = ["DIS", "TB", "AF", "LF"]) @CoverPoint( "top.filt_addr", xf = lambda pkt, event, addr, mask, ll, ul: # filtering based on particular bits in header (addr & mask & 0x0F) if event == "AF" else None, # check only if event is "address filtering" bins = list(range(16)), # check only 4 LSBs if all options tested ) @CoverPoint( "top.filt_len_eq", xf = lambda pkt, event, addr, mask, ll, ul: ll == ul, # filtering of a single packet length bins = [True, False] ) @CoverPoint( "top.filt_len_ll", vname = "ll", # lower limit of packet length bins = list(range(3,32)) # 3 ... 31 ) @CoverPoint( "top.filt_len_ul", vname = "ul", # upper limit of packet length bins = list(range(3,32)) # 3 ... 31 ) @CoverCross( "top.filt_len_ll_x_packet_length", items = ["top.packet_length", "top.filt_len_ll"] ) @CoverCross( "top.filt_len_ul_x_packet_length", items = ["top.packet_length", "top.filt_len_ul"] ) def log_sequence(pkt, event, addr, mask, ll, ul): log.info("Processing packet:") log.info(" ADDRESS: %X", pkt.addr) log.info(" LENGTH: %d", pkt.len) log.info(" PAYLOAD: " + str(pkt.payload)) if event is "DIS": log.info("Filtering disabled") elif event is "TB": log.info("Transmit on both interfaces") elif event is "AF": log.info("Address filtering, address: %02X, mask: %02X", addr, mask) elif event is "LF": log.info("Length filtering, lower limit: %d, upper limit: %d", ll, ul) # main loop for _ in range(1000): # is that enough repetitions to ensure coverage goal? Check out! event = np.random.choice(["DIS", "TB", "AF", "LF"]) # DIS - disable filtering : expect all packets on interface 0 # TB - transmit bot : expect all packets on interface 0 and 1 # AF - address filtering : expect filtered packets on interface 1, others on 0 # LF - length filtering : expect filtered packets on interface 1, others on 0 # randomize test data pkt = Packet(); pkt.randomize() addr = np.random.randint(256) # 0x00 .. 0xFF mask = np.random.randint(256) # 0x00 .. 0xFF low_limit = np.random.randint(3,32) # 3 ... 31 up_limit = np.random.randint(low_limit,32) # low_limit ... 31 # expect the packet on the particular interface if event == "DIS": yield disable_filtering() expected_data0.append(pkt) elif event == "TB": yield enable_transmit_both() expected_data0.append(pkt) expected_data1.append(pkt) elif event == "AF": yield enable_addr_filtering(addr, mask) if ((pkt.addr & mask) == (addr & mask)): expected_data1.append(pkt) else: expected_data0.append(pkt) elif event == "LF": yield enable_len_filtering(low_limit, up_limit) if (low_limit <= pkt.len <= up_limit): expected_data1.append(pkt) else: expected_data0.append(pkt) # wait DUT yield driver.send(pkt) yield RisingEdge(dut.clk) yield RisingEdge(dut.clk) # LOG the action log_sequence(pkt, event, addr, mask, low_limit, up_limit) # print coverage report coverage_db.report_coverage(log.info, bins=False) # export coverage_db.export_to_xml(filename="coverage_pkt_switch.xml") coverage_db.export_to_yaml(filename="coverage_pkt_switch.yml")
def wait_for_signals(self, entity, signals=[]): yield ReadOnly() while (any(entity.sig.value.integer != 1 for sign in signals)): yield [RisingEdge(entity.sig.value) for sign in signals] yield ReadOnly() yield NextTimeStep()
def flush_pipeline(self): for _ in range(self.pipeline_latency): yield RisingEdge(self.dut.pixel_clk)