eth: Support 32 bit mode in BASE-R model

Signed-off-by: Alex Forencich <alex@alexforencich.com>
This commit is contained in:
Alex Forencich
2025-06-15 12:56:03 -07:00
parent 70c0e3d52a
commit e6b5cd6ecd

View File

@@ -73,8 +73,13 @@ class BaseRSerdesSource():
self.width = len(self.data) self.width = len(self.data)
self.byte_size = 8 self.byte_size = 8
self.byte_lanes = 8 self.byte_lanes = self.width // self.byte_size
self.pack_seq = 0
self.pack_cnt = 8 // self.byte_lanes
self.data_mask = (2**self.width)-1
assert self.byte_lanes in [1, 2, 4, 8]
assert self.width == self.byte_lanes * self.byte_size assert self.width == self.byte_lanes * self.byte_size
self.log.info("BASE-R serdes source model configuration") self.log.info("BASE-R serdes source model configuration")
@@ -203,6 +208,9 @@ class BaseRSerdesSource():
last_clk = 0 last_clk = 0
gbx_delay = 0 gbx_delay = 0
data = 0
hdr = 0
while True: while True:
await RisingEdge(self.clock) await RisingEdge(self.clock)
@@ -245,9 +253,27 @@ class BaseRSerdesSource():
if self.gbx_sync is not None: if self.gbx_sync is not None:
self.gbx_sync.value = 0 self.gbx_sync.value = 0
if ifg_cnt + deficit_idle_cnt > self.byte_lanes-1 or (not self.enable_dic and ifg_cnt > 4): if self.pack_seq:
# output data
data_out = data >> (self.width*(self.pack_cnt-self.pack_seq))
self.pack_seq = self.pack_seq-1
if self.reverse:
# bit reverse
data_out = sum(1 << (self.width-1-i) for i in range(self.width) if (data_out >> i) & 1)
self.data.value = data_out & self.data_mask
if self.data_valid is not None:
self.data_valid.value = 1
self.hdr.value = 0
if self.hdr_valid is not None:
self.hdr_valid.value = 0
continue
if ifg_cnt + deficit_idle_cnt > 8-1 or (not self.enable_dic and ifg_cnt > 4):
# in IFG # in IFG
ifg_cnt = ifg_cnt - self.byte_lanes ifg_cnt = ifg_cnt - 8
if ifg_cnt < 0: if ifg_cnt < 0:
if self.enable_dic: if self.enable_dic:
deficit_idle_cnt = max(deficit_idle_cnt+ifg_cnt, 0) deficit_idle_cnt = max(deficit_idle_cnt+ifg_cnt, 0)
@@ -281,7 +307,7 @@ class BaseRSerdesSource():
else: else:
min_ifg = 0 min_ifg = 0
if self.byte_lanes > 4 and (ifg_cnt > min_ifg or self.force_offset_start): if ifg_cnt > min_ifg or self.force_offset_start:
ifg_cnt = ifg_cnt-4 ifg_cnt = ifg_cnt-4
frame.start_lane = 4 frame.start_lane = 4
frame.data = bytearray([XgmiiCtrl.IDLE]*4)+frame.data frame.data = bytearray([XgmiiCtrl.IDLE]*4)+frame.data
@@ -301,7 +327,7 @@ class BaseRSerdesSource():
dl = bytearray() dl = bytearray()
cl = [] cl = []
for k in range(self.byte_lanes): for k in range(8):
if frame is not None: if frame is not None:
d = frame.data[frame_offset] d = frame.data[frame_offset]
if frame.sim_time_sfd is None and d == EthPre.SFD: if frame.sim_time_sfd is None and d == EthPre.SFD:
@@ -311,7 +337,7 @@ class BaseRSerdesSource():
frame_offset += 1 frame_offset += 1
if frame_offset >= len(frame.data): if frame_offset >= len(frame.data):
ifg_cnt = max(self.ifg - (self.byte_lanes-k), 0) ifg_cnt = max(self.ifg - (8-k), 0)
frame.sim_time_end = get_sim_time() - gbx_delay frame.sim_time_end = get_sim_time() - gbx_delay
frame.handle_tx_complete() frame.handle_tx_complete()
frame = None frame = None
@@ -424,7 +450,7 @@ class BaseRSerdesSource():
if self.scramble: if self.scramble:
# 64b/66b scrambler # 64b/66b scrambler
b = 0 b = 0
for i in range(len(self.data)): for i in range(64):
if bool(scrambler_state & (1 << 38)) ^ bool(scrambler_state & (1 << 57)) ^ bool(data & (1 << i)): if bool(scrambler_state & (1 << 38)) ^ bool(scrambler_state & (1 << 57)) ^ bool(data & (1 << i)):
scrambler_state = ((scrambler_state & 0x1ffffffffffffff) << 1) | 1 scrambler_state = ((scrambler_state & 0x1ffffffffffffff) << 1) | 1
b = b | (1 << i) b = b | (1 << i)
@@ -447,15 +473,20 @@ class BaseRSerdesSource():
data = out_d >> 2 data = out_d >> 2
hdr = out_d & 3 hdr = out_d & 3
data_out = data
hdr_out = hdr
self.pack_seq = self.pack_cnt-1
if self.reverse: if self.reverse:
# bit reverse # bit reverse
data = sum(1 << (63-i) for i in range(64) if (data >> i) & 1) data_out = sum(1 << (self.width-1-i) for i in range(self.width) if (data_out >> i) & 1)
hdr = sum(1 << (1-i) for i in range(2) if (hdr >> i) & 1) hdr_out = sum(1 << (1-i) for i in range(2) if (hdr_out >> i) & 1)
self.data.value = data self.data.value = data_out & self.data_mask
if self.data_valid is not None: if self.data_valid is not None:
self.data_valid.value = 1 self.data_valid.value = 1
self.hdr.value = hdr self.hdr.value = hdr_out
if self.hdr_valid is not None: if self.hdr_valid is not None:
self.hdr_valid.value = 1 self.hdr_valid.value = 1
@@ -502,8 +533,12 @@ class BaseRSerdesSink:
self.width = len(self.data) self.width = len(self.data)
self.byte_size = 8 self.byte_size = 8
self.byte_lanes = 8 self.byte_lanes = self.width // self.byte_size
self.pack_seq = 0
self.pack_cnt = 8 // self.byte_lanes
assert self.byte_lanes in [1, 2, 4, 8]
assert self.width == self.byte_lanes * self.byte_size assert self.width == self.byte_lanes * self.byte_size
self.log.info("BASE-R serdes sink model configuration") self.log.info("BASE-R serdes sink model configuration")
@@ -614,6 +649,9 @@ class BaseRSerdesSink:
gbx_delay = 0 gbx_delay = 0
sync_bad = True sync_bad = True
data = 0
hdr = 0
while True: while True:
await RisingEdge(self.clock) await RisingEdge(self.clock)
@@ -672,18 +710,36 @@ class BaseRSerdesSink:
sync_bad = False sync_bad = False
data = self.data.value.integer data_in = self.data.value.integer
hdr = self.hdr.value.integer hdr_in = self.hdr.value.integer
if self.reverse: if self.reverse:
# bit reverse # bit reverse
data = sum(1 << (63-i) for i in range(64) if (data >> i) & 1) data_in = sum(1 << (self.width-1-i) for i in range(self.width) if (data_in >> i) & 1)
hdr = sum(1 << (1-i) for i in range(2) if (hdr >> i) & 1) hdr_in = sum(1 << (1-i) for i in range(2) if (hdr_in >> i) & 1)
if self.pack_cnt > 1:
# pack input data
if self.hdr_valid is not None:
if self.hdr_valid.value:
data = data_in
hdr = hdr_in
self.pack_seq = 1
continue
data |= data_in << (self.width*self.pack_seq)
self.pack_seq = self.pack_seq+1
if self.pack_seq < self.pack_cnt:
continue
else:
data = data_in
hdr = hdr_in
if self.scramble: if self.scramble:
# 64b/66b descrambler # 64b/66b descrambler
b = 0 b = 0
for i in range(len(self.data)): for i in range(64):
if bool(scrambler_state & (1 << 38)) ^ bool(scrambler_state & (1 << 57)) ^ bool(data & (1 << i)): if bool(scrambler_state & (1 << 38)) ^ bool(scrambler_state & (1 << 57)) ^ bool(data & (1 << i)):
b = b | (1 << i) b = b | (1 << i)
scrambler_state = (scrambler_state & 0x1ffffffffffffff) << 1 | bool(data & (1 << i)) scrambler_state = (scrambler_state & 0x1ffffffffffffff) << 1 | bool(data & (1 << i))
@@ -694,95 +750,95 @@ class BaseRSerdesSink:
# remap control characters # remap control characters
ctrl = bytearray(baser_ctrl_to_xgmii_mapping.get((data >> i*7+8) & 0x7f, XgmiiCtrl.ERROR) for i in range(8)) 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') db = data.to_bytes(8, 'little')
dl = bytearray() dl = bytearray()
cl = [] cl = []
if hdr == BaseRSync.DATA: if hdr == BaseRSync.DATA:
# data # data
dl = data dl = db
cl = [0]*8 cl = [0]*8
elif hdr == BaseRSync.CTRL: elif hdr == BaseRSync.CTRL:
if data[0] == BaseRBlockType.CTRL: if db[0] == BaseRBlockType.CTRL:
# C7 C6 C5 C4 C3 C2 C1 C0 BT # C7 C6 C5 C4 C3 C2 C1 C0 BT
dl = ctrl dl = ctrl
cl = [1]*8 cl = [1]*8
elif data[0] == BaseRBlockType.OS_4: elif db[0] == BaseRBlockType.OS_4:
# D7 D6 D5 O4 C3 C2 C1 C0 BT # D7 D6 D5 O4 C3 C2 C1 C0 BT
dl = ctrl[0:4] dl = ctrl[0:4]
cl = [1]*4 cl = [1]*4
if (data[4] >> 4) & 0xf == BaseRO.SEQ_OS: if (db[4] >> 4) & 0xf == BaseRO.SEQ_OS:
dl.append(XgmiiCtrl.SEQ_OS) dl.append(XgmiiCtrl.SEQ_OS)
elif (data[4] >> 4) & 0xf == BaseRO.SIG_OS: elif (db[4] >> 4) & 0xf == BaseRO.SIG_OS:
dl.append(XgmiiCtrl.SIG_OS) dl.append(XgmiiCtrl.SIG_OS)
else: else:
dl.append(XgmiiCtrl.ERROR) dl.append(XgmiiCtrl.ERROR)
cl.append(1) cl.append(1)
dl += data[5:] dl += db[5:]
cl += [0]*3 cl += [0]*3
elif data[0] == BaseRBlockType.START_4: elif db[0] == BaseRBlockType.START_4:
# D7 D6 D5 C3 C2 C1 C0 BT # D7 D6 D5 C3 C2 C1 C0 BT
dl = ctrl[0:4] dl = ctrl[0:4]
cl = [1]*4 cl = [1]*4
dl.append(XgmiiCtrl.START) dl.append(XgmiiCtrl.START)
cl.append(1) cl.append(1)
dl += data[5:] dl += db[5:]
cl += [0]*3 cl += [0]*3
elif data[0] == BaseRBlockType.OS_START: elif db[0] == BaseRBlockType.OS_START:
# D7 D6 D5 O0 D3 D2 D1 BT # D7 D6 D5 O0 D3 D2 D1 BT
if data[4] & 0xf == BaseRO.SEQ_OS: if db[4] & 0xf == BaseRO.SEQ_OS:
dl.append(XgmiiCtrl.SEQ_OS) dl.append(XgmiiCtrl.SEQ_OS)
elif data[4] & 0xf == BaseRO.SIG_OS: elif db[4] & 0xf == BaseRO.SIG_OS:
dl.append(XgmiiCtrl.SIG_OS) dl.append(XgmiiCtrl.SIG_OS)
else: else:
dl.append(XgmiiCtrl.ERROR) dl.append(XgmiiCtrl.ERROR)
cl.append(1) cl.append(1)
dl += data[1:4] dl += db[1:4]
cl += [0]*3 cl += [0]*3
dl.append(XgmiiCtrl.START) dl.append(XgmiiCtrl.START)
cl.append(1) cl.append(1)
dl += data[5:] dl += db[5:]
cl += [0]*3 cl += [0]*3
elif data[0] == BaseRBlockType.OS_04: elif db[0] == BaseRBlockType.OS_04:
# D7 D6 D5 O4 O0 D3 D2 D1 BT # D7 D6 D5 O4 O0 D3 D2 D1 BT
if data[4] & 0xf == BaseRO.SEQ_OS: if db[4] & 0xf == BaseRO.SEQ_OS:
dl.append(XgmiiCtrl.SEQ_OS) dl.append(XgmiiCtrl.SEQ_OS)
elif data[4] & 0xf == BaseRO.SIG_OS: elif db[4] & 0xf == BaseRO.SIG_OS:
dl.append(XgmiiCtrl.SIG_OS) dl.append(XgmiiCtrl.SIG_OS)
else: else:
dl.append(XgmiiCtrl.ERROR) dl.append(XgmiiCtrl.ERROR)
cl.append(1) cl.append(1)
dl += data[1:4] dl += db[1:4]
cl += [0]*3 cl += [0]*3
if (data[4] >> 4) & 0xf == BaseRO.SEQ_OS: if (db[4] >> 4) & 0xf == BaseRO.SEQ_OS:
dl.append(XgmiiCtrl.SEQ_OS) dl.append(XgmiiCtrl.SEQ_OS)
elif (data[4] >> 4) & 0xf == BaseRO.SIG_OS: elif (db[4] >> 4) & 0xf == BaseRO.SIG_OS:
dl.append(XgmiiCtrl.SIG_OS) dl.append(XgmiiCtrl.SIG_OS)
else: else:
dl.append(XgmiiCtrl.ERROR) dl.append(XgmiiCtrl.ERROR)
cl.append(1) cl.append(1)
dl += data[5:] dl += db[5:]
cl += [0]*3 cl += [0]*3
elif data[0] == BaseRBlockType.START_0: elif db[0] == BaseRBlockType.START_0:
# D7 D6 D5 D4 D3 D2 D1 BT # D7 D6 D5 D4 D3 D2 D1 BT
dl.append(XgmiiCtrl.START) dl.append(XgmiiCtrl.START)
cl.append(1) cl.append(1)
dl += data[1:] dl += db[1:]
cl += [0]*7 cl += [0]*7
elif data[0] == BaseRBlockType.OS_0: elif db[0] == BaseRBlockType.OS_0:
# C7 C6 C5 C4 O0 D3 D2 D1 BT # C7 C6 C5 C4 O0 D3 D2 D1 BT
if data[4] & 0xf == BaseRO.SEQ_OS: if db[4] & 0xf == BaseRO.SEQ_OS:
dl.append(XgmiiCtrl.SEQ_OS) dl.append(XgmiiCtrl.SEQ_OS)
elif data[4] & 0xf == BaseRO.SIG_OS: elif db[4] & 0xf == BaseRO.SIG_OS:
dl.append(XgmiiCtrl.SEQ_OS) dl.append(XgmiiCtrl.SEQ_OS)
else: else:
dl.append(XgmiiCtrl.ERROR) dl.append(XgmiiCtrl.ERROR)
cl.append(1) cl.append(1)
dl += data[1:4] dl += db[1:4]
cl += [0]*3 cl += [0]*3
dl += ctrl[4:] dl += ctrl[4:]
cl += [1]*4 cl += [1]*4
elif data[0] in {BaseRBlockType.TERM_0, BaseRBlockType.TERM_1, elif db[0] in {BaseRBlockType.TERM_0, BaseRBlockType.TERM_1,
BaseRBlockType.TERM_2, BaseRBlockType.TERM_3, BaseRBlockType.TERM_4, BaseRBlockType.TERM_2, BaseRBlockType.TERM_3, BaseRBlockType.TERM_4,
BaseRBlockType.TERM_5, BaseRBlockType.TERM_6, BaseRBlockType.TERM_7}: BaseRBlockType.TERM_5, BaseRBlockType.TERM_6, BaseRBlockType.TERM_7}:
# C7 C6 C5 C4 C3 C2 C1 BT # C7 C6 C5 C4 C3 C2 C1 BT
@@ -793,8 +849,8 @@ class BaseRSerdesSink:
# C7 C6 D4 D3 D2 D1 D0 BT # C7 C6 D4 D3 D2 D1 D0 BT
# C7 D5 D4 D3 D2 D1 D0 BT # C7 D5 D4 D3 D2 D1 D0 BT
# D6 D5 D4 D3 D2 D1 D0 BT # D6 D5 D4 D3 D2 D1 D0 BT
term_lane = block_type_term_lane_mapping[data[0]] term_lane = block_type_term_lane_mapping[db[0]]
dl += data[1:term_lane+1] dl += db[1:term_lane+1]
cl += [0]*term_lane cl += [0]*term_lane
dl.append(XgmiiCtrl.TERM) dl.append(XgmiiCtrl.TERM)
cl.append(1) cl.append(1)
@@ -811,7 +867,7 @@ class BaseRSerdesSink:
dl = [XgmiiCtrl.ERROR]*8 dl = [XgmiiCtrl.ERROR]*8
cl = [1]*8 cl = [1]*8
for offset in range(self.byte_lanes): for offset in range(8):
d_val = dl[offset] d_val = dl[offset]
c_val = cl[offset] c_val = cl[offset]