diff --git a/32blit-pico/input/gpio.cpp b/32blit-pico/input/gpio.cpp index ca2894261..410506def 100644 --- a/32blit-pico/input/gpio.cpp +++ b/32blit-pico/input/gpio.cpp @@ -88,5 +88,5 @@ void update_input() { new_buttons |= 1 << i; } - blit::api.buttons = new_buttons; + blit::api_data.buttons = new_buttons; } diff --git a/32blit-pico/input/usb_hid.cpp b/32blit-pico/input/usb_hid.cpp index 9bc0750ac..2ea8f3e7c 100644 --- a/32blit-pico/input/usb_hid.cpp +++ b/32blit-pico/input/usb_hid.cpp @@ -110,7 +110,7 @@ void update_input() { } } - api.buttons = new_buttons; + api_data.buttons = new_buttons; } if(!hid_gamepad_id) @@ -121,19 +121,19 @@ void update_input() { while(mapping->id && mapping->id != hid_gamepad_id) mapping++; - api.buttons = dpad_map[hid_hat > 8 ? 8 : hid_hat] - | (hid_buttons & (1 << mapping->left) ? uint32_t(Button::DPAD_LEFT) : 0) - | (hid_buttons & (1 << mapping->right) ? uint32_t(Button::DPAD_RIGHT) : 0) - | (hid_buttons & (1 << mapping->up) ? uint32_t(Button::DPAD_UP) : 0) - | (hid_buttons & (1 << mapping->down) ? uint32_t(Button::DPAD_DOWN) : 0) - | (hid_buttons & (1 << mapping->a) ? uint32_t(Button::A) : 0) - | (hid_buttons & (1 << mapping->b) ? uint32_t(Button::B) : 0) - | (hid_buttons & (1 << mapping->x) ? uint32_t(Button::X) : 0) - | (hid_buttons & (1 << mapping->y) ? uint32_t(Button::Y) : 0) - | (hid_buttons & (1 << mapping->menu) ? uint32_t(Button::MENU) : 0) - | (hid_buttons & (1 << mapping->home) ? uint32_t(Button::HOME) : 0) - | (hid_buttons & (1 << mapping->joystick) ? uint32_t(Button::JOYSTICK) : 0); - - api.joystick.x = (float(hid_joystick[0]) - 0x80) / 0x80; - api.joystick.y = (float(hid_joystick[1]) - 0x80) / 0x80; + api_data.buttons = dpad_map[hid_hat > 8 ? 8 : hid_hat] + | (hid_buttons & (1 << mapping->left) ? uint32_t(Button::DPAD_LEFT) : 0) + | (hid_buttons & (1 << mapping->right) ? uint32_t(Button::DPAD_RIGHT) : 0) + | (hid_buttons & (1 << mapping->up) ? uint32_t(Button::DPAD_UP) : 0) + | (hid_buttons & (1 << mapping->down) ? uint32_t(Button::DPAD_DOWN) : 0) + | (hid_buttons & (1 << mapping->a) ? uint32_t(Button::A) : 0) + | (hid_buttons & (1 << mapping->b) ? uint32_t(Button::B) : 0) + | (hid_buttons & (1 << mapping->x) ? uint32_t(Button::X) : 0) + | (hid_buttons & (1 << mapping->y) ? uint32_t(Button::Y) : 0) + | (hid_buttons & (1 << mapping->menu) ? uint32_t(Button::MENU) : 0) + | (hid_buttons & (1 << mapping->home) ? uint32_t(Button::HOME) : 0) + | (hid_buttons & (1 << mapping->joystick) ? uint32_t(Button::JOYSTICK) : 0); + + api_data.joystick.x = (float(hid_joystick[0]) - 0x80) / 0x80; + api_data.joystick.y = (float(hid_joystick[1]) - 0x80) / 0x80; } diff --git a/32blit-pico/led.cpp b/32blit-pico/led.cpp index 7fae6aa42..d6f755781 100644 --- a/32blit-pico/led.cpp +++ b/32blit-pico/led.cpp @@ -39,11 +39,11 @@ void update_led() { #ifdef HAVE_LED const float gamma = 2.8; - uint16_t value = (uint16_t)(std::pow((float)(api.LED.r) / 255.0f, gamma) * 65535.0f + 0.5f); + uint16_t value = (uint16_t)(std::pow((float)(api_data.LED.r) / 255.0f, gamma) * 65535.0f + 0.5f); pwm_set_gpio_level(led_pins[0], value); - value = (uint16_t)(std::pow((float)(api.LED.g) / 255.0f, gamma) * 65535.0f + 0.5f); + value = (uint16_t)(std::pow((float)(api_data.LED.g) / 255.0f, gamma) * 65535.0f + 0.5f); pwm_set_gpio_level(led_pins[1], value); - value = (uint16_t)(std::pow((float)(api.LED.b) / 255.0f, gamma) * 65535.0f + 0.5f); + value = (uint16_t)(std::pow((float)(api_data.LED.b) / 255.0f, gamma) * 65535.0f + 0.5f); pwm_set_gpio_level(led_pins[2], value); #endif } diff --git a/32blit-pico/main.cpp b/32blit-pico/main.cpp index 67143e150..d5c6834a6 100644 --- a/32blit-pico/main.cpp +++ b/32blit-pico/main.cpp @@ -99,6 +99,76 @@ static GameMetadata get_metadata() { return ret; } +// blit API +static const blit::APIConst blit_api_const { + blit::api_version_major, blit::api_version_minor, + + ::channels, + + ::set_screen_mode, + ::set_screen_palette, + + ::now, + ::random, + nullptr, // exit + ::debug, + + ::open_file, + ::read_file, + ::write_file, + ::close_file, + ::get_file_length, + ::list_files, + ::file_exists, + ::directory_exists, + ::create_directory, + ::rename_file, + ::remove_file, + ::get_save_path, + ::is_storage_available, + + nullptr, // enable_us_timer + ::get_us_timer, + ::get_max_us_timer, + + nullptr, // decode_jpeg_buffer + nullptr, // decode_jpeg_file + + nullptr, // launch + nullptr, // erase_game + nullptr, // get_type_handler_metadata + + ::get_launch_path, + + ::is_multiplayer_connected, + ::set_multiplayer_enabled, + ::send_multiplayer_message, + + nullptr, // flash_to_tmp + nullptr, // tmp_file_closed + + ::get_metadata, + + ::set_screen_mode_format, + + nullptr, // i2c_send + nullptr, // i2c_recieve + + nullptr, // set_raw_cdc_enabled + nullptr, // cdc_write + nullptr, // cdc_read + + nullptr, // list_installed_games + nullptr, // can_launch +}; + +static blit::APIData blit_api_data; + +namespace blit { + const APIConst &api = blit_api_const; + APIData &api_data = blit_api_data; +} + // user funcs void init(); void render(uint32_t); @@ -141,59 +211,6 @@ int main() { stdio_init_all(); - api.channels = ::channels; - - api.set_screen_mode = ::set_screen_mode; - api.set_screen_palette = ::set_screen_palette; - api.set_screen_mode_format = ::set_screen_mode_format; - api.now = ::now; - api.random = ::random; - // api.exit = ::exit; - - // serial debug - api.debug = ::debug; - - // files - api.open_file = ::open_file; - api.read_file = ::read_file; - api.write_file = ::write_file; - api.close_file = ::close_file; - api.get_file_length = ::get_file_length; - api.list_files = ::list_files; - api.file_exists = ::file_exists; - api.directory_exists = ::directory_exists; - api.create_directory = ::create_directory; - api.rename_file = ::rename_file; - api.remove_file = ::remove_file; - api.get_save_path = ::get_save_path; - api.is_storage_available = ::is_storage_available; - - // profiler - // api.enable_us_timer = ::enable_us_timer; - api.get_us_timer = ::get_us_timer; - api.get_max_us_timer = ::get_max_us_timer; - - // jpeg - // api.decode_jpeg_buffer = ::decode_jpeg_buffer; - // api.decode_jpeg_file = ::decode_jpeg_file; - - // launcher - // api.launch = ::launch; - // api.erase_game = ::erase_game; - // api.get_type_handler_metadata = ::get_type_handler_metadata; - - api.get_launch_path = ::get_launch_path; - - // multiplayer - api.is_multiplayer_connected = ::is_multiplayer_connected; - api.set_multiplayer_enabled = ::set_multiplayer_enabled; - api.send_message = ::send_multiplayer_message; - - // api.flash_to_tmp = ::flash_to_tmp; - // api.tmp_file_closed = ::tmp_file_closed; - - api.get_metadata = ::get_metadata; - init_led(); init_display(); init_input(); diff --git a/32blit-pico/multiplayer.cpp b/32blit-pico/multiplayer.cpp index 3def9e473..32cacf3f9 100644 --- a/32blit-pico/multiplayer.cpp +++ b/32blit-pico/multiplayer.cpp @@ -46,8 +46,8 @@ void update_multiplayer() { mp_buffer_off += usb_cdc_read(mp_buffer + mp_buffer_off, mp_buffer_len - mp_buffer_off); if(mp_buffer_off == mp_buffer_len) { - if(blit::api.message_received) - blit::api.message_received(mp_buffer, mp_buffer_len); + if(blit::api_data.message_received) + blit::api_data.message_received(mp_buffer, mp_buffer_len); delete[] mp_buffer; mp_buffer = nullptr; diff --git a/32blit-sdl/Audio.cpp b/32blit-sdl/Audio.cpp index 38dab6702..b0060377c 100644 --- a/32blit-sdl/Audio.cpp +++ b/32blit-sdl/Audio.cpp @@ -7,13 +7,9 @@ #include "audio/audio.hpp" #include "engine/api_private.hpp" -blit::AudioChannel channels[CHANNEL_COUNT]; - static void _audio_callback(void *userdata, uint8_t *stream, int len); Audio::Audio() { - blit::api.channels = channels; - SDL_AudioSpec desired = {}, audio_spec = {}; desired.freq = _sample_rate; diff --git a/32blit-sdl/Multiplayer.cpp b/32blit-sdl/Multiplayer.cpp index a12c35f57..1c41eaf34 100644 --- a/32blit-sdl/Multiplayer.cpp +++ b/32blit-sdl/Multiplayer.cpp @@ -25,7 +25,7 @@ Multiplayer::~Multiplayer() { void Multiplayer::update() { if(!enabled) return; - + if(!socket && !listen_socket) { // attempt to reconnect auto now = SDL_GetTicks(); @@ -131,8 +131,8 @@ void Multiplayer::update() { // got message, pass to user if(recv_off == recv_len) { - if(api.message_received) - api.message_received(recv_buf, recv_len); + if(api_data.message_received) + api_data.message_received(recv_buf, recv_len); delete[] recv_buf; recv_buf = nullptr; diff --git a/32blit-sdl/System.cpp b/32blit-sdl/System.cpp index d005b5a48..d0014d7d5 100644 --- a/32blit-sdl/System.cpp +++ b/32blit-sdl/System.cpp @@ -15,6 +15,9 @@ extern Input *blit_input; +// blit audio channels +static blit::AudioChannel channels[CHANNEL_COUNT]; + int System::width = System::max_width; int System::height = System::max_height; @@ -168,6 +171,75 @@ void blit_send_message(const uint8_t *data, uint16_t length) { blit_multiplayer->send_message(data, length); } +// blit API +static const blit::APIConst blit_api_const { + blit::api_version_major, blit::api_version_minor, + channels, + + ::set_screen_mode, + ::set_screen_palette, + + ::now, + ::blit_random, + nullptr, // exit + ::blit_debug, + + ::open_file, + ::read_file, + ::write_file, + ::close_file, + ::get_file_length, + ::list_files, + ::file_exists, + ::directory_exists, + ::create_directory, + ::rename_file, + ::remove_file, + ::get_save_path, + ::is_storage_available, + + ::enable_us_timer, + ::get_us_timer, + ::get_max_us_timer, + + blit_decode_jpeg_buffer, + blit_decode_jpeg_file, + + nullptr, // launch + nullptr, // erase_game + nullptr, // get_type_handler_metadata + + ::get_launch_path, + + blit_is_multiplayer_connected, + blit_set_multiplayer_enabled, + blit_send_message, + + nullptr, // flash_to_tmp + nullptr, // tmp_file_closed + + ::get_metadata, + + ::set_screen_mode_format, + + nullptr, // i2c_send + nullptr, // i2c_recieve + + nullptr, // set_raw_cdc_enabled + nullptr, // cdc_write + nullptr, // cdc_read + + nullptr, // list_installed_games + nullptr, // can_launch +}; + +static blit::APIData blit_api_data; + +namespace blit { + const APIConst &api = blit_api_const; + APIData &api_data = blit_api_data; +} + // SDL events const Uint32 System::timer_event = SDL_RegisterEvents(2); const Uint32 System::loop_event = System::timer_event + 1; @@ -208,46 +280,11 @@ void System::run() { start = std::chrono::steady_clock::now(); - blit::api.now = ::now; - blit::api.random = ::blit_random; - blit::api.debug = ::blit_debug; - blit::api.set_screen_mode = ::set_screen_mode; - blit::api.set_screen_palette = ::set_screen_palette; - blit::api.set_screen_mode_format = ::set_screen_mode_format; blit::update = ::update; blit::render = ::render; setup_base_path(); - blit::api.open_file = ::open_file; - blit::api.read_file = ::read_file; - blit::api.write_file = ::write_file; - blit::api.close_file = ::close_file; - blit::api.get_file_length = ::get_file_length; - blit::api.list_files = ::list_files; - blit::api.file_exists = ::file_exists; - blit::api.directory_exists = ::directory_exists; - blit::api.create_directory = ::create_directory; - blit::api.rename_file = ::rename_file; - blit::api.remove_file = ::remove_file; - blit::api.get_save_path = ::get_save_path; - blit::api.is_storage_available = ::is_storage_available; - - blit::api.enable_us_timer = ::enable_us_timer; - blit::api.get_us_timer = ::get_us_timer; - blit::api.get_max_us_timer = ::get_max_us_timer; - - blit::api.decode_jpeg_buffer = blit_decode_jpeg_buffer; - blit::api.decode_jpeg_file = blit_decode_jpeg_file; - - blit::api.get_launch_path = ::get_launch_path; - - blit::api.is_multiplayer_connected = blit_is_multiplayer_connected; - blit::api.set_multiplayer_enabled = blit_set_multiplayer_enabled; - blit::api.send_message = blit_send_message; - - blit::api.get_metadata = ::get_metadata; - blit::set_screen_mode(blit::lores); #ifdef __EMSCRIPTEN__ diff --git a/32blit-stm32/CMakeLists.txt b/32blit-stm32/CMakeLists.txt index db87ea987..33b1c09f8 100644 --- a/32blit-stm32/CMakeLists.txt +++ b/32blit-stm32/CMakeLists.txt @@ -55,6 +55,7 @@ add_library(BlitHalSTM32 OBJECT Middlewares/ST/STM32_USB_Host_Library/Class/CDC/Src/usbh_cdc.c Src/usbd_msc_scsi.c Src/system_stm32h7xx.c + Src/api.cpp Src/fatfs.cpp Src/fatfs_sd.c Src/usb_otg.c diff --git a/32blit-stm32/Src/32blit.cpp b/32blit-stm32/Src/32blit.cpp index 2a7bdd7c9..be3659a20 100644 --- a/32blit-stm32/Src/32blit.cpp +++ b/32blit-stm32/Src/32blit.cpp @@ -71,19 +71,19 @@ void DFUBoot(void) static void init_api_shared() { // Reset button state, this prevents the user app immediately seeing the last button transition used to launch the game - api.buttons.state = 0; - api.buttons.pressed = 0; - api.buttons.released = 0; + api_data.buttons.state = 0; + api_data.buttons.pressed = 0; + api_data.buttons.released = 0; // reset shared outputs - api.vibration = 0.0f; - api.LED = Pen(); + api_data.vibration = 0.0f; + api_data.LED = Pen(); for(int i = 0; i < CHANNEL_COUNT; i++) api.channels[i] = AudioChannel(); - api.message_received = nullptr; - api.i2c_completed = nullptr; + api_data.message_received = nullptr; + api_data.i2c_completed = nullptr; // take CDC back g_commandStream.SetParsingEnabled(true); @@ -362,17 +362,20 @@ void blit_init() { i2c::init(); - blit::api.version_major = api_version_major; - blit::api.version_minor = api_version_minor; + // bit of a hack, but we know it's writable + auto &api = *(APIConst *)&blit::api; - blit::api.debug = blit_debug; - blit::api.now = HAL_GetTick; - blit::api.random = HAL_GetRandom; - blit::api.exit = blit_exit; + api.version_major = api_version_major; + api.version_minor = api_version_minor; - blit::api.set_screen_mode = display::set_screen_mode; - blit::api.set_screen_palette = display::set_screen_palette; - blit::api.set_screen_mode_format = display::set_screen_mode_format; + api.debug = blit_debug; + api.now = HAL_GetTick; + api.random = HAL_GetRandom; + api.exit = blit_exit; + + api.set_screen_mode = display::set_screen_mode; + api.set_screen_palette = display::set_screen_palette; + api.set_screen_mode_format = display::set_screen_mode_format; display::set_screen_mode(blit::lores); @@ -380,43 +383,43 @@ void blit_init() { blit::render = ::render; blit::init = ::init; - blit::api.open_file = ::open_file; - blit::api.read_file = ::read_file; - blit::api.write_file = ::write_file; - blit::api.close_file = ::close_file; - blit::api.get_file_length = ::get_file_length; - blit::api.list_files = ::list_files; - blit::api.file_exists = ::file_exists; - blit::api.directory_exists = ::directory_exists; - blit::api.create_directory = ::create_directory; - blit::api.rename_file = ::rename_file; - blit::api.remove_file = ::remove_file; - blit::api.get_save_path = ::get_save_path; - blit::api.is_storage_available = blit_sd_mounted; + api.open_file = ::open_file; + api.read_file = ::read_file; + api.write_file = ::write_file; + api.close_file = ::close_file; + api.get_file_length = ::get_file_length; + api.list_files = ::list_files; + api.file_exists = ::file_exists; + api.directory_exists = ::directory_exists; + api.create_directory = ::create_directory; + api.rename_file = ::rename_file; + api.remove_file = ::remove_file; + api.get_save_path = ::get_save_path; + api.is_storage_available = blit_sd_mounted; - blit::api.enable_us_timer = ::enable_us_timer; - blit::api.get_us_timer = ::get_us_timer; - blit::api.get_max_us_timer = ::get_max_us_timer; + api.enable_us_timer = ::enable_us_timer; + api.get_us_timer = ::get_us_timer; + api.get_max_us_timer = ::get_max_us_timer; - blit::api.decode_jpeg_buffer = blit_decode_jpeg_buffer; - blit::api.decode_jpeg_file = blit_decode_jpeg_file; + api.decode_jpeg_buffer = blit_decode_jpeg_buffer; + api.decode_jpeg_file = blit_decode_jpeg_file; - blit::api.get_launch_path = ::get_launch_path; + api.get_launch_path = ::get_launch_path; - blit::api.is_multiplayer_connected = multiplayer::is_connected; - blit::api.set_multiplayer_enabled = multiplayer::set_enabled; - blit::api.send_message = multiplayer::send_message; + api.is_multiplayer_connected = multiplayer::is_connected; + api.set_multiplayer_enabled = multiplayer::set_enabled; + api.send_message = multiplayer::send_message; - blit::api.get_metadata = ::get_metadata; + api.get_metadata = ::get_metadata; - blit::api.tick_function_changed = false; + api_data.tick_function_changed = false; - blit::api.i2c_send = i2c::user_send; - blit::api.i2c_receive = i2c::user_receive; + api.i2c_send = i2c::user_send; + api.i2c_receive = i2c::user_receive; - blit::api.set_raw_cdc_enabled = set_raw_cdc_enabled; - blit::api.cdc_write = cdc_write; - blit::api.cdc_read = cdc_read; + api.set_raw_cdc_enabled = set_raw_cdc_enabled; + api.cdc_write = cdc_write; + api.cdc_read = cdc_read; display::init(); @@ -492,7 +495,7 @@ void blit_menu() { if (user_tick && !user_code_disabled) { // user code was running do_tick = user_tick; - api.tick_function_changed = true; + api_data.tick_function_changed = true; blit::render = user_render; } else { blit::update = ::update; @@ -513,7 +516,7 @@ void blit_menu() { blit::update = blit_menu_update; blit::render = blit_menu_render; do_tick = blit::tick; - api.tick_function_changed = true; + api_data.tick_function_changed = true; if(screen.format == PixelFormat::P) { memcpy(menu_saved_colours, screen.palette, num_menu_colours * sizeof(Pen)); @@ -671,7 +674,7 @@ bool blit_switch_execution(uint32_t address, bool force_game) blit::render = ::render; blit::update = ::update; do_tick = blit::tick; - api.tick_function_changed = true; + api_data.tick_function_changed = true; cached_file_in_tmp = false; close_open_files(); @@ -741,7 +744,7 @@ void blit_enable_user_code() { return; do_tick = user_tick; - api.tick_function_changed = true; + api_data.tick_function_changed = true; blit::render = user_render; user_code_disabled = false; sound::enabled = true; @@ -752,7 +755,7 @@ void blit_disable_user_code() { return; do_tick = blit::tick; - api.tick_function_changed = true; + api_data.tick_function_changed = true; blit::render = ::render; sound::enabled = false; user_code_disabled = true; diff --git a/32blit-stm32/Src/32blit/i2c.cpp b/32blit-stm32/Src/32blit/i2c.cpp index 679da2179..bad611a32 100644 --- a/32blit-stm32/Src/32blit/i2c.cpp +++ b/32blit-stm32/Src/32blit/i2c.cpp @@ -186,8 +186,8 @@ namespace i2c { { auto addr = user_addr; user_addr = 0; - if(api.i2c_completed && !blit_user_code_disabled()) - api.i2c_completed(addr, user_reg, user_buf, user_buf_len); + if(api_data.i2c_completed && !blit_user_code_disabled()) + api_data.i2c_completed(addr, user_reg, user_buf, user_buf_len); blit_i2c_delay(16, SEND_ACL); break; diff --git a/32blit-stm32/Src/api.cpp b/32blit-stm32/Src/api.cpp new file mode 100644 index 000000000..3e204ec06 --- /dev/null +++ b/32blit-stm32/Src/api.cpp @@ -0,0 +1,14 @@ +#include "engine/api_private.hpp" + +extern char __api_start; +#pragma GCC diagnostic ignored "-Warray-bounds" + +#ifndef BLIT_API_SPLIT_COMPAT +#error "BLIT_API_SPLIT_COMPAT not set!" +#endif + +namespace blit { + // for compatibility reasons, these are the same thing + const APIConst &api = *(APIConst *)&__api_start; + APIData &api_data = *(APIData *)&__api_start; +} diff --git a/32blit-stm32/Src/multiplayer.cpp b/32blit-stm32/Src/multiplayer.cpp index 75356b95b..aa896ca5c 100644 --- a/32blit-stm32/Src/multiplayer.cpp +++ b/32blit-stm32/Src/multiplayer.cpp @@ -41,8 +41,8 @@ namespace multiplayer { // done, send to user if(read == length) { - if(api.message_received && enabled) - api.message_received(buf, length); + if(api_data.message_received && enabled) + api_data.message_received(buf, length); delete[] buf; buf = nullptr; diff --git a/32blit-stm32/Src/sound.cpp b/32blit-stm32/Src/sound.cpp index 306907e49..32aa19932 100644 --- a/32blit-stm32/Src/sound.cpp +++ b/32blit-stm32/Src/sound.cpp @@ -36,7 +36,7 @@ namespace sound { bool enabled = true; void init() { - blit::api.channels = channels; + ((APIConst *) &blit::api)->channels = channels; // setup the 22,010Hz audio timer HAL_NVIC_EnableIRQ(TIM6_DAC_IRQn); diff --git a/32blit-stm32/executable.cmake b/32blit-stm32/executable.cmake index 3ffc25567..aee239e5a 100644 --- a/32blit-stm32/executable.cmake +++ b/32blit-stm32/executable.cmake @@ -1,7 +1,7 @@ set(MCU_LINKER_SCRIPT "${CMAKE_CURRENT_LIST_DIR}/${MCU_LINKER_SCRIPT}") set(HAL_DIR ${CMAKE_CURRENT_LIST_DIR}) -set(USER_STARTUP ${CMAKE_CURRENT_LIST_DIR}/startup_user.S ${CMAKE_CURRENT_LIST_DIR}/startup_user.cpp) +set(USER_STARTUP ${CMAKE_CURRENT_LIST_DIR}/startup_user.S ${CMAKE_CURRENT_LIST_DIR}/startup_user.cpp ${CMAKE_CURRENT_LIST_DIR}/Src/api.cpp) function(blit_executable_common NAME) target_link_libraries(${NAME} BlitEngine) diff --git a/32blit.toolchain b/32blit.toolchain index 98f5fa514..5d2fde5ae 100644 --- a/32blit.toolchain +++ b/32blit.toolchain @@ -20,7 +20,7 @@ endif () set(CDC_FIFO_BUFFERS 64) -set(COMMON_FLAGS "${MCU_FLAGS} -fsingle-precision-constant -Wall -fdata-sections -ffunction-sections -Wattributes -Wdouble-promotion -Werror=double-promotion -mno-pic-data-is-text-relative -mno-single-pic-base") +set(COMMON_FLAGS "${MCU_FLAGS} -fsingle-precision-constant -Wall -fdata-sections -ffunction-sections -Wattributes -Wdouble-promotion -Werror=double-promotion -mno-pic-data-is-text-relative -mno-single-pic-base -DBLIT_API_SPLIT_COMPAT") set(CMAKE_C_FLAGS_INIT "${COMMON_FLAGS}") set(CMAKE_CXX_FLAGS_INIT "${COMMON_FLAGS} -fno-exceptions") diff --git a/32blit/audio/audio.hpp b/32blit/audio/audio.hpp index ae41008ee..513f14932 100644 --- a/32blit/audio/audio.hpp +++ b/32blit/audio/audio.hpp @@ -127,7 +127,7 @@ namespace blit { } }; - extern AudioChannel *&channels; + extern AudioChannel * const &channels; uint16_t get_audio_frame(); bool is_audio_playing(); diff --git a/32blit/engine/api.cpp b/32blit/engine/api.cpp index b5fe943a9..d7afe9249 100644 --- a/32blit/engine/api.cpp +++ b/32blit/engine/api.cpp @@ -1,28 +1,16 @@ #include "api.hpp" #include "api_private.hpp" -#ifdef TARGET_32BLIT_HW -extern char __api_start; -#pragma GCC diagnostic ignored "-Warray-bounds" -#endif - namespace blit { -#ifdef TARGET_32BLIT_HW - API &api = *(API *)&__api_start; -#else - API real_api; - API &api = real_api; -#endif - - static_assert(sizeof(API) < 2048); + static_assert(sizeof(APIConst) < 2048); - ButtonState &buttons = api.buttons; - float &hack_left = api.hack_left; - float &hack_right = api.hack_right; - float &vibration = api.vibration; - Vec2 &joystick = api.joystick; - Vec3 &tilt = api.tilt; - Pen &LED = api.LED; + ButtonState &buttons = api_data.buttons; + float &hack_left = api_data.hack_left; + float &hack_right = api_data.hack_right; + float &vibration = api_data.vibration; + Vec2 &joystick = api_data.joystick; + Vec3 &tilt = api_data.tilt; + Pen &LED = api_data.LED; - AudioChannel *&channels = api.channels; -} \ No newline at end of file + AudioChannel * const &channels = api.channels; +} diff --git a/32blit/engine/api_private.hpp b/32blit/engine/api_private.hpp index 4be7a539b..14d09b859 100644 --- a/32blit/engine/api_private.hpp +++ b/32blit/engine/api_private.hpp @@ -14,6 +14,13 @@ #include "../types/vec2.hpp" #include "../types/vec3.hpp" +// compatibility with API layout before const/data split +#ifdef BLIT_API_SPLIT_COMPAT +#define COMPAT_PAD(type, name, size) type name[size] +#else +#define COMPAT_PAD(type, name, size) +#endif + namespace blit { using AllocateCallback = uint8_t *(*)(size_t); @@ -62,17 +69,11 @@ namespace blit { }; #pragma pack(push, 4) - struct API { + struct APIConst { uint16_t version_major; uint16_t version_minor; - ButtonState buttons; - float hack_left; - float hack_right; - float vibration; - Vec2 joystick; - Vec3 tilt; - Pen LED; + COMPAT_PAD(uint8_t, pad, 48); // was data AudioChannel *channels; @@ -120,21 +121,21 @@ namespace blit { bool (*is_multiplayer_connected)(); void (*set_multiplayer_enabled)(bool enabled); void (*send_message)(const uint8_t *data, uint16_t len); - void (*message_received)(const uint8_t *data, uint16_t len); // set by user + COMPAT_PAD(uintptr_t, pad2, 1); // was message_recieved const uint8_t *(*flash_to_tmp)(const std::string &filename, uint32_t &size); void (*tmp_file_closed)(const uint8_t *ptr); GameMetadata (*get_metadata)(); - bool tick_function_changed; + COMPAT_PAD(uint8_t, pad3, 1); // was data bool (*set_screen_mode_format)(ScreenMode new_mode, SurfaceTemplate &new_surf_template); // raw i2c access bool (*i2c_send)(uint8_t address, uint8_t reg, const uint8_t *data, uint16_t len); bool (*i2c_receive)(uint8_t address, uint8_t reg, uint8_t *data, uint16_t len); - void (*i2c_completed)(uint8_t address, uint8_t reg, const uint8_t *data, uint16_t len); // callback when done + COMPAT_PAD(uintptr_t, pad4, 1); // was i2c_completed // raw cdc bool (*set_raw_cdc_enabled)(bool enabled); @@ -147,7 +148,43 @@ namespace blit { // files this returns success for should be .blit files or have a registered handler (get_type_handler_metadata should return valid metadata) CanLaunchResult (*can_launch)(const char *path); }; + + struct APIData { + uint16_t pad[2]; + + ButtonState buttons; + float hack_left; + float hack_right; + float vibration; + Vec2 joystick; + Vec3 tilt; + Pen LED; + + COMPAT_PAD(uintptr_t, pad2, 32); + + // multiplayer + void (*message_received)(const uint8_t *data, uint16_t len); // set by user + + COMPAT_PAD(uintptr_t, pad3, 3); + + bool tick_function_changed; + + COMPAT_PAD(uintptr_t, pad4, 3); + + // raw i2c access + void (*i2c_completed)(uint8_t address, uint8_t reg, const uint8_t *data, uint16_t len); // callback when done + + COMPAT_PAD(uintptr_t, pad5, 5); + }; + #pragma pack(pop) - extern API &api; +#ifdef BLIT_API_SPLIT_COMPAT + static_assert(sizeof(APIConst) == sizeof(APIData)); +#else + static_assert(sizeof(APIData) <= 256); +#endif + + extern const APIConst &api; + extern APIData &api_data; } diff --git a/32blit/engine/engine.cpp b/32blit/engine/engine.cpp index 80b1679b0..ba34c1e92 100644 --- a/32blit/engine/engine.cpp +++ b/32blit/engine/engine.cpp @@ -107,7 +107,7 @@ namespace blit { } // skip time where this wasn't the active tick function (menu/game switches) - if (api.tick_function_changed) { + if (api_data.tick_function_changed) { auto skipped_time = time - last_tick_time; last_tick_time = time; @@ -121,7 +121,7 @@ namespace blit { tween->paused += skipped_time; } - api.tick_function_changed = false; + api_data.tick_function_changed = false; } // update timers @@ -132,11 +132,11 @@ namespace blit { pending_update_time += (time - last_tick_time); while (pending_update_time >= update_rate_ms) { // button state changes - uint32_t changed = api.buttons.state ^ last_state; + uint32_t changed = api_data.buttons.state ^ last_state; - api.buttons.pressed = changed & api.buttons.state; - api.buttons.released = changed & last_state; - last_state = api.buttons.state; + api_data.buttons.pressed = changed & api_data.buttons.state; + api_data.buttons.released = changed & last_state; + last_state = api_data.buttons.state; update(time - pending_update_time); // create fake timestamp that would have been accurate for the update event pending_update_time -= update_rate_ms; diff --git a/32blit/engine/multiplayer.cpp b/32blit/engine/multiplayer.cpp index 3dc8b85a2..9aa3b2edb 100644 --- a/32blit/engine/multiplayer.cpp +++ b/32blit/engine/multiplayer.cpp @@ -18,5 +18,5 @@ namespace blit { api.send_message(data, len); } - void (*&message_received)(const uint8_t *data, uint16_t len) = api.message_received; -} \ No newline at end of file + void (*&message_received)(const uint8_t *data, uint16_t len) = api_data.message_received; +} diff --git a/firmware/firmware.cpp b/firmware/firmware.cpp index 85acde332..08f0bb96f 100644 --- a/firmware/firmware.cpp +++ b/firmware/firmware.cpp @@ -690,6 +690,10 @@ static void start_launcher() { } void init() { + // bit of a hack, but we know it's writable + // ... or is the fact part of the "const" api is set much later, the bigger hack? + auto &api = *(APIConst *)&blit::api; + api.launch = launch_file_from_sd; api.erase_game = erase_flash_game; api.get_type_handler_metadata = get_type_handler_metadata;