Skip to content
Open
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
145 changes: 34 additions & 111 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,114 +1,37 @@
# Copyright 2025 ETH Zurich and University of Bologna.
# Copyright 2026 ETH Zurich and University of Bologna.
# Licensed under the Apache License, Version 2.0, see LICENSE for details.
# SPDX-License-Identifier: Apache-2.0
#
# Thomas Benz <tbenz@iis.ee.ethz.ch>
# Paul Scheffler <paulsc@iis.ee.ethz.ch>
# Nils Wistoff <nwistoff@iis.ee.ethz.ch>
# Philippe Sauter <phsauter@iis.ee.ethz.ch>

PYTHON ?= python3
SCRIPTS ?= scripts
KLAYOUT ?= klayout
CFG_FILE ?= /dev/null


CHIPNAME := $(shell $(PYTHON) $(SCRIPTS)/fetch_key.py $(CFG_FILE) general chip)
WORKDIR := $(shell $(PYTHON) $(SCRIPTS)/fetch_key.py $(CFG_FILE) work dir)
SCALE_FAC := $(shell $(PYTHON) $(SCRIPTS)/list_files.py $(CFG_FILE) SCALE "")
ROOT_DIR := $(shell pwd)


.PHONY: analyze
analyze:
mkdir -p $(WORKDIR)
$(PYTHON) $(SCRIPTS)/analyze.py $(CFG_FILE)

.SECONDEXPANSION:
.SECONDARY:
.DELETE_ON_ERROR:
.PRECIOUS:

# Phony targets
.PHONY: all
all : gen_raw gen_pdfs

# color rule
$(WORKDIR)/COL__%.png: $(WORKDIR)/RAW__%.png $(CFG_FILE)
convert \
$< \
-limit thread 1 \
-negate \
-background $(shell $(PYTHON) $(SCRIPTS)/fetch_color.py $(CFG_FILE) $< color) \
-alpha shape \
-alpha set \
-background none \
-channel A \
-evaluate multiply $(shell $(PYTHON) $(SCRIPTS)/fetch_color.py $(CFG_FILE) $< alpha) \
+channel \
$@

# merge tiles
$(WORKDIR)/MRG__%.png: $$(shell $(PYTHON) $(SCRIPTS)/list_files.py $(CFG_FILE) COL $$@)
convert $(shell $(PYTHON) $(SCRIPTS)/list_files.py $(CFG_FILE) CMP $<) \
-limit thread 1 \
-background black \
-alpha remove \
-alpha off \
$@

# resize tiles
$(WORKDIR)/RSZ__%.png: $(WORKDIR)/MRG__%.png $(CFG_FILE)
convert \
$< \
-scale $(SCALE_FAC)% \
$@

# merge tiles
$(WORKDIR)/SEG__%.png: $$(shell $(PYTHON) $(SCRIPTS)/list_files.py $(CFG_FILE) SEGSRC $$@)
$(shell $(PYTHON) $(SCRIPTS)/list_files.py $(CFG_FILE) SEGGEN $@)

# change dpi
$(WORKDIR)/DPI__%.png: $(WORKDIR)/SEG__%.png $(CFG_FILE)
convert \
$< \
-units PixelsPerInch \
-density $(shell $(PYTHON) $(SCRIPTS)/list_files.py $(CFG_FILE) DPI_SCALE $@) \
-page $(shell $(PYTHON) $(SCRIPTS)/list_files.py $(CFG_FILE) PAGE_PX $@) \
-gravity center \
-interlace none \
-background white \
-alpha remove \
-alpha off \
-flatten \
-format png \
$@

# generate PDF
$(WORKDIR)/PDF__%.pdf: $(WORKDIR)/DPI__%.png $(CFG_FILE)
img2pdf \
--verbose \
--pillow-limit-break \
$< \
-o \
$@

# generate raw layer files from KLayout
.PHONY: gen_raw
gen_raw: $(CFG_FILE) $(SCRIPTS)/gen_layer_props.py $(SCRIPTS)/png_export.lym
mkdir -p $(WORKDIR)
cp $(CFG_FILE) $(WORKDIR)/chip.json
$(PYTHON) $(SCRIPTS)/gen_layer_props.py $(CFG_FILE) > $(WORKDIR)/$(CHIPNAME).lyp
cd $(WORKDIR); $(KLAYOUT) -zz -rm $(ROOT_DIR)/$(SCRIPTS)/png_export.lym

.PHONY: gen_tiles
gen_tiles: $$(shell $(PYTHON) $(SCRIPTS)/list_files.py $(CFG_FILE) MRG "")

.PHONY: gen_resized_tiles
gen_resized_tiles: $$(shell $(PYTHON) $(SCRIPTS)/list_files.py $(CFG_FILE) RSZ "")

.PHONY: gen_segs
gen_segs: $$(shell $(PYTHON) $(SCRIPTS)/list_files.py $(CFG_FILE) SEG "")

.PHONY: gen_pdfs
gen_pdfs: $$(shell $(PYTHON) $(SCRIPTS)/list_files.py $(CFG_FILE) PDF "")
PROJECT ?= examples/mlem/project.toml
ARTISTIC ?= ./bin/artistic

