Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
6f996a3
Instruments: the Nordic Power Profiler Kit II
teo1747 Oct 31, 2026
bb5dd81
Add the Rigol DS1054Z oscilloscope: four 1 MOhm || 15 pF inputs, edge…
teo1747 Oct 31, 2026
b54b077
Merge remote-tracking branch 'origin/main' into claude/affectionate-a…
teo1747 Oct 31, 2026
3c0591c
Workbench: instrument front panels opened from their part, docked in …
teo1747 Oct 31, 2026
8781d54
Analog engine: free an instrument's capture memory before a reset zer…
teo1747 Oct 31, 2026
70d0e70
Workbench: open an instrument's front panel from the schematic's cont…
teo1747 Oct 31, 2026
097308e
Workbench: axe on the scope's docked and floating front panel; the st…
teo1747 Oct 31, 2026
f9d039e
Docs: the bench instruments' user guide
teo1747 Nov 1, 2026
e15d377
Workbench: axe on all three instruments' panels in both themes; the l…
teo1747 Nov 1, 2026
927f59c
Timing fidelity: the audit, the accuracy model per target, and the plan
teo1747 Nov 1, 2026
111d1dd
Cortex-M: exception entry, return, tail-chaining and late arrival tak…
teo1747 Nov 1, 2026
649572b
Timing: measurements between boundaries (run --measure), validated on…
teo1747 Nov 1, 2026
83b5443
Speed: analog islands settle at the solver's absolute tolerances; a b…
teo1747 Nov 1, 2026
fcd1ccf
Cortex-M0+ (RP2040): instruction and entry cycles from its own TRM, t…
teo1747 Nov 1, 2026
acdb5f8
STM32F4: the flash's wait states and the ART accelerator (RM0390 3.4)
teo1747 Nov 1, 2026
57db4f8
Timing: execution traces (run --trace), as a table or a value change …
teo1747 Nov 1, 2026
ab545b5
STM32F103: the Cortex-M3 TRM confirms the entry and tail-chain cycles
teo1747 Nov 1, 2026
d40bbbe
Timing docs: the remaining slow workloads, measured and explained
teo1747 Nov 1, 2026
5bd1b2f
Imperfections on by default (ADR-034); a reset is a fresh start; pace…
teo1747 Nov 1, 2026
a824fd6
test_analog includes string.h for memcmp; the gallery's button-bounce…
teo1747 Nov 1, 2026
98d2304
ESP-NOW scenario: 10 s, for either board's broadcast coming first
teo1747 Nov 1, 2026
7594733
Workbench: Visual Benchmark v0.1 shell, settings page and English/French
teo1747 Nov 1, 2026
47a2854
Workbench: the perspectives in English and French; a pin click takes …
teo1747 Nov 1, 2026
6ae4df7
Visual Benchmark v0.1: after screenshots in English and French, the a…
teo1747 Nov 1, 2026
1b75303
Bench: the measure tool takes the contact the pointer names
teo1747 Nov 1, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
229 changes: 229 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,235 @@ versions follow semantic versioning. There is no release yet.

## Unreleased

### Workbench: Visual Benchmark v0.1, settings, English and French

- A two-row header: navigation (project, the four perspectives, diagnostics,
Settings, commands), then the simulation bar (transport, readout, speed,
fidelity, undo). The readout names the state in words and an icon
(running, paused, stopped, loading, failed, disconnected) and shows
**Simulated** time apart from the **Host** rate, which is measured or "—".
- The status bar leads with the state and simulated time, then the project,
timing tiers, error and warning counts, the engine connection last; it
scrolls on a narrow window. A connection screen replaces the perspective
while connecting and when the engine is gone, with Reconnect.
- A Settings page (Ctrl+,): language, theme, text size, density, restore
and reset panel layout, time unit, time precision, host-rate format,
restore defaults; applied at once and kept between sessions.
- The interface in English and French from typed catalogs (`src/i18n`),
English as the fallback; the shared packages take their words through
`uiText` in `@embsim/design`. Technical identifiers, catalog data, the
engine's diagnostics and the instruments' front-panel legends stay as
written.
- Design tokens for state and value colours, a text-size scale and compact
density; panels, titles, ribbons, library rows, controls, meters and
tables brought onto them. Debug's registers read as rows; Verify's panes
no longer repeat their titles. Nothing overflows 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. On the 3D bench, the measure tool takes the contact the
pointer names, as the jumper tool does, instead of snapping only within
1.5 mm of the surface hit.
- `docs/engineering/visual-benchmark.md` gives the review, the design
system, the default workspaces, the verification and the limits; the
gallery has the same twelve workflows before, after and in French.

