async def run_test(dut): tb = TB(dut) await tb.init() tb.log.info("send test packet") payload = bytes([x % 256 for x in range(256)]) eth = Ether(src='5a:51:52:53:54:55', dst='02:00:00:00:00:00', type=0x8000) test_pkt = eth / payload test_frame = XgmiiFrame.from_payload(test_pkt.build()) await tb.eth_l0_source.send(test_frame) rx_frame = await tb.eth_l0_sink.recv() rx_pkt = Ether(bytes(rx_frame.get_payload())) tb.log.info("RX packet: %s", repr(rx_pkt)) assert rx_pkt == test_pkt tb.log.info("update configuration") payload = bytes(range(15, -1, -1)) eth = Ether(src='5a:51:52:53:54:55', dst='02:00:00:00:00:00', type=0x8099) test_pkt = eth / payload test_frame = XgmiiFrame.from_payload(test_pkt.build()) await tb.eth_l11_source.send(test_frame) await Timer(400, 'ns') tb.log.info("send test packet") payload = bytes([x % 256 for x in range(256)]) eth = Ether(src='5a:51:52:53:54:55', dst='02:00:00:00:00:00', type=0x8000) test_pkt = eth / payload test_frame = XgmiiFrame.from_payload(test_pkt.build()) await tb.eth_l0_source.send(test_frame) rx_frame = await tb.eth_r7_sink.recv() rx_pkt = Ether(bytes(rx_frame.get_payload())) tb.log.info("RX packet: %s", repr(rx_pkt)) assert rx_pkt == test_pkt await RisingEdge(dut.clk) await RisingEdge(dut.clk)
async def run_test_rx(dut, payload_lengths=None, payload_data=None, ifg=12): tb = TB(dut) tb.xgmii_source.ifg = ifg tb.serdes_source.ifg = ifg await tb.reset() tb.log.info("Wait for block lock") while not dut.rx_block_lock.value.integer: await RisingEdge(dut.rx_clk) # clear out sink buffer tb.xgmii_sink.clear() test_frames = [payload_data(x) for x in payload_lengths()] for test_data in test_frames: test_frame = XgmiiFrame.from_payload(test_data) await tb.serdes_source.send(test_frame) for test_data in test_frames: rx_frame = await tb.xgmii_sink.recv() assert rx_frame.get_payload() == test_data assert rx_frame.check_fcs() assert tb.xgmii_sink.empty() await RisingEdge(dut.rx_clk) await RisingEdge(dut.rx_clk)
async def run_test_tx(dut, payload_lengths=None, payload_data=None, ifg=12): tb = TB(dut) tb.xgmii_source.ifg = ifg tb.serdes_source.ifg = ifg await tb.reset() test_frames = [payload_data(x) for x in payload_lengths()] for test_data in test_frames: test_frame = XgmiiFrame.from_payload(test_data) await tb.xgmii_source.send(test_frame) for test_data in test_frames: rx_frame = await tb.serdes_sink.recv() assert rx_frame.get_payload() == test_data assert rx_frame.check_fcs() assert tb.serdes_sink.empty() await RisingEdge(dut.tx_clk) await RisingEdge(dut.tx_clk)
async def run_test_rx(dut, payload_lengths=None, payload_data=None, ifg=12): tb = TB(dut) tb.xgmii_source.ifg = ifg tb.dut.ifg_delay <= ifg await tb.reset() test_frames = [payload_data(x) for x in payload_lengths()] for test_data in test_frames: test_frame = XgmiiFrame.from_payload(test_data) await tb.xgmii_source.send(test_frame) for test_data in test_frames: rx_frame = await tb.axis_sink.recv() assert rx_frame.tdata == test_data assert rx_frame.tuser == 0 assert tb.axis_sink.empty() await RisingEdge(dut.rx_clk) await RisingEdge(dut.rx_clk)
async def run_test(dut, payload_lengths=None, payload_data=None, ifg=12, enable_dic=True, force_offset_start=False): tb = TB(dut) tb.source.ifg = ifg tb.source.enable_dic = enable_dic tb.source.force_offset_start = force_offset_start await tb.reset() test_frames = [payload_data(x) for x in payload_lengths()] for test_data in test_frames: test_frame = XgmiiFrame.from_payload(test_data) await tb.source.send(test_frame) for test_data in test_frames: rx_frame = await tb.sink.recv() assert rx_frame.get_payload() == test_data assert rx_frame.check_fcs() assert tb.sink.empty() await RisingEdge(dut.clk) await RisingEdge(dut.clk)
def send_nowait(self, frame): if self.full(): raise QueueFull() frame = XgmiiFrame(frame) self.queue.put_nowait(frame) self.idle_event.clear() self.queue_occupancy_bytes += len(frame) self.queue_occupancy_frames += 1
async def send(self, frame): while self.full(): self.dequeue_event.clear() await self.dequeue_event.wait() frame = XgmiiFrame(frame) await self.queue.put(frame) self.idle_event.clear() self.queue_occupancy_bytes += len(frame) self.queue_occupancy_frames += 1
async def run_test_rx(dut, payload_lengths=None, payload_data=None, ifg=12): tb = TB(dut) tb.serdes_source.ifg = ifg tb.dut.ifg_delay.value = ifg await tb.reset() tb.log.info("Wait for block lock") while not dut.rx_block_lock.value.integer: await RisingEdge(dut.rx_clk) tb.log.info("Wait for PTP CDC lock") while not dut.tx_ptp.tx_ptp_cdc.locked.value.integer: await RisingEdge(dut.tx_clk) # clear out sink buffer tb.axis_sink.clear() test_frames = [payload_data(x) for x in payload_lengths()] tx_frames = [] for test_data in test_frames: test_frame = XgmiiFrame.from_payload(test_data, tx_complete=tx_frames.append) await tb.serdes_source.send(test_frame) for test_data in test_frames: rx_frame = await tb.axis_sink.recv() tx_frame = tx_frames.pop(0) frame_error = rx_frame.tuser & 1 ptp_ts = rx_frame.tuser >> 1 ptp_ts_ns = ptp_ts / 2**16 tx_frame_sfd_ns = get_time_from_sim_steps(tx_frame.sim_time_sfd, "ns") if tx_frame.start_lane == 4: # start in lane 4 reports 1 full cycle delay, so subtract half clock period tx_frame_sfd_ns -= tb.clk_period / 2 tb.log.info("RX frame PTP TS: %f ns", ptp_ts_ns) tb.log.info("TX frame SFD sim time: %f ns", tx_frame_sfd_ns) assert rx_frame.tdata == test_data assert frame_error == 0 assert abs(ptp_ts_ns - tx_frame_sfd_ns - tb.clk_period * 4) < tb.clk_period assert tb.axis_sink.empty() await RisingEdge(dut.logic_clk) await RisingEdge(dut.logic_clk)
async def run_test(dut, payload_lengths=None, payload_data=None, ifg=12): tb = TB(dut) tb.source.ifg = ifg await tb.reset() test_frames = [payload_data(x) for x in payload_lengths()] tx_frames = [] for test_data in test_frames: test_frame = XgmiiFrame.from_payload(test_data, tx_complete=tx_frames.append) await tb.source.send(test_frame) for test_data in test_frames: rx_frame = await tb.sink.recv() tx_frame = tx_frames.pop(0) frame_error = rx_frame.tuser & 1 ptp_ts = rx_frame.tuser >> 1 ptp_ts_ns = ptp_ts / 2**16 tx_frame_sfd_ns = get_time_from_sim_steps(tx_frame.sim_time_sfd, "ns") if tx_frame.start_lane == 4: # start in lane 4 reports 1 full cycle delay, so subtract half clock period tx_frame_sfd_ns -= 3.2 tb.log.info("RX frame PTP TS: %f ns", ptp_ts_ns) tb.log.info("TX frame SFD sim time: %f ns", tx_frame_sfd_ns) assert rx_frame.tdata == test_data assert frame_error == 0 assert abs(ptp_ts_ns - tx_frame_sfd_ns - 6.4) < 0.01 assert tb.sink.empty() await RisingEdge(dut.clk) await RisingEdge(dut.clk)
async def run_test_alignment(dut, payload_data=None, ifg=12, enable_dic=True, force_offset_start=False, enable_gen=False): tb = TB(dut) byte_width = tb.source.width // 8 tb.source.ifg = ifg tb.source.enable_dic = enable_dic tb.source.force_offset_start = force_offset_start if enable_gen is not None: tb.set_enable_generator(enable_gen()) for length in range(60, 92): await tb.reset() test_frames = [payload_data(length) for k in range(10)] start_lane = [] for test_data in test_frames: test_frame = XgmiiFrame.from_payload(test_data) await tb.source.send(test_frame) for test_data in test_frames: rx_frame = await tb.sink.recv() assert rx_frame.get_payload() == test_data assert rx_frame.check_fcs() assert rx_frame.ctrl is None start_lane.append(rx_frame.start_lane) tb.log.info("length: %d", length) tb.log.info("start_lane: %s", start_lane) start_lane_ref = [] # compute expected starting lanes lane = 0 deficit_idle_count = 0 for test_data in test_frames: if ifg == 0: lane = 0 if force_offset_start and byte_width > 4: lane = 4 start_lane_ref.append(lane) lane = (lane + len(test_data) + 4 + ifg) % byte_width if enable_dic: offset = lane % 4 if deficit_idle_count + offset >= 4: offset += 4 lane = (lane - offset) % byte_width deficit_idle_count = (deficit_idle_count + offset) % 4 else: offset = lane % 4 if offset > 0: offset += 4 lane = (lane - offset) % byte_width tb.log.info("start_lane_ref: %s", start_lane_ref) assert start_lane_ref == start_lane await RisingEdge(dut.clk) assert tb.sink.empty() await RisingEdge(dut.clk) await RisingEdge(dut.clk)
async def run_test(dut): tb = TB(dut) await tb.init() tb.log.info("test UDP RX packet") payload = bytes([x % 256 for x in range(256)]) eth = Ether(src='5a:51:52:53:54:55', dst='02:00:00:00:00:00') ip = IP(src='192.168.1.100', dst='192.168.1.128') udp = UDP(sport=5678, dport=1234) test_pkt = eth / ip / udp / payload test_frame = XgmiiFrame.from_payload(test_pkt.build()) await tb.qsfp_1_source.send(test_frame) tb.log.info("receive ARP request") rx_frame = await tb.qsfp_1_sink.recv() rx_pkt = Ether(bytes(rx_frame.get_payload())) tb.log.info("RX packet: %s", repr(rx_pkt)) assert rx_pkt.dst == 'ff:ff:ff:ff:ff:ff' assert rx_pkt.src == test_pkt.dst assert rx_pkt[ARP].hwtype == 1 assert rx_pkt[ARP].ptype == 0x0800 assert rx_pkt[ARP].hwlen == 6 assert rx_pkt[ARP].plen == 4 assert rx_pkt[ARP].op == 1 assert rx_pkt[ARP].hwsrc == test_pkt.dst assert rx_pkt[ARP].psrc == test_pkt[IP].dst assert rx_pkt[ARP].hwdst == '00:00:00:00:00:00' assert rx_pkt[ARP].pdst == test_pkt[IP].src tb.log.info("send ARP response") eth = Ether(src=test_pkt.src, dst=test_pkt.dst) arp = ARP(hwtype=1, ptype=0x0800, hwlen=6, plen=4, op=2, hwsrc=test_pkt.src, psrc=test_pkt[IP].src, hwdst=test_pkt.dst, pdst=test_pkt[IP].dst) resp_pkt = eth / arp resp_frame = XgmiiFrame.from_payload(resp_pkt.build()) await tb.qsfp_1_source.send(resp_frame) tb.log.info("receive UDP packet") rx_frame = await tb.qsfp_1_sink.recv() rx_pkt = Ether(bytes(rx_frame.get_payload())) tb.log.info("RX packet: %s", repr(rx_pkt)) assert rx_pkt.dst == test_pkt.src assert rx_pkt.src == test_pkt.dst assert rx_pkt[IP].dst == test_pkt[IP].src assert rx_pkt[IP].src == test_pkt[IP].dst assert rx_pkt[UDP].dport == test_pkt[UDP].sport assert rx_pkt[UDP].sport == test_pkt[UDP].dport assert rx_pkt[UDP].payload == test_pkt[UDP].payload tb.log.info("test gigabit tap, RX side") # insert tap await RisingEdge(dut.clk) dut.sw <= 0x8 await RisingEdge(dut.clk) payload = bytes([x % 256 for x in range(256)]) eth = Ether(src='5a:51:52:53:54:55', dst='02:00:00:00:00:00') ip = IP(src='192.168.1.100', dst='192.168.1.128') udp = UDP(sport=5678, dport=1234) test_pkt = eth / ip / udp / payload test_frame = GmiiFrame.from_payload(test_pkt.build()) await tb.gmii_source.send(test_frame) tb.log.info("loop back packet on XGMII interface") rx_frame = await tb.qsfp_1_sink.recv() rx_pkt = Ether(bytes(rx_frame.get_payload())) tb.log.info("RX packet: %s", repr(rx_pkt)) await tb.qsfp_1_source.send(rx_frame) tb.log.info("receive UDP packet") rx_frame = await tb.gmii_sink.recv() rx_pkt = Ether(bytes(rx_frame.get_payload())) tb.log.info("RX packet: %s", repr(rx_pkt)) assert rx_pkt.dst == test_pkt.src assert rx_pkt.src == test_pkt.dst assert rx_pkt[IP].dst == test_pkt[IP].src assert rx_pkt[IP].src == test_pkt[IP].dst assert rx_pkt[UDP].dport == test_pkt[UDP].sport assert rx_pkt[UDP].sport == test_pkt[UDP].dport assert rx_pkt[UDP].payload == test_pkt[UDP].payload tb.log.info("test gigabit tap, TX side") # insert tap await RisingEdge(dut.clk) dut.sw <= 0xC await RisingEdge(dut.clk) payload = bytes([x % 256 for x in range(256)]) eth = Ether(src='5a:51:52:53:54:55', dst='02:00:00:00:00:00') ip = IP(src='192.168.1.100', dst='192.168.1.128') udp = UDP(sport=5678, dport=1234) test_pkt = eth / ip / udp / payload test_frame = GmiiFrame.from_payload(test_pkt.build()) await tb.gmii_source.send(test_frame) tb.log.info("loop back packet on XGMII interface") rx_frame = await tb.qsfp_1_sink.recv() rx_pkt = Ether(bytes(rx_frame.get_payload())) tb.log.info("RX packet: %s", repr(rx_pkt)) await tb.qsfp_1_source.send(rx_frame) tb.log.info("receive UDP packet") rx_frame = await tb.gmii_sink.recv() rx_pkt = Ether(bytes(rx_frame.get_payload())) tb.log.info("RX packet: %s", repr(rx_pkt)) assert rx_pkt.dst == test_pkt.src assert rx_pkt.src == test_pkt.dst assert rx_pkt[IP].dst == test_pkt[IP].src assert rx_pkt[IP].src == test_pkt[IP].dst assert rx_pkt[UDP].dport == test_pkt[UDP].sport assert rx_pkt[UDP].sport == test_pkt[UDP].dport assert rx_pkt[UDP].payload == test_pkt[UDP].payload await RisingEdge(dut.clk) await RisingEdge(dut.clk)
async def _run(self): frame = None scrambler_state = 0 self.active = False while True: await RisingEdge(self.clock) if self.enable is None or self.enable.value: data = self.data.value.integer header = self.header.value.integer if self.reverse: # bit reverse data = sum(1 << (63 - i) for i in range(64) if (data >> i) & 1) header = sum(1 << (1 - i) for i in range(2) if (header >> i) & 1) if self.scramble: # 64b/66b descrambler b = 0 for i in range(len(self.data)): if bool(scrambler_state & (1 << 38)) ^ bool( scrambler_state & (1 << 57)) ^ bool(data & (1 << i)): b = b | (1 << i) scrambler_state = (scrambler_state & 0x1ffffffffffffff ) << 1 | bool(data & (1 << i)) data = b # 10GBASE-R decoding # remap control characters ctrl = bytearray( baser_ctrl_to_xgmii_mapping.get((data >> i * 7 + 8) & 0x7f, XgmiiCtrl.ERROR) for i in range(8)) data = data.to_bytes(8, 'little') dl = bytearray() cl = [] if header == BaseRSync.DATA: # data dl = data cl = [0] * 8 elif header == BaseRSync.CTRL: if data[0] == BaseRBlockType.CTRL: # C7 C6 C5 C4 C3 C2 C1 C0 BT dl = ctrl cl = [1] * 8 elif data[0] == BaseRBlockType.OS_4: # D7 D6 D5 O4 C3 C2 C1 C0 BT dl = ctrl[0:4] cl = [1] * 4 if (data[4] >> 4) & 0xf == BaseRO.SEQ_OS: dl.append(XgmiiCtrl.SEQ_OS) elif (data[4] >> 4) & 0xf == BaseRO.SIG_OS: dl.append(XgmiiCtrl.SIG_OS) else: dl.append(XgmiiCtrl.ERROR) cl.append(1) dl += data[5:] cl += [0] * 3 elif data[0] == BaseRBlockType.START_4: # D7 D6 D5 C3 C2 C1 C0 BT dl = ctrl[0:4] cl = [1] * 4 dl.append(XgmiiCtrl.START) cl.append(1) dl += data[5:] cl += [0] * 3 elif data[0] == BaseRBlockType.OS_START: # D7 D6 D5 O0 D3 D2 D1 BT if data[4] & 0xf == BaseRO.SEQ_OS: dl.append(XgmiiCtrl.SEQ_OS) elif data[4] & 0xf == BaseRO.SIG_OS: dl.append(XgmiiCtrl.SIG_OS) else: dl.append(XgmiiCtrl.ERROR) cl.append(1) dl += data[1:4] cl += [0] * 3 dl.append(XgmiiCtrl.START) cl.append(1) dl += data[5:] cl += [0] * 3 elif data[0] == BaseRBlockType.OS_04: # D7 D6 D5 O4 O0 D3 D2 D1 BT if data[4] & 0xf == BaseRO.SEQ_OS: dl.append(XgmiiCtrl.SEQ_OS) elif data[4] & 0xf == BaseRO.SIG_OS: dl.append(XgmiiCtrl.SIG_OS) else: dl.append(XgmiiCtrl.ERROR) cl.append(1) dl += data[1:4] cl += [0] * 3 if (data[4] >> 4) & 0xf == BaseRO.SEQ_OS: dl.append(XgmiiCtrl.SEQ_OS) elif (data[4] >> 4) & 0xf == BaseRO.SIG_OS: dl.append(XgmiiCtrl.SIG_OS) else: dl.append(XgmiiCtrl.ERROR) cl.append(1) dl += data[5:] cl += [0] * 3 elif data[0] == BaseRBlockType.START_0: # D7 D6 D5 D4 D3 D2 D1 BT dl.append(XgmiiCtrl.START) cl.append(1) dl += data[1:] cl += [0] * 7 elif data[0] == BaseRBlockType.OS_0: # C7 C6 C5 C4 O0 D3 D2 D1 BT if data[4] & 0xf == BaseRO.SEQ_OS: dl.append(XgmiiCtrl.SEQ_OS) elif data[4] & 0xf == BaseRO.SIG_OS: dl.append(XgmiiCtrl.SEQ_OS) else: dl.append(XgmiiCtrl.ERROR) cl.append(1) dl += data[1:4] cl += [0] * 3 dl += ctrl[4:] cl += [1] * 4 elif data[0] in { BaseRBlockType.TERM_0, BaseRBlockType.TERM_1, BaseRBlockType.TERM_2, BaseRBlockType.TERM_3, BaseRBlockType.TERM_4, BaseRBlockType.TERM_5, BaseRBlockType.TERM_6, BaseRBlockType.TERM_7 }: # C7 C6 C5 C4 C3 C2 C1 BT # C7 C6 C5 C4 C3 C2 D0 BT # C7 C6 C5 C4 C3 D1 D0 BT # C7 C6 C5 C4 D2 D1 D0 BT # C7 C6 C5 D3 D2 D1 D0 BT # C7 C6 D4 D3 D2 D1 D0 BT # C7 D5 D4 D3 D2 D1 D0 BT # D6 D5 D4 D3 D2 D1 D0 BT term_lane = block_type_term_lane_mapping[data[0]] dl += data[1:term_lane + 1] cl += [0] * term_lane dl.append(XgmiiCtrl.TERM) cl.append(1) dl += ctrl[term_lane + 1:] cl += [1] * (7 - term_lane) else: # invalid block type self.log.warning("Invalid block type") dl = [XgmiiCtrl.ERROR] * 8 cl = [1] * 8 else: # invalid sync header self.log.warning("Invalid sync header") dl = [XgmiiCtrl.ERROR] * 8 cl = [1] * 8 for offset in range(self.byte_lanes): d_val = dl[offset] c_val = cl[offset] if frame is None: if c_val and d_val == XgmiiCtrl.START: # start frame = XgmiiFrame(bytearray([EthPre.PRE]), [0]) frame.sim_time_start = get_sim_time() frame.start_lane = offset else: if c_val: # got a control character; terminate frame reception if d_val != XgmiiCtrl.TERM: # store control character if it's not a termination frame.data.append(d_val) frame.ctrl.append(c_val) 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 else: if frame.sim_time_sfd is None and d_val == EthPre.SFD: frame.sim_time_sfd = get_sim_time() frame.data.append(d_val) frame.ctrl.append(c_val)