or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

binary-types.mdclock-generation.mdindex.mdlogging-utilities.mdsignal-handling.mdtask-management.mdtest-framework.mdtriggers-timing.md

logging-utilities.mddocs/

0

# Logging and Utilities

1

2

Cocotb's logging and utilities system provides simulation-aware logging, time manipulation functions, queue implementations, and debugging tools. The system integrates simulation time context with Python's logging framework and offers utilities for testbench development.

3

4

## Capabilities

5

6

### Simulation-Aware Logging

7

8

Logging system with simulation time context and hierarchical naming for testbench debugging.

9

10

```python { .api }

11

class SimLog:

12

"""

13

Simulator-aware logger with hierarchical naming.

14

15

Automatically adds simulation time and hierarchical context to log messages.

16

Inherits from Python's logging.Logger with simulation-specific enhancements.

17

18

Methods:

19

- debug(msg, *args, **kwargs): Debug level logging

20

- info(msg, *args, **kwargs): Info level logging

21

- warning(msg, *args, **kwargs): Warning level logging

22

- error(msg, *args, **kwargs): Error level logging

23

- critical(msg, *args, **kwargs): Critical level logging

24

"""

25

26

class SimLogFormatter:

27

"""Custom log formatter for simulator logs."""

28

29

class SimColourLogFormatter(SimLogFormatter):

30

"""Colored log formatter for enhanced readability."""

31

32

class SimTimeContextFilter:

33

"""Filter to add simulation time context to log records."""

34

35

def default_config():

36

"""

37

Apply default logging configuration for cocotb.

38

39

Sets up simulation-aware logging with appropriate formatters

40

and filters for testbench development.

41

"""

42

```

43

44

**Usage Examples:**

45

46

```python

47

@cocotb.test()

48

async def logging_test(dut):

49

"""Test demonstrating simulation-aware logging."""

50

51

# Use cocotb's global logger

52

cocotb.log.info("Test started")

53

54

# Create hierarchical loggers

55

test_log = SimLog("test.main")

56

dut_log = SimLog("test.dut")

57

monitor_log = SimLog("test.monitor.data_bus")

58

59

# Log at different levels with time stamps

60

test_log.debug("Debug message - detailed info")

61

test_log.info("Test phase 1 starting")

62

test_log.warning("Potential timing issue detected")

63

64

# Simulate some time passing

65

await Timer(100, units="ns")

66

67

# Logs automatically include simulation time

68

dut_log.info(f"DUT state: {dut.state.value}")

69

monitor_log.info(f"Data bus activity: {dut.data_bus.value}")

70

71

await Timer(50, units="ns")

72

73

# Error logging

74

if dut.error_flag.value:

75

test_log.error("Error condition detected!")

76

77

test_log.info("Test completed successfully")

78

79

@cocotb.test()

80

async def hierarchical_logging_test(dut):

81

"""Test demonstrating hierarchical logging structure."""

82

83

# Create logger hierarchy for complex testbench

84

main_log = SimLog("testbench")

85

cpu_log = SimLog("testbench.cpu")

86

memory_log = SimLog("testbench.memory")

87

bus_log = SimLog("testbench.interconnect.bus")

88

89

# Coordinated logging from different components

90

main_log.info("Starting system-level test")

91

92

cpu_log.info("CPU initialization")

93

await Timer(25, units="ns")

94

95

memory_log.info("Memory subsystem ready")

96

await Timer(25, units="ns")

97

98

bus_log.info("Bus protocol check")

99

await Timer(25, units="ns")

100

101

main_log.info("All subsystems initialized")

102

103

# Component-specific detailed logging

104

for i in range(3):

105

cpu_log.debug(f"Instruction fetch cycle {i}")

106

bus_log.debug(f"Bus transaction {i}: read request")

107

memory_log.debug(f"Memory read from address 0x{i*4:08X}")

108

await Timer(20, units="ns")

109

110

main_log.info("Test sequence completed")

111

```

112

113

### Time Utilities

