diff --git a/CMakeLists.txt b/CMakeLists.txt index 3f62f8d..2a45245 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,6 +7,7 @@ set(CMAKE_EXPORT_COMPILE_COMMANDS ON) set(CMAKE_C_STANDARD 11) set(CMAKE_CXX_STANDARD 20) +set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -O0") include(lib/pico-ice-sdk/cmake/preinit_pico_ice_sdk.cmake) set(PICO_SDK_PATH ${CMAKE_SOURCE_DIR}/lib/pico-ice-sdk/lib/pico-sdk) diff --git a/dvi-dynamic/CMakeLists.txt b/dvi-dynamic/CMakeLists.txt index bd5aab7..7ebe18f 100644 --- a/dvi-dynamic/CMakeLists.txt +++ b/dvi-dynamic/CMakeLists.txt @@ -5,12 +5,15 @@ add_executable(dvi-dynamic src/framebuffer.cpp ) +pico_generate_pio_header(dvi-dynamic ${CMAKE_CURRENT_SOURCE_DIR}/src/fpga.pio) + FileEmbedAdd(${CMAKE_CURRENT_SOURCE_DIR}/rtl_bin/mandelbrot.bin) target_include_directories(dvi-dynamic PRIVATE include) target_link_libraries(dvi-dynamic pico_ice_sdk hardware_dma + hardware_pio file_embed ) pico_add_extra_outputs(dvi-dynamic) diff --git a/dvi-dynamic/rtl/source/impl_1/impl_1.pdc b/dvi-dynamic/rtl/source/impl_1/impl_1.pdc index e1daa21..cd356ce 100644 --- a/dvi-dynamic/rtl/source/impl_1/impl_1.pdc +++ b/dvi-dynamic/rtl/source/impl_1/impl_1.pdc @@ -2,4 +2,13 @@ ldc_set_location -site 35 [get_ports {clk}] ldc_set_location -site 39 [get_ports {led_g}] ldc_set_location -site 40 [get_ports {led_b}] -ldc_set_location -site 41 [get_ports {led_r}] \ No newline at end of file +ldc_set_location -site 41 [get_ports {led_r}] + +ldc_set_location -site 27 [get_ports {data[0]}] +ldc_set_location -site 25 [get_ports {data[1]}] +ldc_set_location -site 21 [get_ports {data[2]}] +ldc_set_location -site 19 [get_ports {data[3]}] +ldc_set_location -site 26 [get_ports {data[4]}] +ldc_set_location -site 23 [get_ports {data[5]}] +ldc_set_location -site 20 [get_ports {data[6]}] +ldc_set_location -site 18 [get_ports {data[7]}] \ No newline at end of file diff --git a/dvi-dynamic/rtl/source/impl_1/top.sv b/dvi-dynamic/rtl/source/impl_1/top.sv index 6ad2a76..1d5617d 100644 --- a/dvi-dynamic/rtl/source/impl_1/top.sv +++ b/dvi-dynamic/rtl/source/impl_1/top.sv @@ -3,10 +3,11 @@ module top input wire clk, output wire led_r, output wire led_g, - output wire led_b + output wire led_b, + output wire [7:0] data ); -localparam N = 22; +localparam N = 25; reg [N:0] counter; @@ -18,4 +19,6 @@ assign led_r = 1'b1; assign led_g = counter[N]; assign led_b = 1'b1; +assign data = '0; + endmodule \ No newline at end of file diff --git a/dvi-dynamic/src/fpga.pio b/dvi-dynamic/src/fpga.pio new file mode 100644 index 0000000..32dc481 --- /dev/null +++ b/dvi-dynamic/src/fpga.pio @@ -0,0 +1,37 @@ +.pio_version 1 + +.define public CLK_PIN 21 + +.program fpga + +wait 1 gpio CLK_PIN +wait 0 gpio CLK_PIN +in pins, 8 + +% c-sdk { + +static inline void fpga_program_init(PIO pio, uint sm, uint offset, uint pin) +{ + pio_sm_config c = fpga_program_get_default_config(offset); + + sm_config_set_in_pins(&c, pin); + pio_sm_set_consecutive_pindirs(pio, sm, pin, 8, false); + for (int i = 0; i < 8; i++) + { + pio_gpio_init(pio, pin + i); + } + + sm_config_set_in_shift( + &c, + false, + true, + 8 + ); + + sm_config_set_fifo_join(&c, PIO_FIFO_JOIN_RX); + + pio_sm_init(pio, sm, offset, &c); + pio_sm_set_enabled(pio, sm, true); +} + +%} diff --git a/dvi-dynamic/src/main.cpp b/dvi-dynamic/src/main.cpp index f5ea40f..7299eba 100644 --- a/dvi-dynamic/src/main.cpp +++ b/dvi-dynamic/src/main.cpp @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -24,6 +25,7 @@ #include "framebuffer.h" #include "mandelbrot_bin.h" +#include "fpga.pio.h" // ---------------------------------------------------------------------------- // DVI constants @@ -108,9 +110,12 @@ static uint32_t vactive_line[] = { #define DMACH_PING 0 #define DMACH_PONG 1 +#define DMACH_FBPI 2 +#define DMACH_FBPO 3 // First we ping. Then we pong. Then... we ping again. static bool dma_pong = false; +static bool dma_fb_pong = false; // A ping and a pong are cued up initially, so the first time we enter this // handler it is to cue up the second ping after the first ping has completed. @@ -121,11 +126,12 @@ static uint v_scanline = 2; // post the command list, and another to post the pixels. static bool vactive_cmdlist_posted = false; -void __scratch_x("") dma_irq_handler() { +void __scratch_x("") dma_irq0_handler() +{ // dma_pong indicates the channel that just finished, which is the one // we're about to reload. uint ch_num = dma_pong ? DMACH_PONG : DMACH_PING; - dma_channel_hw_t *ch = &dma_hw->ch[ch_num]; + dma_channel_hw_t* ch = &dma_hw->ch[ch_num]; dma_hw->intr = 1u << ch_num; dma_pong = !dma_pong; @@ -150,21 +156,59 @@ void __scratch_x("") dma_irq_handler() { } } +void dma_irq1_handler() +{ + uint ch_num = dma_fb_pong ? DMACH_FBPI : DMACH_FBPO; + dma_channel_hw_t* ch = &dma_hw->ch[ch_num]; + dma_hw->intr = 1u << ch_num; + dma_fb_pong = !dma_fb_pong; + + ch->write_addr = (uintptr_t)FRAMEBUFFER; +} + // ---------------------------------------------------------------------------- // Main program -int main(void) { +int main(void) +{ ice_led_init(); - ice_fpga_init(FPGA_DATA, 48); + sleep_ms(1000); ice_cram_open(FPGA_DATA); ice_cram_write(mandelbrot_bin_data, mandelbrot_bin_size); ice_cram_close(); + ice_fpga_init(FPGA_DATA, 16); + for (int i = 0; i < FRAMEBUFFER_SIZE; i++) { - FRAMEBUFFER[i] = 0xFF; + FRAMEBUFFER[i] = rand(); + } + + const PIO pio = pio0; + const uint offset = pio_add_program(pio, &fpga_program); + const uint sm = pio_claim_unused_sm(pio, true); + fpga_program_init(pio, sm, offset, 0); + { + dma_channel_config c = dma_channel_get_default_config(DMACH_FBPI); + channel_config_set_read_increment(&c, false); + channel_config_set_write_increment(&c, true); + channel_config_set_transfer_data_size(&c, DMA_SIZE_8); + channel_config_set_dreq(&c, pio_get_dreq(pio, sm, false)); + + channel_config_set_chain_to(&c, DMACH_FBPO); + dma_channel_configure(DMACH_FBPI, &c, FRAMEBUFFER, &pio->rxf[sm], FRAMEBUFFER_SIZE, false); + + channel_config_set_chain_to(&c, DMACH_FBPI); + dma_channel_configure(DMACH_FBPO, &c, FRAMEBUFFER, &pio->rxf[sm], FRAMEBUFFER_SIZE, false); + + dma_hw->ints1 = (1u << DMACH_FBPI) | (1u << DMACH_FBPO); + dma_hw->inte1 = (1u << DMACH_FBPI) | (1u << DMACH_FBPO); + irq_set_exclusive_handler(DMA_IRQ_1, dma_irq1_handler); + irq_set_enabled(DMA_IRQ_1, true); + + dma_channel_start(DMACH_FBPI); } // Configure HSTX's TMDS encoder for RGB332 @@ -259,7 +303,7 @@ int main(void) { dma_hw->ints0 = (1u << DMACH_PING) | (1u << DMACH_PONG); dma_hw->inte0 = (1u << DMACH_PING) | (1u << DMACH_PONG); - irq_set_exclusive_handler(DMA_IRQ_0, dma_irq_handler); + irq_set_exclusive_handler(DMA_IRQ_0, dma_irq0_handler); irq_set_enabled(DMA_IRQ_0, true); bus_ctrl_hw->priority = BUSCTRL_BUS_PRIORITY_DMA_W_BITS | BUSCTRL_BUS_PRIORITY_DMA_R_BITS;