add utility tests
This commit is contained in:
49
tests/test_sv_int.py
Normal file
49
tests/test_sv_int.py
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
from peakrdl_busdecoder.sv_int import SVInt
|
||||||
|
|
||||||
|
|
||||||
|
def test_string_formatting() -> None:
|
||||||
|
"""SV literals should format width and value correctly."""
|
||||||
|
assert str(SVInt(0x1A, 8)) == "8'h1a"
|
||||||
|
assert str(SVInt(0xDEADBEEF)) == "'hdeadbeef"
|
||||||
|
assert str(SVInt(0x1FFFFFFFF)) == "33'h1ffffffff"
|
||||||
|
|
||||||
|
|
||||||
|
def test_arithmetic_width_propagation() -> None:
|
||||||
|
"""Addition and subtraction should preserve sizing rules."""
|
||||||
|
small = SVInt(3, 4)
|
||||||
|
large = SVInt(5, 6)
|
||||||
|
|
||||||
|
summed = small + large
|
||||||
|
assert summed.value == 8
|
||||||
|
assert summed.width == 6 # max width wins when both are sized
|
||||||
|
|
||||||
|
diff = large - small
|
||||||
|
assert diff.value == 2
|
||||||
|
assert diff.width == 6
|
||||||
|
|
||||||
|
unsized_left = SVInt(1)
|
||||||
|
mixed = unsized_left + small
|
||||||
|
assert mixed.width is None # any unsized operand yields unsized result
|
||||||
|
|
||||||
|
|
||||||
|
def test_length_and_to_bytes() -> None:
|
||||||
|
"""Length and byte conversion should reflect the represented value."""
|
||||||
|
sized = SVInt(0x3, 12)
|
||||||
|
assert len(sized) == 12
|
||||||
|
|
||||||
|
value = SVInt(0x1234)
|
||||||
|
assert len(value) == 13
|
||||||
|
assert value.to_bytes("little") == b"\x34\x12"
|
||||||
|
assert value.to_bytes("big") == b"\x12\x34"
|
||||||
|
|
||||||
|
|
||||||
|
def test_equality_and_hash() -> None:
|
||||||
|
"""Equality compares both value and width."""
|
||||||
|
a = SVInt(7, 4)
|
||||||
|
b = SVInt(7, 4)
|
||||||
|
c = SVInt(7)
|
||||||
|
|
||||||
|
assert a == b
|
||||||
|
assert hash(a) == hash(b)
|
||||||
|
assert a != c
|
||||||
|
assert (a == 7) is False # Non-SVInt comparisons fall back to NotImplemented
|
||||||
@@ -159,22 +159,21 @@ class TestGetIndexedPath:
|
|||||||
addrmap my_addrmap {
|
addrmap my_addrmap {
|
||||||
reg {
|
reg {
|
||||||
field {} data;
|
field {} data;
|
||||||
} always_reg;
|
} always;
|
||||||
};
|
};
|
||||||
"""
|
"""
|
||||||
top = compile_rdl(rdl_source, top="my_addrmap")
|
top = compile_rdl(rdl_source, top="my_addrmap")
|
||||||
reg_node = None
|
reg_node = None
|
||||||
for child in top.children():
|
for child in top.children():
|
||||||
if child.inst_name == "always_reg":
|
if child.inst_name == "always":
|
||||||
reg_node = child
|
reg_node = child
|
||||||
break
|
break
|
||||||
assert reg_node is not None
|
assert reg_node is not None
|
||||||
|
|
||||||
# With keyword filter (default) - SystemRDL identifiers can use keywords but SV can't
|
# With keyword filter (default) - SystemRDL identifiers can use keywords but SV can't
|
||||||
path = get_indexed_path(top, reg_node)
|
path = get_indexed_path(top, reg_node)
|
||||||
# The path should contain always_reg
|
assert path == "always_"
|
||||||
assert "always_reg" in path
|
|
||||||
|
|
||||||
# Without keyword filter
|
# Without keyword filter
|
||||||
path = get_indexed_path(top, reg_node, skip_kw_filter=True)
|
path = get_indexed_path(top, reg_node, skip_kw_filter=True)
|
||||||
assert path == "always_reg"
|
assert path == "always"
|
||||||
|
|||||||
62
tests/utils/test_ref_is_internal.py
Normal file
62
tests/utils/test_ref_is_internal.py
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
from collections.abc import Callable
|
||||||
|
|
||||||
|
from systemrdl.node import AddrmapNode
|
||||||
|
from systemrdl.rdltypes.references import PropertyReference
|
||||||
|
|
||||||
|
from peakrdl_busdecoder.utils import ref_is_internal
|
||||||
|
|
||||||
|
|
||||||
|
def _find_child_by_name(node: AddrmapNode, inst_name: str):
|
||||||
|
for child in node.children():
|
||||||
|
if child.inst_name == inst_name:
|
||||||
|
return child
|
||||||
|
raise AssertionError(f"Child with name {inst_name} not found")
|
||||||
|
|
||||||
|
|
||||||
|
class TestRefIsInternal:
|
||||||
|
"""Tests for ref_is_internal utility."""
|
||||||
|
|
||||||
|
def test_external_components_flagged(
|
||||||
|
self, compile_rdl: Callable[..., AddrmapNode]
|
||||||
|
) -> None:
|
||||||
|
"""External components should be treated as non-internal."""
|
||||||
|
rdl_source = """
|
||||||
|
reg reg_t {
|
||||||
|
field { sw=rw; hw=r; } data[7:0];
|
||||||
|
};
|
||||||
|
|
||||||
|
addrmap top {
|
||||||
|
external reg_t ext @ 0x0;
|
||||||
|
reg_t intrnl @ 0x10;
|
||||||
|
};
|
||||||
|
"""
|
||||||
|
top = compile_rdl(rdl_source, top="top")
|
||||||
|
|
||||||
|
internal_reg = _find_child_by_name(top, "intrnl")
|
||||||
|
assert ref_is_internal(top, internal_reg) is True
|
||||||
|
|
||||||
|
external_reg = _find_child_by_name(top, "ext")
|
||||||
|
assert external_reg.external is True
|
||||||
|
assert ref_is_internal(top, external_reg) is False
|
||||||
|
|
||||||
|
external_prop_ref = PropertyReference.__new__(PropertyReference)
|
||||||
|
external_prop_ref.node = external_reg
|
||||||
|
assert ref_is_internal(top, external_prop_ref) is False
|
||||||
|
|
||||||
|
def test_property_reference_without_node_defaults_internal(
|
||||||
|
self, compile_rdl: Callable[..., AddrmapNode]
|
||||||
|
) -> None:
|
||||||
|
"""Root-level property references should be treated as internal."""
|
||||||
|
rdl_source = """
|
||||||
|
addrmap top {
|
||||||
|
reg {
|
||||||
|
field { sw=rw; hw=r; } data[7:0];
|
||||||
|
} reg0 @ 0x0;
|
||||||
|
};
|
||||||
|
"""
|
||||||
|
top = compile_rdl(rdl_source, top="top")
|
||||||
|
|
||||||
|
prop_ref = PropertyReference.__new__(PropertyReference)
|
||||||
|
prop_ref.node = None
|
||||||
|
|
||||||
|
assert ref_is_internal(top, prop_ref) is True
|
||||||
Reference in New Issue
Block a user