Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ repos:
entry: uv run --no-sync pyright
language: system
files: \.(py)$
exclude: (src/gsim/vlsir/|docs/)

- repo: local
hooks:
Expand All @@ -66,6 +67,7 @@ repos:
entry: uv run --no-sync mypy
language: system
files: \.(py)$
exclude: (src/gsim/vlsir/|docs/)

- repo: local
hooks:
Expand Down
21 changes: 19 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,31 @@ Gsim bridges the gap between circuit layout design (using [GDSFactory](https://g
pip install gsim
```

For development:
For development (using [just](https://github.com/casey/just) and [uv](https://github.com/astral-sh/uv)):

```bash
git clone https://github.com/doplaydo/gsim
cd gsim
pip install -e .[dev]

# Install uv (if not already installed)
just uv

# Install dependencies and set up dev environment
just dev
```

### Available Commands

| Command | Description |
| ---------------- | ------------------------------------------------------ |
| `just dev` | Install all dependencies, extras, and pre-commit hooks |
| `just test` | Run the test suite with pytest |
| `just docs` | Build documentation with mkdocs |
| `just serve` | Serve documentation locally at localhost:8080 |
| `just dist` | Build wheel distribution |
| `just ipykernel` | Install Jupyter kernel for notebooks |
| `just clean` | Clean all build artifacts and caches |

## Quick Start

```python
Expand Down
2 changes: 1 addition & 1 deletion mkdocs.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
site_name: gsim
site_url: https://gdsfactory.com/gsim
site_description: Palace EM Simulation API for GDSFactory
site_description: Simulation API for GDSFactory
site_author: GDSFactory
copyright: Copyright © 2026, GDSFactory

Expand Down
33 changes: 30 additions & 3 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,14 @@ dependencies = [
"meshio>=5.0.0",
"plotly",
"pydantic>=2.10.6",
"pyvista>=0.43.0"
"pyvista>=0.43.0",
"vlsir>=7.0.0",
"vlsirtools>=7.0.0"
]
description = ""
name = "gsim"
readme = "README.md"
requires-python = ">=3.11"
requires-python = ">=3.12"
version = "0.0.0"

[project.optional-dependencies]
Expand Down Expand Up @@ -56,6 +58,10 @@ dev = [
"nbstripout>=0.8.1"
]

[tool.codespell]
ignore-words-list = "inout"
skip = "*.ipynb,.venv,*.lock"

[tool.mypy]
mypy_path = ["src"]
python_version = "3.12"
Expand Down Expand Up @@ -96,13 +102,30 @@ module = "plotly"
ignore_missing_imports = true
module = "plotly.*"

[[tool.mypy.overrides]]
ignore_missing_imports = true
module = "vlsir"

[[tool.mypy.overrides]]
ignore_missing_imports = true
module = "vlsir.*"

[[tool.mypy.overrides]]
# vlsir lacks type stubs, relax checking for this subpackage
check_untyped_defs = false
disable_error_code = ["no-untyped-def", "no-untyped-call", "var-annotated", "no-any-return", "type-arg"]
disallow_any_generics = false
disallow_untyped_defs = false
module = "gsim.vlsir.*"
warn_return_any = false

[tool.pylsp-mypy]
enabled = true
live_mode = true
strict = true

[tool.pyright]
exclude = ["tests", "**/__pycache__", "**/.venv"]
exclude = ["tests", "**/__pycache__", "**/.venv", "src/gsim/vlsir"]
include = ["src"]
pythonVersion = "3.12"
reportMissingImports = "none"
Expand Down Expand Up @@ -191,6 +214,10 @@ select = ["ALL"]
"SLF001", # private-member-access
"T201" # print
]
"src/gsim/vlsir/*.py" = [
"D100", # missing-module-docstring
"D104" # missing-package-docstring
]
"tests/**/*.py" = [
"ANN", # flake8-annotations
"D", # pydocstyle
Expand Down
1 change: 1 addition & 0 deletions src/gsim/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

Currently includes:
- palace: Palace EM simulation API
- vlsir: GDSF -> VLSIR Netlisting API
"""

from __future__ import annotations
Expand Down
95 changes: 95 additions & 0 deletions src/gsim/vlsir/CONNECTIONs.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
# VLSIR-GDSFactory Connection Logic

---

**Status** : Implemented in `netlist.py`

## Overview

GDSFactory connects components in one of three ways:

1. **`.connect()` method** - Physically arranges components side-by-side by aligning ports
2. **`gdsfactory.routing` utilities** - Draws routing between components using PDK rules
3. **Implicit logical links** - Inform routing but are not persistent state

## Implementation

The `to_vlsir_circuit()` function in `netlist.py` extracts connectivity from GDSFactory's recursive netlist using the following rules:

### Instance Classification

1. If an instance has [VLSIR Metadata](./METADATA_SPEC.md) → **device instance** (leaf SPICE element)
2. If an instance references another component in the netlist → **subcircuit instance** (SUBCKT)
3. Otherwise → **routing instance** (used for connectivity)

### Electrical Node Discovery

The algorithm uses BFS (breadth-first search) to discover electrical nodes:

1. Build a graph of routing-to-routing connections from the `nets` array
2. Find connected components in this graph via BFS traversal
3. Each connected component of routing instances becomes a single electrical node (e.g., `net_0`, `net_1`, ...)
4. Device ports are mapped to nodes based on their connections to routing instances

### Connection Flow

```
GDSFactory Component
get_netlist(recursive=True)
Parse instances → devices (vlsir) | routing | subckts
Build routing connectivity graph from nets
BFS to find connected routing components → electrical nodes
Process direct device-to-device connections → new nodes
Recursively process sub-components → nested Modules
Generate VLSIR Package with ExternalModules + Modules
```

## Usage Example

```python
import gdsfactory as gf
from gsim.vlsir import to_vlsir_circuit

@gf.cell
def my_circuit():
c = gf.Component()

# Add device with vlsir metadata
r1 = c << resistor(resistance=1000.0)
r2 = c << resistor(resistance=2000.0)

# Add routing (no vlsir metadata)
w = c << wire(length=10)

# Connect via ports
w.connect("o1", r1.ports["n"])
r2.connect("p", w.ports["o2"])

return c

top = my_circuit()
package, libs = to_vlsir_circuit(top)
```

## Key Points

- Routing instances form the "glue" that defines electrical connectivity
- **Direct device-to-device connections** are now supported - when two devices connect directly without routing, a shared electrical node is automatically created
- The `port_map` in VLSIR metadata translates GDSFactory port names to SPICE port names
- **Recursive SUBCKTs** are supported - sub-components containing devices are processed recursively and represented as local Module references in VLSIR

## Supported Connection Types

| Connection Type | Support | Description |
| ----------------------------------- | ------- | ---------------------------------- |
| Device → Routing → Device | ✅ | Standard routed connection |
| Device → Device (direct) | ✅ | Direct port-to-port connection |
| Device → Routing → Routing → Device | ✅ | Chained routing (merged nodes) |
| Nested SUBCKTs | ✅ | Recursive sub-component processing |
43 changes: 43 additions & 0 deletions src/gsim/vlsir/METADATA_SPEC.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# VLSIR-GDSFactory Metadata Specification

---

### Implementation Status

- [x] Skywater 130nm CMOS
- [x] Global Foundries 180nm MCU CMOS
- [x] IHP SG13G2 130nm BiCMOS

### Motivation

Electrical PDKs in GDSFactory describe the layout of devices with SPICE models using parameterized cell and foundry templates wrapped in GDSFactory `Component` objects with attributed `Port` objects to allow for routing between devices. In order for SPICE simulators to correctly represent the intended circuit submitted by the engineer, it is essential that each device comes equipped with metadata which `gsim` `vlsir` utilities can render into `vlsir` protobuf and can then be converted by `vlsirtools` into ngspice, Xyce or Spectre netlists ready for simulation.

To do this, metadata is standardized according to the following format:

## Specification

```python
@gdsfactory.cell
def MyPDKDevice(...):

c = gdsfactory.Component()

... # Layout Programming

# Specify Electrical Ports!

c.info['vlsir'] = {
"model" : [DEVICE MODEL NAME HERE] (str),
"spice_type" : [SEE IMPLEMENTED SPICE TYPES] (str),
"spice_lib" : [ASSUMED ROOT, PDK/MODELS] (List[str]),
"port_order" : [SPICE PORTS OF DEVICE] (List[str]),
"port_map" : {GDSFACTORY PORT : SPICE PORT} (dict[str,str]),
"params" : {
"param1" : PARAM1 (str/int/float),
"param2" : PARAM2 (str/int/float),
"param3" : PARAM3 (str/int/float)
}
}

return c
```
13 changes: 13 additions & 0 deletions src/gsim/vlsir/SIMULATION.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# VLSIR-GDSFactory Connection Logic

---

### Implementation Status

- [ ] Skywater 130nm CMOS
- [ ] Global Foundries 180nm MCU CMOS
- [ ] IHP SG13G2 130nm BiCMOS

### Proposed Solution

After the [VLSIR Circuit](./CONNECTIONs.md) has been determined, we can now begin the final step of preparing the netlist for a simulator - we note that this often-times can be PDK specific as users may wish to specify simulation corners, use special modelling utilities unique to each PDK and each PDK often contains quirks which don't neatly fit into the [VLSIR Metadata Specification](./METADATA_SPEC.md).
1 change: 1 addition & 0 deletions src/gsim/vlsir/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from .netlist import to_vlsir_circuit
Loading