mirror of
https://github.com/corundum/corundum.git
synced 2025-01-16 08:12:53 +08:00
666 lines
29 KiB
Python
666 lines
29 KiB
Python
"""
|
|
|
|
Copyright (c) 2018 Alex Forencich
|
|
|
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
of this software and associated documentation files (the "Software"), to deal
|
|
in the Software without restriction, including without limitation the rights
|
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
copies of the Software, and to permit persons to whom the Software is
|
|
furnished to do so, subject to the following conditions:
|
|
|
|
The above copyright notice and this permission notice shall be included in
|
|
all copies or substantial portions of the Software.
|
|
|
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
|
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
THE SOFTWARE.
|
|
|
|
"""
|
|
|
|
from myhdl import *
|
|
|
|
import xgmii_ep
|
|
|
|
ETH_PRE = 0x55
|
|
ETH_SFD = 0xD5
|
|
|
|
XGMII_IDLE = 0x07
|
|
XGMII_LPI = 0x06
|
|
XGMII_START = 0xfb
|
|
XGMII_TERM = 0xfd
|
|
XGMII_ERROR = 0xfe
|
|
XGMII_SEQ_OS = 0x9c
|
|
XGMII_RES_0 = 0x1c
|
|
XGMII_RES_1 = 0x3c
|
|
XGMII_RES_2 = 0x7c
|
|
XGMII_RES_3 = 0xbc
|
|
XGMII_RES_4 = 0xdc
|
|
XGMII_RES_5 = 0xf7
|
|
XGMII_SIG_OS = 0x5c
|
|
|
|
CTRL_IDLE = 0x00
|
|
CTRL_LPI = 0x06
|
|
CTRL_ERROR = 0x1e
|
|
CTRL_RES_0 = 0x2d
|
|
CTRL_RES_1 = 0x33
|
|
CTRL_RES_2 = 0x4b
|
|
CTRL_RES_3 = 0x55
|
|
CTRL_RES_4 = 0x66
|
|
CTRL_RES_5 = 0x78
|
|
|
|
O_SEQ_OS = 0x0
|
|
O_SIG_OS = 0xf
|
|
|
|
SYNC_DATA = 0b10
|
|
SYNC_CTRL = 0b01
|
|
|
|
BLOCK_TYPE_CTRL = 0x1e # C7 C6 C5 C4 C3 C2 C1 C0 BT
|
|
BLOCK_TYPE_OS_4 = 0x2d # D7 D6 D5 O4 C3 C2 C1 C0 BT
|
|
BLOCK_TYPE_START_4 = 0x33 # D7 D6 D5 C3 C2 C1 C0 BT
|
|
BLOCK_TYPE_OS_START = 0x66 # D7 D6 D5 O0 D3 D2 D1 BT
|
|
BLOCK_TYPE_OS_04 = 0x55 # D7 D6 D5 O4 O0 D3 D2 D1 BT
|
|
BLOCK_TYPE_START_0 = 0x78 # D7 D6 D5 D4 D3 D2 D1 BT
|
|
BLOCK_TYPE_OS_0 = 0x4b # C7 C6 C5 C4 O0 D3 D2 D1 BT
|
|
BLOCK_TYPE_TERM_0 = 0x87 # C7 C6 C5 C4 C3 C2 C1 BT
|
|
BLOCK_TYPE_TERM_1 = 0x99 # C7 C6 C5 C4 C3 C2 D0 BT
|
|
BLOCK_TYPE_TERM_2 = 0xaa # C7 C6 C5 C4 C3 D1 D0 BT
|
|
BLOCK_TYPE_TERM_3 = 0xb4 # C7 C6 C5 C4 D2 D1 D0 BT
|
|
BLOCK_TYPE_TERM_4 = 0xcc # C7 C6 C5 D3 D2 D1 D0 BT
|
|
BLOCK_TYPE_TERM_5 = 0xd2 # C7 C6 D4 D3 D2 D1 D0 BT
|
|
BLOCK_TYPE_TERM_6 = 0xe1 # C7 D5 D4 D3 D2 D1 D0 BT
|
|
BLOCK_TYPE_TERM_7 = 0xff # D6 D5 D4 D3 D2 D1 D0 BT
|
|
|
|
def block_type_term_lane(bt):
|
|
if bt == BLOCK_TYPE_TERM_0:
|
|
return 0
|
|
elif bt == BLOCK_TYPE_TERM_1:
|
|
return 1
|
|
elif bt == BLOCK_TYPE_TERM_2:
|
|
return 2
|
|
elif bt == BLOCK_TYPE_TERM_3:
|
|
return 3
|
|
elif bt == BLOCK_TYPE_TERM_4:
|
|
return 4
|
|
elif bt == BLOCK_TYPE_TERM_5:
|
|
return 5
|
|
elif bt == BLOCK_TYPE_TERM_6:
|
|
return 6
|
|
elif bt == BLOCK_TYPE_TERM_7:
|
|
return 7
|
|
else:
|
|
return None
|
|
|
|
class BaseRSerdesSource(object):
|
|
def __init__(self, ifg=12, enable_dic=True):
|
|
self.has_logic = False
|
|
self.queue = []
|
|
self.ifg = ifg
|
|
self.enable_dic = enable_dic
|
|
self.force_offset_start = False
|
|
|
|
def send(self, frame):
|
|
self.queue.append(xgmii_ep.XGMIIFrame(frame))
|
|
|
|
def count(self):
|
|
return len(self.queue)
|
|
|
|
def empty(self):
|
|
return not self.queue
|
|
|
|
def create_logic(self,
|
|
clk,
|
|
tx_data,
|
|
tx_header,
|
|
enable=True,
|
|
scramble=True,
|
|
name=None
|
|
):
|
|
|
|
assert not self.has_logic
|
|
|
|
self.has_logic = True
|
|
|
|
assert len(tx_data) in [64]
|
|
assert len(tx_data) == len(tx_header)*32
|
|
|
|
bw = int(len(tx_data)/8)
|
|
|
|
@instance
|
|
def logic():
|
|
frame = None
|
|
ccl = []
|
|
ifg_cnt = 0
|
|
deficit_idle_cnt = 0
|
|
scrambler_state = 0
|
|
|
|
while True:
|
|
yield clk.posedge
|
|
|
|
if enable:
|
|
data = 0x000000000000001e
|
|
header = 0b01
|
|
|
|
if ifg_cnt > bw-1 or (not self.enable_dic and ifg_cnt > 0):
|
|
ifg_cnt = max(ifg_cnt - bw, 0)
|
|
elif ccl:
|
|
header, data = ccl.pop(0)
|
|
if not ccl:
|
|
l = block_type_term_lane(data & 0xff)
|
|
if l is not None:
|
|
ifg_cnt = self.ifg - (bw-l) + deficit_idle_cnt
|
|
else:
|
|
ifg_cnt = self.ifg + deficit_idle_cnt
|
|
elif self.queue:
|
|
frame = self.queue.pop(0)
|
|
dl, cl = frame.build()
|
|
if name is not None:
|
|
print("[%s] Sending frame %s" % (name, repr(frame)))
|
|
|
|
assert len(dl) > 0
|
|
assert dl[0] == ETH_PRE
|
|
dl[0] = XGMII_START
|
|
cl[0] = 1
|
|
dl.append(XGMII_TERM)
|
|
cl.append(1)
|
|
|
|
if (bw == 8 and ifg_cnt >= 4) or self.force_offset_start:
|
|
ifg_cnt = max(ifg_cnt-4, 0)
|
|
dl = [XGMII_IDLE]*4+dl
|
|
cl = [1]*4+cl
|
|
|
|
deficit_idle_cnt = max(ifg_cnt, 0)
|
|
ifg_cnt = 0
|
|
|
|
# pad length to multiple of 8 by adding idles
|
|
if len(dl)%8:
|
|
for k in range(8-(len(dl)%8)):
|
|
dl.append(XGMII_IDLE)
|
|
cl.append(1)
|
|
|
|
# 10GBASE-R encoding
|
|
for k in range(0, len(dl), 8):
|
|
di = dl[k:k+8]
|
|
ci = cl[k:k+8]
|
|
|
|
# remap control characters
|
|
ctrl = 0
|
|
ctrl_decode_error = [0]*8
|
|
for i in range(8):
|
|
if not ci[i]:
|
|
# data
|
|
ctrl |= CTRL_ERROR << i*7
|
|
elif di[i] == XGMII_IDLE:
|
|
# idle
|
|
ctrl |= CTRL_IDLE << i*7
|
|
elif di[i] == XGMII_LPI:
|
|
# LPI
|
|
ctrl |= CTRL_LPI << i*7
|
|
elif di[i] == XGMII_ERROR:
|
|
# error
|
|
ctrl |= CTRL_ERROR << i*7
|
|
elif di[i] == XGMII_RES_0:
|
|
# reserved0
|
|
ctrl |= CTRL_RES_0 << i*7
|
|
elif di[i] == XGMII_RES_1:
|
|
# reserved1
|
|
ctrl |= CTRL_RES_1 << i*7
|
|
elif di[i] == XGMII_RES_2:
|
|
# reserved2
|
|
ctrl |= CTRL_RES_2 << i*7
|
|
elif di[i] == XGMII_RES_3:
|
|
# reserved3
|
|
ctrl |= CTRL_RES_3 << i*7
|
|
elif di[i] == XGMII_RES_4:
|
|
# reserved4
|
|
ctrl |= CTRL_RES_4 << i*7
|
|
elif di[i] == XGMII_RES_5:
|
|
# reserved5
|
|
ctrl |= CTRL_RES_5 << i*7
|
|
else:
|
|
# invalid
|
|
ctrl |= CTRL_ERROR << i*7
|
|
ctrl_decode_error[i] = ci[i]
|
|
|
|
if not any(ci):
|
|
# data
|
|
h = SYNC_DATA
|
|
d = 0
|
|
for i in range(8):
|
|
d |= di[i] << i*8
|
|
else:
|
|
# control
|
|
h = SYNC_CTRL
|
|
if ci[0] and di[0] == XGMII_START and not any(ci[1:]):
|
|
# start in lane 0
|
|
d = BLOCK_TYPE_START_0
|
|
for i in range(1,8):
|
|
d |= di[i] << i*8
|
|
elif ci[4] and di[4] == XGMII_START and not any(ci[5:]):
|
|
# start in lane 4
|
|
if ci[0] and (di[0] == XGMII_SEQ_OS or di[0] == XGMII_SIG_OS) and not any(ci[1:4]):
|
|
# ordered set in lane 0
|
|
d = BLOCK_TYPE_OS_START
|
|
for i in range(1,4):
|
|
d |= di[i] << i*8
|
|
if di[0] == XGMII_SIG_OS:
|
|
# signal ordered set
|
|
d |= O_SIG_OS << 32
|
|
else:
|
|
# other control
|
|
d = BLOCK_TYPE_START_4 | (ctrl & 0xfffffff) << 8
|
|
|
|
for i in range(5,8):
|
|
d |= di[i] << i*8
|
|
elif ci[0] and (di[0] == XGMII_SEQ_OS or di[0] == XGMII_SIG_OS) and not any(ci[1:4]):
|
|
# ordered set in lane 0
|
|
if ci[4] and (di[4] == XGMII_SEQ_OS or di[4] == XGMII_SIG_OS) and not any(ci[5:8]):
|
|
# ordered set in lane 4
|
|
d = BLOCK_TYPE_OS_04
|
|
for i in range(5,8):
|
|
d |= di[i] << i*8
|
|
if di[4] == XGMII_SIG_OS:
|
|
# signal ordered set
|
|
d |= O_SIG_OS << 36
|
|
else:
|
|
d = BLOCK_TYPE_OS_0 | (ctrl & 0xfffffff) << 40
|
|
for i in range(1,4):
|
|
d |= di[i] << i*8
|
|
if di[0] == XGMII_SIG_OS:
|
|
# signal ordered set
|
|
d |= O_SIG_OS << 32
|
|
elif ci[4] and (di[4] == XGMII_SEQ_OS or di[4] == XGMII_SIG_OS) and not any(ci[5:8]):
|
|
# ordered set in lane 4
|
|
d = BLOCK_TYPE_OS_4 | (ctrl & 0xfffffff) << 8
|
|
for i in range(5,8):
|
|
d |= di[i] << i*8
|
|
if di[4] == XGMII_SIG_OS:
|
|
# signal ordered set
|
|
d |= O_SIG_OS << 36
|
|
elif ci[0] and di[0] == XGMII_TERM:
|
|
# terminate in lane 0
|
|
d = BLOCK_TYPE_TERM_0 | (ctrl & 0xffffffffffff80) << 8
|
|
elif ci[1] and di[1] == XGMII_TERM and not ci[0]:
|
|
# terminate in lane 1
|
|
d = BLOCK_TYPE_TERM_1 | (ctrl & 0xffffffffffc000) << 8 | di[0] << 8
|
|
elif ci[2] and di[2] == XGMII_TERM and not any(ci[0:2]):
|
|
# terminate in lane 2
|
|
d = BLOCK_TYPE_TERM_2 | (ctrl & 0xffffffffe00000) << 8
|
|
for i in range(2):
|
|
d |= di[i] << ((i+1)*8)
|
|
elif ci[3] and di[3] == XGMII_TERM and not any(ci[0:3]):
|
|
# terminate in lane 3
|
|
d = BLOCK_TYPE_TERM_3 | (ctrl & 0xfffffff0000000) << 8
|
|
for i in range(3):
|
|
d |= di[i] << ((i+1)*8)
|
|
elif ci[4] and di[4] == XGMII_TERM and not any(ci[0:4]):
|
|
# terminate in lane 4
|
|
d = BLOCK_TYPE_TERM_4 | (ctrl & 0xfffff800000000) << 8
|
|
for i in range(4):
|
|
d |= di[i] << ((i+1)*8)
|
|
elif ci[5] and di[5] == XGMII_TERM and not any(ci[0:5]):
|
|
# terminate in lane 5
|
|
d = BLOCK_TYPE_TERM_5 | (ctrl & 0xfffc0000000000) << 8
|
|
for i in range(5):
|
|
d |= di[i] << ((i+1)*8)
|
|
elif ci[6] and di[6] == XGMII_TERM and not any(ci[0:6]):
|
|
# terminate in lane 6
|
|
d = BLOCK_TYPE_TERM_6 | (ctrl & 0xfe000000000000) << 8
|
|
for i in range(6):
|
|
d |= di[i] << ((i+1)*8)
|
|
elif ci[7] and di[7] == XGMII_TERM and not any(ci[0:7]):
|
|
# terminate in lane 7
|
|
d = BLOCK_TYPE_TERM_7
|
|
for i in range(7):
|
|
d |= di[i] << ((i+1)*8)
|
|
else:
|
|
# all control
|
|
d = BLOCK_TYPE_CTRL | ctrl << 8
|
|
|
|
ccl.append((h, d))
|
|
|
|
header, data = ccl.pop(0)
|
|
if not ccl:
|
|
l = block_type_term_lane(data & 0xff)
|
|
if l is not None:
|
|
ifg_cnt = self.ifg - (bw-l) + deficit_idle_cnt
|
|
else:
|
|
ifg_cnt = self.ifg + deficit_idle_cnt
|
|
else:
|
|
ifg_cnt = 0
|
|
deficit_idle_cnt = 0
|
|
|
|
if scramble:
|
|
# 64b66b scrambler
|
|
b = 0
|
|
for i in range(len(tx_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
|
|
|
|
tx_data.next = data
|
|
tx_header.next = header
|
|
|
|
return instances()
|
|
|
|
|
|
class BaseRSerdesSink(object):
|
|
def __init__(self):
|
|
self.has_logic = False
|
|
self.queue = []
|
|
self.sync = Signal(intbv(0))
|
|
|
|
def recv(self):
|
|
if self.queue:
|
|
return self.queue.pop(0)
|
|
return None
|
|
|
|
def count(self):
|
|
return len(self.queue)
|
|
|
|
def empty(self):
|
|
return not self.queue
|
|
|
|
def wait(self, timeout=0):
|
|
if self.queue:
|
|
return
|
|
if timeout:
|
|
yield self.sync, delay(timeout)
|
|
else:
|
|
yield self.sync
|
|
|
|
def create_logic(self,
|
|
clk,
|
|
rx_data,
|
|
rx_header,
|
|
enable=True,
|
|
scramble=True,
|
|
name=None
|
|
):
|
|
|
|
assert not self.has_logic
|
|
|
|
self.has_logic = True
|
|
|
|
assert len(rx_data) in [64]
|
|
assert len(rx_data) == len(rx_header)*32
|
|
|
|
bw = int(len(rx_data)/8)
|
|
|
|
@instance
|
|
def logic():
|
|
frame = None
|
|
d = []
|
|
c = []
|
|
scrambler_state = 0
|
|
|
|
while True:
|
|
yield clk.posedge
|
|
|
|
if enable:
|
|
data = int(rx_data)
|
|
header = int(rx_header)
|
|
|
|
if scramble:
|
|
# 64b66b descrambler
|
|
b = 0
|
|
for i in range(len(rx_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 = [0]*8
|
|
for i in range(8):
|
|
if (data >> i*7+8) & 0x7f == CTRL_IDLE:
|
|
# idle
|
|
ctrl[i] = XGMII_IDLE;
|
|
elif (data >> i*7+8) & 0x7f == CTRL_LPI:
|
|
# LPI
|
|
ctrl[i] = XGMII_LPI
|
|
elif (data >> i*7+8) & 0x7f == CTRL_ERROR:
|
|
# error
|
|
ctrl[i] = XGMII_ERROR
|
|
elif (data >> i*7+8) & 0x7f == CTRL_RES_0:
|
|
# reserved0
|
|
ctrl[i] = XGMII_RES_0
|
|
elif (data >> i*7+8) & 0x7f == CTRL_RES_1:
|
|
# reserved1
|
|
ctrl[i] = XGMII_RES_1
|
|
elif (data >> i*7+8) & 0x7f == CTRL_RES_2:
|
|
# reserved2
|
|
ctrl[i] = XGMII_RES_2
|
|
elif (data >> i*7+8) & 0x7f == CTRL_RES_3:
|
|
# reserved3
|
|
ctrl[i] = XGMII_RES_3
|
|
elif (data >> i*7+8) & 0x7f == CTRL_RES_4:
|
|
# reserved4
|
|
ctrl[i] = XGMII_RES_4
|
|
elif (data >> i*7+8) & 0x7f == CTRL_RES_5:
|
|
# reserved5
|
|
ctrl[i] = XGMII_RES_5
|
|
else:
|
|
# invalid
|
|
ctrl[i] = XGMII_ERROR
|
|
|
|
dl = []
|
|
cl = []
|
|
if header == SYNC_DATA:
|
|
# data
|
|
for k in range(8):
|
|
dl.append((data >> k*8) & 0xff)
|
|
cl.append(0)
|
|
elif header == SYNC_CTRL:
|
|
if data & 0xff == BLOCK_TYPE_CTRL:
|
|
# C7 C6 C5 C4 C3 C2 C1 C0 BT
|
|
dl = ctrl
|
|
cl = [1]*8
|
|
elif data & 0xff == BLOCK_TYPE_OS_4:
|
|
# D7 D6 D5 O4 C3 C2 C1 C0 BT
|
|
dl = ctrl[0:4]
|
|
cl = [1]*4
|
|
if (data >> 36) & 0xf == O_SEQ_OS:
|
|
dl.append(XGMII_SEQ_OS)
|
|
elif (data >> 36) & 0xf == O_SIG_OS:
|
|
dl.append(XGMII_SIG_OS)
|
|
else:
|
|
dl.append(XGMII_ERROR)
|
|
cl.append(1)
|
|
for k in range(4,7):
|
|
dl.append((data >> (k+1)*8) & 0xff)
|
|
cl.append(0)
|
|
elif data & 0xff == BLOCK_TYPE_START_4:
|
|
# D7 D6 D5 C3 C2 C1 C0 BT
|
|
dl = ctrl[0:4]
|
|
cl = [1]*4
|
|
dl.append(XGMII_START)
|
|
cl.append(1)
|
|
for k in range(4,7):
|
|
dl.append((data >> (k+1)*8) & 0xff)
|
|
cl.append(0)
|
|
elif data & 0xff == BLOCK_TYPE_OS_START:
|
|
# D7 D6 D5 O0 D3 D2 D1 BT
|
|
if (data >> 32) & 0xf == O_SEQ_OS:
|
|
dl.append(XGMII_SEQ_OS)
|
|
elif (data >> 32) & 0xf == O_SIG_OS:
|
|
dl.append(XGMII_SIG_OS)
|
|
else:
|
|
dl.append(XGMII_ERROR)
|
|
cl.append(1)
|
|
for k in range(0,3):
|
|
dl.append((data >> (k+1)*8) & 0xff)
|
|
cl.append(0)
|
|
dl.append(XGMII_START)
|
|
cl.append(1)
|
|
for k in range(4,7):
|
|
dl.append((data >> (k+1)*8) & 0xff)
|
|
cl.append(0)
|
|
elif data & 0xff == BLOCK_TYPE_OS_04:
|
|
# D7 D6 D5 O4 O0 D3 D2 D1 BT
|
|
if (data >> 32) & 0xf == O_SEQ_OS:
|
|
dl.append(XGMII_SEQ_OS)
|
|
elif (data >> 32) & 0xf == O_SIG_OS:
|
|
dl.append(XGMII_SIG_OS)
|
|
else:
|
|
dl.append(XGMII_ERROR)
|
|
cl.append(1)
|
|
for k in range(0,3):
|
|
dl.append((data >> (k+1)*8) & 0xff)
|
|
cl.append(0)
|
|
if (data >> 36) & 0xf == O_SEQ_OS:
|
|
dl.append(XGMII_SEQ_OS)
|
|
elif (data >> 36) & 0xf == O_SIG_OS:
|
|
dl.append(XGMII_SIG_OS)
|
|
else:
|
|
dl.append(XGMII_ERROR)
|
|
cl.append(1)
|
|
for k in range(4,7):
|
|
dl.append((data >> (k+1)*8) & 0xff)
|
|
cl.append(0)
|
|
elif data & 0xff == BLOCK_TYPE_START_0:
|
|
# D7 D6 D5 D4 D3 D2 D1 BT
|
|
dl.append(XGMII_START)
|
|
cl.append(1)
|
|
for k in range(7):
|
|
dl.append((data >> (k+1)*8) & 0xff)
|
|
cl.append(0)
|
|
elif data & 0xff == BLOCK_TYPE_OS_0:
|
|
# C7 C6 C5 C4 O0 D3 D2 D1 BT
|
|
if (data >> 32) & 0xf == O_SEQ_OS:
|
|
dl.append(XGMII_SEQ_OS)
|
|
elif (data >> 32) & 0xf == O_SIG_OS:
|
|
dl.append(XGMII_SEQ_OS)
|
|
else:
|
|
dl.append(XGMII_ERROR)
|
|
cl.append(1)
|
|
for k in range(0,3):
|
|
dl.append((data >> (k+1)*8) & 0xff)
|
|
cl.append(0)
|
|
dl.extend(ctrl[4:8])
|
|
cl.extend([1]*4)
|
|
elif data & 0xff == BLOCK_TYPE_TERM_0:
|
|
# C7 C6 C5 C4 C3 C2 C1 BT
|
|
dl.append(XGMII_TERM)
|
|
cl.append(1)
|
|
dl.extend(ctrl[1:])
|
|
cl.extend([1]*7)
|
|
elif data & 0xff == BLOCK_TYPE_TERM_1:
|
|
# C7 C6 C5 C4 C3 C2 D0 BT
|
|
dl.append((data >> 8) & 0xff)
|
|
cl.append(0)
|
|
dl.append(XGMII_TERM)
|
|
cl.append(1)
|
|
dl.extend(ctrl[2:])
|
|
cl.extend([1]*6)
|
|
elif data & 0xff == BLOCK_TYPE_TERM_2:
|
|
# C7 C6 C5 C4 C3 D1 D0 BT
|
|
for k in range(2):
|
|
dl.append((data >> (k+1)*8) & 0xff)
|
|
cl.append(0)
|
|
dl.append(XGMII_TERM)
|
|
cl.append(1)
|
|
dl.extend(ctrl[3:])
|
|
cl.extend([1]*5)
|
|
elif data & 0xff == BLOCK_TYPE_TERM_3:
|
|
# C7 C6 C5 C4 D2 D1 D0 BT
|
|
for k in range(3):
|
|
dl.append((data >> (k+1)*8) & 0xff)
|
|
cl.append(0)
|
|
dl.append(XGMII_TERM)
|
|
cl.append(1)
|
|
dl.extend(ctrl[4:])
|
|
cl.extend([1]*4)
|
|
elif data & 0xff == BLOCK_TYPE_TERM_4:
|
|
# C7 C6 C5 D3 D2 D1 D0 BT
|
|
for k in range(4):
|
|
dl.append((data >> (k+1)*8) & 0xff)
|
|
cl.append(0)
|
|
dl.append(XGMII_TERM)
|
|
cl.append(1)
|
|
dl.extend(ctrl[5:])
|
|
cl.extend([1]*3)
|
|
elif data & 0xff == BLOCK_TYPE_TERM_5:
|
|
# C7 C6 D4 D3 D2 D1 D0 BT
|
|
for k in range(5):
|
|
dl.append((data >> (k+1)*8) & 0xff)
|
|
cl.append(0)
|
|
dl.append(XGMII_TERM)
|
|
cl.append(1)
|
|
dl.extend(ctrl[6:])
|
|
cl.extend([1]*2)
|
|
elif data & 0xff == BLOCK_TYPE_TERM_6:
|
|
# C7 D5 D4 D3 D2 D1 D0 BT
|
|
for k in range(6):
|
|
dl.append((data >> (k+1)*8) & 0xff)
|
|
cl.append(0)
|
|
dl.append(XGMII_TERM)
|
|
cl.append(1)
|
|
dl.extend(ctrl[7:])
|
|
cl.extend([1]*1)
|
|
elif data & 0xff == BLOCK_TYPE_TERM_7:
|
|
# D6 D5 D4 D3 D2 D1 D0 BT
|
|
for k in range(7):
|
|
dl.append((data >> (k+1)*8) & 0xff)
|
|
cl.append(0)
|
|
dl.append(XGMII_TERM)
|
|
cl.append(1)
|
|
else:
|
|
# invalid block type
|
|
dl = [XGMII_ERROR]*8
|
|
cl = [1]*8
|
|
else:
|
|
# invalid sync header
|
|
dl = [XGMII_ERROR]*8
|
|
cl = [1]*8
|
|
|
|
if frame is None:
|
|
if cl[0] and dl[0] == XGMII_START:
|
|
# start in lane 0
|
|
frame = xgmii_ep.XGMIIFrame()
|
|
d = [ETH_PRE]
|
|
c = [0]
|
|
for i in range(1,bw):
|
|
d.append(dl[i])
|
|
c.append(cl[i])
|
|
elif bw == 8 and cl[4] and dl[4] == XGMII_START:
|
|
# start in lane 4
|
|
frame = xgmii_ep.XGMIIFrame()
|
|
d = [ETH_PRE]
|
|
c = [0]
|
|
for i in range(5,bw):
|
|
d.append(dl[i])
|
|
c.append(cl[i])
|
|
else:
|
|
for i in range(bw):
|
|
if cl[i]:
|
|
# got a control character; terminate frame reception
|
|
if dl[i] != XGMII_TERM:
|
|
# store control character if it's not a termination
|
|
d.append(dl[i])
|
|
c.append(cl[i])
|
|
frame.parse(d, c)
|
|
self.queue.append(frame)
|
|
self.sync.next = not self.sync
|
|
if name is not None:
|
|
print("[%s] Got frame %s" % (name, repr(frame)))
|
|
frame = None
|
|
d = []
|
|
c = []
|
|
break
|
|
else:
|
|
d.append(dl[i])
|
|
c.append(cl[i])
|
|
|
|
return instances()
|
|
|