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

hierarchical-design.mddocs/

0

# Hierarchical Design and Cell Management

1

2

Cell hierarchy management, instance creation and manipulation, library organization, and parametric cell (PCell) support for reusable design components in IC layout design.

3

4

## Capabilities

5

6

### Cell Instance Management

7

8

```python { .api }

9

class CellInstArray:

10

def __init__(self, cell_index: int, trans: Trans, na: int = 1, nb: int = 1,

11

da: Vector = None, db: Vector = None):

12

"""

13

Create a cell instance or instance array.

14

15

Parameters:

16

- cell_index: Index of the cell to instantiate

17

- trans: Transformation for the instance

18

- na: Number of instances in A direction (default 1)

19

- nb: Number of instances in B direction (default 1)

20

- da: Displacement vector for A direction array

21

- db: Displacement vector for B direction array

22

"""

23

24

@property

25

def cell_index(self) -> int:

26

"""Get the instantiated cell index."""

27

28

@property

29

def trans(self) -> Trans:

30

"""Get the instance transformation."""

31

32

@property

33

def na(self) -> int:

34

"""Get number of instances in A direction."""

35

36

@property

37

def nb(self) -> int:

38

"""Get number of instances in B direction."""

39

40

@property

41

def da(self) -> Vector:

42

"""Get A direction displacement vector."""

43

44

@property

45

def db(self) -> Vector:

46

"""Get B direction displacement vector."""

47

48

def is_regular_array(self) -> bool:

49

"""Check if this is a regular array (na > 1 or nb > 1)."""

50

51

def bbox(self, layout: Layout) -> Box:

52

"""Get bounding box of the instance array."""

53

54

def transform_into(self, trans: Trans) -> CellInstArray:

55

"""Apply additional transformation to instance."""

56

57

class DCellInstArray:

58

def __init__(self, cell_index: int, trans: DCplxTrans):

59

"""Create a double precision cell instance."""

60

61

@property

62

def cell_index(self) -> int:

63

"""Get the instantiated cell index."""

64

65

@property

66

def trans(self) -> DCplxTrans:

67

"""Get the instance transformation."""

68

```

69

70

### Cell Hierarchy Navigation

71

72

```python { .api }

73

class Cell:

74

def each_inst(self):

75

"""Iterate over all instances in this cell."""

76

77

def each_parent_inst(self):

78

"""Iterate over all instances of this cell (parent instances)."""

79

80

def each_child_cell(self):

81

"""Iterate over all child cells (cells instantiated by this cell)."""

82

83

def each_parent_cell(self):

84

"""Iterate over all parent cells (cells that instantiate this cell)."""

85

86

def child_cells(self) -> int:

87

"""Get number of child cells."""

88

89

def parent_cells(self) -> int:

90

"""Get number of parent cells."""

91

92

def hierarchy_levels(self) -> int:

93

"""Get maximum hierarchy depth below this cell."""

94

95

def is_top(self) -> bool:

96

"""Check if this is a top-level cell (no parents)."""

97

98

def is_leaf(self) -> bool:

99

"""Check if this is a leaf cell (no children)."""

100

101

def is_proxy(self) -> bool:

102

"""Check if this is a proxy cell (library reference)."""

103

104

class Layout:

105

def top_cells(self):

106

"""Get all top-level cells in the layout."""

107

108

def top_cell(self) -> Cell:

109

"""Get the single top cell (if there is exactly one)."""

110

111

def each_cell(self):

112

"""Iterate over all cells in the layout."""

113

114

def cells(self) -> int:

115

"""Get total number of cells."""

116

```

117

118

### Parametric Cells (PCells)

119

120

