From 81cffda1cb985d160052b36d41a27cf80b4a024d Mon Sep 17 00:00:00 2001 From: cah Date: Wed, 25 Feb 2026 20:08:39 -0700 Subject: [PATCH] feat: add OpenLane hardening config for LDPC decoder (50 MHz) - config.json: 20ns clock period, AREA 2 synth strategy, 2800x1760um die - pin_order.cfg: Wishbone pins on south, outputs on north - base_ldpc.sdc: Caravel-calibrated timing constraints adapted for LDPC ports - Updated wrapper config to reference ldpc_decoder_top macro Co-Authored-By: Claude Opus 4.6 --- openlane/ldpc_decoder_top/base_ldpc.sdc | 116 ++++++++++++++++++++++ openlane/ldpc_decoder_top/config.json | 69 +++++++++++++ openlane/ldpc_decoder_top/pin_order.cfg | 16 +++ openlane/user_project_wrapper/config.json | 16 +-- 4 files changed, 209 insertions(+), 8 deletions(-) create mode 100644 openlane/ldpc_decoder_top/base_ldpc.sdc create mode 100644 openlane/ldpc_decoder_top/config.json create mode 100644 openlane/ldpc_decoder_top/pin_order.cfg diff --git a/openlane/ldpc_decoder_top/base_ldpc.sdc b/openlane/ldpc_decoder_top/base_ldpc.sdc new file mode 100644 index 0000000..c3ae852 --- /dev/null +++ b/openlane/ldpc_decoder_top/base_ldpc.sdc @@ -0,0 +1,116 @@ +# SDC constraints for ldpc_decoder_top +# Adapted from Caravel user_proj_example SDC +# Target: 50 MHz (20 ns period) + +### Note: +# - input clock transition and latency are set for clk port. +# - IO ports are assumed to be asynchronous (IO_SYNC=0). + +#------------------------------------------# +# 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 $::env(MAX_TRANSITION_CONSTRAINT) [current_design] +puts "\[INFO\]: Setting maximum transition to: $::env(MAX_TRANSITION_CONSTRAINT)" + +# 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 {rst_n}] + +# Multicycle paths for Wishbone handshake +set_multicycle_path -setup 2 -through [get_ports {wb_ack_o}] +set_multicycle_path -hold 1 -through [get_ports {wb_ack_o}] +set_multicycle_path -setup 2 -through [get_ports {wb_cyc_i}] +set_multicycle_path -hold 1 -through [get_ports {wb_cyc_i}] +set_multicycle_path -setup 2 -through [get_ports {wb_stb_i}] +set_multicycle_path -hold 1 -through [get_ports {wb_stb_i}] + +#------------------------------------------# +# Retrieved Constraints (from Caravel) +#------------------------------------------# + +# Clock source latency +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 clk_tran 0.61 +set_input_transition $clk_tran [get_ports $clk_input] +puts "\[INFO\]: Setting clock transition: $clk_tran" + +# Input delays (scaled from Caravel characterization) +set_input_delay -max 3.17 -clock [get_clocks {clk}] [get_ports {wb_sel_i[*]}] +set_input_delay -max 3.74 -clock [get_clocks {clk}] [get_ports {wb_we_i}] +set_input_delay -max 3.89 -clock [get_clocks {clk}] [get_ports {wb_adr_i[*]}] +set_input_delay -max 4.13 -clock [get_clocks {clk}] [get_ports {wb_stb_i}] +set_input_delay -max 4.61 -clock [get_clocks {clk}] [get_ports {wb_dat_i[*]}] +set_input_delay -max 4.74 -clock [get_clocks {clk}] [get_ports {wb_cyc_i}] +set_input_delay -min 0.79 -clock [get_clocks {clk}] [get_ports {wb_adr_i[*]}] +set_input_delay -min 1.04 -clock [get_clocks {clk}] [get_ports {wb_dat_i[*]}] +set_input_delay -min 1.19 -clock [get_clocks {clk}] [get_ports {wb_sel_i[*]}] +set_input_delay -min 1.65 -clock [get_clocks {clk}] [get_ports {wb_we_i}] +set_input_delay -min 1.69 -clock [get_clocks {clk}] [get_ports {wb_cyc_i}] +set_input_delay -min 1.86 -clock [get_clocks {clk}] [get_ports {wb_stb_i}] + +# Input Transition +set_input_transition -max 0.14 [get_ports {wb_we_i}] +set_input_transition -max 0.15 [get_ports {wb_stb_i}] +set_input_transition -max 0.17 [get_ports {wb_cyc_i}] +set_input_transition -max 0.18 [get_ports {wb_sel_i[*]}] +set_input_transition -max 0.84 [get_ports {wb_dat_i[*]}] +set_input_transition -max 0.92 [get_ports {wb_adr_i[*]}] +set_input_transition -min 0.07 [get_ports {wb_adr_i[*]}] +set_input_transition -min 0.07 [get_ports {wb_dat_i[*]}] +set_input_transition -min 0.09 [get_ports {wb_cyc_i}] +set_input_transition -min 0.09 [get_ports {wb_sel_i[*]}] +set_input_transition -min 0.09 [get_ports {wb_we_i}] +set_input_transition -min 0.15 [get_ports {wb_stb_i}] + +# Output delays +set_output_delay -max 0.7 -clock [get_clocks {clk}] [get_ports {irq_o}] +set_output_delay -max 3.62 -clock [get_clocks {clk}] [get_ports {wb_dat_o[*]}] +set_output_delay -max 8.41 -clock [get_clocks {clk}] [get_ports {wb_ack_o}] +set_output_delay -min 0 -clock [get_clocks {clk}] [get_ports {irq_o}] +set_output_delay -min 1.13 -clock [get_clocks {clk}] [get_ports {wb_dat_o[*]}] +set_output_delay -min 1.37 -clock [get_clocks {clk}] [get_ports {wb_ack_o}] + +# Output loads +set_load 0.19 [all_outputs] diff --git a/openlane/ldpc_decoder_top/config.json b/openlane/ldpc_decoder_top/config.json new file mode 100644 index 0000000..3a269c0 --- /dev/null +++ b/openlane/ldpc_decoder_top/config.json @@ -0,0 +1,69 @@ +{ + "DESIGN_NAME": "ldpc_decoder_top", + "FP_PDN_MULTILAYER": false, + "VERILOG_FILES": [ + "dir::../../verilog/rtl/defines.v", + "dir::../../verilog/rtl/ldpc_decoder_top.sv", + "dir::../../verilog/rtl/ldpc_decoder_core.sv", + "dir::../../verilog/rtl/wishbone_interface.sv" + ], + "CLOCK_PERIOD": 20, + "CLOCK_PORT": "clk", + "CLOCK_NET": "u_core.clk", + "FP_SIZING": "absolute", + "DIE_AREA": [ + 0, + 0, + 2800, + 1760 + ], + "FP_PIN_ORDER_CFG": "dir::pin_order.cfg", + "MAX_TRANSITION_CONSTRAINT": 1.5, + "MAX_FANOUT_CONSTRAINT": 16, + "PL_RESIZER_SETUP_SLACK_MARGIN": 0.4, + "GRT_RESIZER_SETUP_SLACK_MARGIN": 0.2, + "GRT_RESIZER_HOLD_SLACK_MARGIN": 0.2, + "PL_RESIZER_HOLD_SLACK_MARGIN": 0.4, + "CTS_CLK_MAX_WIRE_LENGTH": 500, + "MAGIC_DEF_LABELS": false, + "SYNTH_ABC_BUFFERING": false, + "RUN_HEURISTIC_DIODE_INSERTION": true, + "HEURISTIC_ANTENNA_THRESHOLD": 110, + "RUN_ANTENNA_REPAIR": true, + "RUN_POST_GRT_DESIGN_REPAIR": true, + "RUN_POST_GRT_RESIZER_TIMING": true, + "VDD_NETS": [ + "vccd1" + ], + "GND_NETS": [ + "vssd1" + ], + "FALLBACK_SDC_FILE": "dir::base_ldpc.sdc", + "MAGIC_DRC_USE_GDS": true, + "DPL_CELL_PADDING": 2, + "GPL_CELL_PADDING": 2, + "SYNTH_STRATEGY": "AREA 2", + "PL_TARGET_DENSITY_PCT": 40, + "pdk::sky130*": { + "RT_MAX_LAYER": "met4", + "scl::sky130_fd_sc_hd": { + "CLOCK_PERIOD": 20 + }, + "scl::sky130_fd_sc_hdll": { + "CLOCK_PERIOD": 10 + }, + "scl::sky130_fd_sc_hs": { + "CLOCK_PERIOD": 8 + }, + "scl::sky130_fd_sc_ls": { + "CLOCK_PERIOD": 10, + "SYNTH_MAX_FANOUT": 5 + }, + "scl::sky130_fd_sc_ms": { + "CLOCK_PERIOD": 10 + } + }, + "meta": { + "version": 2 + } +} diff --git a/openlane/ldpc_decoder_top/pin_order.cfg b/openlane/ldpc_decoder_top/pin_order.cfg new file mode 100644 index 0000000..84db782 --- /dev/null +++ b/openlane/ldpc_decoder_top/pin_order.cfg @@ -0,0 +1,16 @@ +#BUS_SORT + +#S +clk +rst_n +wb_cyc_i +wb_stb_i +wb_we_i +wb_sel_i\[.*\] +wb_adr_i\[.*\] +wb_dat_i\[.*\] + +#N +wb_dat_o\[.*\] +wb_ack_o +irq_o diff --git a/openlane/user_project_wrapper/config.json b/openlane/user_project_wrapper/config.json index 5b31901..e8dab54 100644 --- a/openlane/user_project_wrapper/config.json +++ b/openlane/user_project_wrapper/config.json @@ -21,12 +21,12 @@ "//": "Macros configurations", "MACROS": { - "user_proj_example": { + "ldpc_decoder_top": { "gds": [ - "dir::../../gds/user_proj_example.gds" + "dir::../../gds/ldpc_decoder_top.gds" ], "lef": [ - "dir::../../lef/user_proj_example.lef" + "dir::../../lef/ldpc_decoder_top.lef" ], "instances": { "mprj": { @@ -35,21 +35,21 @@ } }, "nl": [ - "dir::../../verilog/gl/user_proj_example.v" + "dir::../../verilog/gl/ldpc_decoder_top.v" ], "spef": { "min_*": [ - "dir::../../spef/multicorner/user_proj_example.min.spef" + "dir::../../spef/multicorner/ldpc_decoder_top.min.spef" ], "nom_*": [ - "dir::../../spef/multicorner/user_proj_example.nom.spef" + "dir::../../spef/multicorner/ldpc_decoder_top.nom.spef" ], "max_*": [ - "dir::../../spef/multicorner/user_proj_example.max.spef" + "dir::../../spef/multicorner/ldpc_decoder_top.max.spef" ] }, "lib": { - "*": "dir::../../lib/user_proj_example.lib" + "*": "dir::../../lib/ldpc_decoder_top.lib" } } },