Skip to content

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

  1. Make a new file called constraints.sdc Put this inside: create_clock -name clk -period 20 [get_ports clk]

  2. 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

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.

Go to Session 7. Packaging & Board Design