Skip to content
Ch 08 / 14 Chapter 8: Managing Design Blocks
← Prev Next →

CHAPTER EIGHT

Managing Design Blocks: A Named Module Becomes a Thing You Can Hand Off

By the end of this chapter you will be able to read a logical hierarchy the way a floorplan engineer reads it; to draw a module boundary whose size comes from utilisation rather than from hope; to commit that module so it becomes a physical block in a library; to replace the block’s insides with a placement abstract the parent can plan against; to change a block’s shape without leaving its origin behind; and to push, pop and ECO the objects that must move with the handoff — including the cases where a legal command produces an empty, misleading success.

Why this chapter matters in a real project

Seven chapters have treated Nimbus-8 as one die with named regions. Those names were a plan. They were not a handoff. A module in a netlist is a folder. A block in a library is a parcel you can give to another engineer, freeze, abstract, budget, and shape. Until you commit, there is nothing to give.

The reason that matters is ownership. The CPU cluster will be implemented by one team, the two NPU cores by another, the ISP by a third. Each team needs a rectangle, a netlist of what lives inside it, a constraint file that belongs to it, and a stand-in the top-level engineer can place without loading nine million standard cells. This chapter is the moment those four things start to exist.

It is also the chapter where a legal result is most often a wasted afternoon. You can commit a module that has no boundary. The command returns a collection. The GUI shows an outline. The instance sits outside the core with every cell unplaced. Nothing failed. Everything is wrong. That pattern — a quiet success that is not the success you wanted — is the thread this chapter adds to the book.

Prerequisites

Chapter 1, for logical against physical hierarchy and the four-step sketch this chapter now performs. Chapter 3, for split_constraints and the constraint mapping file that placement abstracts require. Chapter 4, for the die, the core, utilisation, and the fact that read_verilog_outline does not partition — commit_block and expand_outline do. Chapter 5, for black-box abstracts, which are a different object: they stand in for missing logic, not for a committed block you already own. Chapter 2, for set_host_options, the run monitor, and how to ask a command what else it can do.

Chapter 7 is not required. An active die was a boundary plus an interface. A committed block is the same idea one level down, on one piece of silicon.

How to read the numbers and the notation in this chapter

This is the same table that opens every chapter, with the entries this chapter actually needs.

Table 8.1 How to read the numbers, the units and the symbols in this chapter
You will seeRead it asWhat you need to know
µmmicrons, or micrometresA length. Typed into every command in this chapter. 1 mm = 1,000 µm.
mm and mm2millimetres and square millimetresUsed when a floorplan should feel like an object. Every area is printed twice: mm2 for the human, µm2 for the tool. 1 mm2 = 1,000,000 µm2.
modulea logical hierarchy cellA name in the netlist. Not a block. Never interchangeable with “block” in this book.
module boundarya movable planning rectangleCreated by explore_logic_hierarchy. Still not a block. Its default size comes from the top-level floorplan utilisation.
blocka physical hierarchy designCreated by commit_block. Lives in a library. Has an origin, a boundary, keepouts, and (later) an abstract.
MIBmultiply instantiated blockOne reference, more than one cell. Commit the drawing once; every instance shares it. Expanded at first use in every chapter that needs it.
.outline / .designtwo representations of one blockcurrent_design tells you which you have. Abstracts need the design, not the outline.
is_shadowa Boolean attributeTrue on objects created by a push or a pop. Pair it with shadow_status.

Learning objectives

After this chapter you will be able to:

  1. Open the Hierarchy Browser and say, for any cell, its utilisation, pin count, hard-macro count and standard-cell count through the entire hierarchy beneath it.
  2. Create, nest, organise and remove module boundaries, and state the default size rule and the default 0.03 size threshold.
  3. Commit a module that has a boundary inside the core, and explain what happens if you commit a module that has none.
  4. Create a placement abstract for every committed child, after expanding an outline and pointing at the constraint mapping file.
  5. Change a block’s boundary and origin together, and explain why editing the outline in the GUI is not enough.
  6. Set push-down options, report them, check them, push, and query the resulting shadow netlist.
  7. Choose among write_split_net_eco, write_push_down_eco and write_spare_ports_eco by the structure you actually need to move.
  8. Name ten ways a legal command in this chapter can still be the wrong result, including one case where the symptom points at the wrong cause.
Hero plate for Chapter 8. Four numbered tiles across the top: Explore, Bound, Commit, Abstract, each with its command. Below, the Nimbus-8 die after commit, with nested core pairs inside the CPU cluster and gold dashed abstracts. Two side notes: what actually changes, and what this chapter is not.
Figure 8.1 The four steps this chapter performs, drawn on the Nimbus-8 die you already know. Solid rectangles are committed blocks. Nested green rectangles are child module boundaries kept with -nested. Gold dashed insets are placement abstracts. Timing abstracts, pin assignment, and block shaping are later chapters. Teaching purpose: one picture of the whole job before any command is typed.

The beginner’s mental model

A named floor is not yet a locked flat

Imagine an office building whose directory lists “CPU floor”, “NPU floor”, “ISP floor”. Those names tell a visitor where to walk. They do not give anyone a key, a lease, or a door that closes. Until Facilities converts a named floor into a locked flat, the furniture can still be shuffled into the corridor, and you cannot hand the floor to a tenant.

A logical module is the name on the directory. A module boundary is a piece of tape on the floor, sized from how densely you intend to pack. A committed block is the locked flat: it has a door (the boundary), a coordinate system (the origin), a keep-out at the walls, and a place in a library you can give to somebody else. A placement abstract is the fire-escape plan you pin in the lobby so the rest of the building can be designed without walking through every room.

Left, a building with four named floors whose keys are still at reception. An arrow labelled commit. Right, the same floors as locked flats, with a gold lock on each door. A yellow note lists where the analogy stops: utilisation is not gravity, a key is not a pin, two identical drawings are an MIB, and the tool does not pre-check furniture consistency.
Figure 8.2 The analogy, and the four places it stops being silicon. Two copies of the NPU floor are a multiply instantiated block: one drawing, two doors. Commit the drawing once. If the furniture inside the two copies was not placed the same way, the result is unpredictable, and the command does not warn you first. Teaching purpose: give the beginner a picture, then take the picture away before it lies.

The precise engineering model

The design database holds a logical hierarchy: cells that instantiate other cells, ending in standard cells and hard macros. None of that is a physical partition. A module boundary is a planning object attached to a logical cell. Its area is, by default, the cell’s content divided by the utilisation of the top-level floorplan. You can move it, nest it, group it, or throw it away. The netlist does not change.

commit_block turns a logical cell into a physical hierarchy block: a separate design, written to a library you name (or to the current design library). The GUI then shows outline views of those designs. What the new block looks like depends on whether the cell’s hierarchy type was module boundary or plain module. That fork is not a preference. It is the difference between a block that sits in the core with its cells placed, and a default square parked outside the core with its cells unplaced.

Sit with those three objects before you type. The name in the netlist does not know about millimetres. The tape on the floor does not live in a library. The locked flat does. If you treat the GUI rectangle as all three, you will commit the wrong thing and then wonder why the command “worked”.

A placement abstract is a third representation of the same block. It keeps the hard macros, remembers the original standard-cell count and area, and keeps enough standard cells and registers to represent the I/O interfaces. It does not keep the timing graph. That is a different abstract, taught in Chapter 14. Chapter 5’s black-box abstract is different again: it stands in for logic you do not have yet.

Three columns: logical module u_cpu_cluster as a dashed empty box; module boundary from explore_logic_hierarchy as a movable rectangle; committed block CPU_CLUSTER as a solid design in a library. A pink note: setting the boundary does not move the origin.
Figure 8.3 The same CPU, three database objects. The name, the tape on the floor, and the locked flat. Origin is a fourth fact, not implied by the outline you see. Teaching purpose: stop the reader treating one GUI rectangle as three different objects.

Do not confuse these

