Exploring Top-Level Integration Options for Caravel User Projects

This article provides an overview of the various top-level integration strategies for the Caravel user project.

There are three main options to do top level integration for the caravel_user_project, we will dive in each option to show when it should be used to help you choose which option is the most suitable for you.

Option 1 - Macro-First Hardening:

In this approach, the user macro(s) are hardened first and then integrated into the user project wrapper without any top-level standard cells. This method is ideal for smaller designs as it significantly reduces the time required for Placement and Routing (PnR) and signoff. It is also most commonly-used, and is the default configuration/flow included as part of the caravel_user_project template repository.

In this setup, a single hardened macro is placed in the user's project wrapper with no logic at the top level, as seen here:

The following variables should be set on the user’s project wrapper configuration to achieve this implementation:

"SYNTH_ELABORATE_ONLY": 1,                             
"PL_RESIZER_DESIGN_OPTIMIZATIONS": 0,
"PL_RESIZER_TIMING_OPTIMIZATIONS": 0,
"GRT_RESIZER_DESIGN_OPTIMIZATIONS": 0,
"GRT_RESIZER_TIMING_OPTIMIZATIONS": 0,
"PL_RESIZER_BUFFER_INPUT_PORTS": 0,
"FP_PDN_ENABLE_RAILS": 0,
"GRT_REPAIR_ANTENNAS": 0,
"RUN_FILL_INSERTION": 0,
"RUN_TAP_DECAP_INSERTION": 0,

The following projects can be used as examples for this option:

Option 2 - Full-Wrapper Flattening:

This method involves merging the user module/macro(s) with the user_project_wrapper, synthesizing to utilize the entire wrapper area instead of into a macro first. Though this approach requires more time and iterations for PnR and signoff, it enhances performance, making it suitable for designs that need the full wrapper area.

In this configuration, there are no separate macros, and all the logic is flattened into the top level, as seen here:

In this approach you modify openlane/user_project_wrapper/config.json to do the bulk of the synthesis, PnR, and timing closure work, and thus you need to:

  • remove some of the default sections that relate to "macro placement" (as you will not be using macros). Namely, delete:
    • FP_PDN_MACRO_HOOKS
      MACRO_PLACEMENT_CFG
      VERILOG_FILES_BLACKBOX
      EXTRA_LEFS
      EXTRA_GDS_FILES
      EXTRA_LIBS
      EXTRA_SPEFS
  • merge in much of the configuration found in what would otherwise be the (say) "user_proj_example" config.json file (e.g. VERILOG_FILES needs refer to your source files for synthesis, you might want "..._MARGIN" parameters added as well as antenna/diode options, and density/utilization parameters).

Set all of the following variables as shown (but retain all of the rest of the default user_project_wrapper config.json parameters)...

"RUN_LINTER":                       1,
"PL_RANDOM_GLB_PLACEMENT":          0,
"SYNTH_ELABORATE_ONLY":             0,
"PL_RESIZER_DESIGN_OPTIMIZATIONS":  1,
"PL_RESIZER_TIMING_OPTIMIZATIONS":  1,
"GLB_RESIZER_DESIGN_OPTIMIZATIONS": 1,
"GLB_RESIZER_TIMING_OPTIMIZATIONS": 1,
"PL_RESIZER_BUFFER_INPUT_PORTS":    1,
"FP_PDN_ENABLE_RAILS":              1,
"GRT_REPAIR_ANTENNAS":              1,
"RUN_FILL_INSERTION":               1,
"RUN_TAP_DECAP_INSERTION":          1,
"FP_PDN_CHECK_NODES":               1,
"RUN_CTS":                          1,
"RUN_CVC":                          1,

Here's an example of a full openlane/user_project_wrapper/config.json file using this 'Option 2' hardening:

{
    "DESIGN_NAME": "user_project_wrapper",

    "ROUTING_CORES":                    4,
    "KLAYOUT_XOR_THREADS":              4,
    "KLAYOUT_DRC_THREADS":              4,

    "CLOCK_PERIOD":                     25,
    "CLOCK_PORT":                       "wb_clk_i",
    "CLOCK_NET":                        "counter.clk",

    "PL_TARGET_DENSITY":                0.3,
    "FP_CORE_UTIL":                     45,
    "IO_SYNC":                          0,
    "MAX_TRANSITION_CONSTRAINT":        1.0,
    "MAX_FANOUT_CONSTRAINT":            16,
    "PL_RESIZER_SETUP_SLACK_MARGIN":    0.4,
    "GLB_RESIZER_SETUP_SLACK_MARGIN":   0.2,
    "GLB_RESIZER_HOLD_SLACK_MARGIN":    0.2,
    "PL_RESIZER_HOLD_SLACK_MARGIN":     0.4,
    "SYNTH_BUFFERING":                  0,
    "RUN_HEURISTIC_DIODE_INSERTION":    1,
    "HEURISTIC_ANTENNA_THRESHOLD":      110,

    "RUN_LINTER":                       1,
    "PL_RANDOM_GLB_PLACEMENT":          0,
    "SYNTH_ELABORATE_ONLY":             0,
    "PL_RESIZER_DESIGN_OPTIMIZATIONS":  1,
    "PL_RESIZER_TIMING_OPTIMIZATIONS":  1,
    "GLB_RESIZER_DESIGN_OPTIMIZATIONS": 1,
    "GLB_RESIZER_TIMING_OPTIMIZATIONS": 1,
    "PL_RESIZER_BUFFER_INPUT_PORTS":    1,
    "FP_PDN_ENABLE_RAILS":              1,
    "GRT_REPAIR_ANTENNAS":              1,
    "RUN_FILL_INSERTION":               1,
    "RUN_TAP_DECAP_INSERTION":          1,

    "FP_PDN_CHECK_NODES":               1,
    "RUN_CTS":                          1,
    "RUN_CVC":                          1,

    "VERILOG_FILES": [
        "dir::../../verilog/rtl/defines.v",
        "dir::../../verilog/rtl/user_proj_example.v",
        "dir::../../verilog/rtl/user_project_wrapper.v"
    ],
   
    "MAGIC_DEF_LABELS": 0,
    "BASE_SDC_FILE": "dir::base_user_project_wrapper.sdc",
    "QUIT_ON_SYNTH_CHECKS": 0,

    "FP_PDN_VPITCH": 180,
    "FP_PDN_HPITCH": 180,
    "FP_PDN_VOFFSET": 5,
    "FP_PDN_HOFFSET": 5,
    "MAGIC_ZEROIZE_ORIGIN": 0,
    "FP_SIZING": "absolute",
    "UNIT": 2.4,
    "FP_IO_VEXTEND": "expr::2 * $UNIT",
    "FP_IO_HEXTEND": "expr::2 * $UNIT",
    "FP_IO_VLENGTH": "expr::$UNIT",
    "FP_IO_HLENGTH": "expr::$UNIT",
    "FP_IO_VTHICKNESS_MULT": 4,
    "FP_IO_HTHICKNESS_MULT": 4,
    "FP_PDN_CORE_RING": 1,
    "FP_PDN_CORE_RING_VWIDTH": 3.1,
    "FP_PDN_CORE_RING_HWIDTH": 3.1,
    "FP_PDN_CORE_RING_VOFFSET": 12.45,
    "FP_PDN_CORE_RING_HOFFSET": 12.45,
    "FP_PDN_CORE_RING_VSPACING": 1.7,
    "FP_PDN_CORE_RING_HSPACING": 1.7,
    "FP_PDN_VWIDTH": 3.1,
    "FP_PDN_HWIDTH": 3.1,
    "FP_PDN_VSPACING": "expr::(5 * $FP_PDN_CORE_RING_VWIDTH)",
    "FP_PDN_HSPACING": "expr::(5 * $FP_PDN_CORE_RING_HWIDTH)",
    "VDD_NETS": [
        "vccd1",
        "vccd2",
        "vdda1",
        "vdda2"
    ],
    "GND_NETS": [
        "vssd1",
        "vssd2",
        "vssa1",
        "vssa2"
    ],
   
    "SYNTH_USE_PG_PINS_DEFINES": "USE_POWER_PINS",
    "pdk::sky130*": {
        "RT_MAX_LAYER": "met4",
        "DIE_AREA": "0 0 2920 3520",
        "FP_DEF_TEMPLATE": "dir::fixed_dont_change/user_project_wrapper.def",
    }
}

 

 

 

Option 3 - Top-Level Integration:

This strategy involves placing user macro(s) within the wrapper along with standard cells at the top level. It is typically chosen when buffering is needed at the top level, fitting scenarios where this approach is necessary.

In this setup, macros are hardened and placed at the top level, with additional logic present at this level as well, as shown here:

The following variables should be set on the user’s project wrapper configuration to achieve this implementation:

"SYNTH_ELABORATE_ONLY": 0,
"PL_RESIZER_DESIGN_OPTIMIZATIONS": 1,
"PL_RESIZER_TIMING_OPTIMIZATIONS": 1,
"GRT_RESIZER_DESIGN_OPTIMIZATIONS": 1,
"GRT_RESIZER_TIMING_OPTIMIZATIONS": 1,
"PL_RESIZER_BUFFER_INPUT_PORTS": 1,
"FP_PDN_ENABLE_RAILS": 1,
"GRT_REPAIR_ANTENNAS": 1,
"RUN_FILL_INSERTION": 1,
"RUN_TAP_DECAP_INSERTION": 1,

The following projects can be used as examples for this option: