/* * eeprom-24c01.c — Velxio custom chip implementing a 24C01-class I2C EEPROM. * * 128 bytes (datasheet says 1 Kbit = 128 × 8). Address pins A0..A2 set the * three low bits of the 7-bit I2C address (base 0x50). * * Protocol on the I2C bus: * write 1 byte → set the read/write address pointer * write 2+ bytes → first sets address pointer, rest stores data sequentially * read → returns memory at pointer, autoincrements * * Build: * bash scripts/compile-chip.sh sdk/examples/eeprom-24c01.c fixtures/eeprom-24c01.wasm */ #include "velxio-chip.h" #include #include #define EEPROM_BASE_ADDR 0x50 #define EEPROM_SIZE 128 typedef enum { ST_IDLE, /* before any byte after addressing */ ST_HAS_POINTER, /* received the pointer byte; further writes are data */ } ee_state; typedef struct { vx_pin a0, a1, a2; uint8_t pointer; uint8_t mem[EEPROM_SIZE]; ee_state state; } chip_state_t; static bool i2c_connect(void* ud, uint8_t address, bool is_read) { chip_state_t* s = (chip_state_t*)ud; /* On a fresh transaction, reads use the existing pointer; writes restart. */ if (!is_read) s->state = ST_IDLE; return true; /* ACK */ } static uint8_t i2c_read(void* ud) { chip_state_t* s = (chip_state_t*)ud; uint8_t b = s->mem[s->pointer & (EEPROM_SIZE - 1)]; s->pointer = (s->pointer + 1) & (EEPROM_SIZE - 1); return b; } static bool i2c_write(void* ud, uint8_t byte) { chip_state_t* s = (chip_state_t*)ud; if (s->state == ST_IDLE) { s->pointer = byte & (EEPROM_SIZE - 1); s->state = ST_HAS_POINTER; } else { s->mem[s->pointer & (EEPROM_SIZE - 1)] = byte; s->pointer = (s->pointer + 1) & (EEPROM_SIZE - 1); } return true; /* ACK */ } static void i2c_stop(void* ud) { chip_state_t* s = (chip_state_t*)ud; s->state = ST_IDLE; } void chip_setup(void) { chip_state_t* s = (chip_state_t*)calloc(1, sizeof(chip_state_t)); s->a0 = vx_pin_register("A0", VX_INPUT); s->a1 = vx_pin_register("A1", VX_INPUT); s->a2 = vx_pin_register("A2", VX_INPUT); uint8_t addr = EEPROM_BASE_ADDR | ((vx_pin_read(s->a2) & 1) << 2) | ((vx_pin_read(s->a1) & 1) << 1) | ((vx_pin_read(s->a0) & 1)); vx_i2c_config cfg = { .address = addr, .scl = vx_pin_register("SCL", VX_INPUT), .sda = vx_pin_register("SDA", VX_INPUT), .on_connect = i2c_connect, .on_read = i2c_read, .on_write = i2c_write, .on_stop = i2c_stop, .user_data = s, }; vx_i2c_attach(&cfg); vx_log("24C01 EEPROM ready"); }