Repository navigation
Conversation
emblink/nordic_ppk2 from Nordic's PPK2 user guide (section 8): as a source meter it powers the board (0.8 to 5.0 V, at most 600 mA, then holds 600 mA as its output falls), as an ampere meter it sits in series with the board's own supply. The current into the board is sampled at 100 kS/s, each sample the 10 us average at the resolution of the range it falls in (0.2, 0.5, 5, 50, 1000 uA for the five ranges, switched by themselves); negative currents read 0. Its logic port samples D0-D7 at 100 kHz on the same grid. It is a composite of its measurement core (emblink/ppk2_core, the new power_profiler primitive, samples completed lazily so a quiet island costs nothing) and its logic port (emblink/ppk2_logic_port, the logic analyzer's sampler at a fixed rate). instrument.read gives its samples (kind: power). The Run perspective's panel shows it as Nordic's Power Profiler app does: Start/Stop, mode and supply voltage, the current followed live, the window's or A-B selection's average, peak and charge, the logic port underneath, CSV export. Evidence: six fixtures on the core and one on the kit, and tests/protocol/test_power_profiler.py (a load sleeping at 1 mA and waking for 1 ms every 10 ms at 101 mA: 5000 samples in 50 ms at their ranges' resolution, a 10 % duty, an 11.00 mA average, D0's edges where the current steps); powerCapture.test.ts; the gallery.
… trigger, Auto/Normal/Single, live screen The scope loads the circuit through its probe (1x or 10x), samples at the DS1054Z's rate for the channels on (1 GSa/s with one, 500 MSa/s with two, 250 MSa/s with three or four) over its 12/6/3 Mpts memory, applies DC, AC (5 Hz) or GND coupling and the 50 MHz (20 MHz limited) bandwidth, and quantises to 8 bits at 25 codes a division. The edge trigger takes source, level, slope and holdoff; Auto forces a sweep when no trigger comes, Normal waits, Single stops after one acquisition and re-arms on Run. instrument.read returns the acquisition (kind "scope"); the workbench shows it on a 12x8 graticule with the front panel's controls and the automatic measurements.
…Run or floating The inspector's Open front panel (and the palette's Open, Float and Dock commands) shows a DS1054Z's, PPK2's or Logic 8's panel: unfolded and focused in the Run perspective's dock, or brought forward where it floats. Float moves a panel into a window over every perspective, moved and resized by pointer or keyboard and remembered across sessions; Dock puts it back. revealDockItem in the design system unfolds a dock item wherever it lives.
…oes its state setup_devices zeroes every device's state before its setup runs, which lost the pointer to the DS1054Z's history ring (and could the PPK2's sample ring) allocated outside the island's allocator: LeakSanitizer found 6 MB leaked per scope fixture in CI's asan job. The rings are freed first; a reset clears the capture and the next sample allocates them again.
…ext menu and the bench's parts list Right-clicking a DS1054Z, PPK2 or Logic 8 on the schematic offers Open front panel; selecting one in the bench's On the bench list does too. Both go to the panel docked in Run or bring its floating window forward.
…atus badges' contrast The front-panels spec runs axe-core in the browser on the DS1054Z's panel docked in Run and floating over Design, with layout, so contrast is checked. It found the STOP badge (white on #d9534f, 4.0:1) and the AUTO badge (white on #4a90d9, 3.5:1) below WCAG's 4.5:1; they are #b52b27 (6.3:1) and #2a6db5 (5.3:1) now.
docs/user/instruments.md: wiring the Logic 8, the PPK2 and the DS1054Z (each lead's load), opening and floating their front panels, what each panel measures and how (the rate limits, the 10 us windows and ranges, the scope's rate by channels, the measurements on the screen's points), and instrument.read for scripts. Linked from docs/README.md.
…ight accent and measurement labels' contrast The front-panels spec checks the DS1054Z, Logic 8 and PPK2 panels, docked and floating, in light and dark, with axe-core in the browser (the demo session gains stand-in entries for the Logic 8 and the PPK2). Fixed what it found: the light theme's accent (white on #0e8a66, 4.33:1) is #0c7f5e (4.98:1), and the measurement strip's labels use --text-muted instead of --text-faint.
docs/engineering/timing-fidelity.md: what is sound (picosecond time, exact rational clocks, deterministic ordering, on-chip peripherals following the core cycle by cycle, the AVR exact) and the gaps that matter to measuring an RTOS context switch: Cortex-M exception entry, return and tail-chaining charge no cycles (ARM DDI 0439B 3.9.1 gives 12, 12 and 6), no late arrival, FP-frame or abandoned-divide timing, a fixed pipeline refill, one M4 table for the M0+ and M3, no flash wait states or ART, DWT with CYCCNT only, no measurement instrument, no performance benchmark. The levels (functional, estimated, cycle-exact for a stated scope, electrical) and what each target aims for; the eight steps.
…e the TRM's cycles On ARMv7-M an exception's entry charges 12 cycles, its return 12 and a tail-chain 6 in place of both (ARM DDI 0439B 3.9.1, zero wait states); they cost nothing before. The entry's cycles pass before the exception is chosen, so an interrupt that becomes pending while a frame is stacked and outranks the one being entered takes the frame, the other then tail-chaining (late arrival). DWT.CYCCNT counts them; exc_cycles totals them. tests/unit/test_cm_timing.c times an entry, a tail-chain and a return, and SysTick firing at each cycle of an IRQ's stacking. Not charged, for want of a documented figure: the FP extended frame and lazy stacking, wait states on stacking and the vector fetch, an interrupt during unstacking, and ARMv6-M. The MCUs' timed fidelity and timing-fidelity.md 4.1 say so.
… FreeRTOS's context switch core/mcu/latency.c, an analysis beside the profile and the stacks: each --measure [NAME=]FROM..TO gives, each time it happens, the cycles and the simulated picoseconds between two boundaries: an instruction at a symbol or address starting, an exception taken (exc:N), an exception becoming pending (pend:N, a hook in the Cortex-M's NVIC) or an exception's return done (ret:N). Time is the core's cycles at the clock that ran them, exactly; the host's wall time is reported apart. The analysis observes and adds no cycle to the firmware. An ARMv7-M return's cycles are now a step of their own, so an instruction's start is stamped after them. tests/vendor/freertos/run.py measures the unmodified FreeRTOS V11.1.0 on the NUCLEO-F446RE at 16 MHz: the tick averages exactly 16000 cycles; each context switch (pend:PendSV..ret:PendSV, 155-167 cycles) equals its request latency plus PendSV's entry to return, sample by sample; two runs measure the same.
…enchmark of fixed workloads An island was settled only when a step moved no unknown by more than 1e-14 relative, so an RC tail (the NUCLEO-F446RE's reset capacitor charging through its pull-up) kept the board's supply island awake for about 130 ms of each run, every step cut at the running core's 1 us quantum: 95% of the host time of a FreeRTOS run. Settled is now no node voltage moving by more than vntol (1 uV) and no branch current by more than abstol (1 pA), what Newton's convergence test resolves; reltol is left out so a slow ramp toward a threshold still steps. FreeRTOS on the NUCLEO runs at 0.23x real time instead of 0.07x, its measured context switch unchanged; all tests, the catalog's fixtures and the ngspice references pass unchanged. tools/perf/bench_mcu.py: example projects and FreeRTOS run headless for a fixed simulated time, simulated and host time reported apart; the results and what is still slow are in timing-fidelity.md 4.4.
…he SIO's single-cycle I/O port The RP2040's cores were charged the Cortex-M4's table. esk_cm0p_cost takes the Cortex-M0+ TRM's Table 3-1 (ARM DDI 0484C): loads and stores 2 cycles on AHB-Lite and 1 on the single-cycle I/O port (the RP2040's 0xd0000000 segment, its datasheet 2.3.1), a taken branch 2, BL 3, POP with PC 3+N, MRS/MSR and barriers 3, MULS 1 for the RP2040's fast multiplier (datasheet 2.4). An exception's entry takes the TRM's worst-case 15 cycles (3.4, datasheet 2.4), with late arrival; the return and tail-chain have no figure in either and are not charged. tests/unit/test_cm_timing.c times each class, an IOPORT load and store, and the entry.
flash_f4.c times the flash's read interface from FLASH_ACR: 128-bit lines read in LATENCY + 1 cycles (Table 5); a fetch from the line executing waits nothing; PRFTEN's prefetch of the next line, ready LATENCY + 1 cycles after the current one arrived; ICEN's 64-line LRU instruction cache, filled on a miss; a miss's LATENCY cycles (RM0390's least); a literal read through D-Code waits LATENCY unless DCEN's 8-line data cache holds its line; ICRST and DCRST empty the caches. The machine's ftime hook, keyed by the flash's memory so the boot alias counts, gives the core each fetch's and data read's stall. test_flash_read_timing: RM0390 Figure 4 (3 WS, sequential 32-bit instructions: 7 cycles a line without prefetch, 4 with it), 5 WS with prefetch (6 a line), a two-line loop with and without ICEN, a literal with and without DCEN, 0 WS. FreeRTOS at 16 MHz is unchanged.
…dump latency.c records each instruction start (with its function), and each exception pending, taken and returned, with its cycle and simulated time, stamped at the measurements' boundaries. --trace FILE writes a table, or with .vcd a value change dump at 1 ps (pc, the exception active, the last pended, the cycle count) for GTKWave and other viewers; --trace-start BOUNDARY and --trace-limit N bound it. tests/vendor/freertos/run.py checks that the traced first context switch, pend to ret, equals the measurement's first sample.
ARM DDI 0337E (r1p1) 5.5 and 5.6 give a 12-cycle interrupt latency and a 6-cycle tail-chain, the figures the M3 was charged from the M4 TRM. It gives no return figure, so the return's 12 stays the M4 TRM's; the F103's timed fidelity and timing-fidelity.md say so.
The RC filter's time is its two 1 MHz probes' exact solves (10.6x real time with 10 kHz probes); interpolated probes would no longer report the solver's solution, so the cost stays. The RP2040's is its two cores' code (25 analog steps a second); FreeRTOS's first 50 ms is the reset RC really moving.
…d time host-independent Contact bounce is on by default on push buttons and toggle switches. R, C and L carry IEC 60062 tolerances, drawn per instance from settings.seed and the instance's id. settings.imperfections "ideal" labels ideal parts. The run report's snapshot.drawn lists the drawn values. examples/button-bounce shows the chatter and an RC with a Schmitt inverter curing it. The Blue Pill gains its 100 nF NRST capacitor. The Uno's DTR auto-reset is a bounce-free part of its own. EmbSIM's own firmware debounces its buttons. Tests and examples that check exact values declare their parts exact, each with its reason. A session reset stops the analog islands before the models reset. A stale crossing of the previous run no longer leaks into the next one, so a replay matches a recording begun mid-run (test_reset_is_load). Islands take a step boundary on a 1 ms simulated grid, and paced slices end on it, so a sliced run equals an uncut one bit for bit (test_grid_slices). The vendor expectations follow the cycle-accurate cores: EEPROM_Emulation ends near 15.6 s; the Pico's polls and PWM wraps follow the M0+'s costs.
With the boards' EN parts drawn inside their tolerances, they boot a few microseconds apart. When the peer's broadcast comes second in a round, the example's handshake takes one round more, and its first unicast arrives at 7.48 s instead of 6.48 s, as on real boards. 10 s covers both orders; checked with five seeds and with ideal parts.
A two-row header (navigation, then the simulation bar) with the state named in words and an icon, simulated time apart from the host rate, a status bar led by the simulation, a connection screen in place of an empty perspective, and a Settings page (language, theme, text size, density, layout restore and reset, time unit, decimals, rate format) applied at once and kept between sessions. Shell strings come from typed English and French catalogs with English fallback. Design tokens gain state and value colours and a scale for text size and density. The before screenshots and the capture script are in the gallery.
…the pin under the pointer Every perspective's panel titles, tabs, toolbars, menus, context actions, dialogs, empty states and toasts come from the catalogs, with French for each. The shared packages (canvas, instruments, dock, command palette, dialogs) take their words through uiText in @embsim/design, which the application feeds with its catalog's pkg.* messages. Library categories are translated; part names, catalog descriptions, net, pin and register names stay as written. A language change rebuilds the perspectives; the layout, project and session are kept. A pointer going down on a pin now starts the wire from that pin, rather than from the pin nearest within 12 units: a click on the edge of a terminal's target used to fall through to the sheet (the visual-language spec on macOS and Windows, whose fonts move the pin label's box). The Debug registers read as one row (name, hex, decimal); Verify's panes no longer repeat their panel's title. New e2e spec: settings apply at once and persist, and the workbench in French.
…ccount, settings and language docs The same twelve workflows after the redesign, in English and in French, beside the before set in the gallery. docs/engineering/visual-benchmark.md gives the review, what changed, the design system, the default workspaces, the settings, the languages, how it was verified and the limits; the workspace guide explains the readout, Settings and the language. Debug's register table alone is sized to its content, so the source and disassembly keep their full-width rows. The capture script takes --settings for text size and density.
The jumper tool names a contact within 11 screen pixels; the measure tool snapped only within 1.5 mm of the surface it hit. On a smaller bench canvas (the new header) a click the jumper tool would call R2.1 measured from a breadboard hole instead (bench-tools.spec on CI). Both now pick the contact the same way.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This PR adds the last two bench instruments and their front panels. It also carries the timing-fidelity work the owner asked for on 2026-11-01, which comes before any release.
docs/engineering/timing-fidelity.mdholds the audit, the accuracy model, the plan, and what each change validates. It ends with the Visual Benchmark v0.1 redesign of the workbench, with settings and English and French (docs/engineering/visual-benchmark.md).Bench instruments
emblink/nordic_ppk2), from the PPK2 user guide §8:emblink/rigol_ds1054z), from the DS1000Z guide ch. 18:docs/user/instruments.md.Timing fidelity
Audit and accuracy model. Four levels (functional, estimated, cycle-exact for a stated scope, electrical), and the level each target is held to.
ARMv7-M exceptions (F446, F103, nRF52840):
Cortex-M0+ (RP2040) from its own TRM (DDI 0484C Table 3-1), instead of the M4's table:
POP {.., PC}3+N;The return and tail-chain have no published figure, so they are not charged, and the fidelity says so.
STM32F4 flash and ART accelerator (RM0390 §3.4):
test_flash_read_timingcovers RM0390 Figure 4's prefetch case, 5 wait states, a cached loop and cached literals.Measurements.
run --measure FROM..TOgives cycles and simulated picoseconds between boundaries: a symbol or address starting,exc:N,pend:Norret:N. Host wall time is reported apart, and the measurement adds no cycles to the firmware. On FreeRTOS V11.1.0 on the NUCLEO-F446RE at 16 MHz,pend:PendSV..ret:PendSVmeasures 155–167 cycles.Traces.
run --trace FILErecords each instruction, and each exception pending, taken and returned, with cycle and simulated time. It writes a table, or a.vcdwaveform for GTKWave and similar viewers.Speed.
tools/perf/bench_mcu.pyreports simulated and host time apart.Imperfections on by default (ADR-034)
settings.seed;settings.imperfections: "ideal"gives ideal parts.examples/button-bounceshows the chatter and its RC and Schmitt cure.test_reset_is_load). Paced slices end on a 1 ms grid, so a sliced run equals an uncut one (test_grid_slices).Visual Benchmark v0.1: the workbench redesigned
Two-row header: navigation (project, perspectives, diagnostics, Settings, commands), then the simulation bar (transport, readout, speed, fidelity, undo).
Readout: the state is named in words with an icon (running, paused, stopped, loading, failed, disconnected), never by colour alone. Simulated time is shown apart from the measured Host rate, which reads "—" when nothing is measured.
Status bar: leads with the simulation, then errors and warnings, with the engine connection last. A connection screen with Reconnect replaces the perspective when the engine is gone.
Settings (Ctrl+,):
Each is applied at once and persisted.
English and French from typed catalogs, with English fallback. The shared packages take their words through
uiText. Technical identifiers, catalog data, engine diagnostics and front-panel legends stay as written.Design system: tokens for state and value colours, a text-size scale and compact density. Panels, ribbons, library rows, controls, meters and registers are brought onto them, with no overflow at 768 px.
Fixed: a pointer going down near the edge of a pin's target started no wire. The pin was looked up by distance; the pin under the pointer is now taken.
Gallery: the same twelve workflows before, after, and in French in
docs/gallery/visual-benchmark-v0.1.Evidence
dev, plus the changed areas onci-clang,ci-tccandasan. They includetest_cm_timing(ARMv7-M and M0+) andtest_flash_read_timing. All 640 catalog fixtures pass with their ngspice references.i18n.test.ts: key parity, placeholders, plural pairs.e2e/settings-language.spec.ts: settings applied and kept over a reload; the workbench in French without overflow; back to English.workspace-layout.spec.tsat 1440, 900 and 768 px.check_docs,check_bannedandtools/validate.pyare clean.Not yet