rp2350 support and a minor fix

This commit is contained in:
graham sanderson 2024-08-11 03:25:29 -07:00
parent 836a29586f
commit 29a453c980
11 changed files with 91 additions and 18 deletions

View file

@ -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`

View file

@ -194,15 +194,27 @@ typedef uint8_t floor_ceiling_clip_t;
#if PICO_ON_DEVICE
#include <assert.h>
#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;

View file

@ -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 ?

View file

@ -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

View file

@ -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)

View file

@ -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

View file

@ -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

View file

@ -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();
}

View file

@ -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() {

View file

@ -6,6 +6,7 @@
#pragma once
#include <string>
#include <algorithm>
#include <limits>
struct statsomizer {
const std::string name;