Session6. Synthesis & Physical Design¶
(Thur Mar 5) Super High Level
Homework¶
1. Synthesize your design — review gate count¶
STEP 1. Prepare the files /foss/designs/hello_morse/ hello_morse.v, debounce.v
STEP 2. Run Yosys (Synthesis)
yosys -p "read_verilog hello_morse.v debounce.v; synth -top hello_morse; stat"
*This does: reads the Verilog files, sets hello_morse as the top module, synthesizes the design, prints resource statistics

STEP 3. Save a synthesized netlist
yosys -p "read_verilog hello_morse.v debounce.v; synth -top hello_morse; write_verilog hello_morse_synth.v"

STEP 4. Review gate count
yosys -p "read_verilog hello_morse.v debounce.v; synth -top hello_morse; stat"

| Module | Total Cells |
|---|---|
debounce |
144 |
hello_morse (local only) |
1421 |
| Full design | 1565 |
Gate Count Table
| Cell Type | debounce | hello_morse (local) | Full Design (total) |
|---|---|---|---|
$_ANDNOT_ |
38 | 516 | 554 |
$_AND_ |
2 | 25 | 27 |
$_DFFE_PN0N_ |
0 | 1 | 1 |
$_DFFE_PN0P_ |
1 | 30 | 31 |
$_DFF_PN0_ |
23 | 89 | 112 |
$_DFF_PN1_ |
0 | 2 | 2 |
$_MUX_ |
0 | 70 | 70 |
$_NAND_ |
11 | 85 | 96 |
$_NOR_ |
2 | 57 | 59 |
$_NOT_ |
1 | 21 | 22 |
$_ORNOT_ |
9 | 48 | 57 |
$_OR_ |
37 | 385 | 422 |
$_XNOR_ |
1 | 26 | 27 |
$_XOR_ |
19 | 66 | 85 |
| Total Cells | 144 | 1421 | 1565 |
2. check for unintended latches¶
yosys -p "read_verilog hello_morse.v debounce.v; proc"
These are all safe truncation warnings from assigning 32-bit arithmetic results into smaller localparams.
The clean fix is to make the widths explicit in the expression.
iverilog -g2012 -o hello_morese.vvp hello_morse.v hello_morse_tb.v debounce.v
vvp hello_morse.vvp
gtkwave hello_morse_tb.vcd

3. Run place and route flow (OpenROAD)¶
hello_morse.v debounce.v ↓ yosys synth.ys ↓ hello_morse_synth.v ↓ OpenROAD pnr.tcl ↓ hello_morse.def / hello_morse.gds
STEP 1. Generate gate-level netlist from Yosys.¶
/foss/designs/hello_morse >
1-1. Create a Yosys script ** touch synth.ys
Output file: synth.ys (empty)
1-2. Write the Yosys script Output file: synth.ys
1-3. Run synthesis yosys synth.ys
Output file: hello_morse_synth.v
This file is used by OpenROAD for place-and-route.

STEP 2. Run place and route flow (OpenROAD)¶
2-1. Create the filetouch pnr.tcl
Output file: pnr.tcl (empty)
2-2. Write the OpenRoad script Output file: pnr.tcl
2-3. Run openroad pnr.tcl
Output file: hello_morse_pnr.v, hello_morse.def

4. Analyze timing reports — identify and fix any violations¶
A minimal constraints file with just create_clock is often enough. The example file is at examples/lib/constraints.sdc.
Static Timing Analysis
</> tcl
# Pre-CTS / pre-route electrical cleanup
repair_design
# Post-CTS timing repair
set_propagated_clock [all_clocks]
repair_timing -setup
repair_timing -hold

