Skip to content

Commit f9a5027

Browse files
Copilotmballance
andcommitted
Add ValueInt.from_bits class method with tests
Co-authored-by: mballance <[email protected]>
1 parent 78a6348 commit f9a5027

File tree

2 files changed

+172
-0
lines changed

2 files changed

+172
-0
lines changed

src/vsc/model/value_scalar.py

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,36 @@
88

99
class ValueInt(int):
1010
"""Wrapper for 'int' values. Permits operators"""
11+
12+
@classmethod
13+
def from_bits(cls, value, width, signed=False):
14+
"""
15+
Create a ValueInt from a bit pattern with specified width and signedness.
16+
17+
Args:
18+
value: The bit pattern value (integer)
19+
width: The bit width (e.g., 8, 16, 32)
20+
signed: Whether to interpret the value as signed (default: False)
21+
22+
Returns:
23+
ValueInt: A properly interpreted integer value
24+
25+
Example:
26+
>>> ValueInt.from_bits(0xFF, 8, signed=True) # Returns -1
27+
>>> ValueInt.from_bits(0xFF, 8, signed=False) # Returns 255
28+
"""
29+
# Mask to the specified width
30+
mask = (1 << width) - 1
31+
masked_value = int(value) & mask
32+
33+
# If signed and MSB is set, convert to negative (two's complement)
34+
if signed and (masked_value & (1 << (width - 1))):
35+
# Convert to negative: -(2^width - value)
36+
result = -((1 << width) - masked_value)
37+
else:
38+
result = masked_value
39+
40+
return cls(result)
1141

1242
def __getitem__(self, rng):
1343
val = self.__int__()