Table 8.2 Pairs that look alike and are not
ThisIs not thisWhy the mix-up is expensive
ModuleBlockA module is logical. A block is physical, after commit. Planning a module’s utilisation is not handing it off.
Module boundaryCommitted boundaryThe first is tape. The second is the block’s shape, with keepouts, origin and site arrays.
Outline viewDesign viewcurrent_design reporting .outline means the Verilog has not been expanded. Abstracts built from that are the wrong object.
Placement abstractTiming abstract-placement does not trace paths to ports. Timing levels (boundary, compact, full_interface) are Chapter 14.
Placement abstractBlack-box abstract (Ch. 5)A black box stands in for missing logic. A placement abstract stands in for a block you already committed.
Boundary attributeOrigin attributeReshaping the outline does not move the origin. Pins you assign later sit in the old coordinate system.
Push-down of routingPush-down of a cell treepush_down_objects cannot push an OR-gate tree. That is write_push_down_eco.
Electrically equivalent portFeedthrough portDefault push creates the first. A feedthrough needs create_pin_constraint ... -allow_feedthroughs true.
Shadow netlistFront-end netlistwrite_verilog includes shadows by default. A synthesis netlist often should not see them.
Until you commit, you are rearranging names. After you commit, you own a design in a library. After you abstract, the parent can plan without the furniture.

Concepts built from first principles

Part 1 — Explore the hierarchy you actually have

Open View > Hierarchy Browser. Each row is a cell. Sit with the columns before you invent a partition:

Expand and collapse. Rearrange columns. Click a block name to select it in the layout. This is a census, not a floorplan. Census first.

WHY?

You are about to invent physical partitions. The Hierarchy Browser is the cheapest way to see whether a candidate is a block or a folder of leftovers. Pin count predicts channel demand. Hard-macro count predicts whether the rectangle is a sea of standard cells or a parking lot of SRAMs. Standard-cell count through the entire hierarchy is the number that will later have to fit inside the keepouts.

The Hierarchy Browser is a census, not a floorplan. Census first.

Part 2 — Draw a module boundary before you commit

A module boundary is how you try a partition on for size without changing the netlist. The command is explore_logic_hierarchy. The option that creates the rectangles is -create_module_boundary.

Default size uses the utilisation of the top-level floorplan. Nimbus-8’s core is a square 3.20 mm on each side, so an area of 10.24 mm² = 10,240,000 µm², at utilisation 0.617. That 0.617 means: of every 1,000 µm² of core, 617 µm² is allowed to hold cells and macros, and 383 µm² is left empty so routes can breathe.

Walk one example slowly. A module whose contents occupy 1.96 mm² = 1,960,000 µm² receives a boundary of 1.96 ÷ 0.617 ≈ 3.18 mm² = 3,180,000 µm² unless you pass -utilization. A square of that area is about 1.78 mm = 1,780 µm on each side. You can still drag it into a rectangle that is not square. Valid utilisation values are between 0.01 and 10. A value less than zero is ignored and the design utilisation is used.

Three panels: a field of standard cells labelled content 1.96 square millimetres equals 1,960,000 square microns; utilisation 0.617 meaning 61.7 percent stuff and 38.3 percent empty; the resulting module boundary 3.18 square millimetres equals 3,180,000 square microns, a square about 1.78 millimetres on each side.
Figure 8.13 The tape is larger than the stuff on purpose. Utilisation 0.617 is not a grade. It is the fraction of the core you are allowed to fill. Teaching purpose: make the division visible before the reader types -create_module_boundary.

Without -cell, -create_module_boundary removes every existing module boundary and rebuilds them for all top-level logical hierarchies, ignoring any hierarchy smaller than the threshold. The default threshold is 0.03 — three per cent of total size — and is also stored in plan.explore.default_threshold. On Nimbus-8 that is 3 per cent of 10.24 mm² = 0.307 mm² = 307,000 µm². A wrapper smaller than that vanishes without a row in the log you will remember. If the threshold is negative the tool warns and uses zero. If you name cells with -cell, the threshold is ignored: you asked for those cells by name.

Four stacked coloured bands numbered 1 to 4: Explore with Hierarchy Browser; Create module boundaries with explore_logic_hierarchy; Commit with commit_block; Placement abstracts with create_abstract -placement. Each band states the gate.
Figure 8.4 The four-step flow, written as gates rather than as a wish list. Skipping a step is legal. It is rarely useful. Teaching purpose: show the sequence the rest of the chapter will perform, in order.
# Nimbus-8: tape on the floor for the four top-level candidates
icc2_shell> explore_logic_hierarchy -create_module_boundary \
    -cell {u_cpu_cluster u_npu_core_0 u_isp u_soc_periph}
# keep the parent, add a child inside it
icc2_shell> explore_logic_hierarchy -create_module_boundary -nested \
    -cell {u_cpu_cluster/u_core_pair_0 u_cpu_cluster/u_core_pair_1}

After creation the layout typically shows the original floorplan, I/Os above it, unplaced macros above the module boundaries, and the new rectangles themselves piled toward the lower right. Sit with that pile. You have not placed anything. You have taped names. Use the GUI assistants (View > Assistants > Hierarchy Exploration, or Floorplan Preparation > Hierarchy Exploration in the Task Assistant) and the context-menu item Create Module Boundary when you want to do the same thing with a mouse.

-organize moves those rectangles, the unplaced macros, and the unplaced pads back into three predefined regions, and resets the boundaries to rectangles after you have been dragging them. -remove deletes all module boundaries, or only those named with -cell. Macros from a removed boundary are placed to the upper-right of the design boundary.

By default nested boundaries are not allowed: you cannot create A and A/B in one breath. -nested keeps the parent and adds the child. -expand removes a parent boundary and builds children that pass the threshold. -collapse does the reverse. -place tries to pack boundaries into the floorplan; committed blocks and boundaries marked fixed stay put. Add -rectangular if you must forbid rectilinear shapes. Without it, -place may create non-rectangular boundaries to reduce overlap. -use_existing_placement is valid only with -place.

WHAT CHANGES IF…

You omit -cell on a real netlist? Every top-level hierarchy larger than three per cent of the design is taped. Tiny wrappers vanish without a row in the log you will remember. That is not a failure. It is the threshold doing its job, and it is the usual reason a candidate “never got a boundary”.

Left: just-created module boundaries overlapping in the lower right of the die, I/Os along the top, unplaced macros above. Right: after -organize, three stacked regions for I/O, rectangular module boundaries, and unplaced macros. A note on nested parent and child.
Figure 8.5 Creation dumps the tape in a pile. -organize sorts the pile into three regions so you can start placing. Nested children need -nested on purpose. Teaching purpose: show the GUI layout the command actually produces, not a tidy textbook floorplan.

Flat designs: virtual hierarchies and move bounds

Some netlists arrive already flattened. Names remain — u_cpu_cluster_alu_0 and so on — but there is no logical cell to attach a module boundary to. Set plan.place.hierarchy_by_name to true. The same command then extracts virtual hierarchies by name and creates move bounds. Existing module boundaries are removed first.

# flattened netlist: one bound per named virtual hierarchy
icc2_shell> set_app_options -list {plan.place.hierarchy_by_name true}
icc2_shell> explore_logic_hierarchy -create_module_boundary -cell {modA}
# or one bound that groups several modules
icc2_shell> explore_logic_hierarchy -name group1 -virtual_group {modA modB}
icc2_shell> get_attribute [get_bounds group1] -name flat_hier_names

-virtual_group must be paired with -name. The members need not share a logical parent. Report them with flat_hier_names on the bound. This is still not a commit. It is tape with a different backing.

A module boundary is a sized guess you can drag. It is not a block, and a missing tiny module is usually the 0.03 threshold, not a broken netlist.

Part 3 — Commit: the moment a module becomes a block

This is the lock. Until now you were taping names. Optional, but this is how a block is distributed to another engineer: create a library, save it, add it as a reference, then commit into it.

# optional distribution library, then commit the CPU reference
icc2_shell> create_lib cpu_cluster.dlib
icc2_shell> save_lib cpu_cluster.dlib
icc2_shell> set_ref_libs -add cpu_cluster.dlib
icc2_shell> commit_block -library cpu_cluster.dlib CPU_CLUSTER

