or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

database-operations.mdfile-io.mdhierarchical-design.mdindex.mdlayout-viewer.mdshape-operations.mdtransformations.mdverification.md

verification.mddocs/

0

# Verification and Results Management

1

2

Design rule checking (DRC), layout versus schematic (LVS) capabilities, and results database management for storing and analyzing verification reports in IC layout workflows.

3

4

## Capabilities

5

6

### Results Database Management

7

8

```python { .api }

9

class ReportDatabase:

10

def __init__(self, name: str):

11

"""

12

Create a results database for verification reports.

13

14

Parameters:

15

- name: Database name

16

"""

17

18

@property

19

def name(self) -> str:

20

"""Get database name."""

21

22

def set_name(self, name: str) -> None:

23

"""Set database name."""

24

25

def create_category(self, name: str) -> Category:

26

"""

27

Create a new result category.

28

29

Parameters:

30

- name: Category name (e.g., "Width Violations", "Spacing Errors")

31

32

Returns:

33

Category: New category object

34

"""

35

36

def category_by_name(self, name: str) -> Category:

37

"""Get category by name."""

38

39

def each_category(self):

40

"""Iterate over all categories."""

41

42

def num_categories(self) -> int:

43

"""Get number of categories."""

44

45

def save(self, filename: str) -> None:

46

"""

47

Save database to file.

48

49

Parameters:

50

- filename: Output file path

51

"""

52

53

def load(self, filename: str) -> None:

54

"""

55

Load database from file.

56

57

Parameters:

58

- filename: Input file path

59

"""

60

61

def clear(self) -> None:

62

"""Clear all categories and items."""

63

64

class Category:

65

def __init__(self, name: str = ""):

66

"""

67

Create a result category.

68

69

Parameters:

70

- name: Category name

71

"""

72

73

@property

74

def name(self) -> str:

75

"""Get category name."""

76

77

def set_name(self, name: str) -> None:

78

"""Set category name."""

79

80

@property

81

def description(self) -> str:

82

"""Get category description."""

83

84

def set_description(self, description: str) -> None:

85

"""Set category description."""

86

87

def create_item(self, polygon: Polygon = None) -> Item:

88

"""

89

Create a new result item in this category.

90

91

Parameters:

92

- polygon: Optional polygon representing the violation area

93

94

Returns:

95

Item: New result item

96

"""

97

98

def each_item(self):

99

"""Iterate over all items in category."""

100

101

def num_items(self) -> int:

102

"""Get number of items in category."""

103

104

def clear(self) -> None:

105

"""Clear all items from category."""

106

107

class Item:

108

def __init__(self):

109

"""Create a result item."""

110

111

def add_value(self, value: Value) -> None:

112

"""

113

Add a measurement value to the item.

114

115

Parameters:

116

- value: Measurement or property value

117

"""

118

119

def each_value(self):

120

"""Iterate over all values."""

121

122

def num_values(self) -> int:

123

"""Get number of values."""

124

125

def add_tag(self, tag: Tags) -> None:

126

"""Add a tag to categorize the item."""

127

128

def each_tag(self):

129

"""Iterate over all tags."""

130

131

def set_visited(self, visited: bool) -> None:

132

"""Mark item as visited/reviewed."""

133

134

def visited(self) -> bool:

135

"""Check if item has been visited."""

136

137

class Value:

138

def __init__(self, value=None):

139

"""

140

Create a measurement value.

141

142

Parameters:

143

- value: Numeric value, string, or geometric object

144

"""

145

146

def is_numeric(self) -> bool:

147

"""Check if value is numeric."""

148

149

def is_string(self) -> bool:

150

"""Check if value is string."""

151

152

def is_geometric(self) -> bool:

153

"""Check if value represents geometry."""

154

155

def to_s(self) -> str:

156

"""Convert value to string representation."""

157

158

class Tags:

159

def __init__(self, tag: str = ""):

160

"""

161

Create a tag for result categorization.

162

163

Parameters:

164

- tag: Tag string

165

"""

166

167

@property

168

def tag(self) -> str:

169

"""Get tag string."""

170

171

def set_tag(self, tag: str) -> None:

172

"""Set tag string."""

173

```

