Module 5: Caravel User Project Wrapper Integration¶
Prerequisites
Before proceeding, ensure your aes_wb_wrapper has completed full physical signoff in
Module 4 and that the classic_flow_eco run tag exists and is complete. The
copy_views.sh script used later in this module will pull its inputs directly from
that run directory.
Table of Contents¶
1. What is the User Project Wrapper?¶
The User Project Wrapper (user_project_wrapper) is the physical boundary between
your custom design and the Caravel SoC harness. Caravel provides the padframe,
the management SoC, and a standardised set of GPIO and Wishbone signals — the
user_project_wrapper is the slot where your design plugs in.
Fig. 32 the User Project Wrapper occupies the central user area and connects to the management SoC via the Wishbone bus and GPIO interface.¶
Because Caravel is a fixed physical chip, it imposes strict requirements on the wrapper that cannot be changed:
The die area must be exactly 2920 × 3520 µm.
All I/O pins must appear at exact coordinate locations with exact metal shapes.
The power rings must be generated with specific widths, spacings, and offsets to align with Caravel’s top-level PDN.
These constraints are encoded in the fixed_dont_change/ directory of the project
template and must never be edited.
2. Integration Strategies Overview¶
There are three established approaches for placing your design inside the
user_project_wrapper. The right choice depends on design size, timing requirements,
and how much control you need over the top-level physical implementation.
Harden the user IP as a standalone macro first, then drop it into the wrapper without adding any top-level standard cells. The wrapper acts as a pass-through. Ideal for small-to-medium designs — fastest runtime and simplest flow.
Harden the macro first, then integrate it into the wrapper with top-level standard cells enabled. The tool may insert buffers or repair logic at the boundary. A hybrid approach useful when the macro has boundary violations that require top-level fixing.
Merge all RTL — AES core, wrapper, and everything else — into one large flattened design that covers the full ≈ 3mm × 3.6mm area. Maximum performance, but requires the most PnR time and iteration. Best for designs that need the full wrapper area.
3. Strategy 1 — Macro-First Hardening¶
In this strategy, aes_wb_wrapper is treated as a pre-hardened black box. The wrapper
only connects its pins to the Caravel interface — no new logic is synthesised or
optimised at the top level, so most flow steps are disabled. This is the approach we
use in this workshop.
3.1 RTL — Instantiating the AES Macro¶
The RTL wrapper connects the Caravel Wishbone and GPIO signals to the aes_wb_wrapper
macro, instantiated as mprj. Open the file for editing:
$ gedit ~/Silicon-Sprint-AUC/verilog/rtl/user_project_wrapper.v
user_project_wrapper.v
// SPDX-FileCopyrightText: 2020 Efabless Corporation
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// SPDX-License-Identifier: Apache-2.0
`default_nettype none
/*
*-------------------------------------------------------------
*
* user_project_wrapper
*
* This wrapper enumerates all of the pins available to the
* user for the user project.
*
* An example user project is provided in this wrapper. The
* example should be removed and replaced with the actual
* user project.
*
*-------------------------------------------------------------
*/
module user_project_wrapper #(
parameter BITS = 32
) (
`ifdef USE_POWER_PINS
inout vdda1, // User area 1 3.3V supply
inout vdda2, // User area 2 3.3V supply
inout vssa1, // User area 1 analog ground
inout vssa2, // User area 2 analog ground
inout vccd1, // User area 1 1.8V supply
inout vccd2, // User area 2 1.8v supply
inout vssd1, // User area 1 digital ground
inout vssd2, // User area 2 digital ground
`endif
// Wishbone Slave ports (WB MI A)
input wb_clk_i,
input wb_rst_i,
input wbs_stb_i,
input wbs_cyc_i,
input wbs_we_i,
input [3:0] wbs_sel_i,
input [31:0] wbs_dat_i,
input [31:0] wbs_adr_i,
output wbs_ack_o,
output [31:0] wbs_dat_o,
// Logic Analyzer Signals
input [127:0] la_data_in,
output [127:0] la_data_out,
input [127:0] la_oenb,
// IOs
input [`MPRJ_IO_PADS-1:0] io_in,
output [`MPRJ_IO_PADS-1:0] io_out,
output [`MPRJ_IO_PADS-1:0] io_oeb,
// Analog (direct connection to GPIO pad---use with caution)
// Note that analog I/O is not available on the 7 lowest-numbered
// GPIO pads, and so the analog_io indexing is offset from the
// GPIO indexing by 7 (also upper 2 GPIOs do not have analog_io).
inout [`MPRJ_IO_PADS-10:0] analog_io,
// Independent clock (on independent integer divider)
input user_clock2,
// User maskable interrupt signals
output [2:0] user_irq
);
/*--------------------------------------*/
/* User project is instantiated here */
/*--------------------------------------*/
aes_wb_wrapper mprj (
`ifdef USE_POWER_PINS
.VPWR(vccd2),
.VGND(vssd2),
`endif
.wb_clk_i(wb_clk_i),
.wb_rst_i(wb_rst_i),
// MGMT SoC Wishbone Slave
.wbs_cyc_i(wbs_cyc_i),
.wbs_stb_i(wbs_stb_i),
.wbs_we_i(wbs_we_i),
.wbs_sel_i(wbs_sel_i),
.wbs_adr_i(wbs_adr_i),
.wbs_dat_i(wbs_dat_i),
.wbs_ack_o(wbs_ack_o),
.wbs_dat_o(wbs_dat_o)
);
endmodule // user_project_wrapper
`default_nettype wire
The instance name mprj must match exactly in both the Verilog instantiation and the
MACROS configuration dictionary.
Create the wrapper configuration file:
$ gedit ~/Silicon-Sprint-AUC/openlane/user_project_wrapper/config.json
Paste the following complete configuration:
config.json
{
"VERILOG_FILES": [
"dir::../../verilog/rtl/defines.v",
"dir::../../verilog/rtl/user_project_wrapper.v"
],
"SYNTH_ELABORATE_ONLY": true,
"RUN_POST_GPL_DESIGN_REPAIR": false,
"RUN_POST_CTS_RESIZER_TIMING": false,
"DESIGN_REPAIR_BUFFER_INPUT_PORTS": false,
"PDN_ENABLE_RAILS": false,
"RUN_ANTENNA_REPAIR": false,
"RUN_FILL_INSERTION": false,
"RUN_TAP_ENDCAP_INSERTION": false,
"RUN_CTS": false,
"RUN_IRDROP_REPORT": false,
"MACROS": {
"aes_wb_wrapper": {
"gds": ["dir::../../gds/aes_wb_wrapper.gds"],
"lef": ["dir::../../lef/aes_wb_wrapper.lef"],
"instances": {
"mprj": {
"location": [10, 20],
"orientation": "N"
}
},
"nl": ["dir::../../verilog/gl/aes_wb_wrapper.v"],
"spef": {
"min_*": ["dir::../../spef/multicorner/aes_wb_wrapper.min.spef"],
"nom_*": ["dir::../../spef/multicorner/aes_wb_wrapper.nom.spef"],
"max_*": ["dir::../../spef/multicorner/aes_wb_wrapper.max.spef"]
},
"lib": {"*": "dir::../../lib/aes_wb_wrapper.lib"}
}
},
"PDN_MACRO_CONNECTIONS": ["mprj vccd2 vssd2 VPWR VGND"],
"PDN_VOFFSET": 5,
"PDN_HOFFSET": 5,
"PDN_VWIDTH": 3.1,
"PDN_HWIDTH": 3.1,
"PDN_VSPACING": 15.5,
"PDN_HSPACING": 15.5,
"PDN_VPITCH": 180,
"PDN_HPITCH": 180,
"QUIT_ON_PDN_VIOLATIONS": false,
"MAGIC_DRC_USE_GDS": true,
"MAX_TRANSITION_CONSTRAINT": 1.5,
"//": "Fixed configurations for Caravel — do NOT edit below this line",
"DESIGN_NAME": "user_project_wrapper",
"FP_SIZING": "absolute",
"DIE_AREA": [0, 0, 2920, 3520],
"FP_DEF_TEMPLATE": "dir::fixed_dont_change/user_project_wrapper.def",
"VDD_NETS": ["vccd1", "vccd2", "vdda1", "vdda2"],
"GND_NETS": ["vssd1", "vssd2", "vssa1", "vssa2"],
"PDN_CORE_RING": 1,
"PDN_CORE_RING_VWIDTH": 3.1,
"PDN_CORE_RING_HWIDTH": 3.1,
"PDN_CORE_RING_VOFFSET": 12.45,
"PDN_CORE_RING_HOFFSET": 12.45,
"PDN_CORE_RING_VSPACING": 1.7,
"PDN_CORE_RING_HSPACING": 1.7,
"CLOCK_PORT": "wb_clk_i",
"PNR_SDC_FILE": "dir::signoff.sdc",
"SIGNOFF_SDC_FILE": "dir::signoff.sdc",
"MAGIC_DEF_LABELS": 0,
"CLOCK_PERIOD": 25,
"MAGIC_ZEROIZE_ORIGIN": 0
}
3.2 The DEF Template¶
"FP_DEF_TEMPLATE": "dir::fixed_dont_change/user_project_wrapper.def"
The Odb.ApplyDEFTemplate step imports a pre-built template into the OpenROAD database. It copies the die area, core area, and I/O pin data (names/locations) to ensure a perfect physical match with the top-level harness.
Key Requirements¶
Pin Matching: By default, the design’s pin set must identically match the template. Any mismatch will cause the flow to fail.
Immutable Source: Templates are stored in
fixed_dont_change/and must not be edited, as they represent fixed physical hardware.
Why It Is Required for Caravel¶
The template (FP_DEF_TEMPLATE) encodes three attributes that config.json cannot define:
Exact Pin Geometry: Assigns the precise shape, layer, and coordinates required for connection to the management SoC and padframe.
Fixed Power Rings: Includes pre-drawn VDD/GND rings designed to align perfectly with the top-level Power Distribution Network (PDN).
Fixed Core Area: Enforces the exact 2,920 × 3,520 µm boundary available in the fabricated silicon.
Fig. 33 User Project Wrapper DEF template in KLayout — pre-placed I/O pins, power ring, and die boundary. The open core area is where your macro is placed.¶
Warning
This file must never be modified. Moving even a single pin by one manufacturing grid step will cause fatal DRC violations during top-level chip assembly.
3.3 Macro Physical Views¶
LibreLane requires several physical view files to place, route, analyse, and verify the macro inside the wrapper. The two essential views are:
LEF (.lef) — Essential for PnR
The physical interface of the macro — boundary dimensions, pin locations on metal layers, and routing obstructions. LibreLane uses the LEF to keep routing out of the macro boundary and prevent shorts against its pins.
GDSII (.gds) — Essential for Tape-Out
The complete physical layout including silicon implant and diffusion layers. Used during GDS stream-out, DRC, and LVS.
The remaining views are optional but improve analysis quality:
View |
Extension |
Role |
|---|---|---|
Gate-Level Netlist |
|
Used during STA and as a fallback for linting. |
Powered Netlist |
|
Same as above with power pins — preferred for LVS. |
Liberty Model |
|
Cell timing models for OpenSTA path analysis through the macro. |
Parasitics |
|
Per-corner RC extraction — enables accurate post-layout STA. |
3.4 Macro Registration and Placement¶
Macros are registered in the MACROS dictionary. The instances sub-key maps the
RTL instance name to a physical placement:
"instances": {
"mprj": {
"location": [10, 20],
"orientation": "N"
}
}
Instance name — must match exactly as instantiated in
user_project_wrapper.v.Location —
[10, 20]places the macro near the bottom-left corner of the core area, minimising wire length to the Wishbone signals that enter the wrapper from that edge.Orientation —
N(North, no rotation) keeps the macro’s Wishbone pins aligned with the correct wrapper edge.
3.5 Power Connections¶
"PDN_MACRO_CONNECTIONS": ["mprj vccd2 vssd2 VPWR VGND"]
Field |
Value |
Meaning |
|---|---|---|
Instance name |
|
Matches the RTL instance name. Accepts regex for multi-instance designs. |
VDD net |
|
The secondary digital power domain in Caravel’s multi-supply architecture. |
GND net |
|
The secondary digital ground. |
VDD pin |
|
Physical power pin name on the macro (from its LEF). |
GND pin |
|
Physical ground pin name on the macro. |
3.6 Disabled Flow Steps¶
Because aes_wb_wrapper is pre-hardened and timing-closed, most optimisation steps
are disabled at the wrapper level to avoid modifying a physically finalised design.
Parameter |
Why Disabled |
|---|---|
|
The wrapper contains only a macro instantiation — elaboration-only mode preserves hierarchy without technology mapping. |
|
The macro has its own internal clock tree. No new CTS is needed at the wrapper level. |
|
Prevents the resizer from attempting to fix violations on an already finalised design. |
|
No CTS is run, so post-CTS timing optimisation has nothing to act on. |
|
Prevents buffer insertion at wrapper input ports, preserving direct connections to macro pins. |
|
Metal 1 standard cell rails are only needed where standard cells exist — the wrapper core is occupied by the macro. |
|
Antenna repair was already performed during Module 4 hardening. |
|
Tap cells support standard cell rows — not needed when the wrapper contains only a hardened macro. |
|
Filler cells close gaps between standard cells. No standard cells means no gaps. |
|
IR drop analysis is performed at the full chip level; skipping it reduces runtime. |
3.7 Full Configuration Reference¶
Variable |
Type |
Description |
Default |
|---|---|---|---|
|
|
Elaborates hierarchy without technology mapping. |
|
|
|
Dictionary of macro physical views, instances, and timing models. |
|
|
|
Explicit power connections. Format: |
|
|
|
Top-level module name. Must be |
|
|
|
|
|
|
|
Fixed die boundary |
|
|
|
Pre-built DEF with fixed I/O pins, power ring, and die boundary. |
|
|
|
Power net names for PDN generation. |
|
|
|
Ground net names. |
|
|
|
Generates a power ring around the core perimeter. |
|
|
|
Width of vertical ring segments (µm). |
|
|
|
Width of horizontal ring segments (µm). |
|
|
|
Spacing between VDD/GND vertical ring straps (µm). |
|
|
|
Spacing between VDD/GND horizontal ring straps (µm). |
|
|
|
Offset of vertical ring from core boundary (µm). |
|
|
|
Offset of horizontal ring from core boundary (µm). |
|
|
|
Primary clock port. |
|
|
|
Moves layout origin to (0, 0) in Magic’s LEF. Must be |
|
3.8 Copying Macro Views¶
Before running the wrapper flow, copy all physical view files from the aes_wb_wrapper
hardening run into the shared project directories:
$ bash ~/Silicon-Sprint-AUC/openlane/copy_views.sh \
~/Silicon-Sprint-AUC \
aes_wb_wrapper \
classic_flow_eco
The three arguments are: project root directory, macro name, and run tag. The script
copies final/gds/ → gds/, final/lef/ → lef/, final/nl/ → verilog/gl/,
final/spef/ → spef/multicorner/, and final/lib/ → lib/.
Note
Verify that all five destination directories are populated before proceeding. A missing file will cause a file-not-found error at the step that first needs that view.
3.9 Flow Execution¶
Enter the Nix shell:
$ nix-shell ~/librelane/shell.nix
Run the wrapper hardening:
[nix-shell:~]$ librelane \
~/Silicon-Sprint-AUC/openlane/user_project_wrapper/config.json \
--run-tag project_wrapper
When the flow completes successfully:
Antenna
Passed ✅
LVS
Passed ✅
DRC
Passed ✅
3.10 Viewing the Layout¶
[nix-shell:~]$ librelane \
--last-run \
--flow openinklayout \
~/Silicon-Sprint-AUC/openlane/user_project_wrapper/config.json
Fig. 34 User Project Wrapper layout — the aes_wb_wrapper macro at the bottom-left corner,
close to the Wishbone signal pins entering from that edge.¶
Toggle layer visibility to prBoundary.boundary, met1.drawing, met2.drawing, and
met3.drawing to inspect the internal macro routing.
Fig. 35 AES macro internal view — the absence of long routes confirms that all internal routing was completed cleanly during Module 4.¶
3.11 Checking the Reports¶
Antenna Check (OpenROAD.CheckAntennas)¶
Location: runs/project_wrapper/XX-openroad-checkantennas/
┏━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━┳━━━━━━━━━┳━━━━━┳━━━━━┳━━━━━━━┓
┃ Partial/Required ┃ Required ┃ Partial ┃ Net ┃ Pin ┃ Layer ┃
┡━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━╇━━━━━━━━━╇━━━━━╇━━━━━╇━━━━━━━┩
└──────────────────┴──────────┴─────────┴─────┴─────┴───────┘
Post-PnR STA (OpenROAD.STAPostPNR)¶
Location: runs/project_wrapper/XX-openroad-stapostpnr/summary.rpt
┏━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━┳━━━━━━━━━━┳━━━━━━━━━━┳━━━━━━━━━━┳━━━━━━━━━━━┳━━━━━━━━━━┳━━━━━━━━━━━┳━━━━━━━━━━┳━━━━━━━━━━━┳━━━━━━━━━━┳━━━━━━━━━━━┳━━━━━━━━━━┓
┃ ┃ Hold ┃ Reg to ┃ ┃ ┃ of which ┃ Setup ┃ ┃ ┃ ┃ of which ┃ ┃ ┃
┃ ┃ Worst ┃ Reg ┃ ┃ Hold Vio ┃ reg to ┃ Worst ┃ Reg to ┃ Setup ┃ Setup Vio ┃ reg to ┃ Max Cap ┃ Max Slew ┃
┃ Corner/Group ┃ Slack ┃ Paths ┃ Hold TNS ┃ Count ┃ reg ┃ Slack ┃ Reg Paths ┃ TNS ┃ Count ┃ reg ┃ Violatio… ┃ Violati… ┃
┡━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━╇━━━━━━━━━━╇━━━━━━━━━━╇━━━━━━━━━━╇━━━━━━━━━━━╇━━━━━━━━━━╇━━━━━━━━━━━╇━━━━━━━━━━╇━━━━━━━━━━━╇━━━━━━━━━━╇━━━━━━━━━━━╇━━━━━━━━━━┩
│ Overall │ 0.0047 │ 0.0047 │ 0.0000 │ 0 │ 0 │ 2.1041 │ 2.1041 │ 0.0000 │ 0 │ 0 │ 1 │ 2 │
│ nom_tt_025C_1v80 │ 0.1483 │ 0.1483 │ 0.0000 │ 0 │ 0 │ 7.9981 │ 13.3840 │ 0.0000 │ 0 │ 0 │ 0 │ 0 │
│ nom_ss_100C_1v60 │ 0.5562 │ 0.5562 │ 0.0000 │ 0 │ 0 │ 2.5763 │ 2.5763 │ 0.0000 │ 0 │ 0 │ 0 │ 0 │
│ nom_ff_n40C_1v95 │ 0.0053 │ 0.0053 │ 0.0000 │ 0 │ 0 │ 9.1132 │ 17.4716 │ 0.0000 │ 0 │ 0 │ 0 │ 0 │
│ min_tt_025C_1v80 │ 0.1474 │ 0.1474 │ 0.0000 │ 0 │ 0 │ 8.1437 │ 13.6547 │ 0.0000 │ 0 │ 0 │ 0 │ 0 │
│ min_ss_100C_1v60 │ 0.5545 │ 0.5545 │ 0.0000 │ 0 │ 0 │ 3.0678 │ 3.0678 │ 0.0000 │ 0 │ 0 │ 0 │ 0 │
│ min_ff_n40C_1v95 │ 0.0047 │ 0.0047 │ 0.0000 │ 0 │ 0 │ 9.2076 │ 17.7111 │ 0.0000 │ 0 │ 0 │ 0 │ 0 │
│ max_tt_025C_1v80 │ 0.1491 │ 0.1491 │ 0.0000 │ 0 │ 0 │ 7.8819 │ 13.1149 │ 0.0000 │ 0 │ 0 │ 0 │ 0 │
│ max_ss_100C_1v60 │ 0.5582 │ 0.5582 │ 0.0000 │ 0 │ 0 │ 2.1041 │ 2.1041 │ 0.0000 │ 0 │ 0 │ 1 │ 2 │
│ max_ff_n40C_1v95 │ 0.0059 │ 0.0059 │ 0.0000 │ 0 │ 0 │ 9.0334 │ 17.2358 │ 0.0000 │ 0 │ 0 │ 0 │ 0 │
└──────────────────────┴──────────┴──────────┴──────────┴──────────┴───────────┴──────────┴───────────┴──────────┴───────────┴──────────┴───────────┴──────────┘
Interpreting the Results
Hold and Setup: zero violations across all 9 corners. The macro’s pre-hardened timing is correctly preserved at the wrapper level.
Max Slew (2) and Max Cap (1) in max_ss_100C_1v60: inherited from the
aes_wb_wrapper interface pins — not resolvable at the wrapper level in this strategy.
They do not affect functional correctness.
DRC and LVS¶
Magic DRC — runs/project_wrapper/XX-magic-drc/reports/drc.rpt:
aes_wb_wrapper
----------------------------------------
[INFO] COUNT: 0
[INFO] Should be divided by 3 or 4
KLayout DRC — runs/project_wrapper/XX-klayout-drc/violations.json:
{ "total": 0 }
LVS — runs/project_wrapper/XX-netgen-lvs/reports/lvs.rpt:
Cell pin lists are equivalent.
Device classes user_project_wrapper and user_project_wrapper are equivalent.
Final result: Circuits match uniquely.
3.12 Saving the Views¶
$ bash ~/Silicon-Sprint-AUC/openlane/copy_views.sh \
~/Silicon-Sprint-AUC \
user_project_wrapper \
project_wrapper
Congratulations — Strategy 1 Complete!
The user_project_wrapper.gds produced by this run is ready for integration into the
Caravel harness.
4. Strategy 2 — Top-Level Integration¶
In the top-level integration methodology, aes_wb_wrapper is still hardened as a
separate macro, but the wrapper is now allowed to place additional standard cells
at the top level alongside it. The tool performs full CTS, placement repair, and
buffering on the wrapper-level logic, closing any boundary timing violations that the
macro-first strategy cannot address.
The key differences from Strategy 1 are that all optimisation steps are enabled, and
the macro is placed away from the corner ([100, 100] instead of [10, 20]) to leave
room for the tool to insert routing, well taps, and buffers at the boundary without
creating congestion.
Warning
Do not use "location": [10, 20] with this strategy. Placing the macro at the extreme
corner leaves no routing headroom for the top-level standard cells, tap cells, and
input port buffers the tool inserts, causing routing overflow.
4.1 Timing Constraints (Top-Level)¶
Both SDC files are used with Strategy 2 — the same files used in Strategy 1. The PnR file over-constrains during implementation; the signoff file applies realistic values for the final timing check.
signoff.sdc
# generated by get_cup_sdc.py
# Date: 2023/06/20
### Note:
# - input clock transition and latency are set for wb_clk_i port.
# If your design is using the user_clock2, update the clock constraints to reflect that and use usr_* variables.
# - IO ports are assumed to be asynchronous. If they're synchronous to the clock, update the variable IO_SYNC to 1.
# As well, update in_ext_delay and out_ext_delay with the required I/O external delays.
#------------------------------------------#
# Pre-defined Constraints
#------------------------------------------#
set ::env(IO_SYNC) 0
# Clock network
if {[info exists ::env(CLOCK_PORT)] && $::env(CLOCK_PORT) != ""} {
set clk_input $::env(CLOCK_PORT)
create_clock [get_ports $clk_input] -name clk -period $::env(CLOCK_PERIOD)
puts "\[INFO\]: Creating clock {clk} for port $clk_input with period: $::env(CLOCK_PERIOD)"
} else {
set clk_input __VIRTUAL_CLK__
create_clock -name clk -period $::env(CLOCK_PERIOD)
puts "\[INFO\]: Creating virtual clock with period: $::env(CLOCK_PERIOD)"
}
if { ![info exists ::env(SYNTH_CLK_DRIVING_CELL)] } {
set ::env(SYNTH_CLK_DRIVING_CELL) $::env(SYNTH_DRIVING_CELL)
}
if { ![info exists ::env(SYNTH_CLK_DRIVING_CELL_PIN)] } {
set ::env(SYNTH_CLK_DRIVING_CELL_PIN) $::env(SYNTH_DRIVING_CELL_PIN)
}
# Clock non-idealities
set_propagated_clock [all_clocks]
set_clock_uncertainty $::env(SYNTH_CLOCK_UNCERTAINTY) [get_clocks {clk}]
puts "\[INFO\]: Setting clock uncertainity to: $::env(SYNTH_CLOCK_UNCERTAINTY)"
set_clock_transition $::env(SYNTH_CLOCK_TRANSITION) [get_clocks {clk}]
puts "\[INFO\]: Setting clock transition to: $::env(SYNTH_CLOCK_TRANSITION)"
# Maximum transition time for the design nets
set_max_transition 1.5 [current_design]
puts "\[INFO\]: Setting maximum transition to: 1.5"
# Maximum fanout
set_max_fanout $::env(MAX_FANOUT_CONSTRAINT) [current_design]
puts "\[INFO\]: Setting maximum fanout to: $::env(MAX_FANOUT_CONSTRAINT)"
# Timing paths delays derate
set_timing_derate -early [expr {1-$::env(SYNTH_TIMING_DERATE)}]
set_timing_derate -late [expr {1+$::env(SYNTH_TIMING_DERATE)}]
puts "\[INFO\]: Setting timing derate to: [expr {$::env(SYNTH_TIMING_DERATE) * 100}] %"
# Reset input delay
set_input_delay [expr $::env(CLOCK_PERIOD) * 0.5] -clock [get_clocks {clk}] [get_ports {wb_rst_i}]
# Multicycle paths
set_multicycle_path -setup 2 -through [get_ports {wbs_ack_o}]
set_multicycle_path -hold 1 -through [get_ports {wbs_ack_o}]
set_multicycle_path -setup 2 -through [get_ports {wbs_cyc_i}]
set_multicycle_path -hold 1 -through [get_ports {wbs_cyc_i}]
set_multicycle_path -setup 2 -through [get_ports {wbs_stb_i}]
set_multicycle_path -hold 1 -through [get_ports {wbs_stb_i}]
#------------------------------------------#
# Retrieved Constraints
#------------------------------------------#
# Clock source latency
set usr_clk_max_latency 4.57
set usr_clk_min_latency 4.11
set clk_max_latency 5.57
set clk_min_latency 4.65
set_clock_latency -source -max $clk_max_latency [get_clocks {clk}]
set_clock_latency -source -min $clk_min_latency [get_clocks {clk}]
puts "\[INFO\]: Setting clock latency range: $clk_min_latency : $clk_max_latency"
# Clock input Transition
set usr_clk_tran 0.13
set clk_tran 0.61
set_input_transition $clk_tran [get_ports $clk_input]
puts "\[INFO\]: Setting clock transition: $clk_tran"
# Input delays
set_input_delay -max 1.87 -clock [get_clocks {clk}] [get_ports {la_data_in[*]}]
set_input_delay -max 1.89 -clock [get_clocks {clk}] [get_ports {la_oenb[*]}]
set_input_delay -max 3.17 -clock [get_clocks {clk}] [get_ports {wbs_sel_i[*]}]
set_input_delay -max 3.74 -clock [get_clocks {clk}] [get_ports {wbs_we_i}]
set_input_delay -max 3.89 -clock [get_clocks {clk}] [get_ports {wbs_adr_i[*]}]
set_input_delay -max 4.13 -clock [get_clocks {clk}] [get_ports {wbs_stb_i}]
set_input_delay -max 4.61 -clock [get_clocks {clk}] [get_ports {wbs_dat_i[*]}]
set_input_delay -max 4.74 -clock [get_clocks {clk}] [get_ports {wbs_cyc_i}]
set_input_delay -min 0.18 -clock [get_clocks {clk}] [get_ports {la_data_in[*]}]
set_input_delay -min 0.3 -clock [get_clocks {clk}] [get_ports {la_oenb[*]}]
set_input_delay -min 0.79 -clock [get_clocks {clk}] [get_ports {wbs_adr_i[*]}]
set_input_delay -min 1.04 -clock [get_clocks {clk}] [get_ports {wbs_dat_i[*]}]
set_input_delay -min 1.19 -clock [get_clocks {clk}] [get_ports {wbs_sel_i[*]}]
set_input_delay -min 1.65 -clock [get_clocks {clk}] [get_ports {wbs_we_i}]
set_input_delay -min 1.69 -clock [get_clocks {clk}] [get_ports {wbs_cyc_i}]
set_input_delay -min 1.86 -clock [get_clocks {clk}] [get_ports {wbs_stb_i}]
if { $::env(IO_SYNC) } {
set in_ext_delay 4
puts "\[INFO\]: Setting input ports external delay to: $in_ext_delay"
set_input_delay -max [expr $in_ext_delay + 4.55] -clock [get_clocks {clk}] [get_ports {io_in[*]}]
set_input_delay -min [expr $in_ext_delay + 1.26] -clock [get_clocks {clk}] [get_ports {io_in[*]}]
}
# Input Transition
set_input_transition -max 0.14 [get_ports {wbs_we_i}]
set_input_transition -max 0.15 [get_ports {wbs_stb_i}]
set_input_transition -max 0.17 [get_ports {wbs_cyc_i}]
set_input_transition -max 0.18 [get_ports {wbs_sel_i[*]}]
set_input_transition -max 0.38 [get_ports {io_in[*]}]
set_input_transition -max 0.84 [get_ports {wbs_dat_i[*]}]
set_input_transition -max 0.86 [get_ports {la_data_in[*]}]
set_input_transition -max 0.92 [get_ports {wbs_adr_i[*]}]
set_input_transition -max 0.97 [get_ports {la_oenb[*]}]
set_input_transition -min 0.05 [get_ports {io_in[*]}]
set_input_transition -min 0.06 [get_ports {la_oenb[*]}]
set_input_transition -min 0.07 [get_ports {la_data_in[*]}]
set_input_transition -min 0.07 [get_ports {wbs_adr_i[*]}]
set_input_transition -min 0.07 [get_ports {wbs_dat_i[*]}]
set_input_transition -min 0.09 [get_ports {wbs_cyc_i}]
set_input_transition -min 0.09 [get_ports {wbs_sel_i[*]}]
set_input_transition -min 0.09 [get_ports {wbs_we_i}]
set_input_transition -min 0.15 [get_ports {wbs_stb_i}]
# Output delays
set_output_delay -max 0.7 -clock [get_clocks {clk}] [get_ports {user_irq[*]}]
set_output_delay -max 1.0 -clock [get_clocks {clk}] [get_ports {la_data_out[*]}]
set_output_delay -max 3.62 -clock [get_clocks {clk}] [get_ports {wbs_dat_o[*]}]
set_output_delay -max 8.41 -clock [get_clocks {clk}] [get_ports {wbs_ack_o}]
set_output_delay -min 0 -clock [get_clocks {clk}] [get_ports {la_data_out[*]}]
set_output_delay -min 0 -clock [get_clocks {clk}] [get_ports {user_irq[*]}]
set_output_delay -min 1.13 -clock [get_clocks {clk}] [get_ports {wbs_dat_o[*]}]
set_output_delay -min 1.37 -clock [get_clocks {clk}] [get_ports {wbs_ack_o}]
if { $::env(IO_SYNC) } {
set out_ext_delay 4
puts "\[INFO\]: Setting output ports external delay to: $out_ext_delay"
set_output_delay -max [expr $out_ext_delay + 9.12] -clock [get_clocks {clk}] [get_ports {io_out[*]}]
set_output_delay -max [expr $out_ext_delay + 9.32] -clock [get_clocks {clk}] [get_ports {io_oeb[*]}]
set_output_delay -min [expr $out_ext_delay + 2.34] -clock [get_clocks {clk}] [get_ports {io_oeb[*]}]
set_output_delay -min [expr $out_ext_delay + 3.9] -clock [get_clocks {clk}] [get_ports {io_out[*]}]
}
# Output loads
set_load 0.19 [all_outputs]
pnr.sdc
# Copied from signoff.sdc then edited
## Note:
# - input clock transition and latency are set for wb_clk_i port.
# If your design is using the user_clock2, update the clock constraints to reflect that and use usr_* variables.
# - IO ports are assumed to be asynchronous. If they're synchronous to the clock, update the variable IO_SYNC to 1.
# As well, update in_ext_delay and out_ext_delay with the required I/O external delays.
#------------------------------------------#
# Pre-defined Constraints
#------------------------------------------#
set ::env(IO_SYNC) 0
# Clock network
if {[info exists ::env(CLOCK_PORT)] && $::env(CLOCK_PORT) != ""} {
set clk_input $::env(CLOCK_PORT)
create_clock [get_ports $clk_input] -name clk -period $::env(CLOCK_PERIOD)
puts "\[INFO\]: Creating clock {clk} for port $clk_input with period: $::env(CLOCK_PERIOD)"
} else {
set clk_input __VIRTUAL_CLK__
create_clock -name clk -period $::env(CLOCK_PERIOD)
puts "\[INFO\]: Creating virtual clock with period: $::env(CLOCK_PERIOD)"
}
if { ![info exists ::env(SYNTH_CLK_DRIVING_CELL)] } {
set ::env(SYNTH_CLK_DRIVING_CELL) $::env(SYNTH_DRIVING_CELL)
}
if { ![info exists ::env(SYNTH_CLK_DRIVING_CELL_PIN)] } {
set ::env(SYNTH_CLK_DRIVING_CELL_PIN) $::env(SYNTH_DRIVING_CELL_PIN)
}
# Clock non-idealities
set_propagated_clock [all_clocks]
set_clock_uncertainty 0.15 [get_clocks {clk}]
puts "\[INFO\]: Setting clock uncertainty to: 0.15"
set_clock_transition $::env(SYNTH_CLOCK_TRANSITION) [get_clocks {clk}]
puts "\[INFO\]: Setting clock transition to: $::env(SYNTH_CLOCK_TRANSITION)"
# Maximum transition time for the design nets
set_max_transition 0.75 [current_design]
puts "\[INFO\]: Setting maximum transition to: 0.75"
# Maximum fanout
set_max_fanout 16 [current_design]
puts "\[INFO\]: Setting maximum fanout to: 16"
# Timing paths delays derate
set_timing_derate -early [expr {1-0.07}]
set_timing_derate -late [expr {1+0.07}]
puts "\[INFO\]: Setting timing derate to: [expr {0.07 * 100}] %"
# Reset input delay
set_input_delay [expr $::env(CLOCK_PERIOD) * 0.5] -clock [get_clocks {clk}] [get_ports {wb_rst_i}]
# Multicycle paths
set_multicycle_path -setup 2 -through [get_ports {wbs_ack_o}]
set_multicycle_path -hold 1 -through [get_ports {wbs_ack_o}]
set_multicycle_path -setup 2 -through [get_ports {wbs_cyc_i}]
set_multicycle_path -hold 1 -through [get_ports {wbs_cyc_i}]
set_multicycle_path -setup 2 -through [get_ports {wbs_stb_i}]
set_multicycle_path -hold 1 -through [get_ports {wbs_stb_i}]
#------------------------------------------#
# Retrieved Constraints
#------------------------------------------#
# Clock source latency
set usr_clk_max_latency 4.57
set usr_clk_min_latency 4.11
set clk_max_latency 5.57
set clk_min_latency 4.65
set_clock_latency -source -max $clk_max_latency [get_clocks {clk}]
set_clock_latency -source -min $clk_min_latency [get_clocks {clk}]
puts "\[INFO\]: Setting clock latency range: $clk_min_latency : $clk_max_latency"
# Clock input Transition
set usr_clk_tran 0.13
set clk_tran 0.61
set_input_transition $clk_tran [get_ports $clk_input]
puts "\[INFO\]: Setting clock transition: $clk_tran"
# Input delays
set_input_delay -max 1.87 -clock [get_clocks {clk}] [get_ports {la_data_in[*]}]
set_input_delay -max 1.89 -clock [get_clocks {clk}] [get_ports {la_oenb[*]}]
set_input_delay -max 3.17 -clock [get_clocks {clk}] [get_ports {wbs_sel_i[*]}]
set_input_delay -max 3.74 -clock [get_clocks {clk}] [get_ports {wbs_we_i}]
set_input_delay -max 3.89 -clock [get_clocks {clk}] [get_ports {wbs_adr_i[*]}]
set_input_delay -max 4.13 -clock [get_clocks {clk}] [get_ports {wbs_stb_i}]
set_input_delay -max 4.61 -clock [get_clocks {clk}] [get_ports {wbs_dat_i[*]}]
set_input_delay -max 4.74 -clock [get_clocks {clk}] [get_ports {wbs_cyc_i}]
set_input_delay -min 0.18 -clock [get_clocks {clk}] [get_ports {la_data_in[*]}]
set_input_delay -min 0.3 -clock [get_clocks {clk}] [get_ports {la_oenb[*]}]
set_input_delay -min 0.79 -clock [get_clocks {clk}] [get_ports {wbs_adr_i[*]}]
# wbs_dat_i minimum input delay was decreased here to fix hold violations
set_input_delay -min 0.80 -clock [get_clocks {clk}] [get_ports {wbs_dat_i[*]}]
set_input_delay -min 1.19 -clock [get_clocks {clk}] [get_ports {wbs_sel_i[*]}]
set_input_delay -min 1.65 -clock [get_clocks {clk}] [get_ports {wbs_we_i}]
set_input_delay -min 1.69 -clock [get_clocks {clk}] [get_ports {wbs_cyc_i}]
set_input_delay -min 1.86 -clock [get_clocks {clk}] [get_ports {wbs_stb_i}]
if { $::env(IO_SYNC) } {
set in_ext_delay 4
puts "\[INFO\]: Setting input ports external delay to: $in_ext_delay"
set_input_delay -max [expr $in_ext_delay + 4.55] -clock [get_clocks {clk}] [get_ports {io_in[*]}]
set_input_delay -min [expr $in_ext_delay + 1.26] -clock [get_clocks {clk}] [get_ports {io_in[*]}]
}
# Input Transition
set_input_transition -max 0.14 [get_ports {wbs_we_i}]
set_input_transition -max 0.15 [get_ports {wbs_stb_i}]
set_input_transition -max 0.17 [get_ports {wbs_cyc_i}]
set_input_transition -max 0.18 [get_ports {wbs_sel_i[*]}]
set_input_transition -max 0.38 [get_ports {io_in[*]}]
set_input_transition -max 0.84 [get_ports {wbs_dat_i[*]}]
set_input_transition -max 0.86 [get_ports {la_data_in[*]}]
set_input_transition -max 0.92 [get_ports {wbs_adr_i[*]}]
set_input_transition -max 0.97 [get_ports {la_oenb[*]}]
set_input_transition -min 0.05 [get_ports {io_in[*]}]
set_input_transition -min 0.06 [get_ports {la_oenb[*]}]
set_input_transition -min 0.07 [get_ports {la_data_in[*]}]
set_input_transition -min 0.07 [get_ports {wbs_adr_i[*]}]
set_input_transition -min 0.07 [get_ports {wbs_dat_i[*]}]
set_input_transition -min 0.09 [get_ports {wbs_cyc_i}]
set_input_transition -min 0.09 [get_ports {wbs_sel_i[*]}]
set_input_transition -min 0.09 [get_ports {wbs_we_i}]
set_input_transition -min 0.15 [get_ports {wbs_stb_i}]
# Output delays
set_output_delay -max 0.7 -clock [get_clocks {clk}] [get_ports {user_irq[*]}]
set_output_delay -max 1.0 -clock [get_clocks {clk}] [get_ports {la_data_out[*]}]
set_output_delay -max 3.62 -clock [get_clocks {clk}] [get_ports {wbs_dat_o[*]}]
set_output_delay -max 8.41 -clock [get_clocks {clk}] [get_ports {wbs_ack_o}]
set_output_delay -min 0 -clock [get_clocks {clk}] [get_ports {la_data_out[*]}]
set_output_delay -min 0 -clock [get_clocks {clk}] [get_ports {user_irq[*]}]
set_output_delay -min 1.13 -clock [get_clocks {clk}] [get_ports {wbs_dat_o[*]}]
set_output_delay -min 1.37 -clock [get_clocks {clk}] [get_ports {wbs_ack_o}]
if { $::env(IO_SYNC) } {
set out_ext_delay 4
puts "\[INFO\]: Setting output ports external delay to: $out_ext_delay"
set_output_delay -max [expr $out_ext_delay + 9.12] -clock [get_clocks {clk}] [get_ports {io_out[*]}]
set_output_delay -max [expr $out_ext_delay + 9.32] -clock [get_clocks {clk}] [get_ports {io_oeb[*]}]
set_output_delay -min [expr $out_ext_delay + 2.34] -clock [get_clocks {clk}] [get_ports {io_oeb[*]}]
set_output_delay -min [expr $out_ext_delay + 3.9] -clock [get_clocks {clk}] [get_ports {io_out[*]}]
}
# Output loads
set_load 0.19 [all_outputs]
4.2 Configuration (Top-Level)¶
The key change from Strategy 1 is that all disabled flags are now set to true, and
SYNTH_ELABORATE_ONLY is set to false:
config.json
{
"QUIT_ON_SYNTH_CHECKS": false,
"//": "Design files",
"VERILOG_FILES": [
"dir::../../verilog/rtl/defines.v",
"dir::../../verilog/rtl/user_project_wrapper.v"
],
"SYNTH_ELABORATE_ONLY": false,
"RUN_POST_GPL_DESIGN_REPAIR": true,
"RUN_POST_CTS_RESIZER_TIMING": true,
"DESIGN_REPAIR_BUFFER_INPUT_PORTS": true,
"PDN_ENABLE_RAILS": true,
"RUN_ANTENNA_REPAIR": true,
"RUN_FILL_INSERTION": true,
"RUN_TAP_ENDCAP_INSERTION": true,
"RUN_CTS": true,
"RUN_IRDROP_REPORT": false,
"//": "Macros configurations",
"MACROS": {
"aes_wb_wrapper": {
"gds": [
"dir::../../gds/aes_wb_wrapper.gds"
],
"lef": [
"dir::../../lef/aes_wb_wrapper.lef"
],
"instances": {
"mprj": {
"location": [100, 100],
"orientation": "N"
}
},
"nl": [
"dir::../../verilog/gl/aes_wb_wrapper.v"
],
"spef": {
"min_*": [
"dir::../../spef/multicorner/aes_wb_wrapper.min.spef"
],
"nom_*": [
"dir::../../spef/multicorner/aes_wb_wrapper.nom.spef"
],
"max_*": [
"dir::../../spef/multicorner/aes_wb_wrapper.max.spef"
]
},
"lib": {
"*": "dir::../../lib/aes_wb_wrapper.lib"
}
}
},
"PDN_MACRO_CONNECTIONS": ["mprj vccd2 vssd2 VPWR VGND"],
"//": "PDN configurations",
"PDN_VOFFSET": 5,
"PDN_HOFFSET": 5,
"PDN_VWIDTH": 3.1,
"PDN_HWIDTH": 3.1,
"PDN_VSPACING": 15.5,
"PDN_HSPACING": 15.5,
"PDN_VPITCH": 180,
"PDN_HPITCH": 180,
"QUIT_ON_PDN_VIOLATIONS": false,
"//": "Magic variables",
"MAGIC_DRC_USE_GDS": true,
"MAX_TRANSITION_CONSTRAINT": 1.5,
"//": "Fixed configurations for caravel. You should NOT edit this section",
"DESIGN_NAME": "user_project_wrapper",
"FP_SIZING": "absolute",
"DIE_AREA": [0, 0, 2920, 3520],
"FP_DEF_TEMPLATE": "dir::fixed_dont_change/user_project_wrapper.def",
"VDD_NETS": [
"vccd1",
"vccd2",
"vdda1",
"vdda2"
],
"GND_NETS": [
"vssd1",
"vssd2",
"vssa1",
"vssa2"
],
"PDN_CORE_RING": 1,
"PDN_CORE_RING_VWIDTH": 3.1,
"PDN_CORE_RING_HWIDTH": 3.1,
"PDN_CORE_RING_VOFFSET": 12.45,
"PDN_CORE_RING_HOFFSET": 12.45,
"PDN_CORE_RING_VSPACING": 1.7,
"PDN_CORE_RING_HSPACING": 1.7,
"CLOCK_PORT": "wb_clk_i",
"PNR_SDC_FILE": "dir::pnr.sdc",
"SIGNOFF_SDC_FILE": "dir::signoff.sdc",
"MAGIC_DEF_LABELS": 0,
"CLOCK_PERIOD": 25,
"MAGIC_ZEROIZE_ORIGIN": 0
}
The table below summarises the key behavioural difference between the two strategies:
Parameter |
Strategy 1 (Macro-First) |
Strategy 2 (Top-Level) |
Reason |
|---|---|---|---|
|
|
|
Strategy 2 synthesises top-level glue logic. |
|
|
|
A new clock tree is built for the top-level standard cells. |
|
|
|
The resizer fixes violations on the new top-level cells. |
|
|
|
Metal 1 rails are needed for the top-level standard cell rows. |
|
|
|
Tap cells bias the N-well of the new standard cell rows. |
|
|
|
Filler cells close gaps in the standard cell rows. |
Macro location |
|
|
Margin required for top-level cells and routing. |
4.3 Running the Flow (Top-Level)¶
[nix-shell:~]$ librelane \
~/Silicon-Sprint-AUC/openlane/user_project_wrapper/config.json \
--run-tag top_level
Note
If the flow crashes during the parasitic extraction (OpenROAD.RCX) step, add the following line to config.json and re-run. This forces single-threaded STA — slower but reliable when multi-thread STA causes memory or scheduling failures:
“STA_THREADS”: 1
4.4 Post-PnR STA Results (Top-Level)¶
Location: runs/top_level/XX-openroad-stapostpnr/summary.rpt
┏━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━┳━━━━━━━━━━┳━━━━━━━━━━┳━━━━━━━━━━┳━━━━━━━━━━━┳━━━━━━━━━━┳━━━━━━━━━━━┳━━━━━━━━━━┳━━━━━━━━━━━┳━━━━━━━━━━┳━━━━━━━━━━━┳━━━━━━━━━━┓
┃ ┃ Hold ┃ Reg to ┃ ┃ ┃ of which ┃ Setup ┃ ┃ ┃ ┃ of which ┃ ┃ ┃
┃ ┃ Worst ┃ Reg ┃ ┃ Hold Vio ┃ reg to ┃ Worst ┃ Reg to ┃ Setup ┃ Setup Vio ┃ reg to ┃ Max Cap ┃ Max Slew ┃
┃ Corner/Group ┃ Slack ┃ Paths ┃ Hold TNS ┃ Count ┃ reg ┃ Slack ┃ Reg Paths ┃ TNS ┃ Count ┃ reg ┃ Violatio… ┃ Violati… ┃
┡━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━╇━━━━━━━━━━╇━━━━━━━━━━╇━━━━━━━━━━╇━━━━━━━━━━━╇━━━━━━━━━━╇━━━━━━━━━━━╇━━━━━━━━━━╇━━━━━━━━━━━╇━━━━━━━━━━╇━━━━━━━━━━━╇━━━━━━━━━━┩
│ Overall │ 0.0047 │ 0.0047 │ 0.0000 │ 0 │ 0 │ 2.1041 │ 2.1041 │ 0.0000 │ 0 │ 0 │ 1 │ 2 │
│ nom_tt_025C_1v80 │ 0.1483 │ 0.1483 │ 0.0000 │ 0 │ 0 │ 7.9981 │ 13.3840 │ 0.0000 │ 0 │ 0 │ 0 │ 0 │
│ nom_ss_100C_1v60 │ 0.5562 │ 0.5562 │ 0.0000 │ 0 │ 0 │ 2.5763 │ 2.5763 │ 0.0000 │ 0 │ 0 │ 0 │ 0 │
│ nom_ff_n40C_1v95 │ 0.0053 │ 0.0053 │ 0.0000 │ 0 │ 0 │ 9.1132 │ 17.4716 │ 0.0000 │ 0 │ 0 │ 0 │ 0 │
│ min_tt_025C_1v80 │ 0.1474 │ 0.1474 │ 0.0000 │ 0 │ 0 │ 8.1437 │ 13.6547 │ 0.0000 │ 0 │ 0 │ 0 │ 0 │
│ min_ss_100C_1v60 │ 0.5545 │ 0.5545 │ 0.0000 │ 0 │ 0 │ 3.0678 │ 3.0678 │ 0.0000 │ 0 │ 0 │ 0 │ 0 │
│ min_ff_n40C_1v95 │ 0.0047 │ 0.0047 │ 0.0000 │ 0 │ 0 │ 9.2076 │ 17.7111 │ 0.0000 │ 0 │ 0 │ 0 │ 0 │
│ max_tt_025C_1v80 │ 0.1491 │ 0.1491 │ 0.0000 │ 0 │ 0 │ 7.8819 │ 13.1149 │ 0.0000 │ 0 │ 0 │ 0 │ 0 │
│ max_ss_100C_1v60 │ 0.5582 │ 0.5582 │ 0.0000 │ 0 │ 0 │ 2.1041 │ 2.1041 │ 0.0000 │ 0 │ 0 │ 1 │ 2 │
│ max_ff_n40C_1v95 │ 0.0059 │ 0.0059 │ 0.0000 │ 0 │ 0 │ 9.0334 │ 17.2358 │ 0.0000 │ 0 │ 0 │ 0 │ 0 │
└──────────────────────┴──────────┴──────────┴──────────┴──────────┴───────────┴──────────┴───────────┴──────────┴───────────┴──────────┴───────────┴──────────┘
To open the final layout:
[nix-shell:~]$ librelane \
--last-run \
--flow openinklayout \
~/Silicon-Sprint-AUC/openlane/user_project_wrapper/config.json
5. Strategy 3 — Full-Wrapper Flattening¶
In this strategy, the user_project_wrapper is hardened with all AES RTL included
directly — no pre-hardened macro. Yosys synthesises the entire design as one flat
netlist and the router covers the full ≈ 3 mm × 3.6 mm area. This produces the best
possible timing but requires the most PnR time and iteration.
5.1 RTL Modification¶
Because this strategy performs full synthesis, Yosys flags undriven top-level output
ports as errors. To prevent approximately 207 synthesis errors, add the following
tie-off assignments to user_project_wrapper.v:
// Required for Full-Wrapper Flattening — tie off unused top-level outputs
assign io_out = {`MPRJ_IO_PADS{1'b0}};
assign io_oeb = {`MPRJ_IO_PADS{1'b0}};
assign la_data_out = 128'b0;
assign user_irq = 3'b0;
Warning
While these tie-offs are mandatory for Full-Wrapper Flattening prevent Yosys synthesis errors ,they must be removed if you switch back to the Macro-First Hardening strategy.
In Macro-First mode, the tool expects the wrapper to be a pure elaboration frame for the pre-hardened macro. If these assign statements are present, Yosys preserves them in the synthesized gate-level netlist (.nl.v). This triggers the Netlist Assign Statement Checker (Stage 9), which is designed to raise a StepError and terminate the flow because assign statements are known to cause bugs in physical design (PnR) tools
5.2 Configuration (Flattening)¶
The MACROS section is removed entirely. All AES RTL source files are added directly
to VERILOG_FILES. All optimisation flags are true (which is the LibreLane Classic
flow default — they do not need to be explicitly written in config.json).
{
"VERILOG_FILES": [
"dir::../../../secworks_aes/src/rtl/*.v",
"dir::../../verilog/rtl/aes_wb_wrapper.v",
"dir::../../verilog/rtl/defines.v",
"dir::../../verilog/rtl/user_project_wrapper.v"
],
"SYNTH_STRATEGY": "DELAY 4",
"DEFAULT_CORNER": "max_tt_025C_1v80",
"DESIGN_REPAIR_MAX_SLEW_PCT": 30,
"DESIGN_REPAIR_MAX_CAP_PCT": 30,
"GRT_ANTENNA_REPAIR_ITERS": 10,
"GRT_ANTENNA_REPAIR_MARGIN": 15,
"VSRC_LOC_FILES": {
"vccd1": "dir::vsrc/upw_vccd1_vsrc.loc",
"vssd1": "dir::vsrc/upw_vssd1_vsrc.loc"
},
"PDN_VOFFSET": 5,
"PDN_HOFFSET": 5,
"PDN_VWIDTH": 3.1,
"PDN_HWIDTH": 3.1,
"PDN_VSPACING": 15.5,
"PDN_HSPACING": 15.5,
"PDN_VPITCH": 180,
"PDN_HPITCH": 180,
"ERROR_ON_PDN_VIOLATIONS": false,
"//": "Fixed configurations for Caravel — do NOT edit below this line",
"DESIGN_NAME": "user_project_wrapper",
"FP_SIZING": "absolute",
"DIE_AREA": [0, 0, 2920, 3520],
"FP_DEF_TEMPLATE": "dir::fixed_dont_change/user_project_wrapper.def",
"VDD_NETS": ["vccd1", "vccd2", "vdda1", "vdda2"],
"GND_NETS": ["vssd1", "vssd2", "vssa1", "vssa2"],
"PDN_CORE_RING": 1,
"PDN_CORE_RING_VWIDTH": 3.1,
"PDN_CORE_RING_HWIDTH": 3.1,
"PDN_CORE_RING_VOFFSET": 12.45,
"PDN_CORE_RING_HOFFSET": 12.45,
"PDN_CORE_RING_VSPACING": 1.7,
"PDN_CORE_RING_HSPACING": 1.7,
"CLOCK_PORT": "wb_clk_i",
"PNR_SDC_FILE": "dir::pnr.sdc",
"SIGNOFF_SDC_FILE": "dir::signoff.sdc",
"MAGIC_DEF_LABELS": 0,
"CLOCK_PERIOD": 25,
"MAGIC_ZEROIZE_ORIGIN": 0
}
Note
The VSRC_LOC_FILES parameter specifies voltage source locations for IR drop analysis.
This is especially important in the flattening strategy because the full design spans
the entire wrapper area and IR drop hotspots are more likely to occur at points far
from the power ring. The .loc files define where the PDN voltage sources are
injected for the OpenROAD.IRDropReport simulation.
4.3 Running the Flow (Top-Level)¶
[nix-shell:~]$ librelane \
~/Silicon-Sprint-AUC/openlane/user_project_wrapper/config.json \
--run-tag flatten
Post-PnR STA (OpenROAD.STAPostPNR)¶
Location: runs/project_wrapper/XX-openroad-stapostpnr/summary.rpt
┏━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━━━━━━━━┳━━━━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━━━━━━━━┓
┃ ┃ ┃ ┃ ┃ ┃ ┃ Setup ┃ ┃ ┃ ┃ ┃ ┃ ┃
┃ ┃ Hold Worst ┃ Reg to Reg ┃ ┃ Hold Vio ┃ of which ┃ Worst ┃ Reg to Reg ┃ ┃ Setup Vio ┃ of which ┃ Max Cap ┃ Max Slew ┃
┃ Corner/Group ┃ Slack ┃ Paths ┃ Hold TNS ┃ Count ┃ reg to reg ┃ Slack ┃ Paths ┃ Setup TNS ┃ Count ┃ reg to reg ┃ Violations ┃ Violations ┃
┡━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━━━━━━━━╇━━━━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━━━━━━━━┩
│ Overall │ 0.0332 │ 0.0332 │ 0.0000 │ 0 │ 0 │ 2.5400 │ 2.5400 │ 0.0000 │ 0 │ 0 │ 0 │ 0 │
│ nom_tt_025C_1v80 │ 0.1949 │ 0.1949 │ 0.0000 │ 0 │ 0 │ 8.6580 │ 13.2886 │ 0.0000 │ 0 │ 0 │ 0 │ 0 │
│ nom_ss_100C_1v60 │ 0.6139 │ 0.7559 │ 0.0000 │ 0 │ 0 │ 3.0788 │ 3.0788 │ 0.0000 │ 0 │ 0 │ 0 │ 0 │
│ nom_ff_n40C_1v95 │ 0.0351 │ 0.0351 │ 0.0000 │ 0 │ 0 │ 9.5322 │ 17.1408 │ 0.0000 │ 0 │ 0 │ 0 │ 0 │
│ min_tt_025C_1v80 │ 0.1925 │ 0.1925 │ 0.0000 │ 0 │ 0 │ 8.7362 │ 13.8739 │ 0.0000 │ 0 │ 0 │ 0 │ 0 │
│ min_ss_100C_1v60 │ 0.6547 │ 0.6547 │ 0.0000 │ 0 │ 0 │ 3.6504 │ 3.6504 │ 0.0000 │ 0 │ 0 │ 0 │ 0 │
│ min_ff_n40C_1v95 │ 0.0332 │ 0.0332 │ 0.0000 │ 0 │ 0 │ 9.5891 │ 17.5575 │ 0.0000 │ 0 │ 0 │ 0 │ 0 │
│ max_tt_025C_1v80 │ 0.1975 │ 0.1975 │ 0.0000 │ 0 │ 0 │ 8.5800 │ 12.6022 │ 0.0000 │ 0 │ 0 │ 0 │ 0 │
│ max_ss_100C_1v60 │ 0.4939 │ 0.7547 │ 0.0000 │ 0 │ 0 │ 2.5400 │ 2.5400 │ 0.0000 │ 0 │ 0 │ 0 │ 0 │
│ max_ff_n40C_1v95 │ 0.0371 │ 0.0371 │ 0.0000 │ 0 │ 0 │ 9.4746 │ 16.6085 │ 0.0000 │ 0 │ 0 │ 0 │ 0 │
└──────────────────────┴────────────┴────────────┴──────────┴────────────┴────────────┴────────────┴─────────────┴───────────┴────────────┴─────────────┴────────────┴─────────────┘
- PDN¶
Power Distribution Network. The network of metal conductors delivering VDD and GND to every cell in the chip.
- DRC¶
Design Rule Check. Verification that the layout conforms to the foundry’s manufacturing constraints.
- LVS¶
Layout vs. Schematic. Verification that the physical layout is electrically equivalent to the design netlist.
- LEF¶
Library Exchange Format. A file describing the physical interface of a macro — boundary, pin locations, and blockages.
- SPEF¶
Standard Parasitic Exchange Format. A text-based map of the resistance and capacitance of every net.
- STA¶
Static Timing Analysis. Exhaustive path-by-path timing verification against declared constraints.
- GDSII¶
Graphic Database System II. The standard binary layout format delivered to the foundry for fabrication.
- SDC¶
Synopsys Design Constraints. Tcl-based timing and clocking constraints.
- WNS¶
Worst Negative Slack. The largest magnitude of negative slack across all failing timing paths.