114

115

Functions for simulation time manipulation and conversion between different time units.

116

117

```python { .api }

118

def get_sim_time(units="step"):

119

"""

120

Get current simulation time.

121

122

Parameters:

123

- units: Time units to return ("fs", "ps", "ns", "us", "ms", "sec", "step")

124

125

Returns:

126

Current simulation time in specified units

127

"""

128

129

def get_time_from_sim_steps(steps, units):

130

"""

131

Convert simulation steps to time units.

132

133

Parameters:

134

- steps: Number of simulation steps

135

- units: Target time units

136

137

Returns:

138

Time value in specified units

139

"""

140

141

def get_sim_steps(time, units, round_mode=None):

142

"""

143

Convert time to simulation steps.

144

145

Parameters:

146

- time: Time value

147

- units: Time units of input

148

- round_mode: Rounding mode for conversion

149

150

Returns:

151

Number of simulation steps

152

"""

153

```

154

155

**Usage Examples:**

156

157

```python

158

@cocotb.test()

159

async def time_utilities_test(dut):

160

"""Test demonstrating time utility functions."""

161

162

# Record start time

163

start_time_ns = get_sim_time("ns")

164

start_time_ps = get_sim_time("ps")

165

start_time_steps = get_sim_time("step")

166

167

cocotb.log.info(f"Test start: {start_time_ns} ns, {start_time_ps} ps, {start_time_steps} steps")

168

169

# Simulate some time

170

await Timer(150, units="ns")

171

172

# Check elapsed time

173

current_time_ns = get_sim_time("ns")

174

elapsed_ns = current_time_ns - start_time_ns

175

176

cocotb.log.info(f"Elapsed time: {elapsed_ns} ns")

177

178

# Convert between units

179

steps_in_100ns = get_sim_steps(100, "ns")

180

time_from_steps = get_time_from_sim_steps(steps_in_100ns, "ps")

181

182

cocotb.log.info(f"100ns = {steps_in_100ns} steps = {time_from_steps} ps")

183

184

# Performance measurement

185

operation_start = get_sim_time("ps")

186

187

# Simulate some operation

188

for i in range(10):

189

dut.data.value = i

190

await Timer(5, units="ns")

191

192

operation_end = get_sim_time("ps")

193

operation_duration = operation_end - operation_start

194

195

cocotb.log.info(f"Operation took {operation_duration} ps ({operation_duration/1000} ns)")

196

197

@cocotb.test()

198

async def timing_analysis_test(dut):

199

"""Test demonstrating timing analysis with utilities."""

200

201

# Measure setup and hold times

202

timestamps = []

203

204

# Clock edge timing

205

for cycle in range(5):

206

await RisingEdge(dut.clk)

207

edge_time = get_sim_time("ps")

208

timestamps.append(edge_time)

209

210

# Setup time check

211

dut.data_in.value = cycle

212

setup_time = get_sim_time("ps")

213

214

cocotb.log.info(f"Cycle {cycle}: Clock edge at {edge_time} ps, data setup at {setup_time} ps")

215

216

# Check setup timing

217

setup_margin = edge_time - setup_time # Should be negative (data before clock)

218

if setup_margin > -1000: # Less than 1ns setup

219

cocotb.log.warning(f"Setup time violation: {setup_margin} ps")

220

221

# Calculate clock period statistics

222

periods = []

223

for i in range(1, len(timestamps)):

224

period = timestamps[i] - timestamps[i-1]

225

periods.append(period)

226

227

avg_period = sum(periods) / len(periods)

228

frequency_mhz = 1e6 / avg_period # Convert ps to MHz

229

230

cocotb.log.info(f"Average clock period: {avg_period} ps ({frequency_mhz:.2f} MHz)")

231

```

232

233

### Queue System

234

235

Async queue implementations for producer-consumer patterns and inter-coroutine communication.

236

237

