def _di_to_bus_rx(dut, num_transfers=500, max_delay=100): wb_master = WishboneMaster(dut, dut.clk) for i in range(num_transfers): delay = random.randint(0, max_delay) for _ in range(delay): yield RisingEdge(dut.clk) # Wait until the UART signals that it is ready for a read while True: lsr_can_read = yield _lsr_can_read(dut, wb_master) if lsr_can_read: break yield RisingEdge(dut.clk) # Only look at the LSB of the 32-bit wide result. ret = yield wb_master.send_cycle([WBOp(adr=0x0, dat=None, sel=0x8)]) res = ret.pop(0).datrd & 0xFF data = _di_to_bus_fifo.pop(0); if data != res: raise TestFailure("Expected result to be 0x%x, got 0x%x" % (data, res)) yield RisingEdge(dut.clk)
def test_uart_irq_tbe(dut): """ Check if the Transmit Buffer Empty interrupt is sent """ yield _init_dut(dut) yield _activate_module(dut) wb_master = WishboneMaster(dut, dut.clk) # ensure that IRQ is lowered before we start sending if dut.irq.value != 0: raise TestFailure("irq is not lowered at start.") # Enable TBE interrupt by setting bit 2 in IER yield wb_master.send_cycle([WBOp(adr=0x0, dat=0x2, sel=0x4)]) yield RisingEdge(dut.clk) # ensure that IRQ is still lowered before we start sending if dut.irq.value != 1: raise TestFailure("irq is not high (indicating an empty transmit buffer)") yield RisingEdge(dut.clk) # simulate the CPU sending a single char to the UART device yield _bus_to_di_tx(dut, num_transfers=1, random_data=False) # check that IRQ is now lowered if dut.irq.value != 0: raise TestFailure("irq it not lowered after receiving data.") # Let the UART module empty its send buffer yield _bus_to_di_rx(dut, num_transfers=1) # check that IRQ is now high again, indicating an empty transmit buffer if dut.irq.value != 1: raise TestFailure("irq not high again after emptying the transmit buffer.") # Disable the TBE interrupt again yield wb_master.send_cycle([WBOp(adr=0x0, dat=0x0, sel=0x4)]) yield RisingEdge(dut.clk) # Ensure that the interrupt signal is now lowered if dut.irq.value != 0: raise TestFailure("irq not lowered after disabling the interrupt.")
def _lsr_can_read(dut, wb_master): """ Check if the UART LSR register signals data available in its input buffer """ ret = yield wb_master.send_cycle([WBOp(adr=0x4, dat=None, sel=0x4)]) lsr = ret.pop(0).datrd & 0xFF # Reading is possible if DR (bit 0) is set raise ReturnValue(lsr & (1 << 0))
def _lsr_can_write(dut, wb_master): """ Check if the UART LSR register signals space in its output buffers """ ret = yield wb_master.send_cycle([WBOp(adr=0x4, dat=None, sel=0x4)]) lsr = ret.pop(0).datrd & 0xFF # Writing is possible if THRE (bit 5) and TEMPT (bit 6) are set raise ReturnValue(lsr & (1 << 5) and lsr & (1 << 6))
def test_uart_read_empty(dut): """ Ensure that the bus doesn't block even though no data is available to read """ yield _init_dut(dut) yield _activate_module(dut) # WB master with 10 cycles timeout wb_master = WishboneMaster(dut, dut.clk, timeout=10) # Read from Receiver Buffer Register (RBR) ret = yield wb_master.send_cycle([WBOp(adr=0x0, dat=None, sel=0x0)]) res = ret.pop(0).datrd & 0xFF
def test_uart_irq_rbf(dut): """ Check if the Receive Buffer Full interrupt is sent """ yield _init_dut(dut) yield _activate_module(dut) _di_to_bus_fifo.clear() wb_master = WishboneMaster(dut, dut.clk) # ensure that IRQ is lowered before we start sending if dut.irq.value != 0: raise TestFailure("irq is not lowered at start.") # Enable RBF interrupt by setting bit 1 in IER yield wb_master.send_cycle([WBOp(adr=0x0, dat=0x1, sel=0x4)]) yield RisingEdge(dut.clk) # ensure that IRQ is still lowered before we start sending if dut.irq.value != 0: raise TestFailure("irq is not low, even though receive buffer is empty") yield RisingEdge(dut.clk) # send a single packet to the UART module yield _di_to_bus_tx(dut, num_transfers=1, random_data=False) for _ in range(4): yield RisingEdge(dut.clk) # check that IRQ is now high if dut.irq.value != 1: raise TestFailure("irq it not high after receiving a character") # simulate CPU consuming the incoming character yield _di_to_bus_rx(dut, num_transfers=1) # check that IRQ is now lowered again if dut.irq.value != 0: raise TestFailure("irq it not lowered after the incoming character has been consumed")
def _bus_to_di_tx(dut, num_transfers=500, max_delay=100, random_data=False): wb_master = WishboneMaster(dut, dut.clk) for i in range(num_transfers): delay = random.randint(0, max_delay) for _ in range(delay): yield RisingEdge(dut.clk) # Wait until the UART signals that it is ready for writes while True: lsr_can_write = yield _lsr_can_write(dut, wb_master) if lsr_can_write: break yield RisingEdge(dut.clk) data = random.randint(0, 255) if random_data else 0x42 _bus_to_di_fifo.append(data) yield wb_master.send_cycle([WBOp(adr=0x0, dat=data, sel=0x8)])
def test_uart_16550_registers(dut): """ Test accessibility and functionality of the implemented UART registers, as well as their correct reset values. """ yield _init_dut(dut) yield _activate_module(dut) wb_master = WishboneMaster(dut, dut.clk) # IER, verify reset values and persistence ret = yield wb_master.send_cycle([WBOp(adr=0x0, dat=None, sel=0x4)]) res = ret.pop(0).datrd & 0xFF if 0 != res: raise TestFailure("IER test failed! Wrong reset values: 0x%x" % res) yield wb_master.send_cycle([WBOp(adr=0x0, dat=0x3, sel=0x4)]) for _ in range(10): yield RisingEdge(dut.clk) ret = yield wb_master.send_cycle([WBOp(adr=0x0, dat=None, sel=0x4)]) res = ret.pop(0).datrd & 0xFF if res != 0x3: raise TestFailure("IER test failed! Written value not stored, Wrote: 0x%x, Read: 0x%x" % (0x3, res)) # IIR (Read Only) & FCR (Write Only), make sure the FIFOs can be enabled yield wb_master.send_cycle([WBOp(adr=0x0, dat=0x1, sel=0x2)]) # Only check if the FIFOs have been enabled correctly ret = yield wb_master.send_cycle([WBOp(adr=0x0, dat=None, sel=0x2)]) res = ret.pop(0).datrd & 0xC0 if res != 0xC0: raise TestFailure("FCR test failed! FIFOs not enabled. 0x%x" % res) # LCR, make sure DLAB can be set ret = yield wb_master.send_cycle([WBOp(adr=0x0, dat=None, sel=0x1)]) res = ret.pop(0).datrd if res != 0x0: raise TestFailure("LCR test failed! Wrong reset values: 0x%x" % res) yield wb_master.send_cycle([WBOp(adr=0x0, dat=0x80, sel=0x1)]) ret = yield wb_master.send_cycle([WBOp(adr=0x0, dat=None, sel=0x1)]) res = ret.pop(0).datrd & 0xFF if res != 0x80: raise TestFailure("LCR test failed! Written value not stored, Wrote: 0x%x, Read: 0x%x" % (0x80, res)) # LSR (Read Only), verify correct reset value ret = yield wb_master.send_cycle([WBOp(adr=0x4, dat=None, sel=0x4)]) res = ret.pop(0).datrd & 0xFF if res != 0x60: raise TestFailure("LSR test failed! Wrong reset values: 0x%x" % res) # DLM & DLL, verify accessibility yield wb_master.send_cycle([WBOp(adr=0x0, dat=0x80, sel=0x1)]) # Set Baudrate to 115200 (LSB first) yield wb_master.send_cycle([WBOp(adr=0x0, dat=0x1, sel=0x8)]) yield wb_master.send_cycle([WBOp(adr=0x0, dat=0x0, sel=0x4)]) ret = yield wb_master.send_cycle([WBOp(adr=0x0, dat=None, sel=0x8)]) res = ret.pop(0).datrd & 0xFF if res != 0x1: raise TestFailure("DLL test failed! Wrote: 0x%x, Read: 0x%x" % (0x1, res)) ret = yield wb_master.send_cycle([WBOp(adr=0x0, dat=None, sel=0x4)]) res = ret.pop(0).datrd & 0xFF if res != 0x0: raise TestFailure("DLM test failed! Wrote: 0x%x, Read: 0x%x" % (0x0, res))
def test_both_directions(dut): """ Randomly alternate between read/write cycles on the WISHBONE bus """ NUM_TRANSFERS = 1000 MAX_DELAY = 50 RANDOM_DATA = True yield _init_dut(dut) yield _activate_module(dut) _bus_to_di_fifo.clear() _di_to_bus_fifo.clear() wb_master = WishboneMaster(dut, dut.clk) rx_packets = NUM_TRANSFERS tx_packets = NUM_TRANSFERS write_thread = cocotb.fork(_di_to_bus_tx(dut, num_transfers=NUM_TRANSFERS, max_delay=MAX_DELAY, random_data=RANDOM_DATA)) read_thread = cocotb.fork(_bus_to_di_rx(dut, num_transfers=NUM_TRANSFERS, max_delay=MAX_DELAY)) # randomly pick a direction and send/receive any remaining packets while tx_packets or rx_packets: if random.randint(0,1): if not tx_packets: continue for _ in range(random.randint(0, MAX_DELAY)): yield RisingEdge(dut.clk) # Check if the UART signals space in its send buffer lsr_can_write = yield _lsr_can_write(dut, wb_master) if not lsr_can_write: continue data = random.randint(0, 255) if RANDOM_DATA else 0x42 _bus_to_di_fifo.append(data) yield wb_master.send_cycle([WBOp(adr=0x0, dat=data, sel=0x8)]) yield RisingEdge(dut.clk) tx_packets -= 1 else: if not rx_packets: continue for _ in range(random.randint(0, MAX_DELAY)): yield RisingEdge(dut.clk) # Check if the UART signals available data in its read buffer lsr_can_read = yield _lsr_can_read(dut, wb_master) if not lsr_can_read: continue ret = yield wb_master.send_cycle([WBOp(adr=0x0, dat=None, sel=0x8)]) res = ret.pop(0).datrd & 0xFF data = _di_to_bus_fifo.pop(0) if data != res: raise TestFailure("Expected result to be 0x%x, got 0x%x" % (data, res)) yield RisingEdge(dut.clk) rx_packets -= 1 # we implicitly wait for the write_thread in the loop above yield read_thread.join()