Without -library, the new design is created in the current design library. -library must name the design library or one of the current reference libraries. -cells and the module-name argument are mutually exclusive: specify one. If you name a reference with -cells, the command commits that module and uses the named cell’s boundary for every MIB instance.

The shape depends on hierarchy type:

During commit, routing on module-owned nets is propagated; move bounds enclosed by the module boundary whose cells belong only to that module are propagated; group bounds and relative-placement groups whose members belong exclusively to the module are propagated. Placement blockages and route guides that lie completely inside the module boundary are propagated; without a module boundary, they are not.

If the committed instance overlaps top-level site arrays, copies of those arrays are created in the block. By default a hard inner keepout margin is created, equal to one row height, and a default outer keepout equal to twice the minimum wire-track width. On Nimbus-8 the inner keepout is therefore 0.576 µm — one teaching-library row, about six tenths of a micron. Sit with that stripe: it is paint along the inside of the wall so standard cells cannot sit on the pins. You type it with a unit character, for example 0.576um. Do not convert it to millimetres and drop the unit: the option will not guess. You can change the paint. You cannot pretend it is not there after a default commit. Read the outer keepout back from the block; do not assume it equals twice the M2 pitch of 0.048 µm. Control both with:

# sizes need a unit character: 0.3um, not a bare 0.3
icc2_shell> set_app_options -list {plan.commit.inner_keepout_margin hard}
icc2_shell> set_app_options -list {plan.commit.inner_keepout_margin_size 0.3um}
icc2_shell> set_app_options -list {plan.commit.outer_keepout_margin hard}
icc2_shell> set_app_options -list {plan.commit.outer_keepout_margin_size 0.1um}
# or suppress both
icc2_shell> set_app_options -list {plan.commit.inner_keepout_margin none}
icc2_shell> set_app_options -list {plan.commit.outer_keepout_margin none}

Distance values must include a unit character. These application options persist in the database. If the parent has SAIF map data, the committed block loads a block-level SAIF map from it.

The command fails if the library is not the design library or a current reference library; if the module does not exist or is not a hierarchical logic cell; or if the library already contains a design of that name. Reverse a commit with uncommit_block — confirm the options on your build with man uncommit_block before you rely on a flag.

Left green panel: commit of a module boundary placed in the core, cells placed, inner keepout labelled 0.576 micrometres. Right pink panel: commit of a module with no boundary, default square sitting outside the core. A yellow MIB trap note at the foot.
Figure 8.6 The same command, two hierarchy types, two completely different databases. The right-hand result is legal. It is the afternoon you do not get back. Teaching purpose: make the empty-success case visible before the reader types commit_block the first time.
Zoomed CPU cluster rectangle with a gold inner keepout stripe labelled 0.576 micrometres equals one row. A pink diagnosis panel: commit returned a collection, the instance sits outside the core, cells unplaced, because a module was committed instead of a module boundary.
Figure 8.14 One row of keepout, and the diagnosis when the block is outside the core. The collection means the write succeeded. It does not mean the floorplan did. Teaching purpose: show the paint stripe, then the empty-success case, as two pictures a beginner can hold.
TRAP / MISTAKE A collection is not a floorplan

commit_block returns a collection of committed cells. That return value means the write succeeded, not that the block is in the core with its cells placed. Look at the instance. If it is outside the core, you committed a module, not a module boundary.

Commit a boundary that already sits in the core. Committing a bare module invents a square and parks it outside.

Part 4 — Placement abstracts: a light stand-in for the parent

After commit, the parent still sees full blocks unless you replace them with abstracts. A placement abstract is the stand-in this chapter owns. Prerequisite: load the full netlist of the top level, without the details of the committed children. If current_design reports lib:BLOCK.outline rather than .design, expand first.

# mapping file from split_constraints (Chapter 3)
icc2_shell> set_constraint_mapping_file split/mapfile
icc2_shell> sh cat split/mapfile
# Verilog must still sit at the path read_verilog_outline used, or on search_path
icc2_shell> expand_outline
icc2_shell> save_lib -all
icc2_shell> set_host_options -name block_script ...
icc2_shell> check_host_options -host_options block_script -target ICC2
icc2_shell> create_abstract -placement -host_options block_script -all_blocks

Omit -host_options to run locally. Use -blocks {list} instead of -all_blocks for a subset. The two are mutually exclusive. With neither, the command abstracts the current design. -work_dir holds generated scripts and logs; default is the host option’s directory, or ./work_dir. -force_recreate rebuilds an abstract of the same type; without it, an existing abstract of the requested type is left alone. -placement always produces an editable abstract and overrides -read_only.

In a multi-level physical hierarchy, only one level of physical hierarchy can be an abstract view at a time. By default -all_blocks abstracts the lowest-level block that is allowed to have an abstract. abstract.allow_all_level_abstract true lets you abstract a child at any level if that child’s plan.flow.design_view_only is false. False (the planning default) means only the lowest-level block with plan.flow.design_view_only false. -target_use planning applies that rule; -target_use implementation allows abstract creation at any physical-hierarchy level. -preserve_block_instances defaults to true; false flattens nested physical hierarchy into the abstract.

The readiness gate is check_design -checks {dp_pre_create_placement_abstract}: the mapping file has UPF for all blocks, and outline netlists are in place. The Verilog files expand_outline rereads must still be at the original read_verilog_outline path, or on search_path. -force rereads even if they look unchanged; use it with care, because modules are found by the original line numbers. Insert a comment, and expansion can fail. -keep retains the outline in memory. -no_def skips DEF during expansion. -strip removes path prefixes when searching.

All leaf cells of a block must be mapped before abstract creation. The command also saves the current block to disk.

Three columns: outline view as an empty box with ports; design view with SRAMs and a field of standard cells; placement abstract with macros kept and a few gold I/O-facing cells. Captions warn not to abstract an outline.
Figure 8.7 Three views of CPU_CLUSTER. Abstracts need the middle column. The left column is a silhouette. The right column is what the parent should plan against. Teaching purpose: connect current_design’s .outline/.design suffix to a picture of what is loaded.
WHY?

Top-level global placement needs connectivity and area, not nine million standard-cell shapes. A placement abstract is that compromise. Using it for timing closure is a category error: there is no timing graph. Using a black-box abstract here is the other category error: you do have the logic; you committed it.

Expand the outline, map the constraints, then create_abstract -placement. An abstract built on an outline is a silhouette of a silhouette.

Part 5 — Boundary and origin are two attributes

Editing a committed block’s outline in the GUI writes the boundary attribute. It does not write origin. The pins, the keepouts and every child coordinate still speak the old origin. The command that writes both is:

# teaching L-shape; every number is micrometres
# 50 um = 0.050 mm. This is not the Nimbus-8 CPU size.
icc2_shell> set_block_boundary -cell u_cpu_cluster \
    -boundary {{50 50} {300 50} {300 200} {150 200} {150 300} {50 300}} \
    -origin {50 50} -orientation R0

-boundary is a polyrect: a list of coordinates in the current design. Table 8.1 still holds: you type micrometres. Sit with the two attributes. The outline is the wall. The origin is the (0, 0) of every pin, keepout and child that will be written later. If you omit -origin, origin is derived from orientation: R0 uses the lower-left of the bounding box; MX uses the upper-left; and so on. Message DPP-057 confirms the write.

move_block_origin -to {500 500} is a different job. It moves the current top-level origin relative to the current origin. On a square 1,000 µm = 1.000 mm on each side whose origin is (0, 0), so an area of 1.00 mm² = 1,000,000 µm², -to {500 500} places the origin at the centre. It does not reshape a child.

