This document describes the work-in-progress C API for writing custom chips for the Wokwi simulator.
First, make sure to include wokwi-api.h
. Every external method you declare should be wrapped with the EXPORT
macro (e.g. void EXPORT(my_method_name) (uint32_t arg) { ... }
).
The chip should declare a chip_init
method. This method will be called for every new instance of the chip. If the chip has some internal state, chip_init
should allocate memory for the internal state and return a pointer to this memory.
This pointer will be passed in the first argument for any listener that you declare (e.g. chip_pin_change
). For chip without any internal state, simply return NULL.
Here's an example of a minimal chip file:
#include "wokwi-api.h"
void* EXPORT(chip_init)(void) {
/* This method runs when the simulation starts. It's called once for each instance of the chip. */
/* It should return a pointer to a structure with chip instance specific data, or NULL if the chip has no internal state. */
return NULL;
}
Chips interacts with the simulation using digital pins. Use the DECLARE_PIN
macro to define your pins, e.g.:
DECLARE_PIN(VCC);
DECLARE_PIN(GND);
DECLARE_PIN(SCL);
DECLARE_PIN(SDA);
DECLARE_PIN(INT);
Then use the pins in the code by calling the PIN
macro. For instance, the following code will configure the INT
pin as a digital output pin:
pin_mode(PIN(INT), OUTPUT);
The following API methods interact with GPIO pins:
Configures the given pin
as digital input or output. The valid values for mode
are: INPUT
, OUTPUT
, INPUT_PULLUP
and INPUT_PULLDOWN
.
Set the output value for a digital pin. Use the LOW
and HIGH
constants for value
.
Reads the current digital value of the pin, returns either LOW
or HIGH
.
Listens for changes in the digital value of the given pin. The valid values for edge are:
BOTH
- Listen for any value changeFALLING
- Listen for HIGH to LOW changesRISING
- Listen for LOW to high changesNONE
- Stop listening for changes
You also need to declare a listener with the following signature:
void EXPORT(chip_pin_change)(void *chip, uint32_t pin, uint32_t value) {
// ...
}
This listener will be called for changes on any pin you watched with digital_watch()
.
The chip
argument is a pointer to the chip state, as returned from chip_init()
. The pin
parameter is the index of the pin, and value
is the new digital value of the pin, LOW
or HIGH
.
Returns the current simulator (virtual) time in nanoseconds.
To create an I2C device, you need to declare four callbacks: chip_i2c_connect
, chip_i2c_read
, chip_i2c_write
, and chip_i2c_disconnect
. The first two arguments for all these callbacks are a pointer to the chip state, and the index of the i2c interface.
Initializes an I2C device. The device will attach to the I2C bus on pins pin_scl
and pin_sda
, and will listen for requests matching the given address
.
Note: i2c_init
can only be called from chip_init()
. Do not call it at a later time.
Called whenever your chip is addressed on the I2C bus. The address
parameter contains the address of your device.
Return true
to acknowledge the connection, or false
to discard it.
Called when the microcontroller wants to read a byte of data from your chip.
Called when the microcontroller writes a byte to your chip. data
will contain the incoming byte. Return true
to acknowledge the transaction, or false
to terminate the connection.
Called when the microcontroller disconnects from your chip.
Attributes are input parameters that the user can set in diagram.json. You can also define a "controls" section in the "wokwi-custom-chip.json" file to let the user edit these parameters interactively during the simulation. This is particularly useful for sensor inputs (e.g. temperature, humidity, etc).
Defines a new integer attribute with the given name. The default_value
will be used when the user does not define a value for the attribute in diagram.json (under the "attrs" section of the "wokwi-custom-chip").
The function returns an handle to the attribute, which can be used by attr_read()
.
Note: attr_init
can only be called from chip_init()
. Do not call it at a later time.
Returns the current value of the attribute. attr
should be a valid attribute handle, previously returned by attr_init()
.
Defines a new floating point attribute with the given name. See attr_init()
for more info.
Note: attr_init_float
can only be called from chip_init()
. Do not call it at a later time.
Returns the current value of the attribute. attr
should be a valid attribute handle, previously returned by attr_init_float()
.