.PHONY: all inspect logo-prepare logo-merge logo render-generate render-compose render \
map-generate map-build map

all:
$(MAKE) logo
$(MAKE) render
$(MAKE) map
inspect:
$(ARTISTIC) inspect $(PROJECT)
logo-prepare:
$(ARTISTIC) logo prepare $(PROJECT)
logo-merge:
$(ARTISTIC) logo merge $(PROJECT)
logo:
$(MAKE) logo-prepare
$(MAKE) logo-merge
render-generate:
$(ARTISTIC) render generate $(PROJECT)
render-compose:
$(ARTISTIC) render compose $(PROJECT)
render:
$(MAKE) render-generate
$(MAKE) render-compose
map-generate:
$(ARTISTIC) map generate $(PROJECT)
map-build:
$(ARTISTIC) map build $(PROJECT)
map:
$(MAKE) map-generate
$(MAKE) map-build
214 changes: 71 additions & 143 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,170 +1,98 @@
# ArtistIC: An Open-Source Toolchain for Top-Metal IC Art and Ultra-High-Fidelity GDSII Renders
# ArtistIC

ArtistIC is a framework can be used to
ArtistIC turns a chip GDS into artwork, layer images, and a zoomable map. A
project is a TOML file and the Python `Project` class is the implementation of
the flow. The `bin/artistic` command and the Makefile only select a project and
call that interface.

* Translate and insert ASIC art on top-metal layers.
* Render GDSII files at ultra-high fidelity.
Each product has explicit stages. KLayout stages generate physical data;
host stages apply colors or assemble image files.