```python { .api }

121

class PCellDeclaration:

122

def __init__(self):

123

"""Base class for parametric cell declarations."""

124

125

def display_name(self, parameters) -> str:

126

"""

127

Get display name for the PCell with given parameters.

128

129

Parameters:

130

- parameters: Dictionary of parameter values

131

132

Returns:

133

str: Display name for this parameter set

134

"""

135

136

def produce(self, layout: Layout, layers, parameters, cell: Cell) -> None:

137

"""

138

Produce the PCell geometry.

139

140

Parameters:

141

- layout: Target layout

142

- layers: Layer mapping

143

- parameters: Parameter values

144

- cell: Target cell to populate

145

"""

146

147

def get_parameters(self) -> list:

148

"""Get list of parameter declarations."""

149

150

def get_layers(self) -> list:

151

"""Get list of layer declarations."""

152

153

class PCellDeclarationHelper:

154

def __init__(self, name: str):

155

"""

156

Helper class for creating parametric cells.

157

158

Parameters:

159

- name: Name of the PCell

160

"""

161

162

def param(self, name: str, param_type: type, description: str, default=None) -> None:

163

"""

164

Declare a parameter.

165

166

Parameters:

167

- name: Parameter name

168

- param_type: Parameter type (int, float, str, bool)

169

- description: Parameter description

170

- default: Default value

171

"""

172

173

def layer(self, name: str, description: str, default: LayerInfo = None) -> None:

174

"""

175

Declare a layer parameter.

176

177

Parameters:

178

- name: Layer parameter name

179

- description: Layer description

180

- default: Default layer info

181

"""

182

183

def produce_impl(self) -> None:

184

"""

185

Implementation method to be overridden.

186

This method should create the actual geometry.

187

"""

188

189

class PCellParameterDeclaration:

190

def __init__(self, name: str, param_type: type, description: str = "",

191

default=None, choices=None):

192

"""

193

Parameter declaration for PCells.

194

195

Parameters:

196

- name: Parameter name

197

- param_type: Parameter type

198

- description: Parameter description

199

- default: Default value

200

- choices: List of valid choices (for enum parameters)

201

"""

202

203

@property

204

def name(self) -> str:

205

"""Get parameter name."""

206

207

@property

208

def type(self) -> type:

209

"""Get parameter type."""

210

211

@property

212

def description(self) -> str:

213

"""Get parameter description."""

214

215

# Parameter types

216

class PCellParameterType:

217

TypeInt = int

218

TypeDouble = float

219

TypeString = str

220

TypeBoolean = bool

221

TypeLayer = LayerInfo

222

TypeShape = object

223

```

224

225

### Library Management

226

227

```python { .api }

228

class Library:

229

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

230

"""

231

Create a library.

232

233

Parameters:

234

- name: Library name

235

"""

236

237

@property

238

def name(self) -> str:

239

"""Get library name."""

240

241

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

242

"""Set library name."""

243

244

def register_pcell(self, pcell_class, name: str) -> int:

245

"""

246

Register a PCell class in the library.

247

248

Parameters:

249

- pcell_class: PCell declaration class

250

- name: PCell name in library

251

252

Returns:

253

int: PCell ID

254

"""

255

256

def layout(self) -> Layout:

257

"""Get the library layout."""

258

259

def delete(self) -> None:

260

"""Delete the library."""

261

262

class Technology:

263

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

264

"""

265

Create a technology definition.

266

267

Parameters:

268

- name: Technology name

269

"""

270

271

@property

272

def name(self) -> str:

273

"""Get technology name."""

274

275

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

276

"""Load technology from file."""

277

278

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

279

"""Save technology to file."""

280

```

281

282

## Usage Examples

283

284

### Creating Cell Hierarchies

285

286

```python

287

import klayout.db as db

288

289

# Create layout with hierarchy

290

layout = db.Layout()

291

292

# Create leaf cell (basic building block)

293

nmos_cell = layout.create_cell("NMOS_TRANSISTOR")

294

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

295

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

296

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

297

298

# Add transistor geometry

299

nmos_cell.shapes(layer_active).insert(db.Box(0, 0, 200, 100))

300

nmos_cell.shapes(layer_poly).insert(db.Box(50, -20, 150, 120))

301

nmos_cell.shapes(layer_contact).insert(db.Box(25, 25, 75, 75))

302

nmos_cell.shapes(layer_contact).insert(db.Box(125, 25, 175, 75))

303

304

# Create intermediate cell (logic gate)

305

inverter_cell = layout.create_cell("INVERTER")

306

307

# Instantiate NMOS in inverter

308

nmos_instance = db.CellInstArray(nmos_cell.cell_index, db.Trans(db.Point(0, 0)))

309

inverter_cell.insert(nmos_instance)

310

311

# Add PMOS (simplified - just another NMOS for this example)

312

pmos_instance = db.CellInstArray(nmos_cell.cell_index,

313

db.Trans(0, True, db.Point(0, 200))) # Mirrored

314

inverter_cell.insert(pmos_instance)

315

316

# Create top-level cell

317

top_cell = layout.create_cell("LOGIC_BLOCK")

318

319

# Create array of inverters

320

for x in range(0, 1000, 250):

321

for y in range(0, 500, 300):

322

inv_instance = db.CellInstArray(inverter_cell.cell_index,

323

db.Trans(db.Point(x, y)))

324

top_cell.insert(inv_instance)

325

326

layout.write("hierarchy_example.gds")

327

```

328

329

### Instance Arrays

330

331