174

175

### Design Rule Checking Operations

176

177

```python { .api }

178

# DRC operations are primarily performed using Region methods

179

# from the shape operations module

180

181

class Region:

182

def width_check(self, d: int, whole_edges: bool = False,

183

metrics: str = "euclidean", ignore_angle: float = None) -> EdgePairs:

184

"""

185

Check minimum width rule.

186

187

Parameters:

188

- d: Minimum width requirement

189

- whole_edges: Check whole edges vs. edge segments

190

- metrics: Distance metrics ("euclidean", "square", "projected")

191

- ignore_angle: Ignore edges at this angle (degrees)

192

193

Returns:

194

EdgePairs: Width violations as edge pairs

195

"""

196

197

def space_check(self, d: int, whole_edges: bool = False,

198

metrics: str = "euclidean", ignore_angle: float = None) -> EdgePairs:

199

"""

200

Check minimum spacing rule.

201

202

Parameters:

203

- d: Minimum spacing requirement

204

- whole_edges: Check whole edges vs. edge segments

205

- metrics: Distance metrics

206

- ignore_angle: Ignore edges at this angle

207

208

Returns:

209

EdgePairs: Spacing violations as edge pairs

210

"""

211

212

def enclosing_check(self, other: Region, d: int,

213

whole_edges: bool = False) -> EdgePairs:

214

"""

215

Check enclosure rule (this region must enclose other by distance d).

216

217

Parameters:

218

- other: Region to be enclosed

219

- d: Minimum enclosure distance

220

- whole_edges: Check whole edges vs. segments

221

222

Returns:

223

EdgePairs: Enclosure violations

224

"""

225

226

def overlap_check(self, other: Region, d: int,

227

whole_edges: bool = False) -> EdgePairs:

228

"""

229

Check overlap rule (regions must overlap by at least distance d).

230

231

Parameters:

232

- other: Other region to check overlap with

233

- d: Minimum overlap distance

234

- whole_edges: Check whole edges vs. segments

235

236

Returns:

237

EdgePairs: Overlap violations

238

"""

239

240

def separation_check(self, other: Region, d: int,

241

whole_edges: bool = False) -> EdgePairs:

242

"""

243

Check separation rule (regions must be separated by at least d).

244

245

Parameters:

246

- other: Other region to check separation from

247

- d: Minimum separation distance

248

- whole_edges: Check whole edges vs. segments

249

250

Returns:

251

EdgePairs: Separation violations

252

"""

253

254

def notch_check(self, d: int) -> EdgePairs:

255

"""

256

Check for notches smaller than minimum width.

257

258

Parameters:

259

- d: Minimum notch width

260

261

Returns:

262

EdgePairs: Notch violations

263

"""

264

265

def isolated_check(self, d: int) -> EdgePairs:

266

"""

267

Check for isolated features smaller than minimum size.

268

269

Parameters:

270

- d: Minimum feature size

271

272

Returns:

273

EdgePairs: Isolated feature violations

274

"""

275

```

276

277

### Netlist and Circuit Analysis

278

279

