From 1f54f33bb6257783d21cb5960fc3e119fd70a334 Mon Sep 17 00:00:00 2001 From: Kaleb Barrett Date: Wed, 21 Feb 2024 22:02:17 -0600 Subject: [PATCH] Use Array for ArrayObject types This changes the return type of ArrayObjects to be Arrays. This allows the simulator objects indexing to be used rather than just 0 to length-1 as was done for list. Lists, and now any sequence, is still accepted when setting the value in addition to Array. --- src/cocotb/handle.py | 41 ++++++++++--------- .../test_array_simple/test_array_simple.py | 20 ++------- 2 files changed, 25 insertions(+), 36 deletions(-) diff --git a/src/cocotb/handle.py b/src/cocotb/handle.py index 150076c8cb..e264550486 100755 --- a/src/cocotb/handle.py +++ b/src/cocotb/handle.py @@ -25,6 +25,7 @@ # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +import collections.abc import enum import logging import re @@ -37,7 +38,6 @@ Dict, Generic, Iterable, - List, Optional, Sequence, Tuple, @@ -51,8 +51,7 @@ from cocotb import simulator from cocotb._deprecation import deprecated from cocotb._py_compat import cached_property -from cocotb.types import Logic, LogicArray -from cocotb.types.range import Range +from cocotb.types import Array, Logic, LogicArray, Range class _Limits(enum.IntEnum): @@ -809,7 +808,9 @@ def __iter__(self) -> Iterable[ChildObjectT]: class ArrayObject( - IndexableValueObjectBase[List[ElemValueT], List[ElemValueT], ChildObjectT], + IndexableValueObjectBase[ + Array[ElemValueT], Union[Array[ElemValueT], Sequence[ElemValueT]], ChildObjectT + ], Generic[ElemValueT, ChildObjectT], ): """A simulation object that is an array of value-having simulation objects. @@ -821,26 +822,26 @@ def __init__(self, handle: simulator.gpi_sim_hdl, path: Optional[str]) -> None: super().__init__(handle, path) @property - def value(self) -> List[ElemValueT]: + def value(self) -> Array[ElemValueT]: """The current value of the simulation object. :getter: - Returns the current values of each element of the array object as a :class:`list` of element values. + Returns the current values of each element of the array object as a :class:`~cocotb.types.Array` of element values. The elements of the array appear in the list in left-to-right order. :setter: - Assigns a :class:`list` of values to each element of the array at the end of the current delta cycle. + Assigns a :class:`~cocotb.types.Array`, :class:`list`, or :class:`tuple` of values to each element of the array at the end of the current delta cycle. The element values are assigned in left-to-right order. Given an HDL array ``arr``, when getting the value: - +--------------+---------------------+--------------------------------------------------------------+ - | Verilog | VHDL | ``arr.value`` is equivalent to | - +==============+=====================+==============================================================+ - | ``arr[4:7]`` | ``arr(4 to 7)`` | ``[arr[4].value, arr[5].value, arr[6].value, arr[7].value]`` | - +--------------+---------------------+--------------------------------------------------------------+ - | ``arr[7:4]`` | ``arr(7 downto 4)`` | ``[arr[7].value, arr[6].value, arr[5].value, arr[4].value]`` | - +--------------+---------------------+--------------------------------------------------------------+ + +--------------+---------------------+--------------------------------------------------------------------------------------------------+ + | Verilog | VHDL | ``arr.value`` is equivalent to | + +==============+=====================+==================================================================================================+ + | ``arr[4:7]`` | ``arr(4 to 7)`` | ``Array([arr[4].value, arr[5].value, arr[6].value, arr[7].value], range=Range(4, 'to', 7))`` | + +--------------+---------------------+--------------------------------------------------------------------------------------------------+ + | ``arr[7:4]`` | ``arr(7 downto 4)`` | ``Array([arr[7].value, arr[6].value, arr[5].value, arr[4].value], range=Range(7, 'downto', 4))`` | + +--------------+---------------------+--------------------------------------------------------------------------------------------------+ When setting the signal as in ``arr.value = ...``, the same index equivalence as noted in the table holds. @@ -857,21 +858,21 @@ def value(self) -> List[ElemValueT]: ValueError: If assigning a :class:`list` of different length than the simulation object. """ - return [self[i].value for i in self.range] + return Array((self[i].value for i in self.range), range=self.range) @value.setter - def value(self, value: List[ElemValueT]) -> None: + def value(self, value: Array[ElemValueT]) -> None: self.set(value) def _set_value( self, - value: List[ElemValueT], + value: Union[Array[ElemValueT], Sequence[ElemValueT]], action: _GPISetAction, schedule_write: Callable[ [ValueObjectBase[Any, Any], Callable[..., None], Sequence[Any]], None ], ) -> None: - if not isinstance(value, list): + if not isinstance(value, (collections.abc.Sequence, Array)): raise TypeError( f"Assigning non-list value to object {self._name} of type {type(self)}" ) @@ -880,8 +881,8 @@ def _set_value( "Assigning list of length %d to object %s of length %d" % (len(value), self._name, len(self)) ) - for val_idx, self_idx in enumerate(self.range): - self[self_idx]._set_value(value[val_idx], action, schedule_write) + for elem, self_idx in zip(value, self.range): + self[self_idx]._set_value(elem, action, schedule_write) class LogicObject( diff --git a/tests/test_cases/test_array_simple/test_array_simple.py b/tests/test_cases/test_array_simple/test_array_simple.py index 47bc373a9d..3c9171c3f3 100644 --- a/tests/test_cases/test_array_simple/test_array_simple.py +++ b/tests/test_cases/test_array_simple/test_array_simple.py @@ -2,10 +2,10 @@ # Licensed under the Revised BSD License, see LICENSE for details. # SPDX-License-Identifier: BSD-3-Clause """Test getting and setting values of arrays""" -import contextlib import logging import cocotb +import pytest from cocotb._sim_versions import RivieraVersion from cocotb.clock import Clock from cocotb.triggers import Timer @@ -169,24 +169,12 @@ async def test_struct(dut): _check_value(tlog, dut.inout_if.a_in, 0) -@contextlib.contextmanager -def assert_raises(exc_type): - try: - yield - except exc_type as exc: - tlog.info(f" {exc_type.__name__} raised as expected: {exc}") - else: - raise AssertionError(f"{exc_type.__name__} was not raised") - - @cocotb.test() async def test_exceptions(dut): """Test that correct Exceptions are raised.""" - with assert_raises(TypeError): - dut.array_7_downto_4.value = (0xF0, 0xE0, 0xD0, 0xC0) - with assert_raises(TypeError): + with pytest.raises(TypeError): dut.array_4_to_7.value = Exception("Exception Object") - with assert_raises(ValueError): + with pytest.raises(ValueError): dut.array_3_downto_0.value = [0x70, 0x60, 0x50] - with assert_raises(ValueError): + with pytest.raises(ValueError): dut.array_0_to_3.value = [0x40, 0x30, 0x20, 0x10, 0x00]