Skip to content

Commit

Permalink
RP2350 changes (including RISC-V)
Browse files Browse the repository at this point in the history
  • Loading branch information
Wren6991 committed Aug 10, 2024
1 parent 8ecccce commit ca941ba
Show file tree
Hide file tree
Showing 28 changed files with 1,704 additions and 168 deletions.
27 changes: 27 additions & 0 deletions Readme.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,30 @@
RP2350 PicoDVI Preview
======================

Changes from the public GitHub version:

* All Arm assembly in `libdvi` has been ported to RISC-V and tuned for Hazard3
* Some of the existing Arm assembly in `libdvi` has been tweaked for better performance on Cortex-M33
* RGB encode now uses the SIO TMDS encoders by default on RP2350 (can be disabled by defining `DVI_USE_SIO_TMDS_ENCODE=0` -- see `software/libdvi/dvi_config_defs.h`)
* Much of the Arm assembly in `libsprite` has been ported to RISC-V -- enough to run the stock demos

Build instructions:

```bash
cd software
mkdir build
# PICO_PLATFORM can also be rp2350-riscv
# List of DVI configs is in software/include/common_dvi_pin_configs.h
cmake -DPICO_SDK_PATH=/path/to/sdk -DPICO_PLATFORM=rp2350 -DPICO_COPY_TO_RAM=1 -DDVI_DEFAULT_SERIAL_CONFIG=pico_sock_cfg ..
make -j$(nproc)
# Then flash a binary, e.g.:
cp apps/tiles_and_sprites/tiles_and_sprites.uf2
```

If you plan to run the `vista` demo, then note that there are now two UF2 data files, `software/assets/vista_data_rp2040.uf2` and `software/assets/vista_data_rp2350.uf2`. The only difference is the family IDs: the first can be dragged on RP2040 and on RP2350 A0, and the second can be dragged on RP2350 A1 and later.

The following is the original RP2040 writeup:

Bitbanged DVI on the RP2040 Microcontroller
===========================================

Expand Down
1 change: 1 addition & 0 deletions software/.gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
build
*.swp
build-*
10 changes: 8 additions & 2 deletions software/apps/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
add_subdirectory(bad_apple)
if (NOT PICO_RISCV)
# Arm assembly needs porting to RISC-V
add_subdirectory(bad_apple)
endif()
add_subdirectory(colour_terminal)
add_subdirectory(christmas_snowflakes)
add_subdirectory(dht_logging)
Expand All @@ -12,5 +15,8 @@ add_subdirectory(tiles)
add_subdirectory(tiles_and_sprites)
add_subdirectory(tiles_parallax)
add_subdirectory(vista)
add_subdirectory(vista-palette)
if (PICO_RP2040)
# Needs porting to use XIP stream instead of SSI, as was done to vista
add_subdirectory(vista-palette)
endif()
add_subdirectory(mandel-full)
1 change: 0 additions & 1 deletion software/apps/colour_terminal/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
#include "hardware/gpio.h"
#include "hardware/vreg.h"
#include "hardware/structs/bus_ctrl.h"
#include "hardware/structs/ssi.h"
#include "hardware/dma.h"
#include "pico/sem.h"

Expand Down
65 changes: 61 additions & 4 deletions software/apps/colour_terminal/tmds_encode_font_2bpp.S
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
#include "hardware/regs/addressmap.h"
#include "hardware/regs/sio.h"

#ifndef __riscv
.syntax unified
.cpu cortex-m0plus
.thumb
#endif