ve/unit/test_value_int.py

Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
'''
2+
Created on Nov 8, 2024
3+
4+
Test for ValueInt.from_bits functionality
5+
'''
6+
import sys
7+
import os
8+
# Add src to path to allow importing vsc modules
9+
sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', '..', 'src'))
10+
11+
from unittest import TestCase
12+
13+
# Import ValueInt directly to avoid full vsc package dependencies
14+
try:
15+
from vsc.types import ValueInt
16+
except ImportError:
17+
# Fallback to direct import if vsc package can't be fully loaded
18+
from vsc.model.value_scalar import ValueInt
19+
20+
21+
class TestValueInt(TestCase):
22+
23+
def test_from_bits_unsigned_8bit(self):
24+
"""Test unsigned 8-bit value conversion"""
25+
# Test maximum unsigned value
26+
result = ValueInt.from_bits(0xFF, 8, signed=False)
27+
self.assertEqual(result, 255)
28+
29+
# Test zero
30+
result = ValueInt.from_bits(0x00, 8, signed=False)
31+
self.assertEqual(result, 0)
32+
33+
# Test mid-range value
34+
result = ValueInt.from_bits(0x7F, 8, signed=False)
35+
self.assertEqual(result, 127)
36+
37+
def test_from_bits_signed_8bit(self):
38+
"""Test signed 8-bit value conversion"""
39+
# Test -1 (0xFF in 8-bit two's complement)
40+
result = ValueInt.from_bits(0xFF, 8, signed=True)
41+
self.assertEqual(result, -1)
42+
43+
# Test -128 (0x80 in 8-bit two's complement)
44+
result = ValueInt.from_bits(0x80, 8, signed=True)
45+
self.assertEqual(result, -128)
46+
47+
# Test positive value (MSB = 0)
48+
result = ValueInt.from_bits(0x7F, 8, signed=True)
49+
self.assertEqual(result, 127)
50+
51+
# Test zero
52+
result = ValueInt.from_bits(0x00, 8, signed=True)
53+
self.assertEqual(result, 0)
54+
55+
def test_from_bits_unsigned_32bit(self):
56+
"""Test unsigned 32-bit value conversion"""
57+
# Test maximum unsigned 32-bit value
58+
result = ValueInt.from_bits(0xFFFFFFFF, 32, signed=False)
59+
self.assertEqual(result, 4294967295)
60+
61+
# Test mid-range value
62+
result = ValueInt.from_bits(0x80000000, 32, signed=False)
63+
self.assertEqual(result, 2147483648)
64+
65+
def test_from_bits_signed_32bit(self):
66+
"""Test signed 32-bit value conversion"""
67+
# Test -1 (0xFFFFFFFF in 32-bit two's complement)
68+
result = ValueInt.from_bits(0xFFFFFFFF, 32, signed=True)
69+
self.assertEqual(result, -1)
70+
71+
# Test minimum signed 32-bit value
72+
result = ValueInt.from_bits(0x80000000, 32, signed=True)
73+
self.assertEqual(result, -2147483648)
74+
75+
# Test positive value
76+
result = ValueInt.from_bits(0x7FFFFFFF, 32, signed=True)
77+
self.assertEqual(result, 2147483647)
78+
79+
def test_from_bits_masking(self):
80+
"""Test that values are properly masked to specified width"""
81+
# Value larger than 8 bits should be masked
82+
result = ValueInt.from_bits(0x1FF, 8, signed=False)
83+
self.assertEqual(result, 0xFF)
84+
85+
# Value larger than 4 bits should be masked
86+
result = ValueInt.from_bits(0xFF, 4, signed=False)
87+
self.assertEqual(result, 0x0F)
88+
89+
# Signed masking
90+
result = ValueInt.from_bits(0xFF, 4, signed=True)
91+
self.assertEqual(result, -1)
92+
93+
def test_from_bits_sign_detection(self):
94+
"""Test sign bit detection at various widths"""
95+
# 4-bit: 0x8 should be -8 when signed
96+
result = ValueInt.from_bits(0x8, 4, signed=True)
97+
self.assertEqual(result, -8)
98+
99+
# 4-bit: 0x7 should be 7 when signed (positive)
100+
result = ValueInt.from_bits(0x7, 4, signed=True)
101+
self.assertEqual(result, 7)
102+
103+
# 16-bit: 0x8000 should be -32768 when signed
104+
result = ValueInt.from_bits(0x8000, 16, signed=True)
105+
self.assertEqual(result, -32768)
106+
107+
# 16-bit: 0x7FFF should be 32767 when signed (positive)
108+
result = ValueInt.from_bits(0x7FFF, 16, signed=True)
109+
self.assertEqual(result, 32767)
110+
111+
def test_from_bits_edge_cases(self):
112+
"""Test edge cases"""
113+
# 1-bit unsigned
114+
result = ValueInt.from_bits(1, 1, signed=False)
115+
self.assertEqual(result, 1)
116+
117+
result = ValueInt.from_bits(0, 1, signed=False)
118+
self.assertEqual(result, 0)
119+
120+
# 1-bit signed: can only represent -1 and 0
121+
result = ValueInt.from_bits(1, 1, signed=True)
122+
self.assertEqual(result, -1)
123+
124+
result = ValueInt.from_bits(0, 1, signed=True)
125+
self.assertEqual(result, 0)
126+
127+
def test_from_bits_practical_dut_example(self):
128+
"""Test practical example from DUT interface"""
129+
# Simulating a DUT returning 0xFFFFFFF0 from a 32-bit signed register
130+
dut_val = 0xFFFFFFF0
131+
vsc_val = ValueInt.from_bits(dut_val, width=32, signed=True)
132+
self.assertEqual(vsc_val, -16)
133+
134+
# Simulating a DUT returning 0xFF from an 8-bit signed register
135+
dut_val = 0xFF
136+
vsc_val = ValueInt.from_bits(dut_val, width=8, signed=True)
137+
self.assertEqual(vsc_val, -1)
138+
139+
# Simulating a DUT returning 0xFF from an 8-bit unsigned register
140+
dut_val = 0xFF
141+
vsc_val = ValueInt.from_bits(dut_val, width=8, signed=False)
142+
self.assertEqual(vsc_val, 255)

0 commit comments

Comments
 (0)