Add clock enable and MII select to GMII module and tests
This commit is contained in:
@@ -93,12 +93,13 @@ class GmiiSource(object):
|
|||||||
_signals = ["d"]
|
_signals = ["d"]
|
||||||
_optional_signals = ["er", "en", "dv"]
|
_optional_signals = ["er", "en", "dv"]
|
||||||
|
|
||||||
def __init__(self, entity, name, clock, reset=None, enable=None, *args, **kwargs):
|
def __init__(self, entity, name, clock, reset=None, enable=None, mii_select=None, *args, **kwargs):
|
||||||
self.log = SimLog("cocotb.%s.%s" % (entity._name, name))
|
self.log = SimLog("cocotb.%s.%s" % (entity._name, name))
|
||||||
self.entity = entity
|
self.entity = entity
|
||||||
self.clock = clock
|
self.clock = clock
|
||||||
self.reset = reset
|
self.reset = reset
|
||||||
self.enable = enable
|
self.enable = enable
|
||||||
|
self.mii_select = mii_select
|
||||||
self.bus = Bus(self.entity, name, self._signals, optional_signals=self._optional_signals, **kwargs)
|
self.bus = Bus(self.entity, name, self._signals, optional_signals=self._optional_signals, **kwargs)
|
||||||
|
|
||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
@@ -183,6 +184,18 @@ class GmiiSource(object):
|
|||||||
self.queue_occupancy_frames -= 1
|
self.queue_occupancy_frames -= 1
|
||||||
self.log.info(f"TX frame: {frame}")
|
self.log.info(f"TX frame: {frame}")
|
||||||
frame.normalize()
|
frame.normalize()
|
||||||
|
|
||||||
|
if self.mii_select is not None and self.mii_select.value:
|
||||||
|
mii_data = []
|
||||||
|
mii_error = []
|
||||||
|
for b, e in zip(frame.data, frame.error):
|
||||||
|
mii_data.append(b & 0x0F)
|
||||||
|
mii_data.append(b >> 4)
|
||||||
|
mii_error.append(e)
|
||||||
|
mii_error.append(e)
|
||||||
|
frame.data = mii_data
|
||||||
|
frame.error = mii_error
|
||||||
|
|
||||||
self.active = True
|
self.active = True
|
||||||
|
|
||||||
if frame is not None:
|
if frame is not None:
|
||||||
@@ -207,12 +220,13 @@ class GmiiSink(object):
|
|||||||
_signals = ["d"]
|
_signals = ["d"]
|
||||||
_optional_signals = ["er", "en", "dv"]
|
_optional_signals = ["er", "en", "dv"]
|
||||||
|
|
||||||
def __init__(self, entity, name, clock, reset=None, enable=None, *args, **kwargs):
|
def __init__(self, entity, name, clock, reset=None, enable=None, mii_select=None, *args, **kwargs):
|
||||||
self.log = SimLog("cocotb.%s.%s" % (entity._name, name))
|
self.log = SimLog("cocotb.%s.%s" % (entity._name, name))
|
||||||
self.entity = entity
|
self.entity = entity
|
||||||
self.clock = clock
|
self.clock = clock
|
||||||
self.reset = reset
|
self.reset = reset
|
||||||
self.enable = enable
|
self.enable = enable
|
||||||
|
self.mii_select = mii_select
|
||||||
self.bus = Bus(self.entity, name, self._signals, optional_signals=self._optional_signals, **kwargs)
|
self.bus = Bus(self.entity, name, self._signals, optional_signals=self._optional_signals, **kwargs)
|
||||||
|
|
||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
@@ -293,6 +307,27 @@ class GmiiSink(object):
|
|||||||
if not dv_val:
|
if not dv_val:
|
||||||
# end of frame
|
# end of frame
|
||||||
|
|
||||||
|
if self.mii_select is not None and self.mii_select.value:
|
||||||
|
odd = True
|
||||||
|
sync = False
|
||||||
|
b = 0
|
||||||
|
be = 0
|
||||||
|
data = bytearray()
|
||||||
|
error = []
|
||||||
|
for n, e in zip(frame.data, frame.error):
|
||||||
|
odd = not odd
|
||||||
|
b = (n & 0x0F) << 4 | b >> 4
|
||||||
|
be |= e
|
||||||
|
if not sync and b == 0xD5:
|
||||||
|
odd = True
|
||||||
|
sync = True
|
||||||
|
if odd:
|
||||||
|
data.append(b)
|
||||||
|
error.append(be)
|
||||||
|
be = 0
|
||||||
|
frame.data = data
|
||||||
|
frame.error = error
|
||||||
|
|
||||||
frame.compact()
|
frame.compact()
|
||||||
self.log.info(f"RX frame: {frame}")
|
self.log.info(f"RX frame: {frame}")
|
||||||
|
|
||||||
|
|||||||
@@ -45,10 +45,16 @@ class TB(object):
|
|||||||
self.log = SimLog(f"cocotb.tb")
|
self.log = SimLog(f"cocotb.tb")
|
||||||
self.log.setLevel(logging.DEBUG)
|
self.log.setLevel(logging.DEBUG)
|
||||||
|
|
||||||
|
self._enable_generator = None
|
||||||
|
self._enable_cr = None
|
||||||
|
|
||||||
cocotb.fork(Clock(dut.clk, 2, units="ns").start())
|
cocotb.fork(Clock(dut.clk, 2, units="ns").start())
|
||||||
|
|
||||||
self.source = GmiiSource(dut, "gmii", dut.clk, dut.rst)
|
self.source = GmiiSource(dut, "gmii", dut.clk, dut.rst, dut.gmii_clk_en, dut.gmii_mii_sel)
|
||||||
self.sink = GmiiSink(dut, "gmii", dut.clk, dut.rst)
|
self.sink = GmiiSink(dut, "gmii", dut.clk, dut.rst, dut.gmii_clk_en, dut.gmii_mii_sel)
|
||||||
|
|
||||||
|
dut.gmii_clk_en.setimmediatevalue(1)
|
||||||
|
dut.gmii_mii_sel.setimmediatevalue(0)
|
||||||
|
|
||||||
async def reset(self):
|
async def reset(self):
|
||||||
self.dut.rst.setimmediatevalue(0)
|
self.dut.rst.setimmediatevalue(0)
|
||||||
@@ -61,13 +67,35 @@ class TB(object):
|
|||||||
await RisingEdge(self.dut.clk)
|
await RisingEdge(self.dut.clk)
|
||||||
await RisingEdge(self.dut.clk)
|
await RisingEdge(self.dut.clk)
|
||||||
|
|
||||||
async def run_test(dut, payload_lengths=None, payload_data=None, ifg=12):
|
def set_enable_generator(self, generator=None):
|
||||||
|
if self._enable_cr is not None:
|
||||||
|
self._enable_cr.kill()
|
||||||
|
self._enable_cr = None
|
||||||
|
|
||||||
|
self._enable_generator = generator
|
||||||
|
|
||||||
|
if self._enable_generator is not None:
|
||||||
|
self._enable_cr = cocotb.fork(self._run_enable())
|
||||||
|
|
||||||
|
def clear_enable_generator(self):
|
||||||
|
self.set_enable_generator(None)
|
||||||
|
|
||||||
|
async def _run_enable(self):
|
||||||
|
for val in self._enable_generator:
|
||||||
|
self.dut.gmii_clk_en <= val
|
||||||
|
await RisingEdge(self.dut.clk)
|
||||||
|
|
||||||
|
async def run_test(dut, payload_lengths=None, payload_data=None, ifg=12, enable_gen=None, mii_sel=False):
|
||||||
|
|
||||||
tb = TB(dut)
|
tb = TB(dut)
|
||||||
|
|
||||||
byte_width = tb.source.width // 8
|
byte_width = tb.source.width // 8
|
||||||
|
|
||||||
tb.source.ifg = ifg
|
tb.source.ifg = ifg
|
||||||
|
tb.dut.gmii_mii_sel <= mii_sel
|
||||||
|
|
||||||
|
if enable_gen is not None:
|
||||||
|
tb.set_enable_generator(enable_gen())
|
||||||
|
|
||||||
await tb.reset()
|
await tb.reset()
|
||||||
|
|
||||||
@@ -95,12 +123,17 @@ def size_list():
|
|||||||
def incrementing_payload(length):
|
def incrementing_payload(length):
|
||||||
return bytearray(itertools.islice(itertools.cycle(range(256)), length))
|
return bytearray(itertools.islice(itertools.cycle(range(256)), length))
|
||||||
|
|
||||||
|
def cycle_en():
|
||||||
|
return itertools.cycle([0, 0, 0, 1])
|
||||||
|
|
||||||
if cocotb.SIM_NAME:
|
if cocotb.SIM_NAME:
|
||||||
|
|
||||||
factory = TestFactory(run_test)
|
factory = TestFactory(run_test)
|
||||||
factory.add_option("payload_lengths", [size_list])
|
factory.add_option("payload_lengths", [size_list])
|
||||||
factory.add_option("payload_data", [incrementing_payload])
|
factory.add_option("payload_data", [incrementing_payload])
|
||||||
factory.add_option("ifg", [12, 0])
|
factory.add_option("ifg", [12, 0])
|
||||||
|
factory.add_option("enable_gen", [None, cycle_en])
|
||||||
|
factory.add_option("mii_sel", [False, True])
|
||||||
factory.generate_tests()
|
factory.generate_tests()
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -39,7 +39,9 @@ module test_gmii #
|
|||||||
|
|
||||||
inout wire [DATA_WIDTH-1:0] gmii_d,
|
inout wire [DATA_WIDTH-1:0] gmii_d,
|
||||||
inout wire gmii_er,
|
inout wire gmii_er,
|
||||||
inout wire gmii_en
|
inout wire gmii_en,
|
||||||
|
inout wire gmii_clk_en,
|
||||||
|
inout wire gmii_mii_sel
|
||||||
);
|
);
|
||||||
|
|
||||||
endmodule
|
endmodule
|
||||||
|
|||||||
Reference in New Issue
Block a user