tb: Break out the core of pcs_send_codes into its own function
The PMA also has to deal with "recoverd bitstreams" (that is, inputs which can have 0, 1, or 2 valid bits). Export the core of pcs_send_codes into its own function, as it is useful for generating these signals. Signed-off-by: Sean Anderson <seanga2@gmail.com>
This commit is contained in:
parent
fec8a0a9f6
commit
c1301ca31a
47
tb/pcs.py
47
tb/pcs.py
|
@ -2,7 +2,6 @@
|
||||||
# Copyright (C) 2022 Sean Anderson <seanga2@gmail.com>
|
# Copyright (C) 2022 Sean Anderson <seanga2@gmail.com>
|
||||||
|
|
||||||
import enum
|
import enum
|
||||||
import random
|
|
||||||
import itertools
|
import itertools
|
||||||
|
|
||||||
import cocotb
|
import cocotb
|
||||||
|
@ -11,7 +10,7 @@ from cocotb.regression import TestFactory
|
||||||
from cocotb.triggers import ClockCycles, Edge, RisingEdge, FallingEdge, Timer
|
from cocotb.triggers import ClockCycles, Edge, RisingEdge, FallingEdge, Timer
|
||||||
from cocotb.types import LogicArray
|
from cocotb.types import LogicArray
|
||||||
|
|
||||||
from .util import alist, classproperty, ReverseList, timeout
|
from .util import *
|
||||||
|
|
||||||
class Code(enum.Enum):
|
class Code(enum.Enum):
|
||||||
_0 = (0b11110, '0')
|
_0 = (0b11110, '0')
|
||||||
|
@ -195,49 +194,9 @@ async def pcs_recv_packet(pcs):
|
||||||
yield code.data
|
yield code.data
|
||||||
raise PrematureEndError()
|
raise PrematureEndError()
|
||||||
|
|
||||||
def one_valid():
|
|
||||||
return 1
|
|
||||||
|
|
||||||
def two_valid():
|
|
||||||
return 2
|
|
||||||
|
|
||||||
def rand_valid():
|
|
||||||
return random.randrange(3)
|
|
||||||
|
|
||||||
class saw_valid:
|
|
||||||
def __init__(self):
|
|
||||||
self.last = 0
|
|
||||||
# Lie for TestFactory
|
|
||||||
self.__qualname__ = self.__class__.__qualname__
|
|
||||||
|
|
||||||
def __call__(self):
|
|
||||||
self.last += 1
|
|
||||||
if self.last > 2:
|
|
||||||
self.last = 0
|
|
||||||
return self.last
|
|
||||||
|
|
||||||
async def pcs_send_codes(pcs, codes, valids):
|
async def pcs_send_codes(pcs, codes, valids):
|
||||||
await FallingEdge(pcs.rx_clk)
|
await send_recovered_bits(pcs.rx_clk, pcs.pma_data_rx, pcs.pma_data_rx_valid,
|
||||||
bits = itertools.chain(*codes)
|
itertools.chain(*codes), valids)
|
||||||
try:
|
|
||||||
while True:
|
|
||||||
valid = valids()
|
|
||||||
pcs.pma_data_rx_valid.value = valid
|
|
||||||
if valid == 0:
|
|
||||||
data = 'XX'
|
|
||||||
elif valid == 1:
|
|
||||||
data = (next(bits), 'X')
|
|
||||||
else:
|
|
||||||
first = next(bits)
|
|
||||||
try:
|
|
||||||
second = next(bits)
|
|
||||||
except StopIteration:
|
|
||||||
second = 'X'
|
|
||||||
data = (first, second)
|
|
||||||
pcs.pma_data_rx.value = LogicArray(data)
|
|
||||||
await FallingEdge(pcs.rx_clk)
|
|
||||||
except StopIteration:
|
|
||||||
pass
|
|
||||||
|
|
||||||
@cocotb.test(timeout_time=10, timeout_unit='us')
|
@cocotb.test(timeout_time=10, timeout_unit='us')
|
||||||
async def test_tx(pcs):
|
async def test_tx(pcs):
|
||||||
|
|
47
tb/util.py
47
tb/util.py
|
@ -2,10 +2,12 @@
|
||||||
# Copyright (C) 2022 Sean Anderson <seanga2@gmail.com>
|
# Copyright (C) 2022 Sean Anderson <seanga2@gmail.com>
|
||||||
|
|
||||||
import functools
|
import functools
|
||||||
|
import random
|
||||||
|
|
||||||
import cocotb
|
import cocotb
|
||||||
from cocotb.triggers import with_timeout
|
|
||||||
from cocotb.result import SimTimeoutError
|
from cocotb.result import SimTimeoutError
|
||||||
|
from cocotb.triggers import with_timeout, FallingEdge
|
||||||
|
from cocotb.types import LogicArray
|
||||||
|
|
||||||
async def alist(xs):
|
async def alist(xs):
|
||||||
return [x async for x in xs]
|
return [x async for x in xs]
|
||||||
|
@ -65,3 +67,46 @@ class ReverseList(list):
|
||||||
|
|
||||||
def __iter__(self):
|
def __iter__(self):
|
||||||
return super().__reversed__()
|
return super().__reversed__()
|
||||||
|
|
||||||
|
def one_valid():
|
||||||
|
return 1
|
||||||
|
|
||||||
|
def two_valid():
|
||||||
|
return 2
|
||||||
|
|
||||||
|
def rand_valid():
|
||||||
|
return random.randrange(3)
|
||||||
|
|
||||||
|
class saw_valid:
|
||||||
|
def __init__(self):
|
||||||
|
self.last = 0
|
||||||
|
# Lie for TestFactory
|
||||||
|
self.__qualname__ = self.__class__.__qualname__
|
||||||
|
|
||||||
|
def __call__(self):
|
||||||
|
self.last += 1
|
||||||
|
if self.last > 2:
|
||||||
|
self.last = 0
|
||||||
|
return self.last
|
||||||
|
|
||||||
|
async def send_recovered_bits(clk, data, valid, bits, valids):
|
||||||
|
await FallingEdge(clk)
|
||||||
|
try:
|
||||||
|
while True:
|
||||||
|
v = valids()
|
||||||
|
valid.value = v
|
||||||
|
if v == 0:
|
||||||
|
d = 'XX'
|
||||||
|
elif v == 1:
|
||||||
|
d = (next(bits), 'X')
|
||||||
|
else:
|
||||||
|
first = next(bits)
|
||||||
|
try:
|
||||||
|
second = next(bits)
|
||||||
|
except StopIteration:
|
||||||
|
second = 'X'
|
||||||
|
d = (first, second)
|
||||||
|
data.value = LogicArray(d)
|
||||||
|
await FallingEdge(clk)
|
||||||
|
except StopIteration:
|
||||||
|
pass
|
||||||
|
|
Loading…
Reference in New Issue