// Using the following:
//
Expand Down Expand Up @@ -46,12 +48,13 @@
// r8 contains a pointer to the font bitmap for this scanline.
// r9 contains the TMDS LUT base.
.macro do_char charbuf_offs colour_shift_instr colour_shamt
#ifndef __riscv
// Get 8x font bits for next character, put 4 LSBs in bits 6:3 of r4 (so
// scaled to 8-byte LUT entries), and 4 MSBs in bits 6:3 of r6.
ldrb r4, [r0, #\charbuf_offs] // 2
add r4, r8 // 1
ldrb r4, [r4] // 2
lsrs r6, r4, #4 // 1
ldrb r4, [r0, #\charbuf_offs] // 2 (note these cycle
add r4, r8 // 1 counts are for M0+
ldrb r4, [r4] // 2 and are a little
lsrs r6, r4, #4 // 1 pessimistic on M33)
lsls r6, #3 // 1
lsls r4, #28 // 1
lsrs r4, #25 // 1
Expand All @@ -67,6 +70,31 @@
ldmia r4, {r4, r5} // 3
ldmia r6, {r6, r7} // 3
stmia r2!, {r4-r7} // 5
#else
lbu a4, \charbuf_offs(a0) // 1
\colour_shift_instr a5, a1, \colour_shamt // 1
add a4, a4, t1 // 1
lbu a4, (a4) // 2
srli a6, a4, 4 // 1
andi a4, a4, 0xf // 1

// Get colour bits, add to TMDS LUT base and font bits
and a5, a5, a3 // 1
add a5, a5, t2 // 1
sh3add a4, a4, a5 // 1
sh3add a6, a6, a5 // 1

// Look up and write out 8 TMDS symbols
lw a5, 4(a4) // 1
lw a4, 0(a4) // 1
lw a7, 4(a6) // 1
lw a6, 0(a6) // 1
sw a4, 0(a2) // 1
sw a5, 4(a2) // 1
sw a6, 8(a2) // 1
sw a7, 12(a2) // 1
addi a2, a2, 16 // 1
#endif
.endm


Expand All @@ -78,9 +106,12 @@

.section .scratch_x.tmds_encode_font_2bpp, "ax"
.global tmds_encode_font_2bpp
#ifndef __riscv
.type tmds_encode_font_2bpp,%function
.thumb_func
#endif
tmds_encode_font_2bpp:
#ifndef __riscv
push {r4-r7, lr}
mov r4, r8
mov r5, r9
Expand Down Expand Up @@ -123,6 +154,32 @@ tmds_encode_font_2bpp:
mov r10, r6
pop {r4-r7, pc}

#else

sh1add t0, a3, a2
li a3, 0xf0 * 8

mv t1, a4
la t2, palettised_1bpp_tables
mv t3, a1

bgeu a2, t0, 2f
1:
lw a1, (t3)
addi t3, t3, 4
do_char 0 slli 7
do_char 1 slli 3
do_char 2 srli 1
do_char 3 srli 5
do_char 4 srli 9
do_char 5 srli 13
do_char 6 srli 17
do_char 7 srli 21
addi a0, a0, 8
bltu a2, t0, 1b
2:
ret
#endif

// Table generation:
// levels_2bpp_even = [0x05, 0x50, 0xaf, 0xfa]
Expand Down
1 change: 0 additions & 1 deletion software/apps/mandel-full/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
#include "hardware/pll.h"
#include "hardware/sync.h"
#include "hardware/structs/bus_ctrl.h"
#include "hardware/structs/ssi.h"
#include "hardware/vreg.h"
#include "pico/multicore.h"
#include "pico/sem.h"
Expand Down
1 change: 0 additions & 1 deletion software/apps/terminal/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
#include "hardware/gpio.h"
#include "hardware/vreg.h"
#include "hardware/structs/bus_ctrl.h"
#include "hardware/structs/ssi.h"
#include "hardware/dma.h"
#include "pico/sem.h"

Expand Down
6 changes: 4 additions & 2 deletions software/apps/tiles_parallax/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -127,8 +127,10 @@ void __not_in_flash("render") render_loop() {
tile16(pixbuf, &bg1, y, FRAME_WIDTH);
queue_add_blocking(&dvi0.q_colour_valid, &pixbuf);
}
bg0.xscroll += 1;
bg1.xscroll += 2;
bg1.xscroll += 1;
if (frame_ctr & 1) {
bg0.xscroll += 1;
}
++frame_ctr;
}
}
Expand Down
16 changes: 13 additions & 3 deletions software/apps/vista-palette/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,19 @@ add_executable(vista-palette
# flash using direct SSI DMA, which would trample on XIP.
pico_set_binary_type(vista-palette copy_to_ram)

pico_define_boot_stage2(vista-palette_boot2 ${PICO_SDK_PATH}/src/rp2_common/boot_stage2/boot2_w25q080.S)
target_compile_definitions(vista-palette_boot2 PRIVATE PICO_FLASH_SPI_CLKDIV=4)
pico_set_boot_stage2(vista-palette vista-palette_boot2)

if (PICO_RP2040)
pico_define_boot_stage2(vista-palette_boot2 ${PICO_SDK_PATH}/src/rp2040/boot_stage2/boot2_w25q080.S)
pico_set_boot_stage2(vista-palette vista-palette_boot2)
target_compile_definitions(vista-palette_boot2 PRIVATE PICO_FLASH_SPI_CLKDIV=4)
else ()
target_compile_definitions(vista-palette PRIVATE
PICO_EMBED_XIP_SETUP=1
PICO_BOOT_STAGE2_CHOOSE_W25Q080=1
PICO_FLASH_SPI_CLKDIV=2
PICO_FLASH_SPI_RXDELAY=3
)
endif()

target_compile_definitions(vista-palette PRIVATE
DVI_DEFAULT_SERIAL_CONFIG=${DVI_DEFAULT_SERIAL_CONFIG}
Expand Down
13 changes: 13 additions & 0 deletions software/apps/vista/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,19 @@ target_compile_definitions(vista PRIVATE
DVI_SYMBOLS_PER_WORD=1
)

if (PICO_RP2040)
pico_define_boot_stage2(vista_boot2 ${PICO_SDK_PATH}/src/rp2040/boot_stage2/boot2_w25q080.S)
pico_set_boot_stage2(vista vista_boot2)
target_compile_definitions(vista_boot2 PRIVATE PICO_FLASH_SPI_CLKDIV=4)
else ()
target_compile_definitions(vista PRIVATE
PICO_EMBED_XIP_SETUP=1
PICO_BOOT_STAGE2_CHOOSE_W25Q080=1
PICO_FLASH_SPI_CLKDIV=2
PICO_FLASH_SPI_RXDELAY=3
)
endif()

target_compile_definitions(vista PRIVATE PICO_STACK_SIZE=0x200)

target_link_libraries(vista
Expand Down
55 changes: 43 additions & 12 deletions software/apps/vista/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,17 @@
#include "hardware/pll.h"
#include "hardware/sync.h"
#include "hardware/structs/bus_ctrl.h"
#include "hardware/structs/ssi.h"
#include "hardware/vreg.h"
#include "pico/multicore.h"
#include "pico/sem.h"
#include "pico/stdlib.h"
#if PICO_RP2040
#include "hardware/structs/ssi.h"
#else
#include "hardware/structs/xip_ctrl.h"
#include "hardware/structs/xip_aux.h"
#include "hardware/structs/qmi.h"
#endif

#include "tmds_encode.h"

Expand Down Expand Up @@ -45,27 +51,40 @@ static inline void prepare_scanline(const uint32_t *colourbuf, uint32_t *tmdsbuf
tmds_encode_data_channel_fullres_16bpp(colourbuf, tmdsbuf + 2 * pixwidth, pixwidth, 15, 11);
}

void __no_inline_not_in_flash_func(flash_bulk_dma_start)(uint32_t *rxbuf, uint32_t flash_offs, size_t len, uint dma_chan)
{
void __no_inline_not_in_flash_func(flash_bulk_dma_start)(uint32_t *rxbuf, uint32_t flash_offs, size_t len, uint dma_chan) {
#if PICO_RP2040
// On RP2040, program the SSI to clock the correct amount of data without stopping
ssi_hw->ssienr = 0;
ssi_hw->ctrlr1 = len - 1; // NDF, number of data frames
ssi_hw->dmacr = SSI_DMACR_TDMAE_BITS | SSI_DMACR_RDMAE_BITS;
ssi_hw->ssienr = 1;
// Other than NDF, the SSI configuration used for XIP is suitable for a bulk read too.

dma_hw->ch[dma_chan].read_addr = (uint32_t)&ssi_hw->dr0;
const uintptr_t read_addr = (uintptr_t)&ssi_hw->dr0;
const uint dreq = DREQ_XIP_SSIRX;
const bool bswap = true;
#else
// On RP2350, SSI is gone, but XIP streaming is fast enough to keep up with this demo
// (you can still DMA to the DIRECT_MODE FIFOs if you really need 100%)
xip_ctrl_hw->stream_addr = flash_offs;
xip_ctrl_hw->stream_ctr = len;
const uintptr_t read_addr = (uintptr_t)&xip_aux_hw->stream;
const uint dreq = DREQ_XIP_STREAM;
const bool bswap = false;
#endif
dma_hw->ch[dma_chan].read_addr = read_addr;
dma_hw->ch[dma_chan].write_addr = (uint32_t)rxbuf;
dma_hw->ch[dma_chan].transfer_count = len;
dma_hw->ch[dma_chan].ctrl_trig =
DMA_CH0_CTRL_TRIG_BSWAP_BITS |
DREQ_XIP_SSIRX << DMA_CH0_CTRL_TRIG_TREQ_SEL_LSB |
(uint)bswap << DMA_CH0_CTRL_TRIG_BSWAP_LSB |
dreq << DMA_CH0_CTRL_TRIG_TREQ_SEL_LSB |
dma_chan << DMA_CH0_CTRL_TRIG_CHAIN_TO_LSB |
DMA_CH0_CTRL_TRIG_INCR_WRITE_BITS |
DMA_CH0_CTRL_TRIG_DATA_SIZE_VALUE_SIZE_WORD << DMA_CH0_CTRL_TRIG_DATA_SIZE_LSB |
DMA_CH0_CTRL_TRIG_EN_BITS;

#if PICO_RP2040
// Now DMA is waiting, kick off the SSI transfer (mode continuation bits in LSBs)
ssi_hw->dr0 = (flash_offs << 8) | 0xa0;
#endif
}

// Core 1 handles DMA IRQs and runs TMDS encode on scanline buffers it
Expand All @@ -91,6 +110,15 @@ int __not_in_flash("main") main() {
sleep_ms(10);
set_sys_clock_khz(DVI_TIMING.bit_clk_khz, true);

// A0 SDK won't pick up on the PICO_EMBED_XIP_SETUP flag, so just to make sure:
#if PICO_RP2350
hw_write_masked(
&qmi_hw->m[0].timing,
3 << QMI_M0_TIMING_RXDELAY_LSB | 2 << QMI_M0_TIMING_CLKDIV_LSB,
QMI_M0_TIMING_RXDELAY_BITS | QMI_M0_TIMING_CLKDIV_BITS
);
#endif

setup_default_uart();

gpio_init(LED_PIN);
Expand Down Expand Up @@ -131,21 +159,25 @@ int __not_in_flash("main") main() {
}
for (int y = 0; y < 2 * FRAME_HEIGHT; y += 2) {
// Start DMA to back buffer before starting to encode the front buffer (each buffer is two scanlines)
#if !PICO_RP2040
// On RP2040 we could never reach this point early, because of the slow encode!
dma_channel_wait_for_finish_blocking(img_dma_chan);
#endif
flash_bulk_dma_start(
(uint32_t*)img_buf[img_buf_back],
current_image_base + ((y + 2) % (2 * FRAME_HEIGHT)) * IMAGE_SCANLINE_SIZE,
IMAGE_SCANLINE_SIZE * 2 / sizeof(uint32_t),
img_dma_chan
);
const uint16_t *img = (const uint16_t*)img_buf[img_buf_front];
const uint16_t *img = (const uint16_t*)img_buf[img_buf_front];
uint32_t *our_tmds_buf, *their_tmds_buf;
queue_remove_blocking_u32(&dvi0.q_tmds_free, &their_tmds_buf);
multicore_fifo_push_blocking((uint32_t)(img));
multicore_fifo_push_blocking((uint32_t)their_tmds_buf);

queue_remove_blocking_u32(&dvi0.q_tmds_free, &our_tmds_buf);
prepare_scanline((const uint32_t*)(img + FRAME_WIDTH * 2), our_tmds_buf);

multicore_fifo_pop_blocking();
queue_add_blocking_u32(&dvi0.q_tmds_valid, &their_tmds_buf);
queue_add_blocking_u32(&dvi0.q_tmds_valid, &our_tmds_buf);
Expand All @@ -156,4 +188,3 @@ int __not_in_flash("main") main() {
}
__builtin_unreachable();
}

File renamed without changes.
Binary file added software/assets/vista_data_rp2350.uf2
Binary file not shown.
11 changes: 11 additions & 0 deletions software/include/common_dvi_pin_configs.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,17 @@ static const struct dvi_serialiser_cfg picodvi_reva_dvi_cfg = {
.invert_diffpairs = true
};

// AMY-DVI board, for getting HDMI from the RP2350 FPGA development platform,
// again a cursed board that only a couple of people in the world possess:
static const struct dvi_serialiser_cfg amy_dvi_cfg = {
.pio = DVI_DEFAULT_PIO_INST,
.sm_tmds = {0, 1, 2},
.pins_tmds = {14, 16, 18},
.pins_clk = 12,
.invert_diffpairs = true
};


// The not-HDMI socket on Rev C PicoDVI boards
// (we don't talk about Rev B)
static const struct dvi_serialiser_cfg picodvi_dvi_cfg = {
Expand Down
2 changes: 1 addition & 1 deletion software/libdvi/dvi.c
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,7 @@ static void __dvi_func(dvi_dma_irq_handler)(struct dvi_inst *inst) {
// Make sure all three channels have definitely loaded their last block
// (should be within a few cycles of one another)
for (int i = 0; i < N_TMDS_LANES; ++i) {
while (dma_debug_hw->ch[inst->dma_cfg[i].chan_data].tcr != inst->timing->h_active_pixels / DVI_SYMBOLS_PER_WORD)
while (dma_debug_hw->ch[inst->dma_cfg[i].chan_data].dbg_tcr != inst->timing->h_active_pixels / DVI_SYMBOLS_PER_WORD)
tight_loop_contents();
}

Expand Down
Loading

0 comments on commit ca941ba

Please sign in to comment.