Compare commits
32 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2bfe8a0e50 | ||
|
|
9c88b0440e | ||
|
|
37b23c358b | ||
|
|
dd35d734f9 | ||
|
|
45ee1193cb | ||
|
|
5caafbb9e7 | ||
|
|
2d4450e048 | ||
|
|
c5d28182c4 | ||
|
|
79991205b5 | ||
|
|
a22123649c | ||
|
|
b5ba332ecc | ||
|
|
eb62e43fd1 | ||
|
|
5c4ef258ac | ||
|
|
6c5845fad3 | ||
|
|
32f6e449c0 | ||
|
|
2af7852006 | ||
|
|
3325568406 | ||
|
|
6a35c31b4b | ||
|
|
73fe54705f | ||
|
|
448451e274 | ||
|
|
21c2c05c57 | ||
|
|
ab84a3b100 | ||
|
|
0f3060b9ba | ||
|
|
2ee51890f5 | ||
|
|
fbdf4149b3 | ||
|
|
03156ff759 | ||
|
|
8956de42b5 | ||
|
|
de18e62024 | ||
|
|
14738c1dae | ||
|
|
3d43812c7b | ||
|
|
008d903bb9 | ||
|
|
0bd66da868 |
6
.github/workflows/regression-tests.yml
vendored
6
.github/workflows/regression-tests.yml
vendored
@@ -9,13 +9,13 @@ jobs:
|
|||||||
|
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
python-version: [3.6, 3.7, 3.8, 3.9]
|
python-version: ["3.7", "3.8", "3.9", "3.10"]
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v1
|
- uses: actions/checkout@v3
|
||||||
|
|
||||||
- name: Set up Python ${{ matrix.python-version }}
|
- name: Set up Python ${{ matrix.python-version }}
|
||||||
uses: actions/setup-python@v2
|
uses: actions/setup-python@v4
|
||||||
with:
|
with:
|
||||||
python-version: ${{ matrix.python-version }}
|
python-version: ${{ matrix.python-version }}
|
||||||
|
|
||||||
|
|||||||
15
README.md
15
README.md
@@ -467,6 +467,7 @@ To use these modules, import the one you need and connect it to the DUT:
|
|||||||
tx_bus=AxiStreamBus.from_prefix(dut, "tx_axis"),
|
tx_bus=AxiStreamBus.from_prefix(dut, "tx_axis"),
|
||||||
tx_ptp_time=dut.tx_ptp_time,
|
tx_ptp_time=dut.tx_ptp_time,
|
||||||
tx_ptp_ts=dut.tx_ptp_ts,
|
tx_ptp_ts=dut.tx_ptp_ts,
|
||||||
|
tx_ptp_ts_tag=dut.tx_ptp_ts_tag,
|
||||||
tx_ptp_ts_valid=dut.tx_ptp_ts_valid,
|
tx_ptp_ts_valid=dut.tx_ptp_ts_valid,
|
||||||
rx_clk=dut.rx_clk,
|
rx_clk=dut.rx_clk,
|
||||||
rx_rst=dut.rx_rst,
|
rx_rst=dut.rx_rst,
|
||||||
@@ -492,6 +493,8 @@ To receive data, call `recv()` or `recv_nowait()`. Optionally call `wait()` to
|
|||||||
|
|
||||||
data = await mac.tx.recv()
|
data = await mac.tx.recv()
|
||||||
|
|
||||||
|
PTP timestamping requires free-running PTP clocks driving the PTP time inputs, synchronous with the corresponding MAC clocks. The values of these fields are then captured when the frame SFD is transferred and returned either on tuser (for received frames) or on a separate streaming interface (for transmitted frames). Additionally, on the transmit path, a tag value from tuser is returned along with the timestamp.
|
||||||
|
|
||||||
#### Signals
|
#### Signals
|
||||||
|
|
||||||
* `tdata`: payload data, must be a multiple of 8 bits
|
* `tdata`: payload data, must be a multiple of 8 bits
|
||||||
@@ -499,9 +502,10 @@ To receive data, call `recv()` or `recv_nowait()`. Optionally call `wait()` to
|
|||||||
* `tready`: indicates sink is ready for data (tx only)
|
* `tready`: indicates sink is ready for data (tx only)
|
||||||
* `tlast`: marks the last cycle of a frame
|
* `tlast`: marks the last cycle of a frame
|
||||||
* `tkeep`: qualifies data byte, data bus width must be evenly divisible by `tkeep` signal width
|
* `tkeep`: qualifies data byte, data bus width must be evenly divisible by `tkeep` signal width
|
||||||
* `tuser`: user data, carries frame error mark and captured receive PTP timestamp
|
* `tuser`: user data, carries frame error mark and captured receive PTP timestamp (RX) or PTP timestamp tag (TX)
|
||||||
* `ptp_time`: PTP time input from PHC, captured into `ptp_timestamp` field coincident with transfer of frame SFD and output on `ptp_ts`
|
* `ptp_time`: PTP time input from PHC, captured into `ptp_timestamp` field coincident with transfer of frame SFD and output on `ptp_ts` (TX) or `tuser` (RX)
|
||||||
* `ptp_ts`: captured transmit PTP timestamp
|
* `ptp_ts`: captured transmit PTP timestamp
|
||||||
|
* `ptp_ts_tag`: captured transmit PTP timestamp tag
|
||||||
* `ptp_ts_valid`: qualifies captured transmit PTP timestamp
|
* `ptp_ts_valid`: qualifies captured transmit PTP timestamp
|
||||||
|
|
||||||
#### Constructor parameters (`EthMacRx` and `EthMacTx`):
|
#### Constructor parameters (`EthMacRx` and `EthMacTx`):
|
||||||
@@ -510,7 +514,8 @@ To receive data, call `recv()` or `recv_nowait()`. Optionally call `wait()` to
|
|||||||
* _clock_: clock signal
|
* _clock_: clock signal
|
||||||
* _reset_: reset signal (optional)
|
* _reset_: reset signal (optional)
|
||||||
* _ptp_time_: PTP time input from PHC (optional)
|
* _ptp_time_: PTP time input from PHC (optional)
|
||||||
* _ptp_ts_: PTP timestamp output (optional) (tx)
|
* _ptp_ts_: PTP timestamp (optional) (tx)
|
||||||
|
* _ptp_ts_tag_: PTP timestamp tag (optional) (tx)
|
||||||
* _ptp_ts_valid_: PTP timestamp valid (optional) (tx)
|
* _ptp_ts_valid_: PTP timestamp valid (optional) (tx)
|
||||||
* _reset_active_level_: reset active level (optional, default `True`)
|
* _reset_active_level_: reset active level (optional, default `True`)
|
||||||
* _ifg_: IFG size in byte times (optional, default `12`)
|
* _ifg_: IFG size in byte times (optional, default `12`)
|
||||||
@@ -522,7 +527,8 @@ To receive data, call `recv()` or `recv_nowait()`. Optionally call `wait()` to
|
|||||||
* _tx_clk_: transmit clock
|
* _tx_clk_: transmit clock
|
||||||
* _tx_rst_: transmit reset (optional)
|
* _tx_rst_: transmit reset (optional)
|
||||||
* _tx_ptp_time_: transmit PTP time input from PHC (optional)
|
* _tx_ptp_time_: transmit PTP time input from PHC (optional)
|
||||||
* _tx_ptp_ts_: transmit PTP timestamp output (optional)
|
* _tx_ptp_ts_: transmit PTP timestamp (optional)
|
||||||
|
* _tx_ptp_ts_tag_: transmit PTP timestamp tag (optional)
|
||||||
* _tx_ptp_ts_valid_: transmit PTP timestamp valid (optional)
|
* _tx_ptp_ts_valid_: transmit PTP timestamp valid (optional)
|
||||||
* _rx_bus_: `AxiStreamBus` object containing receive AXI stream interface signals
|
* _rx_bus_: `AxiStreamBus` object containing receive AXI stream interface signals
|
||||||
* _rx_clk_: receive clock
|
* _rx_clk_: receive clock
|
||||||
@@ -565,6 +571,7 @@ Attributes:
|
|||||||
* `sim_time_start`: simulation time of first transfer cycle of frame.
|
* `sim_time_start`: simulation time of first transfer cycle of frame.
|
||||||
* `sim_time_sfd`: simulation time at which the SFD was transferred.
|
* `sim_time_sfd`: simulation time at which the SFD was transferred.
|
||||||
* `sim_time_end`: simulation time of last transfer cycle of frame.
|
* `sim_time_end`: simulation time of last transfer cycle of frame.
|
||||||
|
* `ptp_tag`: PTP timestamp tag for transmitted frames.
|
||||||
* `ptp_timestamp`: captured value of `ptp_time` at frame SFD
|
* `ptp_timestamp`: captured value of `ptp_time` at frame SFD
|
||||||
* `tx_complete`: event or callable triggered when frame is transmitted.
|
* `tx_complete`: event or callable triggered when frame is transmitted.
|
||||||
|
|
||||||
|
|||||||
@@ -42,12 +42,12 @@ class XgmiiCtrl(enum.IntEnum):
|
|||||||
TERM = 0xfd
|
TERM = 0xfd
|
||||||
ERROR = 0xfe
|
ERROR = 0xfe
|
||||||
SEQ_OS = 0x9c
|
SEQ_OS = 0x9c
|
||||||
RES0 = 0x1c
|
RES_0 = 0x1c
|
||||||
RES1 = 0x3c
|
RES_1 = 0x3c
|
||||||
RES2 = 0x7c
|
RES_2 = 0x7c
|
||||||
RES3 = 0xbc
|
RES_3 = 0xbc
|
||||||
RES4 = 0xdc
|
RES_4 = 0xdc
|
||||||
RES5 = 0xf7
|
RES_5 = 0xf7
|
||||||
SIG_OS = 0x5c
|
SIG_OS = 0x5c
|
||||||
|
|
||||||
|
|
||||||
@@ -93,3 +93,41 @@ class BaseRBlockType(enum.IntEnum):
|
|||||||
TERM_5 = 0xd2 # C7 C6 D4 D3 D2 D1 D0 BT
|
TERM_5 = 0xd2 # C7 C6 D4 D3 D2 D1 D0 BT
|
||||||
TERM_6 = 0xe1 # C7 D5 D4 D3 D2 D1 D0 BT
|
TERM_6 = 0xe1 # C7 D5 D4 D3 D2 D1 D0 BT
|
||||||
TERM_7 = 0xff # D6 D5 D4 D3 D2 D1 D0 BT
|
TERM_7 = 0xff # D6 D5 D4 D3 D2 D1 D0 BT
|
||||||
|
|
||||||
|
|
||||||
|
xgmii_ctrl_to_baser_mapping = {
|
||||||
|
XgmiiCtrl.IDLE: BaseRCtrl.IDLE,
|
||||||
|
XgmiiCtrl.LPI: BaseRCtrl.LPI,
|
||||||
|
XgmiiCtrl.ERROR: BaseRCtrl.ERROR,
|
||||||
|
XgmiiCtrl.RES_0: BaseRCtrl.RES_0,
|
||||||
|
XgmiiCtrl.RES_1: BaseRCtrl.RES_1,
|
||||||
|
XgmiiCtrl.RES_2: BaseRCtrl.RES_2,
|
||||||
|
XgmiiCtrl.RES_3: BaseRCtrl.RES_3,
|
||||||
|
XgmiiCtrl.RES_4: BaseRCtrl.RES_4,
|
||||||
|
XgmiiCtrl.RES_5: BaseRCtrl.RES_5,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
baser_ctrl_to_xgmii_mapping = {
|
||||||
|
BaseRCtrl.IDLE: XgmiiCtrl.IDLE,
|
||||||
|
BaseRCtrl.LPI: XgmiiCtrl.LPI,
|
||||||
|
BaseRCtrl.ERROR: XgmiiCtrl.ERROR,
|
||||||
|
BaseRCtrl.RES_0: XgmiiCtrl.RES_0,
|
||||||
|
BaseRCtrl.RES_1: XgmiiCtrl.RES_1,
|
||||||
|
BaseRCtrl.RES_2: XgmiiCtrl.RES_2,
|
||||||
|
BaseRCtrl.RES_3: XgmiiCtrl.RES_3,
|
||||||
|
BaseRCtrl.RES_4: XgmiiCtrl.RES_4,
|
||||||
|
BaseRCtrl.RES_5: XgmiiCtrl.RES_5,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
block_type_term_lane_mapping = {
|
||||||
|
BaseRBlockType.TERM_0: 0,
|
||||||
|
BaseRBlockType.TERM_1: 1,
|
||||||
|
BaseRBlockType.TERM_2: 2,
|
||||||
|
BaseRBlockType.TERM_3: 3,
|
||||||
|
BaseRBlockType.TERM_4: 4,
|
||||||
|
BaseRBlockType.TERM_5: 5,
|
||||||
|
BaseRBlockType.TERM_6: 6,
|
||||||
|
BaseRBlockType.TERM_7: 7,
|
||||||
|
}
|
||||||
|
|||||||
@@ -49,6 +49,7 @@ class EthMacFrame:
|
|||||||
self.sim_time_sfd = None
|
self.sim_time_sfd = None
|
||||||
self.sim_time_end = None
|
self.sim_time_end = None
|
||||||
self.ptp_timestamp = None
|
self.ptp_timestamp = None
|
||||||
|
self.ptp_tag = None
|
||||||
self.tx_complete = None
|
self.tx_complete = None
|
||||||
|
|
||||||
if type(data) is EthMacFrame:
|
if type(data) is EthMacFrame:
|
||||||
@@ -57,6 +58,7 @@ class EthMacFrame:
|
|||||||
self.sim_time_sfd = data.sim_time_sfd
|
self.sim_time_sfd = data.sim_time_sfd
|
||||||
self.sim_time_end = data.sim_time_end
|
self.sim_time_end = data.sim_time_end
|
||||||
self.ptp_timestamp = data.ptp_timestamp
|
self.ptp_timestamp = data.ptp_timestamp
|
||||||
|
self.ptp_tag = data.ptp_tag
|
||||||
self.tx_complete = data.tx_complete
|
self.tx_complete = data.tx_complete
|
||||||
else:
|
else:
|
||||||
self.data = bytearray(data)
|
self.data = bytearray(data)
|
||||||
@@ -104,7 +106,8 @@ class EthMacFrame:
|
|||||||
f"sim_time_start={self.sim_time_start!r}, "
|
f"sim_time_start={self.sim_time_start!r}, "
|
||||||
f"sim_time_sfd={self.sim_time_sfd!r}, "
|
f"sim_time_sfd={self.sim_time_sfd!r}, "
|
||||||
f"sim_time_end={self.sim_time_end!r}, "
|
f"sim_time_end={self.sim_time_end!r}, "
|
||||||
f"ptp_timestamp={self.ptp_timestamp!r})"
|
f"ptp_timestamp={self.ptp_timestamp!r}, "
|
||||||
|
f"ptp_tag={self.ptp_tag!r})"
|
||||||
)
|
)
|
||||||
|
|
||||||
def __len__(self):
|
def __len__(self):
|
||||||
@@ -118,7 +121,7 @@ class EthMacFrame:
|
|||||||
|
|
||||||
|
|
||||||
class EthMacTx(Reset):
|
class EthMacTx(Reset):
|
||||||
def __init__(self, bus, clock, reset=None, ptp_time=None, ptp_ts=None, ptp_ts_valid=None,
|
def __init__(self, bus, clock, reset=None, ptp_time=None, ptp_ts=None, ptp_ts_tag=None, ptp_ts_valid=None,
|
||||||
reset_active_level=True, ifg=12, speed=1000e6, *args, **kwargs):
|
reset_active_level=True, ifg=12, speed=1000e6, *args, **kwargs):
|
||||||
|
|
||||||
self.bus = bus
|
self.bus = bus
|
||||||
@@ -126,6 +129,7 @@ class EthMacTx(Reset):
|
|||||||
self.reset = reset
|
self.reset = reset
|
||||||
self.ptp_time = ptp_time
|
self.ptp_time = ptp_time
|
||||||
self.ptp_ts = ptp_ts
|
self.ptp_ts = ptp_ts
|
||||||
|
self.ptp_ts_tag = ptp_ts_tag
|
||||||
self.ptp_ts_valid = ptp_ts_valid
|
self.ptp_ts_valid = ptp_ts_valid
|
||||||
self.ifg = ifg
|
self.ifg = ifg
|
||||||
self.speed = speed
|
self.speed = speed
|
||||||
@@ -172,6 +176,10 @@ class EthMacTx(Reset):
|
|||||||
self.log.info(" tuser width: %d bits", len(self.bus.tuser))
|
self.log.info(" tuser width: %d bits", len(self.bus.tuser))
|
||||||
else:
|
else:
|
||||||
self.log.info(" tuser: not present")
|
self.log.info(" tuser: not present")
|
||||||
|
if self.ptp_time:
|
||||||
|
self.log.info(" ptp_time width: %d bits", len(self.ptp_time))
|
||||||
|
else:
|
||||||
|
self.log.info(" ptp_time: not present")
|
||||||
|
|
||||||
if self.bus.tready is None:
|
if self.bus.tready is None:
|
||||||
raise ValueError("tready is required")
|
raise ValueError("tready is required")
|
||||||
@@ -185,6 +193,8 @@ class EthMacTx(Reset):
|
|||||||
|
|
||||||
if self.ptp_ts:
|
if self.ptp_ts:
|
||||||
self.ptp_ts.setimmediatevalue(0)
|
self.ptp_ts.setimmediatevalue(0)
|
||||||
|
if self.ptp_ts_tag:
|
||||||
|
self.ptp_ts_tag.setimmediatevalue(0)
|
||||||
if self.ptp_ts_valid:
|
if self.ptp_ts_valid:
|
||||||
self.ptp_ts_valid.setimmediatevalue(0)
|
self.ptp_ts_valid.setimmediatevalue(0)
|
||||||
|
|
||||||
@@ -243,7 +253,7 @@ class EthMacTx(Reset):
|
|||||||
self._run_ts_cr = None
|
self._run_ts_cr = None
|
||||||
|
|
||||||
if self.ptp_ts_valid:
|
if self.ptp_ts_valid:
|
||||||
self.ptp_ts_valid <= 0
|
self.ptp_ts_valid.value = 0
|
||||||
|
|
||||||
self.active = False
|
self.active = False
|
||||||
|
|
||||||
@@ -252,9 +262,9 @@ class EthMacTx(Reset):
|
|||||||
else:
|
else:
|
||||||
self.log.info("Reset de-asserted")
|
self.log.info("Reset de-asserted")
|
||||||
if self._run_cr is None:
|
if self._run_cr is None:
|
||||||
self._run_cr = cocotb.fork(self._run())
|
self._run_cr = cocotb.start_soon(self._run())
|
||||||
if self._run_ts_cr is None and self.ptp_ts:
|
if self._run_ts_cr is None and self.ptp_ts:
|
||||||
self._run_ts_cr = cocotb.fork(self._run_ts())
|
self._run_ts_cr = cocotb.start_soon(self._run_ts())
|
||||||
|
|
||||||
async def _run(self):
|
async def _run(self):
|
||||||
frame = None
|
frame = None
|
||||||
@@ -274,7 +284,8 @@ class EthMacTx(Reset):
|
|||||||
|
|
||||||
if self.ptp_time:
|
if self.ptp_time:
|
||||||
frame.ptp_timestamp = self.ptp_time.value.integer
|
frame.ptp_timestamp = self.ptp_time.value.integer
|
||||||
self.ts_queue.put_nowait(frame.ptp_timestamp)
|
frame.ptp_tag = cycle.tuser.integer >> 1
|
||||||
|
self.ts_queue.put_nowait((frame.ptp_timestamp, frame.ptp_tag))
|
||||||
|
|
||||||
# process frame data
|
# process frame data
|
||||||
while True:
|
while True:
|
||||||
@@ -311,14 +322,18 @@ class EthMacTx(Reset):
|
|||||||
await Timer(self.time_scale*self.ifg*8//self.speed, 'step')
|
await Timer(self.time_scale*self.ifg*8//self.speed, 'step')
|
||||||
|
|
||||||
async def _run_ts(self):
|
async def _run_ts(self):
|
||||||
|
clock_edge_event = RisingEdge(self.clock)
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
await RisingEdge(self.clock)
|
await clock_edge_event
|
||||||
self.ptp_ts_valid <= 0
|
self.ptp_ts_valid.value = 0
|
||||||
|
|
||||||
if not self.ts_queue.empty():
|
if not self.ts_queue.empty():
|
||||||
ts = self.ts_queue.get_nowait()
|
ts, tag = self.ts_queue.get_nowait()
|
||||||
self.ptp_ts <= ts
|
self.ptp_ts.value = ts
|
||||||
self.ptp_ts_valid <= 1
|
if self.ptp_ts_tag is not None:
|
||||||
|
self.ptp_ts_tag.value = tag
|
||||||
|
self.ptp_ts_valid.value = 1
|
||||||
|
|
||||||
|
|
||||||
class EthMacRx(Reset):
|
class EthMacRx(Reset):
|
||||||
@@ -378,6 +393,10 @@ class EthMacRx(Reset):
|
|||||||
self.log.info(" tuser width: %d bits", len(self.bus.tuser))
|
self.log.info(" tuser width: %d bits", len(self.bus.tuser))
|
||||||
else:
|
else:
|
||||||
self.log.info(" tuser: not present")
|
self.log.info(" tuser: not present")
|
||||||
|
if self.ptp_time:
|
||||||
|
self.log.info(" ptp_time width: %d bits", len(self.ptp_time))
|
||||||
|
else:
|
||||||
|
self.log.info(" ptp_time: not present")
|
||||||
|
|
||||||
if self.byte_size != 8:
|
if self.byte_size != 8:
|
||||||
raise ValueError("Byte size must be 8")
|
raise ValueError("Byte size must be 8")
|
||||||
@@ -458,10 +477,11 @@ class EthMacRx(Reset):
|
|||||||
else:
|
else:
|
||||||
self.log.info("Reset de-asserted")
|
self.log.info("Reset de-asserted")
|
||||||
if self._run_cr is None:
|
if self._run_cr is None:
|
||||||
self._run_cr = cocotb.fork(self._run())
|
self._run_cr = cocotb.start_soon(self._run())
|
||||||
|
|
||||||
async def _run(self):
|
async def _run(self):
|
||||||
frame = None
|
frame = None
|
||||||
|
frame_offset = 0
|
||||||
tuser = 0
|
tuser = 0
|
||||||
self.active = False
|
self.active = False
|
||||||
|
|
||||||
@@ -477,6 +497,7 @@ class EthMacRx(Reset):
|
|||||||
frame.sim_time_sfd = None
|
frame.sim_time_sfd = None
|
||||||
frame.sim_time_end = None
|
frame.sim_time_end = None
|
||||||
self.log.info("TX frame: %s", frame)
|
self.log.info("TX frame: %s", frame)
|
||||||
|
frame_offset = 0
|
||||||
|
|
||||||
# wait for preamble time
|
# wait for preamble time
|
||||||
await Timer(self.time_scale*8*8//self.speed, 'step')
|
await Timer(self.time_scale*8*8//self.speed, 'step')
|
||||||
@@ -499,11 +520,12 @@ class EthMacRx(Reset):
|
|||||||
cycle.tuser = tuser
|
cycle.tuser = tuser
|
||||||
|
|
||||||
for offset in range(self.byte_lanes):
|
for offset in range(self.byte_lanes):
|
||||||
cycle.tdata |= (frame.data.pop(0) & self.byte_mask) << (offset * self.byte_size)
|
cycle.tdata |= (frame.data[frame_offset] & self.byte_mask) << (offset * self.byte_size)
|
||||||
cycle.tkeep |= 1 << offset
|
cycle.tkeep |= 1 << offset
|
||||||
byte_count += 1
|
byte_count += 1
|
||||||
|
frame_offset += 1
|
||||||
|
|
||||||
if len(frame.data) == 0:
|
if frame_offset >= len(frame.data):
|
||||||
cycle.tlast = 1
|
cycle.tlast = 1
|
||||||
frame.sim_time_end = get_sim_time()
|
frame.sim_time_end = get_sim_time()
|
||||||
frame.handle_tx_complete()
|
frame.handle_tx_complete()
|
||||||
@@ -521,13 +543,13 @@ class EthMacRx(Reset):
|
|||||||
|
|
||||||
|
|
||||||
class EthMac:
|
class EthMac:
|
||||||
def __init__(self, tx_bus=None, tx_clk=None, tx_rst=None, tx_ptp_time=None, tx_ptp_ts=None, tx_ptp_ts_valid=None,
|
def __init__(self, tx_bus=None, tx_clk=None, tx_rst=None, tx_ptp_time=None, tx_ptp_ts=None, tx_ptp_ts_tag=None,
|
||||||
rx_bus=None, rx_clk=None, rx_rst=None, rx_ptp_time=None,
|
tx_ptp_ts_valid=None, rx_bus=None, rx_clk=None, rx_rst=None, rx_ptp_time=None,
|
||||||
reset_active_level=True, ifg=12, speed=1000e6, *args, **kwargs):
|
reset_active_level=True, ifg=12, speed=1000e6, *args, **kwargs):
|
||||||
|
|
||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
|
|
||||||
self.tx = EthMacTx(tx_bus, tx_clk, tx_rst, tx_ptp_time, tx_ptp_ts, tx_ptp_ts_valid,
|
self.tx = EthMacTx(tx_bus, tx_clk, tx_rst, tx_ptp_time, tx_ptp_ts, tx_ptp_ts_tag, tx_ptp_ts_valid,
|
||||||
reset_active_level=reset_active_level, ifg=ifg, speed=speed)
|
reset_active_level=reset_active_level, ifg=ifg, speed=speed)
|
||||||
self.rx = EthMacRx(rx_bus, rx_clk, rx_rst, rx_ptp_time,
|
self.rx = EthMacRx(rx_bus, rx_clk, rx_rst, rx_ptp_time,
|
||||||
reset_active_level=reset_active_level, ifg=ifg, speed=speed)
|
reset_active_level=reset_active_level, ifg=ifg, speed=speed)
|
||||||
|
|||||||
@@ -157,6 +157,7 @@ class GmiiSource(Reset):
|
|||||||
self.current_frame = None
|
self.current_frame = None
|
||||||
self.idle_event = Event()
|
self.idle_event = Event()
|
||||||
self.idle_event.set()
|
self.idle_event.set()
|
||||||
|
self.active_event = Event()
|
||||||
|
|
||||||
self.ifg = 12
|
self.ifg = 12
|
||||||
self.mii_mode = False
|
self.mii_mode = False
|
||||||
@@ -189,6 +190,7 @@ class GmiiSource(Reset):
|
|||||||
frame = GmiiFrame(frame)
|
frame = GmiiFrame(frame)
|
||||||
await self.queue.put(frame)
|
await self.queue.put(frame)
|
||||||
self.idle_event.clear()
|
self.idle_event.clear()
|
||||||
|
self.active_event.set()
|
||||||
self.queue_occupancy_bytes += len(frame)
|
self.queue_occupancy_bytes += len(frame)
|
||||||
self.queue_occupancy_frames += 1
|
self.queue_occupancy_frames += 1
|
||||||
|
|
||||||
@@ -198,6 +200,7 @@ class GmiiSource(Reset):
|
|||||||
frame = GmiiFrame(frame)
|
frame = GmiiFrame(frame)
|
||||||
self.queue.put_nowait(frame)
|
self.queue.put_nowait(frame)
|
||||||
self.idle_event.clear()
|
self.idle_event.clear()
|
||||||
|
self.active_event.set()
|
||||||
self.queue_occupancy_bytes += len(frame)
|
self.queue_occupancy_bytes += len(frame)
|
||||||
self.queue_occupancy_frames += 1
|
self.queue_occupancy_frames += 1
|
||||||
|
|
||||||
@@ -225,6 +228,7 @@ class GmiiSource(Reset):
|
|||||||
frame.handle_tx_complete()
|
frame.handle_tx_complete()
|
||||||
self.dequeue_event.set()
|
self.dequeue_event.set()
|
||||||
self.idle_event.set()
|
self.idle_event.set()
|
||||||
|
self.active_event.clear()
|
||||||
self.queue_occupancy_bytes = 0
|
self.queue_occupancy_bytes = 0
|
||||||
self.queue_occupancy_frames = 0
|
self.queue_occupancy_frames = 0
|
||||||
|
|
||||||
@@ -239,10 +243,10 @@ class GmiiSource(Reset):
|
|||||||
self._run_cr = None
|
self._run_cr = None
|
||||||
|
|
||||||
self.active = False
|
self.active = False
|
||||||
self.data <= 0
|
self.data.value = 0
|
||||||
if self.er is not None:
|
if self.er is not None:
|
||||||
self.er <= 0
|
self.er.value = 0
|
||||||
self.dv <= 0
|
self.dv.value = 0
|
||||||
|
|
||||||
if self.current_frame:
|
if self.current_frame:
|
||||||
self.log.warning("Flushed transmit frame during reset: %s", self.current_frame)
|
self.log.warning("Flushed transmit frame during reset: %s", self.current_frame)
|
||||||
@@ -251,18 +255,28 @@ class GmiiSource(Reset):
|
|||||||
|
|
||||||
if self.queue.empty():
|
if self.queue.empty():
|
||||||
self.idle_event.set()
|
self.idle_event.set()
|
||||||
|
self.active_event.clear()
|
||||||
else:
|
else:
|
||||||
self.log.info("Reset de-asserted")
|
self.log.info("Reset de-asserted")
|
||||||
if self._run_cr is None:
|
if self._run_cr is None:
|
||||||
self._run_cr = cocotb.fork(self._run())
|
self._run_cr = cocotb.start_soon(self._run())
|
||||||
|
|
||||||
async def _run(self):
|
async def _run(self):
|
||||||
frame = None
|
frame = None
|
||||||
|
frame_offset = 0
|
||||||
|
frame_data = None
|
||||||
|
frame_error = None
|
||||||
ifg_cnt = 0
|
ifg_cnt = 0
|
||||||
self.active = False
|
self.active = False
|
||||||
|
|
||||||
|
clock_edge_event = RisingEdge(self.clock)
|
||||||
|
|
||||||
|
enable_event = None
|
||||||
|
if self.enable is not None:
|
||||||
|
enable_event = RisingEdge(self.enable)
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
await RisingEdge(self.clock)
|
await clock_edge_event
|
||||||
|
|
||||||
if self.enable is None or self.enable.value:
|
if self.enable is None or self.enable.value:
|
||||||
if ifg_cnt > 0:
|
if ifg_cnt > 0:
|
||||||
@@ -286,40 +300,51 @@ class GmiiSource(Reset):
|
|||||||
self.mii_mode = bool(self.mii_select.value.integer)
|
self.mii_mode = bool(self.mii_select.value.integer)
|
||||||
|
|
||||||
if self.mii_mode:
|
if self.mii_mode:
|
||||||
mii_data = []
|
# convert to MII
|
||||||
mii_error = []
|
frame_data = []
|
||||||
|
frame_error = []
|
||||||
for b, e in zip(frame.data, frame.error):
|
for b, e in zip(frame.data, frame.error):
|
||||||
mii_data.append(b & 0x0F)
|
frame_data.append(b & 0x0F)
|
||||||
mii_data.append(b >> 4)
|
frame_data.append(b >> 4)
|
||||||
mii_error.append(e)
|
frame_error.append(e)
|
||||||
mii_error.append(e)
|
frame_error.append(e)
|
||||||
frame.data = mii_data
|
else:
|
||||||
frame.error = mii_error
|
frame_data = frame.data
|
||||||
|
frame_error = frame.error
|
||||||
|
|
||||||
self.active = True
|
self.active = True
|
||||||
|
frame_offset = 0
|
||||||
|
|
||||||
if frame is not None:
|
if frame is not None:
|
||||||
d = frame.data.pop(0)
|
d = frame_data[frame_offset]
|
||||||
if frame.sim_time_sfd is None and d in (EthPre.SFD, 0xD):
|
if frame.sim_time_sfd is None and d in (EthPre.SFD, 0xD):
|
||||||
frame.sim_time_sfd = get_sim_time()
|
frame.sim_time_sfd = get_sim_time()
|
||||||
self.data <= d
|
self.data.value = d
|
||||||
if self.er is not None:
|
if self.er is not None:
|
||||||
self.er <= frame.error.pop(0)
|
self.er.value = frame_error[frame_offset]
|
||||||
self.dv <= 1
|
self.dv.value = 1
|
||||||
|
frame_offset += 1
|
||||||
|
|
||||||
if not frame.data:
|
if frame_offset >= len(frame_data):
|
||||||
ifg_cnt = max(self.ifg, 1)
|
ifg_cnt = max(self.ifg, 1)
|
||||||
frame.sim_time_end = get_sim_time()
|
frame.sim_time_end = get_sim_time()
|
||||||
frame.handle_tx_complete()
|
frame.handle_tx_complete()
|
||||||
frame = None
|
frame = None
|
||||||
self.current_frame = None
|
self.current_frame = None
|
||||||
else:
|
else:
|
||||||
self.data <= 0
|
self.data.value = 0
|
||||||
if self.er is not None:
|
if self.er is not None:
|
||||||
self.er <= 0
|
self.er.value = 0
|
||||||
self.dv <= 0
|
self.dv.value = 0
|
||||||
self.active = False
|
self.active = False
|
||||||
|
|
||||||
|
if ifg_cnt == 0 and self.queue.empty():
|
||||||
self.idle_event.set()
|
self.idle_event.set()
|
||||||
|
self.active_event.clear()
|
||||||
|
await self.active_event.wait()
|
||||||
|
|
||||||
|
elif self.enable is not None and not self.enable.value:
|
||||||
|
await enable_event
|
||||||
|
|
||||||
|
|
||||||
class GmiiSink(Reset):
|
class GmiiSink(Reset):
|
||||||
@@ -415,14 +440,22 @@ class GmiiSink(Reset):
|
|||||||
else:
|
else:
|
||||||
self.log.info("Reset de-asserted")
|
self.log.info("Reset de-asserted")
|
||||||
if self._run_cr is None:
|
if self._run_cr is None:
|
||||||
self._run_cr = cocotb.fork(self._run())
|
self._run_cr = cocotb.start_soon(self._run())
|
||||||
|
|
||||||
async def _run(self):
|
async def _run(self):
|
||||||
frame = None
|
frame = None
|
||||||
self.active = False
|
self.active = False
|
||||||
|
|
||||||
|
clock_edge_event = RisingEdge(self.clock)
|
||||||
|
|
||||||
|
active_event = RisingEdge(self.dv)
|
||||||
|
|
||||||
|
enable_event = None
|
||||||
|
if self.enable is not None:
|
||||||
|
enable_event = RisingEdge(self.enable)
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
await RisingEdge(self.clock)
|
await clock_edge_event
|
||||||
|
|
||||||
if self.enable is None or self.enable.value:
|
if self.enable is None or self.enable.value:
|
||||||
d_val = self.data.value.integer
|
d_val = self.data.value.integer
|
||||||
@@ -481,6 +514,12 @@ class GmiiSink(Reset):
|
|||||||
frame.data.append(d_val)
|
frame.data.append(d_val)
|
||||||
frame.error.append(er_val)
|
frame.error.append(er_val)
|
||||||
|
|
||||||
|
if not dv_val:
|
||||||
|
await active_event
|
||||||
|
|
||||||
|
elif self.enable is not None and not self.enable.value:
|
||||||
|
await enable_event
|
||||||
|
|
||||||
|
|
||||||
class GmiiPhy:
|
class GmiiPhy:
|
||||||
def __init__(self, txd, tx_er, tx_en, tx_clk, gtx_clk, rxd, rx_er, rx_dv, rx_clk,
|
def __init__(self, txd, tx_er, tx_en, tx_clk, gtx_clk, rxd, rx_er, rx_dv, rx_clk,
|
||||||
@@ -510,12 +549,12 @@ class GmiiPhy:
|
|||||||
self._clock_cr.kill()
|
self._clock_cr.kill()
|
||||||
|
|
||||||
if self.speed == 1000e6:
|
if self.speed == 1000e6:
|
||||||
self._clock_cr = cocotb.fork(self._run_clocks(8*1e9/self.speed))
|
self._clock_cr = cocotb.start_soon(self._run_clocks(8*1e9/self.speed))
|
||||||
self.tx.mii_mode = False
|
self.tx.mii_mode = False
|
||||||
self.rx.mii_mode = False
|
self.rx.mii_mode = False
|
||||||
self.tx.clock = self.gtx_clk
|
self.tx.clock = self.gtx_clk
|
||||||
else:
|
else:
|
||||||
self._clock_cr = cocotb.fork(self._run_clocks(4*1e9/self.speed))
|
self._clock_cr = cocotb.start_soon(self._run_clocks(4*1e9/self.speed))
|
||||||
self.tx.mii_mode = True
|
self.tx.mii_mode = True
|
||||||
self.rx.mii_mode = True
|
self.rx.mii_mode = True
|
||||||
self.tx.clock = self.tx_clk
|
self.tx.clock = self.tx_clk
|
||||||
@@ -529,8 +568,8 @@ class GmiiPhy:
|
|||||||
|
|
||||||
while True:
|
while True:
|
||||||
await t
|
await t
|
||||||
self.rx_clk <= 1
|
self.rx_clk.value = 1
|
||||||
self.tx_clk <= 1
|
self.tx_clk.value = 1
|
||||||
await t
|
await t
|
||||||
self.rx_clk <= 0
|
self.rx_clk.value = 0
|
||||||
self.tx_clk <= 0
|
self.tx_clk.value = 0
|
||||||
|
|||||||
@@ -59,6 +59,7 @@ class MiiSource(Reset):
|
|||||||
self.current_frame = None
|
self.current_frame = None
|
||||||
self.idle_event = Event()
|
self.idle_event = Event()
|
||||||
self.idle_event.set()
|
self.idle_event.set()
|
||||||
|
self.active_event = Event()
|
||||||
|
|
||||||
self.ifg = 12
|
self.ifg = 12
|
||||||
|
|
||||||
@@ -90,6 +91,7 @@ class MiiSource(Reset):
|
|||||||
frame = GmiiFrame(frame)
|
frame = GmiiFrame(frame)
|
||||||
await self.queue.put(frame)
|
await self.queue.put(frame)
|
||||||
self.idle_event.clear()
|
self.idle_event.clear()
|
||||||
|
self.active_event.set()
|
||||||
self.queue_occupancy_bytes += len(frame)
|
self.queue_occupancy_bytes += len(frame)
|
||||||
self.queue_occupancy_frames += 1
|
self.queue_occupancy_frames += 1
|
||||||
|
|
||||||
@@ -99,6 +101,7 @@ class MiiSource(Reset):
|
|||||||
frame = GmiiFrame(frame)
|
frame = GmiiFrame(frame)
|
||||||
self.queue.put_nowait(frame)
|
self.queue.put_nowait(frame)
|
||||||
self.idle_event.clear()
|
self.idle_event.clear()
|
||||||
|
self.active_event.set()
|
||||||
self.queue_occupancy_bytes += len(frame)
|
self.queue_occupancy_bytes += len(frame)
|
||||||
self.queue_occupancy_frames += 1
|
self.queue_occupancy_frames += 1
|
||||||
|
|
||||||
@@ -126,6 +129,7 @@ class MiiSource(Reset):
|
|||||||
frame.handle_tx_complete()
|
frame.handle_tx_complete()
|
||||||
self.dequeue_event.set()
|
self.dequeue_event.set()
|
||||||
self.idle_event.set()
|
self.idle_event.set()
|
||||||
|
self.active_event.clear()
|
||||||
self.queue_occupancy_bytes = 0
|
self.queue_occupancy_bytes = 0
|
||||||
self.queue_occupancy_frames = 0
|
self.queue_occupancy_frames = 0
|
||||||
|
|
||||||
@@ -140,10 +144,10 @@ class MiiSource(Reset):
|
|||||||
self._run_cr = None
|
self._run_cr = None
|
||||||
|
|
||||||
self.active = False
|
self.active = False
|
||||||
self.data <= 0
|
self.data.value = 0
|
||||||
if self.er is not None:
|
if self.er is not None:
|
||||||
self.er <= 0
|
self.er.value = 0
|
||||||
self.dv <= 0
|
self.dv.value = 0
|
||||||
|
|
||||||
if self.current_frame:
|
if self.current_frame:
|
||||||
self.log.warning("Flushed transmit frame during reset: %s", self.current_frame)
|
self.log.warning("Flushed transmit frame during reset: %s", self.current_frame)
|
||||||
@@ -152,18 +156,28 @@ class MiiSource(Reset):
|
|||||||
|
|
||||||
if self.queue.empty():
|
if self.queue.empty():
|
||||||
self.idle_event.set()
|
self.idle_event.set()
|
||||||
|
self.active_event.clear()
|
||||||
else:
|
else:
|
||||||
self.log.info("Reset de-asserted")
|
self.log.info("Reset de-asserted")
|
||||||
if self._run_cr is None:
|
if self._run_cr is None:
|
||||||
self._run_cr = cocotb.fork(self._run())
|
self._run_cr = cocotb.start_soon(self._run())
|
||||||
|
|
||||||
async def _run(self):
|
async def _run(self):
|
||||||
frame = None
|
frame = None
|
||||||
|
frame_offset = 0
|
||||||
|
frame_data = None
|
||||||
|
frame_error = None
|
||||||
ifg_cnt = 0
|
ifg_cnt = 0
|
||||||
self.active = False
|
self.active = False
|
||||||
|
|
||||||
|
clock_edge_event = RisingEdge(self.clock)
|
||||||
|
|
||||||
|
enable_event = None
|
||||||
|
if self.enable is not None:
|
||||||
|
enable_event = RisingEdge(self.enable)
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
await RisingEdge(self.clock)
|
await clock_edge_event
|
||||||
|
|
||||||
if self.enable is None or self.enable.value:
|
if self.enable is None or self.enable.value:
|
||||||
if ifg_cnt > 0:
|
if ifg_cnt > 0:
|
||||||
@@ -183,40 +197,48 @@ class MiiSource(Reset):
|
|||||||
self.log.info("TX frame: %s", frame)
|
self.log.info("TX frame: %s", frame)
|
||||||
frame.normalize()
|
frame.normalize()
|
||||||
|
|
||||||
mii_data = []
|
# convert to MII
|
||||||
mii_error = []
|
frame_data = []
|
||||||
|
frame_error = []
|
||||||
for b, e in zip(frame.data, frame.error):
|
for b, e in zip(frame.data, frame.error):
|
||||||
mii_data.append(b & 0x0F)
|
frame_data.append(b & 0x0F)
|
||||||
mii_data.append(b >> 4)
|
frame_data.append(b >> 4)
|
||||||
mii_error.append(e)
|
frame_error.append(e)
|
||||||
mii_error.append(e)
|
frame_error.append(e)
|
||||||
frame.data = mii_data
|
|
||||||
frame.error = mii_error
|
|
||||||
|
|
||||||
self.active = True
|
self.active = True
|
||||||
|
frame_offset = 0
|
||||||
|
|
||||||
if frame is not None:
|
if frame is not None:
|
||||||
d = frame.data.pop(0)
|
d = frame_data[frame_offset]
|
||||||
if frame.sim_time_sfd is None and d == 0xD:
|
if frame.sim_time_sfd is None and d == 0xD:
|
||||||
frame.sim_time_sfd = get_sim_time()
|
frame.sim_time_sfd = get_sim_time()
|
||||||
self.data <= d
|
self.data.value = d
|
||||||
if self.er is not None:
|
if self.er is not None:
|
||||||
self.er <= frame.error.pop(0)
|
self.er.value = frame_error[frame_offset]
|
||||||
self.dv <= 1
|
self.dv.value = 1
|
||||||
|
frame_offset += 1
|
||||||
|
|
||||||
if not frame.data:
|
if frame_offset >= len(frame_data):
|
||||||
ifg_cnt = max(self.ifg, 1)
|
ifg_cnt = max(self.ifg, 1)
|
||||||
frame.sim_time_end = get_sim_time()
|
frame.sim_time_end = get_sim_time()
|
||||||
frame.handle_tx_complete()
|
frame.handle_tx_complete()
|
||||||
frame = None
|
frame = None
|
||||||
self.current_frame = None
|
self.current_frame = None
|
||||||
else:
|
else:
|
||||||
self.data <= 0
|
self.data.value = 0
|
||||||
if self.er is not None:
|
if self.er is not None:
|
||||||
self.er <= 0
|
self.er.value = 0
|
||||||
self.dv <= 0
|
self.dv.value = 0
|
||||||
self.active = False
|
self.active = False
|
||||||
|
|
||||||
|
if ifg_cnt == 0 and self.queue.empty():
|
||||||
self.idle_event.set()
|
self.idle_event.set()
|
||||||
|
self.active_event.clear()
|
||||||
|
await self.active_event.wait()
|
||||||
|
|
||||||
|
elif self.enable is not None and not self.enable.value:
|
||||||
|
await enable_event
|
||||||
|
|
||||||
|
|
||||||
class MiiSink(Reset):
|
class MiiSink(Reset):
|
||||||
@@ -309,14 +331,22 @@ class MiiSink(Reset):
|
|||||||
else:
|
else:
|
||||||
self.log.info("Reset de-asserted")
|
self.log.info("Reset de-asserted")
|
||||||
if self._run_cr is None:
|
if self._run_cr is None:
|
||||||
self._run_cr = cocotb.fork(self._run())
|
self._run_cr = cocotb.start_soon(self._run())
|
||||||
|
|
||||||
async def _run(self):
|
async def _run(self):
|
||||||
frame = None
|
frame = None
|
||||||
self.active = False
|
self.active = False
|
||||||
|
|
||||||
|
clock_edge_event = RisingEdge(self.clock)
|
||||||
|
|
||||||
|
active_event = RisingEdge(self.dv)
|
||||||
|
|
||||||
|
enable_event = None
|
||||||
|
if self.enable is not None:
|
||||||
|
enable_event = RisingEdge(self.enable)
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
await RisingEdge(self.clock)
|
await clock_edge_event
|
||||||
|
|
||||||
if self.enable is None or self.enable.value:
|
if self.enable is None or self.enable.value:
|
||||||
d_val = self.data.value.integer
|
d_val = self.data.value.integer
|
||||||
@@ -370,6 +400,12 @@ class MiiSink(Reset):
|
|||||||
frame.data.append(d_val)
|
frame.data.append(d_val)
|
||||||
frame.error.append(er_val)
|
frame.error.append(er_val)
|
||||||
|
|
||||||
|
if not dv_val:
|
||||||
|
await active_event
|
||||||
|
|
||||||
|
elif self.enable is not None and not self.enable.value:
|
||||||
|
await enable_event
|
||||||
|
|
||||||
|
|
||||||
class MiiPhy:
|
class MiiPhy:
|
||||||
def __init__(self, txd, tx_er, tx_en, tx_clk, rxd, rx_er, rx_dv, rx_clk, reset=None,
|
def __init__(self, txd, tx_er, tx_en, tx_clk, rxd, rx_er, rx_dv, rx_clk, reset=None,
|
||||||
@@ -398,7 +434,7 @@ class MiiPhy:
|
|||||||
if self._clock_cr is not None:
|
if self._clock_cr is not None:
|
||||||
self._clock_cr.kill()
|
self._clock_cr.kill()
|
||||||
|
|
||||||
self._clock_cr = cocotb.fork(self._run_clocks(4*1e9/self.speed))
|
self._clock_cr = cocotb.start_soon(self._run_clocks(4*1e9/self.speed))
|
||||||
|
|
||||||
async def _run_clocks(self, period):
|
async def _run_clocks(self, period):
|
||||||
half_period = get_sim_steps(period / 2.0, 'ns')
|
half_period = get_sim_steps(period / 2.0, 'ns')
|
||||||
@@ -406,8 +442,8 @@ class MiiPhy:
|
|||||||
|
|
||||||
while True:
|
while True:
|
||||||
await t
|
await t
|
||||||
self.tx_clk <= 1
|
self.tx_clk.value = 1
|
||||||
self.rx_clk <= 1
|
self.rx_clk.value = 1
|
||||||
await t
|
await t
|
||||||
self.tx_clk <= 0
|
self.tx_clk.value = 0
|
||||||
self.rx_clk <= 0
|
self.rx_clk.value = 0
|
||||||
|
|||||||
@@ -195,28 +195,30 @@ class PtpClock(Reset):
|
|||||||
self.ts_64_fns = 0
|
self.ts_64_fns = 0
|
||||||
self.drift_cnt = 0
|
self.drift_cnt = 0
|
||||||
if self.ts_96 is not None:
|
if self.ts_96 is not None:
|
||||||
self.ts_96 <= 0
|
self.ts_96.value = 0
|
||||||
if self.ts_64 is not None:
|
if self.ts_64 is not None:
|
||||||
self.ts_64 <= 0
|
self.ts_64.value = 0
|
||||||
if self.ts_step is not None:
|
if self.ts_step is not None:
|
||||||
self.ts_step <= 0
|
self.ts_step.value = 0
|
||||||
if self.pps is not None:
|
if self.pps is not None:
|
||||||
self.pps <= 0
|
self.pps.value = 0
|
||||||
else:
|
else:
|
||||||
self.log.info("Reset de-asserted")
|
self.log.info("Reset de-asserted")
|
||||||
if self._run_cr is None:
|
if self._run_cr is None:
|
||||||
self._run_cr = cocotb.fork(self._run())
|
self._run_cr = cocotb.start_soon(self._run())
|
||||||
|
|
||||||
async def _run(self):
|
async def _run(self):
|
||||||
|
clock_edge_event = RisingEdge(self.clock)
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
await RisingEdge(self.clock)
|
await clock_edge_event
|
||||||
|
|
||||||
if self.ts_step is not None:
|
if self.ts_step is not None:
|
||||||
self.ts_step <= self.ts_updated
|
self.ts_step.value = self.ts_updated
|
||||||
self.ts_updated = False
|
self.ts_updated = False
|
||||||
|
|
||||||
if self.pps is not None:
|
if self.pps is not None:
|
||||||
self.pps <= 0
|
self.pps.value = 0
|
||||||
|
|
||||||
# increment 96 bit timestamp
|
# increment 96 bit timestamp
|
||||||
if self.ts_96 is not None or self.pps is not None:
|
if self.ts_96 is not None or self.pps is not None:
|
||||||
@@ -229,13 +231,13 @@ class PtpClock(Reset):
|
|||||||
self.ts_96_s += 1
|
self.ts_96_s += 1
|
||||||
t -= (1000000000 << 16)
|
t -= (1000000000 << 16)
|
||||||
if self.pps is not None:
|
if self.pps is not None:
|
||||||
self.pps <= 1
|
self.pps.value = 1
|
||||||
|
|
||||||
self.ts_96_fns = t & 0xffff
|
self.ts_96_fns = t & 0xffff
|
||||||
self.ts_96_ns = t >> 16
|
self.ts_96_ns = t >> 16
|
||||||
|
|
||||||
if self.ts_96 is not None:
|
if self.ts_96 is not None:
|
||||||
self.ts_96 <= (self.ts_96_s << 48) | (self.ts_96_ns << 16) | (self.ts_96_fns)
|
self.ts_96.value = (self.ts_96_s << 48) | (self.ts_96_ns << 16) | (self.ts_96_fns)
|
||||||
|
|
||||||
# increment 64 bit timestamp
|
# increment 64 bit timestamp
|
||||||
if self.ts_64 is not None:
|
if self.ts_64 is not None:
|
||||||
@@ -247,7 +249,7 @@ class PtpClock(Reset):
|
|||||||
self.ts_64_fns = t & 0xffff
|
self.ts_64_fns = t & 0xffff
|
||||||
self.ts_64_ns = t >> 16
|
self.ts_64_ns = t >> 16
|
||||||
|
|
||||||
self.ts_64 <= (self.ts_64_ns << 16) | self.ts_64_fns
|
self.ts_64.value = (self.ts_64_ns << 16) | self.ts_64_fns
|
||||||
|
|
||||||
if self.drift_rate:
|
if self.drift_rate:
|
||||||
if self.drift_cnt > 0:
|
if self.drift_cnt > 0:
|
||||||
@@ -286,9 +288,9 @@ class PtpClockSimTime:
|
|||||||
if self.ts_64 is not None:
|
if self.ts_64 is not None:
|
||||||
self.ts_64.setimmediatevalue(0)
|
self.ts_64.setimmediatevalue(0)
|
||||||
if self.pps is not None:
|
if self.pps is not None:
|
||||||
self.pps <= 0
|
self.pps.value = 0
|
||||||
|
|
||||||
self._run_cr = cocotb.fork(self._run())
|
self._run_cr = cocotb.start_soon(self._run())
|
||||||
|
|
||||||
def get_ts_96(self):
|
def get_ts_96(self):
|
||||||
return (self.ts_96_s << 48) | (self.ts_96_ns << 16) | self.ts_96_fns
|
return (self.ts_96_s << 48) | (self.ts_96_ns << 16) | self.ts_96_fns
|
||||||
@@ -309,8 +311,10 @@ class PtpClockSimTime:
|
|||||||
return self.get_ts_64()*1e-9
|
return self.get_ts_64()*1e-9
|
||||||
|
|
||||||
async def _run(self):
|
async def _run(self):
|
||||||
|
clock_edge_event = RisingEdge(self.clock)
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
await RisingEdge(self.clock)
|
await clock_edge_event
|
||||||
|
|
||||||
self.ts_64_fns, self.ts_64_ns = math.modf(get_sim_time('ns'))
|
self.ts_64_fns, self.ts_64_ns = math.modf(get_sim_time('ns'))
|
||||||
|
|
||||||
@@ -321,12 +325,12 @@ class PtpClockSimTime:
|
|||||||
self.ts_96_fns = self.ts_64_fns
|
self.ts_96_fns = self.ts_64_fns
|
||||||
|
|
||||||
if self.ts_96 is not None:
|
if self.ts_96 is not None:
|
||||||
self.ts_96 <= (self.ts_96_s << 48) | (self.ts_96_ns << 16) | self.ts_96_fns
|
self.ts_96.value = (self.ts_96_s << 48) | (self.ts_96_ns << 16) | self.ts_96_fns
|
||||||
|
|
||||||
if self.ts_64 is not None:
|
if self.ts_64 is not None:
|
||||||
self.ts_64 <= (self.ts_64_ns << 16) | self.ts_64_fns
|
self.ts_64.value = (self.ts_64_ns << 16) | self.ts_64_fns
|
||||||
|
|
||||||
if self.pps is not None:
|
if self.pps is not None:
|
||||||
self.pps <= int(self.last_ts_96_s != self.ts_96_s)
|
self.pps.value = int(self.last_ts_96_s != self.ts_96_s)
|
||||||
|
|
||||||
self.last_ts_96_s = self.ts_96_s
|
self.last_ts_96_s = self.ts_96_s
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ class Reset:
|
|||||||
self._reset_state = True
|
self._reset_state = True
|
||||||
|
|
||||||
if reset_signal is not None:
|
if reset_signal is not None:
|
||||||
cocotb.fork(self._run_reset(reset_signal, bool(active_level)))
|
cocotb.start_soon(self._run_reset(reset_signal, bool(active_level)))
|
||||||
|
|
||||||
self._update_reset()
|
self._update_reset()
|
||||||
|
|
||||||
|
|||||||
@@ -61,6 +61,7 @@ class RgmiiSource(Reset):
|
|||||||
self.current_frame = None
|
self.current_frame = None
|
||||||
self.idle_event = Event()
|
self.idle_event = Event()
|
||||||
self.idle_event.set()
|
self.idle_event.set()
|
||||||
|
self.active_event = Event()
|
||||||
|
|
||||||
self.ifg = 12
|
self.ifg = 12
|
||||||
self.mii_mode = False
|
self.mii_mode = False
|
||||||
@@ -90,6 +91,7 @@ class RgmiiSource(Reset):
|
|||||||
frame = GmiiFrame(frame)
|
frame = GmiiFrame(frame)
|
||||||
await self.queue.put(frame)
|
await self.queue.put(frame)
|
||||||
self.idle_event.clear()
|
self.idle_event.clear()
|
||||||
|
self.active_event.set()
|
||||||
self.queue_occupancy_bytes += len(frame)
|
self.queue_occupancy_bytes += len(frame)
|
||||||
self.queue_occupancy_frames += 1
|
self.queue_occupancy_frames += 1
|
||||||
|
|
||||||
@@ -99,6 +101,7 @@ class RgmiiSource(Reset):
|
|||||||
frame = GmiiFrame(frame)
|
frame = GmiiFrame(frame)
|
||||||
self.queue.put_nowait(frame)
|
self.queue.put_nowait(frame)
|
||||||
self.idle_event.clear()
|
self.idle_event.clear()
|
||||||
|
self.active_event.set()
|
||||||
self.queue_occupancy_bytes += len(frame)
|
self.queue_occupancy_bytes += len(frame)
|
||||||
self.queue_occupancy_frames += 1
|
self.queue_occupancy_frames += 1
|
||||||
|
|
||||||
@@ -126,6 +129,7 @@ class RgmiiSource(Reset):
|
|||||||
frame.handle_tx_complete()
|
frame.handle_tx_complete()
|
||||||
self.dequeue_event.set()
|
self.dequeue_event.set()
|
||||||
self.idle_event.set()
|
self.idle_event.set()
|
||||||
|
self.active_event.clear()
|
||||||
self.queue_occupancy_bytes = 0
|
self.queue_occupancy_bytes = 0
|
||||||
self.queue_occupancy_frames = 0
|
self.queue_occupancy_frames = 0
|
||||||
|
|
||||||
@@ -140,8 +144,8 @@ class RgmiiSource(Reset):
|
|||||||
self._run_cr = None
|
self._run_cr = None
|
||||||
|
|
||||||
self.active = False
|
self.active = False
|
||||||
self.data <= 0
|
self.data.value = 0
|
||||||
self.ctrl <= 0
|
self.ctrl.value = 0
|
||||||
|
|
||||||
if self.current_frame:
|
if self.current_frame:
|
||||||
self.log.warning("Flushed transmit frame during reset: %s", self.current_frame)
|
self.log.warning("Flushed transmit frame during reset: %s", self.current_frame)
|
||||||
@@ -150,30 +154,51 @@ class RgmiiSource(Reset):
|
|||||||
|
|
||||||
if self.queue.empty():
|
if self.queue.empty():
|
||||||
self.idle_event.set()
|
self.idle_event.set()
|
||||||
|
self.active_event.clear()
|
||||||
else:
|
else:
|
||||||
self.log.info("Reset de-asserted")
|
self.log.info("Reset de-asserted")
|
||||||
if self._run_cr is None:
|
if self._run_cr is None:
|
||||||
self._run_cr = cocotb.fork(self._run())
|
self._run_cr = cocotb.start_soon(self._run())
|
||||||
|
|
||||||
async def _run(self):
|
async def _run(self):
|
||||||
frame = None
|
frame = None
|
||||||
|
frame_offset = 0
|
||||||
|
frame_data = None
|
||||||
|
frame_error = None
|
||||||
ifg_cnt = 0
|
ifg_cnt = 0
|
||||||
|
in_ifg = False
|
||||||
self.active = False
|
self.active = False
|
||||||
d = 0
|
d = 0
|
||||||
er = 0
|
er = 0
|
||||||
en = 0
|
en = 0
|
||||||
|
|
||||||
|
clock_rising_edge_event = RisingEdge(self.clock)
|
||||||
|
clock_falling_edge_event = FallingEdge(self.clock)
|
||||||
|
|
||||||
|
enable_event = None
|
||||||
|
if self.enable is not None:
|
||||||
|
enable_event = RisingEdge(self.enable)
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
await RisingEdge(self.clock)
|
await clock_falling_edge_event
|
||||||
|
|
||||||
|
# send low nibble after falling edge, leading in to rising edge
|
||||||
|
self.data.value = d & 0x0F
|
||||||
|
self.ctrl.value = en
|
||||||
|
|
||||||
|
await clock_rising_edge_event
|
||||||
|
|
||||||
# send high nibble after rising edge, leading in to falling edge
|
# send high nibble after rising edge, leading in to falling edge
|
||||||
self.data <= d >> 4
|
self.data.value = d >> 4
|
||||||
self.ctrl <= en ^ er
|
self.ctrl.value = en ^ er
|
||||||
|
|
||||||
if self.enable is None or self.enable.value:
|
if self.enable is None or self.enable.value:
|
||||||
|
in_ifg = False
|
||||||
|
|
||||||
if ifg_cnt > 0:
|
if ifg_cnt > 0:
|
||||||
# in IFG
|
# in IFG
|
||||||
ifg_cnt -= 1
|
ifg_cnt -= 1
|
||||||
|
in_ifg = True
|
||||||
|
|
||||||
elif frame is None and not self.queue.empty():
|
elif frame is None and not self.queue.empty():
|
||||||
# send frame
|
# send frame
|
||||||
@@ -192,28 +217,33 @@ class RgmiiSource(Reset):
|
|||||||
self.mii_mode = bool(self.mii_select.value.integer)
|
self.mii_mode = bool(self.mii_select.value.integer)
|
||||||
|
|
||||||
if self.mii_mode:
|
if self.mii_mode:
|
||||||
mii_data = []
|
# convert to MII
|
||||||
mii_error = []
|
frame_data = []
|
||||||
|
frame_error = []
|
||||||
for b, e in zip(frame.data, frame.error):
|
for b, e in zip(frame.data, frame.error):
|
||||||
mii_data.append((b & 0x0F)*0x11)
|
frame_data.append((b & 0x0F)*0x11)
|
||||||
mii_data.append((b >> 4)*0x11)
|
frame_data.append((b >> 4)*0x11)
|
||||||
mii_error.append(e)
|
frame_error.append(e)
|
||||||
mii_error.append(e)
|
frame_error.append(e)
|
||||||
frame.data = mii_data
|
else:
|
||||||
frame.error = mii_error
|
frame_data = frame.data
|
||||||
|
frame_error = frame.error
|
||||||
|
|
||||||
self.active = True
|
self.active = True
|
||||||
|
frame_offset = 0
|
||||||
|
|
||||||
if frame is not None:
|
if frame is not None:
|
||||||
d = frame.data.pop(0)
|
d = frame_data[frame_offset]
|
||||||
er = frame.error.pop(0)
|
er = frame_error[frame_offset]
|
||||||
en = 1
|
en = 1
|
||||||
|
frame_offset += 1
|
||||||
|
|
||||||
if frame.sim_time_sfd is None and d in (EthPre.SFD, 0xD, 0xDD):
|
if frame.sim_time_sfd is None and d in (EthPre.SFD, 0xD, 0xDD):
|
||||||
frame.sim_time_sfd = get_sim_time()
|
frame.sim_time_sfd = get_sim_time()
|
||||||
|
|
||||||
if not frame.data:
|
if frame_offset >= len(frame_data):
|
||||||
ifg_cnt = max(self.ifg, 1)
|
ifg_cnt = max(self.ifg, 1)
|
||||||
|
in_ifg = True
|
||||||
frame.sim_time_end = get_sim_time()
|
frame.sim_time_end = get_sim_time()
|
||||||
frame.handle_tx_complete()
|
frame.handle_tx_complete()
|
||||||
frame = None
|
frame = None
|
||||||
@@ -223,13 +253,14 @@ class RgmiiSource(Reset):
|
|||||||
er = 0
|
er = 0
|
||||||
en = 0
|
en = 0
|
||||||
self.active = False
|
self.active = False
|
||||||
|
|
||||||
|
if not in_ifg and self.queue.empty():
|
||||||
self.idle_event.set()
|
self.idle_event.set()
|
||||||
|
self.active_event.clear()
|
||||||
|
await self.active_event.wait()
|
||||||
|
|
||||||
await FallingEdge(self.clock)
|
elif self.enable is not None and not self.enable.value:
|
||||||
|
await enable_event
|
||||||
# send low nibble after falling edge, leading in to rising edge
|
|
||||||
self.data <= d & 0x0F
|
|
||||||
self.ctrl <= en
|
|
||||||
|
|
||||||
|
|
||||||
class RgmiiSink(Reset):
|
class RgmiiSink(Reset):
|
||||||
@@ -323,7 +354,7 @@ class RgmiiSink(Reset):
|
|||||||
else:
|
else:
|
||||||
self.log.info("Reset de-asserted")
|
self.log.info("Reset de-asserted")
|
||||||
if self._run_cr is None:
|
if self._run_cr is None:
|
||||||
self._run_cr = cocotb.fork(self._run())
|
self._run_cr = cocotb.start_soon(self._run())
|
||||||
|
|
||||||
async def _run(self):
|
async def _run(self):
|
||||||
frame = None
|
frame = None
|
||||||
@@ -332,21 +363,30 @@ class RgmiiSink(Reset):
|
|||||||
dv_val = 0
|
dv_val = 0
|
||||||
er_val = 0
|
er_val = 0
|
||||||
|
|
||||||
|
clock_rising_edge_event = RisingEdge(self.clock)
|
||||||
|
clock_falling_edge_event = FallingEdge(self.clock)
|
||||||
|
|
||||||
|
active_event = RisingEdge(self.ctrl)
|
||||||
|
|
||||||
|
enable_event = None
|
||||||
|
if self.enable is not None:
|
||||||
|
enable_event = RisingEdge(self.enable)
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
await RisingEdge(self.clock)
|
await clock_rising_edge_event
|
||||||
|
|
||||||
|
if self.enable is None or self.enable.value:
|
||||||
|
|
||||||
# capture low nibble on rising edge
|
# capture low nibble on rising edge
|
||||||
d_val = self.data.value.integer
|
d_val = self.data.value.integer
|
||||||
dv_val = self.ctrl.value.integer
|
dv_val = self.ctrl.value.integer
|
||||||
|
|
||||||
await FallingEdge(self.clock)
|
await clock_falling_edge_event
|
||||||
|
|
||||||
# capture high nibble on falling edge
|
# capture high nibble on falling edge
|
||||||
d_val |= self.data.value.integer << 4
|
d_val |= self.data.value.integer << 4
|
||||||
er_val = dv_val ^ self.ctrl.value.integer
|
er_val = dv_val ^ self.ctrl.value.integer
|
||||||
|
|
||||||
if self.enable is None or self.enable.value:
|
|
||||||
|
|
||||||
if frame is None:
|
if frame is None:
|
||||||
if dv_val:
|
if dv_val:
|
||||||
# start of frame
|
# start of frame
|
||||||
@@ -399,6 +439,12 @@ class RgmiiSink(Reset):
|
|||||||
frame.data.append(d_val)
|
frame.data.append(d_val)
|
||||||
frame.error.append(er_val)
|
frame.error.append(er_val)
|
||||||
|
|
||||||
|
if not dv_val:
|
||||||
|
await active_event
|
||||||
|
|
||||||
|
elif self.enable is not None and not self.enable.value:
|
||||||
|
await enable_event
|
||||||
|
|
||||||
|
|
||||||
class RgmiiPhy:
|
class RgmiiPhy:
|
||||||
def __init__(self, txd, tx_ctl, tx_clk, rxd, rx_ctl, rx_clk, reset=None,
|
def __init__(self, txd, tx_ctl, tx_clk, rxd, rx_ctl, rx_clk, reset=None,
|
||||||
@@ -427,11 +473,11 @@ class RgmiiPhy:
|
|||||||
self._clock_cr.kill()
|
self._clock_cr.kill()
|
||||||
|
|
||||||
if self.speed == 1000e6:
|
if self.speed == 1000e6:
|
||||||
self._clock_cr = cocotb.fork(self._run_clock(8*1e9/self.speed))
|
self._clock_cr = cocotb.start_soon(self._run_clock(8*1e9/self.speed))
|
||||||
self.tx.mii_mode = False
|
self.tx.mii_mode = False
|
||||||
self.rx.mii_mode = False
|
self.rx.mii_mode = False
|
||||||
else:
|
else:
|
||||||
self._clock_cr = cocotb.fork(self._run_clock(4*1e9/self.speed))
|
self._clock_cr = cocotb.start_soon(self._run_clock(4*1e9/self.speed))
|
||||||
self.tx.mii_mode = True
|
self.tx.mii_mode = True
|
||||||
self.rx.mii_mode = True
|
self.rx.mii_mode = True
|
||||||
|
|
||||||
@@ -441,6 +487,6 @@ class RgmiiPhy:
|
|||||||
|
|
||||||
while True:
|
while True:
|
||||||
await t
|
await t
|
||||||
self.rx_clk <= 1
|
self.rx_clk.value = 1
|
||||||
await t
|
await t
|
||||||
self.rx_clk <= 0
|
self.rx_clk.value = 0
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
__version__ = "0.1.12"
|
__version__ = "0.1.20"
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ import zlib
|
|||||||
|
|
||||||
import cocotb
|
import cocotb
|
||||||
from cocotb.queue import Queue, QueueFull
|
from cocotb.queue import Queue, QueueFull
|
||||||
from cocotb.triggers import RisingEdge, Timer, First, Event
|
from cocotb.triggers import Edge, RisingEdge, Timer, First, Event
|
||||||
from cocotb.utils import get_sim_time
|
from cocotb.utils import get_sim_time
|
||||||
|
|
||||||
from .version import __version__
|
from .version import __version__
|
||||||
@@ -158,6 +158,7 @@ class XgmiiSource(Reset):
|
|||||||
self.current_frame = None
|
self.current_frame = None
|
||||||
self.idle_event = Event()
|
self.idle_event = Event()
|
||||||
self.idle_event.set()
|
self.idle_event.set()
|
||||||
|
self.active_event = Event()
|
||||||
|
|
||||||
self.enable_dic = True
|
self.enable_dic = True
|
||||||
self.ifg = 12
|
self.ifg = 12
|
||||||
@@ -170,14 +171,19 @@ class XgmiiSource(Reset):
|
|||||||
self.queue_occupancy_limit_frames = -1
|
self.queue_occupancy_limit_frames = -1
|
||||||
|
|
||||||
self.width = len(self.data)
|
self.width = len(self.data)
|
||||||
self.byte_width = len(self.ctrl)
|
self.byte_size = 8
|
||||||
|
self.byte_lanes = len(self.ctrl)
|
||||||
|
|
||||||
assert self.width == self.byte_width * 8
|
assert self.width == self.byte_lanes * self.byte_size
|
||||||
|
|
||||||
|
self.log.info("XGMII source model configuration")
|
||||||
|
self.log.info(" Byte size: %d bits", self.byte_size)
|
||||||
|
self.log.info(" Data width: %d bits (%d bytes)", self.width, self.byte_lanes)
|
||||||
|
|
||||||
self.idle_d = 0
|
self.idle_d = 0
|
||||||
self.idle_c = 0
|
self.idle_c = 0
|
||||||
|
|
||||||
for k in range(self.byte_width):
|
for k in range(self.byte_lanes):
|
||||||
self.idle_d |= XgmiiCtrl.IDLE << k*8
|
self.idle_d |= XgmiiCtrl.IDLE << k*8
|
||||||
self.idle_c |= 1 << k
|
self.idle_c |= 1 << k
|
||||||
|
|
||||||
@@ -195,6 +201,7 @@ class XgmiiSource(Reset):
|
|||||||
frame = XgmiiFrame(frame)
|
frame = XgmiiFrame(frame)
|
||||||
await self.queue.put(frame)
|
await self.queue.put(frame)
|
||||||
self.idle_event.clear()
|
self.idle_event.clear()
|
||||||
|
self.active_event.set()
|
||||||
self.queue_occupancy_bytes += len(frame)
|
self.queue_occupancy_bytes += len(frame)
|
||||||
self.queue_occupancy_frames += 1
|
self.queue_occupancy_frames += 1
|
||||||
|
|
||||||
@@ -204,6 +211,7 @@ class XgmiiSource(Reset):
|
|||||||
frame = XgmiiFrame(frame)
|
frame = XgmiiFrame(frame)
|
||||||
self.queue.put_nowait(frame)
|
self.queue.put_nowait(frame)
|
||||||
self.idle_event.clear()
|
self.idle_event.clear()
|
||||||
|
self.active_event.set()
|
||||||
self.queue_occupancy_bytes += len(frame)
|
self.queue_occupancy_bytes += len(frame)
|
||||||
self.queue_occupancy_frames += 1
|
self.queue_occupancy_frames += 1
|
||||||
|
|
||||||
@@ -231,6 +239,7 @@ class XgmiiSource(Reset):
|
|||||||
frame.handle_tx_complete()
|
frame.handle_tx_complete()
|
||||||
self.dequeue_event.set()
|
self.dequeue_event.set()
|
||||||
self.idle_event.set()
|
self.idle_event.set()
|
||||||
|
self.active_event.clear()
|
||||||
self.queue_occupancy_bytes = 0
|
self.queue_occupancy_bytes = 0
|
||||||
self.queue_occupancy_frames = 0
|
self.queue_occupancy_frames = 0
|
||||||
|
|
||||||
@@ -245,8 +254,8 @@ class XgmiiSource(Reset):
|
|||||||
self._run_cr = None
|
self._run_cr = None
|
||||||
|
|
||||||
self.active = False
|
self.active = False
|
||||||
self.data <= 0
|
self.data.value = 0
|
||||||
self.ctrl <= 0
|
self.ctrl.value = 0
|
||||||
|
|
||||||
if self.current_frame:
|
if self.current_frame:
|
||||||
self.log.warning("Flushed transmit frame during reset: %s", self.current_frame)
|
self.log.warning("Flushed transmit frame during reset: %s", self.current_frame)
|
||||||
@@ -255,24 +264,32 @@ class XgmiiSource(Reset):
|
|||||||
|
|
||||||
if self.queue.empty():
|
if self.queue.empty():
|
||||||
self.idle_event.set()
|
self.idle_event.set()
|
||||||
|
self.active_event.clear()
|
||||||
else:
|
else:
|
||||||
self.log.info("Reset de-asserted")
|
self.log.info("Reset de-asserted")
|
||||||
if self._run_cr is None:
|
if self._run_cr is None:
|
||||||
self._run_cr = cocotb.fork(self._run())
|
self._run_cr = cocotb.start_soon(self._run())
|
||||||
|
|
||||||
async def _run(self):
|
async def _run(self):
|
||||||
frame = None
|
frame = None
|
||||||
|
frame_offset = 0
|
||||||
ifg_cnt = 0
|
ifg_cnt = 0
|
||||||
deficit_idle_cnt = 0
|
deficit_idle_cnt = 0
|
||||||
self.active = False
|
self.active = False
|
||||||
|
|
||||||
|
clock_edge_event = RisingEdge(self.clock)
|
||||||
|
|
||||||
|
enable_event = None
|
||||||
|
if self.enable is not None:
|
||||||
|
enable_event = RisingEdge(self.enable)
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
await RisingEdge(self.clock)
|
await clock_edge_event
|
||||||
|
|
||||||
if self.enable is None or self.enable.value:
|
if self.enable is None or self.enable.value:
|
||||||
if ifg_cnt + deficit_idle_cnt > self.byte_width-1 or (not self.enable_dic and ifg_cnt > 4):
|
if ifg_cnt + deficit_idle_cnt > self.byte_lanes-1 or (not self.enable_dic and ifg_cnt > 4):
|
||||||
# in IFG
|
# in IFG
|
||||||
ifg_cnt = ifg_cnt - self.byte_width
|
ifg_cnt = ifg_cnt - self.byte_lanes
|
||||||
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)
|
||||||
@@ -306,7 +323,7 @@ class XgmiiSource(Reset):
|
|||||||
else:
|
else:
|
||||||
min_ifg = 0
|
min_ifg = 0
|
||||||
|
|
||||||
if self.byte_width > 4 and (ifg_cnt > min_ifg or self.force_offset_start):
|
if self.byte_lanes > 4 and (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
|
||||||
@@ -316,6 +333,7 @@ class XgmiiSource(Reset):
|
|||||||
deficit_idle_cnt = max(deficit_idle_cnt+ifg_cnt, 0)
|
deficit_idle_cnt = max(deficit_idle_cnt+ifg_cnt, 0)
|
||||||
ifg_cnt = 0
|
ifg_cnt = 0
|
||||||
self.active = True
|
self.active = True
|
||||||
|
frame_offset = 0
|
||||||
else:
|
else:
|
||||||
# clear counters
|
# clear counters
|
||||||
deficit_idle_cnt = 0
|
deficit_idle_cnt = 0
|
||||||
@@ -325,16 +343,17 @@ class XgmiiSource(Reset):
|
|||||||
d_val = 0
|
d_val = 0
|
||||||
c_val = 0
|
c_val = 0
|
||||||
|
|
||||||
for k in range(self.byte_width):
|
for k in range(self.byte_lanes):
|
||||||
if frame is not None:
|
if frame is not None:
|
||||||
d = frame.data.pop(0)
|
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:
|
||||||
frame.sim_time_sfd = get_sim_time()
|
frame.sim_time_sfd = get_sim_time()
|
||||||
d_val |= d << k*8
|
d_val |= d << k*8
|
||||||
c_val |= frame.ctrl.pop(0) << k
|
c_val |= frame.ctrl[frame_offset] << k
|
||||||
|
frame_offset += 1
|
||||||
|
|
||||||
if not frame.data:
|
if frame_offset >= len(frame.data):
|
||||||
ifg_cnt = max(self.ifg - (self.byte_width-k), 0)
|
ifg_cnt = max(self.ifg - (self.byte_lanes-k), 0)
|
||||||
frame.sim_time_end = get_sim_time()
|
frame.sim_time_end = get_sim_time()
|
||||||
frame.handle_tx_complete()
|
frame.handle_tx_complete()
|
||||||
frame = None
|
frame = None
|
||||||
@@ -343,13 +362,20 @@ class XgmiiSource(Reset):
|
|||||||
d_val |= XgmiiCtrl.IDLE << k*8
|
d_val |= XgmiiCtrl.IDLE << k*8
|
||||||
c_val |= 1 << k
|
c_val |= 1 << k
|
||||||
|
|
||||||
self.data <= d_val
|
self.data.value = d_val
|
||||||
self.ctrl <= c_val
|
self.ctrl.value = c_val
|
||||||
else:
|
else:
|
||||||
self.data <= self.idle_d
|
self.data.value = self.idle_d
|
||||||
self.ctrl <= self.idle_c
|
self.ctrl.value = self.idle_c
|
||||||
self.active = False
|
self.active = False
|
||||||
|
|
||||||
|
if ifg_cnt == 0 and self.queue.empty():
|
||||||
self.idle_event.set()
|
self.idle_event.set()
|
||||||
|
self.active_event.clear()
|
||||||
|
await self.active_event.wait()
|
||||||
|
|
||||||
|
elif self.enable is not None and not self.enable.value:
|
||||||
|
await enable_event
|
||||||
|
|
||||||
|
|
||||||
class XgmiiSink(Reset):
|
class XgmiiSink(Reset):
|
||||||
@@ -377,9 +403,14 @@ class XgmiiSink(Reset):
|
|||||||
self.queue_occupancy_frames = 0
|
self.queue_occupancy_frames = 0
|
||||||
|
|
||||||
self.width = len(self.data)
|
self.width = len(self.data)
|
||||||
self.byte_width = len(self.ctrl)
|
self.byte_size = 8
|
||||||
|
self.byte_lanes = len(self.ctrl)
|
||||||
|
|
||||||
assert self.width == self.byte_width * 8
|
assert self.width == self.byte_lanes * self.byte_size
|
||||||
|
|
||||||
|
self.log.info("XGMII sink model configuration")
|
||||||
|
self.log.info(" Byte size: %d bits", self.byte_size)
|
||||||
|
self.log.info(" Data width: %d bits (%d bytes)", self.width, self.byte_lanes)
|
||||||
|
|
||||||
self._run_cr = None
|
self._run_cr = None
|
||||||
|
|
||||||
@@ -437,19 +468,32 @@ class XgmiiSink(Reset):
|
|||||||
else:
|
else:
|
||||||
self.log.info("Reset de-asserted")
|
self.log.info("Reset de-asserted")
|
||||||
if self._run_cr is None:
|
if self._run_cr is None:
|
||||||
self._run_cr = cocotb.fork(self._run())
|
self._run_cr = cocotb.start_soon(self._run())
|
||||||
|
|
||||||
async def _run(self):
|
async def _run(self):
|
||||||
frame = None
|
frame = None
|
||||||
self.active = False
|
self.active = False
|
||||||
|
|
||||||
|
clock_edge_event = RisingEdge(self.clock)
|
||||||
|
|
||||||
|
active_event = First(Edge(self.data), Edge(self.ctrl))
|
||||||
|
|
||||||
|
enable_event = None
|
||||||
|
if self.enable is not None:
|
||||||
|
enable_event = RisingEdge(self.enable)
|
||||||
|
|
||||||
|
idle_d = sum([XgmiiCtrl.IDLE << n*8 for n in range(self.byte_lanes)])
|
||||||
|
idle_c = 2**self.byte_lanes-1
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
await RisingEdge(self.clock)
|
await clock_edge_event
|
||||||
|
|
||||||
if self.enable is None or self.enable.value:
|
if self.enable is None or self.enable.value:
|
||||||
for offset in range(self.byte_width):
|
data_val = self.data.value.integer
|
||||||
d_val = (self.data.value.integer >> (offset*8)) & 0xff
|
ctrl_val = self.ctrl.value.integer
|
||||||
c_val = (self.ctrl.value.integer >> offset) & 1
|
for offset in range(self.byte_lanes):
|
||||||
|
d_val = (data_val >> (offset*8)) & 0xff
|
||||||
|
c_val = (ctrl_val >> offset) & 1
|
||||||
|
|
||||||
if frame is None:
|
if frame is None:
|
||||||
if c_val and d_val == XgmiiCtrl.START:
|
if c_val and d_val == XgmiiCtrl.START:
|
||||||
@@ -482,3 +526,9 @@ class XgmiiSink(Reset):
|
|||||||
|
|
||||||
frame.data.append(d_val)
|
frame.data.append(d_val)
|
||||||
frame.ctrl.append(c_val)
|
frame.ctrl.append(c_val)
|
||||||
|
|
||||||
|
if data_val == idle_d and ctrl_val == idle_c:
|
||||||
|
await active_event
|
||||||
|
|
||||||
|
elif self.enable is not None and not self.enable.value:
|
||||||
|
await enable_event
|
||||||
|
|||||||
33
setup.cfg
33
setup.cfg
@@ -17,17 +17,18 @@ long-description-content-type = text/markdown
|
|||||||
platforms = any
|
platforms = any
|
||||||
classifiers =
|
classifiers =
|
||||||
Development Status :: 3 - Alpha
|
Development Status :: 3 - Alpha
|
||||||
Programming Language :: Python :: 3
|
Framework :: cocotb
|
||||||
License :: OSI Approved :: MIT License
|
License :: OSI Approved :: MIT License
|
||||||
Operating System :: OS Independent
|
Operating System :: OS Independent
|
||||||
|
Programming Language :: Python :: 3
|
||||||
Topic :: Scientific/Engineering :: Electronic Design Automation (EDA)
|
Topic :: Scientific/Engineering :: Electronic Design Automation (EDA)
|
||||||
|
|
||||||
[options]
|
[options]
|
||||||
packages = find_namespace:
|
packages = find_namespace:
|
||||||
python_requires = >=3.6
|
python_requires = >=3.6
|
||||||
install_requires =
|
install_requires =
|
||||||
cocotb
|
cocotb >= 1.6.0
|
||||||
cocotbext-axi
|
cocotbext-axi >= 0.1.16
|
||||||
|
|
||||||
[options.extras_require]
|
[options.extras_require]
|
||||||
test =
|
test =
|
||||||
@@ -46,31 +47,39 @@ addopts =
|
|||||||
|
|
||||||
# tox configuration
|
# tox configuration
|
||||||
[tox:tox]
|
[tox:tox]
|
||||||
envlist = py36, py37, py38, py39
|
envlist = py37, py38, py39, py310
|
||||||
|
skip_missing_interpreters = true
|
||||||
|
minversion = 3.18.0
|
||||||
|
requires = virtualenv >= 16.1
|
||||||
|
|
||||||
[gh-actions]
|
[gh-actions]
|
||||||
python =
|
python =
|
||||||
3.6: py36
|
|
||||||
3.7: py37
|
3.7: py37
|
||||||
3.8: py38
|
3.8: py38
|
||||||
3.9: py39
|
3.9: py39
|
||||||
|
3.10: py310
|
||||||
|
|
||||||
[testenv]
|
[testenv]
|
||||||
setenv =
|
setenv =
|
||||||
COVERAGE=1
|
COVERAGE=1
|
||||||
|
usedevelop = True
|
||||||
|
|
||||||
deps =
|
deps =
|
||||||
pytest
|
pytest == 7.2.1
|
||||||
pytest-xdist
|
pytest-xdist == 3.1.0
|
||||||
cocotb-test
|
cocotb == 1.7.2
|
||||||
coverage
|
cocotb-bus == 0.2.1
|
||||||
pytest-cov
|
cocotb-test == 0.2.4
|
||||||
|
cocotbext-axi == 0.1.20
|
||||||
|
coverage == 7.0.5
|
||||||
|
pytest-cov == 4.0.0
|
||||||
|
|
||||||
commands =
|
commands =
|
||||||
pytest --cov=cocotbext --cov=tests --cov-branch -n auto
|
pytest --cov=cocotbext --cov=tests --cov-branch {posargs:-n auto --verbose}
|
||||||
bash -c 'find . -type f -name "\.coverage" | xargs coverage combine --append'
|
bash -c 'find . -type f -name "\.coverage" | xargs coverage combine --append'
|
||||||
|
coverage report
|
||||||
|
|
||||||
whitelist_externals =
|
allowlist_externals =
|
||||||
bash
|
bash
|
||||||
|
|
||||||
# combine if paths are different
|
# combine if paths are different
|
||||||
|
|||||||
@@ -45,8 +45,8 @@ class TB:
|
|||||||
self.log = logging.getLogger("cocotb.tb")
|
self.log = logging.getLogger("cocotb.tb")
|
||||||
self.log.setLevel(logging.DEBUG)
|
self.log.setLevel(logging.DEBUG)
|
||||||
|
|
||||||
cocotb.fork(Clock(dut.tx_clk, 6.4, units="ns").start())
|
cocotb.start_soon(Clock(dut.tx_clk, 6.4, units="ns").start())
|
||||||
cocotb.fork(Clock(dut.rx_clk, 6.4, units="ns").start())
|
cocotb.start_soon(Clock(dut.rx_clk, 6.4, units="ns").start())
|
||||||
|
|
||||||
self.mac = EthMac(
|
self.mac = EthMac(
|
||||||
tx_clk=dut.tx_clk,
|
tx_clk=dut.tx_clk,
|
||||||
@@ -54,6 +54,7 @@ class TB:
|
|||||||
tx_bus=AxiStreamBus.from_prefix(dut, "tx_axis"),
|
tx_bus=AxiStreamBus.from_prefix(dut, "tx_axis"),
|
||||||
tx_ptp_time=dut.tx_ptp_time,
|
tx_ptp_time=dut.tx_ptp_time,
|
||||||
tx_ptp_ts=dut.tx_ptp_ts,
|
tx_ptp_ts=dut.tx_ptp_ts,
|
||||||
|
tx_ptp_ts_tag=dut.tx_ptp_ts_tag,
|
||||||
tx_ptp_ts_valid=dut.tx_ptp_ts_valid,
|
tx_ptp_ts_valid=dut.tx_ptp_ts_valid,
|
||||||
rx_clk=dut.rx_clk,
|
rx_clk=dut.rx_clk,
|
||||||
rx_rst=dut.rx_rst,
|
rx_rst=dut.rx_rst,
|
||||||
@@ -80,12 +81,12 @@ class TB:
|
|||||||
self.dut.rx_rst.setimmediatevalue(0)
|
self.dut.rx_rst.setimmediatevalue(0)
|
||||||
await RisingEdge(self.dut.tx_clk)
|
await RisingEdge(self.dut.tx_clk)
|
||||||
await RisingEdge(self.dut.tx_clk)
|
await RisingEdge(self.dut.tx_clk)
|
||||||
self.dut.tx_rst <= 1
|
self.dut.tx_rst.value = 1
|
||||||
self.dut.rx_rst <= 1
|
self.dut.rx_rst.value = 1
|
||||||
await RisingEdge(self.dut.tx_clk)
|
await RisingEdge(self.dut.tx_clk)
|
||||||
await RisingEdge(self.dut.tx_clk)
|
await RisingEdge(self.dut.tx_clk)
|
||||||
self.dut.tx_rst <= 0
|
self.dut.tx_rst.value = 0
|
||||||
self.dut.rx_rst <= 0
|
self.dut.rx_rst.value = 0
|
||||||
await RisingEdge(self.dut.tx_clk)
|
await RisingEdge(self.dut.tx_clk)
|
||||||
await RisingEdge(self.dut.tx_clk)
|
await RisingEdge(self.dut.tx_clk)
|
||||||
|
|
||||||
|
|||||||
@@ -36,11 +36,12 @@ module test_eth_mac
|
|||||||
inout wire [63:0] tx_axis_tdata,
|
inout wire [63:0] tx_axis_tdata,
|
||||||
inout wire [7:0] tx_axis_tkeep,
|
inout wire [7:0] tx_axis_tkeep,
|
||||||
inout wire tx_axis_tlast,
|
inout wire tx_axis_tlast,
|
||||||
inout wire tx_axis_tuser,
|
inout wire [16:0] tx_axis_tuser,
|
||||||
inout wire tx_axis_tvalid,
|
inout wire tx_axis_tvalid,
|
||||||
inout wire tx_axis_tready,
|
inout wire tx_axis_tready,
|
||||||
inout wire [95:0] tx_ptp_time,
|
inout wire [95:0] tx_ptp_time,
|
||||||
inout wire [95:0] tx_ptp_ts,
|
inout wire [95:0] tx_ptp_ts,
|
||||||
|
inout wire [15:0] tx_ptp_ts_tag,
|
||||||
inout wire tx_ptp_ts_valid,
|
inout wire tx_ptp_ts_valid,
|
||||||
|
|
||||||
inout wire rx_clk,
|
inout wire rx_clk,
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ class TB:
|
|||||||
self._enable_generator = None
|
self._enable_generator = None
|
||||||
self._enable_cr = None
|
self._enable_cr = None
|
||||||
|
|
||||||
cocotb.fork(Clock(dut.clk, 2, units="ns").start())
|
cocotb.start_soon(Clock(dut.clk, 2, units="ns").start())
|
||||||
|
|
||||||
self.source = GmiiSource(dut.gmii_d, dut.gmii_er, dut.gmii_en,
|
self.source = GmiiSource(dut.gmii_d, dut.gmii_er, dut.gmii_en,
|
||||||
dut.clk, dut.rst, dut.gmii_clk_en, dut.gmii_mii_sel)
|
dut.clk, dut.rst, dut.gmii_clk_en, dut.gmii_mii_sel)
|
||||||
@@ -61,10 +61,10 @@ class TB:
|
|||||||
self.dut.rst.setimmediatevalue(0)
|
self.dut.rst.setimmediatevalue(0)
|
||||||
await RisingEdge(self.dut.clk)
|
await RisingEdge(self.dut.clk)
|
||||||
await RisingEdge(self.dut.clk)
|
await RisingEdge(self.dut.clk)
|
||||||
self.dut.rst <= 1
|
self.dut.rst.value = 1
|
||||||
await RisingEdge(self.dut.clk)
|
await RisingEdge(self.dut.clk)
|
||||||
await RisingEdge(self.dut.clk)
|
await RisingEdge(self.dut.clk)
|
||||||
self.dut.rst <= 0
|
self.dut.rst.value = 0
|
||||||
await RisingEdge(self.dut.clk)
|
await RisingEdge(self.dut.clk)
|
||||||
await RisingEdge(self.dut.clk)
|
await RisingEdge(self.dut.clk)
|
||||||
|
|
||||||
@@ -76,15 +76,17 @@ class TB:
|
|||||||
self._enable_generator = generator
|
self._enable_generator = generator
|
||||||
|
|
||||||
if self._enable_generator is not None:
|
if self._enable_generator is not None:
|
||||||
self._enable_cr = cocotb.fork(self._run_enable())
|
self._enable_cr = cocotb.start_soon(self._run_enable())
|
||||||
|
|
||||||
def clear_enable_generator(self):
|
def clear_enable_generator(self):
|
||||||
self.set_enable_generator(None)
|
self.set_enable_generator(None)
|
||||||
|
|
||||||
async def _run_enable(self):
|
async def _run_enable(self):
|
||||||
|
clock_edge_event = RisingEdge(self.dut.clk)
|
||||||
|
|
||||||
for val in self._enable_generator:
|
for val in self._enable_generator:
|
||||||
self.dut.gmii_clk_en <= val
|
self.dut.gmii_clk_en.value = val
|
||||||
await RisingEdge(self.dut.clk)
|
await clock_edge_event
|
||||||
|
|
||||||
|
|
||||||
async def run_test(dut, payload_lengths=None, payload_data=None, ifg=12, enable_gen=None, mii_sel=False):
|
async def run_test(dut, payload_lengths=None, payload_data=None, ifg=12, enable_gen=None, mii_sel=False):
|
||||||
@@ -92,7 +94,7 @@ async def run_test(dut, payload_lengths=None, payload_data=None, ifg=12, enable_
|
|||||||
tb = TB(dut)
|
tb = TB(dut)
|
||||||
|
|
||||||
tb.source.ifg = ifg
|
tb.source.ifg = ifg
|
||||||
tb.dut.gmii_mii_sel <= mii_sel
|
tb.dut.gmii_mii_sel.value = mii_sel
|
||||||
|
|
||||||
if enable_gen is not None:
|
if enable_gen is not None:
|
||||||
tb.set_enable_generator(enable_gen())
|
tb.set_enable_generator(enable_gen())
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ class TB:
|
|||||||
self.log = logging.getLogger("cocotb.tb")
|
self.log = logging.getLogger("cocotb.tb")
|
||||||
self.log.setLevel(logging.DEBUG)
|
self.log.setLevel(logging.DEBUG)
|
||||||
|
|
||||||
cocotb.fork(Clock(dut.phy_gtx_clk, 8, units="ns").start())
|
cocotb.start_soon(Clock(dut.phy_gtx_clk, 8, units="ns").start())
|
||||||
|
|
||||||
self.gmii_phy = GmiiPhy(dut.phy_txd, dut.phy_tx_er, dut.phy_tx_en, dut.phy_tx_clk, dut.phy_gtx_clk,
|
self.gmii_phy = GmiiPhy(dut.phy_txd, dut.phy_tx_er, dut.phy_tx_en, dut.phy_tx_clk, dut.phy_gtx_clk,
|
||||||
dut.phy_rxd, dut.phy_rx_er, dut.phy_rx_dv, dut.phy_rx_clk, dut.phy_rst, speed=speed)
|
dut.phy_rxd, dut.phy_rx_er, dut.phy_rx_dv, dut.phy_rx_clk, dut.phy_rst, speed=speed)
|
||||||
@@ -64,10 +64,10 @@ class TB:
|
|||||||
self.dut.phy_rst.setimmediatevalue(0)
|
self.dut.phy_rst.setimmediatevalue(0)
|
||||||
await RisingEdge(self.dut.phy_tx_clk)
|
await RisingEdge(self.dut.phy_tx_clk)
|
||||||
await RisingEdge(self.dut.phy_tx_clk)
|
await RisingEdge(self.dut.phy_tx_clk)
|
||||||
self.dut.phy_rst <= 1
|
self.dut.phy_rst.value = 1
|
||||||
await RisingEdge(self.dut.phy_tx_clk)
|
await RisingEdge(self.dut.phy_tx_clk)
|
||||||
await RisingEdge(self.dut.phy_tx_clk)
|
await RisingEdge(self.dut.phy_tx_clk)
|
||||||
self.dut.phy_rst <= 0
|
self.dut.phy_rst.value = 0
|
||||||
await RisingEdge(self.dut.phy_tx_clk)
|
await RisingEdge(self.dut.phy_tx_clk)
|
||||||
await RisingEdge(self.dut.phy_tx_clk)
|
await RisingEdge(self.dut.phy_tx_clk)
|
||||||
|
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ class TB:
|
|||||||
self._enable_generator = None
|
self._enable_generator = None
|
||||||
self._enable_cr = None
|
self._enable_cr = None
|
||||||
|
|
||||||
cocotb.fork(Clock(dut.clk, 2, units="ns").start())
|
cocotb.start_soon(Clock(dut.clk, 2, units="ns").start())
|
||||||
|
|
||||||
self.source = MiiSource(dut.mii_d, dut.mii_er, dut.mii_en,
|
self.source = MiiSource(dut.mii_d, dut.mii_er, dut.mii_en,
|
||||||
dut.clk, dut.rst, dut.mii_clk_en)
|
dut.clk, dut.rst, dut.mii_clk_en)
|
||||||
@@ -60,10 +60,10 @@ class TB:
|
|||||||
self.dut.rst.setimmediatevalue(0)
|
self.dut.rst.setimmediatevalue(0)
|
||||||
await RisingEdge(self.dut.clk)
|
await RisingEdge(self.dut.clk)
|
||||||
await RisingEdge(self.dut.clk)
|
await RisingEdge(self.dut.clk)
|
||||||
self.dut.rst <= 1
|
self.dut.rst.value = 1
|
||||||
await RisingEdge(self.dut.clk)
|
await RisingEdge(self.dut.clk)
|
||||||
await RisingEdge(self.dut.clk)
|
await RisingEdge(self.dut.clk)
|
||||||
self.dut.rst <= 0
|
self.dut.rst.value = 0
|
||||||
await RisingEdge(self.dut.clk)
|
await RisingEdge(self.dut.clk)
|
||||||
await RisingEdge(self.dut.clk)
|
await RisingEdge(self.dut.clk)
|
||||||
|
|
||||||
@@ -75,15 +75,17 @@ class TB:
|
|||||||
self._enable_generator = generator
|
self._enable_generator = generator
|
||||||
|
|
||||||
if self._enable_generator is not None:
|
if self._enable_generator is not None:
|
||||||
self._enable_cr = cocotb.fork(self._run_enable())
|
self._enable_cr = cocotb.start_soon(self._run_enable())
|
||||||
|
|
||||||
def clear_enable_generator(self):
|
def clear_enable_generator(self):
|
||||||
self.set_enable_generator(None)
|
self.set_enable_generator(None)
|
||||||
|
|
||||||
async def _run_enable(self):
|
async def _run_enable(self):
|
||||||
|
clock_edge_event = RisingEdge(self.dut.clk)
|
||||||
|
|
||||||
for val in self._enable_generator:
|
for val in self._enable_generator:
|
||||||
self.dut.mii_clk_en <= val
|
self.dut.mii_clk_en.value = val
|
||||||
await RisingEdge(self.dut.clk)
|
await clock_edge_event
|
||||||
|
|
||||||
|
|
||||||
async def run_test(dut, payload_lengths=None, payload_data=None, ifg=12, enable_gen=None):
|
async def run_test(dut, payload_lengths=None, payload_data=None, ifg=12, enable_gen=None):
|
||||||
|
|||||||
@@ -55,10 +55,10 @@ class TB:
|
|||||||
self.dut.phy_rst.setimmediatevalue(0)
|
self.dut.phy_rst.setimmediatevalue(0)
|
||||||
await RisingEdge(self.dut.phy_tx_clk)
|
await RisingEdge(self.dut.phy_tx_clk)
|
||||||
await RisingEdge(self.dut.phy_tx_clk)
|
await RisingEdge(self.dut.phy_tx_clk)
|
||||||
self.dut.phy_rst <= 1
|
self.dut.phy_rst.value = 1
|
||||||
await RisingEdge(self.dut.phy_tx_clk)
|
await RisingEdge(self.dut.phy_tx_clk)
|
||||||
await RisingEdge(self.dut.phy_tx_clk)
|
await RisingEdge(self.dut.phy_tx_clk)
|
||||||
self.dut.phy_rst <= 0
|
self.dut.phy_rst.value = 0
|
||||||
await RisingEdge(self.dut.phy_tx_clk)
|
await RisingEdge(self.dut.phy_tx_clk)
|
||||||
await RisingEdge(self.dut.phy_tx_clk)
|
await RisingEdge(self.dut.phy_tx_clk)
|
||||||
|
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ import cocotb_test.simulator
|
|||||||
|
|
||||||
import cocotb
|
import cocotb
|
||||||
from cocotb.clock import Clock
|
from cocotb.clock import Clock
|
||||||
from cocotb.triggers import RisingEdge
|
from cocotb.triggers import RisingEdge, ClockCycles
|
||||||
from cocotb.utils import get_sim_time
|
from cocotb.utils import get_sim_time
|
||||||
|
|
||||||
from cocotbext.eth import PtpClock
|
from cocotbext.eth import PtpClock
|
||||||
@@ -43,7 +43,7 @@ class TB:
|
|||||||
self.log = logging.getLogger("cocotb.tb")
|
self.log = logging.getLogger("cocotb.tb")
|
||||||
self.log.setLevel(logging.DEBUG)
|
self.log.setLevel(logging.DEBUG)
|
||||||
|
|
||||||
cocotb.fork(Clock(dut.clk, 6.4, units="ns").start())
|
cocotb.start_soon(Clock(dut.clk, 6.4, units="ns").start())
|
||||||
|
|
||||||
self.ptp_clock = PtpClock(
|
self.ptp_clock = PtpClock(
|
||||||
ts_96=dut.ts_96,
|
ts_96=dut.ts_96,
|
||||||
@@ -59,10 +59,10 @@ class TB:
|
|||||||
self.dut.rst.setimmediatevalue(0)
|
self.dut.rst.setimmediatevalue(0)
|
||||||
await RisingEdge(self.dut.clk)
|
await RisingEdge(self.dut.clk)
|
||||||
await RisingEdge(self.dut.clk)
|
await RisingEdge(self.dut.clk)
|
||||||
self.dut.rst <= 1
|
self.dut.rst.value = 1
|
||||||
await RisingEdge(self.dut.clk)
|
await RisingEdge(self.dut.clk)
|
||||||
await RisingEdge(self.dut.clk)
|
await RisingEdge(self.dut.clk)
|
||||||
self.dut.rst <= 0
|
self.dut.rst.value = 0
|
||||||
await RisingEdge(self.dut.clk)
|
await RisingEdge(self.dut.clk)
|
||||||
await RisingEdge(self.dut.clk)
|
await RisingEdge(self.dut.clk)
|
||||||
|
|
||||||
@@ -79,8 +79,7 @@ async def run_default_rate(dut):
|
|||||||
start_ts_96 = (dut.ts_96.value.integer >> 48) + ((dut.ts_96.value.integer & 0xffffffffffff)/2**16*1e-9)
|
start_ts_96 = (dut.ts_96.value.integer >> 48) + ((dut.ts_96.value.integer & 0xffffffffffff)/2**16*1e-9)
|
||||||
start_ts_64 = dut.ts_64.value.integer/2**16*1e-9
|
start_ts_64 = dut.ts_64.value.integer/2**16*1e-9
|
||||||
|
|
||||||
for k in range(10000):
|
await ClockCycles(dut.clk, 10000)
|
||||||
await RisingEdge(dut.clk)
|
|
||||||
|
|
||||||
stop_time = get_sim_time('sec')
|
stop_time = get_sim_time('sec')
|
||||||
stop_ts_96 = (dut.ts_96.value.integer >> 48) + ((dut.ts_96.value.integer & 0xffffffffffff)/2**16*1e-9)
|
stop_ts_96 = (dut.ts_96.value.integer >> 48) + ((dut.ts_96.value.integer & 0xffffffffffff)/2**16*1e-9)
|
||||||
@@ -126,8 +125,7 @@ async def run_load_timestamps(dut):
|
|||||||
start_ts_96 = (dut.ts_96.value.integer >> 48) + ((dut.ts_96.value.integer & 0xffffffffffff)/2**16*1e-9)
|
start_ts_96 = (dut.ts_96.value.integer >> 48) + ((dut.ts_96.value.integer & 0xffffffffffff)/2**16*1e-9)
|
||||||
start_ts_64 = dut.ts_64.value.integer/2**16*1e-9
|
start_ts_64 = dut.ts_64.value.integer/2**16*1e-9
|
||||||
|
|
||||||
for k in range(2000):
|
await ClockCycles(dut.clk, 2000)
|
||||||
await RisingEdge(dut.clk)
|
|
||||||
|
|
||||||
stop_time = get_sim_time('sec')
|
stop_time = get_sim_time('sec')
|
||||||
stop_ts_96 = (dut.ts_96.value.integer >> 48) + ((dut.ts_96.value.integer & 0xffffffffffff)/2**16*1e-9)
|
stop_ts_96 = (dut.ts_96.value.integer >> 48) + ((dut.ts_96.value.integer & 0xffffffffffff)/2**16*1e-9)
|
||||||
@@ -221,8 +219,7 @@ async def run_frequency_adjustment(dut):
|
|||||||
start_ts_96 = (dut.ts_96.value.integer >> 48) + ((dut.ts_96.value.integer & 0xffffffffffff)/2**16*1e-9)
|
start_ts_96 = (dut.ts_96.value.integer >> 48) + ((dut.ts_96.value.integer & 0xffffffffffff)/2**16*1e-9)
|
||||||
start_ts_64 = dut.ts_64.value.integer/2**16*1e-9
|
start_ts_64 = dut.ts_64.value.integer/2**16*1e-9
|
||||||
|
|
||||||
for k in range(10000):
|
await ClockCycles(dut.clk, 10000)
|
||||||
await RisingEdge(dut.clk)
|
|
||||||
|
|
||||||
stop_time = get_sim_time('sec')
|
stop_time = get_sim_time('sec')
|
||||||
stop_ts_96 = (dut.ts_96.value.integer >> 48) + ((dut.ts_96.value.integer & 0xffffffffffff)/2**16*1e-9)
|
stop_ts_96 = (dut.ts_96.value.integer >> 48) + ((dut.ts_96.value.integer & 0xffffffffffff)/2**16*1e-9)
|
||||||
@@ -264,8 +261,7 @@ async def run_drift_adjustment(dut):
|
|||||||
start_ts_96 = (dut.ts_96.value.integer >> 48) + ((dut.ts_96.value.integer & 0xffffffffffff)/2**16*1e-9)
|
start_ts_96 = (dut.ts_96.value.integer >> 48) + ((dut.ts_96.value.integer & 0xffffffffffff)/2**16*1e-9)
|
||||||
start_ts_64 = dut.ts_64.value.integer/2**16*1e-9
|
start_ts_64 = dut.ts_64.value.integer/2**16*1e-9
|
||||||
|
|
||||||
for k in range(10000):
|
await ClockCycles(dut.clk, 10000)
|
||||||
await RisingEdge(dut.clk)
|
|
||||||
|
|
||||||
stop_time = get_sim_time('sec')
|
stop_time = get_sim_time('sec')
|
||||||
stop_ts_96 = (dut.ts_96.value.integer >> 48) + ((dut.ts_96.value.integer & 0xffffffffffff)/2**16*1e-9)
|
stop_ts_96 = (dut.ts_96.value.integer >> 48) + ((dut.ts_96.value.integer & 0xffffffffffff)/2**16*1e-9)
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ import cocotb_test.simulator
|
|||||||
|
|
||||||
import cocotb
|
import cocotb
|
||||||
from cocotb.clock import Clock
|
from cocotb.clock import Clock
|
||||||
from cocotb.triggers import RisingEdge
|
from cocotb.triggers import RisingEdge, ClockCycles
|
||||||
from cocotb.utils import get_sim_time
|
from cocotb.utils import get_sim_time
|
||||||
|
|
||||||
from cocotbext.eth import PtpClockSimTime
|
from cocotbext.eth import PtpClockSimTime
|
||||||
@@ -43,7 +43,7 @@ class TB:
|
|||||||
self.log = logging.getLogger("cocotb.tb")
|
self.log = logging.getLogger("cocotb.tb")
|
||||||
self.log.setLevel(logging.DEBUG)
|
self.log.setLevel(logging.DEBUG)
|
||||||
|
|
||||||
cocotb.fork(Clock(dut.clk, 6.4, units="ns").start())
|
cocotb.start_soon(Clock(dut.clk, 6.4, units="ns").start())
|
||||||
|
|
||||||
self.ptp_clock = PtpClockSimTime(
|
self.ptp_clock = PtpClockSimTime(
|
||||||
ts_96=dut.ts_96,
|
ts_96=dut.ts_96,
|
||||||
@@ -66,8 +66,7 @@ async def run_test(dut):
|
|||||||
start_ts_96 = (dut.ts_96.value.integer >> 48) + ((dut.ts_96.value.integer & 0xffffffffffff)/2**16*1e-9)
|
start_ts_96 = (dut.ts_96.value.integer >> 48) + ((dut.ts_96.value.integer & 0xffffffffffff)/2**16*1e-9)
|
||||||
start_ts_64 = dut.ts_64.value.integer/2**16*1e-9
|
start_ts_64 = dut.ts_64.value.integer/2**16*1e-9
|
||||||
|
|
||||||
for k in range(10000):
|
await ClockCycles(dut.clk, 10000)
|
||||||
await RisingEdge(dut.clk)
|
|
||||||
|
|
||||||
stop_time = get_sim_time('sec')
|
stop_time = get_sim_time('sec')
|
||||||
stop_ts_96 = (dut.ts_96.value.integer >> 48) + ((dut.ts_96.value.integer & 0xffffffffffff)/2**16*1e-9)
|
stop_ts_96 = (dut.ts_96.value.integer >> 48) + ((dut.ts_96.value.integer & 0xffffffffffff)/2**16*1e-9)
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ class TB:
|
|||||||
self._enable_generator = None
|
self._enable_generator = None
|
||||||
self._enable_cr = None
|
self._enable_cr = None
|
||||||
|
|
||||||
cocotb.fork(Clock(dut.clk, 2, units="ns").start())
|
cocotb.start_soon(Clock(dut.clk, 2, units="ns").start())
|
||||||
|
|
||||||
self.source = RgmiiSource(dut.rgmii_d, dut.rgmii_ctl, dut.clk, dut.rst, dut.rgmii_clk_en, dut.rgmii_mii_sel)
|
self.source = RgmiiSource(dut.rgmii_d, dut.rgmii_ctl, dut.clk, dut.rst, dut.rgmii_clk_en, dut.rgmii_mii_sel)
|
||||||
self.sink = RgmiiSink(dut.rgmii_d, dut.rgmii_ctl, dut.clk, dut.rst, dut.rgmii_clk_en, dut.rgmii_mii_sel)
|
self.sink = RgmiiSink(dut.rgmii_d, dut.rgmii_ctl, dut.clk, dut.rst, dut.rgmii_clk_en, dut.rgmii_mii_sel)
|
||||||
@@ -59,10 +59,10 @@ class TB:
|
|||||||
self.dut.rst.setimmediatevalue(0)
|
self.dut.rst.setimmediatevalue(0)
|
||||||
await RisingEdge(self.dut.clk)
|
await RisingEdge(self.dut.clk)
|
||||||
await RisingEdge(self.dut.clk)
|
await RisingEdge(self.dut.clk)
|
||||||
self.dut.rst <= 1
|
self.dut.rst.value = 1
|
||||||
await RisingEdge(self.dut.clk)
|
await RisingEdge(self.dut.clk)
|
||||||
await RisingEdge(self.dut.clk)
|
await RisingEdge(self.dut.clk)
|
||||||
self.dut.rst <= 0
|
self.dut.rst.value = 0
|
||||||
await RisingEdge(self.dut.clk)
|
await RisingEdge(self.dut.clk)
|
||||||
await RisingEdge(self.dut.clk)
|
await RisingEdge(self.dut.clk)
|
||||||
|
|
||||||
@@ -74,15 +74,17 @@ class TB:
|
|||||||
self._enable_generator = generator
|
self._enable_generator = generator
|
||||||
|
|
||||||
if self._enable_generator is not None:
|
if self._enable_generator is not None:
|
||||||
self._enable_cr = cocotb.fork(self._run_enable())
|
self._enable_cr = cocotb.start_soon(self._run_enable())
|
||||||
|
|
||||||
def clear_enable_generator(self):
|
def clear_enable_generator(self):
|
||||||
self.set_enable_generator(None)
|
self.set_enable_generator(None)
|
||||||
|
|
||||||
async def _run_enable(self):
|
async def _run_enable(self):
|
||||||
|
clock_edge_event = RisingEdge(self.dut.clk)
|
||||||
|
|
||||||
for val in self._enable_generator:
|
for val in self._enable_generator:
|
||||||
self.dut.rgmii_clk_en <= val
|
self.dut.rgmii_clk_en.value = val
|
||||||
await RisingEdge(self.dut.clk)
|
await clock_edge_event
|
||||||
|
|
||||||
|
|
||||||
async def run_test(dut, payload_lengths=None, payload_data=None, ifg=12, enable_gen=None, mii_sel=False):
|
async def run_test(dut, payload_lengths=None, payload_data=None, ifg=12, enable_gen=None, mii_sel=False):
|
||||||
@@ -90,7 +92,7 @@ async def run_test(dut, payload_lengths=None, payload_data=None, ifg=12, enable_
|
|||||||
tb = TB(dut)
|
tb = TB(dut)
|
||||||
|
|
||||||
tb.source.ifg = ifg
|
tb.source.ifg = ifg
|
||||||
tb.dut.rgmii_mii_sel <= mii_sel
|
tb.dut.rgmii_mii_sel.value = mii_sel
|
||||||
|
|
||||||
if enable_gen is not None:
|
if enable_gen is not None:
|
||||||
tb.set_enable_generator(enable_gen())
|
tb.set_enable_generator(enable_gen())
|
||||||
|
|||||||
@@ -45,11 +45,11 @@ class TB:
|
|||||||
self.log.setLevel(logging.DEBUG)
|
self.log.setLevel(logging.DEBUG)
|
||||||
|
|
||||||
if speed == 1000e6:
|
if speed == 1000e6:
|
||||||
cocotb.fork(Clock(dut.phy_tx_clk, 8, units="ns").start())
|
cocotb.start_soon(Clock(dut.phy_tx_clk, 8, units="ns").start())
|
||||||
elif speed == 100e6:
|
elif speed == 100e6:
|
||||||
cocotb.fork(Clock(dut.phy_tx_clk, 40, units="ns").start())
|
cocotb.start_soon(Clock(dut.phy_tx_clk, 40, units="ns").start())
|
||||||
elif speed == 10e6:
|
elif speed == 10e6:
|
||||||
cocotb.fork(Clock(dut.phy_tx_clk, 400, units="ns").start())
|
cocotb.start_soon(Clock(dut.phy_tx_clk, 400, units="ns").start())
|
||||||
|
|
||||||
self.rgmii_phy = RgmiiPhy(dut.phy_txd, dut.phy_tx_ctl, dut.phy_tx_clk,
|
self.rgmii_phy = RgmiiPhy(dut.phy_txd, dut.phy_tx_ctl, dut.phy_tx_clk,
|
||||||
dut.phy_rxd, dut.phy_rx_ctl, dut.phy_rx_clk, dut.phy_rst, speed=speed)
|
dut.phy_rxd, dut.phy_rx_ctl, dut.phy_rx_clk, dut.phy_rst, speed=speed)
|
||||||
@@ -68,10 +68,10 @@ class TB:
|
|||||||
self.dut.phy_rst.setimmediatevalue(0)
|
self.dut.phy_rst.setimmediatevalue(0)
|
||||||
await RisingEdge(self.dut.phy_tx_clk)
|
await RisingEdge(self.dut.phy_tx_clk)
|
||||||
await RisingEdge(self.dut.phy_tx_clk)
|
await RisingEdge(self.dut.phy_tx_clk)
|
||||||
self.dut.phy_rst <= 1
|
self.dut.phy_rst.value = 1
|
||||||
await RisingEdge(self.dut.phy_tx_clk)
|
await RisingEdge(self.dut.phy_tx_clk)
|
||||||
await RisingEdge(self.dut.phy_tx_clk)
|
await RisingEdge(self.dut.phy_tx_clk)
|
||||||
self.dut.phy_rst <= 0
|
self.dut.phy_rst.value = 0
|
||||||
await RisingEdge(self.dut.phy_tx_clk)
|
await RisingEdge(self.dut.phy_tx_clk)
|
||||||
await RisingEdge(self.dut.phy_tx_clk)
|
await RisingEdge(self.dut.phy_tx_clk)
|
||||||
|
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ class TB:
|
|||||||
self._enable_generator = None
|
self._enable_generator = None
|
||||||
self._enable_cr = None
|
self._enable_cr = None
|
||||||
|
|
||||||
cocotb.fork(Clock(dut.clk, 2, units="ns").start())
|
cocotb.start_soon(Clock(dut.clk, 2, units="ns").start())
|
||||||
|
|
||||||
self.source = XgmiiSource(dut.xgmii_d, dut.xgmii_c, dut.clk, dut.rst, dut.xgmii_clk_en)
|
self.source = XgmiiSource(dut.xgmii_d, dut.xgmii_c, dut.clk, dut.rst, dut.xgmii_clk_en)
|
||||||
self.sink = XgmiiSink(dut.xgmii_d, dut.xgmii_c, dut.clk, dut.rst, dut.xgmii_clk_en)
|
self.sink = XgmiiSink(dut.xgmii_d, dut.xgmii_c, dut.clk, dut.rst, dut.xgmii_clk_en)
|
||||||
@@ -59,10 +59,10 @@ class TB:
|
|||||||
self.dut.rst.setimmediatevalue(0)
|
self.dut.rst.setimmediatevalue(0)
|
||||||
await RisingEdge(self.dut.clk)
|
await RisingEdge(self.dut.clk)
|
||||||
await RisingEdge(self.dut.clk)
|
await RisingEdge(self.dut.clk)
|
||||||
self.dut.rst <= 1
|
self.dut.rst.value = 1
|
||||||
await RisingEdge(self.dut.clk)
|
await RisingEdge(self.dut.clk)
|
||||||
await RisingEdge(self.dut.clk)
|
await RisingEdge(self.dut.clk)
|
||||||
self.dut.rst <= 0
|
self.dut.rst.value = 0
|
||||||
await RisingEdge(self.dut.clk)
|
await RisingEdge(self.dut.clk)
|
||||||
await RisingEdge(self.dut.clk)
|
await RisingEdge(self.dut.clk)
|
||||||
|
|
||||||
@@ -74,15 +74,17 @@ class TB:
|
|||||||
self._enable_generator = generator
|
self._enable_generator = generator
|
||||||
|
|
||||||
if self._enable_generator is not None:
|
if self._enable_generator is not None:
|
||||||
self._enable_cr = cocotb.fork(self._run_enable())
|
self._enable_cr = cocotb.start_soon(self._run_enable())
|
||||||
|
|
||||||
def clear_enable_generator(self):
|
def clear_enable_generator(self):
|
||||||
self.set_enable_generator(None)
|
self.set_enable_generator(None)
|
||||||
|
|
||||||
async def _run_enable(self):
|
async def _run_enable(self):
|
||||||
|
clock_edge_event = RisingEdge(self.dut.clk)
|
||||||
|
|
||||||
for val in self._enable_generator:
|
for val in self._enable_generator:
|
||||||
self.dut.xgmii_clk_en <= val
|
self.dut.xgmii_clk_en.value = val
|
||||||
await RisingEdge(self.dut.clk)
|
await clock_edge_event
|
||||||
|
|
||||||
|
|
||||||
async def run_test(dut, payload_lengths=None, payload_data=None, ifg=12, enable_dic=True,
|
async def run_test(dut, payload_lengths=None, payload_data=None, ifg=12, enable_dic=True,
|
||||||
@@ -123,7 +125,7 @@ async def run_test_alignment(dut, payload_data=None, ifg=12, enable_dic=True,
|
|||||||
|
|
||||||
tb = TB(dut)
|
tb = TB(dut)
|
||||||
|
|
||||||
byte_width = tb.source.width // 8
|
byte_lanes = tb.source.byte_lanes
|
||||||
|
|
||||||
tb.source.ifg = ifg
|
tb.source.ifg = ifg
|
||||||
tb.source.enable_dic = enable_dic
|
tb.source.enable_dic = enable_dic
|
||||||
@@ -164,23 +166,23 @@ async def run_test_alignment(dut, payload_data=None, ifg=12, enable_dic=True,
|
|||||||
for test_data in test_frames:
|
for test_data in test_frames:
|
||||||
if ifg == 0:
|
if ifg == 0:
|
||||||
lane = 0
|
lane = 0
|
||||||
if force_offset_start and byte_width > 4:
|
if force_offset_start and byte_lanes > 4:
|
||||||
lane = 4
|
lane = 4
|
||||||
|
|
||||||
start_lane_ref.append(lane)
|
start_lane_ref.append(lane)
|
||||||
lane = (lane + len(test_data)+4+ifg) % byte_width
|
lane = (lane + len(test_data)+4+ifg) % byte_lanes
|
||||||
|
|
||||||
if enable_dic:
|
if enable_dic:
|
||||||
offset = lane % 4
|
offset = lane % 4
|
||||||
if deficit_idle_count+offset >= 4:
|
if deficit_idle_count+offset >= 4:
|
||||||
offset += 4
|
offset += 4
|
||||||
lane = (lane - offset) % byte_width
|
lane = (lane - offset) % byte_lanes
|
||||||
deficit_idle_count = (deficit_idle_count + offset) % 4
|
deficit_idle_count = (deficit_idle_count + offset) % 4
|
||||||
else:
|
else:
|
||||||
offset = lane % 4
|
offset = lane % 4
|
||||||
if offset > 0:
|
if offset > 0:
|
||||||
offset += 4
|
offset += 4
|
||||||
lane = (lane - offset) % byte_width
|
lane = (lane - offset) % byte_lanes
|
||||||
|
|
||||||
tb.log.info("start_lane_ref: %s", start_lane_ref)
|
tb.log.info("start_lane_ref: %s", start_lane_ref)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user