```python { .api }

280

class Netlist:

281

def __init__(self):

282

"""Create an empty netlist."""

283

284

def create_circuit(self, name: str) -> Circuit:

285

"""

286

Create a new circuit in the netlist.

287

288

Parameters:

289

- name: Circuit name

290

291

Returns:

292

Circuit: New circuit object

293

"""

294

295

def circuit_by_name(self, name: str) -> Circuit:

296

"""Get circuit by name."""

297

298

def each_circuit(self):

299

"""Iterate over all circuits."""

300

301

def purge(self) -> None:

302

"""Remove unused circuits and nets."""

303

304

def make_top_level_pins(self) -> None:

305

"""Create top-level pins for unconnected nets."""

306

307

class Circuit:

308

def __init__(self, name: str = ""):

309

"""

310

Create a circuit.

311

312

Parameters:

313

- name: Circuit name

314

"""

315

316

@property

317

def name(self) -> str:

318

"""Get circuit name."""

319

320

def create_net(self, name: str = "") -> Net:

321

"""

322

Create a new net in the circuit.

323

324

Parameters:

325

- name: Net name (optional)

326

327

Returns:

328

Net: New net object

329

"""

330

331

def create_device(self, device_class, name: str = "") -> Device:

332

"""

333

Create a device instance.

334

335

Parameters:

336

- device_class: Device class/model

337

- name: Device instance name

338

339

Returns:

340

Device: New device instance

341

"""

342

343

def create_pin(self, name: str) -> Pin:

344

"""

345

Create a circuit pin.

346

347

Parameters:

348

- name: Pin name

349

350

Returns:

351

Pin: New pin object

352

"""

353

354

def each_net(self):

355

"""Iterate over all nets."""

356

357

def each_device(self):

358

"""Iterate over all devices."""

359

360

def each_pin(self):

361

"""Iterate over all pins."""

362

363

class Net:

364

def __init__(self, name: str = ""):

365

"""

366

Create a net.

367

368

Parameters:

369

- name: Net name

370

"""

371

372

@property

373

def name(self) -> str:

374

"""Get net name."""

375

376

def connect_pin(self, pin: Pin) -> None:

377

"""

378

Connect a pin to this net.

379

380

Parameters:

381

- pin: Pin to connect

382

"""

383

384

def each_pin(self):

385

"""Iterate over connected pins."""

386

387

def pin_count(self) -> int:

388

"""Get number of connected pins."""

389

390

class Device:

391

def __init__(self, name: str = ""):

392

"""

393

Create a device.

394

395

Parameters:

396

- name: Device name

397

"""

398

399

@property

400

def name(self) -> str:

401

"""Get device name."""

402

403

def create_terminal(self, name: str) -> Pin:

404

"""

405

Create a device terminal.

406

407

Parameters:

408

- name: Terminal name

409

410

Returns:

411

Pin: Terminal pin

412

"""

413

414

def each_terminal(self):

415

"""Iterate over device terminals."""

416

417

class Pin:

418

def __init__(self, name: str = ""):

419

"""

420

Create a pin.

421

422

Parameters:

423

- name: Pin name

424

"""

425

426

@property

427

def name(self) -> str:

428

"""Get pin name."""

429

430

def net(self) -> Net:

431

"""Get connected net."""

432

```

433

434

## Usage Examples

435

436

### Basic DRC Rule Checking

437

438

```python

439

import klayout.db as db

440

import klayout.rdb as rdb

441

442

# Load layout

443

layout = db.Layout()

444

layout.read("design.gds")

445

446

# Get shapes from specific layers

447

metal1_layer = layout.layer(db.LayerInfo(1, 0))

448

metal1_region = db.Region()

449

450

# Collect all Metal1 shapes

451

top_cell = layout.top_cell()

452

for shape in top_cell.shapes(metal1_layer).each():

453

metal1_region.insert(shape.polygon)

454

455

# Create results database

456

report_db = rdb.ReportDatabase("DRC_Report")

457

458

# Define DRC rules

459

min_width = 120 # 120nm minimum width

460

min_spacing = 140 # 140nm minimum spacing

461

462

# Check width violations

463

width_violations = metal1_region.width_check(min_width)

464

if width_violations.count() > 0:

465

width_category = report_db.create_category("Metal1 Width Violations")

466

width_category.set_description(f"Minimum width {min_width}nm")

467

468

for edge_pair in width_violations.each():

469

item = width_category.create_item()

470

# Convert edge pair to polygon for visualization

471

violation_poly = edge_pair.to_polygon(10) # 10nm marker

472

item.add_value(rdb.Value(violation_poly))

473

474

# Add measurement value

475

distance = edge_pair.distance()

476

item.add_value(rdb.Value(f"Width: {distance}nm"))

477

478

# Check spacing violations

479

space_violations = metal1_region.space_check(min_spacing)

480

if space_violations.count() > 0:

481

space_category = report_db.create_category("Metal1 Spacing Violations")

482

space_category.set_description(f"Minimum spacing {min_spacing}nm")

483

484

for edge_pair in space_violations.each():

485

item = space_category.create_item()

486

violation_poly = edge_pair.to_polygon(10)

487

item.add_value(rdb.Value(violation_poly))

488

489

distance = edge_pair.distance()

490

item.add_value(rdb.Value(f"Spacing: {distance}nm"))

491

492

# Save report

493

report_db.save("metal1_drc_report.lyrdb")

494

print(f"DRC complete: {width_violations.count()} width, {space_violations.count()} spacing violations")

495

```

