mirror of
https://github.com/Silicon1602/srdl2sv.git
synced 2024-12-22 06:58:41 +00:00
Extend test_simple_rw_reg with 3 more tests
The following tests are now included: - Check access to registers over AHB bus - Check access to register over HW interface - Check access to register over HW interface if hw_wr-input is disabled. - Check if the slave responds with a correct error sequence if an illegal address is accessed.
This commit is contained in:
parent
ed08d4bd35
commit
4ba047dd2a
@ -3,8 +3,14 @@ import math
|
||||
import cocotb
|
||||
from cocotb.triggers import Timer, RisingEdge
|
||||
|
||||
# TODO: Does not yet implement HREADY_OUT == 0
|
||||
# TODO: Add support for HRESP (and throw error if HRESP occurs)
|
||||
class BusErrorResponse(Exception):
|
||||
pass
|
||||
|
||||
class WrongErrorSequence(Exception):
|
||||
pass
|
||||
|
||||
class WrongHREADYOUTSequence(Exception):
|
||||
pass
|
||||
|
||||
class HTRANS(Enum):
|
||||
IDLE = 0
|
||||
@ -59,24 +65,47 @@ class AMBA3AHBLiteDriver:
|
||||
await RisingEdge(self._dut.clk)
|
||||
|
||||
while True:
|
||||
# Save address from previous phase
|
||||
previous_address = hex(self._dut.HADDR.value)
|
||||
if self._dut.HREADYOUT.value:
|
||||
# Save address from previous phase
|
||||
previous_address = int(self._dut.HADDR.value)
|
||||
|
||||
# Set data for dataphase
|
||||
self._dut.HWDATA <= (value >> (nbytes_cnt * 8))
|
||||
# Set data for dataphase
|
||||
self._dut.HWDATA <= (value >> (nbytes_cnt * 8))
|
||||
|
||||
# Check if we are done in next phase
|
||||
if (nbytes_cnt := nbytes_cnt + step_size) >= nbytes:
|
||||
self._dut.HTRANS <= HTRANS.IDLE.value
|
||||
# Check if we are done in next phase
|
||||
if (nbytes_cnt := nbytes_cnt + step_size) >= nbytes:
|
||||
self._dut.HTRANS <= HTRANS.IDLE.value
|
||||
else:
|
||||
# Update address
|
||||
self._dut.HADDR <= self._dut.HADDR.value + step_size
|
||||
|
||||
# Wait for next clock cycle
|
||||
await RisingEdge(self._dut.clk)
|
||||
|
||||
# Save into dictionary
|
||||
write_dict[previous_address] = int(self._dut.HWDATA.value)
|
||||
|
||||
# If HREADYOUT == 0 immediately after the first address phase
|
||||
# this is illegal
|
||||
elif nbytes_cnt == 0:
|
||||
raise WrongHREADYOUTSequence
|
||||
# If the slave is not yet ready, just wait
|
||||
else:
|
||||
# Update address
|
||||
self._dut.HADDR <= self._dut.HADDR.value + step_size
|
||||
await RisingEdge(self._dut.clk)
|
||||
continue
|
||||
|
||||
# Wait for next clock cycle
|
||||
await RisingEdge(self._dut.clk)
|
||||
# Check for error condition
|
||||
if self._dut.HRESP.value:
|
||||
if self._dut.HREADYOUT.value:
|
||||
raise WrongErrorSequence
|
||||
|
||||
await RisingEdge(self._dut.clk)
|
||||
|
||||
if self._dut.HREADYOUT.value:
|
||||
raise BusErrorResponse
|
||||
|
||||
raise WrongErrorSequence
|
||||
|
||||
# Save into dictionary
|
||||
write_dict[previous_address] = hex(self._dut.HWDATA.value)
|
||||
|
||||
if nbytes_cnt >= nbytes:
|
||||
break
|
||||
@ -113,21 +142,42 @@ class AMBA3AHBLiteDriver:
|
||||
await RisingEdge(self._dut.clk)
|
||||
|
||||
while True:
|
||||
# Save address from previous phase
|
||||
previous_address = hex(self._dut.HADDR.value)
|
||||
if self._dut.HREADYOUT.value:
|
||||
# Save address from previous phase
|
||||
previous_address = int(self._dut.HADDR.value)
|
||||
|
||||
# Check if we are done in next phase
|
||||
if (nbytes_cnt := nbytes_cnt + step_size) >= nbytes:
|
||||
self._dut.HTRANS <= HTRANS.IDLE.value
|
||||
# Check if we are done in next phase
|
||||
if (nbytes_cnt := nbytes_cnt + step_size) >= nbytes:
|
||||
self._dut.HTRANS <= HTRANS.IDLE.value
|
||||
else:
|
||||
# Update address
|
||||
self._dut.HADDR <= self._dut.HADDR.value + step_size
|
||||
|
||||
# Wait for next clock cycle
|
||||
await RisingEdge(self._dut.clk)
|
||||
|
||||
# Save into dictionary
|
||||
read_dict[previous_address] = int(self._dut.HRDATA.value)
|
||||
# If HREADYOUT == 0 immediately after the first address phase
|
||||
# this is illegal
|
||||
elif nbytes_cnt == 0:
|
||||
raise WrongHREADYOUTSequence
|
||||
# If the slave is not yet ready, just wait
|
||||
else:
|
||||
# Update address
|
||||
self._dut.HADDR <= self._dut.HADDR.value + step_size
|
||||
await RisingEdge(self._dut.clk)
|
||||
continue
|
||||
|
||||
# Wait for next clock cycle
|
||||
await RisingEdge(self._dut.clk)
|
||||
# Check for error condition
|
||||
if self._dut.HRESP.value:
|
||||
if self._dut.HREADYOUT.value:
|
||||
raise WrongErrorSequence
|
||||
|
||||
# Save into dictionary
|
||||
read_dict[previous_address] = hex(self._dut.HRDATA.value)
|
||||
await RisingEdge(self._dut.clk)
|
||||
|
||||
if self._dut.HREADYOUT.value:
|
||||
raise BusErrorResponse
|
||||
|
||||
raise WrongErrorSequence
|
||||
|
||||
if nbytes_cnt >= nbytes:
|
||||
break
|
||||
|
@ -1,12 +1,13 @@
|
||||
from enum import Enum
|
||||
from cocotb.clock import Clock
|
||||
from cocotb.triggers import RisingEdge
|
||||
import cocotb
|
||||
import random
|
||||
|
||||
from libs import AMBA3AHBLiteDriver
|
||||
|
||||
@cocotb.test()
|
||||
async def test_simple_rw_reg(dut):
|
||||
async def test_ahb_access(dut):
|
||||
"""Test writing via the bus and reading back"""
|
||||
|
||||
clock = Clock(dut.clk, 1, units="ns") # Create a 10us period clock on port clk
|
||||
@ -47,5 +48,141 @@ async def test_simple_rw_reg(dut):
|
||||
|
||||
assert write_dict == read_dict, "Read and write values differ!"
|
||||
|
||||
@cocotb.test()
|
||||
async def test_hw_access(dut):
|
||||
"""Test writing via the hardware interface
|
||||
and reading it back.
|
||||
"""
|
||||
|
||||
clock = Clock(dut.clk, 1, units="ns") # Create a 10us period clock on port clk
|
||||
cocotb.fork(clock.start()) # Start the clock
|
||||
|
||||
bus = AMBA3AHBLiteDriver.AMBA3AHBLiteDriver(dut=dut, nbytes=4)
|
||||
|
||||
await bus.reset()
|
||||
|
||||
write_dict = {}
|
||||
read_dict = {}
|
||||
|
||||
# TODO: At this point, CocoTB has issues with single dimension unpacked but
|
||||
# multidimensional packed arrays. Only check first dimension
|
||||
dut.register_0__f1_hw_wr <= 1
|
||||
dut.register_0__f2_hw_wr <= 1
|
||||
|
||||
rand_val = []
|
||||
|
||||
for addr in (0, 2):
|
||||
# Save value that was written in dictionary
|
||||
write_dict[addr] = random.randint(0, (1 << 16)-1)
|
||||
|
||||
dut.register_0__f2_in <= [write_dict[2], 0] #, write_dict[6]]
|
||||
dut.register_0__f1_in <= [write_dict[0], 0] #, write_dict[4]]
|
||||
|
||||
await RisingEdge(dut.clk)
|
||||
|
||||
dut.register_0__f1_hw_wr <= 0
|
||||
dut.register_0__f2_hw_wr <= 0
|
||||
|
||||
for addr in range(0, 4, 2):
|
||||
read_dict.update(
|
||||
await bus.read(
|
||||
address=addr,
|
||||
nbytes=2,
|
||||
step_size=2))
|
||||
|
||||
dut._log.info(f"Wrote dictionary {write_dict}")
|
||||
dut._log.info(f"Read back dictionary {read_dict}")
|
||||
assert write_dict == read_dict, "Read and write values differ!"
|
||||
|
||||
@cocotb.test()
|
||||
async def test_hw_access_hw_wr_inactive(dut):
|
||||
"""Test writing via the hardware interface but
|
||||
keeping the write-enable 0. The value that is
|
||||
read back should *not* be the same as the value
|
||||
that was fed by the testbench.
|
||||
"""
|
||||
|
||||
clock = Clock(dut.clk, 1, units="ns") # Create a 10us period clock on port clk
|
||||
cocotb.fork(clock.start()) # Start the clock
|
||||
|
||||
bus = AMBA3AHBLiteDriver.AMBA3AHBLiteDriver(dut=dut, nbytes=4)
|
||||
|
||||
await bus.reset()
|
||||
|
||||
write_dict = {}
|
||||
read_dict = {}
|
||||
|
||||
# Force initial value
|
||||
dut.register_0__f1_q <= [0, 0]
|
||||
dut.register_0__f2_q <= [0, 0]
|
||||
|
||||
# Disable write
|
||||
dut.register_0__f1_hw_wr <= 0
|
||||
dut.register_0__f2_hw_wr <= 0
|
||||
|
||||
rand_val = []
|
||||
|
||||
for addr in (0, 2, 4, 6):
|
||||
# Save value that was written in dictionary
|
||||
write_dict[addr] = random.randint(0, (1 << 16)-1)
|
||||
|
||||
dut.register_0__f2_in <= [write_dict[2], write_dict[6]]
|
||||
dut.register_0__f1_in <= [write_dict[0], write_dict[4]]
|
||||
|
||||
await RisingEdge(dut.clk)
|
||||
|
||||
dut.register_0__f1_hw_wr <= 0
|
||||
dut.register_0__f2_hw_wr <= 0
|
||||
|
||||
for addr in range(0, 8, 2):
|
||||
read_dict.update(
|
||||
await bus.read(
|
||||
address=addr,
|
||||
nbytes=2,
|
||||
step_size=2))
|
||||
|
||||
dut._log.info(f"Wrote dictionary {write_dict}")
|
||||
dut._log.info(f"Read back dictionary {read_dict}")
|
||||
assert write_dict != read_dict, "Read and write values differ!"
|
||||
|
||||
@cocotb.test()
|
||||
async def test_illegal_address(dut):
|
||||
"""Test reading and writing to an illegal address.
|
||||
The logic should return a correct error sequence.
|
||||
"""
|
||||
|
||||
clock = Clock(dut.clk, 1, units="ns") # Create a 10us period clock on port clk
|
||||
cocotb.fork(clock.start()) # Start the clock
|
||||
|
||||
bus = AMBA3AHBLiteDriver.AMBA3AHBLiteDriver(dut=dut, nbytes=4)
|
||||
await bus.reset()
|
||||
|
||||
rand_addr = random.randint(8, 1337)
|
||||
rand_val = random.randint(0, (1 << 32)-1)
|
||||
|
||||
dut._log.info(f"Write value {rand_val} to illegal addres {rand_addr}.")
|
||||
|
||||
write_error = False
|
||||
|
||||
try:
|
||||
await bus.write(
|
||||
address=rand_addr,
|
||||
value=rand_val,
|
||||
nbytes=4,
|
||||
step_size=4)
|
||||
except AMBA3AHBLiteDriver.BusErrorResponse:
|
||||
write_error = True
|
||||
|
||||
assert write_error == True, "Write to illegal address did not return an error!"
|
||||
|
||||
read_error = False
|
||||
|
||||
try:
|
||||
await bus.read(
|
||||
address=rand_addr,
|
||||
nbytes=4,
|
||||
step_size=4)
|
||||
except AMBA3AHBLiteDriver.BusErrorResponse:
|
||||
read_error = True
|
||||
|
||||
assert read_error == True, "Read from illegal address did not return an error!"
|
||||
|
Loading…
Reference in New Issue
Block a user