velxio/test/test_circuit/src/avr/asm.js

88 lines
2.4 KiB
JavaScript
Raw Normal View History

feat: electrical simulation via ngspice-WASM (eecircuit-engine) Adds full SPICE-accurate electrical simulation to Velxio, behind a lazy- loaded ⚡ toolbar toggle. Arduino / ESP32 / RP2040 sketches now co-simulate with real analog behaviour: correct voltages on wires, real I–V curves on LEDs, working potentiometers, NTC thermistors read by analogRead(), PWM driving RC filters, transistors, op-amps, diodes, MOSFETs, etc. Engine: eecircuit-engine (ngspice compiled to WebAssembly). Main bundle stays at 2.4 MB; the 20 MB SPICE chunk only loads when the user activates electrical mode. Disabled at build time via VITE_ELECTRICAL_SIM=false. Frontend additions: - simulation/spice/: SpiceEngine wrapper + lazy entry, NetlistBuilder with UnionFind over wires, componentToSpice mapping (24 metadataIds incl. real part numbers: 2N2222, 2N3055, BC547, IRF540, 2N7000, 1N4148, 1N4007, 1N4733, LEDs, NTC, op-amp ideal), CircuitScheduler with debounced coalescing, AVRSpiceBridge for quasi-static co-simulation. - store/useElectricalStore: Zustand slice, feature-flag aware. - components/analog-ui/: ⚡ toolbar toggle + SVG voltage overlay. - components/components-instruments/: Voltmeter, Ammeter probes. - 62 tests (spice-*, netlist-builder, component-to-spice, instruments). Sandbox (test/test_circuit/): 47-test validation sandbox that proved the approach (hand-rolled MNA baseline + ngspice pipeline) before porting to the app. Kept as reference. Docs: docs/wiki/circuit-emulation-*.md (13 engineering pages covering architecture, solvers, components, AVR bridge, gotchas, performance, integration plan, API reference, appendix) + electrical-simulation- user-guide.md (end-user facing). Reference plan: test/test_circuit/plan/phase_8_velxio_implementation.md Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-15 19:11:54 +07:00
/**
* Tiny hand-rolled AVR assembler for the few opcodes we need to build
* test programs without an avr-gcc toolchain.
*
* Only the instructions exercised by the test suites are implemented.
* All addresses / offsets use AVR's word-addressed convention.
*/
/** LDI Rd, K Rd [16..31], K [0..255]
* Encoding: 1110 KKKK dddd KKKK
*/
export const LDI = (rd, k) => {
if (rd < 16 || rd > 31) throw new Error(`LDI: rd=${rd} out of range`);
if (k < 0 || k > 255) throw new Error(`LDI: k=${k} out of range`);
const d = rd - 16;
return 0xE000 | ((k & 0xF0) << 4) | (d << 4) | (k & 0x0F);
};
/** OUT A, Rr A [0..63], Rr [0..31]
* Encoding: 1011 1AAr rrrr AAAA
*/
export const OUT = (A, rr) => {
if (A < 0 || A > 63) throw new Error(`OUT: A=${A} out of range`);
return 0xB800 | ((A & 0x30) << 5) | (rr << 4) | (A & 0x0F);
};
/** IN Rd, A Rd [0..31], A [0..63]
* Encoding: 1011 0AAd dddd AAAA
*/
export const IN = (rd, A) => {
return 0xB000 | ((A & 0x30) << 5) | (rd << 4) | (A & 0x0F);
};
/** STS k, Rr 32-bit instruction, k [0..65535], Rr [0..31]
* Encoding: 1001 001r rrrr 0000 kkkkkkkk kkkkkkkk
* Returns [word1, word2].
*/
export const STS = (k, rr) => {
const w1 = 0x9200 | ((rr & 0x10) << 4) | ((rr & 0x0F) << 4);
return [w1, k & 0xFFFF];
};
/** LDS Rd, k 32-bit instruction
* Encoding: 1001 000d dddd 0000 kkkkkkkk kkkkkkkk
*/
export const LDS = (rd, k) => {
const w1 = 0x9000 | ((rd & 0x10) << 4) | ((rd & 0x0F) << 4);
return [w1, k & 0xFFFF];
};
/** RJMP jump by signed word offset from PC+1
* Encoding: 1100 kkkk kkkk kkkk (12-bit signed)
*/
export const RJMP = (offset) => {
const k = offset & 0xFFF;
return 0xC000 | k;
};
/** SBRC Rr, b Skip if Bit in Register Clear
* Encoding: 1111 110r rrrr 0bbb
*/
export const SBRC = (rr, b) => {
return 0xFC00 | (rr << 4) | (b & 0x07);
};
/** SBRS Rr, b Skip if Bit in Register Set
* Encoding: 1111 111r rrrr 0bbb
*/
export const SBRS = (rr, b) => {
return 0xFE00 | (rr << 4) | (b & 0x07);
};
/** NOP */
export const NOP = () => 0x0000;
/**
* Assemble a flat list of values (each either a number = 1 word, or an
* array [w1, w2] = two words) into a Uint16Array.
*/
export function assemble(items) {
const flat = [];
for (const it of items) {
if (Array.isArray(it)) flat.push(...it);
else flat.push(it);
}
return Uint16Array.from(flat);
}