496

497

### Comprehensive Multi-Layer DRC

498

499

```python

500

import klayout.db as db

501

import klayout.rdb as rdb

502

503

def run_comprehensive_drc(layout_file: str, output_report: str):

504

"""Run comprehensive DRC on a layout file."""

505

506

layout = db.Layout()

507

layout.read(layout_file)

508

509

# Define layers and rules

510

layer_rules = {

511

"NWELL": {"layer": (1, 0), "min_width": 600, "min_spacing": 600},

512

"ACTIVE": {"layer": (2, 0), "min_width": 150, "min_spacing": 150},

513

"POLY": {"layer": (3, 0), "min_width": 100, "min_spacing": 140},

514

"CONTACT": {"layer": (4, 0), "min_width": 120, "min_spacing": 140},

515

"METAL1": {"layer": (5, 0), "min_width": 120, "min_spacing": 140},

516

"VIA1": {"layer": (6, 0), "min_width": 120, "min_spacing": 140},

517

"METAL2": {"layer": (7, 0), "min_width": 140, "min_spacing": 140},

518

}

519

520

# Define enclosure rules

521

enclosure_rules = [

522

{"inner": "CONTACT", "outer": "ACTIVE", "min_enc": 60},

523

{"inner": "CONTACT", "outer": "POLY", "min_enc": 50},

524

{"inner": "VIA1", "outer": "METAL1", "min_enc": 60},

525

{"inner": "VIA1", "outer": "METAL2", "min_enc": 60},

526

]

527

528

report_db = rdb.ReportDatabase("Comprehensive_DRC")

529

530

# Extract regions for each layer

531

regions = {}

532

for layer_name, rules in layer_rules.items():

533

layer_info = db.LayerInfo(rules["layer"][0], rules["layer"][1])

534

layer_idx = layout.layer(layer_info)

535

536

region = db.Region()

537

for cell in layout.each_cell():

538

for shape in cell.shapes(layer_idx).each():

539

region.insert(shape.polygon)

540

541

regions[layer_name] = region.merged() # Merge overlapping shapes

542

543

# Run width and spacing checks

544

for layer_name, rules in layer_rules.items():

545

region = regions[layer_name]

546

547

if region.is_empty():

548

continue

549

550

# Width check

551

width_violations = region.width_check(rules["min_width"])

552

if width_violations.count() > 0:

553

category = report_db.create_category(f"{layer_name} Width Violations")

554

category.set_description(f"Minimum width {rules['min_width']}nm")

555

556

for edge_pair in width_violations.each():

557

item = category.create_item()

558

violation_poly = edge_pair.to_polygon(20)

559

item.add_value(rdb.Value(violation_poly))

560

item.add_value(rdb.Value(f"Measured: {edge_pair.distance()}nm"))

561

562

# Spacing check

563

space_violations = region.space_check(rules["min_spacing"])

564

if space_violations.count() > 0:

565

category = report_db.create_category(f"{layer_name} Spacing Violations")

566

category.set_description(f"Minimum spacing {rules['min_spacing']}nm")

567

568

for edge_pair in space_violations.each():

569

item = category.create_item()

570

violation_poly = edge_pair.to_polygon(20)

571

item.add_value(rdb.Value(violation_poly))

572

item.add_value(rdb.Value(f"Measured: {edge_pair.distance()}nm"))

573

574

# Run enclosure checks

575

for rule in enclosure_rules:

576

inner_region = regions.get(rule["inner"])

577

outer_region = regions.get(rule["outer"])

578

579

if inner_region and outer_region and not inner_region.is_empty() and not outer_region.is_empty():

580

enc_violations = inner_region.enclosing_check(outer_region, rule["min_enc"])

581

582

if enc_violations.count() > 0:

583

category = report_db.create_category(

584

f"{rule['inner']} in {rule['outer']} Enclosure Violations"

585

)

586

category.set_description(f"Minimum enclosure {rule['min_enc']}nm")

587

588

for edge_pair in enc_violations.each():

589

item = category.create_item()

590

violation_poly = edge_pair.to_polygon(20)

591

item.add_value(rdb.Value(violation_poly))

592

item.add_value(rdb.Value(f"Measured: {edge_pair.distance()}nm"))

593

594

# Generate summary

595

total_violations = sum(cat.num_items() for cat in report_db.each_category())

596

print(f"DRC Summary: {total_violations} total violations in {report_db.num_categories()} categories")

597

598

# Save report

599

report_db.save(output_report)

600

return report_db

601

602

# Run comprehensive DRC

603

report = run_comprehensive_drc("complex_design.gds", "comprehensive_drc.lyrdb")

604

```

