Skip to content

Commit c4ca8d7

Browse files
committed
riscv32: embedded JIT on esp32
Signed-off-by: Paul Guyot <pguyot@kallisys.net>
1 parent 28084fc commit c4ca8d7

File tree

3 files changed

+162
-11
lines changed

3 files changed

+162
-11
lines changed

src/platforms/esp32/components/avm_sys/CMakeLists.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,8 @@ set(AVM_SYS_COMPONENT_SRCS
2525
"sys.c"
2626
"platform_nifs.c"
2727
"platform_defaultatoms.c"
28-
"jit_stream_flash.c"
28+
"jit_stream_flash_platform.c"
29+
"../../../../libAtomVM/jit_stream_flash.c"
2930
"../../../../libAtomVM/inet.c"
3031
"../../../../libAtomVM/otp_crypto.c"
3132
"../../../../libAtomVM/otp_net.c"

src/platforms/esp32/components/avm_sys/jit_stream_flash.c renamed to src/platforms/esp32/components/avm_sys/include/jit_stream_flash_platform.h

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -18,17 +18,26 @@
1818
* SPDX-License-Identifier: Apache-2.0 OR LGPL-2.1-or-later
1919
*/
2020

21-
#ifndef AVM_NO_JIT
21+
#ifndef _JIT_STREAM_FLASH_PLATFORM_H_
22+
#define _JIT_STREAM_FLASH_PLATFORM_H_
2223

23-
#include "context.h"
24-
#include "jit.h"
25-
#include "term.h"
24+
#include <stdbool.h>
25+
#include <stddef.h>
26+
#include <stdint.h>
2627

27-
ModuleNativeEntryPoint jit_stream_entry_point(Context *ctx, term jit_stream)
28-
{
29-
UNUSED(ctx);
30-
UNUSED(jit_stream);
31-
return NULL;
32-
}
28+
#ifdef __cplusplus
29+
extern "C" {
30+
#endif
31+
32+
// ESP32 flash constants
33+
#define FLASH_SECTOR_SIZE 4096
34+
#define FLASH_PAGE_SIZE 256
3335

36+
// JIT code is stored in main.avm partition
37+
#define JIT_PARTITION_NAME "main.avm"
38+
39+
#ifdef __cplusplus
40+
}
3441
#endif
42+
43+
#endif // _JIT_STREAM_FLASH_PLATFORM_H_
Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
/*
2+
* This file is part of AtomVM.
3+
*
4+
* Copyright 2025 by Paul Guyot <pguyot@kallisys.net>
5+
*
6+
* Licensed under the Apache License, Version 2.0 (the "License");
7+
* you may not use this file except in compliance with the License.
8+
* You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing, software
13+
* distributed under the License is distributed on an "AS IS" BASIS,
14+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
* See the License for the specific language governing permissions and
16+
* limitations under the License.
17+
*
18+
* SPDX-License-Identifier: Apache-2.0 OR LGPL-2.1-or-later
19+
*/
20+
21+
#ifndef AVM_NO_JIT
22+
23+
#include "jit_stream_flash.h"
24+
25+
#include <esp_partition.h>
26+
#include <stdio.h>
27+
28+
#include "esp32_sys.h"
29+
30+
#if ESP_IDF_VERSION_MAJOR >= 5
31+
#include <spi_flash_mmap.h>
32+
#endif
33+
34+
#ifdef CONFIG_IDF_TARGET_ARCH_RISCV
35+
#include <soc/ext_mem_defs.h>
36+
#endif
37+
38+
struct JSFlashPlatformContext
39+
{
40+
const esp_partition_t *partition;
41+
};
42+
43+
struct JSFlashPlatformContext *jit_stream_flash_platform_init(void)
44+
{
45+
const esp_partition_t *partition = esp_partition_find_first(
46+
ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_ANY, JIT_PARTITION_NAME);
47+
if (IS_NULL_PTR(partition)) {
48+
fprintf(stderr, "Failed to find partition '%s' for JIT cache\n", JIT_PARTITION_NAME);
49+
return NULL;
50+
}
51+
52+
struct JSFlashPlatformContext *pf_ctx = malloc(sizeof(struct JSFlashPlatformContext));
53+
if (IS_NULL_PTR(pf_ctx)) {
54+
return NULL;
55+
}
56+
57+
pf_ctx->partition = partition;
58+
return pf_ctx;
59+
}
60+
61+
void jit_stream_flash_platform_destroy(struct JSFlashPlatformContext *ctx)
62+
{
63+
free(ctx);
64+
}
65+
66+
bool jit_stream_flash_platform_erase_sector(struct JSFlashPlatformContext *ctx, uintptr_t addr)
67+
{
68+
if (UNLIKELY(!ctx || !ctx->partition)) {
69+
return false;
70+
}
71+
72+
size_t flash_offset = spi_flash_cache2phys((const void *) addr);
73+
if (UNLIKELY(flash_offset == SPI_FLASH_CACHE2PHYS_FAIL)) {
74+
fprintf(stderr, "Failed to convert cache address 0x%lx to physical address\n", (unsigned long) addr);
75+
return false;
76+
}
77+
78+
esp_err_t err = esp_partition_erase_range(ctx->partition,
79+
flash_offset - ctx->partition->address, FLASH_SECTOR_SIZE);
80+
if (UNLIKELY(err != ESP_OK)) {
81+
fprintf(stderr, "Failed to erase sector at offset 0x%lx: %d\n", (unsigned long) flash_offset, err);
82+
return false;
83+
}
84+
85+
return true;
86+
}
87+
88+
bool jit_stream_flash_platform_write_page(struct JSFlashPlatformContext *ctx, uintptr_t addr, const uint8_t *data)
89+
{
90+
if (UNLIKELY(!ctx || !ctx->partition)) {
91+
return false;
92+
}
93+
94+
size_t flash_offset = spi_flash_cache2phys((const void *) addr);
95+
if (UNLIKELY(flash_offset == SPI_FLASH_CACHE2PHYS_FAIL)) {
96+
fprintf(stderr, "Failed to convert cache address 0x%lx to physical address\n", (unsigned long) addr);
97+
return false;
98+
}
99+
100+
esp_err_t err = esp_partition_write(ctx->partition,
101+
flash_offset - ctx->partition->address, data, FLASH_PAGE_SIZE);
102+
if (UNLIKELY(err != ESP_OK)) {
103+
fprintf(stderr, "Failed to write page at offset 0x%lx: %d\n", (unsigned long) flash_offset, err);
104+
return false;
105+
}
106+
107+
return true;
108+
}
109+
110+
uintptr_t jit_stream_flash_platform_ptr_to_executable(uintptr_t addr)
111+
{
112+
// Convert data cache address to instruction cache address for RISC-V targets
113+
// On ESP32-C3/C6/H2, flash is mapped to both DBUS (0x3C...) and IBUS (0x42...)
114+
// but only IBUS addresses are executable
115+
#ifdef CONFIG_IDF_TARGET_ARCH_RISCV
116+
if ((addr & ~SOC_MMU_VADDR_MASK) == SOC_MMU_DBUS_VADDR_BASE) {
117+
return (addr & SOC_MMU_VADDR_MASK) | SOC_MMU_IBUS_VADDR_BASE;
118+
}
119+
return addr;
120+
#else
121+
return addr;
122+
#endif
123+
}
124+
125+
uintptr_t jit_stream_flash_platform_executable_to_ptr(uintptr_t addr)
126+
{
127+
// Convert instruction cache address to data cache address for RISC-V targets
128+
// This is the reverse of ptr_to_executable
129+
#ifdef CONFIG_IDF_TARGET_ARCH_RISCV
130+
if ((addr & ~SOC_MMU_VADDR_MASK) == SOC_MMU_IBUS_VADDR_BASE) {
131+
return (addr & SOC_MMU_VADDR_MASK) | SOC_MMU_DBUS_VADDR_BASE;
132+
}
133+
return addr;
134+
#else
135+
return addr;
136+
#endif
137+
}
138+
139+
REGISTER_NIF_COLLECTION(jit_stream_flash, jit_stream_flash_init, NULL, jit_stream_flash_get_nif)
140+
141+
#endif // AVM_NO_JIT

0 commit comments

Comments
 (0)