Left: rectangular block, origin marked at lower-left, pins on the edges. Right: the same block reshaped into an L in the GUI, origin still at the old lower-left, labelled origin still here. Notes on set_block_boundary and move_block_origin.
Figure 8.8 The outline moved. The origin did not. That is not a bug; it is two attributes. Write both, or the next pin assignment will be in the wrong coordinate system. Teaching purpose: show the silent mismatch a GUI reshape leaves behind.
Reshape with set_block_boundary and an explicit origin. A GUI outline is only half the write.

Part 6 — Push down, pop up, and the shadow netlist

Objects you drew at the top — PG straps, signal routes, guides, blockages, bump regions — often belong inside a child once the child exists. Sit with the sequence before you type it: set the options, report them so you can see what you set, optionally check, then push. Skipping the report is how a clean check of the wrong options becomes a wasted afternoon.

icc2_shell> set_push_down_object_options \
    -object_type {pg_routing signal_routing} \
    -top_action remove \
    -block_action {copy create_pin_shape}
icc2_shell> report_push_down_object_options
icc2_shell> check_objects_for_push_down
icc2_shell> push_down_objects

Object types: pg_routing, signal_routing, routing_guide, routing_corridor, blockage, pin_guide, pin_blockage, cells, charging_station, bump_region, marker_layer. Top actions: keep or remove. Block actions depend on type: center_pin_from_wire, copy, create_blockage, create_pin_shape, create_route_blockage_from_cell, retain_obsolete_ports. For PG routing, copy, create_blockage and center_pin_from_wire are mutually exclusive; create_pin_shape may combine with the others. Default block action for PG routing is create_pin_shape. center_pin_from_wire makes a pin from any wire in the interior — use it on a limited set, then turn it off.

Other options: -routing_overlap_check; -ignore_misalignment (MIB PG); -allow_multi_rail_cells; -collinear_margin (PG only; default −1, overlapping parallels only; 0 means abutting; greater than zero copies parallels within that distance into the child and leaves the original at the top); -pin_meet_fatwire_rule; -location_based_terminal_naming; -create_pg_feedthrough. Confirm current defaults with report_push_down_object_options and man set_push_down_object_options.

Pushed objects are named with suffix _PUSHDOWN_n unless you set plan.pins.new_port_name_tag (ports and nets) or plan.pins.new_cell_name_tag (cells). After a push, is_shadow is true and shadow_status is pushed_down. Other status values: copied_down, copied_up, normal, pulled_up, virtual_flat. Feedthroughs that were pushed down tag the pins, nets and buffers.

check_objects_for_push_down looks at collinear routes and vias, physical routing incompatible with a logical net, incomplete top-level routing, and charging stations for UPF. It uses the options you just set. Zero problems with default options is not zero problems with the options you meant to set. The readiness gate dp_pre_push_down is the MIB alignment check.

Three blocks in a row, CPU, NPU, ISP, with a gold top-level net crossing all three. After push, pins appear on the facing edges. A grey panel lists is_shadow, shadow_status values, the _PUSHDOWN_n suffix, and bump-region orientation limits.
Figure 8.9 Default push creates electrically equivalent ports where the net hits a child. A feedthrough port is a different request. Bump regions accept only R0, MX, MY and R180. Teaching purpose: show the net before and after, and the attributes that prove the push.

Bump regions, feedthroughs, and a via as a pin

Pushing a bump region recalculates boundary, pattern offset, orientation, pitches and staggers so the region looks the same from the top; cuts overlapping block boundaries; checks MIB alignment; refuses overlapping regions that have different attributes (warning, not pushed); and maps TSV information onto pseudo bumps. After the push the net matrix is kept or mapped, and top regions stay anchored. Allowed orientations: R0, MX, MY, R180 only.

Default push of a signal creates an electrically equivalent port on the lower block. To create a feedthrough port instead:

icc2_shell> create_pin_constraint -type individual \
    -nets [get_nets * -filter "net_type == signal"] \
    -allow_feedthroughs true

Full pin-constraint teaching is Chapter 13; this chapter needs only that option. A routing corridor’s nets, pushed down, produce a pure feedthrough in a middle block and physical pins where a detailed route meets a boundary.

Pins default to block edges. To use a via as the pin location (which limits pin count on MIBs), set block actions to {copy create_pin_shape} and push the via:

icc2_shell> push_down_objects [get_vias VIA_S_5] -cells {u1 u2}

Pop up

The reverse sequence: set_pop_up_object_options, report_pop_up_object_options, pop_up_objects. Same object types. Block action is keep or remove. -routing_overlap_check applies to PG and signal. -pins_as_terminals creates top-level terminals. After a pull-up, shadow_status is pulled_up.

Child bump regions become separate top regions, not merged. Geometry is recalculated; TSV mapping is copied. Keep leaves the original; remove deletes the child. Top action for bump regions is only copy. Shadow status is copied_up or pulled_up according to the block action.

Set, report, check, then push. Zero check-violations under the wrong options is a clean log of the wrong job.

Part 7 — When the netlist must move, not the geometry

push_down_objects moves physical objects. Three ECO commands move netlist structure the push cannot touch.

write_split_net_eco pushes the branching of a physical multiple-fanout net — a net that connects more than one physical block — as high in the hierarchy as it can go, including through logic wrappers. Default: all such nets. -nets selects. -filename writes a file; without it, the script prints to the console. source the file to apply it.

write_push_down_eco pushes a tree of standard cells (an OR-gate tree is the teaching case) one physical level. The tree must completely fit in the block. New ports are created; original ports are not reused; unused inputs are tied to VSS. One ECO file per block; default directory push_down_eco_scripts; -dir overrides. Source the top-level Tcl.

write_spare_ports_eco creates spare or dummy feedthrough ports and the top-level nets that connect them. Specify the cell_list. -name defaults to dummyFT. -direction is in, out or inout, and is required. -bits is a start index and an end index, both non-negative: {0 4} is bits 0, 1, 2, 3 and 4 — five bits. Default directory create_spare_ports. Source the top-level script; it calls the others.

Left: three atlas-style OR gates forming a tree that must fit inside a dashed block, for write_push_down_eco. Centre: a gold node fanning out to blocks A, B and C, for write_split_net_eco. Right: spare dummyFT ports, bits 0 through 4. A green note on write_verilog shadows versus write_shadow_eco.
Figure 8.10 Three scripts, three structures. Geometry push cannot move an OR tree or a multi-block fanout branch. Spare ports are planned leftovers, not accidents. Teaching purpose: put a real OR-gate symbol on the page so ‘tree of standard cells’ is not a labelled box.

write_verilog includes shadow objects by default. Use -include shadow_netlist or -exclude shadow_netlist when you mean it. To give a front-end the feedthroughs without the shadow attributes, run change_names -rules verilog then write_shadow_eco. -command_style icc2 is the default; dc writes a flavour a synthesis session can consume — and will error if net and port names were allowed to diverge. Query:

icc2_shell> open_block
icc2_shell> get_cells -filter is_shadow
icc2_shell> get_nets -filter is_shadow
icc2_shell> get_attribute [get_nets * -filter is_shadow] shadow_status
If the structure you need to move is a tree, a multi-block fanout, or a spare port, write an ECO. The push will not do it, and a Verilog file full of shadows is not a front-end netlist.

Inputs, outputs, and readiness

Table 8.3 What this chapter consumes and what it writes
StageNeedsWrites
ExploreA linked design with a floorplan utilisationNothing persistent. A census.
Module boundariesNamed logical cells, or plan.place.hierarchy_by_name on a flat netlistPlanning rectangles (or move bounds). Netlist unchanged.
CommitA hierarchical logic cell; preferably a module boundary in the core; a library that does not already hold that design nameA physical block in a library; keepouts; propagated routing and bounds; outline views in the GUI.
ExpandVerilog still at the original path or on search_pathA .design representation. Outline closed unless -keep.
Placement abstractFull top netlist, mapping file, mapped leaf cells, host options if distributedAn editable placement abstract; parent switched onto it; block saved.
Push / popOptions set and reported; MIB alignment for bump regionsChild geometry; shadow attributes; optional top removal.
ECO scriptsThe structure that actually exists (fanout, tree, or spare)Tcl under the stated directory. Nothing changes until you source it.

