diff --git a/README.md b/README.md index e9342209..5f3d1beb 100644 --- a/README.md +++ b/README.md @@ -1,13 +1,13 @@ -# RP2040 Doom +# RP2040 (+RP2350) Doom -This is a port of Doom for RP2040 devices, derived from [Chocolate Doom](https://github.com/chocolate-doom/chocolate-doom). +This is a port of Doom for RP2040 / RP2350 devices, derived from [Chocolate Doom](https://github.com/chocolate-doom/chocolate-doom). -Significant changes have been made to support running on the RP2040 device, but particularly to support running the +Significant changes have been made to support running on the RP2xxx device, but particularly to support running the entire shareware `DOOM1.WAD` which is 4M big on a Raspberry Pi Pico with only 2M flash! You can read many details on this port in the blog post [here](https://kilograham.github.io/rp2040-doom/). -Note that a hopefully-fully-functional `chocolate-doom` executable is buildable from this RP2040 code base as a +Note that a hopefully-fully-functional `chocolate-doom` executable is buildable from this RP2xxx code base as a means of verification that everything still works, but whilst they can still be built, Hexen, Strife and Heretic are almost certainly broken, so are not built by default. @@ -101,8 +101,7 @@ pico-sdk requisites (e.g. [documentation](https://datasheets.raspberrypi.com/pico/getting-started-with-pico.pdf). I have been building against the `develop` branch of `pico-sdk`, so I recommend that.. -**NOTE: I was building with arm-none-eabi-gcc 9.2.1 .. it seems like other versions may cause problems with binary -size, so stick with that for now.** +**NOTE: I am building with arm-none-eabi-gcc 13.2.rel1 .. whilst other versions may work, changes in compiler version may affect the binary size which, being tight, can cause problems (either link failure, or you may see stack overflow in the form of color palette corruption). Particularly I know tjhat arm-none-eabi-gcc 10.x versions don't work well.** For USB keyboard input support, RP2040 Doom currently uses a modified version of TinyUSB included as a submodule. Make sure you have initialized this submodule via `git submodule update --init` diff --git a/src/doomtype.h b/src/doomtype.h index f6f0aa1f..06caf3db 100644 --- a/src/doomtype.h +++ b/src/doomtype.h @@ -194,15 +194,27 @@ typedef uint8_t floor_ceiling_clip_t; #if PICO_ON_DEVICE #include +#if !PICO_RP2350 +#define SHORTPTR_BASE 0x20000000 +#else +#define SHORTPTR_BASE 0x20030000 +#endif typedef uint16_t shortptr_t; static inline void *shortptr_to_ptr(shortptr_t s) { - return s ? (void *)(0x20000000 + s * 4) : NULL; + return s ? (void *)(SHORTPTR_BASE + s * 4) : NULL; } static inline shortptr_t ptr_to_shortptr(void *p) { if (!p) return 0; uintptr_t v = (uintptr_t)p; - assert(v>=0x20000004 && v <= 0x20040000 && !(v&3)); + if (!(v>=SHORTPTR_BASE+4 && v < SHORTPTR_BASE + 0x40000 && !(v&3))) { + asm("bkpt #0"); + } + assert(v>=SHORTPTR_BASE+4 && v < SHORTPTR_BASE + 0x40000 && !(v&3)); +#if SHORTPTR_BASE == 0x20000000 return (shortptr_t) ((v << 14u)>>16u); +#else + return (shortptr_t) ((v - SHORTPTR_BASE) >> 2); +#endif } #else typedef void *shortptr_t; diff --git a/src/i_main.c b/src/i_main.c index 7e7ca595..13fe30a5 100644 --- a/src/i_main.c +++ b/src/i_main.c @@ -30,6 +30,7 @@ #include "pico/sem.h" #include "pico/multicore.h" #if PICO_ON_DEVICE +#include "hardware/clocks.h" #include "hardware/vreg.h" #endif #endif @@ -39,7 +40,9 @@ #include "doomtype.h" #include "i_system.h" #include "m_argv.h" - +#if PICO_RP2350 +#include "hardware/structs/qmi.h" +#endif // // D_DoomMain() // Not a globally visible function, just included for source reference, @@ -61,8 +64,19 @@ int main(int argc, char **argv) myargv = argv; #endif #if PICO_ON_DEVICE +#if PICO_RP2350 + uint clkdiv = 3; + uint rxdelay = 2; + hw_write_masked( + &qmi_hw->m[0].timing, + ((clkdiv << QMI_M0_TIMING_CLKDIV_LSB) & QMI_M0_TIMING_CLKDIV_BITS) | + ((rxdelay << QMI_M0_TIMING_RXDELAY_LSB) & QMI_M0_TIMING_RXDELAY_BITS), + QMI_M0_TIMING_CLKDIV_BITS | QMI_M0_TIMING_RXDELAY_BITS + ); +#endif vreg_set_voltage(VREG_VOLTAGE_1_30); - // todo pause? is this the cause of the cold start isue? + busy_wait_us(1000); + // todo pause? is this the cause of the cold start issue? set_sys_clock_khz(270000, true); #if !USE_PICO_NET // debug ? diff --git a/src/pd_render.cpp b/src/pd_render.cpp index 7efefb5e..3192d65d 100644 --- a/src/pd_render.cpp +++ b/src/pd_render.cpp @@ -317,7 +317,11 @@ const char *type_name(pd_column column) { #endif } +#if !PICO_RP2350 #define RENDER_COL_MAX 3600 +#else +#define RENDER_COL_MAX 7200 +#endif static uint8_t __aligned(4) list_buffer[RENDER_COL_MAX * sizeof(pd_column) + 64*64]; // extra 64*64 is for one flat static uint8_t *last_list_buffer_limit = list_buffer + sizeof(list_buffer); //static_assert(text_font_cpy > list_buffer, ""); @@ -817,7 +821,12 @@ void pd_init() { sem_init(&core1_done, 0, 1); #if PICO_ON_DEVICE static_assert(sizeof(vpatchlists_t) < 0xc00, ""); +#if !PICO_RP2350 vpatchlists = (vpatchlists_t *)(USBCTRL_DPRAM_BASE + 0x400); +#else + static_assert(SRAM_SCRATCH_X_BASE - 0xc00 >= SHORTPTR_BASE + 0x4000, ""); // avoid potential heap locations + vpatchlists = (vpatchlists_t *)(SRAM_SCRATCH_X_BASE - 0xc00); +#endif #else vpatchlists = (vpatchlists_t*)malloc(sizeof(vpatchlists_t)); #endif diff --git a/src/pico/CMakeLists.txt b/src/pico/CMakeLists.txt index 20dd6407..4c470b0f 100644 --- a/src/pico/CMakeLists.txt +++ b/src/pico/CMakeLists.txt @@ -34,7 +34,9 @@ target_compile_definitions(common_pico INTERFACE NO_USE_MOUSE=1 PICO_AUDIO_I2S_PIO=1 PICO_AUDIO_I2S_DMA_IRQ=1 - ) + PICO_USE_SW_SPIN_LOCKS=0 + PICO_USE_STACK_GUARDS=0 # todo we can actually use these sensibly, but right now we do overflow! +) pico_generate_pio_header(common_pico ${CMAKE_CURRENT_LIST_DIR}/video_doom.pio) target_link_libraries(common_pico INTERFACE pico_stdlib pico_multicore pico_scanvideo_dpi) diff --git a/src/pico/i_system.c b/src/pico/i_system.c index a4d3a535..cd05c644 100644 --- a/src/pico/i_system.c +++ b/src/pico/i_system.c @@ -142,6 +142,16 @@ static byte *AutoAllocMemory(int *size, int default_ram, int min_ram) extern char __end__; zonemem = (uint8_t *)(((uintptr_t)&__end__)&~3); *size = ((uint8_t *)SRAM4_BASE) - zonemem; +#if !PICO_RP2350 + *size = ((uint8_t *)SRAM4_BASE) - zonemem; +#else + // because of our shortptrs, heap cannot be bigger than 256K + // todo limit this to any static stuff at the end + *size = ((uint8_t *)SHORTPTR_BASE + 0x40000) - zonemem; + if (SHORTPTR_BASE >= (uintptr_t)zonemem) { + I_Error("SHORTPTR_BASE bad"); + } +#endif #else #error use zone for malloc only on device #endif diff --git a/src/pico/i_video.c b/src/pico/i_video.c index 3a5bc244..15bb9d7c 100644 --- a/src/pico/i_video.c +++ b/src/pico/i_video.c @@ -751,7 +751,12 @@ static inline uint draw_vpatch(uint16_t *dest, patch_t *patch, vpatchlist_t *vp, #if PICO_ON_DEVICE if (patch == stbar) { static const uint8_t *cached_data; +#if PICO_RP2040 static uint32_t __scratch_x("data_cache") data_cache[41]; +#else + // short of scratch space on RP2350 for some reason, so lets put this in main RAM + static uint32_t data_cache[41]; +#endif int i = 0; uint32_t *d = (uint32_t *) dest; #define DMA_CHANNEL 11 @@ -772,14 +777,20 @@ static inline uint draw_vpatch(uint16_t *dest, patch_t *patch, vpatchlist_t *vp, // once = true; xip_ctrl_hw->stream_ctr = 0; // workaround yucky bug +#if !PICO_RP2350 (void) *(io_rw_32 *) XIP_NOCACHE_NOALLOC_BASE; xip_ctrl_hw->stream_fifo; +#endif dma_channel_abort(DMA_CHANNEL); dma_channel_config c = dma_channel_get_default_config(DMA_CHANNEL); channel_config_set_read_increment(&c, false); channel_config_set_write_increment(&c, true); channel_config_set_dreq(&c, DREQ_XIP_STREAM); +#if !PICO_RP2350 dma_channel_set_read_addr(DMA_CHANNEL, (void *) XIP_AUX_BASE, false); +#else + dma_channel_set_read_addr(DMA_CHANNEL, &xip_ctrl_hw->stream_fifo, false); +#endif dma_channel_set_config(DMA_CHANNEL, &c, false); cached_data = data + SCREENWIDTH / 2; xip_ctrl_hw->stream_addr = (uintptr_t) cached_data; @@ -1067,7 +1078,11 @@ void __scratch_x("scanlines") fill_scanlines() { static void __not_in_flash_func(free_buffer_callback)() { // irq_set_pending(LOW_PRIO_IRQ); // ^ is in flash by default +#if !PICO_RP2350 *((io_rw_32 *) (PPB_BASE + M0PLUS_NVIC_ISPR_OFFSET)) = 1u << LOW_PRIO_IRQ; +#else + nvic_hw->ispr[LOW_PRIO_IRQ / 32] = 1 << (LOW_PRIO_IRQ % 32); +#endif } #endif @@ -1100,6 +1115,9 @@ static void core1() { } } +#if PICO_RP2350 +#include "hardware/structs/accessctrl.h" +#endif void I_InitGraphics(void) { stbar = resolve_vpatch_handle(VPATCH_STBAR); @@ -1112,6 +1130,9 @@ void I_InitGraphics(void) sem_acquire_blocking(&core1_launch); #if USE_ZONE_FOR_MALLOC disallow_core1_malloc = true; +#endif +#if PICO_RP2350 + hw_set_bits(&accessctrl_hw->xip_ctrl, ACCESSCTRL_PASSWORD_BITS | 0xff); #endif initialized = true; } @@ -1179,6 +1200,7 @@ int I_GetPaletteIndex(int r, int g, int b) #if !NO_USE_ENDDOOM void I_Endoom(byte *endoom_data) { +#if SUPPORT_TEXT uint32_t size; uint8_t *wa = pd_get_work_area(&size); assert(size >=TEXT_SCANLINE_BUFFER_TOTAL_WORDS * 4 + 80*25*2 + 4096); @@ -1210,6 +1232,7 @@ void I_Endoom(byte *endoom_data) { } #endif text_screen_data = text_screen_cpy; +#endif } #endif diff --git a/src/pico/picoflash.c b/src/pico/picoflash.c index 4757200c..42edff7d 100644 --- a/src/pico/picoflash.c +++ b/src/pico/picoflash.c @@ -9,9 +9,6 @@ #include "picoflash.h" #include "pico/bootrom.h" -#include "hardware/structs/ssi.h" -#include "hardware/structs/ioqspi.h" - #define FLASH_BLOCK_ERASE_CMD 0xd8 //----------------------------------------------------------------------------- @@ -23,8 +20,13 @@ #define BOOT2_SIZE_WORDS 64 static void __no_inline_not_in_flash_func(flash_init_boot2_copyout)(uint32_t boot2_copyout[BOOT2_SIZE_WORDS]) { +#if PICO_RP2040 + const volatile uint32_t *copy_from = (uint32_t *)XIP_BASE; +#else + const volatile uint32_t *copy_from = (uint32_t *)BOOTRAM_BASE; +#endif for (int i = 0; i < BOOT2_SIZE_WORDS; ++i) - boot2_copyout[i] = ((uint32_t *)XIP_BASE)[i]; + boot2_copyout[i] = copy_from[i]; __compiler_memory_barrier(); } diff --git a/src/pico/piconet.c b/src/pico/piconet.c index 09471011..f0c9aa68 100644 --- a/src/pico/piconet.c +++ b/src/pico/piconet.c @@ -664,8 +664,9 @@ void piconet_init() { gpio_pull_up(PICO_DEFAULT_I2C_SCL_PIN); irq_set_exclusive_handler(I2C_IRQ, i2c_irq_handler); hardware_alarm_set_callback(PERIODIC_ALARM_NUM, periodic_tick); - irq_set_priority(TIMER_IRQ_0 + PERIODIC_ALARM_NUM, 0xc0); // don't want timer pre-empting the other IRQs - irq_set_enabled(TIMER_IRQ_0 + PERIODIC_ALARM_NUM, true); // no harm turning it on + uint irq = TIMER_ALARM_IRQ_NUM(PICO_DEFAULT_TIMER_INSTANCE(), PERIODIC_ALARM_NUM); + irq_set_priority(irq, 0xc0); // don't want timer pre-empting the other IRQs + irq_set_enabled(irq, true); // no harm turning it on } static void clear_state() { diff --git a/src/whd_gen/statsomizer.h b/src/whd_gen/statsomizer.h index 2696bc9a..9e3c5b2c 100644 --- a/src/whd_gen/statsomizer.h +++ b/src/whd_gen/statsomizer.h @@ -6,6 +6,7 @@ #pragma once #include #include +#include struct statsomizer { const std::string name; diff --git a/src/z_zone.c b/src/z_zone.c index 9765c0c4..7ae37892 100644 --- a/src/z_zone.c +++ b/src/z_zone.c @@ -368,7 +368,7 @@ Z_MallocNoUser // found a block big enough extra = memblock_size(base) - size; - + if (extra > MINFRAGMENT) { // there will be a free fragment after the allocated block