-
Make a new file called constraints.sdc Put this inside:
create_clock -name clk -period 20 [get_ports clk] -
Replace your pnr.tcl with this
##############################################################################
# pnr.tcl — Standalone OpenROAD flow for hello_morse
##############################################################################
set DESIGN_NAME hello_morse
set pdk_root /foss/pdks/ciel/sky130/versions/54435919abffb937387ec956209f9cf5fd2dfbee/sky130A
set lib_path $pdk_root/libs.ref/sky130_fd_sc_hd/lib/sky130_fd_sc_hd__tt_025C_1v80.lib
set tech_lef $pdk_root/libs.ref/sky130_fd_sc_hd/techlef/sky130_fd_sc_hd__nom.tlef
set cell_lef $pdk_root/libs.ref/sky130_fd_sc_hd/lef/sky130_fd_sc_hd.lef
set sdc_file constraints.sdc
read_lef $tech_lef
read_lef $cell_lef
read_liberty $lib_path
read_verilog hello_morse_synth.v
link_design $DESIGN_NAME
read_sdc $sdc_file
initialize_floorplan \
-site unithd \
-die_area "0 0 200 200" \
-core_area "20 20 180 180"
make_tracks
place_pins \
-hor_layers met3 \
-ver_layers met2 \
-corner_avoidance 5 \
-min_distance 2 \
-min_distance_in_tracks
global_placement
detailed_placement
# This part fixes your error
set_wire_rc -signal -layer met1
set_wire_rc -clock -layer met3
estimate_parasitics -placement
repair_design
report_worst_slack -max
report_worst_slack -min
global_route
write_def hello_morse.def
write_verilog hello_morse_pnr.v
Do not use these lines yet Remove these for now: Right now they are causing confusion.
set_propagated_clock [all_clocks]
repair_timing -setup
repair_timing -hold
After you run it Show me the output of:
report_worst_slack -max
report_worst_slack -min
AI said “Good news: there is no timing violation right now.”
Finish routing in OpenROAD your script should end like this:
global_route
detailed_route
write_def hello_morse_final.def
write_verilog hello_morse_pnr.v
/foss/designs/hello_morse > Run openroad pnr.tcl
5. Generate GDS and review layout in KLayout¶
OPTION A. openroad pnr.tcl¶
STEP 1. Finish routing successfully Before detailed_route, add tie cells:
insert_tiecells sky130_fd_sc_hd__conb_1/LO
insert_tiecells sky130_fd_sc_hd__conb_1/HI
Then use:
global_route
detailed_route
write_def hello_morse_final.def
Run openroad pnr.tcl
STEP 2. Open that DEF in KLayout with the SKY130 tech/LEF files
STEP 3. Save/export as GDS hello_morse.gds

The file had been calculating for over 8 hours, so I gave up.
OPTION B. Makefile¶
** At this point, I refered from another advanced students about Makefile
My flow is:
- Verilog
- ↓
- Yosys (synth.tcl)
- ↓
- hello_morse_synth.v
- ↓
- OpenROAD (pnr.tcl)
- ↓
- DEF
- ↓
- KLayout → GDS
-
The Makefile flow automates all of this.
To run the Makefile, It needs to copy the lib and flow folders from the examples into the designs directory. Also, edit the Makefile.


