0
# Test Framework
1
2
The cocotb test framework provides decorators and infrastructure for defining, discovering, and executing HDL testbenches using Python's async/await syntax. Tests are automatically discovered and can be configured with timeouts, failure expectations, and execution stages.
3
4
## Capabilities
5
6
### Test Decorator
7
8
Marks async functions as tests with optional configuration for timeouts, failure expectations, and execution control.
9
10
```python { .api }
11
@test(timeout_time=None, timeout_unit="step", expect_fail=False, expect_error=(), skip=False, stage=0)
12
def test_decorator(func):
13
"""
14
Decorator to mark a Callable which returns a Coroutine as a test.
15
16
Parameters:
17
- timeout_time (numbers.Real or decimal.Decimal, optional): Simulation time duration before timeout
18
- timeout_unit (str, optional): Units of timeout_time, accepts any units that Timer does
19
- expect_fail (bool, optional): If True, test passes when it fails a functional check
20
- expect_error (exception type or tuple, optional): Test passes only if specified exception types are raised
21
- skip (bool, optional): Don't execute this test as part of regression
22
- stage (int): Order tests logically into stages, defaults to 0
23
24
Returns:
25
Test coroutine decorator
26
"""
27
```
28
29
**Usage Examples:**
30
31
```python
32
@cocotb.test()
33
async def basic_test(dut):
34
"""Simple test without configuration."""
35
await Timer(100, units="ns")
36
assert dut.output.value == 1
37
38
@cocotb.test(timeout_time=1000, timeout_unit="ns")
39
async def timed_test(dut):
40
"""Test with timeout protection."""
41
# Long-running test operations
42
await Timer(500, units="ns")
43
44
@cocotb.test(expect_fail=True)
45
async def failing_test(dut):
46
"""Test that expects to fail."""
47
assert False, "This test is expected to fail"
48
49
@cocotb.test(expect_error=ValueError)
50
async def error_test(dut):
51
"""Test that expects specific exception."""
52
raise ValueError("Expected error")
53
54
@cocotb.test(skip=True)
55
async def skipped_test(dut):
56
"""Test that will be skipped."""
57
pass
58
59
@cocotb.test(stage=1)
60
async def staged_test(dut):
61
"""Test in execution stage 1."""
62
await Timer(50, units="ns")
63
```
64
65
### Coroutine Decorator
66
67
Transforms functions into coroutines with logging capabilities and join functionality for creating reusable testbench components.
68
69
```python { .api }
70
@coroutine
71
def coroutine_decorator(func):
72
"""
73
Decorator class that provides common coroutine mechanisms.
74
75
Features:
76
- log methods will log to cocotb.coroutine.name
77
- join method returns event which fires when coroutine exits
78
79
Returns:
80
Coroutine with enhanced capabilities
81
"""
82
```
83
84
**Usage Examples:**
85
86
```python
87
@cocotb.coroutine
88
async def stimulus_generator(dut, data_list):
89
"""Reusable stimulus generation coroutine."""
90
for data in data_list:
91
dut.input_data.value = data
92
await RisingEdge(dut.clk)
93
stimulus_generator.log.info(f"Applied stimulus: {data}")
94
95
@cocotb.coroutine
96
async def response_checker(dut, expected_list):
97
"""Reusable response checking coroutine."""
98
for expected in expected_list:
99
await RisingEdge(dut.clk)
100
actual = dut.output_data.value
101
assert actual == expected, f"Expected {expected}, got {actual}"
102
response_checker.log.info(f"Verified response: {actual}")
103
104
@cocotb.test()
105
async def coordinated_test(dut):
106
"""Test using coroutine components."""
107
stim_task = cocotb.start_soon(stimulus_generator(dut, [1, 2, 3, 4]))
108
check_task = cocotb.start_soon(response_checker(dut, [1, 2, 3, 4]))
109
110
await stim_task.join()
111
await check_task.join()
112
```
113
114
### External Decorator
115
116
Wraps functions to run in separate threads, enabling blocking operations without stopping simulation time progression.
117
118
```python { .api }
119
@external
120
def external_decorator(func):
121
"""
122
Decorator to apply to an external function to enable calling from cocotb.
123
124
Converts normal function into blocking coroutine that runs in separate thread.
125
Currently creates new execution thread for each function call.
126
127
Returns:
128
Blocking coroutine that yields until thread completion
129
"""
130
```
131
132
**Usage Examples:**
133
134
```python
135
@cocotb.external
136
def file_operation(filename):
137
"""External function for file I/O."""
138
with open(filename, 'r') as f:
139
data = f.read()
140
time.sleep(1) # Simulate slow operation
141
return data.strip()
142
143
@cocotb.external
144
def network_request(url):
145
"""External function for network operations."""
146
import requests
147
response = requests.get(url)
148
return response.json()
149
150
@cocotb.test()
151
async def external_test(dut):
152
"""Test using external functions."""
153
# These operations run in threads and don't block simulation
154
config_data = await file_operation("config.txt")
155
api_data = await network_request("http://api.example.com/data")
156
157
# Use the data in simulation
158
dut.config.value = int(config_data)
159
dut.api_value.value = api_data['value']
160
161
await Timer(100, units="ns")
162
```
163
164
### Function Decorator
165
166
Creates functions that can block simulation time while being called from external threads, bridging threaded code back to simulation context.
167
168
```python { .api }
169
@function
170
def function_decorator(func):
171
"""
172
Decorator for functions that can block and consume simulation time.
173
174
Allows coroutine that consumes simulation time to be called by thread
175
started with @external. Function internally blocks while externally
176
appears to yield.
177
178
Returns:
179
Function that can be called from external threads
180
"""
181
```
182
183
**Usage Examples:**
184
185
```python
186
@cocotb.function
187
async def wait_for_condition(dut, signal, value, timeout_ns=1000):
188
"""Function that waits for signal condition."""
189
start_time = get_sim_time("ns")
190
191
while dut._id(signal, extended=False).value != value:
192
await Timer(10, units="ns")
193
current_time = get_sim_time("ns")
194
195
if current_time - start_time > timeout_ns:
196
raise TimeoutError(f"Signal {signal} never reached {value}")
197
198
return current_time - start_time
199
200
@cocotb.external
201
def threaded_test_sequence(dut):
202
"""External function that calls back into simulation."""
203
import threading
204
205
# This external function can call @function decorated functions
206
duration = wait_for_condition(dut, "ready", 1, 500)
207
print(f"Ready signal asserted after {duration} ns")
208
209
return "sequence_complete"
210
211
@cocotb.test()
212
async def hybrid_test(dut):
213
"""Test combining external and function decorators."""
214
# Start external thread that will call back into simulation
215
result = await threaded_test_sequence(dut)
216
assert result == "sequence_complete"
217
```
218
219
## Public Utility Function
220
221
### Public Decorator
222
223
Utility decorator for marking functions as part of the public API.
224
225
```python { .api }
226
def public(f):
227
"""
228
Use decorator to avoid retyping function/class names.
229
230
Adds function name to module's __all__ list to mark as public API.
231
232
Parameters:
233
- f: Function to mark as public
234
235
Returns:
236
The original function unchanged
237
"""
238
```
239
240
## Test Execution Context
241
242
### Global Test Variables
243
244
During test execution, cocotb provides access to test context through global variables:
245
246
```python { .api }
247
# Available during test execution
248
cocotb.regression_manager # Access to test execution manager
249
cocotb.scheduler # Access to coroutine scheduler
250
cocotb.top # Handle to top-level design entity (DUT)
251
cocotb.argv # Command-line arguments from simulator
252
cocotb.plusargs # Plus-args from simulator command line
253
```
254
255
**Usage Examples:**
256
257
```python
258
@cocotb.test()
259
async def context_test(dut):
260
"""Test accessing execution context."""
261
# Access top-level design directly
262
assert cocotb.top is dut # They reference the same object
263
264
# Check simulator arguments
265
if "debug" in cocotb.plusargs:
266
cocotb.log.info("Debug mode enabled")
267
268
# Access scheduler for advanced operations
269
current_time = cocotb.scheduler.sim_time
270
cocotb.log.info(f"Test started at {current_time}")
271
```