0
# Binary and Type System
1
2
Cocotb's binary and type system provides HDL-compatible data types for representing and manipulating binary values, logic states, arrays, and ranges. The system supports multiple binary representations, 4-value logic, and HDL-style indexing and slicing operations.
3
4
## Capabilities
5
6
### Binary Value Representation
7
8
Core class for representing binary values with multiple formats and automatic conversion capabilities.
9
10
```python { .api }
11
class BinaryValue(value=None, n_bits=None, bigEndian=True, binaryRepresentation=BinaryRepresentation.UNSIGNED):
12
"""
13
Binary value representation supporting multiple formats and bit manipulations.
14
15
Parameters:
16
- value: Initial value (int, str, bytes, or BinaryValue)
17
- n_bits: Number of bits (auto-detected if None)
18
- bigEndian: True for big-endian bit ordering
19
- binaryRepresentation: Binary format (UNSIGNED, SIGNED_MAGNITUDE, TWOS_COMPLEMENT)
20
21
Properties:
22
- integer: Value as unsigned integer
23
- signed_integer: Value as signed integer
24
- binstr: Binary string representation
25
- buff: Raw buffer data
26
- n_bits: Number of bits
27
- is_resolvable: True if value contains no X/Z states
28
29
Methods:
30
- assign(value): Assign new value
31
- hex(): Hexadecimal string representation
32
"""
33
34
@property
35
def integer(self) -> int:
36
"""Get value as unsigned integer."""
37
38
@property
39
def signed_integer(self) -> int:
40
"""Get value as signed integer."""
41
42
@property
43
def binstr(self) -> str:
44
"""Get binary string representation."""
45
46
@property
47
def buff(self) -> bytes:
48
"""Get raw buffer data."""
49
50
@property
51
def n_bits(self) -> int:
52
"""Get number of bits."""
53
54
@property
55
def is_resolvable(self) -> bool:
56
"""Check if value contains no X/Z states."""
57
58
def assign(self, value):
59
"""
60
Assign new value to BinaryValue.
61
62
Parameters:
63
- value: New value to assign
64
"""
65
66
def hex(self) -> str:
67
"""
68
Get hexadecimal string representation.
69
70
Returns:
71
Hexadecimal string (e.g., "0xABCD")
72
"""
73
74
class BinaryRepresentation:
75
"""Binary representation format constants."""
76
UNSIGNED = "UNSIGNED"
77
SIGNED_MAGNITUDE = "SIGNED_MAGNITUDE"
78
TWOS_COMPLEMENT = "TWOS_COMPLEMENT"
79
```
80
81
**Usage Examples:**
82
83
```python
84
@cocotb.test()
85
async def binary_value_test(dut):
86
"""Test demonstrating BinaryValue operations."""
87
88
# Create binary values with different representations
89
unsigned_val = BinaryValue(42, n_bits=8, binaryRepresentation=BinaryRepresentation.UNSIGNED)
90
signed_val = BinaryValue(-42, n_bits=8, binaryRepresentation=BinaryRepresentation.TWOS_COMPLEMENT)
91
92
# Access different representations
93
cocotb.log.info(f"Unsigned 42: binary={unsigned_val.binstr}, hex={unsigned_val.hex()}")
94
cocotb.log.info(f"Signed -42: binary={signed_val.binstr}, hex={signed_val.hex()}")
95
96
# Convert from different sources
97
from_string = BinaryValue("10101010", n_bits=8)
98
from_int = BinaryValue(170, n_bits=8)
99
from_hex = BinaryValue(0xAA, n_bits=8)
100
101
# All should be equivalent
102
assert from_string.integer == from_int.integer == from_hex.integer
103
104
# Assign to DUT signals
105
dut.data_bus.value = unsigned_val
106
await Timer(10, units="ns")
107
108
# Read back and verify
109
readback = BinaryValue(dut.data_bus.value, n_bits=8)
110
assert readback.integer == 42
111
112
@cocotb.test()
113
async def binary_formats_test(dut):
114
"""Test different binary representation formats."""
115
116
# Test unsigned format
117
unsigned = BinaryValue(200, n_bits=8, binaryRepresentation=BinaryRepresentation.UNSIGNED)
118
cocotb.log.info(f"Unsigned 200: {unsigned.integer} (0x{unsigned.integer:02X})")
119
120
# Test two's complement
121
twos_comp = BinaryValue(-56, n_bits=8, binaryRepresentation=BinaryRepresentation.TWOS_COMPLEMENT)
122
cocotb.log.info(f"2's complement -56: signed={twos_comp.signed_integer}, unsigned={twos_comp.integer}")
123
124
# Test sign-magnitude (rarely used)
125
sign_mag = BinaryValue(-56, n_bits=8, binaryRepresentation=BinaryRepresentation.SIGNED_MAGNITUDE)
126
cocotb.log.info(f"Sign-magnitude -56: {sign_mag.binstr}")
127
128
# Test big vs little endian
129
big_endian = BinaryValue(0x1234, n_bits=16, bigEndian=True)
130
little_endian = BinaryValue(0x1234, n_bits=16, bigEndian=False)
131
132
cocotb.log.info(f"Big endian 0x1234: {big_endian.binstr}")
133
cocotb.log.info(f"Little endian 0x1234: {little_endian.binstr}")
134
```
135
136
### Binary Utility Functions
137
138
Utility functions for binary string manipulation and X/Z value resolution.
139
140
```python { .api }
141
def resolve(string):
142
"""
143
Resolve X/Z values in binary string.
144
145
Converts X and Z characters to 0 for numeric operations.
146
147
Parameters:
148
- string: Binary string potentially containing X/Z
149
150
Returns:
151
Binary string with X/Z resolved to 0
152
"""
153
```
154
155
**Usage Examples:**
156
157
```python
158
@cocotb.test()
159
async def binary_utilities_test(dut):
160
"""Test demonstrating binary utility functions."""
161
162
# Handle X/Z values in signals
163
dut.test_signal.value = "10X1Z010" # String with X/Z
164
await Timer(1, units="ns")
165
166
# Read back signal value
167
signal_value = str(dut.test_signal.value)
168
cocotb.log.info(f"Signal with X/Z: {signal_value}")
169
170
# Resolve X/Z for numeric operations
171
resolved = resolve(signal_value)
172
cocotb.log.info(f"Resolved value: {resolved}")
173
174
# Convert to numeric value
175
numeric_val = BinaryValue(resolved)
176
cocotb.log.info(f"Numeric value: {numeric_val.integer}")
177
178
# Check if value is fully resolvable
179
test_values = ["11010101", "110X0101", "110Z0101", "XXXXXXXX"]
180
181
for test_val in test_values:
182
bv = BinaryValue(test_val)
183
cocotb.log.info(f"Value {test_val}: resolvable={bv.is_resolvable}")
184
```
185
186
### 4-Value Logic System
187
188
HDL-compatible logic types supporting 0, 1, X (unknown), and Z (high-impedance) states.
189
190
```python { .api }
191
class Logic:
192
"""
193
4-value logic type supporting 0, 1, X, Z states.
194
195
Constants:
196
- Logic.0: Logic 0 state
197
- Logic.1: Logic 1 state
198
- Logic.X: Unknown/uninitialized state
199
- Logic.Z: High-impedance state
200
201
Operations:
202
- & (and): Bitwise AND operation
203
- | (or): Bitwise OR operation
204
- ^ (xor): Bitwise XOR operation
205
- ~ (not): Bitwise NOT operation
206
"""
207
208
# Type alias for backward compatibility
209
Bit = Logic
210
211
class LogicArray:
212
"""
213
Array of Logic values with HDL semantics.
214
215
Properties:
216
- binstr: Binary string representation
217
- integer: Integer value (X/Z resolved to 0)
218
- signed_integer: Signed integer value
219
220
Methods:
221
- to_BinaryValue(): Convert to BinaryValue object
222
"""
223
224
@property
225
def binstr(self) -> str:
226
"""Get binary string representation."""
227
228
@property
229
def integer(self) -> int:
230
"""Get integer value (X/Z resolved to 0)."""
231
232
@property
233
def signed_integer(self) -> int:
234
"""Get signed integer value."""
235
236
def to_BinaryValue(self):
237
"""
238
Convert to BinaryValue object.
239
240
Returns:
241
BinaryValue representation of the LogicArray
242
"""
243
```
244
245
**Usage Examples:**
246
247
```python
248
@cocotb.test()
249
async def logic_types_test(dut):
250
"""Test demonstrating 4-value logic operations."""
251
252
# Create individual logic values
253
from cocotb.types import Logic
254
255
zero = Logic.0
256
one = Logic.1
257
unknown = Logic.X
258
high_z = Logic.Z
259
260
# Logic operations
261
and_result = one & zero # Should be Logic.0
262
or_result = one | zero # Should be Logic.1
263
xor_result = one ^ one # Should be Logic.0
264
not_result = ~zero # Should be Logic.1
265
266
cocotb.log.info(f"Logic operations:")
267
cocotb.log.info(f" 1 & 0 = {and_result}")
268
cocotb.log.info(f" 1 | 0 = {or_result}")
269
cocotb.log.info(f" 1 ^ 1 = {xor_result}")
270
cocotb.log.info(f" ~0 = {not_result}")
271
272
# Unknown value propagation
273
unknown_and = one & unknown # Should be Logic.X
274
unknown_or = zero | unknown # Should be Logic.X
275
276
cocotb.log.info(f"Unknown propagation:")
277
cocotb.log.info(f" 1 & X = {unknown_and}")
278
cocotb.log.info(f" 0 | X = {unknown_or}")
279
280
@cocotb.test()
281
async def logic_array_test(dut):
282
"""Test demonstrating LogicArray operations."""
283
284
from cocotb.types import LogicArray, Logic
285
286
# Create logic arrays
287
array1 = LogicArray([Logic.1, Logic.0, Logic.1, Logic.0]) # 0b1010
288
array2 = LogicArray([Logic.0, Logic.1, Logic.X, Logic.Z]) # with X and Z
289
290
# Access properties
291
cocotb.log.info(f"Array1 binary: {array1.binstr}")
292
cocotb.log.info(f"Array1 integer: {array1.integer}")
293
294
cocotb.log.info(f"Array2 binary: {array2.binstr}")
295
cocotb.log.info(f"Array2 integer: {array2.integer}") # X/Z resolved to 0
296
297
# Convert to BinaryValue
298
bv1 = array1.to_BinaryValue()
299
bv2 = array2.to_BinaryValue()
300
301
cocotb.log.info(f"BinaryValue1: 0x{bv1.integer:X}")
302
cocotb.log.info(f"BinaryValue2 resolvable: {bv2.is_resolvable}")
303
304
# Use with DUT signals
305
dut.logic_signal.value = array1
306
await Timer(10, units="ns")
307
```
308
309
### Container Types
310
311
HDL-compatible container types for arrays and ranges with proper indexing semantics.
312
313
```python { .api }
314
class Array[T](obj, range):
315
"""
316
Fixed-size arbitrarily-indexed array.
317
318
Parameters:
319
- obj: Object to wrap as array
320
- range: Range object defining array bounds
321
322
Properties:
323
- range: Range object for array bounds
324
325
Supports:
326
- Indexing: array[index]
327
- Slicing: array[start:end]
328
- Iteration: for item in array
329
"""
330
331
@property
332
def range(self):
333
"""Get range object defining array bounds."""
334
335
class Range(left, direction, right):
336
"""
337
HDL-style inclusive range specification.
338
339
Parameters:
340
- left: Left bound of range
341
- direction: "to" or "downto"
342
- right: Right bound of range
343
344
Properties:
345
- left: Left bound
346
- right: Right bound
347
- direction: Range direction
348
349
Methods:
350
- to_range(): Convert to Python range object
351
- from_range(range): Create Range from Python range
352
"""
353
354
@property
355
def left(self) -> int:
356
"""Get left bound of range."""
357
358
@property
359
def right(self) -> int:
360
"""Get right bound of range."""
361
362
@property
363
def direction(self) -> str:
364
"""Get range direction ('to' or 'downto')."""
365
366
def to_range(self):
367
"""
368
Convert to Python range object.
369
370
Returns:
371
Python range object with equivalent bounds
372
"""
373
374
@classmethod
375
def from_range(cls, range):
376
"""
377
Create Range from Python range object.
378
379
Parameters:
380
- range: Python range object
381
382
Returns:
383
Range object with equivalent bounds
384
"""
385
```
386
387
**Usage Examples:**
388
389
```python
390
@cocotb.test()
391
async def container_types_test(dut):
392
"""Test demonstrating container type operations."""
393
394
from cocotb.types import Array, Range
395
396
# Create HDL-style ranges
397
range1 = Range(31, "downto", 0) # 32-bit word, MSB first
398
range2 = Range(0, "to", 7) # 8-bit byte, LSB first
399
400
cocotb.log.info(f"Range1: {range1.left} {range1.direction} {range1.right}")
401
cocotb.log.info(f"Range2: {range2.left} {range2.direction} {range2.right}")
402
403
# Convert to Python ranges for iteration
404
py_range1 = range1.to_range()
405
py_range2 = range2.to_range()
406
407
cocotb.log.info(f"Python range1: {list(py_range1)}")
408
cocotb.log.info(f"Python range2: {list(py_range2)}")
409
410
# Create arrays with specific ranges
411
if hasattr(dut, 'register_file'):
412
reg_array = Array(dut.register_file, Range(31, "downto", 0))
413
414
# Access array elements using HDL indexing
415
first_reg = reg_array[31] # MSB
416
last_reg = reg_array[0] # LSB
417
418
# Set values
419
first_reg.value = 0xDEAD
420
last_reg.value = 0xBEEF
421
422
await Timer(10, units="ns")
423
424
cocotb.log.info(f"Register[31]: 0x{first_reg.value:X}")
425
cocotb.log.info(f"Register[0]: 0x{last_reg.value:X}")
426
427
@cocotb.test()
428
async def array_slicing_test(dut):
429
"""Test demonstrating array slicing operations."""
430
431
from cocotb.types import Array, Range
432
433
# Create array representing a memory
434
if hasattr(dut, 'memory_block'):
435
memory = Array(dut.memory_block, Range(1023, "downto", 0))
436
437
# Write test pattern to slice
438
for i in range(16):
439
memory[i].value = i * 0x10
440
441
await Timer(50, units="ns")
442
443
# Read back slice
444
for i in range(16):
445
value = memory[i].value
446
expected = i * 0x10
447
assert value == expected, f"Memory[{i}]: expected {expected}, got {value}"
448
449
cocotb.log.info("Array slicing test passed")
450
```
451
452
### Type Operations
453
454
Operations for combining and manipulating HDL-compatible types.
455
456
```python { .api }
457
def concat(a, b, *args):
458
"""
459
Concatenate arrays or values.
460
461
Parameters:
462
- a: First array/value
463
- b: Second array/value
464
- *args: Additional arrays/values to concatenate
465
466
Returns:
467
Concatenated result
468
"""
469
```
470
471
**Usage Examples:**
472
473
```python
474
@cocotb.test()
475
async def type_operations_test(dut):
476
"""Test demonstrating type operations."""
477
478
from cocotb.types import LogicArray, Logic, concat
479
480
# Create arrays to concatenate
481
high_nibble = LogicArray([Logic.1, Logic.0, Logic.1, Logic.1]) # 0xB
482
low_nibble = LogicArray([Logic.0, Logic.1, Logic.0, Logic.1]) # 0x5
483
484
# Concatenate to form byte
485
full_byte = concat(high_nibble, low_nibble)
486
487
cocotb.log.info(f"High nibble: {high_nibble.binstr}")
488
cocotb.log.info(f"Low nibble: {low_nibble.binstr}")
489
cocotb.log.info(f"Concatenated: {full_byte.binstr}")
490
cocotb.log.info(f"Result: 0x{full_byte.integer:02X}")
491
492
# Multiple concatenation
493
byte1 = LogicArray([Logic.1, Logic.1, Logic.0, Logic.0]) # 0xC
494
byte2 = LogicArray([Logic.0, Logic.0, Logic.1, Logic.1]) # 0x3
495
byte3 = LogicArray([Logic.1, Logic.0, Logic.1, Logic.0]) # 0xA
496
497
word = concat(byte1, byte2, byte3, low_nibble) # 16-bit word
498
499
cocotb.log.info(f"Multi-concat result: {word.binstr}")
500
cocotb.log.info(f"Word value: 0x{word.integer:04X}")
501
502
# Use with DUT
503
dut.concat_result.value = word
504
await Timer(10, units="ns")
505
```
506
507
## Advanced Type Usage
508
509
### Custom Type Wrappers
510
511
```python
512
class SignedByte:
513
"""Custom wrapper for signed 8-bit values."""
514
515
def __init__(self, value=0):
516
self._value = BinaryValue(value, n_bits=8,
517
binaryRepresentation=BinaryRepresentation.TWOS_COMPLEMENT)
518
519
@property
520
def value(self):
521
return self._value.signed_integer
522
523
@value.setter
524
def value(self, val):
525
self._value.assign(val)
526
527
@property
528
def binary_value(self):
529
return self._value
530
531
def __str__(self):
532
return f"SignedByte({self.value})"
533
534
@cocotb.test()
535
async def custom_types_test(dut):
536
"""Test demonstrating custom type wrappers."""
537
538
# Create signed byte values
539
sb1 = SignedByte(100)
540
sb2 = SignedByte(-50)
541
542
cocotb.log.info(f"Signed byte 1: {sb1}")
543
cocotb.log.info(f"Signed byte 2: {sb2}")
544
545
# Use with DUT
546
dut.signed_input.value = sb1.binary_value
547
await Timer(10, units="ns")
548
549
# Arithmetic with overflow handling
550
sb1.value = 127 # Maximum positive
551
cocotb.log.info(f"Max positive: {sb1}")
552
553
sb1.value = 128 # Wraps to -128
554
cocotb.log.info(f"Overflow to: {sb1}")
555
```
556
557
### Type Conversion Utilities
558
559
```python
560
def to_logic_array(value, width=None):
561
"""Convert various types to LogicArray."""
562
from cocotb.types import LogicArray, Logic
563
564
if isinstance(value, str):
565
# Convert binary string
566
logic_bits = []
567
for char in value:
568
if char == '0':
569
logic_bits.append(Logic.0)
570
elif char == '1':
571
logic_bits.append(Logic.1)
572
elif char.upper() == 'X':
573
logic_bits.append(Logic.X)
574
elif char.upper() == 'Z':
575
logic_bits.append(Logic.Z)
576
return LogicArray(logic_bits)
577
578
elif isinstance(value, int):
579
# Convert integer to LogicArray
580
if width is None:
581
width = value.bit_length() if value > 0 else 1
582
583
binary_str = format(value, f'0{width}b')
584
return to_logic_array(binary_str)
585
586
else:
587
raise ValueError(f"Cannot convert {type(value)} to LogicArray")
588
589
@cocotb.test()
590
async def conversion_test(dut):
591
"""Test demonstrating type conversion utilities."""
592
593
# Convert from different sources
594
from_string = to_logic_array("1010X01Z")
595
from_int = to_logic_array(0xAB, width=8)
596
597
cocotb.log.info(f"From string: {from_string.binstr}")
598
cocotb.log.info(f"From int: {from_int.binstr}")
599
600
# Use converted values
601
dut.test_input1.value = from_string
602
dut.test_input2.value = from_int
603
604
await Timer(20, units="ns")
605
```