605

606

### Netlist Extraction and LVS

607

608

```python

609

import klayout.db as db

610

611

def extract_netlist(layout: db.Layout) -> db.Netlist:

612

"""Extract netlist from layout (simplified example)."""

613

614

netlist = db.Netlist()

615

top_circuit = netlist.create_circuit("TOP")

616

617

# Get layer regions

618

active_layer = layout.layer(db.LayerInfo(2, 0))

619

poly_layer = layout.layer(db.LayerInfo(3, 0))

620

contact_layer = layout.layer(db.LayerInfo(4, 0))

621

metal1_layer = layout.layer(db.LayerInfo(5, 0))

622

623

active_region = db.Region()

624

poly_region = db.Region()

625

contact_region = db.Region()

626

metal1_region = db.Region()

627

628

top_cell = layout.top_cell()

629

630

# Collect shapes

631

for shape in top_cell.shapes(active_layer).each():

632

active_region.insert(shape.polygon)

633

for shape in top_cell.shapes(poly_layer).each():

634

poly_region.insert(shape.polygon)

635

for shape in top_cell.shapes(contact_layer).each():

636

contact_region.insert(shape.polygon)

637

for shape in top_cell.shapes(metal1_layer).each():

638

metal1_region.insert(shape.polygon)

639

640

# Find transistors (simplified: active AND poly intersections)

641

transistor_regions = active_region & poly_region

642

643

device_count = 0

644

for transistor_poly in transistor_regions.each():

645

device_count += 1

646

device = top_circuit.create_device(None, f"M{device_count}")

647

648

# Create terminals

649

gate_pin = device.create_terminal("G")

650

source_pin = device.create_terminal("S")

651

drain_pin = device.create_terminal("D")

652

bulk_pin = device.create_terminal("B")

653

654

# This is a simplified example - real extraction would:

655

# 1. Analyze connectivity through contacts and metal

656

# 2. Identify source/drain regions

657

# 3. Trace nets through the layout

658

# 4. Handle hierarchy and instances

659

660

# Extract nets by analyzing metal connectivity

661

# (This would be much more complex in a real implementation)

662

metal_connected = metal1_region.merged()

663

664

net_count = 0

665

for metal_poly in metal_connected.each():

666

net_count += 1

667

net = top_circuit.create_net(f"net{net_count}")

668

669

# Find contacts that connect to this metal

670

metal_contacts = contact_region & db.Region([metal_poly])

671

672

# Connect devices through contacts (simplified)

673

# Real implementation would trace through layout hierarchy

674

675

return netlist

676

677

def compare_netlists(layout_netlist: db.Netlist, schematic_netlist: db.Netlist) -> rdb.ReportDatabase:

678

"""Compare extracted netlist with reference schematic (simplified LVS)."""

679

680

report_db = rdb.ReportDatabase("LVS_Report")

681

682

# Compare circuit counts

683

layout_circuits = list(layout_netlist.each_circuit())

684

schematic_circuits = list(schematic_netlist.each_circuit())

685

686

if len(layout_circuits) != len(schematic_circuits):

687

category = report_db.create_category("Circuit Count Mismatch")

688

item = category.create_item()

689

item.add_value(rdb.Value(f"Layout: {len(layout_circuits)}, Schematic: {len(schematic_circuits)}"))

690

691

# Compare each circuit

692

for layout_circuit in layout_circuits:

693

schematic_circuit = schematic_netlist.circuit_by_name(layout_circuit.name)

694

695

if not schematic_circuit:

696

category = report_db.create_category("Missing Circuits")

697

item = category.create_item()

698

item.add_value(rdb.Value(f"Circuit {layout_circuit.name} not found in schematic"))

699

continue

700

701

# Compare device counts

702

layout_devices = list(layout_circuit.each_device())

703

schematic_devices = list(schematic_circuit.each_device())

704

705

if len(layout_devices) != len(schematic_devices):

706

category = report_db.create_category("Device Count Mismatch")

707

item = category.create_item()

708

item.add_value(rdb.Value(

709

f"Circuit {layout_circuit.name}: Layout {len(layout_devices)}, "

710

f"Schematic {len(schematic_devices)}"

711

))

712

713

# Compare net counts

714

layout_nets = list(layout_circuit.each_net())

715

schematic_nets = list(schematic_circuit.each_net())

716

717

if len(layout_nets) != len(schematic_nets):

718

category = report_db.create_category("Net Count Mismatch")

719

item = category.create_item()

720

item.add_value(rdb.Value(

721

f"Circuit {layout_circuit.name}: Layout {len(layout_nets)}, "

722

f"Schematic {len(schematic_nets)}"

723

))

724

725

return report_db

726

727

# Example usage

728

layout = db.Layout()

729

layout.read("extracted_design.gds")

730

731

# Extract netlist from layout

732

layout_netlist = extract_netlist(layout)

733

734

# Load reference schematic netlist (would typically be SPICE format)

735

schematic_netlist = db.Netlist()

736

# ... load schematic netlist from file ...

737

738

# Run LVS comparison

739

lvs_report = compare_netlists(layout_netlist, schematic_netlist)

740

lvs_report.save("lvs_report.lyrdb")

741

742

print(f"LVS complete: {lvs_report.num_categories()} categories, "

743

f"{sum(cat.num_items() for cat in lvs_report.each_category())} total issues")

744

```

