diff options
| author | Gabriel Schneider <[email protected]> | 2026-08-25 12:40:53 -0300 |
|---|---|---|
| committer | Gabriel Schneider <[email protected]> | 2026-08-25 12:46:51 -0300 |
| commit | f5f8068fac59b4f16046c2022c2fc7c7e447ef4c (patch) | |
| tree | 2731a3ed4e51cae09e184e25778eded5fc37d1f5 /src/oracle/gpio_ref.c | |
| download | esp32p4-f5f8068fac59b4f16046c2022c2fc7c7e447ef4c.tar.gz esp32p4-f5f8068fac59b4f16046c2022c2fc7c7e447ef4c.zip | |
zig-p4: pure-Zig ESP32-P4 toolchain
build.zig generates the linker script and drives Zig's own LLD; tools/image.zig
turns the ELF into a flashable image and tools/{rom,serial}.zig speak the mask
ROM loader over the UART. No CMake, ninja, idf.py, esptool, or external linker.
src/soc.zig is a comptime register model over ESP-IDF's own *_reg.h headers;
src/hal/ adds peripheral sequences; src/io/ implements std.Io for the chip;
src/oracle/ diffs this HAL against ESP-IDF's on the die.
Diffstat (limited to 'src/oracle/gpio_ref.c')
| -rw-r--r-- | src/oracle/gpio_ref.c | 116 |
1 files changed, 116 insertions, 0 deletions
diff --git a/src/oracle/gpio_ref.c b/src/oracle/gpio_ref.c new file mode 100644 index 0000000..b4070a2 --- /dev/null +++ b/src/oracle/gpio_ref.c @@ -0,0 +1,116 @@ +/* The reference implementation, which is ESP-IDF's own. + * + * ESP-IDF's `*_ll.h` headers are `static inline` functions over the same registers this project's + * Zig HAL drives. Compiled by Zig's clang for riscv32-freestanding they link into the same image as + * the Zig code, which is what makes a differential test possible at all: one binary, one boot, one + * set of clocks, both implementations, and the diff taken on the die. + * + * These wrappers exist only to give the inline functions external linkage so Zig can call them. + * There is no logic here - anything clever in this file would be a third implementation to doubt. + */ + +/* IDF's clock and reset LL functions are shadowed by a wrapper macro that references + * `__DECLARE_RCC_ATOMIC_ENV`, an identifier IDF never defines anywhere; its purpose is to make an + * unguarded call fail to compile, because the only legal caller holds a spinlock. There is no + * FreeRTOS here, and core 1 is held in reset at power-on, so declaring the name is exactly as safe + * as the spinlock would be - and it is what IDF's own bootloader does + * (bootloader_support/src/bootloader_console.c:53 declares a dummy local for the same reason). */ +static int __DECLARE_RCC_ATOMIC_ENV __attribute__((unused)); + +#include "hal/gpio_ll.h" +#include "soc/gpio_struct.h" +#include "soc/io_mux_struct.h" + +/* Whether this translation unit was built with the ROM path switched on. The harness prints it, so + * that a differential run can never silently be "my registers versus the mask ROM". */ +int oracle_gpio_uses_rom_api(void) +{ +#if HAL_CONFIG(GPIO_USE_ROM_API) + return 1; +#else + return 0; +#endif +} + +void oracle_gpio_set_level(unsigned pin, unsigned level) +{ + gpio_ll_set_level(&GPIO, pin, level); +} + +int oracle_gpio_get_level(unsigned pin) +{ + return gpio_ll_get_level(&GPIO, pin); +} + +void oracle_gpio_output_enable(unsigned pin) +{ + gpio_ll_output_enable(&GPIO, pin); +} + +void oracle_gpio_output_disable(unsigned pin) +{ + gpio_ll_output_disable(&GPIO, pin); +} + +void oracle_gpio_input_enable(unsigned pin) +{ + gpio_ll_input_enable(&GPIO, pin); +} + +void oracle_gpio_input_disable(unsigned pin) +{ + gpio_ll_input_disable(&GPIO, pin); +} + +void oracle_gpio_func_sel(unsigned pin, unsigned func) +{ + gpio_ll_func_sel(&GPIO, pin, func); +} + +void oracle_gpio_set_drive(unsigned pin, unsigned strength) +{ + gpio_ll_set_drive_capability(&GPIO, pin, (gpio_drive_cap_t)strength); +} + +void oracle_gpio_pullup_en(unsigned pin) +{ + gpio_ll_pullup_en(&GPIO, pin); +} + +void oracle_gpio_pullup_dis(unsigned pin) +{ + gpio_ll_pullup_dis(&GPIO, pin); +} + +void oracle_gpio_pulldown_en(unsigned pin) +{ + gpio_ll_pulldown_en(&GPIO, pin); +} + +void oracle_gpio_pulldown_dis(unsigned pin) +{ + gpio_ll_pulldown_dis(&GPIO, pin); +} + +/* Open drain, which lives in the GPIO block's own per-pin register (GPIO_PINn_PAD_DRIVER) rather + * than in the IO MUX pad register - a different register file for the same pad. The I2C HAL needs it + * because that bus is wired-AND, and a pin left push-pull shorts a shared bus against another + * device's driver. One bit, and expensive to get wrong. */ +void oracle_gpio_od_enable(unsigned pin) +{ + gpio_ll_od_enable(&GPIO, pin); +} + +void oracle_gpio_od_disable(unsigned pin) +{ + gpio_ll_od_disable(&GPIO, pin); +} + +/* Route a peripheral signal to a pad through the GPIO matrix. This is the one GPIO operation with a + * real sequence rather than a single field write, and therefore the one where a write-trace + * comparison can find something a state comparison cannot. */ +void oracle_gpio_matrix_out(unsigned pin, unsigned signal) +{ + gpio_ll_set_output_signal_matrix_source(&GPIO, pin, signal, false); + gpio_ll_set_output_enable_ctrl(&GPIO, pin, true, false); +} |
