From aa8f19bf3ba2e26639ce7ba7b0ca66040bd1c686 Mon Sep 17 00:00:00 2001 From: Alex Forencich Date: Tue, 27 May 2025 23:56:28 -0700 Subject: [PATCH] eth: Reorganize clock enable in BASE-R model Signed-off-by: Alex Forencich --- src/eth/tb/baser.py | 682 ++++++++++++++++++++++---------------------- 1 file changed, 344 insertions(+), 338 deletions(-) diff --git a/src/eth/tb/baser.py b/src/eth/tb/baser.py index 6a9460c..09e2090 100644 --- a/src/eth/tb/baser.py +++ b/src/eth/tb/baser.py @@ -137,216 +137,219 @@ class BaseRSerdesSource(): while True: await RisingEdge(self.clock) - if self.enable is None or self.enable.value: - if ifg_cnt + deficit_idle_cnt > self.byte_lanes-1 or (not self.enable_dic and ifg_cnt > 4): - # in IFG - ifg_cnt = ifg_cnt - self.byte_lanes - if ifg_cnt < 0: - if self.enable_dic: - deficit_idle_cnt = max(deficit_idle_cnt+ifg_cnt, 0) - ifg_cnt = 0 + # clock enable + if self.enable is not None and not self.enable.value: + continue - elif frame is None: - # idle - if 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() - 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) + if ifg_cnt + deficit_idle_cnt > self.byte_lanes-1 or (not self.enable_dic and ifg_cnt > 4): + # in IFG + ifg_cnt = ifg_cnt - self.byte_lanes + if ifg_cnt < 0: + if self.enable_dic: + deficit_idle_cnt = max(deficit_idle_cnt+ifg_cnt, 0) + ifg_cnt = 0 - # offset start - if self.enable_dic: - min_ifg = 3 - deficit_idle_cnt - else: - min_ifg = 0 + elif frame is None: + # idle + if 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() + 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) - if self.byte_lanes > 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 - frame_offset = 0 + # offset start + if self.enable_dic: + min_ifg = 3 - deficit_idle_cnt else: - # clear counters - deficit_idle_cnt = 0 - ifg_cnt = 0 + min_ifg = 0 - if frame is not None: - dl = bytearray() - cl = [] + if self.byte_lanes > 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 - for k in range(self.byte_lanes): - if frame is not None: - d = frame.data[frame_offset] - if frame.sim_time_sfd is None and d == EthPre.SFD: - frame.sim_time_sfd = get_sim_time() - dl.append(d) - cl.append(frame.ctrl[frame_offset]) - frame_offset += 1 + if self.enable_dic: + deficit_idle_cnt = max(deficit_idle_cnt+ifg_cnt, 0) + ifg_cnt = 0 + self.active = True + frame_offset = 0 + else: + # clear counters + deficit_idle_cnt = 0 + ifg_cnt = 0 - if frame_offset >= len(frame.data): - ifg_cnt = max(self.ifg - (self.byte_lanes-k), 0) - frame.sim_time_end = get_sim_time() - frame.handle_tx_complete() - frame = None - self.current_frame = None - else: - dl.append(XgmiiCtrl.IDLE) - cl.append(1) + if frame is not None: + dl = bytearray() + cl = [] - # remap control characters - ctrl = sum(xgmii_ctrl_to_baser_mapping.get(d, BaseRCtrl.ERROR) << i*7 for i, d in enumerate(dl)) + for k in range(self.byte_lanes): + if frame is not None: + d = frame.data[frame_offset] + if frame.sim_time_sfd is None and d == EthPre.SFD: + frame.sim_time_sfd = get_sim_time() + dl.append(d) + cl.append(frame.ctrl[frame_offset]) + frame_offset += 1 - if not any(cl): - # data - hdr = BaseRSync.DATA - data = int.from_bytes(dl, 'little') + if frame_offset >= len(frame.data): + ifg_cnt = max(self.ifg - (self.byte_lanes-k), 0) + frame.sim_time_end = get_sim_time() + frame.handle_tx_complete() + frame = None + self.current_frame = None else: - # control - hdr = BaseRSync.CTRL - if cl[0] and dl[0] == XgmiiCtrl.START and not any(cl[1:]): - # start in lane 0 - data = BaseRBlockType.START_0 - for i in range(1, 8): - data |= dl[i] << i*8 - elif cl[4] and dl[4] == XgmiiCtrl.START and not any(cl[5:]): - # start in lane 4 - if cl[0] and (dl[0] == XgmiiCtrl.SEQ_OS or dl[0] == XgmiiCtrl.SIG_OS) and not any(cl[1:4]): - # ordered set in lane 0 - data = BaseRBlockType.OS_START - for i in range(1, 4): - data |= dl[i] << i*8 - if dl[0] == XgmiiCtrl.SIG_OS: - # signal ordered set - data |= BaseRO.SIG_OS << 32 - else: - # other control - data = BaseRBlockType.START_4 | (ctrl & 0xfffffff) << 8 + dl.append(XgmiiCtrl.IDLE) + cl.append(1) - for i in range(5, 8): - data |= dl[i] << i*8 - elif cl[0] and (dl[0] == XgmiiCtrl.SEQ_OS or dl[0] == XgmiiCtrl.SIG_OS) and not any(cl[1:4]): + # remap control characters + ctrl = sum(xgmii_ctrl_to_baser_mapping.get(d, BaseRCtrl.ERROR) << i*7 for i, d in enumerate(dl)) + + if not any(cl): + # data + hdr = BaseRSync.DATA + data = int.from_bytes(dl, 'little') + else: + # control + hdr = BaseRSync.CTRL + if cl[0] and dl[0] == XgmiiCtrl.START and not any(cl[1:]): + # start in lane 0 + data = BaseRBlockType.START_0 + for i in range(1, 8): + data |= dl[i] << i*8 + elif cl[4] and dl[4] == XgmiiCtrl.START and not any(cl[5:]): + # start in lane 4 + if cl[0] and (dl[0] == XgmiiCtrl.SEQ_OS or dl[0] == XgmiiCtrl.SIG_OS) and not any(cl[1:4]): # ordered set in lane 0 - if cl[4] and (dl[4] == XgmiiCtrl.SEQ_OS or dl[4] == XgmiiCtrl.SIG_OS) and not any(cl[5:8]): - # ordered set in lane 4 - data = BaseRBlockType.OS_04 - for i in range(5, 8): - data |= dl[i] << i*8 - if dl[4] == XgmiiCtrl.SIG_OS: - # signal ordered set - data |= BaseRO.SIG_OS << 36 - else: - data = BaseRBlockType.OS_0 | (ctrl & 0xfffffff) << 40 + data = BaseRBlockType.OS_START for i in range(1, 4): data |= dl[i] << i*8 if dl[0] == XgmiiCtrl.SIG_OS: # signal ordered set data |= BaseRO.SIG_OS << 32 - elif cl[4] and (dl[4] == XgmiiCtrl.SEQ_OS or dl[4] == XgmiiCtrl.SIG_OS) and not any(cl[5:8]): + else: + # other control + data = BaseRBlockType.START_4 | (ctrl & 0xfffffff) << 8 + + for i in range(5, 8): + data |= dl[i] << i*8 + elif cl[0] and (dl[0] == XgmiiCtrl.SEQ_OS or dl[0] == XgmiiCtrl.SIG_OS) and not any(cl[1:4]): + # ordered set in lane 0 + if cl[4] and (dl[4] == XgmiiCtrl.SEQ_OS or dl[4] == XgmiiCtrl.SIG_OS) and not any(cl[5:8]): # ordered set in lane 4 - data = BaseRBlockType.OS_4 | (ctrl & 0xfffffff) << 8 + data = BaseRBlockType.OS_04 for i in range(5, 8): data |= dl[i] << i*8 if dl[4] == XgmiiCtrl.SIG_OS: # signal ordered set data |= BaseRO.SIG_OS << 36 - elif cl[0] and dl[0] == XgmiiCtrl.TERM: - # terminate in lane 0 - data = BaseRBlockType.TERM_0 | (ctrl & 0xffffffffffff80) << 8 - elif cl[1] and dl[1] == XgmiiCtrl.TERM and not cl[0]: - # terminate in lane 1 - data = BaseRBlockType.TERM_1 | (ctrl & 0xffffffffffc000) << 8 | dl[0] << 8 - elif cl[2] and dl[2] == XgmiiCtrl.TERM and not any(cl[0:2]): - # terminate in lane 2 - data = BaseRBlockType.TERM_2 | (ctrl & 0xffffffffe00000) << 8 - for i in range(2): - data |= dl[i] << ((i+1)*8) - elif cl[3] and dl[3] == XgmiiCtrl.TERM and not any(cl[0:3]): - # terminate in lane 3 - data = BaseRBlockType.TERM_3 | (ctrl & 0xfffffff0000000) << 8 - for i in range(3): - data |= dl[i] << ((i+1)*8) - elif cl[4] and dl[4] == XgmiiCtrl.TERM and not any(cl[0:4]): - # terminate in lane 4 - data = BaseRBlockType.TERM_4 | (ctrl & 0xfffff800000000) << 8 - for i in range(4): - data |= dl[i] << ((i+1)*8) - elif cl[5] and dl[5] == XgmiiCtrl.TERM and not any(cl[0:5]): - # terminate in lane 5 - data = BaseRBlockType.TERM_5 | (ctrl & 0xfffc0000000000) << 8 - for i in range(5): - data |= dl[i] << ((i+1)*8) - elif cl[6] and dl[6] == XgmiiCtrl.TERM and not any(cl[0:6]): - # terminate in lane 6 - data = BaseRBlockType.TERM_6 | (ctrl & 0xfe000000000000) << 8 - for i in range(6): - data |= dl[i] << ((i+1)*8) - elif cl[7] and dl[7] == XgmiiCtrl.TERM and not any(cl[0:7]): - # terminate in lane 7 - data = BaseRBlockType.TERM_7 - for i in range(7): - data |= dl[i] << ((i+1)*8) else: - # all control - data = BaseRBlockType.CTRL | ctrl << 8 - else: - data = BaseRBlockType.CTRL - hdr = BaseRSync.CTRL - self.active = False - self.idle_event.set() + data = BaseRBlockType.OS_0 | (ctrl & 0xfffffff) << 40 + for i in range(1, 4): + data |= dl[i] << i*8 + if dl[0] == XgmiiCtrl.SIG_OS: + # signal ordered set + data |= BaseRO.SIG_OS << 32 + elif cl[4] and (dl[4] == XgmiiCtrl.SEQ_OS or dl[4] == XgmiiCtrl.SIG_OS) and not any(cl[5:8]): + # ordered set in lane 4 + data = BaseRBlockType.OS_4 | (ctrl & 0xfffffff) << 8 + for i in range(5, 8): + data |= dl[i] << i*8 + if dl[4] == XgmiiCtrl.SIG_OS: + # signal ordered set + data |= BaseRO.SIG_OS << 36 + elif cl[0] and dl[0] == XgmiiCtrl.TERM: + # terminate in lane 0 + data = BaseRBlockType.TERM_0 | (ctrl & 0xffffffffffff80) << 8 + elif cl[1] and dl[1] == XgmiiCtrl.TERM and not cl[0]: + # terminate in lane 1 + data = BaseRBlockType.TERM_1 | (ctrl & 0xffffffffffc000) << 8 | dl[0] << 8 + elif cl[2] and dl[2] == XgmiiCtrl.TERM and not any(cl[0:2]): + # terminate in lane 2 + data = BaseRBlockType.TERM_2 | (ctrl & 0xffffffffe00000) << 8 + for i in range(2): + data |= dl[i] << ((i+1)*8) + elif cl[3] and dl[3] == XgmiiCtrl.TERM and not any(cl[0:3]): + # terminate in lane 3 + data = BaseRBlockType.TERM_3 | (ctrl & 0xfffffff0000000) << 8 + for i in range(3): + data |= dl[i] << ((i+1)*8) + elif cl[4] and dl[4] == XgmiiCtrl.TERM and not any(cl[0:4]): + # terminate in lane 4 + data = BaseRBlockType.TERM_4 | (ctrl & 0xfffff800000000) << 8 + for i in range(4): + data |= dl[i] << ((i+1)*8) + elif cl[5] and dl[5] == XgmiiCtrl.TERM and not any(cl[0:5]): + # terminate in lane 5 + data = BaseRBlockType.TERM_5 | (ctrl & 0xfffc0000000000) << 8 + for i in range(5): + data |= dl[i] << ((i+1)*8) + elif cl[6] and dl[6] == XgmiiCtrl.TERM and not any(cl[0:6]): + # terminate in lane 6 + data = BaseRBlockType.TERM_6 | (ctrl & 0xfe000000000000) << 8 + for i in range(6): + data |= dl[i] << ((i+1)*8) + elif cl[7] and dl[7] == XgmiiCtrl.TERM and not any(cl[0:7]): + # terminate in lane 7 + data = BaseRBlockType.TERM_7 + for i in range(7): + data |= dl[i] << ((i+1)*8) + else: + # all control + data = BaseRBlockType.CTRL | ctrl << 8 + else: + data = BaseRBlockType.CTRL + hdr = BaseRSync.CTRL + self.active = False + self.idle_event.set() - if self.scramble: - # 64b/66b scrambler - b = 0 - for i in range(len(self.data)): - if bool(scrambler_state & (1 << 38)) ^ bool(scrambler_state & (1 << 57)) ^ bool(data & (1 << i)): - scrambler_state = ((scrambler_state & 0x1ffffffffffffff) << 1) | 1 - b = b | (1 << i) - else: - scrambler_state = (scrambler_state & 0x1ffffffffffffff) << 1 - data = b + if self.scramble: + # 64b/66b scrambler + b = 0 + for i in range(len(self.data)): + if bool(scrambler_state & (1 << 38)) ^ bool(scrambler_state & (1 << 57)) ^ bool(data & (1 << i)): + scrambler_state = ((scrambler_state & 0x1ffffffffffffff) << 1) | 1 + b = b | (1 << i) + else: + scrambler_state = (scrambler_state & 0x1ffffffffffffff) << 1 + data = b - if self.slip is not None and self.slip.value: - self.bit_offset += 1 + if self.slip is not None and self.slip.value: + self.bit_offset += 1 - self.bit_offset = max(0, self.bit_offset) % 66 + self.bit_offset = max(0, self.bit_offset) % 66 - if self.bit_offset != 0: - d = data << 2 | hdr + if self.bit_offset != 0: + d = data << 2 | hdr - out_d = ((last_d | d << 66) >> 66-self.bit_offset) & 0x3ffffffffffffffff + out_d = ((last_d | d << 66) >> 66-self.bit_offset) & 0x3ffffffffffffffff - last_d = d + last_d = d - data = out_d >> 2 - hdr = out_d & 3 + data = out_d >> 2 + hdr = out_d & 3 - if self.reverse: - # bit reverse - data = sum(1 << (63-i) for i in range(64) if (data >> i) & 1) - hdr = sum(1 << (1-i) for i in range(2) if (hdr >> i) & 1) + if self.reverse: + # bit reverse + data = sum(1 << (63-i) for i in range(64) if (data >> i) & 1) + hdr = sum(1 << (1-i) for i in range(2) if (hdr >> i) & 1) - self.data.value = data - self.hdr.value = hdr + self.data.value = data + self.hdr.value = hdr class BaseRSerdesSink: @@ -436,178 +439,181 @@ class BaseRSerdesSink: while True: await RisingEdge(self.clock) - if self.enable is None or self.enable.value: - data = self.data.value.integer - hdr = self.hdr.value.integer + # clock enable + if self.enable is not None and not self.enable.value: + continue - if self.reverse: - # bit reverse - data = sum(1 << (63-i) for i in range(64) if (data >> i) & 1) - hdr = sum(1 << (1-i) for i in range(2) if (hdr >> i) & 1) + data = self.data.value.integer + hdr = self.hdr.value.integer - 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 + if self.reverse: + # bit reverse + data = sum(1 << (63-i) for i in range(64) if (data >> i) & 1) + hdr = sum(1 << (1-i) for i in range(2) if (hdr >> i) & 1) - # 10GBASE-R decoding + 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 - # remap control characters - ctrl = bytearray(baser_ctrl_to_xgmii_mapping.get((data >> i*7+8) & 0x7f, XgmiiCtrl.ERROR) for i in range(8)) + # 10GBASE-R decoding - data = data.to_bytes(8, 'little') + # remap control characters + ctrl = bytearray(baser_ctrl_to_xgmii_mapping.get((data >> i*7+8) & 0x7f, XgmiiCtrl.ERROR) for i in range(8)) - dl = bytearray() - cl = [] - if hdr == BaseRSync.DATA: - # data - dl = data - cl = [0]*8 - elif hdr == 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) + data = data.to_bytes(8, 'little') + + dl = bytearray() + cl = [] + if hdr == BaseRSync.DATA: + # data + dl = data + cl = [0]*8 + elif hdr == 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: - # invalid block type - self.log.warning("Invalid block type") - dl = [XgmiiCtrl.ERROR]*8 - cl = [1]*8 + 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 sync header - self.log.warning("Invalid sync header") + # 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() + 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)