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:
Dennis Potter 2021-10-11 23:49:31 -07:00
parent ed08d4bd35
commit 4ba047dd2a
Signed by: Dennis
GPG Key ID: 186A8AD440942BAF
2 changed files with 214 additions and 27 deletions

View File

@ -3,8 +3,14 @@ import math
import cocotb import cocotb
from cocotb.triggers import Timer, RisingEdge from cocotb.triggers import Timer, RisingEdge
# TODO: Does not yet implement HREADY_OUT == 0 class BusErrorResponse(Exception):
# TODO: Add support for HRESP (and throw error if HRESP occurs) pass
class WrongErrorSequence(Exception):
pass
class WrongHREADYOUTSequence(Exception):
pass
class HTRANS(Enum): class HTRANS(Enum):
IDLE = 0 IDLE = 0
@ -59,24 +65,47 @@ class AMBA3AHBLiteDriver:
await RisingEdge(self._dut.clk) await RisingEdge(self._dut.clk)
while True: while True:
# Save address from previous phase if self._dut.HREADYOUT.value:
previous_address = hex(self._dut.HADDR.value) # Save address from previous phase
previous_address = int(self._dut.HADDR.value)
# Set data for dataphase # Set data for dataphase
self._dut.HWDATA <= (value >> (nbytes_cnt * 8)) self._dut.HWDATA <= (value >> (nbytes_cnt * 8))
# Check if we are done in next phase # Check if we are done in next phase
if (nbytes_cnt := nbytes_cnt + step_size) >= nbytes: if (nbytes_cnt := nbytes_cnt + step_size) >= nbytes:
self._dut.HTRANS <= HTRANS.IDLE.value 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: else:
# Update address await RisingEdge(self._dut.clk)
self._dut.HADDR <= self._dut.HADDR.value + step_size continue
# Wait for next clock cycle # Check for error condition
await RisingEdge(self._dut.clk) 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: if nbytes_cnt >= nbytes:
break break
@ -113,21 +142,42 @@ class AMBA3AHBLiteDriver:
await RisingEdge(self._dut.clk) await RisingEdge(self._dut.clk)
while True: while True:
# Save address from previous phase if self._dut.HREADYOUT.value:
previous_address = hex(self._dut.HADDR.value) # Save address from previous phase
previous_address = int(self._dut.HADDR.value)
# Check if we are done in next phase # Check if we are done in next phase
if (nbytes_cnt := nbytes_cnt + step_size) >= nbytes: if (nbytes_cnt := nbytes_cnt + step_size) >= nbytes:
self._dut.HTRANS <= HTRANS.IDLE.value 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: else:
# Update address await RisingEdge(self._dut.clk)
self._dut.HADDR <= self._dut.HADDR.value + step_size continue
# Wait for next clock cycle # Check for error condition
await RisingEdge(self._dut.clk) if self._dut.HRESP.value:
if self._dut.HREADYOUT.value:
raise WrongErrorSequence
# Save into dictionary await RisingEdge(self._dut.clk)
read_dict[previous_address] = hex(self._dut.HRDATA.value)
if self._dut.HREADYOUT.value:
raise BusErrorResponse
raise WrongErrorSequence
if nbytes_cnt >= nbytes: if nbytes_cnt >= nbytes:
break break

View File

@ -1,12 +1,13 @@
from enum import Enum from enum import Enum
from cocotb.clock import Clock from cocotb.clock import Clock
from cocotb.triggers import RisingEdge
import cocotb import cocotb
import random import random
from libs import AMBA3AHBLiteDriver from libs import AMBA3AHBLiteDriver
@cocotb.test() @cocotb.test()
async def test_simple_rw_reg(dut): async def test_ahb_access(dut):
"""Test writing via the bus and reading back""" """Test writing via the bus and reading back"""
clock = Clock(dut.clk, 1, units="ns") # Create a 10us period clock on port clk 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!" 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!"