FPGA · measurement · 2026
Propagation delay vs. die temperature on an FPGA
Two ring oscillators on an Artix-7, one routed through the 3.3 V I/O buffers and one kept inside the 1.0 V core, clock hardware counters while heaters built from the fabric itself warm the die and the XADC reads the temperature back. I built it for the CS 1410 FPGA labs at Harvard SEAS.
- Board
- Opal Kelly XEM7310-A75 (Artix-7 XC7A75T-1FGG484), USB 3.0, USB-powered
- My part
- RTL, constraints, FrontPanel interface, host acquisition and fitting software
- Tools
- SystemVerilog, Vivado 2022.2, Opal Kelly FrontPanel, Python (NumPy, Matplotlib)
- Code
- RTL on GitHub · the host software is kept private
What I was trying to build
Vivado’s timing analysis tells you whether a design closes at the process, voltage and temperature corners it models. It doesn’t show the delay of a particular chip moving as that chip heats up. For the CS 1410 labs I wanted students to measure that shift themselves, on the board on their desk, with nothing but the FPGA, a USB cable and a laptop. So the delay sensor, the heater and the thermometer all had to come from the FPGA itself.
The other constraint shaped most of the design: the lab boards run from USB power alone, with no external supply. Whatever heats the die has to stay inside what a laptop port can deliver, or the board browns out in the middle of a measurement.
System architecture
The host talks to the FPGA through Opal Kelly’s FrontPanel endpoints: three WireIns for control, one TriggerIn to start a measurement, and eight WireOuts for counts, telemetry and status. Everything below the endpoint bus in the diagram is my RTL.
thermolab_top.sv (v2.00). The two rings are the sensors; the heater regions, MMCM and XADC monitor exist to change and observe the die temperature. Every block is an instance in the RTL.How a ring oscillator measures delay
A loop with an odd number of inverting stages has no stable state, so it oscillates. A transition has to go around the loop twice per period, so the period is twice the sum of the stage delays. If every stage gets slower as the die warms, the frequency drops. Counting ring cycles over a fixed window gives that frequency, and its inverse is a delay proxy:
Here N is the number of ring cycles counted, T_window the window length, and T_ref the mean period of the coolest 5 % of samples. The last line is what the host fits against temperature. Normalizing to each board’s own coolest samples removes the absolute frequency, which varies from board to board with process and routing, and leaves the relative change. It also means I never claim the ring period is a single gate’s delay: it’s the whole loop, including routing.
Two rings in two voltage domains
The sensor ring runs through the I/O. Each of its 21 stages is a LUT driving an IOBUF whose output buffer is permanently enabled: the output driver drives the pad, the input buffer reads the same pad straight back, and that feeds the next LUT. The pads are on the MC1 expansion connector (bank 13, 3.3 V) with nothing plugged in, so the loop needs no external wiring. The control ring is the same idea with 33 LUT stages and no pads, so it never leaves the core.
ring_io.sv and ring_lut.sv. Both loops are closed by the same inverting LUT2 gate (O = ~I0 & enable), so disabling a ring parks it at 0. All cells are DONT_TOUCH so synthesis can’t simplify the loop away.The reason for two rings is device physics. Heating a transistor does two things that pull in opposite directions: carrier mobility drops, which slows it down, and the threshold voltage drops, which speeds it up. In the 28 nm core at its nominal 1.0 V the two partly cancel, so a LUT ring’s frequency moves less with temperature than you might expect. The thick-oxide I/O transistors run from 3.3 V, far above the point where the effects balance, so the mobility term wins and their delay rises steadily as the die warms.
The first version of this lab, in June, used only LUT rings (sixteen long LUT-inverter rings per board) and ran into exactly this. On one board every ring slowed by about 0.044 %/°C with R² of 0.97 or better. The same experiment on three more boards gave mean coefficients of 0.011, 0.004 and 0.003 %/°C, with weak fits and single rings going the wrong way:
| Board (June prototype, 16 LUT rings) | Mean delay coefficient | Ring-to-ring range | R² range |
|---|---|---|---|
| 2538001HWN | +0.044 %/°C | +0.037 to +0.047 | 0.97–0.99 |
| 2437001CVS | +0.011 %/°C | +0.005 to +0.014 | 0.63–0.96 |
| 2437001CZF | +0.004 %/°C | −0.002 to +0.006 | 0.32–0.79 |
| 2538001HXW | +0.003 %/°C | −0.002 to +0.007 | 0.02–0.68 |
Those runs were read during heat-up with the heater running, so some of the spread may be supply droop rather than temperature. Either way, a lab where three boards out of four show almost nothing can’t teach the effect, so I moved the sensor out to the I/O. The cost is 21 package pins that must stay unconnected.
The LUT ring shares the window and counting logic with the I/O ring, which makes it a control. If both channels moved by the same amount, I’d suspect the measurement chain before the silicon.
Counting across clock domains
Each ring’s output goes onto a global clock buffer and clocks its own 32-bit counter. The measurement window comes from the FrontPanel clock (okClk, 100.8 MHz from the board’s crystal), which doesn’t care what the die temperature is. That window has to cross into each ring’s clock domain, and the count has to cross back.
(* ASYNC_REG = "TRUE" *) reg [1:0] wsync = 2'd0;
reg wprev = 1'b0;
reg [31:0] cnt = 32'd0;
always @(posedge clk_ring) begin
wsync <= {wsync[0], window_ok};
wprev <= wsync[1];
if (wsync[1] && !wprev)
cnt <= 32'd1; // first counted cycle of the window
else if (wsync[1])
cnt <= cnt + 32'd1;
end
always @(posedge okClk)
if (cap_strobe)
value <= cnt; // quasi-static at this moment
okClk domain. Source: freq_counter.sv.The capture side doesn’t use a handshake or a FIFO. When the window ends, the top level waits 512 okClk cycles (about 5 µs) before pulsing cap_strobe. By then the ring-domain counter has stopped changing, so sampling it from the other domain is safe. The synchronizer costs a cycle or two of uncertainty at each window edge, which is small next to the hundreds of thousands of cycles counted in a 100 ms window.
done rises with the capture and the counts are read from WireOut 0x20 and 0x21.Heating the die from a USB port
The heater is ordinary logic switching as fast as it can. There are three regions. Each has 9,000 toggle cells (a LUT1 inverter feeding its own flip-flop, so every cell flips every cycle) and 40 DSP48 multiply-accumulates fed from an LFSR so the multipliers actually switch. An MMCM multiplies okClk up to 403.2 MHz, and each region gets that clock through its own BUFGCE, so an idle region’s clock tree is off rather than just its logic.
Only one region runs at a time. Pblocks place the three regions in different parts of the die so that a run can heat close to the I/O ring, close to the XADC, or away from both. The power control sits in front of the clock gates:
- Duty. The host requests 0–255. An 8-bit PWM at about 98 kHz gates the region clock, fast enough that the board’s decoupling sees an average load rather than steps.
- Soft start. The applied duty moves one step every 1.3 ms toward the request, so going from off to full takes about a third of a second.
- VCCINT governor. The XADC measures the 1.0 V core supply. Below 0.970 V the governor lowers its duty ceiling by 16 steps every 10.4 ms. Below 0.938 V it drops the duty to zero at once. Recovery is one step per ~42 ms, about 10 s from zero to full.
always_ff @(posedge okClk) begin
if (!heat_ok || vpanic) begin
cap_q <= 8'd0; // hard dump; recover from zero
healthy_cnt <= '0;
end else if (gstep) begin
if (vlow_now) begin
cap_q <= (cap_q > 8'd16) ? cap_q - 8'd16 : 8'd0;
healthy_cnt <= '0;
end else if (cap_q != 8'hFF) begin
healthy_cnt <= healthy_cnt + 1'b1;
if (healthy_cnt == 2'b11) cap_q <= cap_q + 8'd1;
end
end
end
gstep fires every 2²⁰ okClk cycles (10.4 ms). A weak port gives a lower temperature plateau instead of a reset. Source: heater.sv.Telemetry and interlocks
The XADC is instantiated through the XADC Wizard with its DRP port exposed. A small state machine reads temperature and VCCINT alternately, one read every 0.65 ms, with a watchdog that abandons a read if DRDY never comes back. It also counts end-of-conversion pulses and completed DRP reads and reports both to the host, because a frozen ADC otherwise looks exactly like a stable temperature.
The heater only runs when all of these hold:
- the MMCM is locked;
- the XADC has finished a conversion within the last ~125 ms;
- the XADC’s own over-temperature alarm is clear;
- a fabric comparator on the temperature code hasn’t tripped. It sets at 85 °C and clears below 60 °C.
The host adds its own limits on top: it heats toward 78 °C by default and aborts above 82 °C. Conversions use the 7-series transfer functions, T = code × 503.975 / 4096 − 273.15 and V = code × 3 / 4096.
Running an experiment
The host program configures the board, checks the design signature (0x544C0200) so it can’t talk to a mismatched bitstream, and then runs one of three protocols. The default heats one region and records the cooldown:
- Take ten 100 ms windows at ambient as a baseline.
- Step the duty up until the die reaches the target or stops warming.
- Turn the heater off and keep sampling as the die cools.
- Fit the delay change against temperature using the baseline and cooldown samples.
I fit the cooldown rather than the heat-up on purpose. While the heater runs, it loads VCCINT and keeps a steep temperature gradient between the active region and the rest of the die. When it turns off, that gradient collapses within seconds and the board then cools slowly, with no switching load on the supply. That is the clean part of the dataset. The other two modes soak at a staircase of duty levels (averaging several windows per step) or just monitor without heating to measure the noise floor. An option also pauses the heater during each window.
Each sample stores the temperature read just before and just after its window, VCCINT, both counts, the applied duty and the governor state. The fit reports the slope in %/°C, its standard error, R², and a rank correlation.
Results
The clearest run is from August 4, with v2.00 heating region C. The I/O ring ran at about 4.58 MHz and the LUT ring at about 38.5 MHz, which works out to an average of 5.2 ns per stage for the trip through the pad drivers and receivers and 0.39 ns per stage inside the fabric. Over the cooldown from 66 °C to 41 °C:
Data table
Delay change in percent, normalized to the mean of the coolest 5 % of samples.
| XADC die temperature (°C) | I/O ring (21 pads) | LUT ring (33 stages) |
|---|---|---|
| 41.3 | −0.032 | −0.031 |
| 41.4 | −0.036 | −0.021 |
| 41.3 | −0.042 | −0.023 |
| 41.3 | −0.027 | −0.013 |
| 41.2 | −0.023 | −0.005 |
| 41.5 | −0.025 | −0.014 |
| 41.2 | −0.027 | −0.014 |
| 41.3 | −0.021 | −0.001 |
| 41.3 | −0.020 | −0.003 |
| 41.3 | −0.014 | 0.005 |
| 65.8 | 0.956 | 0.013 |
| 60.2 | 0.815 | 0.143 |
| 58.6 | 0.771 | 0.163 |
| 57.5 | 0.732 | 0.168 |
| 56.7 | 0.707 | 0.164 |
| 56.1 | 0.682 | 0.167 |
| 55.8 | 0.663 | 0.160 |
| 55.1 | 0.646 | 0.152 |
| 54.9 | 0.618 | 0.140 |
| 54.5 | 0.616 | 0.156 |
| 54.2 | 0.600 | 0.156 |
| 53.9 | 0.590 | 0.156 |
| 53.8 | 0.591 | 0.153 |
| 53.5 | 0.570 | 0.139 |
| 53.2 | 0.584 | 0.157 |
| 52.9 | 0.564 | 0.147 |
| 53.0 | 0.556 | 0.142 |
| 52.7 | 0.562 | 0.161 |
| 52.4 | 0.528 | 0.127 |
| 52.5 | 0.526 | 0.145 |
| 52.1 | 0.522 | 0.135 |
| 51.9 | 0.519 | 0.146 |
| 51.9 | 0.513 | 0.146 |
| 51.8 | 0.497 | 0.132 |
| 51.7 | 0.496 | 0.132 |
| 51.6 | 0.502 | 0.149 |
| 51.3 | 0.484 | 0.148 |
| 51.3 | 0.493 | 0.144 |
| 51.0 | 0.488 | 0.152 |
| 51.1 | 0.469 | 0.136 |
| 50.8 | 0.456 | 0.121 |
| 50.6 | 0.450 | 0.119 |
| 50.6 | 0.457 | 0.131 |
| 50.6 | 0.467 | 0.137 |
| 50.6 | 0.457 | 0.136 |
| 50.4 | 0.459 | 0.143 |
| 50.2 | 0.454 | 0.139 |
| 50.4 | 0.456 | 0.139 |
| 50.1 | 0.454 | 0.149 |
| 50.1 | 0.444 | 0.143 |
| 50.0 | 0.447 | 0.139 |
| 50.0 | 0.445 | 0.142 |
| 50.0 | 0.442 | 0.141 |
| 49.7 | 0.429 | 0.134 |
| 49.7 | 0.430 | 0.138 |
| 49.6 | 0.420 | 0.133 |
| 49.6 | 0.410 | 0.124 |
| 49.6 | 0.428 | 0.139 |
| 49.4 | 0.429 | 0.143 |
| 49.3 | 0.414 | 0.124 |
| 49.5 | 0.413 | 0.134 |
| 49.2 | 0.411 | 0.144 |
| 49.2 | 0.408 | 0.138 |
| 49.2 | 0.398 | 0.133 |
| 49.1 | 0.388 | 0.124 |
| 49.1 | 0.392 | 0.124 |
| 48.8 | 0.402 | 0.123 |
| 48.9 | 0.381 | 0.125 |
| 49.0 | 0.381 | 0.124 |
| 49.0 | 0.376 | 0.120 |
| 48.8 | 0.374 | 0.120 |
| 48.8 | 0.371 | 0.126 |
| 48.7 | 0.367 | 0.118 |
| 48.6 | 0.358 | 0.106 |
| 48.7 | 0.359 | 0.112 |
| 48.6 | 0.359 | 0.122 |
| 48.5 | 0.354 | 0.115 |
| 48.4 | 0.345 | 0.104 |
| 48.3 | 0.334 | 0.098 |
| 48.4 | 0.342 | 0.112 |
| 48.4 | 0.340 | 0.113 |
| 48.2 | 0.334 | 0.096 |
| 48.2 | 0.338 | 0.114 |
| 48.1 | 0.329 | 0.096 |
| 48.2 | 0.341 | 0.118 |
| 48.1 | 0.326 | 0.093 |
| 47.9 | 0.328 | 0.105 |
| 47.8 | 0.321 | 0.094 |
| 47.9 | 0.318 | 0.096 |
| 47.9 | 0.310 | 0.083 |
| 47.8 | 0.316 | 0.091 |
| 47.9 | 0.299 | 0.081 |
| 47.8 | 0.298 | 0.083 |
| 47.6 | 0.301 | 0.081 |
| 47.7 | 0.312 | 0.097 |
| 47.6 | 0.300 | 0.092 |
| 47.5 | 0.297 | 0.085 |
| 47.4 | 0.298 | 0.091 |
| 47.6 | 0.301 | 0.090 |
| 47.3 | 0.292 | 0.088 |
| 47.3 | 0.300 | 0.090 |
| 47.4 | 0.296 | 0.089 |
| 47.4 | 0.287 | 0.089 |
| 47.3 | 0.280 | 0.074 |
| 47.4 | 0.291 | 0.086 |
| 47.2 | 0.286 | 0.088 |
| 47.3 | 0.282 | 0.078 |
| 47.1 | 0.288 | 0.093 |
| 47.0 | 0.275 | 0.079 |
| 46.9 | 0.278 | 0.087 |
| 47.0 | 0.288 | 0.104 |
| 47.0 | 0.280 | 0.090 |
| 46.9 | 0.275 | 0.076 |
| 46.9 | 0.275 | 0.085 |
| 46.9 | 0.275 | 0.083 |
| 46.9 | 0.270 | 0.091 |
| 46.8 | 0.267 | 0.082 |
| 46.8 | 0.270 | 0.092 |
| 46.8 | 0.260 | 0.088 |
| 46.9 | 0.261 | 0.088 |
| 46.8 | 0.261 | 0.083 |
| 46.7 | 0.261 | 0.078 |
| 46.6 | 0.263 | 0.087 |
| 46.6 | 0.262 | 0.082 |
| 46.6 | 0.263 | 0.082 |
| 46.5 | 0.256 | 0.075 |
| 46.3 | 0.240 | 0.055 |
| 46.5 | 0.236 | 0.053 |
| 46.4 | 0.249 | 0.064 |
| 46.5 | 0.238 | 0.064 |
| 46.3 | 0.256 | 0.083 |
| 46.3 | 0.239 | 0.071 |
| 46.1 | 0.238 | 0.065 |
| 46.1 | 0.235 | 0.060 |
| 46.1 | 0.237 | 0.070 |
| 46.3 | 0.216 | 0.054 |
| 46.0 | 0.231 | 0.081 |
| 46.1 | 0.244 | 0.077 |
| 46.2 | 0.239 | 0.070 |
| 46.1 | 0.231 | 0.068 |
| 46.0 | 0.240 | 0.078 |
| 46.2 | 0.232 | 0.073 |
| 46.2 | 0.226 | 0.056 |
| 46.2 | 0.233 | 0.083 |
| 46.0 | 0.208 | 0.050 |
| 45.9 | 0.219 | 0.051 |
| 46.0 | 0.228 | 0.060 |
| 45.9 | 0.220 | 0.061 |
| 45.8 | 0.212 | 0.058 |
| 46.0 | 0.219 | 0.071 |
| 45.8 | 0.202 | 0.055 |
| 45.8 | 0.210 | 0.064 |
| 45.7 | 0.208 | 0.057 |
| 45.8 | 0.207 | 0.049 |
| 45.7 | 0.207 | 0.055 |
| 45.8 | 0.201 | 0.045 |
| 45.6 | 0.202 | 0.059 |
| 45.7 | 0.200 | 0.047 |
| 45.8 | 0.198 | 0.039 |
| 45.7 | 0.200 | 0.056 |
| 45.5 | 0.199 | 0.069 |
| 45.7 | 0.197 | 0.054 |
| 45.5 | 0.184 | 0.048 |
| 45.3 | 0.181 | 0.041 |
| 45.7 | 0.176 | 0.040 |
| 45.5 | 0.185 | 0.050 |
| 45.5 | 0.188 | 0.049 |
| 45.3 | 0.185 | 0.049 |
| 45.5 | 0.184 | 0.055 |
| 45.5 | 0.188 | 0.060 |
| 45.3 | 0.179 | 0.045 |
| 45.3 | 0.181 | 0.052 |
| 45.3 | 0.183 | 0.052 |
| 45.4 | 0.183 | 0.057 |
| 45.4 | 0.190 | 0.065 |
| 45.3 | 0.173 | 0.051 |
| 45.3 | 0.177 | 0.051 |
| 45.3 | 0.165 | 0.050 |
| 45.3 | 0.180 | 0.060 |
| 45.2 | 0.183 | 0.054 |
| 45.0 | 0.173 | 0.054 |
| 45.0 | 0.179 | 0.059 |
| 45.0 | 0.161 | 0.057 |
| 45.0 | 0.175 | 0.067 |
| 45.0 | 0.168 | 0.069 |
| 44.9 | 0.157 | 0.060 |
| 45.0 | 0.173 | 0.069 |
| 44.9 | 0.160 | 0.061 |
| 45.0 | 0.154 | 0.054 |
| 44.9 | 0.147 | 0.046 |
| 45.0 | 0.157 | 0.045 |
| 44.9 | 0.165 | 0.049 |
| 45.0 | 0.162 | 0.049 |
| 44.8 | 0.158 | 0.039 |
| 44.9 | 0.162 | 0.053 |
| 44.9 | 0.170 | 0.069 |
| 44.9 | 0.159 | 0.056 |
| 44.9 | 0.160 | 0.059 |
| 44.8 | 0.160 | 0.057 |
| 44.9 | 0.170 | 0.058 |
| 44.8 | 0.159 | 0.056 |
| 44.8 | 0.156 | 0.053 |
| 44.7 | 0.164 | 0.061 |
| 44.9 | 0.173 | 0.079 |
| 44.9 | 0.159 | 0.047 |
| 44.7 | 0.168 | 0.051 |
| 44.7 | 0.159 | 0.053 |
| 44.9 | 0.150 | 0.040 |
| 44.5 | 0.160 | 0.050 |
| 44.8 | 0.154 | 0.055 |
| 44.7 | 0.167 | 0.076 |
| 44.5 | 0.159 | 0.061 |
| 44.7 | 0.155 | 0.056 |
| 44.6 | 0.154 | 0.063 |
| 44.5 | 0.153 | 0.053 |
| 44.5 | 0.148 | 0.056 |
| 44.6 | 0.147 | 0.053 |
| 44.6 | 0.144 | 0.053 |
| 44.8 | 0.159 | 0.058 |
| 44.7 | 0.149 | 0.045 |
| 44.4 | 0.158 | 0.050 |
| 44.6 | 0.142 | 0.047 |
| 44.5 | 0.149 | 0.057 |
| 44.5 | 0.151 | 0.051 |
| 44.5 | 0.155 | 0.060 |
| 44.5 | 0.172 | 0.090 |
| 44.5 | 0.146 | 0.059 |
| 44.4 | 0.155 | 0.064 |
| 44.5 | 0.149 | 0.056 |
| 44.4 | 0.154 | 0.066 |
| 44.5 | 0.152 | 0.068 |
| 44.4 | 0.147 | 0.059 |
| 44.5 | 0.148 | 0.065 |
| 44.4 | 0.156 | 0.078 |
| 44.3 | 0.140 | 0.048 |
| 44.2 | 0.138 | 0.054 |
| 44.4 | 0.149 | 0.063 |
| 44.4 | 0.139 | 0.062 |
| 44.4 | 0.134 | 0.057 |
| 44.3 | 0.140 | 0.060 |
| 44.4 | 0.153 | 0.076 |
| 44.4 | 0.133 | 0.056 |
| 44.4 | 0.140 | 0.071 |
| 44.2 | 0.124 | 0.051 |
| 44.4 | 0.140 | 0.063 |
| 44.2 | 0.138 | 0.075 |
| 44.2 | 0.128 | 0.049 |
| 44.2 | 0.143 | 0.071 |
| 44.4 | 0.138 | 0.057 |
| 44.2 | 0.136 | 0.060 |
| 44.3 | 0.138 | 0.066 |
| 44.2 | 0.151 | 0.076 |
The I/O ring slowed by 0.047 % per °C and tracked temperature closely. The LUT ring, measured through the same window and counters, moved a fifth as much and with much more scatter. That gap is the whole point of the two-ring design. The other complete runs agree:
| Run | Samples | Span (°C) | I/O ring (%/°C) | R² | LUT ring (%/°C) | R² |
|---|---|---|---|---|---|---|
| Jul 15, earlier build, 7-pad ring | 231 | 40–76 | +0.044 | 0.97 | +0.008 | 0.56 |
| Aug 4, v2.00, heater C | 252 | 41–66 | +0.047 | 0.98 | +0.010 | 0.66 |
| Sep 2, v2.00, heater B | 91 | 48–66 | +0.042 | 0.99 | +0.002 | 0.08 |
The I/O coefficient lands between 0.042 and 0.047 %/°C in every run, across two ring lengths. The LUT ring’s coefficient never gets above 0.010 %/°C and its fit is weak, which is what a ring near its zero-temperature-coefficient point should look like. A fourth run, heating region A, stopped before the cooldown had any span, so it isn’t included. The runs don’t record the board serial, so I can’t say whether they were on the same board.
The supply held: across the three v2.00 runs VCCINT never dropped below 0.988 V and the governor’s low-voltage flag never set.
Why the fit uses only the cooldown
The heat-up half of the same run shows what the heater does to the measurement. The LUT ring’s delay jumps every time the duty steps up, by about 0.02 % per duty count, reaching about 5 % at full duty. That is a hundred times its temperature coefficient, and it disappears within one sample when the heater turns off, long before the die can cool.
Data table
Time in seconds; delay change in percent.
| Time since the first window (s) | I/O ring | LUT ring |
|---|---|---|
| 0.0 | −0.03 | −0.03 |
| 0.1 | −0.04 | −0.02 |
| 0.2 | −0.04 | −0.02 |
| 0.3 | −0.03 | −0.01 |
| 0.4 | −0.02 | −0.01 |
| 0.5 | −0.03 | −0.01 |
| 0.6 | −0.03 | −0.01 |
| 0.8 | −0.02 | 0.00 |
| 0.9 | −0.02 | 0.00 |
| 1.0 | −0.01 | 0.01 |
| 1.1 | −0.01 | 0.02 |
| 2.2 | 0.10 | 0.51 |
| 3.3 | 0.23 | 1.03 |
| 4.4 | 0.29 | 1.23 |
| 5.5 | 0.30 | 1.23 |
| 6.6 | 0.30 | 1.22 |
| 7.7 | 0.32 | 1.23 |
| 8.8 | 0.32 | 1.22 |
| 9.9 | 0.32 | 1.22 |
| 11.1 | 0.33 | 1.23 |
| 12.2 | 0.33 | 1.22 |
| 13.3 | 0.34 | 1.23 |
| 14.4 | 0.33 | 1.21 |
| 15.5 | 0.34 | 1.23 |
| 16.6 | 0.34 | 1.21 |
| 17.7 | 0.35 | 1.22 |
| 18.8 | 0.35 | 1.23 |
| 19.9 | 0.35 | 1.22 |
| 21.0 | 0.35 | 1.22 |
| 22.1 | 0.51 | 2.03 |
| 23.3 | 0.65 | 2.47 |
| 24.4 | 0.67 | 2.47 |
| 25.5 | 0.67 | 2.47 |
| 26.6 | 0.67 | 2.45 |
| 27.7 | 0.68 | 2.46 |
| 28.8 | 0.69 | 2.46 |
| 29.9 | 0.70 | 2.47 |
| 31.0 | 0.71 | 2.47 |
| 32.1 | 0.72 | 2.49 |
| 33.2 | 0.72 | 2.47 |
| 34.4 | 0.72 | 2.47 |
| 35.5 | 0.72 | 2.47 |
| 36.6 | 0.73 | 2.46 |
| 37.7 | 0.73 | 2.47 |
| 38.8 | 0.74 | 2.48 |
| 39.9 | 0.75 | 2.48 |
| 41.0 | 0.74 | 2.47 |
| 42.1 | 0.73 | 2.46 |
| 43.2 | 0.91 | 3.32 |
| 44.3 | 1.03 | 3.76 |
| 45.4 | 1.05 | 3.75 |
| 46.6 | 1.06 | 3.75 |
| 47.7 | 1.07 | 3.75 |
| 48.8 | 1.08 | 3.75 |
| 49.9 | 1.08 | 3.75 |
| 51.0 | 1.12 | 3.78 |
| 52.1 | 1.12 | 3.76 |
| 53.2 | 1.14 | 3.79 |
| 54.3 | 1.14 | 3.79 |
| 55.4 | 1.14 | 3.77 |
| 56.5 | 1.16 | 3.78 |
| 57.7 | 1.17 | 3.79 |
| 58.8 | 1.17 | 3.79 |
| 59.9 | 1.17 | 3.79 |
| 61.0 | 1.16 | 3.77 |
| 62.1 | 1.17 | 3.79 |
| 63.2 | 1.17 | 3.79 |
| 64.3 | 1.34 | 4.63 |
| 65.4 | 1.47 | 5.08 |
| 66.5 | 1.49 | 5.09 |
| 67.7 | 1.50 | 5.09 |
| 68.8 | 1.51 | 5.07 |
| 69.9 | 1.53 | 5.09 |
| 71.0 | 1.52 | 5.08 |
| 72.1 | 1.54 | 5.08 |
| 73.2 | 1.55 | 5.09 |
| 74.3 | 1.54 | 5.08 |
| 75.4 | 1.57 | 5.10 |
| 76.5 | 1.57 | 5.09 |
| 77.6 | 1.59 | 5.10 |
| 78.7 | 1.60 | 5.10 |
| 79.9 | 1.60 | 5.11 |
| 81.0 | 1.61 | 5.11 |
| 82.1 | 1.62 | 5.11 |
| 83.2 | 1.62 | 5.10 |
| 84.3 | 1.62 | 5.11 |
| 85.4 | 1.64 | 5.13 |
| 86.5 | 1.63 | 5.11 |
| 87.6 | 1.64 | 5.12 |
| 88.7 | 1.64 | 5.12 |
| 89.8 | 1.66 | 5.12 |
| 90.9 | 1.64 | 5.10 |
| 92.1 | 1.65 | 5.12 |
| 93.2 | 1.66 | 5.12 |
| 94.3 | 1.68 | 5.13 |
| 95.4 | 1.68 | 5.14 |
| 96.5 | 1.69 | 5.15 |
| 97.6 | 1.69 | 5.14 |
| 98.7 | 1.69 | 5.14 |
| 99.8 | 1.70 | 5.15 |
| 100.9 | 1.70 | 5.13 |
| 102.0 | 1.71 | 5.15 |
| 103.2 | 1.72 | 5.16 |
| 104.3 | 1.71 | 5.13 |
| 105.4 | 1.72 | 5.14 |
| 106.5 | 1.73 | 5.15 |
| 107.6 | 1.74 | 5.15 |
| 108.7 | 1.74 | 5.16 |
| 109.8 | 1.75 | 5.16 |
| 110.9 | 1.75 | 5.16 |
| 112.0 | 1.74 | 5.16 |
| 113.1 | 1.75 | 5.14 |
| 114.3 | 1.76 | 5.16 |
| 115.4 | 1.76 | 5.16 |
| 116.5 | 1.75 | 5.14 |
| 117.6 | 1.77 | 5.16 |
| 118.7 | 1.77 | 5.16 |
| 119.8 | 1.77 | 5.16 |
| 120.9 | 1.78 | 5.17 |
| 122.0 | 1.78 | 5.17 |
| 123.1 | 1.78 | 5.17 |
| 124.2 | 1.78 | 5.16 |
| 125.3 | 1.80 | 5.17 |
| 126.4 | 1.81 | 5.18 |
| 127.5 | 1.80 | 5.17 |
| 128.7 | 1.80 | 5.18 |
| 129.8 | 1.80 | 5.17 |
| 130.9 | 1.81 | 5.17 |
| 132.0 | 1.80 | 5.16 |
| 133.1 | 1.80 | 5.17 |
| 134.2 | 1.83 | 5.18 |
| 135.3 | 1.84 | 5.19 |
| 136.4 | 1.83 | 5.18 |
| 137.5 | 1.82 | 5.18 |
| 138.6 | 1.82 | 5.17 |
| 139.8 | 1.84 | 5.19 |
| 140.9 | 1.85 | 5.21 |
| 142.0 | 1.84 | 5.18 |
| 143.1 | 1.85 | 5.18 |
| 144.2 | 1.85 | 5.18 |
| 145.3 | 1.85 | 5.18 |
| 146.4 | 1.85 | 5.17 |
| 147.5 | 1.86 | 5.20 |
| 148.6 | 1.87 | 5.21 |
| 149.7 | 1.88 | 5.22 |
| 150.8 | 1.87 | 5.20 |
| 151.9 | 1.86 | 5.18 |
| 153.1 | 1.87 | 5.19 |
| 154.2 | 1.87 | 5.20 |
| 155.3 | 1.88 | 5.20 |
| 156.4 | 1.88 | 5.20 |
| 157.5 | 1.88 | 5.21 |
| 158.6 | 1.87 | 5.20 |
| 159.7 | 1.87 | 5.19 |
| 160.8 | 1.89 | 5.22 |
| 161.9 | 1.89 | 5.21 |
| 163.0 | 1.89 | 5.22 |
| 164.1 | 1.91 | 5.24 |
| 165.2 | 1.90 | 5.23 |
| 166.4 | 1.92 | 5.23 |
| 167.5 | 1.91 | 5.23 |
| 168.6 | 1.91 | 5.22 |
| 169.7 | 1.91 | 5.22 |
| 170.8 | 1.91 | 5.22 |
| 171.9 | 1.91 | 5.22 |
| 173.0 | 1.90 | 5.21 |
| 174.1 | 1.92 | 5.22 |
| 175.2 | 1.92 | 5.22 |
| 176.3 | 1.92 | 5.22 |
| 177.5 | 1.94 | 5.25 |
| 178.6 | 1.93 | 5.23 |
| 179.7 | 1.93 | 5.22 |
| 180.8 | 1.94 | 5.23 |
| 181.9 | 1.94 | 5.22 |
| 183.0 | 1.95 | 5.23 |
| 184.1 | 1.93 | 5.21 |
| 185.2 | 1.93 | 5.21 |
| 186.3 | 1.94 | 5.21 |
| 187.4 | 1.95 | 5.22 |
| 188.5 | 1.93 | 5.21 |
| 189.7 | 1.93 | 5.21 |
| 190.8 | 1.94 | 5.22 |
| 191.9 | 1.93 | 5.20 |
| 193.0 | 1.94 | 5.21 |
| 194.1 | 1.96 | 5.23 |
| 195.2 | 1.94 | 5.21 |
| 196.3 | 1.95 | 5.20 |
| 197.4 | 1.95 | 5.19 |
| 198.5 | 1.97 | 5.22 |
| 199.6 | 1.97 | 5.21 |
| 200.7 | 1.96 | 5.22 |
| 201.8 | 1.98 | 5.23 |
| 203.0 | 1.97 | 5.23 |
| 204.1 | 1.97 | 5.22 |
| 205.2 | 1.98 | 5.22 |
| 206.3 | 1.98 | 5.24 |
| 207.4 | 1.98 | 5.23 |
| 207.5 | 0.96 | 0.01 |
| 208.6 | 0.82 | 0.14 |
| 209.7 | 0.77 | 0.16 |
| 210.8 | 0.73 | 0.17 |
| 211.9 | 0.71 | 0.16 |
| 213.0 | 0.68 | 0.17 |
| 214.1 | 0.66 | 0.16 |
| 215.3 | 0.65 | 0.15 |
| 216.4 | 0.62 | 0.14 |
| 217.5 | 0.62 | 0.16 |
| 218.6 | 0.60 | 0.16 |
| 219.7 | 0.59 | 0.16 |
| 220.8 | 0.59 | 0.15 |
| 221.9 | 0.57 | 0.14 |
| 223.0 | 0.58 | 0.16 |
| 224.1 | 0.56 | 0.15 |
| 225.3 | 0.56 | 0.14 |
| 226.4 | 0.56 | 0.16 |
| 227.5 | 0.53 | 0.13 |
| 228.6 | 0.53 | 0.15 |
| 229.7 | 0.52 | 0.13 |
| 230.8 | 0.52 | 0.15 |
| 231.9 | 0.51 | 0.15 |
| 233.0 | 0.50 | 0.13 |
| 234.1 | 0.50 | 0.13 |
| 235.2 | 0.50 | 0.15 |
| 236.4 | 0.48 | 0.15 |
| 237.5 | 0.49 | 0.14 |
| 238.6 | 0.49 | 0.15 |
| 239.7 | 0.47 | 0.14 |
| 240.8 | 0.46 | 0.12 |
| 241.9 | 0.45 | 0.12 |
| 243.0 | 0.46 | 0.13 |
| 244.1 | 0.47 | 0.14 |
| 245.2 | 0.46 | 0.14 |
| 246.3 | 0.46 | 0.14 |
| 247.4 | 0.45 | 0.14 |
| 248.6 | 0.46 | 0.14 |
| 249.7 | 0.45 | 0.15 |
| 250.8 | 0.44 | 0.14 |
| 251.9 | 0.45 | 0.14 |
| 253.0 | 0.45 | 0.14 |
| 254.1 | 0.44 | 0.14 |
| 255.2 | 0.43 | 0.13 |
| 256.3 | 0.43 | 0.14 |
| 257.4 | 0.42 | 0.13 |
| 258.5 | 0.41 | 0.12 |
| 259.6 | 0.43 | 0.14 |
| 260.7 | 0.43 | 0.14 |
| 261.8 | 0.41 | 0.12 |
| 263.0 | 0.41 | 0.13 |
| 264.1 | 0.41 | 0.14 |
| 265.2 | 0.41 | 0.14 |
| 266.3 | 0.40 | 0.13 |
| 267.4 | 0.39 | 0.12 |
| 268.5 | 0.39 | 0.12 |
| 269.6 | 0.40 | 0.12 |
| 270.7 | 0.38 | 0.13 |
| 271.8 | 0.38 | 0.12 |
| 272.9 | 0.38 | 0.12 |
| 274.0 | 0.37 | 0.12 |
| 275.1 | 0.37 | 0.13 |
| 276.3 | 0.37 | 0.12 |
| 277.4 | 0.36 | 0.11 |
| 278.5 | 0.36 | 0.11 |
| 279.6 | 0.36 | 0.12 |
| 280.7 | 0.35 | 0.12 |
| 281.8 | 0.35 | 0.10 |
| 282.9 | 0.33 | 0.10 |
| 284.0 | 0.34 | 0.11 |
| 285.1 | 0.34 | 0.11 |
| 286.2 | 0.33 | 0.10 |
| 287.3 | 0.34 | 0.11 |
| 288.4 | 0.33 | 0.10 |
| 289.6 | 0.34 | 0.12 |
| 290.7 | 0.33 | 0.09 |
| 291.8 | 0.33 | 0.11 |
| 292.9 | 0.32 | 0.09 |
| 294.0 | 0.32 | 0.10 |
| 295.1 | 0.31 | 0.08 |
| 296.2 | 0.32 | 0.09 |
| 297.3 | 0.30 | 0.08 |
| 298.4 | 0.30 | 0.08 |
| 299.5 | 0.30 | 0.08 |
| 300.7 | 0.31 | 0.10 |
| 301.8 | 0.30 | 0.09 |
| 302.9 | 0.30 | 0.09 |
| 304.0 | 0.30 | 0.09 |
| 305.1 | 0.30 | 0.09 |
| 306.2 | 0.29 | 0.09 |
| 307.3 | 0.30 | 0.09 |
| 308.4 | 0.30 | 0.09 |
| 309.5 | 0.29 | 0.09 |
| 310.6 | 0.28 | 0.07 |
| 311.7 | 0.29 | 0.09 |
| 312.9 | 0.29 | 0.09 |
| 314.0 | 0.28 | 0.08 |
| 315.1 | 0.29 | 0.09 |
| 316.2 | 0.28 | 0.08 |
| 317.3 | 0.28 | 0.09 |
| 318.4 | 0.29 | 0.10 |
| 319.5 | 0.28 | 0.09 |
| 320.6 | 0.28 | 0.08 |
| 321.7 | 0.28 | 0.09 |
| 322.8 | 0.28 | 0.08 |
| 323.9 | 0.27 | 0.09 |
| 325.1 | 0.27 | 0.08 |
| 326.2 | 0.27 | 0.09 |
| 327.3 | 0.26 | 0.09 |
| 328.4 | 0.26 | 0.09 |
| 329.5 | 0.26 | 0.08 |
| 330.6 | 0.26 | 0.08 |
| 331.7 | 0.26 | 0.09 |
| 332.8 | 0.26 | 0.08 |
| 333.9 | 0.26 | 0.08 |
| 335.0 | 0.26 | 0.08 |
| 336.1 | 0.24 | 0.06 |
| 337.2 | 0.24 | 0.05 |
| 338.4 | 0.25 | 0.06 |
| 339.5 | 0.24 | 0.06 |
| 340.6 | 0.26 | 0.08 |
| 341.7 | 0.24 | 0.07 |
| 342.8 | 0.24 | 0.07 |
| 343.9 | 0.24 | 0.06 |
| 345.0 | 0.24 | 0.07 |
| 346.1 | 0.22 | 0.05 |
| 347.2 | 0.23 | 0.08 |
| 348.3 | 0.24 | 0.08 |
| 349.4 | 0.24 | 0.07 |
| 350.5 | 0.23 | 0.07 |
| 351.7 | 0.24 | 0.08 |
| 352.8 | 0.23 | 0.07 |
| 353.9 | 0.23 | 0.06 |
| 355.0 | 0.23 | 0.08 |
| 356.1 | 0.21 | 0.05 |
| 357.2 | 0.22 | 0.05 |
| 358.3 | 0.23 | 0.06 |
| 359.4 | 0.22 | 0.06 |
| 360.5 | 0.21 | 0.06 |
| 361.6 | 0.22 | 0.07 |
| 362.7 | 0.20 | 0.06 |
| 363.9 | 0.21 | 0.06 |
| 365.0 | 0.21 | 0.06 |
| 366.1 | 0.21 | 0.05 |
| 367.2 | 0.21 | 0.06 |
| 368.3 | 0.20 | 0.05 |
| 369.4 | 0.20 | 0.06 |
| 370.5 | 0.20 | 0.05 |
| 371.6 | 0.20 | 0.04 |
| 372.7 | 0.20 | 0.06 |
| 373.8 | 0.20 | 0.07 |
| 375.0 | 0.20 | 0.05 |
| 376.1 | 0.18 | 0.05 |
| 377.2 | 0.18 | 0.04 |
| 378.3 | 0.18 | 0.04 |
| 379.4 | 0.19 | 0.05 |
| 380.5 | 0.19 | 0.05 |
| 381.6 | 0.19 | 0.05 |
| 382.7 | 0.18 | 0.06 |
| 383.8 | 0.19 | 0.06 |
| 384.9 | 0.18 | 0.05 |
| 386.1 | 0.18 | 0.05 |
| 387.2 | 0.18 | 0.05 |
| 388.3 | 0.18 | 0.06 |
| 389.4 | 0.19 | 0.07 |
| 390.5 | 0.17 | 0.05 |
| 391.6 | 0.18 | 0.05 |
| 392.7 | 0.17 | 0.05 |
| 393.8 | 0.18 | 0.06 |
| 394.9 | 0.18 | 0.05 |
| 396.0 | 0.17 | 0.05 |
| 397.2 | 0.18 | 0.06 |
| 398.3 | 0.16 | 0.06 |
| 399.4 | 0.18 | 0.07 |
| 400.5 | 0.17 | 0.07 |
| 401.6 | 0.16 | 0.06 |
| 402.7 | 0.17 | 0.07 |
| 403.8 | 0.16 | 0.06 |
| 404.9 | 0.15 | 0.05 |
| 406.0 | 0.15 | 0.05 |
| 407.2 | 0.16 | 0.05 |
| 408.3 | 0.17 | 0.05 |
| 409.4 | 0.16 | 0.05 |
| 410.5 | 0.16 | 0.04 |
| 411.6 | 0.16 | 0.05 |
| 412.7 | 0.17 | 0.07 |
| 413.8 | 0.16 | 0.06 |
| 414.9 | 0.16 | 0.06 |
| 416.0 | 0.16 | 0.06 |
| 417.1 | 0.17 | 0.06 |
| 418.2 | 0.16 | 0.06 |
| 419.4 | 0.16 | 0.05 |
| 420.5 | 0.16 | 0.06 |
| 421.6 | 0.17 | 0.08 |
| 422.7 | 0.16 | 0.05 |
| 423.8 | 0.17 | 0.05 |
| 424.9 | 0.16 | 0.05 |
| 426.0 | 0.15 | 0.04 |
| 427.1 | 0.16 | 0.05 |
| 428.2 | 0.15 | 0.06 |
| 429.3 | 0.17 | 0.08 |
| 430.5 | 0.16 | 0.06 |
| 431.6 | 0.16 | 0.06 |
| 432.7 | 0.15 | 0.06 |
| 433.8 | 0.15 | 0.05 |
| 434.9 | 0.15 | 0.06 |
| 436.0 | 0.15 | 0.05 |
| 437.1 | 0.14 | 0.05 |
| 438.2 | 0.16 | 0.06 |
| 439.3 | 0.15 | 0.05 |
| 440.5 | 0.16 | 0.05 |
| 441.6 | 0.14 | 0.05 |
| 442.7 | 0.15 | 0.06 |
| 443.8 | 0.15 | 0.05 |
| 444.9 | 0.16 | 0.06 |
| 446.0 | 0.17 | 0.09 |
| 447.1 | 0.15 | 0.06 |
| 448.2 | 0.16 | 0.06 |
| 449.3 | 0.15 | 0.06 |
| 450.4 | 0.15 | 0.07 |
| 451.5 | 0.15 | 0.07 |
| 452.6 | 0.15 | 0.06 |
| 453.7 | 0.15 | 0.07 |
| 454.9 | 0.16 | 0.08 |
| 456.0 | 0.14 | 0.05 |
| 457.1 | 0.14 | 0.05 |
| 458.2 | 0.15 | 0.06 |
| 459.3 | 0.14 | 0.06 |
| 460.4 | 0.13 | 0.06 |
| 461.5 | 0.14 | 0.06 |
| 462.6 | 0.15 | 0.08 |
| 463.7 | 0.13 | 0.06 |
| 464.8 | 0.14 | 0.07 |
| 465.9 | 0.12 | 0.05 |
| 467.1 | 0.14 | 0.06 |
| 468.2 | 0.14 | 0.08 |
| 469.3 | 0.13 | 0.05 |
| 470.4 | 0.14 | 0.07 |
| 471.5 | 0.14 | 0.06 |
| 472.6 | 0.14 | 0.06 |
| 473.7 | 0.14 | 0.07 |
| 474.8 | 0.15 | 0.08 |
The XADC’s VCCINT reading moved by only about 5 mV through all of this, so whatever slows the ring is local to the fabric or faster than the XADC’s averaged reading. I don’t know which yet. The I/O ring shows a smaller version of the same steps, probably because each of its stages also has a LUT in the core. Both effects are gone in the cooldown, which is why the fit uses only those samples and why the lab has an option to pause the heater during each window.
Where the noise is
At a 100 ms window one count of the I/O ring is 2.2 ppm of its frequency, but the scatter about the fit is about 200 ppm, or roughly 0.4 °C of equivalent temperature. So the counter isn’t the limit. The XADC reads temperature in steps of 0.12 °C, and it measures the die at its own location rather than at the pads, so the thermometer and its distance from the sensor are the more likely sources.
Implementation
The September build of v2.00 placed and routed on the XC7A75T with the heater regions taking most of the fabric:
| Resource | Used | Available | Utilization |
|---|---|---|---|
| Slice LUTs | 30,797 | 47,200 | 65.3 % |
| Slice registers | 34,151 | 94,400 | 36.2 % |
| DSP48E1 | 120 | 180 | 66.7 % |
| BUFGCTRL | 7 | 32 | 21.9 % |
| XADC | 1 | 1 | 100 % |
Timing closed with +0.208 ns worst setup slack and +0.068 ns worst hold slack across 3,175 endpoints, with the ring clocks constrained at 50 MHz for analysis. The methodology report still flags two critical warnings about clock definitions and a handful of unconstrained endpoints, so positive slack here doesn’t mean every path is covered. Vivado’s vectorless power estimate for the routed design is 2.3 W on-chip, which it marks as low confidence.
Testing the lab’s boards
Before any of this could run in a lab section, the boards had to work. I wrote a go/no-go design and a test station for the lab’s XEM7310s. The test bitstream echoes a WireIn back on a WireOut, runs a free-running counter on a second WireOut, and drives the eight LEDs; a second bitstream reads the XADC. The station, a small Tk app in Python, programs each board it finds, checks that the counter advances between two reads, walks ten patterns through the loopback, asks the operator to confirm the LEDs, checks that the die temperature is plausible, and logs every result against the board’s serial number. On the Windows lab machines, a PowerShell script attaches each board to WSL through usbipd as it’s plugged in.
Over June 23 and 25 it tested 60 boards, and all 60 passed. It doesn’t test the on-board DDR3, the expansion connectors, the transceivers or FrontPanel pipes, and the report I wrote for the lab lists those gaps. The loopback design and its Python check are on GitHub.