ArtistIC is part of the [PULP (Parallel Ultra-Low-Power) platform](https://pulp-platform.org/),
where it is used render high-definition posters of our [chips](http://asic.ethz.ch/).

ArtistIC is in a ***experimental*** stage and might produce bad results. We are happy to
receive your contributions through issues and PRs improving this framework. In a first step, the
entire process has to be streamlined.


## Top-Metal ASIC Artwork Generation (Meerkat)

***Logo Generation Only Tested for the [IHP 130nm Open PDK](https://github.com/IHP-GmbH/IHP-Open-PDK)***

Prepare a temporary work directory:

```
mkdir -p meerkat_work
```


Export the top-metal layer:

```
python3 scripts/meerkat_interface.py \
-i ../examples/mlem/mlem_vanilla.gds.gz \
-m mlem_tm.gds.gz \
-g mlem_logo.gds \
-o mlem_chip.gds.gz \
-w meerkat_work \
-l 134
cd meerkat_work; klayout -zz -rm ../scripts/export_top_metal.py; cd ..
cd meerkat_work; gzip -d mlem_tm.gds.gz; cd ..
```


Transform the logo to a 1-bit b/w image:

```
convert examples/mlem/mlem_logo.png -remap pattern:gray50 meerkat_work/mlem_logo_mono.png
```


Transform the logo to GDS:

```
python3 scripts/meerkat.py \
-m 210,210 \
-i meerkat_work/mlem_logo_mono.png \
-g meerkat_work/mlem_tm.gds \
-l 134 \
-n mlem \
-s meerkat_work/mlem_logo.svg \
-o meerkat_work/mlem_logo.gds
```


Merge the logo into the chip:

```
cd meerkat_work; klayout -zz -rm ../scripts/merge_logo.py; cd ..
```


This generates the file `meerkat_work/mlem_chip.gds.gz` containing the generated top-metal logo.



## Ultra-High-Fidelity Rendering (RenderICs, formally Tapete)

For this example to work, ensure the previously generated GDSII is present in the work directory:

```
mkdir -p /dev/shm/renderics
cp meerkat_work/mlem_chip.gds.gz /dev/shm/renderics
```


Configuration is given through a `json` file. An example is provided in `examples/mlem/mlem.json`

The configuration can be checked using the Makefile.
Make sure to point this to a large enough temporary work directory (*abs path expected*)!

```
make CFG_FILE=examples/mlem/mlem.json analyze
```text
logo prepare -> logo merge -> render generate -> render compose
\-> map generate -> map build
```

## Quick start

The black/white database can be rendered using:
Use the example project from the ArtistIC directory:

```
make CFG_FILE=examples/mlem/mlem.json gen_raw
```sh
bin/artistic inspect examples/mlem/project.toml
make PROJECT=examples/mlem/project.toml logo-prepare
# In the environment that provides KLayout:
make PROJECT=examples/mlem/project.toml logo-merge render-generate map-generate
make PROJECT=examples/mlem/project.toml render-compose map-build
```

`make all` runs the same stages in order when one environment provides both
KLayout and the host image tools.

The resulting PNGs and PDFs can be created using:
The same commands work from another working directory. Paths in the TOML file
are resolved relative to that file, not relative to the shell's current
directory.

```
make CFG_FILE=examples/mlem/mlem.json gen_pdfs
```
The stages are also available as Make targets:

In this example, the generated PDF is called `/dev/shm/renderics/PDF__mlem_0-0.pdf`
The last step can be parallelized using the '-j' option.
| Target | Result |
| --- | --- |
| `inspect` | Detect the layout bounding box and routing stack |
| `logo-prepare` | Convert artwork to a feature-grid mask |
| `logo-merge` | Place complete mask features on the selected metal layer |
| `render-generate` | Generate one raw mask per selected layer and segment |
| `render-compose` | Apply colors and write PNG, JPEG, or PDF images |
| `map-generate` | Generate raw masks for map tiles |
| `map-build` | Assemble memory-bounded tile pyramids and an HTML viewer |
| `all` | Run logo, render, and map stages in dependency order |

Profit!
Run `bin/artistic --help` or `make -f Makefile -n all` to inspect the thin
adapters without executing a stage.

## Project file

## Automatic Module Outline Generation
See [`examples/mlem/project.toml`](examples/mlem/project.toml). Users edit only
the TOML file; JSON files in `work/` are generated records containing the
resolved inputs and hashes used to reject stale later stages.

***Module Outline Generation Only Tested for the [IHP 130nm Open PDK](https://github.com/IHP-GmbH/IHP-Open-PDK) and OpenROAD***
- `[design]` defines the project name, source GDS, and work directory.
- `[technology]` may provide a technology file override.
- `[logo]` defines artwork, physical width and height, feature size, selected
layer, and optional center offsets.
- `[render]` and `[map]` define the input (`design`, `logo`, or another GDS),
viewport margin, resolution, segments, layers, palette, and outputs.
- `[palettes.<name>]` contains the background and per-layer colors. A
`[render.colors.<layer>]` or `[map.colors.<layer>]` table overrides one color.

With the information gathered from the chip's DEF file, ArtistIC can automatically annotate module
outlines on top of renders.
`layers = "routing"` follows the routing stack in the technology file. A list
selects exact layers. `top-metal` is an alias for the terminal routing layer.
For maps, `views = "metals"` selects the metal layers from the generated set;
`composite` is the colorized combination of all selected layers.

For the provided example, fetch `v0.1.0` of IHP's open PDK in the `pdk` directory:
Render and map viewports start at the actual GDS bounding box and expand by
`margin_um`. Logo placement is centered in that box by default. Width, height,
and `offset_x_um`/`offset_y_um` control its feature-grid canvas.

```
git clone https://github.com/IHP-GmbH/IHP-Open-PDK.git --recursive --branch v0.1.0 pdk
```

Unzip the DEF file:
Raw masks need to be regenerated after changing the input, resolution, segment
grid, overrender factor, viewport margin, or selected layers. Colors, palettes,
render formats, map views, tile size, and output directory are applied by the
host stages and can be changed without rerunning KLayout.

```
gzip -dc examples/mlem/mlem.def.gz > /dev/shm/renderics/mlem.def
```
## Technology and tools

A vector image containing the outlines can then be generated using:
Technology files are resolved in this order:

```
python3 scripts/gen_outline.py \
-i /dev/shm/renderics/mlem.def \
-o /dev/shm/renderics/mlem_modules.svg \
-b /dev/shm/renderics/DPI__mlem_0-0.png \
--lef_files pdk/ihp-sg13g2/libs.ref/sg13g2_sram/lef/*.lef \
--px_scale 15000 \
--offset_x 100 \
--offset_y 83 \
--module_json examples/mlem/mlem_modules.json \
--opacity 0.65 \
--font_size 35 \
--luminosity 0.85
```
1. `[technology].file` in the project;
2. `KLAYOUT_TECH_FILE`;
3. `tech/$KLAYOUT_TECH.lyt` below each location in `KLAYOUT_PATH`.

The resulting file is called `/dev/shm/renderics/mlem_modules.svg` and does not contain the bond pads.
ArtistIC reads the technology connectivity graph to discover the routing stack
and terminal metal. The KLayout worker inspects the actual GDS and writes raw
layer masks. Image composition and map assembly run in ordinary Python.

KLayout stages require KLayout with Python support. Host stages require Python
3.11 or newer, Pillow, ImageMagick, and Inkscape for SVG artwork. Map viewers
load Leaflet from its public CDN.

## License
ArtistIC is released under Version 2.0 (Apache-2.0) see [`LICENSE`](LICENSE):


## Contributing
We are happy to accept pull requests and issues from any contributors. See [`CONTRIBUTING.md`](CONTRIBUTING.md)
for additional information.


## Prerequisites

- [`ImageMagick >= v6.9.12-93`](https://imagemagick.org/script/download.php)
- [`Inkscape >= v1.0.0`](inkscape.org)
- [`Potrace >= v1.15`](https://potrace.sourceforge.net/)
- [`KLayout >= v0.29.0`](https://www.klayout.de/build.html)
- [`img2pdf >= v0.4.4`](https://pypi.org/project/img2pdf)
- [`gdspy >= v1.6.13`](https://pypi.org/project/gdspy)
- [`Pillow >= v10.0.0`](https://pypi.org/project/pillow)
- [`svgpathtools >= v1.7.2`](https://pypi.org/project/svgpathtools)
ArtistIC is licensed under Apache-2.0. See [`LICENSE`](LICENSE).
Loading