Preflight checklist

  1. Hierarchy Browser: every candidate has a pin count and a hard-macro count you believe.
  2. Top-level utilisation is the utilisation you want the boundaries sized from, or you will pass -utilization.
  3. MIB copies: fixed-placed children agree, because commit will not check.
  4. Target library exists, is a reference library, and does not already contain the new design name.
  5. split_constraints mapping file lists UPF for every block you will abstract.
  6. Verilog files have not moved, and have not gained a comment that shifted line numbers, unless you intend expand_outline -force.
  7. current_design reports .design before create_abstract -placement.
  8. check_design -checks {dp_pre_create_placement_abstract} is clean, then dp_pre_push_down before a bump-region push.
TRAP / MISTAKE When the result is legal and still misleading

A module boundary sized from a stale utilisation. A commit of a bare module that “succeeds” outside the core. An abstract created while current_design still says .outline. A push-down check that reports zero because the options were never set. A write_verilog the front-end accepts that still contains every shadow object. None of these are crashes. All of them are the wrong database.

Guided tool workflow

Numbered path from a linked Nimbus-8 floorplan to a parent that plans against placement abstracts, with the objects that belong in the children pushed down.

  1. Census: Hierarchy Browser. Record utilisation, pins, macros, standard cells for u_cpu_cluster, u_npu_core_0, u_isp, u_soc_periph.
  2. Tape: explore_logic_hierarchy -create_module_boundary -cell {...}, then nested core pairs with -nested. Drag into the core. -organize if the pile takes over.
  3. Commit each reference into its library (or the current design library). Confirm each instance sits in the core and that cells inside are placed.
  4. Point at the mapping file. expand_outline if needed. save_lib -all.
  5. Gate: check_design -checks {dp_pre_create_placement_abstract}.
  6. create_abstract -placement -all_blocks (distributed or local).
  7. If a child’s outline is wrong, set_block_boundary with origin and orientation. Confirm DPP-057.
  8. Set push-down options, report, check_objects_for_push_down, push_down_objects. Query is_shadow.
  9. Where the structure is a tree, a multi-block fanout, or a spare port, write the matching ECO and source it.

Eight-point treatment of the commands that matter

For every important command: purpose, syntax, prerequisites, a small example, expected result, verification, common mistakes, and how to discover more. Additional options: man <command> and help <command>, as in Chapter 2. Do not invent flags from memory.

Table 8.4 Eight points for each important command
CommandThe eight points
explore_logic_hierarchy
  1. Purpose. Create, place, organise or remove module boundaries (or, with hierarchy_by_name, move bounds) so you can judge a partition before you commit it.
  2. Syntax. explore_logic_hierarchy [-cell cells] [-create_module_boundary | -organize | -remove | -expand | -collapse | -place ...] [-nested] [-utilization u] [-threshold t] [-name n -virtual_group {...}]
  3. Prerequisites. A linked design. For flat netlists, plan.place.hierarchy_by_name true first.
  4. Example. explore_logic_hierarchy -create_module_boundary -cell {u_isp}
  5. Expected result. A planning rectangle sized from top utilisation (or -utilization). Named cells ignore the 0.03 threshold.
  6. Verify. Select the boundary in the layout. Confirm it is a module boundary, not a block. After -virtual_group, get_attribute [get_bounds group1] -name flat_hier_names.
  7. Common mistakes. Omitting -cell silently drops hierarchies under 3 per cent. Creating A and A/B without -nested fails. Treating the lower-right pile as a floorplan.
  8. Discover more. man explore_logic_hierarchy — note -auto_partition is deprecated.
commit_block
  1. Purpose. Turn a logical hierarchical cell into a physical block in a library.
  2. Syntax. commit_block [-library library] [-cells cells] [-verbose] modules
  3. Prerequisites. The module exists and is hierarchical. The library is the design library or a current reference library, and does not already hold that design name. Prefer a module boundary already in the core.
  4. Example. commit_block -library nimbus8.dlib CPU_CLUSTER
  5. Expected result. A collection of committed cells. Outline views in the GUI. Keepouts. Cells placed only if a module boundary supplied an origin.
  6. Verify. Is the instance inside the core? Are member cells placed? Report keepout margins. For MIBs, inspect every instance.
  7. Common mistakes. Committing a bare module (square outside the core). MIB children that do not agree. A name collision in the target library.
  8. Discover more. man commit_block. Also man uncommit_block before you reverse one.
expand_outline
  1. Purpose. Reread the original Verilog and replace an outline representation with a full design representation.
  2. Syntax. expand_outline [-design name] [-force] [-strip prefixes] [-keep] [-no_def]
  3. Prerequisites. read_verilog_outline was used; the files still sit at that path or on search_path.
  4. Example. expand_outline
  5. Expected result. current_design reports .design. Outline closed unless -keep.
  6. Verify. current_design. If it still says .outline, the Verilog was not found.
  7. Common mistakes. -force after someone inserted a comment (line numbers moved). Moving the Verilog without updating search_path.
  8. Discover more. man expand_outline
create_abstract
  1. Purpose. Build a placement abstract the parent can use for global placement, without a timing graph.
  2. Syntax. create_abstract [-placement] [-host_options name] [-work_dir path] [-blocks list | -all_blocks] [-force_recreate] [-target_use planning|implementation] ...
  3. Prerequisites. Full top netlist, mapped leaf cells, constraint mapping file, .design not .outline. Host options if distributed.
  4. Example. create_abstract -placement -all_blocks
  5. Expected result. Editable placement abstracts; parent switched onto them; block saved. Lowest allowed level unless abstract.allow_all_level_abstract is true.
  6. Verify. check_design -checks {dp_pre_create_placement_abstract}. Parent instances reference abstract views. Hard macros still visible; most standard cells gone.
  7. Common mistakes. Abstracting an outline. Using this abstract for timing. Confusing it with a Chapter 5 black-box abstract. Forgetting -force_recreate after an ECO.
  8. Discover more. man create_abstract — timing_level values are not this chapter’s job.
set_block_boundary
  1. Purpose. Write a block instance’s boundary, and optionally its origin and orientation, together.
  2. Syntax. set_block_boundary -cell name -boundary {polyrect} [-origin {x y}] [-orientation R0|...]
  3. Prerequisites. A committed block instance in the current design.
  4. Example. set_block_boundary -cell u_isp -boundary {{0 0} {1550 0} {1550 1108} {0 1108}} -origin {0 0} -orientation R0
  5. Expected result. DPP-057. New polyrect. Origin as specified, or derived from orientation if omitted. The numbers 1550 and 1108 are micrometres (1.550 mm × 1.108 mm).
  6. Verify. Report origin and boundary. They must match the shape you see.
  7. Common mistakes. GUI reshape without this command (origin stale). Forgetting -origin on a non-R0 instance.
  8. Discover more. man set_block_boundary
move_block_origin
  1. Purpose. Move the current top-level origin relative to the current origin.
  2. Syntax. move_block_origin -to {x y}
  3. Prerequisites. The block whose origin you mean is current.
  4. Example. move_block_origin -to {500 500}
  5. Expected result. On a square 1,000 µm = 1.000 mm on each side (area 1.00 mm² = 1,000,000 µm²) whose origin is (0, 0), origin moves to the centre.
  6. Verify. Report origin. Child coordinates will have moved relative to the top.
  7. Common mistakes. Using it to reshape a child. Using it when you meant set_block_boundary -origin.
  8. Discover more. man move_block_origin
set_push_down_object_options / push_down_objects
  1. Purpose. Declare how each object type is copied or removed, then push those objects into children.
  2. Syntax. set_push_down_object_options -object_type {...} [-top_action keep|remove] [-block_action {...}] ... ; push_down_objects [objects] [-cells cells]
  3. Prerequisites. Committed children. Options set and reported. For bump regions, orientations in {R0, MX, MY, R180} and MIB alignment.
  4. Example. report_push_down_object_options ; check_objects_for_push_down ; push_down_objects
  5. Expected result. Child geometry; is_shadow true; shadow_status pushed_down or copied_down; names with _PUSHDOWN_n unless retagged.
  6. Verify. get_cells -filter is_shadow. Visual check that PG straps still meet the boundary. Warnings on bump regions that were skipped.
  7. Common mistakes. Checking before setting options. Expecting an OR-tree to move. Expecting a feedthrough port without -allow_feedthroughs. Overlapping bump regions with different attributes.
  8. Discover more. man set_push_down_object_options and man push_down_objects. Then man set_pop_up_object_options.