### Imperfections: contact bounce and tolerances on by default (ADR-034)

- Push buttons and toggle switches bounce by default, as real contacts do
(2 ms and 5 ms; `"bounce": false` gives an ideal contact). The keypad
already did.
- Resistors, capacitors, electrolytics and inductors gain a `tolerance`
(IEC 60062's J, K, M and M grades: 5, 10, 20 and 20 %). Each part's value
is drawn inside that band from the project's `settings.seed` and the
instance's id, so a run is the same on every host and two parts of one
project differ. A catalog parameter names its tolerance with `spread`.
- `settings.imperfections: "ideal"` gives nominal values and no bounce, for
a lesson that says so (Q17). Component fixtures run ideal unless they name
their `settings`.
- The run report's `snapshot.drawn` lists each drawn value with its nominal
value and tolerance.
- The Blue Pill gains its 100 nF NRST capacitor. It filters the reset
button's bounce and delays the boot by about 0.8 ms after power-up.
- The Uno's DTR auto-reset is its own bounce-free part (`DTR_RESET`), not a
press of the reset button.
- `examples/button-bounce` shows a raw button line chattering and an RC
with a Schmitt inverter debouncing it.
- Firmware written for EmbSIM's own tests and examples now debounces its
buttons in software: the NUCLEO-F446ZE example, and the Arduino, STM32F1
HAL, Pico SDK and nrfx tours.
- Examples and tests that check exact values declare their parts exact,
each with the reason.

### Fixed: a reset is a fresh start

- A session reset could leave a stale analog crossing from the previous run.
The MCU reconfigured its pins during the reset and touched islands still
running. So a run after a reset (a replay, or a recording begun at 0)
could differ from the run after loading, by 1.4 ns in an interrupt on the
Blue Pill.
- Islands now stop at the start of a reset.
- `test_reset_is_load` replays a recording begun mid-run while an RC is
still charging, and gets the same result to the picosecond.

### Timing: paced real time no longer depends on the host's speed

- Analog islands take a step boundary at each millisecond of simulated
time, and paced slices end on that grid.
- A run cut into slices by the host's speed now computes the same values as
an uncut one, to the bit (`test_grid_slices`).

### Timing: vendor expectations after the cycle-accurate cores

- STM32CubeF4's EEPROM_Emulation now ends between 15.5 and 15.75 s, not
just past 13 s: its code is fetched from flash at five wait states.
- The Pico SDK's polls and PWM wraps follow the Cortex-M0+'s cycle costs:
540 polls through the 25LC040's write cycle, and the 520th wrap just
after the 520 ms line.

### Timing: execution traces

- `embsim run --trace FILE` records each instruction start (with its
function), and each exception pending, taken and returned. Every event
carries its cycle and simulated time.
- The trace is a table, or with `.vcd` a waveform for GTKWave and similar
viewers (pc, exception active, pending, cycle).
- `--trace-start BOUNDARY` and `--trace-limit N` bound it.
- The FreeRTOS test checks that a traced context switch equals the measured
one.

### Timing: the STM32F4's flash wait states and ART accelerator

- Code and literal pools in the STM32F446's flash now wait FLASH_ACR's
LATENCY cycles for each 128-bit line (RM0390 3.4).
- The ART accelerator hides those waits the way RM0390 describes:
- prefetch reads the next line while the current one executes;
- the instruction cache holds 64 lines (LRU);
- the data cache holds 8 lines;
- ICRST and DCRST empty the caches.
- `test_flash_read_timing` checks RM0390 Figure 4's prefetch case, a loop
in the instruction cache, and a literal in the data cache.
- 180 MHz results are no longer optimistic by the waits.

### Timing: the Cortex-M0+ (RP2040) from its own manual

- The RP2040's cores now take the Cortex-M0+ TRM's cycles (ARM DDI 0484C
Table 3-1), not the Cortex-M4's: a load or store 2 cycles, 1 on the SIO's
single-cycle I/O port; a taken branch 2, BL 3, POP with PC 3+N; MULS 1
(the RP2040's fast multiplier, datasheet 2.4).
- An exception's entry takes the TRM's worst-case 15 cycles, with late
arrival. The return and tail-chain are not charged, because neither the
TRM nor the datasheet gives a figure.
- `tests/unit/test_cm_timing.c` times each class.

### Speed: analog islands settle at the solver's tolerance

- An analog island now counts as settled when a step changes no node by more
than vntol (1 uV) and no branch current by more than abstol (1 pA). Before,
the limit was 1e-14 relative, so an RC tail such as a reset pin's kept the
board's supply island stepping at every 1 us core quantum for about 130 ms
of each run.
- FreeRTOS on the NUCLEO-F446RE runs 3.4x faster (0.23x real time, from
0.07x), and the NUCLEO blink example 1.9x faster. All tests, catalog
fixtures and ngspice references are unchanged.
- `tools/perf/bench_mcu.py` benchmarks fixed workloads, with simulated and
host time in separate columns.

### Timing: measurements between boundaries

- `embsim run --measure [NAME=]FROM..TO` measures the cycles and the
simulated time between two boundaries each time they happen. A boundary
is an instruction starting at a symbol or address, an exception taken
(`exc:N`), an exception becoming pending (`pend:N`), or an exception's
return done (`ret:N`).
- `--measure-out` writes the report as text or JSON, with the host's wall
time kept apart.
- The measurement adds nothing to the firmware's cycles, and two runs give
identical numbers.
- `pend:PendSV..ret:PendSV` measures an RTOS context switch. For FreeRTOS
V11.1.0 on the NUCLEO-F446RE at 16 MHz it is 155 to 167 cycles; the
FreeRTOS vendor test checks the tick period and that the parts of each
switch add up (`tests/vendor/freertos/run.py`).

### Timing: Cortex-M exception entry, return, tail-chaining and late arrival

- `docs/engineering/timing-fidelity.md`: an audit of the simulator's timing
against what an RTOS context-switch measurement needs, the accuracy levels
(functional, estimated, cycle-exact for a stated scope, electrical), each
target's level, and the plan.
- On ARMv7-M, exceptions now take the Cortex-M4 TRM's cycles (ARM DDI 0439B
3.9.1, zero wait states): 12 to enter, 12 to return, 6 to tail-chain. A
higher priority interrupt arriving while a frame is stacked takes it (late
arrival). Before this, exceptions cost nothing, and a PendSV context
switch read about 24 cycles short. `tests/unit/test_cm_timing.c` times
each case.

### Front panels opened from their parts, docked or floating

- An instrument with a front panel of its own (the DS1054Z, the PPK2, the
Logic 8) opens it from its part: the inspector's Open front panel, the
schematic's right-click menu, the bench's list of what is on it, or the
command palette's Open, Float and Dock commands for each one. Opened, it
unfolds in the Run perspective's dock and takes the focus.
- Float takes a panel out of the dock into a window over the workbench,
which stays over every perspective, so the scope can be watched while
the circuit is edited. Its title bar moves it (or the arrow keys on it),
its corner resizes it (or Shift with the arrow keys), and Dock puts it
back. Each window's place and size are remembered for the next session.
- `revealDockItem` in the design system unfolds and focuses a dock item
wherever it is laid out, even one whose perspective is not open yet.
- `docs/user/instruments.md`: how to wire the three instruments, open and
float their panels, and read each one.
- axe runs in the browser on each instrument's front panel (the DS1054Z,
the Logic 8, the PPK2), docked and floating, in the light and the dark
theme, contrast included (`e2e/front-panels.spec.ts`; the demo session
has stand-in catalog entries for the three). It found, and these now
meet 4.5:1:
- the scope's STOP and AUTO badges: white on #b52b27 (6.3:1) and on
#2a6db5 (5.3:1);
- the light theme's accent, white on #0e8a66 at 4.33:1 under every small
primary button: #0c7f5e (4.98:1);
- the instruments' measurement labels, in --text-faint (3.2-4.2:1): now
--text-muted (6.5:1 on white). The token file says --text-faint is not
for text.

