IPKISS Canvas
IPKISS Canvas is a Graphical User Interface (GUI) that functions together with the IPKISS Python code. IPKISS Canvas allows users to easily verify designs created with IPKISS Python code in a schematic representation. In addition it allows PIC designers to capture new schematics quickly and accurately, and assist in bringing those designs into IPKISS Python code. This is done either by loading the design directly or by generating a piece of code that can be used as starting point.
Canvas concepts
Designs in the Canvas are stored in a database. IPKISS defines two file formats for this:
IPKISS Canvas library files (with a .iclib extension). This file contains the description of a library. A library contains designs.
IPKISS Canvas project files (with a .icproject extension). This file contains a list of libraries and some user settings (which file is opened, zoom level).
Below are several other concepts that are useful to understand so you can get started with Canvas:
Design: each design can have a symbol representation and a schematic representation. Both are optional: Basic PDK components will often only contain a symbol, or a top-level circuit does not necessarily have a symbol representation.
Symbol: A symbol is represented by an image, size (width/height), terms, parameters, and default visibility of each parameter.
Schematic: A schematic is an abstract drawing representing a (P)IC design, containing symbol instances, connected through nets, and including additional visual elements to help understand your design and communicate it with others.
Cards: Cards are used to visualize additional information on the canvas. They can be invoked by making a selection and then clicking ‘Show Card’ in the context menu.
Extraction: extraction is the process of taking an IPKISS PCell and exporting it to Canvas. There are a variety of options that allow customizing the extraction routines.
Annotation: the process of bringing annotations into the schematic to ‘enrich’ the schematic with important information that is only known after doing the physical implementation.
Backannotation: when the original design is a schematic, then going roundtrip from the Canvas to IPKISS Python and back to Canvas to annotate schematics, is called backannotation.
SDL: schematic-driven layout: this refers to the process of generating a layout based on a schematic created in Canvas.
Exporting an IPKISS design to Canvas
An IPKISS cell can be schematically shown in Canvas using the to_canvas
method.
Here’s a simple example, which exports the MZI cell, and launches Canvas:
# Load a PDK
import si_fab.all as pdk
import ipkiss3.all as i3
class MZI(i3.Circuit):
delta_L = i3.PositiveNumberProperty(doc="Delay length difference", default=10)
def _default_insts(self):
coupler = pdk.SiDirectionalCouplerSPower()
return {
"coupler1": coupler,
"coupler2": coupler,
}
def _default_specs(self):
return [
i3.Place("coupler1", (0, 0)),
i3.Place("coupler2", (100, 0)),
i3.FlipH("coupler2"),
i3.ConnectManhattan("coupler1:out1", "coupler2:out1", control_points=[i3.H(-100+0.5 * self.delta_L)]),
i3.ConnectManhattan("coupler1:out2", "coupler2:out2", control_points=[i3.H(100)]),
]
def _default_exposed_ports(self):
return {
"coupler1:in1": "in1",
"coupler1:in2": "in2",
"coupler2:in1": "out1",
"coupler2:in2": "out2",
}
mzi = MZI(name='MZI')
lay = mzi.Layout()
lay.to_canvas(
project_name="example_mzi",
)
Upon calling this function for the first time, a fresh [cell_name].icproject
and [cell_name].iclib
are generated, where [cell_name]
refers to the name of the IPKISS cell (mzi.name
).
Then IPKISS Canvas proceeds to open this project.
It is similar to writing a GDSII and opening it with a GDS viewer (such as KLayout),
except here we visualize a schematic extracted from the layout.
By default, to_canvas
extracts both optical and full electrical connectivity.
These settings can be changed by passing a custom i3.NetlistExtractionSettings
to to_canvas
.
For more information on electrical netlist extraction, please check out the 3.10 release notes.
Interactivity
When calling to_canvas
, by default this opens IPKISS Canvas (you can set show
to False
to disable launching Canvas).
Whenever you update your code and re-export the design, Canvas automatically refreshes with the changes made.
To make this possible, we are managing the Canvas sessions, so that IPKISS code can communicate with Canvas. We manage a session per project: exporting the same project will reuse the existing window, exporting a different project will launch a new window.
Changes made in Canvas
Certain changes that the user performs in Canvas are remembered: moving instances, displaying cards, changing parameter visibility, which window is opened. However, it’s important to note that any functional changes (new instances, nets, …) are discarded when you re-export.
Functional changes are:
Adding new instances.
Changing the connectivity.
Renaming/removing designs, renaming/removing libraries.
Non-functional changes are remembered when re-exporting from IPKISS Python code:
Positions of symbol instances and cards.
Visibility of cards.
Visibility settings of parameters.
Which schematic windows are open and which is the currently selected one.
Which cell is currently selected and what is the position on the canvas.
Changes to metadata of cells (in so far as the same metadata keys were not updated from Python).
Library files
For predefined cells that come from a PDK or component library, the corresponding library will be loaded into IPKISS Canvas as well.
Each library file has its own .iclib
file.
If a PDK or library already has a predefined
.iclib
file, then that one will be used by to_canvas. This file has to be stored next to the all.py file of the library.If a PDK or library does not have an associated
.iclib
file yet, thento_canvas
will automatically export one, however it will be saved next to the project file (.icproject
).
As a PDK or library maintainer you can also export your existing PDKs / libraries for use in Canvas.
To be a valid Luceda PDK or library, it must have an all.py
file that defines the components in the PDK/library.
The all.py
imports all components that the user wants to extract, and an __all__
list with strings for each symbol.
See the SiFab PDK shipped with the product, or any other Luceda PDK, for examples.
If you have a PDK which is structured according to the PDK guidelines (with a <pdk_path>/ipkiss/<pdk_name> structure), you can call
i3.canvas.export_pdk
. For instance:import ipkiss3.all as i3 # The PDK is stored in <pdk_path>/ipkiss/<pdk_name> # And has a <pdk_path>/ipkiss/<pdk_name>/all.py file i3.canvas.export_pdk(pdk_path=pdk_path, pdk_name=pdk_name)
Alternatively, if you have a single python package that has an all.py file which exports a library of components, then
i3.canvas.export_ipkiss_library
is to be used:import ipkiss3.all as i3 # The library is stored in a python package <library_name> and has a <library_name>/all.py file i3.canvas.export_ipkiss_library(library_path=library_path, library_name=library_name)
You can also customize how symbols are defined when exporting the library.
For an example of how to do so, check the documentation of i3.canvas.export_pdk
.
To see how we customize symbols in si_fab
, our example PDK that is distributed with Luceda Academy, take a look at pdks_sources/si_fab/building/build_iclib.py under Windows: %USERPROFILE%\luceda\luceda_academy\luceda_academy_2024091
and Linux: ~/luceda/luceda_academy/luceda_academy_2024091
.
The i3.canvas.export_pdk
and i3.canvas.export_ipkiss_library
functions both store the resulting .iclib
file in the same directory location as the all.py
file.
Annotating a schematic with more information
Optionally, the cells and instances in the schematic can be annotated with user-specified information.
By default (if annotate
is not set), all optical waveguides and point-to-point electrical traces will be annotated with their exact length in the layout.
Defining custom annotations can be done as follows:
# Load a PDK
import si_fab.all as pdk
import ipkiss3.all as i3
class MZI(i3.Circuit):
delta_L = i3.PositiveNumberProperty(doc="Delay length difference", default=10)
def _default_insts(self):
coupler = pdk.SiDirectionalCouplerSPower()
return {
"coupler1": coupler,
"coupler2": coupler,
}
def _default_specs(self):
return [
i3.Place("coupler1", (0, 0)),
i3.Place("coupler2", (100, 0)),
i3.FlipH("coupler2"),
i3.ConnectManhattan("coupler1:out1", "coupler2:out1", control_points=[i3.H(-100 + 0.5 * self.delta_L)]),
i3.ConnectManhattan("coupler1:out2", "coupler2:out2", control_points=[i3.H(100)]),
]
def _default_exposed_ports(self):
return {
"coupler1:in1": "in1",
"coupler1:in2": "in2",
"coupler2:in1": "out1",
"coupler2:in2": "out2",
}
def annotate_mzi(mzi_layout):
return {"delay length": str(mzi_layout.delta_L)}
def annotate_all(view):
return {"project": "sifab_mzi"}
def annotate_trace_template(trace):
return {"trace template": trace.trace_template.cell.__class__.__name__}
annotations = {
MZI.Layout: annotate_mzi,
i3.LayoutView: annotate_all,
i3.Trace.Layout: [i3.canvas.annotate_trace_length, annotate_trace_template]
# keep the predefined trace length annotation + add our own
}
mzi = MZI(delta_L=20)
mzi.Layout().to_canvas(
project_name='example_export',
annotate=annotations,
show=True,
)
As can be seen from the example, there are two steps:
Define one or multiple annotation functions that take a view as input and return a dictionary of metadata keys and values:
def annotation_function(view): return {"key": "value"}
Specify which annotation functions(s) to use for which view type in the
annotate
argument toto_canvas
. This is a dictionary that maps view types to a list of annotation functions or a single annotation_function:annotations={ ViewType1: annotation_function, ViewType2: [annotation_function1, annotation_function2], }
Schematic capture
One of the functions of Canvas is to create schematics (also known as schematic capture): users can drag-drop symbols on a canvas and build up hierarchical PIC designs based on the large number of supported PDKs or any other custom-built PDK or library.
This method of creating circuits is a great way to quickly build initial designs that can then be further finetuned in IPKISS. In addition it can be used as a communication aid: building PICs, sharing them with colleagues, and avoid making mistakes while translating ideas into PIC implementations.
Once you’re happy with your PIC circuit, you can transfer it into IPKISS Python code for layout, circuit simulation, verification, and perform backannotation.
Going from Canvas to IPKISS code
After schematic capture, two methods are available to go from Canvas to IPKISS code.
Generating a code snippet
This method is useful to generate an initial piece of code to help build pcells in IPKISS, which can be a real time-saver! Please note that code generated this way can be suboptimal, and it’s always the user’s responsibility to check the generated code properly and adjust it further in a code editor to achieve optimal result.
To do so, right-click anywhere on an empty place in the canvas, and click ‘Code Templates’.
Loading a design
A design can be loaded with i3.ConnectComponents.from_canvas
and i3.canvas.load_design
.
A code template is available by default that generates the code that loads this design into IPKISS Python code.
i3.ConnectComponents.from_canvas
is mostly useful for circuit simulation as it contains the full design as represented in the schematic.
i3.canvas.load_design
is a bit more low-level, and allows to use it as a starting point to generate layouts based on automated
placement and routing rules (SDL, schematic driven layout).
For a more in depth-tutorial, check the getting started material on Luceda Academy.
Known limitations
Below is a list of known limitations. These may change over time as we improve the software.
Layout view only
Currently, to_canvas
starts from the layout view.
Only properties defined on the main PCell and its layout view will be shown as parameters.
Properties that are defined specifically on other views (e.g. CircuitModelView
) are not shown as parameters.
to_canvas
directly generates the netlist data by performing a netlist extraction, which by default extracts both the optical + electrical netlist.
That means to_canvas
does not consider the netlist data generated by the NetlistView
of the PCell.
The main use case for this is to verify designs extracted from layout in IPKISS Canvas.
Because we only use LayoutView
, this also means that pcells do not necessarily have to define a NetlistView.
Visualizing netlists of a NetlistView directly is not yet supported.
PDK and library variants and subsets
IPKISS-based libraries that merely import components from another ‘base’ library in their all.py
file are supported through that base library.
All components in the library will be resolved to the base library: instances of them will refer to the cells in that base library.
For instance, suppose you have a base library silicon_fab
with 20 cells, and a derived library silicon_fab_subset
which does not define components of its own
but merely imports 10 cells from silicon_fab
in its all.py
file.
When writing the schematic of a design made with silicon_fab_subset
, the cell instances in the schematic will be from silicon_fab
.
This reflects is similar to how it works in the Python code as well.
A number of Luceda PDK have technology flavors (e.g. with a different device layer thickness or different back-end options). These may be supported through their generic base library.
Python API reference
Various API functions are available for exporting library and design data to Canvas, as well as for importing from Canvas. See IPKISS Canvas - Python API for an overview.