write_split_net_eco / write_push_down_eco / write_spare_ports_eco
  1. Purpose. Write Tcl that moves a multi-block fanout branch, a fitting standard-cell tree, or spare feedthrough ports — then source it.
  2. Syntax. write_split_net_eco [-filename f] [-nets nets]; write_push_down_eco ...; write_spare_ports_eco [-dir d] [-name n] -direction in|out|inout [-bits {start end}] cell_list
  3. Prerequisites. Physical blocks exist. For a cell tree, the cells completely fit in the child. change_names -rules verilog before write_shadow_eco.
  4. Example. write_spare_ports_eco [get_cells u_*] -direction in -dir test_path -bits {0 4} -name spareFT
  5. Expected result. Scripts on disk (or at the console). Database unchanged until source. Spare example: five bits named spareFT, indices 0 to 4.
  6. Verify. diff the scripts. After source, the new ports, the tied-off unused inputs, or the raised branch exist in the netlist.
  7. Common mistakes. Sourcing the wrong directory. A tree that does not fit. Omitting -direction on spare ports. Sending write_verilog shadows to a front-end that wanted write_shadow_eco -command_style dc.
  8. Discover more. man on each of the three, and man write_shadow_eco.

One continuous worked example — Nimbus-8

Situation. The floorplan from Chapter 4 is still one physical design. The four named regions are modules. Two NPU instances share one reference. The CPU cluster has two core pairs you intend to keep nested. You must produce libraries the block owners can take, and a top level that can be planned against placement abstracts.

Initial conditions. Library nimbus8.dlib, top NIMBUS8. Core a square 3.20 mm on each side, so 10.24 mm² = 10,240,000 µm², utilisation 0.617. Die a square 3.44 mm on each side, so 11.83 mm² = 11,833,600 µm². Block-boundary total we are aiming at: 8.149 mm² = 8,149,000 µm²; channel 2.091 mm² = 2,091,000 µm² (20.4 per cent of the core). Row height 0.576 µm. Mapping file from Chapter 3 at split/mapfile.

Before-and-after Nimbus-8 floorplan. Left: dashed yellow uncommitted modules. Right: solid committed blocks, nested green core pairs, gold dashed abstracts, DDR PHY as a hard macro. A note restates core area, channel, and inner keepout.
Figure 8.11 The same die, before commit and after abstracts. The channel is still 2.091 mm² = 2,091,000 µm². The inner keepout on every committed block is one row, 0.576 µm. Teaching purpose: one continuous design, two database states, numbers that still add up.
# 1. tape the four top-level candidates, then nest the core pairs
icc2_shell> explore_logic_hierarchy -create_module_boundary -cell \
    {u_cpu_cluster u_npu_core_0 u_isp u_soc_periph}
icc2_shell> explore_logic_hierarchy -create_module_boundary -nested -cell \
    {u_cpu_cluster/u_core_pair_0 u_cpu_cluster/u_core_pair_1}
# drag into the core; NPU instance 1 shares the NPU_CORE drawing
icc2_shell> explore_logic_hierarchy -organize

Place the CPU boundary at 2.00 mm × 1.586 mm = 3.172 mm² = 3,172,000 µm², the NPU at 1.03 mm × 1.154 mm = 1.189 mm² = 1,189,000 µm² (both instances), the ISP at 1.55 mm × 1.108 mm = 1.717 mm² = 1,717,000 µm², the SoC periphery at 0.82 mm × 0.413 mm = 0.339 mm² = 339,000 µm². The block-boundary total we are aiming at remains 8.149 mm² = 8,149,000 µm²; the leftover channel is 2.091 mm² = 2,091,000 µm². Confirm the two NPU rectangles are congruent. If they are not, stop: commit will not fix furniture that already disagrees.

# 2. commit references. NPU is one MIB reference, two cells.
icc2_shell> commit_block -library nimbus8.dlib CPU_CLUSTER
icc2_shell> commit_block -library nimbus8.dlib NPU_CORE
icc2_shell> commit_block -library nimbus8.dlib ISP
icc2_shell> commit_block -library nimbus8.dlib SOC_PERIPH

Expected: four outline views. Each instance in the core. Inner keepout 0.576 µm. Member cells placed, because these were module boundaries. The two NPU cells share one reference. Nested core pairs remain children of CPU_CLUSTER if you committed the parent with those boundaries present; if you needed them as their own physical blocks, commit the children before abstracting the parent, and read abstract.allow_all_level_abstract before you abstract a mid-level block.

# 3. full top netlist, then placement abstracts
icc2_shell> set_constraint_mapping_file split/mapfile
icc2_shell> current_design
# if the reply contains .outline:
icc2_shell> expand_outline
icc2_shell> save_lib -all
icc2_shell> check_design -checks {dp_pre_create_placement_abstract}
icc2_shell> create_abstract -placement -all_blocks

Interpret the abstract: hard macros remain; most standard cells vanish; interface registers remain; the parent’s global placer now sees area and connectivity, not nine million shapes. This is an estimate of congestion, not a signoff.

# 4. a child outline that must become rectilinear, origin included
# 1550 um = 1.550 mm; 1108 um = 1.108 mm. Same ISP you just placed.
icc2_shell> set_block_boundary -cell u_isp \
    -boundary {{0 0} {1550 0} {1550 1108} {0 1108}} \
    -origin {0 0} -orientation R0
# 5. push PG and signal routing that already exists at the top
icc2_shell> set_push_down_object_options -object_type {pg_routing} \
    -top_action keep -block_action {copy create_pin_shape}
icc2_shell> report_push_down_object_options
icc2_shell> check_design -checks {dp_pre_push_down}
icc2_shell> check_objects_for_push_down
icc2_shell> push_down_objects
icc2_shell> get_nets -filter is_shadow

Engineering judgement — what a senior engineer inspects next. Not the log. The instances: in the core, congruent MIBs, keepouts present. Then current_design’s suffix. Then whether the abstract still shows every SRAM you counted in the Hierarchy Browser. Then whether the front-end has asked for a shadow ECO or a clean Verilog. Then, and only then, Chapter 9’s question: are these rectangles the right shape?

Failure modes and debugging

Major-chapter bar: ten realistic mistakes, including one misleading symptom. Warnings are not hard errors. A poor-quality-but-legal result is the usual failure mode in this chapter.

Table 8.5 Symptom, cause, check, correction, prevention
SymptomLikely causeCheckCorrectionPrevention
Candidate never got a boundaryDefault 0.03 threshold, and you omitted -cellSize against 3 per cent of the designName it with -cell, or lower plan.explore.default_thresholdAlways name the cells you mean
Nested child refused-nested omittedParent already has a boundaryRerun with -nestedTreat nesting as opt-in
Commit “worked”; block sits outside the core, cells unplacedHierarchy type was module, not module boundaryIs the instance outside the core?uncommit_block, create a boundary in the core, recommitNever commit tape you have not placed
MIB instances look different after commitFixed-placed children disagreed; no pre-checkCompare child origins before commitUncommit, align furniture, recommit from one referenceCongruence check is yours
Library already contains that designName collisionList designs in the target libraryNew library, or remove the stale design on purposeOne reference name per drawing
Abstract looks emptycurrent_design was still .outline, or Verilog movedcurrent_design; search_pathexpand_outline, then recreate with -force_recreateGate on dp_pre_create_placement_abstract
expand_outline fails after a “harmless” editLine numbers moved; -force cannot invent modulesDiff the Verilog against the outline’s recorded linesRestore the file, or re-read the outline from scratchDo not comment a netlist the outline still points at
Push-down check is clean, PG is wrong in the childOptions never set; check used defaultsreport_push_down_object_optionsSet, report, recheck, pushNo check before a report
Bump region not pushed, warning onlyOrientation not in {R0, MX, MY, R180}, or overlapping regions with different attributesRegion orientation and attributesFix orientation or attributes, push againTreat the warning as a skip, not a success
Front-end rejects nets that “exist”write_verilog included shadows, or net/port names diverged for -command_style dcget_nets -filter is_shadowwrite_verilog -exclude shadow_netlist or write_shadow_eco -command_style dc after change_names -rules verilogAsk which file the front-end is actually going to read
OR-tree still at the top after a pushpush_down_objects cannot move that treeDo the cells completely fit in the child?write_push_down_eco, then sourceGeometry push versus netlist ECO is a classification, not a retry
Pins sit off the new outlineGUI reshaped boundary, left originReport both attributesset_block_boundary with -originNever reshape without origin

