velxio/test/autosearch/04_findings.md

12 KiB

Findings — log corrido

Formato: por sesión + fecha. Lo más reciente arriba.


2026-04-28 (sesión 4) — SPI + 5 chips nuevos + gaps cubiertos

Resultado

Test Files  26 passed | 0 skipped (26)
Tests       70 passed | 0 skipped (70)

Gaps de wokwi-api.h ahora cubiertos

SPI slave: nuevo SPIBus + SPIDevice + vx_spi_attach/start/stop. Modelo buffer-bidireccional como Wokwi: chip pre-llena con MISO, master clockea bytes, buffer queda con MOSI recibido, fires on_done(buffer, count). VX_OUTPUT_LOW / VX_OUTPUT_HIGH: modos 16/17 que inicializan el pin a un nivel concreto al registrar — elimina la ventana glitch entre register+write. vx_pin_watch_stop: por-handle, libera todos los watches del pin. vx_pin_dac_write: dispara analog listeners en PinManager (DAC). vx_pin_set_mode: cambiar modo después del init (renombrado de pin_mode por colisión con el nombre del enum en C). reserved[8] en configs: i2c_config = 64 bytes, uart_config = 56 bytes, spi_config = 60 bytes. ABI estable hacia adelante.

Chips nuevos compilados (5)

Chip Tamaño Protocolos Notas
sn74hc595.wasm 64 KB SPI + GPIO + RCLK latch Shift register 8-bit, latch en RCLK rising
mcp3008.wasm 64 KB SPI + ANALOG ADC 8-canales 10-bit
pcf8574.wasm 64 KB I2C + GPIO bidireccional I/O expander 8-bit, base 0x20
ds3231.wasm 64 KB I2C + estado interno RTC con 19 registros, BCD encoding
pulse-counter.wasm 64 KB GPIO + atributos Cuenta flancos, OVF cada N pulsos

Tests nuevos (21 más, total 70)

  • 14_sn74hc595 — 4 tests: SPI byte transfer, RCLK latching, SRCLR clear, byte override.
  • 15_mcp3008 — 3 tests: 0V/2.5V/5V analog readings via SPI command protocol.
  • 16_pcf8574 — 4 tests: I2C write→pin pattern, read line state, A0..A2 addressing, latched persistence.
  • 17_ds3231 — 3 tests: read default time, set+read time round-trip BCD, register pointer.
  • 18_pulse_counter — 3 tests: default threshold (4), custom threshold attr, RST clear.
  • 19_api_extras — 4 tests: import surface, OUTPUT_HIGH init, OUTPUT_LOW init, DAC dispatch.

Lo que se aprendió

  1. Re-arm SPI: chips como 74HC595 que no usan CS deben llamar vx_spi_start de nuevo dentro del on_done callback. Si no, solo el primer byte llega.
  2. Naming collision en C: vx_pin_mode no podía ser tipo Y función. Renombrado a vx_pin_set_mode. Lección: prefijar funciones distinto del enum/typedef.
  3. Struct ABI con reserved[8]: agregar campos al final no rompe los chips ya compilados solo si las posiciones existentes no se mueven. El _Static_assert en el header detecta cualquier movimiento accidental.
  4. PinManager.setAnalogVoltage ya existía y permitió implementar pin_dac_write sin agregar infraestructura nueva.

Aún pendiente (deferido)

  • Framebuffer para displays (LCD/OLED custom). El IL9163 que pasaste sería el caso de uso. Implementarlo cuando sea necesario; SSD1306 / ILI9341 ya están en wokwi-elements y no necesitan custom chip.
  • attr_string_init (atributos texto/select). Caso raro.
  • Experimental _mcu_* (memoria del CPU emulado). Solo para debug.

2026-04-28 (sesión 3) — AVR Wire + chip I2C: full E2E

Resultado

Test Files  20 passed | 0 skipped (20)
Tests       49 passed | 0 skipped (49)

Cero tests skipped. Toda la suite corre verde sin excepción.

Lo que se completó

  • Sketch Arduino real (sketches/i2c_eeprom_demo/i2c_eeprom_demo.ino) que usa Wire.h para hablar con el chip 24C01.
  • Compilado con arduino-cli compile --fqbn arduino:avr:uno. Salida en fixtures/i2c_eeprom_demo.hex (11 KB, ATmega328P).
  • Test 07_chip_eeprom_avr_e2e pasa: el sketch escribe 4 bytes (0xAA..0xDD), resetea el pointer, lee de vuelta, y los emite por Serial. La suite verifica que los 4 bytes aparecen en getSerialOutput() en el orden correcto.

