move wokwi files into simulation

This commit is contained in:
2026-07-26 12:40:08 +00:00
parent 35bd3ab945
commit 74a964985d
21 changed files with 0 additions and 0 deletions
@@ -0,0 +1,19 @@
SOURCES = src/main.c
TARGET = dist/chip.wasm
.PHONY: all clean
all: $(TARGET) dist/chip.json
clean:
rm -rf dist
dist:
mkdir -p dist
$(TARGET): dist $(SOURCES) wokwi-api.h
podman run --rm -u root -v "$(CURDIR)":/src:Z -w /src docker.io/wokwi/builder-clang-wasm:latest \
clang --target=wasm32-unknown-wasi --sysroot /opt/wasi-libc -nostartfiles -Wl,--import-memory -Wl,--export-table -Wl,--no-entry -Werror -o $(TARGET) $(SOURCES)
dist/chip.json: dist chip.json
cp chip.json dist
@@ -0,0 +1,6 @@
{
"name": "Main Display",
"author": "GitHub Copilot",
"display": { "width": 240, "height": 320 },
"pins": ["VCC", "GND", "SCK", "MOSI", "CS", "DC", "RESET", "LED"]
}
+6
View File
@@ -0,0 +1,6 @@
{
"name": "Main Display",
"author": "GitHub Copilot",
"display": { "width": 240, "height": 320 },
"pins": ["VCC", "GND", "SCK", "MOSI", "CS", "DC", "RESET", "LED"]
}
Binary file not shown.
@@ -0,0 +1,243 @@
#include "../wokwi-api.h"
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>
typedef struct {
buffer_t framebuffer;
uint32_t width;
uint32_t height;
spi_dev_t spi;
pin_t cs_pin;
pin_t dc_pin;
pin_t rst_pin;
pin_t led_pin;
uint8_t spi_buffer[128];
uint8_t current_cmd;
uint8_t expected_params;
uint8_t param_index;
uint8_t params[4];
bool memory_write;
bool color_high_pending;
uint8_t color_high;
uint16_t col_start;
uint16_t col_end;
uint16_t row_start;
uint16_t row_end;
uint16_t cursor_col;
uint16_t cursor_row;
} main_display_state_t;
static main_display_state_t *chip;
static uint16_t clamp_u16(uint16_t value, uint16_t limit) {
return value > limit ? limit : value;
}
static void draw_pixel(uint16_t x, uint16_t y, uint16_t color565) {
if (x >= chip->width || y >= chip->height) {
return;
}
uint8_t pixel[4];
pixel[0] = (uint8_t)(((color565 >> 11) & 0x1F) << 3);
pixel[1] = (uint8_t)(((color565 >> 5) & 0x3F) << 2);
pixel[2] = (uint8_t)((color565 & 0x1F) << 3);
pixel[3] = 255;
buffer_write(chip->framebuffer, ((y * chip->width) + x) * 4, pixel, 4);
}
static void fill_screen(uint16_t color565) {
for (uint32_t y = 0; y < chip->height; ++y) {
for (uint32_t x = 0; x < chip->width; ++x) {
draw_pixel((uint16_t)x, (uint16_t)y, color565);
}
}
}
static void reset_state(void) {
chip->current_cmd = 0;
chip->expected_params = 0;
chip->param_index = 0;
chip->memory_write = false;
chip->color_high_pending = false;
chip->col_start = 0;
chip->col_end = (uint16_t)(chip->width - 1);
chip->row_start = 0;
chip->row_end = (uint16_t)(chip->height - 1);
chip->cursor_col = 0;
chip->cursor_row = 0;
fill_screen(0x0000);
}
static void advance_pixel_cursor(void) {
if (chip->cursor_col < chip->col_end) {
++chip->cursor_col;
return;
}
chip->cursor_col = chip->col_start;
if (chip->cursor_row < chip->row_end) {
++chip->cursor_row;
return;
}
chip->cursor_row = chip->row_start;
}
static void apply_params(void) {
switch (chip->current_cmd) {
case 0x2A:
chip->col_start = clamp_u16((uint16_t)((chip->params[0] << 8) | chip->params[1]), (uint16_t)(chip->width - 1));
chip->col_end = clamp_u16((uint16_t)((chip->params[2] << 8) | chip->params[3]), (uint16_t)(chip->width - 1));
if (chip->col_end < chip->col_start) {
chip->col_end = chip->col_start;
}
chip->cursor_col = chip->col_start;
break;
case 0x2B:
chip->row_start = clamp_u16((uint16_t)((chip->params[0] << 8) | chip->params[1]), (uint16_t)(chip->height - 1));
chip->row_end = clamp_u16((uint16_t)((chip->params[2] << 8) | chip->params[3]), (uint16_t)(chip->height - 1));
if (chip->row_end < chip->row_start) {
chip->row_end = chip->row_start;
}
chip->cursor_row = chip->row_start;
break;
default:
break;
}
chip->current_cmd = 0;
chip->expected_params = 0;
chip->param_index = 0;
}
static void process_command(uint8_t command) {
chip->current_cmd = command;
chip->param_index = 0;
chip->expected_params = 0;
chip->memory_write = false;
switch (command) {
case 0x01:
reset_state();
break;
case 0x2A:
case 0x2B:
chip->expected_params = 4;
break;
case 0x2C:
chip->memory_write = true;
chip->cursor_col = chip->col_start;
chip->cursor_row = chip->row_start;
chip->color_high_pending = false;
break;
case 0x36:
case 0x3A:
chip->expected_params = 1;
break;
default:
break;
}
}
static void handle_data_byte(uint8_t data) {
if (chip->current_cmd != 0 && chip->expected_params > 0) {
chip->params[chip->param_index++] = data;
if (chip->param_index >= chip->expected_params) {
apply_params();
}
return;
}
if (!chip->memory_write) {
return;
}
if (!chip->color_high_pending) {
chip->color_high = data;
chip->color_high_pending = true;
return;
}
uint16_t color565 = (uint16_t)((chip->color_high << 8) | data);
draw_pixel(chip->cursor_col, chip->cursor_row, color565);
advance_pixel_cursor();
chip->color_high_pending = false;
}
static void chip_spi_done(void *user_data, uint8_t *buffer, uint32_t count) {
(void)user_data;
for (uint32_t i = 0; i < count; ++i) {
if (pin_read(chip->dc_pin) == 0) {
process_command(buffer[i]);
} else {
handle_data_byte(buffer[i]);
}
}
if (pin_read(chip->cs_pin) == 0) {
spi_start(chip->spi, chip->spi_buffer, sizeof(chip->spi_buffer));
}
}
static void chip_cs_changed(void *user_data, pin_t pin, uint32_t value) {
(void)user_data;
(void)pin;
if (value == 0) {
spi_start(chip->spi, chip->spi_buffer, sizeof(chip->spi_buffer));
} else {
spi_stop(chip->spi);
chip->memory_write = false;
chip->color_high_pending = false;
}
}
static void chip_reset_changed(void *user_data, pin_t pin, uint32_t value) {
(void)user_data;
(void)pin;
if (value == 0) {
reset_state();
}
}
void chip_init(void) {
chip = (main_display_state_t *)malloc(sizeof(main_display_state_t));
chip->framebuffer = framebuffer_init(&chip->width, &chip->height);
chip->cs_pin = pin_init("CS", INPUT);
chip->dc_pin = pin_init("DC", INPUT);
chip->rst_pin = pin_init("RESET", INPUT_PULLUP);
chip->led_pin = pin_init("LED", INPUT);
const spi_config_t spi_config = {
.user_data = chip,
.sck = pin_init("SCK", INPUT),
.mosi = pin_init("MOSI", INPUT),
.miso = NO_PIN,
.mode = 0,
.done = chip_spi_done,
};
chip->spi = spi_init(&spi_config);
const pin_watch_config_t cs_watch = {
.user_data = chip,
.edge = BOTH,
.pin_change = chip_cs_changed,
};
pin_watch(chip->cs_pin, &cs_watch);
const pin_watch_config_t reset_watch = {
.user_data = chip,
.edge = BOTH,
.pin_change = chip_reset_changed,
};
pin_watch(chip->rst_pin, &reset_watch);
pin_mode(chip->led_pin, OUTPUT_HIGH);
reset_state();
}
@@ -0,0 +1,74 @@
#ifndef WOKWI_API_H
#define WOKWI_API_H
#include <stdbool.h>
#include <stdint.h>
typedef int32_t pin_t;
#define NO_PIN ((pin_t)-1)
enum pin_mode {
INPUT = 0,
OUTPUT = 1,
INPUT_PULLUP = 2,
INPUT_PULLDOWN = 3,
ANALOG = 4,
OUTPUT_LOW = 16,
OUTPUT_HIGH = 17,
};
enum edge {
RISING = 1,
FALLING = 2,
BOTH = 3,
};
typedef struct {
void *user_data;
uint32_t edge;
void (*pin_change)(void *user_data, pin_t pin, uint32_t value);
} pin_watch_config_t;
typedef struct {
void *user_data;
pin_t sck;
pin_t mosi;
pin_t miso;
uint32_t mode;
void (*done)(void *user_data, uint8_t *buffer, uint32_t count);
uint32_t reserved[8];
} spi_config_t;
typedef uint32_t spi_dev_t;
typedef struct {
void *user_data;
uint32_t address;
pin_t scl;
pin_t sda;
bool (*connect)(void *user_data, uint32_t address, bool read);
uint8_t (*read)(void *user_data);
bool (*write)(void *user_data, uint8_t data);
void (*disconnect)(void *user_data);
uint32_t reserved[8];
} i2c_config_t;
typedef uint32_t i2c_dev_t;
typedef uint32_t buffer_t;
extern __attribute__((export_name("chipInit"))) void chip_init(void);
extern __attribute__((import_name("pinInit"))) pin_t pin_init(const char *name, uint32_t mode);
extern __attribute__((import_name("pinWatch"))) bool pin_watch(pin_t pin, const pin_watch_config_t *config);
extern __attribute__((import_name("pinWatchStop"))) void pin_watch_stop(pin_t pin);
extern __attribute__((import_name("pinMode"))) void pin_mode(pin_t pin, uint32_t value);
extern __attribute__((import_name("pinRead"))) uint32_t pin_read(pin_t pin);
extern __attribute__((import_name("pinWrite"))) void pin_write(pin_t pin, uint32_t value);
extern __attribute__((import_name("spiInit"))) spi_dev_t spi_init(const spi_config_t *config);
extern __attribute__((import_name("spiStart"))) void spi_start(const spi_dev_t spi, uint8_t *buffer, uint32_t count);
extern __attribute__((import_name("spiStop"))) void spi_stop(const spi_dev_t spi);
extern __attribute__((import_name("i2cInit"))) i2c_dev_t i2c_init(const i2c_config_t *config);
extern __attribute__((import_name("framebufferInit"))) buffer_t framebuffer_init(uint32_t *pixel_width, uint32_t *pixel_height);
extern __attribute__((import_name("bufferWrite"))) void buffer_write(buffer_t buffer, uint32_t offset, void *data, uint32_t data_len);
#endif