TraceMaker
C++ API of the engine
Loading...
Searching...
No Matches
congestion.hpp
Go to the documentation of this file.
1// SPDX-License-Identifier: GPL-3.0-or-later
2#pragma once
3// Routability estimate for placement (design doc 04 §3 B `R(x)`, E `β·RUDY overflow`, G).
4//
5// RUDY (Rectangular Uniform wire DensitY; Spindler & Johannes, "Fast and accurate routing demand estimation
6// for efficient routability-driven placement", DATE 2007): each signal net's half-perimeter wirelength is spread
7// uniformly over its pin bounding box, so the demand of a bin is Σ_nets HPWL · area(box ∩ bin) / area(box).
8// Every pin also consumes a fixed amount of track length in its bin (pin density). Capacity per bin is the
9// track length the copper layers offer there (layers × bin² / pitch × usable fraction × fraction inside the
10// outline). The cost is the total overflow Σ max(0, demand − capacity), all in integer nm so incremental and
11// from-scratch evaluation agree exactly (CLAUDE.md rules 2 and 3).
12//
13// Power nets (PNet::signal false) are left out (they are expected on pours or planes; the same reason they get a low HPWL
14// weight). The router-in-the-loop (G) lowers the capacity of bins where the router failed (`scale_bins`), which
15// is the PCB analogue of RePlAce's cell inflation in overflowed tiles.
16#include <algorithm>
17#include <cstdint>
18#include <vector>
19
20#include "place/legality.hpp"
21
22namespace tmk::place {
23
25 double pitch_mm = 0.5; // track pitch (width + clearance) used for the capacity
26 double usable = 0.6; // fraction of the ideal track length that is routable (pads, vias, detours)
27 double pin_tracks = 0.5; // a pin consumes this many tracks across its bin
28 int max_bins = 32; // bins along the longer side of the board
29};
30
32 Coord ox = 0, oy = 0, cell = 1'000'000;
33 int nx = 1, ny = 1;
34 std::vector<std::int64_t> cap; // track-length capacity per bin, nm
35 Coord pin_demand = 0; // track length consumed by one pin, nm
36 int bin(Point q) const; // bin containing q (clamped to the grid)
37 std::size_t size() const { return cap.size(); }
38};
39
41
42// True if the net contributes RUDY demand (signal nets with at least two pins).
43bool rudy_net(const Problem& p, int net);
44
45// Pin bounding box of one net.
46Box net_box(const Problem& p, const Placement& pl, int net);
47
48// Adds `sign` × the RUDY demand of a net with pin bounding box `b` to `demand`. `touch(bin)` is called before a
49// bin is changed (for incremental bookkeeping); pass a no-op lambda when not needed.
50template <class Touch>
51void add_box_demand(const CongestionMap& m, const Box& b, int sign, std::vector<std::int64_t>& demand, Touch&& touch);
52
53// From-scratch demand of a placement (reference path for the annealer's incremental bookkeeping).
54std::vector<std::int64_t> rudy_demand(const Problem& p, const Placement& pl, const CongestionMap& m);
55inline std::int64_t bin_overflow(std::int64_t demand, std::int64_t cap) { return demand > cap ? demand - cap : 0; }
56std::int64_t total_overflow(const CongestionMap& m, const std::vector<std::int64_t>& demand);
57std::int64_t rudy_overflow(const Problem& p, const Placement& pl, const CongestionMap& m);
58
59// Multiplies the capacity of the bins within `radius` of each point by `factor` (once per bin per call).
60void scale_bins(CongestionMap& m, const std::vector<Point>& pts, Coord radius, double factor);
61
62// ---- implementation of the template -------------------------------------------------------------------------
63
64namespace detail {
65// RUDY box: the pin box widened to at least one bin per axis, so aligned pins do not give infinite density.
66inline Box rudy_box(const CongestionMap& m, const Box& b) {
67 Box r = b;
68 if (r.x1 - r.x0 < m.cell) {
69 const Coord c = (r.x0 + r.x1) / 2;
70 r.x0 = c - m.cell / 2;
71 r.x1 = r.x0 + m.cell;
72 }
73 if (r.y1 - r.y0 < m.cell) {
74 const Coord c = (r.y0 + r.y1) / 2;
75 r.y0 = c - m.cell / 2;
76 r.y1 = r.y0 + m.cell;
77 }
78 return r;
79}
80} // namespace detail
81
82template <class Touch>
83void add_box_demand(const CongestionMap& m, const Box& b, int sign, std::vector<std::int64_t>& demand, Touch&& touch) {
84 if (b.empty()) return;
85 const Coord hp = (b.x1 - b.x0) + (b.y1 - b.y0);
86 if (hp <= 0) return;
87 const Box r = detail::rudy_box(m, b);
88 const geom::i128 area = static_cast<geom::i128>(r.x1 - r.x0) * (r.y1 - r.y0);
89 auto cx = [&](Coord v) { return static_cast<int>(std::clamp<Coord>((v - m.ox) / m.cell, 0, m.nx - 1)); };
90 auto cy = [&](Coord v) { return static_cast<int>(std::clamp<Coord>((v - m.oy) / m.cell, 0, m.ny - 1)); };
91 const int x0 = cx(r.x0), x1 = cx(r.x1 - 1), y0 = cy(r.y0), y1 = cy(r.y1 - 1);
92 for (int y = y0; y <= y1; ++y) {
93 // Bins at the grid border absorb everything beyond it.
94 const Coord by0 = y == 0 ? r.y0 : std::max(r.y0, m.oy + y * m.cell);
95 const Coord by1 = y == m.ny - 1 ? r.y1 : std::min(r.y1, m.oy + (y + 1) * m.cell);
96 if (by1 <= by0) continue;
97 for (int x = x0; x <= x1; ++x) {
98 const Coord bx0 = x == 0 ? r.x0 : std::max(r.x0, m.ox + x * m.cell);
99 const Coord bx1 = x == m.nx - 1 ? r.x1 : std::min(r.x1, m.ox + (x + 1) * m.cell);
100 if (bx1 <= bx0) continue;
101 const geom::i128 ov = static_cast<geom::i128>(bx1 - bx0) * (by1 - by0);
102 const auto d = static_cast<std::int64_t>(static_cast<geom::i128>(hp) * ov / area);
103 if (d == 0) continue;
104 const auto k = static_cast<std::size_t>(y * m.nx + x);
105 touch(k);
106 demand[k] += sign * d;
107 }
108 }
109}
110
111} // namespace tmk::place
Placement legality (design doc 04 §3 D/E): exact integer tests of courtyards, through-hole obstacles,...
__int128 i128
GCC extension; exact products of nm coordinates.
Definition shape.hpp:16
Box rudy_box(const CongestionMap &m, const Box &b)
RUDY box: the pin box widened to at least one bin per axis, so aligned pins do not give infinite dens...
std::vector< std::int64_t > rudy_demand(const Problem &p, const Placement &pl, const CongestionMap &m)
From-scratch demand of a placement (reference path for the annealer's incremental bookkeeping).
bool rudy_net(const Problem &p, int net)
True if the net contributes RUDY demand (signal nets with at least two pins).
std::int64_t rudy_overflow(const Problem &p, const Placement &pl, const CongestionMap &m)
std::int64_t bin_overflow(std::int64_t demand, std::int64_t cap)
std::int64_t total_overflow(const CongestionMap &m, const std::vector< std::int64_t > &demand)
void scale_bins(CongestionMap &m, const std::vector< Point > &pts, Coord radius, double factor)
Multiplies the capacity of the bins within radius of each point by factor (once per bin per call).
CongestionMap make_congestion_map(const Problem &p, const CongestionOptions &o={})
void add_box_demand(const CongestionMap &m, const Box &b, int sign, std::vector< std::int64_t > &demand, Touch &&touch)
Adds sign × the RUDY demand of a net with pin bounding box b to demand.
Box net_box(const Problem &p, const Placement &pl, int net)
Pin bounding box of one net.
std::int64_t Coord
Engine coordinate: signed 64-bit nanometres.
Definition units.hpp:12
Coord y1
empty when x1 < x0
Definition point.hpp:21
constexpr bool empty() const
Definition point.hpp:22
std::size_t size() const
std::vector< std::int64_t > cap
track-length capacity per bin, nm
int bin(Point q) const
bin containing q (clamped to the grid)
Coord pin_demand
track length consumed by one pin, nm
double pin_tracks
a pin consumes this many tracks across its bin
double pitch_mm
track pitch (width + clearance) used for the capacity
int max_bins
bins along the longer side of the board
double usable
fraction of the ideal track length that is routable (pads, vias, detours)