# =============================================================================
# Hello Morse - Build Automation
# =============================================================================
SHELL := /bin/bash
# Tools
IVERILOG := iverilog
VVP := vvp
VERILATOR := verilator
YOSYS := yosys
OPENROAD := openroad
KLAYOUT := klayout
MAGIC := magic
# Common options
IVERILOG_FLAGS := -Wall -g2012
VERILATOR_FLAGS := --lint-only -Wall
# Paths
LIB := lib
FLOW := flow
# =============================================================================
# PDK Detection
# =============================================================================
ifndef PDK_ROOT
ifneq (,$(wildcard /foss/pdks/sky130A))
PDK_ROOT := /foss/pdks
else ifneq (,$(wildcard $(HOME)/pdks/sky130A))
PDK_ROOT := $(HOME)/pdks
else ifneq (,$(wildcard /opt/pdks/sky130A))
PDK_ROOT := /opt/pdks
endif
endif
define check_pdk
@if [ -z "$(PDK_ROOT)" ]; then \
echo "ERROR: PDK_ROOT is not set and Sky130 PDK not found."; \
echo ""; \
echo "To run the ASIC flow, you need the Sky130 PDK."; \
echo "Use IIC-OSIC-TOOLS Docker or export PDK_ROOT manually."; \
exit 1; \
fi
endef
# =============================================================================
# Project definition
# =============================================================================
HELLO_TOP := hello_morse
HELLO_DIR := hello_morse
HELLO_SRC := $(HELLO_DIR)/hello_morse.v
HELLO_BUILD := $(HELLO_DIR)/build
# Optional testbench
HELLO_TB := $(HELLO_DIR)/hello_morse_tb.v
# Standard cell library GDS path
LIB_DIR := $(PDK_ROOT)/sky130A/libs.ref/sky130_fd_sc_hd
# =============================================================================
# Simulation
# =============================================================================
.PHONY: sim-hello
sim-hello: $(HELLO_DIR)/hello_morse.vvp
$(VVP) $<
$(HELLO_DIR)/hello_morse.vvp: $(HELLO_SRC) $(HELLO_TB)
$(IVERILOG) $(IVERILOG_FLAGS) -I$(LIB) -o $@ $^
# =============================================================================
# Lint
# =============================================================================
.PHONY: lint-hello
lint-hello:
$(VERILATOR) $(VERILATOR_FLAGS) -I$(LIB) $(HELLO_SRC)
# =============================================================================
# Quick synthesis (no PDK required)
# =============================================================================
.PHONY: synth-hello
synth-hello:
$(YOSYS) -p "read_verilog -I$(LIB) $(HELLO_SRC); synth -top $(HELLO_TOP); stat"
# =============================================================================
# Sky130 synthesis
# =============================================================================
.PHONY: sky130-hello
sky130-hello: $(HELLO_BUILD)/$(HELLO_TOP)_synth.v
$(HELLO_BUILD)/$(HELLO_TOP)_synth.v: $(HELLO_SRC)
$(call check_pdk)
@mkdir -p $(HELLO_BUILD)
cd $(HELLO_DIR) && \
TOP=$(HELLO_TOP) \
VERILOG="hello_morse.v ../lib/debounce.v" \
OUT_DIR=build \
$(YOSYS) -c ../$(FLOW)/synth.tcl
# =============================================================================
# Place & Route
# =============================================================================
.PHONY: pnr-hello
pnr-hello: $(HELLO_BUILD)/$(HELLO_TOP).def
$(HELLO_BUILD)/$(HELLO_TOP).def: $(HELLO_BUILD)/$(HELLO_TOP)_synth.v
cd $(HELLO_DIR) && \
TOP=$(HELLO_TOP) \
OUT_DIR=build \
$(OPENROAD) -exit ../$(FLOW)/pnr.tcl
# =============================================================================
# GDS generation
# =============================================================================
.PHONY: gds-hello
gds-hello: $(HELLO_BUILD)/$(HELLO_TOP).gds
$(HELLO_BUILD)/$(HELLO_TOP).gds: $(HELLO_BUILD)/$(HELLO_TOP).def
cd $(HELLO_DIR) && \
$(KLAYOUT) -zz -r ../$(FLOW)/def2gds.rb \
-rd def_file=build/$(HELLO_TOP).def \
-rd gds_file=build/$(HELLO_TOP).gds
# =============================================================================
# Full build
# =============================================================================
.PHONY: build-hello
build-hello: gds-hello
@echo "Hello Morse build complete: $(HELLO_BUILD)/$(HELLO_TOP).gds"
# =============================================================================
# View layout
# =============================================================================
.PHONY: view-hello view-hello-gds
view-hello: $(HELLO_BUILD)/$(HELLO_TOP).def
$(call check_pdk)
$(KLAYOUT) -n $(PDK_ROOT)/sky130A/libs.tech/klayout/tech/sky130A.lyt \
$(LIB_DIR)/gds/sky130_fd_sc_hd.gds $<
view-hello-gds: $(HELLO_BUILD)/$(HELLO_TOP).gds
$(call check_pdk)
$(KLAYOUT) -n $(PDK_ROOT)/sky130A/libs.tech/klayout/tech/sky130A.lyt \
$<
# =============================================================================
# Reports
# =============================================================================
.PHONY: report-hello
report-hello:
@echo "=== Hello Morse Reports ==="
@cat $(HELLO_BUILD)/$(HELLO_TOP)_timing.rpt 2>/dev/null || echo "Run 'make pnr-hello' first"
@cat $(HELLO_BUILD)/$(HELLO_TOP)_area.rpt 2>/dev/null || true
# =============================================================================
# Environment check
# =============================================================================
.PHONY: check-env
check-env:
@echo "=== Environment Check ==="
@echo ""
@echo "PDK_ROOT: $(PDK_ROOT)"
@if [ -n "$(PDK_ROOT)" ] && [ -d "$(PDK_ROOT)/sky130A" ]; then \
echo " Status: OK (Sky130 PDK found)"; \
else \
echo " Status: NOT FOUND"; \
fi
@echo ""
@echo "Tools:"
@which $(YOSYS) > /dev/null 2>&1 && echo " yosys: OK ($(shell which $(YOSYS)))" || echo " yosys: NOT FOUND"
@which $(OPENROAD) > /dev/null 2>&1 && echo " openroad: OK ($(shell which $(OPENROAD)))" || echo " openroad: NOT FOUND"
@which $(KLAYOUT) > /dev/null 2>&1 && echo " klayout: OK ($(shell which $(KLAYOUT)))" || echo " klayout: NOT FOUND"
@which $(IVERILOG) > /dev/null 2>&1 && echo " iverilog: OK ($(shell which $(IVERILOG)))" || echo " iverilog: NOT FOUND"
@which $(VERILATOR) > /dev/null 2>&1 && echo " verilator: OK ($(shell which $(VERILATOR)))" || echo " verilator: NOT FOUND"
# =============================================================================
# Clean
# =============================================================================
.PHONY: clean clean-sim clean-build
clean-sim:
rm -f $(HELLO_DIR)/*.vvp $(HELLO_DIR)/*.vcd
@echo "Cleaned simulation files."
clean-build:
rm -rf $(HELLO_BUILD)
@echo "Cleaned build directory."
clean: clean-sim clean-build
@echo "All cleaned."
# =============================================================================
# Help
# =============================================================================
.PHONY: help
help:
@echo "Hello Morse Makefile"
@echo ""
@echo "Setup:"
@echo " make check-env - Check tools and PDK"
@echo ""
@echo "Simulation:"
@echo " make sim-hello - Run simulation"
@echo ""
@echo "Lint:"
@echo " make lint-hello - Lint with Verilator"
@echo ""
@echo "Quick synthesis:"
@echo " make synth-hello - Synthesize and show stats"
@echo ""
@echo "ASIC flow:"
@echo " make sky130-hello - Synthesize to Sky130 cells"
@echo " make pnr-hello - Place and route"
@echo " make gds-hello - Generate GDS"
@echo " make build-hello - Full flow"
@echo ""
@echo "View:"
@echo " make view-hello - View DEF in KLayout"
@echo " make view-hello-gds - View final GDS in KLayout"
@echo ""
@echo "Reports:"
@echo " make report-hello - Show timing/area reports"
@echo ""
@echo "Cleanup:"
@echo " make clean - Remove generated files"
STEP 1. Teminal make sky130-hello¶
make sky130-hello¶Output file: hello_morse/build/hello_mprse_synth.json, hello_morse_synth.v

STEP2. Place & Route make pnr-hello¶
Output file: hello_morse/build/hello_mprse_def, hello_morse_pnr.v
STEP3. Make GDS make gds-hello¶
Output file: hello_morse/build/hello_mprse.gds

STEP4. View KLayout make view-hello-gds¶
Finally gds layout!


Class Note¶
1. What is Synthesis?¶
Synthesis converts RTL code into a netlist of logic gates.
- Verilog RTL → [Synthesis] → Gate Netlist → [Place & Route] → GDS
2. Logic Synthesis with Yosys¶
Basic Yosys Commands
# Read Verilog
read_verilog my_design.v
# Elaborate hierarchy
hierarchy -check -top my_design
# Synthesize to generic gates
synth -top my_design
# Map to Sky130 cells
dfflibmap -liberty sky130_fd_sc_hd__tt_025C_1v80.lib
abc -liberty sky130_fd_sc_hd__tt_025C_1v80.lib
# Clean up
clean
# Write output
write_verilog -noattr synth.v
3. Standard Cells¶
Pre-designed,pre-characterized logic gates. Fixed height and variable width.
4. Place and Route¶
P&R takes the synthesized netlist and creates physical lauout.
OpenROAD flow for place & route

5. Clock Tree Synthesis¶
CTS builds a balanced distribution network for the clock signal.
For our projects: A minimal constraints file with just create_clock is often enough. The example file is at examples/lib/constraints.sdc.
6. Static Timing Analysis¶
STA checks if your design meets timing without simulation.
7. Power Analysis¶
PA estimate battery life, heat dissipation, and avoid exceeding package limits.
8. What You’ll Submit¶
For tapeout, you typically need:
- A GDS file (generated by the flow)
- Documentation (README, pinout diagram)
- [The Tiny Tapeout GitHub template] handles most of this automatically - see tinytapeout.com for the submission guide.