Cadena verificada end-to-end

i2c_eeprom_demo.ino (C++)
  → arduino-cli + arduino:avr:1.8.7
    → ATmega328P .hex
      → avr8js CPU (real instrucciones)
        → AVRTWI peripheral (real I2C bit-banging)
          → I2CBus (TWIEventHandler)
            → ChipInstance (WASM)
              → eeprom-24c01.wasm
                → callbacks I2C (connect/read/write/stop)
                  → respuestas del bus
                    → AVR USART transmit
                      → serialOut buffer
                        → assertion en el test ✅

API gap vs wokwi-api.h

Documentado en 06_wokwi_api_gap_analysis.md. Lo importante que falta:

  • SPI slave (alta prioridad)
  • OUTPUT_LOW/OUTPUT_HIGH modes
  • pin_watch_stop
  • reserved[8] en configs (forward-compat)
  • pin_dac_write, pin_mode

Total estimado: ~1 día para cubrir esos gaps.


2026-04-28 (sesión 2) — Suite completa: GPIO + I2C + UART + multi-chip + AVR

Resultado

Test Files  19 passed | 1 skipped (20)
Tests       48 passed | 1 skipped (49)

Chips compilados y validados

Chip Tamaño Protocolos ejercitados
inverter.wasm 63 KB GPIO + pin_watch
xor.wasm 63 KB GPIO + pin_watch (2 inputs)
cd4094.wasm 64 KB GPIO + pin_watch BOTH/RISING + state machine 8-bit
eeprom-24c01.wasm 64 KB I2C slave + addressing + 128-byte memory
eeprom-24lc256.wasm 64 KB I2C slave + 16-bit addressing + 32 KB memory
uart-rot13.wasm 63 KB UART RX/TX + struct passing + uart_write

Tests por categoría

Tier 1 — single chip (10 tests): inicialización, edges, truth table XOR, shift register 8-bit, power gate, strobe latching.

Tier 2 — protocols (13 tests):

  • I2C 24C01: write/read básico, auto-increment, wrap @ 0x80, A0/A1/A2 pin selection.
  • I2C 24LC256: 16-bit addressing, high addresses (>0xff), page write 8 bytes, cross-page read.
  • UART ROT13: A↔N, Z↔M wrap, lowercase, non-alpha passthrough, round-trip todos los printables.

Tier 3 — multi-chip (4 tests):

  • Dos 24C01 con A0 distinto → 0x50 y 0x51 independientes en el mismo bus.
  • NACK a direcciones no usadas (0x52..0x77).
  • Dos CD4094 cascadeados (A.QS → B.DATA) con CLK/STR compartidos.
  • XOR.OUT → Inverter.IN → XNOR truth table (logic chaining).
  • EEPROM I2C + UART chip operando en paralelo sin interferencia.

Tier 4 — AVR + chips (3 tests):

  • avr8js con blink.hex real → pin 13 toggle → Inverter chip OUT toggle inverso.
  • avr8js → XOR.A (B held LOW) → OUT mirrors A.
  • avr8js → CD4094.CLK + DATA HIGH + strobe → register latches non-zero.

Protocolos validados end-to-end

GPIO: pin_register, pin_read, pin_write, pin_watch (RISING/FALLING/BOTH). I2C slave: connect/read/write/stop callbacks via function table indirect. UART: rx_byte callback, write_done callback, vx_uart_write con buffer. Multi-instance: dos .wasm idénticos con state independiente (memorias separadas). Multi-chip: chips de protocolos distintos en el mismo PinManager + I2CBus. Chip → chip: la salida de un chip dispara el pin_watch de otro chip. AVR → chip: el AVR drivea pines y los chips reaccionan correctamente.

Lo que NO hicimos (todavía)

  • Test #07 chip_eeprom_avr_e2e requiere .hex de un sketch con Wire.h hablando con el chip 24C01. Si bien todos los componentes están validados por separado, falta ese caso "AVR Wire master + chip I2C slave" como prueba final.

2026-04-28 — wasi-sdk + compilación real + E2E pasando

Hito alcanzado: VIABILIDAD CONFIRMADA

El sistema completo funciona end-to-end. Un .c escrito contra velxio-chip.h compila a .wasm con clang+wasi-sdk, se carga en el ChipRuntime, y la lógica del chip (incluyendo I2C slave con callbacks via function table) ejecuta correctamente.

Resultados