The rose row is the misleading symptom. The apparent cause is “commit failed to place the block”. The real cause is that you never gave it a boundary to place. The command did exactly what a bare module is specified to do.

Hard errors: missing module, library name collision, library not a reference. Warnings: skipped bump regions, threshold replacements. Poor-quality-but-legal: everything else in that table.

Hands-on mini lab — Orion-5

Goal. On a tiny synthetic die, create one module boundary, commit it, expand if needed, build a placement abstract, and prove the origin survived a reshape.

Supplied assumptions. Core a square 1,200 µm = 1.200 mm on each side, so 1.44 mm² = 1,440,000 µm². Utilisation 0.70. Two logical cells: u_core (placeable content 0.490 mm² = 490,000 µm²) and u_glue (stays at the top). Teaching row height 0.576 µm. Verilog at orion5.v, mapping file split/mapfile. No proprietary data.

Steps.

  1. Compute the default module-boundary area for u_core: 0.490 ÷ 0.70 = 0.700 mm² = 700,000 µm². Side of a square: √700,000 ≈ 836.7 µm = 0.837 mm.
  2. explore_logic_hierarchy -create_module_boundary -cell {u_core}. Place that rectangle in the core.
  3. commit_block ORION5_CORE (or -library of your design library). Confirm the instance is inside the core and the inner keepout is one row, 0.576 µm.
  4. current_design. If the suffix is .outline, expand_outline then save_lib -all.
  5. set_constraint_mapping_file split/mapfile then check_design -checks {dp_pre_create_placement_abstract} then create_abstract -placement.
  6. Reshape with set_block_boundary -cell u_core -boundary {{0 0} {900 0} {900 780} {0 780}} -origin {0 0} -orientation R0. Those numbers are micrometres: 900 µm = 0.900 mm, 780 µm = 0.780 mm, so an area of 0.702 mm² = 702,000 µm² — a hair larger than the 0.700 mm² default square, and rectangular on purpose. Confirm DPP-057. Report origin: it must still be (0, 0), not a stale corner from a GUI drag.

Expected observations. Boundary area before commit near 0.700 mm² = 700,000 µm². After commit, instance in the core, cells placed, keepout 0.576 µm. Abstract retains macros and interface cells. Origin matches the lower-left of the new 900 µm × 780 µm = 0.900 mm × 0.780 mm rectangle.

Verification checklist. Instance inside core; .design before abstract; mapping file set; DPP-057; origin report; get_cells -filter is_shadow empty until you push.

Stretch. Add a second instance of the same reference. Mis-place one child’s dummy macro on purpose, commit, and write down what each instance looks like. Then uncommit and explain why the tool was allowed to do that.

Interview preparation

BEGINNER

1. What is the difference between a module and a block?

A module is a logical hierarchy cell. A block is a physical hierarchy design, created by commit_block.

The directory name versus the locked flat. Until commit, there is nothing to hand off, abstract, or shape.

What is being tested. Treating the words as synonyms. A weak answer never mentions the library.
BEGINNER

2. Where does a module boundary’s default size come from?

The utilisation of the top-level floorplan. Override with -utilization (0.01 to 10). Negative values fall back to design utilisation.

Nimbus-8 at 0.617. Content 1.96 mm² = 1,960,000 µm² becomes about 3.18 mm² = 3,180,000 µm² of tape.

What is being tested. Saying ‘whatever you type’ or confusing it with the 0.03 threshold.
BEGINNER

3. What does the default 0.03 threshold do?

Without -cell, hierarchies smaller than 3 per cent of total size are ignored when creating or expanding boundaries. Named cells ignore it.

plan.explore.default_threshold holds the default. Negative input is warned and replaced by zero.

What is being tested. Calling a missing tiny module a netlist bug.
BEGINNER

4. What does current_design reporting lib:CPU_CLUSTER.outline mean for create_abstract?

You have a silhouette. expand_outline first, then abstract. Placement abstracts need the full top netlist.

The Verilog must still be at the read_verilog_outline path or on search_path.

What is being tested. Abstracting anyway and calling the empty result ‘lightweight’.
BEGINNER

5. Inner keepout after commit: what is the default, on Nimbus-8?

A hard inner keepout equal to one row height: 0.576 µm. Outer keepout is twice the minimum wire-track width; read it back.

plan.commit.inner_keepout_margin and _size override it. Values persist.

What is being tested. Using the M2 pitch 0.048 µm as if it were the outer keepout.
BEGINNER

6. Name the four steps of this chapter, in order.

Explore hierarchy; create module boundaries; commit blocks; create placement abstracts.

Each step is a gate. Skipping is legal and usually expensive.

What is being tested. Starting at commit, or inserting pin assignment (Chapter 13) in the middle.
INTERMEDIATE

7. You commit a module with no boundary. What should you expect to see?

A default square from leaf counts, cells unplaced, instance outside the top core. The command still returns a collection.

This is specified behaviour, not a crash. Site arrays may not align until later shaping.

What is being tested. Calling it a tool bug. The misleading-success case.
INTERMEDIATE

8. Compare a placement abstract with a Chapter 5 black-box abstract and with a timing abstract.

Placement: stand-in for a committed block, macros plus interface cells, no timing graph, always editable. Black box: stand-in for missing logic. Timing abstract: Chapter 14, traces paths, timing_level compact/full_interface/boundary.

-placement overrides -read_only and sets timing_level none (deprecated name, same idea).

What is being tested. One word ‘abstract’ for three objects.
INTERMEDIATE

9. Tradeoff: commit every MIB instance from a named -cells reference, versus committing after checking congruence.

Naming a reference applies one boundary to every instance — fast, and wrong if furniture disagrees. The tool does not pre-check. Checking first costs an hour and saves a respin.

dp_pre_push_down is alignment at push time, not at commit time.

What is being tested. Assuming commit validates MIB copies.
INTERMEDIATE

10. Tradeoff: keep versus remove as top_action on PG push-down.

keep leaves the top straps in place (parent still sees them); remove deletes them at the top (child owns them). Collinear copies with collinear_margin leave the original at the top even when the child gets a copy.

Quality: IR drop wants continuity; hierarchy wants ownership. Both can be true if you copy and keep.

What is being tested. A one-word answer with no IR or ownership.
INTERMEDIATE

11. What does abstract.allow_all_level_abstract change?

True: you may abstract a child at any level if that child’s plan.flow.design_view_only is false. False: only the lowest-level block with that flag false. Planning target_use uses the stricter default.

Only one physical-hierarchy level can be an abstract view at a time.

What is being tested. Thinking it abstracts every level at once.
SCENARIO

12. What would you do if commit_block returns a collection but the instance is outside the core?

Do not celebrate. Uncommit. Create a module boundary in the core. Confirm hierarchy type. Recommit. Then look at cell placement and keepouts.

The collection means the write succeeded. It does not mean the floorplan did.

What is being tested. Pushing on, or deleting the library.
SCENARIO

13. What would you do if create_abstract -placement finishes in seconds and the parent still looks full of standard cells?

