91 lines
2.5 KiB
C
91 lines
2.5 KiB
C
/*
|
||
* 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 <stdlib.h>
|
||
#include <string.h>
|
||
|
||
#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");
|
||
}
|