```python { .api }

238

class Queue[T](maxsize=0):

239

"""

240

Generic async queue implementation.

241

242

Parameters:

243

- maxsize: Maximum queue size (0 for unlimited)

244

245

Methods:

246

- put(item): Put item into queue (async)

247

- get(): Get item from queue (async)

248

- put_nowait(item): Put item without waiting

249

- get_nowait(): Get item without waiting

250

- qsize(): Get current queue size

251

- empty(): Check if queue is empty

252

- full(): Check if queue is full

253

"""

254

255

async def put(self, item):

256

"""

257

Put item into queue.

258

259

Parameters:

260

- item: Item to add to queue

261

262

Blocks if queue is full until space available.

263

"""

264

265

async def get(self):

266

"""

267

Get item from queue.

268

269

Returns:

270

Item from queue

271

272

Blocks if queue is empty until item available.

273

"""

274

275

def put_nowait(self, item):

276

"""

277

Put item without waiting.

278

279

Parameters:

280

- item: Item to add

281

282

Raises:

283

QueueFull: If queue is at capacity

284

"""

285

286

def get_nowait(self):

287

"""

288

Get item without waiting.

289

290

Returns:

291

Item from queue

292

293

Raises:

294

QueueEmpty: If queue is empty

295

"""

296

297

def qsize(self) -> int:

298

"""Get current number of items in queue."""

299

300

@property

301

def maxsize(self) -> int:

302

"""Get maximum number of items allowed in queue."""

303

304

def empty(self) -> bool:

305

"""Check if queue is empty."""

306

307

def full(self) -> bool:

308

"""Check if queue is full."""

309

310

class PriorityQueue(maxsize=0):

311

"""

312

Priority queue implementation (smallest item first).

313

314

Items should be comparable or tuples of (priority, item).

315

"""

316

317

class LifoQueue(maxsize=0):

318

"""

319

LIFO queue (stack) implementation.

320

321

Last item put is first item retrieved.

322

"""

323

324

class QueueFull(Exception):

325

"""Raised when queue is full and put_nowait() is called."""

326

327

class QueueEmpty(Exception):

328

"""Raised when queue is empty and get_nowait() is called."""

329

```

330

331

**Usage Examples:**

332

333

```python

334

@cocotb.test()

335

async def queue_basic_test(dut):

336

"""Test demonstrating basic queue operations."""

337

338

# Create bounded queue

339

data_queue = Queue(maxsize=5)

340

341

# Producer coroutine

342

async def producer():

343

for i in range(10):

344

await data_queue.put(f"data_{i}")

345

cocotb.log.info(f"Produced: data_{i} (queue size: {data_queue.qsize()})")

346

await Timer(20, units="ns")

347

348

# Consumer coroutine

349

async def consumer():

350

consumed = []

351

while len(consumed) < 10:

352

item = await data_queue.get()

353

consumed.append(item)

354

cocotb.log.info(f"Consumed: {item} (queue size: {data_queue.qsize()})")

355

await Timer(30, units="ns") # Slower than producer

356

return consumed

357

358

# Run producer and consumer concurrently

359

producer_task = cocotb.start_soon(producer())

360

consumer_task = cocotb.start_soon(consumer())

361

362

# Wait for completion

363

await producer_task.join()

364

consumed_items = await consumer_task.join()

365

366

cocotb.log.info(f"Test completed. Consumed {len(consumed_items)} items")

367

368

@cocotb.test()

369

async def queue_types_test(dut):

370

"""Test demonstrating different queue types."""

371

372

# FIFO queue (default)

373

fifo_queue = Queue()

374

375

# LIFO queue (stack)

376

lifo_queue = LifoQueue()

377

378

# Priority queue

379

priority_queue = PriorityQueue()

380

381

# Fill queues with test data

382

test_items = ["first", "second", "third"]

383

priorities = [(3, "low"), (1, "high"), (2, "medium")]

384

385

# FIFO operations

386

for item in test_items:

387

await fifo_queue.put(item)

388

389

fifo_result = []

390

while not fifo_queue.empty():

391

fifo_result.append(await fifo_queue.get())

392

393

# LIFO operations

394

for item in test_items:

395

await lifo_queue.put(item)

396

397

lifo_result = []

398

while not lifo_queue.empty():

399

lifo_result.append(await lifo_queue.get())

400

401

# Priority operations

402

for priority_item in priorities:

403

await priority_queue.put(priority_item)

404

405

priority_result = []

406

while not priority_queue.empty():

407

priority_result.append(await priority_queue.get())

408

409

# Log results

410

cocotb.log.info(f"FIFO order: {fifo_result}")

411

cocotb.log.info(f"LIFO order: {lifo_result}")

412

cocotb.log.info(f"Priority order: {priority_result}")

413

414

@cocotb.test()

415

async def queue_flow_control_test(dut):

416

"""Test demonstrating queue flow control."""

417

418

# Small queue to test flow control

419

flow_queue = Queue(maxsize=2)

420

421

# Fast producer that will block

422

async def fast_producer():

423

for i in range(6):

424

cocotb.log.info(f"Attempting to put item_{i}")

425

await flow_queue.put(f"item_{i}")

426

cocotb.log.info(f"Successfully put item_{i}")

427

await Timer(10, units="ns")

428

429

# Slow consumer

430

async def slow_consumer():

431

consumed = []

432

for _ in range(6):

433

await Timer(50, units="ns") # Slow processing

434

item = await flow_queue.get()

435

consumed.append(item)

436

cocotb.log.info(f"Consumed: {item}")

437

return consumed

438

439

# Run with flow control

440

producer_task = cocotb.start_soon(fast_producer())

441

consumer_task = cocotb.start_soon(slow_consumer())

442

443

await consumer_task.join()

444

await producer_task.join()

445

446

cocotb.log.info("Flow control test completed")

447

```