Test Files  6 passed | 1 skipped (7)
Tests      17 passed | 1 skipped (18)
  • inverter.c compilado (~63 KB) — vx_pin_register/vx_pin_write/vx_pin_watch con callback indirect-call funcionan en WASM real.
  • eeprom-24c01.c compilado (~63 KB) — protocolo I2C completo: addressing, write pointer + bytes, read sequential, pointer auto-increment.
  • Dos instancias del mismo .wasm (24C01 con A0 distintos → direcciones 0x50 y 0x51) operan en paralelo en el mismo I2CBus sin interferencia.
  • ⏭ Skipped: test #07 que requiere un .hex de Arduino real con Wire.h hablándole al chip. Falta compilarlo con arduino-cli.

Setup que funcionó

  • WASI-SDK 32.0 instalado en C:\wasi-sdk (Windows). Apache 2.0.
  • clang 22.1.0 con target wasm32-unknown-wasip1.
  • Comando final:
    clang --target=wasm32-unknown-wasip1 -O2 -nostartfiles \
          -Wl,--import-memory -Wl,--export-table -Wl,--no-entry \
          -Wl,--export=chip_setup -Wl,--allow-undefined \
          -I sdk/include chip.c -o chip.wasm
    

Lo que NO funcionó al primer intento

  1. Target deprecado: --target=wasm32-unknown-wasi daba warning. Se cambió a wasm32-unknown-wasip1.
  2. Linker fallaba con "undefined symbol: vx_pin_register …": faltaba -Wl,--allow-undefined. Sin ese flag, las funciones extern del header se trataban como link errors. Con el flag, el linker las convierte en imports WASM (que es exactamente lo que queremos).
  3. Doble prefijo [chip] [chip] inverter ready en stdout: el WasiShim prefijaba el output de printf y el ChipRuntime también prefijaba en vx_log. Se removió el prefijo del runtime (lo deja al WasiShim).

Tamaño del WASM

~63 KB tanto para inverter como para 24C01. Más de lo estimado (~10 KB) porque wasi-libc trae malloc+printf+familia. Aceptable para el caso de uso (almacenar por proyecto en SQLite).

Próximos pasos

  • Compilar un sketch Arduino real (Wire.h) con arduino-cli y dropearlo en fixtures/i2c_eeprom_demo.hex para activar el test #07. Eso valida el flujo completo: AVR sketch → I2C bus virtual → chip WASM → respuesta.
  • Implementar vx_uart_attach (hoy stub).
  • Validar el _Static_assert(sizeof(vx_i2c_config) == 32) realmente se honra: el header lo declara, pero confirmarlo en runtime con un script de compilación que falle si cambia.
  • Decidir cómo reducir el tamaño del .wasm (¿compilar sin printf? ¿stripping agresivo?). No urgente.

2026-04-27 — Sesión inicial: scaffold + diseño

Lo que se hizo

  • Se creó la estructura test/autosearch/ y test/test_custom_chips/.
  • Se documentó la API de Wokwi como referencia (no como código a usar).
  • Se diseñó velxio-chip.h desde cero, naming propio (vx_*).
  • Se decidió: cero código de Wokwi en el proyecto. Toolchain solo LLVM/WASI.
  • Se implementaron los siguientes módulos JS en el sandbox:
    • src/PinManager.js — espejo 1:1 de frontend/src/simulation/PinManager.ts.
    • src/I2CBus.js — espejo de I2CBusManager.ts.
    • src/AVRHarness.js — copiado desde test_circuit/src/avr/AVRHarness.js (mismo pattern que Velxio).
    • src/ChipRuntime.js — loader WASM + tabla de host imports.
    • src/WasiShim.jsfd_write, proc_exit, clock_time_get.

Qué probamos

  • Tests JS-only (no requieren clang) corren con pnpm test.
  • Validan el shape de PinManager, I2CBus, host imports, AVRHarness con .hex real.

Qué falta (próxima sesión)

  • Compilar inverter.c y eeprom-24c01.c con compile-chip.sh para generar fixtures .wasm.
  • Test E2E: AVR sketch + 24C01 chip vía I2C bus virtual. Validar lectura/escritura.
  • Implementar vx_pin_watch con indirect call al function table.
  • Decidir layout exacto del struct vx_i2c_config (ABI estable entre clang y host JS).

Lo que NO funcionó (todavía)

  • N/A — primera sesión.

Lo que funcionó

  • Reusar AVRHarness.js de test_circuit sin modificaciones — buena señal de que la abstracción está bien hecha en Velxio.
  • I2CBusManager de Velxio ya tiene la interface que necesita el chip (writeByte/readByte/stop) → mapeo casi directo.