```python

332

import klayout.db as db

333

334

layout = db.Layout()

335

unit_cell = layout.create_cell("UNIT")

336

top_cell = layout.create_cell("TOP")

337

338

# Add content to unit cell

339

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

340

unit_cell.shapes(layer).insert(db.Box(0, 0, 10, 10))

341

342

# Create 1D array

343

array_1d = db.CellInstArray(

344

unit_cell.cell_index,

345

db.Trans(db.Point(0, 0)), # Base transformation

346

na=10, # 10 instances in A direction

347

nb=1, # 1 instance in B direction

348

da=db.Vector(15, 0), # 15 unit spacing in X

349

db=db.Vector(0, 0) # No B direction spacing

350

)

351

top_cell.insert(array_1d)

352

353

# Create 2D array

354

array_2d = db.CellInstArray(

355

unit_cell.cell_index,

356

db.Trans(db.Point(0, 50)), # Offset from 1D array

357

na=8, # 8 instances in A direction

358

nb=6, # 6 instances in B direction

359

da=db.Vector(15, 0), # 15 unit spacing in X

360

db=db.Vector(0, 20) # 20 unit spacing in Y

361

)

362

top_cell.insert(array_2d)

363

364

print(f"1D Array bbox: {array_1d.bbox(layout)}")

365

print(f"2D Array bbox: {array_2d.bbox(layout)}")

366

367

layout.write("array_example.gds")

368

```

369

370

### Hierarchy Navigation

371

372

```python

373

import klayout.db as db

374

375

layout = db.Layout()

376

layout.read("complex_design.gds")

377

378

# Find all top cells

379

top_cells = list(layout.top_cells())

380

print(f"Found {len(top_cells)} top-level cells")

381

382

if top_cells:

383

top_cell = top_cells[0]

384

print(f"Analyzing cell: {top_cell.name}")

385

386

# Analyze hierarchy

387

print(f"Child cells: {top_cell.child_cells()}")

388

print(f"Parent cells: {top_cell.parent_cells()}")

389

print(f"Hierarchy levels: {top_cell.hierarchy_levels()}")

390

391

# Walk through hierarchy

392

def analyze_cell(cell, level=0):

393

indent = " " * level

394

print(f"{indent}Cell: {cell.name}")

395

print(f"{indent} Instances: {sum(1 for _ in cell.each_inst())}")

396

print(f"{indent} Is leaf: {cell.is_leaf()}")

397

398

# Analyze instances

399

for inst in cell.each_inst():

400

child_cell = layout.cell(inst.cell_index)

401

print(f"{indent} -> {child_cell.name} at {inst.trans.disp}")

402

403

# Recurse for first few levels

404

if level < 3:

405

analyze_cell(child_cell, level + 1)

406

407

analyze_cell(top_cell)

408

```

409

410

### Simple Parametric Cell Example

411

412

```python

413

import klayout.db as db

414

415

class ResistorPCell(db.PCellDeclarationHelper):

416

def __init__(self):

417

super().__init__("Resistor")

418

419

# Declare parameters

420

self.param("width", db.PCellParameterType.TypeDouble, "Width", 1.0)

421

self.param("length", db.PCellParameterType.TypeDouble, "Length", 10.0)

422

self.param("num_contacts", db.PCellParameterType.TypeInt, "Number of contacts", 2)

423

424

# Declare layers

425

self.layer("poly", "Poly layer", db.LayerInfo(1, 0))

426

self.layer("contact", "Contact layer", db.LayerInfo(2, 0))

427

428

def produce_impl(self):

429

# Get parameter values

430

width = self.width

431

length = self.length

432

num_contacts = self.num_contacts

433

434

# Get layer indices

435

poly_layer = self.layout.layer(self.poly)

436

contact_layer = self.layout.layer(self.contact)

437

438

# Create resistor body

439

resistor_body = db.Box(0, 0, int(length * 1000), int(width * 1000))

440

self.cell.shapes(poly_layer).insert(resistor_body)

441

442

# Add contacts

443

contact_size = min(int(width * 200), int(length * 200 / num_contacts))

444

for i in range(num_contacts):

445

if num_contacts == 1:

446

x = int(length * 500) # Center

447

else:

448

x = int(length * 1000 * i / (num_contacts - 1))

449

450

y = int(width * 500 - contact_size / 2)

451

contact = db.Box(x - contact_size//2, y,

452

x + contact_size//2, y + contact_size)

453

self.cell.shapes(contact_layer).insert(contact)

454

455

# Register and use the PCell

456

library = db.Library("MyLibrary")

457

resistor_id = library.register_pcell(ResistorPCell(), "Resistor")

458

459

# Create layout using the PCell

460

layout = db.Layout()

461

top_cell = layout.create_cell("TOP")

462

463

# Instantiate PCell with different parameters

464

params1 = {"width": 2.0, "length": 20.0, "num_contacts": 3}

465

params2 = {"width": 1.5, "length": 15.0, "num_contacts": 2}

466

467

# Note: Actual PCell instantiation requires library integration

468

# This is a simplified example

469

```

470

471

### Cell Manipulation and Analysis

472

473