448

449

### Debugging Utilities

450

451

Tools for debugging coroutines, handling tracebacks, and development support.

452

453

```python { .api }

454

def want_color_output() -> bool:

455

"""

456

Check if colored terminal output is wanted.

457

458

Returns:

459

True if colored output should be used

460

"""

461

462

def remove_traceback_frames(tb_or_exc, frame_names):

463

"""

464

Strip specific frames from traceback for cleaner error reporting.

465

466

Parameters:

467

- tb_or_exc: Traceback or exception object

468

- frame_names: List of frame names to remove

469

470

Returns:

471

Cleaned traceback

472

"""

473

474

def walk_coro_stack(coro):

475

"""

476

Walk coroutine call stack for debugging.

477

478

Parameters:

479

- coro: Coroutine to examine

480

481

Returns:

482

Iterator over stack frames

483

"""

484

485

def extract_coro_stack(coro, limit=None):

486

"""

487

Extract coroutine call stack as list.

488

489

Parameters:

490

- coro: Coroutine to examine

491

- limit: Maximum number of frames

492

493

Returns:

494

List of stack frames

495

"""

496

```

497

498

**Usage Examples:**

499

500

```python

501

@cocotb.test()

502

async def debugging_test(dut):

503

"""Test demonstrating debugging utilities."""

504

505

# Check terminal capabilities

506

if want_color_output():

507

cocotb.log.info("Color output is available")

508

else:

509

cocotb.log.info("Color output not available")

510

511

# Start a coroutine for stack inspection

512

debug_task = cocotb.start_soon(nested_coroutine_example(dut))

513

514

# Allow some execution

515

await Timer(50, units="ns")

516

517

# Extract coroutine stack

518

if not debug_task.done():

519

stack = extract_coro_stack(debug_task._handle, limit=5)

520

cocotb.log.info(f"Coroutine stack has {len(stack)} frames")

521

522

for i, frame in enumerate(stack):

523

cocotb.log.info(f" Frame {i}: {frame}")

524

525

# Wait for completion

526

await debug_task.join()

527

528

async def nested_coroutine_example(dut):

529

"""Example nested coroutine for stack inspection."""

530

531

async def level_1():

532

await level_2()

533

534

async def level_2():

535

await level_3()

536

537

async def level_3():

538

# This creates a deep call stack

539

await Timer(100, units="ns")

540

return "completed"

541

542

return await level_1()

543

544

@cocotb.test()

545

async def error_handling_test(dut):

546

"""Test demonstrating error handling utilities."""

547

548

async def failing_coroutine():

549

await Timer(25, units="ns")

550

raise ValueError("Intentional test error")

551

552

# Catch and analyze error

553

try:

554

await failing_coroutine()

555

except Exception as e:

556

cocotb.log.info(f"Caught exception: {e}")

557

558

# Get clean traceback

559

import traceback

560

tb = traceback.format_exc()

561

cocotb.log.info("Full traceback:")

562

for line in tb.split('\n'):

563

if line.strip():

564

cocotb.log.info(f" {line}")

565

```