current_design suffix, mapping file, whether -all_blocks saw any eligible child, whether an old abstract of the same type blocked recreation without -force_recreate, whether you abstracted the parent instead of the children.

Seconds can be a cache hit, not a success.

What is being tested. Rerunning the same command louder.
SCENARIO

14. What would you do if write_verilog is accepted by the front-end but many nets ‘do not exist’ in a later ECO?

Those nets were shadows, or net and port names diverged. Query is_shadow. Exclude shadows, or write_shadow_eco -command_style dc after change_names -rules verilog.

Two consumers, two files. Ask which file they sourced.

What is being tested. Blaming the front-end for a file you made ambiguous.
SCENARIO

15. A push of bump regions warns and skips one region. The log is otherwise clean. Next action?

Treat the warning as a skip. Check orientation (only R0, MX, MY, R180) and whether overlapping regions have different attributes. Fix, then push that region again. Do not proceed to RDL as if the field were complete.

A clean log plus a skip is an incomplete field.

What is being tested. Ignoring warnings because the command returned.
SCENARIO

16. You need an OR-tree inside a child. push_down_objects left it at the top. Why, and what instead?

The push moves geometry, not a standard-cell tree. If the tree completely fits, write_push_down_eco (new ports, unused inputs tied to VSS), then source the top Tcl. If it does not fit, reshape or split first — that is Chapter 9 meeting this chapter.

Classification before retry.

What is being tested. Repeating push_down_objects with more object types.

Chapter close

Sign-off checklist for this stage of planning

  1. Every intended partition is a committed block in a library, sitting in the core, cells placed.
  2. MIB instances are congruent; you checked, because the tool did not.
  3. Inner keepout is the keepout you wanted (default one row), not an accident.
  4. current_design is .design where you will abstract.
  5. Placement abstracts exist for the children the parent will plan against; SRAMs still visible; timing not claimed.
  6. Boundary and origin match on every block you reshaped. DPP-057 on file.
  7. Push-down options were reported before they were checked. Shadows query as expected.
  8. Front-end file flavour is agreed: shadows in, shadows out, or a shadow ECO.
  9. ECO scripts that were needed (split, tree, spare) have been sourced, not only written.
  10. The rectangles are now ready to be shaped. That is the next chapter, not this one.

Key-concept flashcards

Module against block

Module: logical cell. Block: physical design after commit_block, in a library.

Module boundary

Movable tape. Default area = content ÷ top utilisation. Not a handoff.

The 0.03 threshold

Unnamed hierarchies under 3 per cent of total size are ignored. -cell bypasses it.

Commit without a boundary

Default square, cells unplaced, instance outside the core. Legal. Wrong.

MIB

One reference, many cells. Commit the drawing once. Congruence is your check.

Inner keepout

Default hard, one row height. Nimbus-8: 0.576 µm. Persistent application options.

Outline against design

current_design suffix. Abstracts need .design. expand_outline rereads Verilog by line number.

Placement abstract

Macros, original cell count and area, interface cells. No timing graph. Always editable.

Origin against boundary

Two attributes. GUI reshape writes one. set_block_boundary writes both.

Push sequence

Set options, report, check, push. Shadows: is_shadow, shadow_status, _PUSHDOWN_n.

Feedthrough against equivalent port

Default push: equivalent port. Feedthrough: create_pin_constraint -allow_feedthroughs true.

Three ECO scripts

Split a multi-block fanout. Push a fitting cell tree. Create spare dummyFT ports. Then source.

Compact glossary

Table 8.6 Chapter 8 glossary
TermMeaning as used in this book
BlockA physical hierarchy design produced by commit_block, stored in a library, with origin, boundary and keepouts.
Electrically equivalent portThe default port push_down_objects creates on a child where a top net meets the boundary. Not a feedthrough.
Feedthrough portA port that carries a net through a block. Requires -allow_feedthroughs true on an individual pin constraint.
Hierarchy BrowserThe GUI census of cells: utilisation, pins, hard macros, standard cells in the entire hierarchy.
Move boundOn a flattened netlist with plan.place.hierarchy_by_name true, the planning rectangle that stands in for a virtual hierarchy.
ModuleA logical hierarchy cell. A name. Not a block.
Module boundaryA planning rectangle attached to a module, created by explore_logic_hierarchy.
Multiply instantiated block (MIB)One block reference instantiated more than once. One drawing, several cells.
Outline viewA representation that holds ports and a silhouette, not the leaf netlist. current_design reports .outline.
Placement abstractA lightweight, always-editable stand-in for a committed block used in top-level global placement. No timing graph.
Shadow netlistObjects created by push, pop or feedthrough insertion, tagged is_shadow with a shadow_status.
Shadow statusOne of pushed_down, copied_down, copied_up, normal, pulled_up, virtual_flat.

Five-question self-check

A new design, Pegasus-4. Core a square 800 µm = 0.800 mm on each side, so 0.64 mm² = 640,000 µm², utilisation 0.50. Three logical modules with content 0.200 mm² = 200,000 µm², 0.150 mm² = 150,000 µm² and 0.010 mm² = 10,000 µm². Row height 0.576 µm. You will name only the first two cells if a threshold would drop the third. A later reshape of the first committed block must keep origin at the lower-left of a 500 µm × 400 µm = 0.500 mm × 0.400 mm rectangle.

  1. Without -cell, which modules receive a boundary at the default threshold, and why?
  2. With -cell naming all three, what boundary area does each module receive at the default utilisation?
  3. You commit the first module after placing its boundary in the core. What inner keepout do you expect, and where should the instance sit?
  4. You then commit the third module without a boundary. What legal result should you refuse to accept as done?
  5. Write the set_block_boundary command that makes the first block 500 µm × 400 µm with R0 origin at the lower-left, and say what a GUI-only reshape would get wrong.

Answers.

1. Three per cent of 0.64 mm² is 0.0192 mm² = 19,200 µm². The 0.200 mm² = 200,000 µm² and 0.150 mm² = 150,000 µm² modules are larger; the 0.010 mm² = 10,000 µm² module is smaller and is ignored. The third module “never got a boundary” because of the threshold, not because it is missing from the netlist.

2. Default utilisation 0.50. Areas: 0.200 ÷ 0.50 = 0.400 mm² = 400,000 µm²; 0.150 ÷ 0.50 = 0.300 mm² = 300,000 µm²; 0.010 ÷ 0.50 = 0.020 mm² = 20,000 µm². Naming them with -cell bypasses the threshold, which is why the tiny one now has tape.

3. Inner keepout = one row = 0.576 µm, hard by default. The instance sits in the core on the origin of that module boundary, with member cells placed relative to its lower-left.

4. A default square parked outside the core, cells unplaced, command still returning a collection. That is specified behaviour for hierarchy type module. Uncommit, tape it, place it, recommit.

5. set_block_boundary -cell u_pegasus_a -boundary {{0 0} {500 0} {500 400} {0 400}} -origin {0 0} -orientation R0. Those numbers are micrometres: 500 µm = 0.500 mm, 400 µm = 0.400 mm, so an area of 0.200 mm² = 200,000 µm². A GUI-only reshape would move the outline and leave the origin on the old lower-left, so later pins would not sit on the new edges. Look for DPP-057.

Eight recap panels: what it is; the four words; the numbers; the habit; push pop ECO; shadow truth; MIB; next chapter. A navy footer band: a block is a locked flat.
Figure 8.12 Chapter 8 on one page. A block is a locked flat. Until you commit, you are rearranging names. The parent plans with an abstract. The child still owns the furniture. Teaching purpose: a single recap the reader can photograph.

Why Chapter 9 follows

You now have rectangles that are real designs in a library. They are not yet the right rectangles. A committed block can be too square for its SRAMs, too tight on a side that will carry a bus, too generous on a side that will starve the channel. The next chapter takes these blocks and shapes them — constraints, relative placement, keepouts, arrays, channels, grids — without undoing the handoff you just made. Do not shape a module. Shape a block. That is why this chapter had to come first.