```python

474

import klayout.db as db

475

476

layout = db.Layout()

477

layout.read("design.gds")

478

479

def analyze_hierarchy(layout):

480

"""Analyze layout hierarchy and provide statistics."""

481

482

stats = {

483

"total_cells": layout.cells(),

484

"top_cells": len(list(layout.top_cells())),

485

"leaf_cells": 0,

486

"max_depth": 0,

487

"total_instances": 0

488

}

489

490

# Analyze each cell

491

for cell in layout.each_cell():

492

if cell.is_leaf():

493

stats["leaf_cells"] += 1

494

495

# Count instances

496

instance_count = sum(1 for _ in cell.each_inst())

497

stats["total_instances"] += instance_count

498

499

# Track maximum depth

500

depth = cell.hierarchy_levels()

501

if depth > stats["max_depth"]:

502

stats["max_depth"] = depth

503

504

return stats

505

506

def find_unused_cells(layout):

507

"""Find cells that are never instantiated."""

508

509

used_cells = set()

510

511

# Mark all instantiated cells as used

512

for cell in layout.each_cell():

513

for inst in cell.each_inst():

514

used_cells.add(inst.cell_index)

515

516

# Find unused cells

517

unused_cells = []

518

for cell in layout.each_cell():

519

if cell.cell_index not in used_cells and not cell.is_top():

520

unused_cells.append(cell)

521

522

return unused_cells

523

524

def flatten_hierarchy(cell, target_cell, level=1):

525

"""Flatten cell hierarchy to specified level."""

526

527

if level <= 0:

528

return

529

530

instances_to_remove = []

531

532

for inst in cell.each_inst():

533

child_cell = cell.layout().cell(inst.cell_index)

534

535

# Copy child cell content to target cell with transformation

536

for layer in range(cell.layout().layers()):

537

for shape in child_cell.shapes(layer).each():

538

transformed_shape = shape.transformed(inst.trans)

539

target_cell.shapes(layer).insert(transformed_shape)

540

541

# Recursively flatten child cells

542

flatten_hierarchy(child_cell, target_cell, level - 1)

543

544

instances_to_remove.append(inst)

545

546

# Remove flattened instances

547

for inst in instances_to_remove:

548

cell.erase(inst)

549

550

# Use the analysis functions

551

stats = analyze_hierarchy(layout)

552

print(f"Hierarchy Statistics: {stats}")

553

554

unused = find_unused_cells(layout)

555

print(f"Unused cells: {[cell.name for cell in unused]}")

556

557

# Flatten top cell by 2 levels

558

if layout.top_cell():

559

flattened_cell = layout.create_cell("FLATTENED")

560

flatten_hierarchy(layout.top_cell(), flattened_cell, 2)

561

```

562

563

### Advanced Instance Transformations

564

565

```python

566

import klayout.db as db

567

568

layout = db.Layout()

569

base_cell = layout.create_cell("BASE")

570

pattern_cell = layout.create_cell("PATTERN")

571

572

# Add content to base cell

573

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

574

base_cell.shapes(layer).insert(db.Box(0, 0, 100, 50))

575

576

# Create various transformed instances

577

transformations = [

578

db.Trans(0, False, db.Point(0, 0)), # Original

579

db.Trans(1, False, db.Point(200, 0)), # 90° rotation

580

db.Trans(2, False, db.Point(200, 200)), # 180° rotation

581

db.Trans(3, False, db.Point(0, 200)), # 270° rotation

582

db.Trans(0, True, db.Point(400, 0)), # X mirror

583

db.Trans(1, True, db.Point(600, 0)), # X mirror + 90° rotation

584

]

585

586

for i, trans in enumerate(transformations):

587

instance = db.CellInstArray(base_cell.cell_index, trans)

588

589

# Apply additional transformation

590

if i > 2: # Scale some instances

591

scaled_trans = db.Trans(db.Vector(50, 25)) # Additional offset

592

modified_instance = instance.transform_into(scaled_trans)

593

pattern_cell.insert(modified_instance)

594

else:

595

pattern_cell.insert(instance)

596

597

# Create complex patterns with arrays and transformations

598

spiral_cell = layout.create_cell("SPIRAL")

599

radius = 50

600

angle_step = 30

601

602

for i in range(12): # 12 positions around circle

603

angle_rad = i * angle_step * 3.14159 / 180

604

x = int(radius * cos(angle_rad))

605

y = int(radius * sin(angle_rad))

606

607

# Rotation to face outward

608

rotation = i * angle_step / 90 # Convert to 90-degree increments

609

610

trans = db.Trans(int(rotation) % 4, False, db.Point(x, y))

611

instance = db.CellInstArray(base_cell.cell_index, trans)

612

spiral_cell.insert(instance)

613

614

layout.write("advanced_instances.gds")

615

```