136 lines
4.0 KiB
Python
136 lines
4.0 KiB
Python
# SPDX-License-Identifier: AGPL-3.0-Only
|
|
# Copyright (C) 2022 Sean Anderson <seanga2@gmail.com>
|
|
|
|
import cocotb
|
|
from cocotb.clock import Clock
|
|
from cocotb.triggers import FallingEdge, Timer
|
|
from cocotb.types import LogicArray
|
|
|
|
def BIT(n):
|
|
return 1 << n
|
|
|
|
BMCR = 0
|
|
BMSR = 1
|
|
PHYID1 = 2
|
|
PHYID2 = 3
|
|
EXTSTATUS = 15
|
|
NWCR = 16
|
|
PWCR = 17
|
|
DCR = 18
|
|
FCCR = 19
|
|
SECR = 21
|
|
VCR = 30
|
|
|
|
BMCR_RESET = BIT(15)
|
|
BMCR_LOOPBACK = BIT(14)
|
|
BMCR_SPEED_LSB = BIT(13)
|
|
BMCR_PDOWN = BIT(11)
|
|
BMCR_ISOLATE = BIT(10)
|
|
BMCR_DUPLEX = BIT(8)
|
|
BMCR_COLTEST = BIT(7)
|
|
BMCR_SPEED_MSB = BIT(6)
|
|
|
|
BMSR_100BASEXFD = BIT(14)
|
|
BMSR_100BASEXHD = BIT(13)
|
|
BMSR_LSTATUS = BIT(2)
|
|
BMSR_EXTCAP = BIT(0)
|
|
|
|
VCR_DTEST = BIT(15)
|
|
VCR_LTEST = BIT(14)
|
|
|
|
@cocotb.test(timeout_time=1, timeout_unit='us')
|
|
async def test_mdio(regs):
|
|
regs.cyc.value = 1
|
|
regs.stb.value = 0
|
|
regs.link_status.value = 1
|
|
regs.positive_wraparound.value = 0
|
|
regs.negative_wraparound.value = 0
|
|
regs.false_carrier.value = 0
|
|
regs.symbol_error.value = 0
|
|
await Timer(1)
|
|
await cocotb.start(Clock(regs.clk, 8, units='ns').start())
|
|
|
|
async def xfer(regad, data=None):
|
|
await FallingEdge(regs.clk)
|
|
regs.stb.value = 1
|
|
regs.addr.value = regad
|
|
if data is None:
|
|
regs.we.value = 0
|
|
else:
|
|
regs.we.value = 1
|
|
regs.data_write.value = data
|
|
|
|
await FallingEdge(regs.clk)
|
|
assert regs.ack.value or regs.err.value
|
|
regs.stb.value = 0
|
|
regs.we.value = LogicArray('X')
|
|
regs.addr.value = LogicArray('X' * 4)
|
|
regs.data_write.value = LogicArray('X' * 16)
|
|
if data is None and regs.ack.value:
|
|
return regs.data_read.value
|
|
|
|
async def reg_toggle(reg, bit, signal, ro_mask=0):
|
|
if signal:
|
|
assert not signal.value
|
|
await xfer(reg, bit)
|
|
if signal:
|
|
assert signal.value
|
|
assert await xfer(reg) == (ro_mask | bit)
|
|
await xfer(reg, 0)
|
|
if signal:
|
|
assert not signal.value
|
|
|
|
def bmcr_toggle(bit, signal):
|
|
return reg_toggle(BMCR, bit, signal, ro_mask=BMCR_SPEED_LSB)
|
|
|
|
assert await xfer(BMCR) == (BMCR_SPEED_LSB | BMCR_ISOLATE)
|
|
await bmcr_toggle(BMCR_LOOPBACK, regs.loopback)
|
|
await bmcr_toggle(BMCR_PDOWN, regs.pdown)
|
|
await bmcr_toggle(BMCR_ISOLATE, regs.isolate)
|
|
await bmcr_toggle(BMCR_DUPLEX, None)
|
|
await bmcr_toggle(BMCR_COLTEST, regs.coltest)
|
|
await xfer(BMCR, BMCR_RESET)
|
|
assert await xfer(BMCR) == (BMCR_SPEED_LSB | BMCR_ISOLATE)
|
|
|
|
await xfer(BMSR, 0xffff)
|
|
assert await xfer(BMSR) == (BMSR_100BASEXFD | BMSR_100BASEXHD | BMSR_LSTATUS | BMSR_EXTCAP)
|
|
regs.link_status.value = 0
|
|
assert not await xfer(BMSR) & BMSR_LSTATUS
|
|
regs.link_status.value = 1
|
|
assert not await xfer(BMSR) & BMSR_LSTATUS
|
|
assert await xfer(BMSR) & BMSR_LSTATUS
|
|
|
|
await xfer(PHYID1, 0xffff)
|
|
assert await xfer(PHYID1) == 0
|
|
|
|
await xfer(PHYID2, 0xffff)
|
|
assert await xfer(PHYID2) == 0
|
|
|
|
# I'm pretty sure this register will never be implemented
|
|
assert await xfer(EXTSTATUS) is None
|
|
assert await xfer(EXTSTATUS, 0) is None
|
|
|
|
async def counter_test(reg, signal, edge_triggered=False, active_high=True):
|
|
signal.value = 1 if active_high else 0
|
|
assert await xfer(reg) == 1
|
|
await xfer(reg, 0xfffe)
|
|
if edge_triggered:
|
|
signal.value = 0 if active_high else 1
|
|
await FallingEdge(regs.clk)
|
|
if edge_triggered:
|
|
signal.value = 1 if active_high else 0
|
|
await FallingEdge(regs.clk)
|
|
signal.value = 0 if active_high else 1
|
|
assert await xfer(reg) == 0x7fff
|
|
assert await xfer(reg) == 0
|
|
|
|
await counter_test(NWCR, regs.negative_wraparound)
|
|
await counter_test(PWCR, regs.positive_wraparound)
|
|
await xfer(DCR) # Clear DCR from the BMSR testing
|
|
await counter_test(DCR, regs.link_status, True, False)
|
|
await counter_test(FCCR, regs.false_carrier)
|
|
await counter_test(SECR, regs.symbol_error)
|
|
|
|
await reg_toggle(VCR, VCR_DTEST, regs.descrambler_test)
|
|
await reg_toggle(VCR, VCR_LTEST, regs.link_monitor_test)
|