566

567

### Deprecated Utilities

568

569

Legacy utility functions maintained for backwards compatibility.

570

571

```python { .api }

572

def hexdump(x):

573

"""

574

DEPRECATED: Hexdump of buffer.

575

576

Parameters:

577

- x: Buffer to dump

578

579

Returns:

580

Hexadecimal representation string

581

"""

582

583

def hexdiffs(x, y):

584

"""

585

DEPRECATED: Show hex differences between buffers.

586

587

Parameters:

588

- x: First buffer

589

- y: Second buffer

590

591

Returns:

592

String showing differences

593

"""

594

595

def pack(ctypes_obj):

596

"""

597

DEPRECATED: Convert ctypes object to string.

598

599

Parameters:

600

- ctypes_obj: Ctypes object to convert

601

602

Returns:

603

String representation

604

"""

605

606

def unpack(ctypes_obj, string, bytes=None):

607

"""

608

DEPRECATED: Unpack string to ctypes object.

609

610

Parameters:

611

- ctypes_obj: Target ctypes object

612

- string: String to unpack

613

- bytes: Optional byte specification

614

615

Returns:

616

Unpacked ctypes object

617

"""

618

```

619

620

### Utility Classes

621

622

Helper classes for advanced patterns and singleton implementations.

623

624

```python { .api }

625

class ParametrizedSingleton(type):

626

"""

627

Metaclass for parametrized singleton pattern.

628

629

Creates singleton instances based on constructor parameters.

630

"""

631

632

class lazy_property:

633

"""

634

Property decorator for lazy evaluation.

635

636

Property value is computed only once and cached.

637

"""

638

```

639

640

**Usage Examples:**

641

642

```python

643

class ConfigManager(metaclass=ParametrizedSingleton):

644

"""Example using parametrized singleton."""

645

646

def __init__(self, config_name):

647

self.config_name = config_name

648

self.settings = {}

649

cocotb.log.info(f"Created config manager for: {config_name}")

650

651

class TestBench:

652

"""Example using lazy property."""

653

654

def __init__(self, dut):

655

self.dut = dut

656

657

@lazy_property

658

def memory_map(self):

659

"""Expensive computation done only once."""

660

cocotb.log.info("Computing memory map...")

661

# Simulate expensive operation

662

return {"base": 0x1000, "size": 0x1000}

663

664

@cocotb.test()

665

async def utility_classes_test(dut):

666

"""Test demonstrating utility classes."""

667

668

# Singleton pattern test

669

config1 = ConfigManager("test_config")

670

config2 = ConfigManager("test_config") # Same instance

671

config3 = ConfigManager("other_config") # Different instance

672

673

assert config1 is config2 # Same singleton

674

assert config1 is not config3 # Different parameter

675

676

# Lazy property test

677

tb = TestBench(dut)

678

679

# First access computes value

680

mem_map1 = tb.memory_map

681

682

# Second access uses cached value

683

mem_map2 = tb.memory_map

684

685

assert mem_map1 is mem_map2 # Same cached object

686

cocotb.log.info(f"Memory map: {mem_map1}")

687

```