745

746

### Advanced Verification Reporting

747

748

```python

749

import klayout.db as db

750

import klayout.rdb as rdb

751

752

def create_detailed_drc_report(violations: db.EdgePairs, rule_name: str,

753

rule_value: int, category: rdb.Category):

754

"""Create detailed DRC report with comprehensive information."""

755

756

violation_count = violations.count()

757

category.set_description(

758

f"{rule_name}: {rule_value}nm requirement, {violation_count} violations found"

759

)

760

761

# Statistics

762

distances = []

763

areas = []

764

765

for edge_pair in violations.each():

766

item = category.create_item()

767

768

# Add geometric representation

769

violation_poly = edge_pair.to_polygon(25) # 25nm marker

770

item.add_value(rdb.Value(violation_poly))

771

772

# Add measurements

773

distance = edge_pair.distance()

774

distances.append(distance)

775

item.add_value(rdb.Value(f"Measured: {distance}nm"))

776

item.add_value(rdb.Value(f"Required: {rule_value}nm"))

777

item.add_value(rdb.Value(f"Violation: {rule_value - distance}nm"))

778

779

# Add location information

780

bbox = violation_poly.bbox()

781

center_x = (bbox.left + bbox.right) // 2

782

center_y = (bbox.bottom + bbox.top) // 2

783

item.add_value(rdb.Value(f"Location: ({center_x}, {center_y})"))

784

785

# Add severity tag

786

severity = "Critical" if distance < rule_value * 0.8 else "Warning"

787

tag = rdb.Tags(severity)

788

item.add_tag(tag)

789

790

# Calculate affected area (approximate)

791

area = violation_poly.area()

792

areas.append(area)

793

item.add_value(rdb.Value(f"Affected area: {area} sq.nm"))

794

795

# Add summary statistics to first item

796

if violation_count > 0:

797

summary_item = category.create_item()

798

summary_item.add_value(rdb.Value(f"Total violations: {violation_count}"))

799

summary_item.add_value(rdb.Value(f"Min distance: {min(distances)}nm"))

800

summary_item.add_value(rdb.Value(f"Max distance: {max(distances)}nm"))

801

summary_item.add_value(rdb.Value(f"Avg distance: {sum(distances)/len(distances):.1f}nm"))

802

summary_item.add_value(rdb.Value(f"Total affected area: {sum(areas)} sq.nm"))

803

804

summary_tag = rdb.Tags("Summary")

805

summary_item.add_tag(summary_tag)

806

807

def generate_verification_dashboard(report_db: rdb.ReportDatabase):

808

"""Generate verification dashboard with key metrics."""

809

810

print("=== VERIFICATION DASHBOARD ===")

811

print(f"Report: {report_db.name}")

812

print(f"Categories: {report_db.num_categories()}")

813

814

total_items = 0

815

critical_items = 0

816

warning_items = 0

817

818

for category in report_db.each_category():

819

cat_items = category.num_items()

820

total_items += cat_items

821

822

print(f"\n{category.name}: {cat_items} items")

823

print(f" Description: {category.description}")

824

825

# Count by severity

826

cat_critical = 0

827

cat_warning = 0

828

829

for item in category.each_item():

830

for tag in item.each_tag():

831

if tag.tag == "Critical":

832

cat_critical += 1

833

critical_items += 1

834

elif tag.tag == "Warning":

835

cat_warning += 1

836

warning_items += 1

837

838

if cat_critical > 0 or cat_warning > 0:

839

print(f" Critical: {cat_critical}, Warnings: {cat_warning}")

840

841

print(f"\n=== SUMMARY ===")

842

print(f"Total violations: {total_items}")

843

print(f"Critical: {critical_items}")

844

print(f"Warnings: {warning_items}")

845

print(f"Success rate: {max(0, 100 - (critical_items + warning_items)/max(1, total_items)*100):.1f}%")

846

847

# Example: Enhanced DRC with detailed reporting

848

def run_enhanced_drc(layout_file: str):

849

"""Run DRC with enhanced reporting and analysis."""

850

851

layout = db.Layout()

852

layout.read(layout_file)

853

854

report_db = rdb.ReportDatabase("Enhanced_DRC_Report")

855

856

# Extract Metal1 layer

857

metal1_layer = layout.layer(db.LayerInfo(5, 0))

858

metal1_region = db.Region()

859

860

top_cell = layout.top_cell()

861

for shape in top_cell.shapes(metal1_layer).each():

862

metal1_region.insert(shape.polygon)

863

864

metal1_region = metal1_region.merged()

865

866

# Run checks with detailed reporting

867

min_width = 120

868

width_violations = metal1_region.width_check(min_width)

869

870

if width_violations.count() > 0:

871

width_category = report_db.create_category("Metal1 Width Violations")

872

create_detailed_drc_report(width_violations, "Minimum Width",

873

min_width, width_category)

874

875

min_spacing = 140

876

space_violations = metal1_region.space_check(min_spacing)

877

878

if space_violations.count() > 0:

879

space_category = report_db.create_category("Metal1 Spacing Violations")

880

create_detailed_drc_report(space_violations, "Minimum Spacing",

881

min_spacing, space_category)

882

883

# Generate dashboard

884

generate_verification_dashboard(report_db)

885

886

# Save enhanced report

887

report_db.save("enhanced_drc_report.lyrdb")

888

889

return report_db

890

891

# Run enhanced DRC

892

enhanced_report = run_enhanced_drc("test_design.gds")

893

```