### An oscilloscope: the Rigol DS1054Z

- `emblink/rigol_ds1054z` from Rigol's DS1000Z specifications: four inputs
that load the circuit (1 MΩ ∥ 15 pF, 10 MΩ through the 10x probes it ships
with); acquisitions at 1 GSa/s with one channel on, 500 MSa/s with two,
250 MSa/s with three or four, lowered when the memory (12, 6 or 3 Mpts;
twice with the option) cannot hold the screen; 8 bits over 10 divisions
at 1 mV/div to 10 V/div times the probe, with offset; a first-order
50 MHz bandwidth (20 MHz limit); DC, AC (5 Hz) or GND coupling; the edge
trigger (level, slope, holdoff) in Auto, Normal or Single; Run/Stop.
- The Run perspective draws its screen (12 by 8 divisions, the channels in
Rigol's colours, ground and trigger markers, the status) and its front
panel's controls, the acquisitions followed live as the circuit runs, and
the automatic measurements (frequency, period, Vpp, Vmax, Vmin, Vavg,
Vrms, duty, rise time) on a channel.
- `instrument.read` gives an oscilloscope's last acquisition
(`kind: "scope"`). Electrical parts now hear an input as it is set
(`esk_adev_on_input`), so Run/Stop and Start/Stop act at their instant.

### A power profiler: the Nordic Power Profiler Kit II

- `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. It samples the current into the board at
100 kS/s, each sample the 10 µs average at the resolution of the range it
falls in (0.2, 0.5, 5, 50 or 1000 µA for the five ranges, switched by
itself); negative currents read 0. Its logic port samples D0 to D7 at
100 kHz on the same grid. It is a composite of its measurement core
(`emblink/ppk2_core`, the new `power_profiler` primitive) and its logic
port (`emblink/ppk2_logic_port`, the logic analyzer's sampler at a fixed
rate).
- The Run perspective has a panel for each PPK2, as Nordic's Power Profiler
app shows it: Start and Stop, the mode and supply voltage, the current
followed live, the window's or A-B selection's average, peak and charge,
the logic port's channels underneath, export as CSV.
- `instrument.read` gives a power profiler's samples (`kind: "power"`).

### A logic analyzer: the Saleae Logic 8

- `emblink/saleae_logic8`: Saleae's 8-channel USB logic analyzer as a part
Expand Down
12 changes: 11 additions & 1 deletion catalog/boards/arduino_uno/board.json
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,14 @@
"component": "emblink/push_button",
"doc": "Reset, pulls RESET low"
},
{
"id": "DTR_RESET",
"component": "emblink/push_button",
"params": {
"bounce": false
},
"doc": "The 16U2's auto-reset: DTR falling pulls RESET low through the 100 nF capacitor until the pull-up recharges it (the console bridge's dtr_reset). An electronic pulse, not a contact: it does not bounce"
},
{
"id": "R_RESET",
"component": "emblink/pull_up",
Expand Down Expand Up @@ -186,6 +194,7 @@
"LED_L.K",
"LED_ON.K",
"SW_RESET.2",
"DTR_RESET.2",
"J_PWR.6",
"J_PWR.7",
"J_DHI.7",
Expand All @@ -203,6 +212,7 @@
"RESET": [
"U1.NRST",
"SW_RESET.1",
"DTR_RESET.1",
"R_RESET.1",
"J_PWR.3"
],
Expand Down Expand Up @@ -528,7 +538,7 @@
"bridge": {
"part": "ATmega16U2",
"dtr_reset": {
"component": "SW_RESET",
"component": "DTR_RESET",
"ms": 0.7
}
}
Expand Down
15 changes: 12 additions & 3 deletions catalog/boards/bluepill/board.json
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,15 @@
"resistance": "10k",
"voltage": 3.3
},
"doc": "NRST pull-up (the 100 nF reset capacitor is omitted)"
"doc": "NRST pull-up"
},
{
"id": "C_RESET",
"component": "emblink/capacitor",
"params": {
"capacitance": "100n"
},
"doc": "The 100 nF NRST capacitor: with the 10k pull-up it holds NRST low through the reset button's bounce"
},
{
"id": "Y1",
Expand Down Expand Up @@ -185,6 +193,7 @@
"J3.1"
],
"GND": [
"C_RESET.2",
"U2.GND",
"U1.VSS",
"U1.VSSA",
Expand Down Expand Up @@ -212,6 +221,7 @@
"U1.NRST",
"SW_RESET.1",
"R_RESET.1",
"C_RESET.1",
"J1.17"
],
"BOOT0": [
Expand Down Expand Up @@ -877,11 +887,10 @@
"validation": []
},
"electrical": {
"claims": "LDO, LEDs with series resistors, pull-ups and pull-downs, crystals as BVD equivalents, headers; GPIO bridges use the MCU pin-model defaults.",
"claims": "LDO, LEDs with series resistors, pull-ups and pull-downs, the 100 nF NRST capacitor (with the 10k pull-up it holds NRST low about 0.8 ms after power-up and through the reset button's bounce), crystals as BVD equivalents, headers; GPIO bridges use the MCU pin-model defaults.",
"omissions": [
"decoupling",
"USB",
"reset capacitor",
"ESD diodes",
"trace impedance"
],
Expand Down
20 changes: 15 additions & 5 deletions catalog/components/capacitor/component.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,16 @@
"default": "100n",
"doc": "Capacitance",
"min": "1f",
"max": "10"
"max": "10",
"spread": "tolerance"
},
"tolerance": {
"type": "number",
"unit": "%",
"default": 10,
"min": 0,
"max": 50,
"doc": "Tolerance: each part's capacitance lies within this band of the nominal, drawn from the project's seed (ADR-034). 10 % is IEC 60062's code K, the usual grade of X7R ceramic capacitors; 0 for an exact part."
},
"esr": {
"type": "number",
Expand All @@ -51,14 +60,14 @@
"doc": "Initial voltage at t=0 (pin 1 relative to pin 2)",
"advanced": true
}
}, "functional": {
},
"functional": {
"composite": {
"components": [],
"nets": {},
"ports": {}
}
},

"model": {
"primitive": "capacitor",
"bind": {
Expand Down Expand Up @@ -99,12 +108,13 @@
"omissions": []
},
"electrical": {
"claims": "Linear capacitance with ESR and initial condition, trapezoidal/BDF2 companion (SPEC-004 §7 capacitor).",
"claims": "Linear capacitance with ESR and initial condition, trapezoidal/BDF2 companion (SPEC-004 §7 capacitor); each instance's capacitance drawn uniformly inside ±tolerance of the nominal from the project's seed and its id (ADR-034; nominal with settings.imperfections \"ideal\").",
"omissions": [
"dielectric absorption",
"leakage",
"ESL",
"voltage coefficient"
"voltage coefficient",
"the distribution inside the tolerance band (uniform: a manufacturer guarantees the band only)"
],
"range": {
"voltage_v": [
Expand Down
Loading
Loading