Writing a Pin Order Configuration
The first article of this section sketched a side assignment on paper: control signals west, the count bus east, north and south empty. That sketch is only useful once it is a file OpenLane can read. This article writes it and runs the step that consumes it.
The file format
OpenLane’s pin order mechanism, FP_PIN_ORDER_CFG, takes a plain text file with one section per side, marked by a #N, #S, #E or #W header, listing the pin names in the order you want them along that side. An empty section means no pins are forced onto that side.
The file for counter8:
# pin_order.cfg for counter8
# Control cluster (clk, rst_n, en) grouped on the west side.
# count[7:0] bus kept together, in bit order, on the east side.
#N
#S
#E
count[7]
count[6]
count[5]
count[4]
count[3]
count[2]
count[1]
count[0]
#W
clk
rst_n
en
Order within a section matters. Pins are placed along the side in the order listed, so listing count[7] down to count[0] keeps the bus in a predictable physical order rather than scrambling bit positions along the edge.
Wiring it into the flow
Save the file beside the design (designs/counter8/pin_order.cfg) and point config.json at it:
{
"DESIGN_NAME": "counter8",
"FP_PIN_ORDER_CFG": "dir::pin_order.cfg",
"FP_IO_MODE": 0
}
FP_IO_MODE: 0 selects fixed, explicit placement honouring the file, instead of the default equidistant mode.
Running it
Pin placement happens inside the floorplan step, after the core geometry and the PDN:
% prep -design counter8
% run_floorplan
[INFO]: Generating floorplan...
[INFO]: Core area set to 5.00 5.00 45.00 45.00 (die 0.00 0.00 50.00 50.00)
[INFO]: Generating power distribution network...
[INFO]: Placing I/O pins using FP_PIN_ORDER_CFG: pin_order.cfg
[INFO]: West: clk, rst_n, en (3 pins)
[INFO]: East: count[7], count[6], count[5], count[4], count[3], count[2], count[1], count[0] (8 pins)
[INFO]: North: (0 pins)
[INFO]: South: (0 pins)
[INFO]: Writing floorplan DEF to runs/<tag>/results/floorplan/counter8.floorplan.def
The DEF’s PINS section now records real (x, y) coordinates and orientations for each of the 11 pins, all on the sides you specified. You will see them alongside the ring, straps and core boundary when you open the DEF at the end of the module.
Two practical notes. A misspelt bit index (count[8] on an 8-bit port) is not silently ignored; OpenLane reports that the pin does not exist, at floorplan time, so check indices against the Verilog port declaration first. And on designs with dozens or hundreds of pins, hand-listing every one gets unwieldy; real pin order files are often generated from a pinout spreadsheet shared with the board or package team.
Try an edit: move en to #S instead of grouping it with clk and rst_n on the west, and predict before rerunning whether that helps routing to the increment logic en feeds. By the first article’s principle, signals sharing a destination stay together, so separating en probably lengthens its route for no compensating benefit.
Practice Exercise
Write a pin order file for a design with ports clk (feeds everything), data_in[3:0] (feeds an input register on one side of the design), and data_out[3:0] (driven by logic on the opposite side).
Solution
#N
#S
clk
#E
data_out[3]
data_out[2]
data_out[1]
data_out[0]
#W
data_in[3]
data_in[2]
data_in[1]
data_in[0]
clk gets its own side (south) since it is a global signal feeding every flop rather than belonging to either data group. data_in and data_out go on opposite sides, matching the physical separation between the input register and the output logic, so each bus routes directly into the region that needs it instead of crossing the core.
Pins are placed, power is delivered, the core has its shape. In the next section we turn to a different kind of object: hard macros, and the room they need around them that standard cells never do.