Session 3: Schematic Design & Simulation¶
Assignment 1 — NAND Gate with Sky130 PDK¶
Starting from the AND gate netlist from the previous session, I removed the output inverter to convert it to a NAND gate. Then I replaced the simple transistor models with real Sky130 PDK models.
Copying the AND gate as a starting point:

First draft netlist in nano — with wrong PDK path and M prefix:

Problems encountered¶
Problem 1: Wrong PDK path
The path in the course notes did not exist in our environment. Running ngspice gave a model error:


I found the correct path using:
find /foss/pdks -name "sky130.lib.spice" 2>/dev/null

Correct path:
/foss/pdks/ciel/sky130/versions/54435919abffb937387ec956209f9cf5fd2dfbee/sky130A/libs.tech/ngspice/sky130.lib.spice
Problem 2: Transistor naming convention
Even after fixing the path, the same error persisted:


Sky130 PDK transistors are subcircuits, not primitive models, so they require the X prefix instead of M. Mp1 → Xp1, Mn1 → Xn1. This is not obvious from the documentation — it only becomes clear when ngspice throws this error.
Changes from AND gate to NAND gate¶
- Removed inverter transistors
Mp3andMn3 - Changed
Mp1,Mp2→Xp1,Xp2with Sky130 PMOS model - Changed
Mn1,Mn2→Xn1,Xn2with Sky130 NMOS model - Updated
.libpath to correct PDK location - Added propagation delay measurements
Final netlist:
* NAND Gate using CMOS with Sky130 PDK
Vdd vdd gnd 1.8
VinA inA gnd PULSE(0 1.8 1n 100p 100p 2n 6n)
VinB inB gnd PULSE(0 1.8 1n 100p 100p 4n 10n)
Xp1 nand_out inA vdd vdd sky130_fd_pr__pfet_01v8 W=0.99 L=0.150
Xp2 nand_out inB vdd vdd sky130_fd_pr__pfet_01v8 W=0.99 L=0.150
Xn1 nand_out inA mid gnd sky130_fd_pr__nfet_01v8 W=0.495 L=0.150
Xn2 mid inB gnd gnd sky130_fd_pr__nfet_01v8 W=0.495 L=0.150
.lib "...sky130.lib.spice" tt
.tran 10p 20n
.control
run
plot v(inA) v(inB) v(nand_out)
.endc
.end
Assignment 2 — Simulation & Truth Table Verification¶
I ran a transient simulation to verify the truth table and measure propagation delays. The two pulse inputs have different frequencies so all 4 input combinations appear over time.
| A | B | NAND Output |
|---|---|---|
| 0 | 0 | 1 |
| 0 | 1 | 1 |
| 1 | 0 | 1 |
| 1 | 1 | 0 |
The waveform confirms this — nand_out goes LOW only when both inputs are HIGH simultaneously.

Propagation delay results¶

| Measurement | Value | Direction |
|---|---|---|
| tpd_hl | 103.6 ps | Output HIGH → LOW |
| tpd_lh | 82.5 ps | Output LOW → HIGH |
The LOW-to-HIGH transition is faster because PMOS transistors pull up quickly when both inputs go low.
Assignment 3 — Initial Analog Block for RGB Mixer¶
For my chip project I chose to build an RGB Mixer — a chip that takes 3 rotary encoder inputs and controls the brightness of Red, Green, and Blue LEDs independently using PWM signals. Inspired by the silicon-proven project on Tiny Tapeout (tt05, Matt Venn).
As a first analog block, I wrote a voltage amplifier in Verilog-A. This block takes an input voltage and multiplies it by a gain parameter. For the RGB Mixer, this represents the signal conditioning stage — scaling the encoder voltage before feeding it into the PWM generator.
Writing rgb_pwm.va in nano:

Compiling with openvaf:


Writing the SPICE testbench:


Running the simulation:


A 1V amplitude input (red) produces a 1.5V amplitude output (blue) — confirming gain=1.5 is working correctly.
What I learned¶
The X prefix rule for Sky130 subcircuits is not obvious from the documentation — it only becomes clear when ngspice throws a model error. This is the kind of thing that is easy to miss and hard to debug without knowing what to look for.
Propagation delay depends on direction. tpd_hl and tpd_lh are different because PMOS and NMOS transistors have different drive strengths. In Sky130 this asymmetry is intentional — PMOS transistors are sized wider to compensate for their lower mobility.
Verilog-A allows you to describe analog behavior mathematically and compile it into a model that ngspice can use. The openvaf compiler translates the .va file into an .osdi shared library that ngspice loads at runtime with pre_osdi.