# Why resource costs are measured A `CoreDefinition` records its resource cost as a list of *measurement points*. Each point is keyed by the part it was synthesized for, the clock period it was constrained to (or none, for a combinational core), and the module parameters it was built with. The registry used to allow a second form, a scalar envelope: one LUT/FF/BRAM/DSP tuple per core with no coordinates. That form was removed, and the reasons are worth recording. ## A cost only means something at a coordinate "This core costs 733 LUTs" (a made-up figure) only answers the question if you also know the part, the clock, and the parameters. A scalar envelope gives the same number whichever of those you ask about. That caused two real failures. **One part's number priced another part's build.** A design targeting the Kintex was priced with a wide-predicate figure measured on the Artix. The estimate reported `measured=True` while mixing parts, and it hid a tile that had never met timing on the target part. **Parameters that change the cost were ignored.** When the shared dispatcher gained a hash decode, that mode cost 3 DSP48s where the mask decode costs none. A scalar envelope has nowhere to record that the cost depends on `MODE`, so a hash-dispatched design would have been priced as DSP-free and failed at implementation. ## An unmeasured coordinate raises A core does not interpolate, extrapolate, or fall back to a nearby point. Ask for a coordinate it has not been measured at and it raises `UnmeasuredResourceError`, naming the missing coordinate. An exception is used instead of a sentinel value on purpose. A sentinel can be summed, compared, or formatted by numeric code and turn into a plausible-looking number further down. An exception has to be handled. The planner catches it and reports which measurement would fill the gap, so "this cannot be priced" is something it can tell the user instead of a wrong number. Timing follows the same rule. A point whose `timing` is `VIOLATED` is never usable as a budget: it records a failed build, not a smaller one. ## Where the numbers come from Points are produced by the `dau-build` `synthesize-cores` task, one out-of-context synthesis per (part, clock, parameter) combination, and the task reports any drift from what the registry already declares. Synthesis is never run by hand, because a hand-run number loses the coordinate it was measured at. The numbers also cannot say which HDL produced them, so each entry records that as `measured_from`, a digest of the tile's source and everything it imports or includes. A test recomputes the digest from the tree, so editing the HDL under a recorded envelope fails the suite until the core is measured again. Before that stamp existed, two envelopes went stale for months because one commit re-measured the coordinates it added and not the ones it changed. ## What a measured point does not tell you An out-of-context run measures the core by itself. Inside a shell the same core shares routing and placement with everything else, and its timing margin can move a long way: one tile measured +0.410 ns standalone and −0.348 ns composed, a 0.76 ns swing that turned a pass into a failure. A measurement point answers "what does this core cost on its own", and it is an input to "will this composition close timing". It does not answer the second question. Treat a margin under about half a nanosecond as a risk for the composed build, not as headroom. The registry notes this next to the numbers, since the numbers cannot show it. ## What it costs Measuring a core means synthesizing it across its parameter space on every supported part, which takes real machine time. Until a core has been measured on a part, a design for that part cannot be priced: the estimator raises instead of borrowing another part's number. In exchange, a Kintex build is never priced with an Artix figure.