89 lines
3.9 KiB
Markdown
89 lines
3.9 KiB
Markdown
# Velxio Chip API — diseño
|
|
|
|
> Header propio, naming propio. Cero dependencia de Wokwi a nivel código fuente o binario.
|
|
|
|
## Convenciones
|
|
|
|
- Prefijo: `vx_*` (lowercase, snake_case en C).
|
|
- Tipos opacos: `vx_pin`, `vx_attr`, `vx_timer`, `vx_i2c`, `vx_uart`, `vx_spi`. Todos son `int32_t`
|
|
bajo el capot — opacos para el chip, índices o handles para el host.
|
|
- Constantes en MAYÚSCULAS con prefijo `VX_`.
|
|
- El chip exporta una sola función obligatoria: `chip_setup()`. Se llama una vez por instancia.
|
|
|
|
## Header completo (resumido)
|
|
|
|
Ver `test_custom_chips/sdk/include/velxio-chip.h` para el header con docstrings.
|
|
|
|
```c
|
|
// Pines
|
|
typedef int32_t vx_pin;
|
|
typedef enum { VX_INPUT, VX_OUTPUT, VX_INPUT_PULLUP, VX_INPUT_PULLDOWN, VX_ANALOG } vx_pin_mode;
|
|
typedef enum { VX_LOW = 0, VX_HIGH = 1 } vx_pin_value;
|
|
typedef enum { VX_EDGE_RISING, VX_EDGE_FALLING, VX_EDGE_BOTH } vx_edge;
|
|
|
|
vx_pin vx_pin_register(const char* name, vx_pin_mode mode);
|
|
int vx_pin_read(vx_pin p);
|
|
void vx_pin_write(vx_pin p, int value);
|
|
void vx_pin_watch(vx_pin p, vx_edge edge,
|
|
void (*cb)(void* ud, vx_pin p, int value),
|
|
void* user_data);
|
|
|
|
// Atributos editables
|
|
typedef int32_t vx_attr;
|
|
vx_attr vx_attr_register(const char* name, double default_val);
|
|
double vx_attr_read(vx_attr a);
|
|
|
|
// I2C slave
|
|
typedef int32_t vx_i2c;
|
|
typedef struct {
|
|
uint8_t address;
|
|
vx_pin scl, sda;
|
|
bool (*on_connect)(void* ud, uint8_t addr, bool is_read);
|
|
uint8_t (*on_read)(void* ud);
|
|
bool (*on_write)(void* ud, uint8_t byte);
|
|
void (*on_stop)(void* ud);
|
|
void* user_data;
|
|
} vx_i2c_config;
|
|
vx_i2c vx_i2c_attach(const vx_i2c_config* cfg);
|
|
|
|
// Tiempo + Timer
|
|
typedef int32_t vx_timer;
|
|
uint64_t vx_sim_now_nanos(void);
|
|
vx_timer vx_timer_create(void (*cb)(void* ud), void* user_data);
|
|
void vx_timer_start(vx_timer t, uint64_t period_nanos, bool repeat);
|
|
void vx_timer_stop(vx_timer t);
|
|
|
|
// Log
|
|
void vx_log(const char* msg);
|
|
```
|
|
|
|
## Mapeo a infraestructura existente de Velxio
|
|
|
|
| API velxio-chip | Implementación host | Reusa de |
|
|
|---|---|---|
|
|
| `vx_pin_register` | Registra nombre lógico → handle. La conexión real vía wires se resuelve al cablear | nada nuevo |
|
|
| `vx_pin_read` / `vx_pin_write` | Resuelve handle → wire → otro endpoint → PinManager | `PinManager.getPinState`, `triggerPinChange` |
|
|
| `vx_pin_watch` | Suscribe al PinManager y enruta evento al WASM vía `__indirect_function_table` | `PinManager.onPinChange` |
|
|
| `vx_attr_register` / `vx_attr_read` | Lee de `component.properties` (mapa user-editable) | `ComponentMetadata.properties` |
|
|
| `vx_i2c_attach` | Crea un `I2CDevice` con writeByte/readByte/stop que llaman al WASM, lo agrega al `I2CBusManager` | `I2CDevice` interface |
|
|
| `vx_timer_*` | Cola interna de timers tickeada cada frame de `cpu.tick()` | clock del simulador activo |
|
|
| `vx_sim_now_nanos` | `cpu.cycles / clockFreq * 1e9` o equivalente por simulador | `cpu.cycles` |
|
|
| `vx_log` | Concatena al buffer de "Chips Console" (panel UI nuevo) | nada por ahora |
|
|
|
|
## Decisiones tomadas
|
|
|
|
- **Lifecycle**: una sola función `chip_setup`. No hay `chip_loop` — los chips son reactivos
|
|
(callbacks de pin/I2C/timer). Esto elimina el problema del scheduler entre el AVR y el chip.
|
|
- **`malloc` está OK**: viene en `wasi-libc`. Cada instancia del chip hace su `malloc(sizeof(state))`
|
|
igual que en Wokwi.
|
|
- **String passing**: punteros `const char*` se pasan como i32 a la host function, que lee bytes
|
|
hasta nul desde `instance.exports.memory.buffer`.
|
|
- **Struct passing**: para `vx_i2c_config` se pasa puntero. El host lee los offsets fijos del struct.
|
|
ABI: `__attribute__((packed))` o documentación explícita del layout.
|
|
- **Function pointers**: el WASM es compilado con `--export-table`. El host invoca `instance.exports.__indirect_function_table.get(idx)(...args)`.
|
|
- **Memoria**: el host crea un `WebAssembly.Memory({initial: 2})` por instancia y la pasa como import.
|
|
|
|
## Pendiente de decidir
|
|
|
|
Ver `05_open_questions.md`.
|