diff options
-rw-r--r-- | basys3/basys3.srcs/io.xdc | 4 | ||||
-rw-r--r-- | basys3/basys3.srcs/ppu_addr_dec.vhd | 13 | ||||
-rw-r--r-- | basys3/basys3.srcs/spi.vhd | 39 | ||||
-rw-r--r-- | basys3/basys3.srcs/spi_tb.vhd | 78 | ||||
-rw-r--r-- | basys3/basys3.srcs/top.vhd | 22 | ||||
-rw-r--r-- | basys3/basys3.xpr | 10 | ||||
-rw-r--r-- | docs/hardware/pinout.md | 3 | ||||
-rw-r--r-- | src/main.c | 12 | ||||
-rw-r--r-- | src/ppu/consts.h | 6 | ||||
-rw-r--r-- | src/ppu/internals.c | 29 | ||||
-rw-r--r-- | src/ppu/internals.h | 10 | ||||
-rw-r--r-- | src/ppu/stm.c | 15 | ||||
-rw-r--r-- | src/ppusim/mem.c | 14 | ||||
-rw-r--r-- | src/stm32/main.c | 6 | ||||
-rwxr-xr-x | test/ppu-stm-integration-demo/data2test.awk | 15 | ||||
-rw-r--r-- | test/ppu-stm-integration-demo/makefile | 8 |
16 files changed, 178 insertions, 106 deletions
diff --git a/basys3/basys3.srcs/io.xdc b/basys3/basys3.srcs/io.xdc index 8243f1e..419e4cd 100644 --- a/basys3/basys3.srcs/io.xdc +++ b/basys3/basys3.srcs/io.xdc @@ -41,10 +41,10 @@ set_property PACKAGE_PIN L18 [get_ports {B[1]}] set_property PACKAGE_PIN N18 [get_ports {B[0]}] set_property IOSTANDARD LVCMOS33 [get_ports VBLANK] -set_property IOSTANDARD LVCMOS33 [get_ports WEN] +set_property IOSTANDARD LVCMOS33 [get_ports SPI_RESET] set_property PACKAGE_PIN C16 [get_ports VBLANK] -set_property PACKAGE_PIN J1 [get_ports WEN] +set_property PACKAGE_PIN J1 [get_ports SPI_RESET] diff --git a/basys3/basys3.srcs/ppu_addr_dec.vhd b/basys3/basys3.srcs/ppu_addr_dec.vhd index 33f247c..649d582 100644 --- a/basys3/basys3.srcs/ppu_addr_dec.vhd +++ b/basys3/basys3.srcs/ppu_addr_dec.vhd @@ -20,7 +20,7 @@ entity ppu_addr_dec is port( -- address decoder end ppu_addr_dec; architecture Behavioral of ppu_addr_dec is - signal TMM_RANGE, BAM_RANGE, FAM_RANGE, PAL_RANGE, AUX_RANGE : std_logic := '0'; -- ADDR in range of memory area + signal NUL_RANGE, TMM_RANGE, BAM_RANGE, FAM_RANGE, PAL_RANGE, AUX_RANGE : std_logic := '0'; -- ADDR in range of memory area begin -- address MUX TMM_ADDR <= ADDR(PPU_TMM_ADDR_WIDTH-1 downto 0); @@ -29,12 +29,13 @@ begin PAL_ADDR <= ADDR(PPU_PAL_ADDR_WIDTH-1 downto 0); AUX_ADDR <= ADDR(PPU_AUX_ADDR_WIDTH-1 downto 0); + NUL_RANGE <= '1' when (and ADDR) else '0'; -- address is 0xffff -- WEN MUX - TMM_WEN <= TMM_RANGE and WEN; - BAM_WEN <= BAM_RANGE and WEN; - FAM_WEN <= FAM_RANGE and WEN; - PAL_WEN <= PAL_RANGE and WEN; - AUX_WEN <= AUX_RANGE and WEN; + TMM_WEN <= TMM_RANGE and WEN and (not NUL_RANGE); + BAM_WEN <= BAM_RANGE and WEN and (not NUL_RANGE); + FAM_WEN <= FAM_RANGE and WEN and (not NUL_RANGE); + PAL_WEN <= PAL_RANGE and WEN and (not NUL_RANGE); + AUX_WEN <= AUX_RANGE and WEN and (not NUL_RANGE); -- address ranges TMM_RANGE <= '1' when not ((ADDR(15) and ADDR(14) and ADDR(13)) or (ADDR(15) and ADDR(14) and ADDR(12))) else '0'; diff --git a/basys3/basys3.srcs/spi.vhd b/basys3/basys3.srcs/spi.vhd index a09d5df..d0e918e 100644 --- a/basys3/basys3.srcs/spi.vhd +++ b/basys3/basys3.srcs/spi.vhd @@ -6,10 +6,11 @@ use work.ppu_consts.all; entity spi is port ( SYSCLK : in std_logic; -- clock basys3 100MHz - SPI_CLK : in std_logic; -- incoming clock of SPI - SPI_MOSI : in std_logic; -- incoming data of SPI RESET : in std_logic; -- async reset - DATA : out std_logic_vector(PPU_RAM_BUS_ADDR_WIDTH+PPU_RAM_BUS_DATA_WIDTH-1 downto 0) := (others => '0')); -- data read + DCK : in std_logic; -- data clock (spi format) + DI : in std_logic; -- data in (spi format) + DO : out std_logic_vector(PPU_RAM_BUS_ADDR_WIDTH+PPU_RAM_BUS_DATA_WIDTH-1 downto 0) := (others => '1'); -- data out (parallel) + WEN : out std_logic := '0'); -- write enable (triggers during each word to propagate previous word) end spi; architecture Behavioral of spi is @@ -17,37 +18,45 @@ architecture Behavioral of spi is signal dataFF0,dataFF1,dataFF2,dataFF3 : std_logic := '0'; -- signal for metastability synchronizer of data SPI constant COUNTER_RESET_VALUE : integer := PPU_RAM_BUS_ADDR_WIDTH + PPU_RAM_BUS_DATA_WIDTH - 1; + signal DBG_I : integer range 0 to COUNTER_RESET_VALUE := COUNTER_RESET_VALUE; -- counter for data position begin process (SYSCLK) - variable bit_idx : integer range 0 to COUNTER_RESET_VALUE := COUNTER_RESET_VALUE; -- counter for data position - variable spi_reg : std_logic_vector(PPU_RAM_BUS_ADDR_WIDTH+PPU_RAM_BUS_DATA_WIDTH-1 downto 0) := (others => '0'); + variable i : integer range 0 to COUNTER_RESET_VALUE := COUNTER_RESET_VALUE; -- counter for data position + variable data_r : std_logic_vector(PPU_RAM_BUS_ADDR_WIDTH+PPU_RAM_BUS_DATA_WIDTH-1 downto 0) := (others => '1'); -- data register begin if RESET = '1' then - spi_reg := (others => '0'); - bit_idx := COUNTER_RESET_VALUE; - DATA <= (others => '0'); + data_r := (others => '1'); + i := COUNTER_RESET_VALUE; + DBG_I <= i; + DO <= (others => '1'); + WEN <= '0'; elsif rising_edge(SYSCLK) then -- flip flop for clk SPI to synchronise a - clkFF0 <= SPI_CLK; + clkFF0 <= DCK; clkFF1 <= clkFF0; clkFF2 <= clkFF1; clkFF3 <= clkFF2; -- flip flop for data SPI to synchronise - dataFF0 <= SPI_MOSI; + dataFF0 <= DI; dataFF1 <= dataFF0; dataFF2 <= dataFF1; dataFF3 <= dataFF2; if (clkFF3 = '0' and clkFF2 = '1') then -- check for rising edge of clk SPI - spi_reg(bit_idx) := dataFF3; -- load new data into temporary register + data_r(i) := dataFF3; -- load new data into temporary register - if bit_idx = 0 then - bit_idx := COUNTER_RESET_VALUE; -- reset bit index - DATA <= spi_reg; -- flush temporary register to data outpu + if i = 0 then + i := COUNTER_RESET_VALUE; -- reset bit index + DO <= data_r; -- flush temporary register to data outpu else - bit_idx := bit_idx - 1; -- decrement bit index + i := i - 1; -- decrement bit index end if; + + -- propagate previous command to ppu during second byte of current command + if i = 23 then WEN <= '1'; end if; + if i = 15 then WEN <= '0'; end if; end if; + DBG_I <= i; end if; end process; end Behavioral; diff --git a/basys3/basys3.srcs/spi_tb.vhd b/basys3/basys3.srcs/spi_tb.vhd index f6e2d21..8e4b8aa 100644 --- a/basys3/basys3.srcs/spi_tb.vhd +++ b/basys3/basys3.srcs/spi_tb.vhd @@ -12,18 +12,18 @@ end spi_tb; architecture behavioral of spi_tb is signal SYSCLK : std_logic := '0'; signal SPI_CLK : std_logic := '0'; - signal SPI_MOSI : std_logic := '0'; + signal SPI_DATA : std_logic := '0'; signal RESET : std_logic := '0'; - signal DATA : std_logic_vector(PPU_RAM_BUS_ADDR_WIDTH+PPU_RAM_BUS_DATA_WIDTH-1 downto 0) := (others => '0'); begin uut : entity work.spi port map( SYSCLK => SYSCLK, RESET => RESET, - DATA => DATA, - SPI_CLK => SPI_CLK, - SPI_MOSI => SPI_MOSI); + DO => open, + DI => SPI_DATA, + DCK => SPI_CLK, + WEN => open); - sysclkgen: process + process begin for i in 0 to 10000 loop wait for 5 ns; @@ -34,197 +34,197 @@ begin wait; -- stop for simulator end process; - spi_data: process + process begin for i in 0 to 2 loop -- data = 0b01010110010100001001110011111111 (0x56509cff) - SPI_MOSI <= '0'; + SPI_DATA <= '0'; wait for 50 ns; SPI_CLK <= '1'; wait for 50 ns; SPI_CLK <= '0'; - SPI_MOSI <= '1'; + SPI_DATA <= '1'; wait for 50 ns; SPI_CLK <= '1'; wait for 50 ns; SPI_CLK <= '0'; - SPI_MOSI <= '0'; + SPI_DATA <= '0'; wait for 50 ns; SPI_CLK <= '1'; wait for 50 ns; SPI_CLK <= '0'; - SPI_MOSI <= '1'; + SPI_DATA <= '1'; wait for 50 ns; SPI_CLK <= '1'; wait for 50 ns; SPI_CLK <= '0'; - SPI_MOSI <= '0'; + SPI_DATA <= '0'; wait for 50 ns; SPI_CLK <= '1'; wait for 50 ns; SPI_CLK <= '0'; - SPI_MOSI <= '1'; + SPI_DATA <= '1'; wait for 50 ns; SPI_CLK <= '1'; wait for 50 ns; SPI_CLK <= '0'; - SPI_MOSI <= '1'; + SPI_DATA <= '1'; wait for 50 ns; SPI_CLK <= '1'; wait for 50 ns; SPI_CLK <= '0'; - SPI_MOSI <= '0'; + SPI_DATA <= '0'; wait for 50 ns; SPI_CLK <= '1'; wait for 50 ns; SPI_CLK <= '0'; - SPI_MOSI <= '0'; + SPI_DATA <= '0'; wait for 50 ns; SPI_CLK <= '1'; wait for 50 ns; SPI_CLK <= '0'; - SPI_MOSI <= '1'; + SPI_DATA <= '1'; wait for 50 ns; SPI_CLK <= '1'; wait for 50 ns; SPI_CLK <= '0'; - SPI_MOSI <= '0'; + SPI_DATA <= '0'; wait for 50 ns; SPI_CLK <= '1'; wait for 50 ns; SPI_CLK <= '0'; - SPI_MOSI <= '1'; + SPI_DATA <= '1'; wait for 50 ns; SPI_CLK <= '1'; wait for 50 ns; SPI_CLK <= '0'; - SPI_MOSI <= '0'; + SPI_DATA <= '0'; wait for 50 ns; SPI_CLK <= '1'; wait for 50 ns; SPI_CLK <= '0'; - SPI_MOSI <= '0'; + SPI_DATA <= '0'; wait for 50 ns; SPI_CLK <= '1'; wait for 50 ns; SPI_CLK <= '0'; - SPI_MOSI <= '0'; + SPI_DATA <= '0'; wait for 50 ns; SPI_CLK <= '1'; wait for 50 ns; SPI_CLK <= '0'; - SPI_MOSI <= '0'; + SPI_DATA <= '0'; wait for 50 ns; SPI_CLK <= '1'; wait for 50 ns; SPI_CLK <= '0'; - SPI_MOSI <= '1'; + SPI_DATA <= '1'; wait for 50 ns; SPI_CLK <= '1'; wait for 50 ns; SPI_CLK <= '0'; - SPI_MOSI <= '0'; + SPI_DATA <= '0'; wait for 50 ns; SPI_CLK <= '1'; wait for 50 ns; SPI_CLK <= '0'; - SPI_MOSI <= '0'; + SPI_DATA <= '0'; wait for 50 ns; SPI_CLK <= '1'; wait for 50 ns; SPI_CLK <= '0'; - SPI_MOSI <= '1'; + SPI_DATA <= '1'; wait for 50 ns; SPI_CLK <= '1'; wait for 50 ns; SPI_CLK <= '0'; - SPI_MOSI <= '1'; + SPI_DATA <= '1'; wait for 50 ns; SPI_CLK <= '1'; wait for 50 ns; SPI_CLK <= '0'; - SPI_MOSI <= '1'; + SPI_DATA <= '1'; wait for 50 ns; SPI_CLK <= '1'; wait for 50 ns; SPI_CLK <= '0'; - SPI_MOSI <= '0'; + SPI_DATA <= '0'; wait for 50 ns; SPI_CLK <= '1'; wait for 50 ns; SPI_CLK <= '0'; - SPI_MOSI <= '0'; + SPI_DATA <= '0'; wait for 50 ns; SPI_CLK <= '1'; wait for 50 ns; SPI_CLK <= '0'; - SPI_MOSI <= '1'; + SPI_DATA <= '1'; wait for 50 ns; SPI_CLK <= '1'; wait for 50 ns; SPI_CLK <= '0'; - SPI_MOSI <= '1'; + SPI_DATA <= '1'; wait for 50 ns; SPI_CLK <= '1'; wait for 50 ns; SPI_CLK <= '0'; - SPI_MOSI <= '1'; + SPI_DATA <= '1'; wait for 50 ns; SPI_CLK <= '1'; wait for 50 ns; SPI_CLK <= '0'; - SPI_MOSI <= '1'; + SPI_DATA <= '1'; wait for 50 ns; SPI_CLK <= '1'; wait for 50 ns; SPI_CLK <= '0'; - SPI_MOSI <= '1'; + SPI_DATA <= '1'; wait for 50 ns; SPI_CLK <= '1'; wait for 50 ns; SPI_CLK <= '0'; - SPI_MOSI <= '1'; + SPI_DATA <= '1'; wait for 50 ns; SPI_CLK <= '1'; wait for 50 ns; SPI_CLK <= '0'; - SPI_MOSI <= '1'; + SPI_DATA <= '1'; wait for 50 ns; SPI_CLK <= '1'; wait for 50 ns; SPI_CLK <= '0'; - SPI_MOSI <= '1'; + SPI_DATA <= '1'; wait for 50 ns; SPI_CLK <= '1'; wait for 50 ns; diff --git a/basys3/basys3.srcs/top.vhd b/basys3/basys3.srcs/top.vhd index ed1c3b0..1c58b60 100644 --- a/basys3/basys3.srcs/top.vhd +++ b/basys3/basys3.srcs/top.vhd @@ -8,7 +8,7 @@ entity top is port ( RESET : in std_logic; -- global (async) system reset SPI_CLK : in std_logic; -- incoming clock of SPI SPI_MOSI : in std_logic; -- incoming data of SPI - WEN : in std_logic; -- PPU VRAM write enable + SPI_RESET : in std_logic; -- PPU VRAM write enable DBG_DISP_ADDR : in std_logic; -- display address/data switch (debug) DBG_LEDS_OUT : out std_logic_vector(15 downto 0); -- debug address/data output leds R,G,B : out std_logic_vector(PPU_COLOR_OUTPUT_DEPTH-1 downto 0); @@ -29,29 +29,33 @@ architecture Behavioral of top is end component; component spi port ( SYSCLK : in std_logic; -- clock basys3 100MHz - SPI_CLK : in std_logic; -- incoming clock of SPI - SPI_MOSI : in std_logic; -- incoming data of SPI RESET : in std_logic; -- async reset - DATA : out std_logic_vector(PPU_RAM_BUS_ADDR_WIDTH+PPU_RAM_BUS_DATA_WIDTH-1 downto 0)); -- data read + DCK : in std_logic; -- data clock (spi format) + DI : in std_logic; -- data in (spi format) + DO : out std_logic_vector(PPU_RAM_BUS_ADDR_WIDTH+PPU_RAM_BUS_DATA_WIDTH-1 downto 0) := (others => '0'); -- data out (parallel) + WEN : out std_logic); -- write enable (triggers during each word to propagate previous word) end component; + signal SPI_RST, PPU_WEN : std_logic; signal SPI_DATA : std_logic_vector(PPU_RAM_BUS_ADDR_WIDTH+PPU_RAM_BUS_DATA_WIDTH-1 downto 0); alias SPI_DATA_ADDR is SPI_DATA(31 downto 16); alias SPI_DATA_DATA is SPI_DATA(15 downto 0); begin + SPI_RST <= RESET or SPI_RESET; serial_peripheral_interface: component spi port map( SYSCLK => SYSCLK, - RESET => RESET, - SPI_CLK => SPI_CLK, - SPI_MOSI => SPI_MOSI, - DATA => SPI_DATA); + RESET => SPI_RST, + DCK => SPI_CLK, + DI => SPI_MOSI, + DO => SPI_DATA, + WEN => PPU_WEN); DBG_LEDS_OUT <= SPI_DATA_ADDR when DBG_DISP_ADDR = '1' else SPI_DATA_DATA; picture_processing_unit: component ppu port map( CLK100 => SYSCLK, RESET => RESET, - WEN => WEN, + WEN => PPU_WEN, ADDR => SPI_DATA_ADDR, DATA => SPI_DATA_DATA, R => R, diff --git a/basys3/basys3.xpr b/basys3/basys3.xpr index 8645fca..19bbeec 100644 --- a/basys3/basys3.xpr +++ b/basys3/basys3.xpr @@ -60,7 +60,7 @@ <Option Name="IPStaticSourceDir" Val="$PIPUSERFILESDIR/ipstatic"/> <Option Name="EnableBDX" Val="FALSE"/> <Option Name="DSABoardId" Val="basys3"/> - <Option Name="WTXSimLaunchSim" Val="86"/> + <Option Name="WTXSimLaunchSim" Val="108"/> <Option Name="WTModelSimLaunchSim" Val="0"/> <Option Name="WTQuestaLaunchSim" Val="0"/> <Option Name="WTIesLaunchSim" Val="0"/> @@ -235,9 +235,15 @@ <Attr Name="UsedIn" Val="simulation"/> </FileInfo> </File> + <File Path="$PSRCDIR/ppu_addr_dec_tb.vhd"> + <FileInfo SFType="VHDL2008"> + <Attr Name="UsedIn" Val="synthesis"/> + <Attr Name="UsedIn" Val="simulation"/> + </FileInfo> + </File> <Config> <Option Name="DesignMode" Val="RTL"/> - <Option Name="TopModule" Val="ppu_tb"/> + <Option Name="TopModule" Val="spi_tb"/> <Option Name="TopLib" Val="xil_defaultlib"/> <Option Name="TransportPathDelay" Val="0"/> <Option Name="TransportIntDelay" Val="0"/> diff --git a/docs/hardware/pinout.md b/docs/hardware/pinout.md index a0c11aa..3713087 100644 --- a/docs/hardware/pinout.md +++ b/docs/hardware/pinout.md @@ -4,8 +4,7 @@ |-|-|-|-|-| |SPI MOSI|PA7|D11|L2|JA2| |SPI CLK|PA5|D13|J2|JA3| -|| -|PPU VRAM WEN|PA9|D8|J1|JA1| +|SPI RESET|PA9|D8|J1|JA1| || |APU PWM out|||A15|JB7| || @@ -6,12 +6,14 @@ bool g_hh_run = true; +bool g_hh_test_complete = false; + void hh_ppu_vblank_interrupt() { - for (unsigned long i = 0; i < HH_PPUINTDEMO_LENGTH; i++) { - uint16_t addr = HH_PPUINTDEMO_ADDR[i]; - uint16_t data = HH_PPUINTDEMO_DATA[i]; - hh_ppu_vram_dwrite(addr, data); - } +#ifdef HH_TARGET_DESKTOP + if (g_hh_test_complete) return; +#endif + hh_ppu_vram_dwrite((uint8_t*) HH_PPUINTDEMO_ARR, HH_PPUINTDEMO_LENGTH); + g_hh_test_complete = true; } int main() { diff --git a/src/ppu/consts.h b/src/ppu/consts.h index a27b7b7..917510f 100644 --- a/src/ppu/consts.h +++ b/src/ppu/consts.h @@ -23,6 +23,12 @@ /** @brief amount of vertical background tiles on background canvas */ #define HH_PPU_BG_CANVAS_TILES_V 30 +/** @brief amount of bytes in command (16 + 16 bits) */ +#define HH_PPU_COMMAND_BYTES 4 +/** @brief command buffer size (large enough to update entire screen + all fg sprites + aux + all palettes) */ +#define HH_PPU_COMMAND_BUFFER_SIZE (HH_PPU_COMMAND_BYTES * \ + (HH_PPU_VRAM_FAM_SIZE + HH_PPU_VRAM_BAM_SIZE + HH_PPU_VRAM_AUX_SIZE + HH_PPU_VRAM_PAL_SIZE)) + #include "ppu/types.h" /** @brief tilemap memory address offset */ diff --git a/src/ppu/internals.c b/src/ppu/internals.c index 66c0ac1..a60cb68 100644 --- a/src/ppu/internals.c +++ b/src/ppu/internals.c @@ -4,6 +4,9 @@ #include "ppu/internals.h" #include "ppu/types.h" +uint8_t g_hh_ppu_vram_buffer[HH_PPU_COMMAND_BUFFER_SIZE] = { 0 }; +size_t g_hh_ppu_vram_buffer_head = 0; + bool hh_ppu_vram_valid_address(hh_ppu_addr_t addr) { #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wtype-limits" @@ -17,7 +20,16 @@ bool hh_ppu_vram_valid_address(hh_ppu_addr_t addr) { } void hh_ppu_vram_write(hh_s_ppu_vram_data data) { - for (unsigned i = 0; i < data.size; i++) hh_ppu_vram_dwrite(data.offset + i, data.data[i]); + for (unsigned i = 0; i < data.size; i++) { + hh_ppu_addr_t ppu_addr = data.offset + i; + hh_ppu_data_t ppu_data = data.data[i]; + hh_ppu_vram_buffer((uint8_t[4]) { + (ppu_addr >> 8) & 0xff, + (ppu_addr >> 0) & 0xff, + (ppu_data >> 8) & 0xff, + (ppu_data >> 0) & 0xff, + }); + } } hh_s_ppu_vram_data hh_ppu_2nat_bam(hh_s_ppu_loc_bam_entry e) { @@ -73,3 +85,18 @@ hh_s_ppu_vram_data hh_ppu_2nat_color(hh_ppu_rgb_color_t rgb) { hh_s_ppu_vram_data out = {.data = data, .size = HH_PPU_VRAM_PAL_ENTRY_SIZE}; return out; } + +void hh_ppu_vram_buffer(uint8_t data[4]) { + size_t head = g_hh_ppu_vram_buffer_head; + g_hh_ppu_vram_buffer[head+0] = data[0]; + g_hh_ppu_vram_buffer[head+1] = data[1]; + g_hh_ppu_vram_buffer[head+2] = data[2]; + g_hh_ppu_vram_buffer[head+3] = data[3]; + g_hh_ppu_vram_buffer_head += 4; +} + +void hh_ppu_vram_flush() { + hh_ppu_vram_dwrite(g_hh_ppu_vram_buffer, g_hh_ppu_vram_buffer_head); + g_hh_ppu_vram_buffer_head = 0; +} + diff --git a/src/ppu/internals.h b/src/ppu/internals.h index 4a1726e..12c556e 100644 --- a/src/ppu/internals.h +++ b/src/ppu/internals.h @@ -1,6 +1,7 @@ #pragma once #include <stdbool.h> +#include <stdlib.h> #include "ppu/types.h" @@ -18,11 +19,16 @@ typedef struct { /** @brief check if `addr` is a valid PPU address */ bool hh_ppu_vram_valid_address(hh_ppu_addr_t addr); -/** @brief direct write vram word (platform-specific implementation) */ -void hh_ppu_vram_dwrite(hh_ppu_addr_t addr, hh_ppu_data_t data); /** @brief write data block into vram */ void hh_ppu_vram_write(hh_s_ppu_vram_data data); +/** @brief add raw SPI data to ppu command buffer */ +void hh_ppu_vram_buffer(uint8_t data[4]); +/** @brief propagate command buffer (also handles SPI reset) */ +void hh_ppu_vram_flush(); +/** @brief write raw spi bytes in ppu format */ +void hh_ppu_vram_dwrite(uint8_t* data, size_t size); + /** @brief convert local background attribute memory entry to PPU format */ hh_s_ppu_vram_data hh_ppu_2nat_bam(hh_s_ppu_loc_bam_entry); /** @brief convert local foreground attribute memory entry to PPU format */ diff --git a/src/ppu/stm.c b/src/ppu/stm.c index 371e557..18811cf 100644 --- a/src/ppu/stm.c +++ b/src/ppu/stm.c @@ -7,17 +7,10 @@ void hh_ppu_init() {} void hh_ppu_deinit() {} -void hh_ppu_vram_dwrite(hh_ppu_addr_t addr, hh_ppu_data_t data) { - // if (!hh_ppu_vram_valid_address(addr)) return; - - uint8_t spi_data[4] = { - (addr & 0xff00) >> 8, - (addr & 0x00ff) >> 0, - (data & 0xff00) >> 8, - (data & 0x00ff) >> 0, - }; - - HAL_SPI_Transmit(&hspi1, spi_data, 4, HAL_MAX_DELAY); +void hh_ppu_vram_dwrite(uint8_t* data, size_t size) { + HAL_SPI_Transmit(&hspi1, data, size, HAL_MAX_DELAY); + HAL_SPI_Transmit(&hspi1, (uint8_t[4]) { 0xff, 0xff, 0xff, 0xff }, 4, HAL_MAX_DELAY); HAL_GPIO_WritePin(GPIOA, GPIO_PIN_9, true); HAL_GPIO_WritePin(GPIOA, GPIO_PIN_9, false); } + diff --git a/src/ppusim/mem.c b/src/ppusim/mem.c index bd8606e..f536727 100644 --- a/src/ppusim/mem.c +++ b/src/ppusim/mem.c @@ -6,8 +6,14 @@ hh_ppu_data_t *g_hh_ppusim_vram = NULL; -void hh_ppu_vram_dwrite(hh_ppu_addr_t addr, hh_ppu_data_t data) { - if (!hh_ppu_vram_valid_address(addr)) return; - // printf("ppu[0x%04x] = %04x\n", addr, data); - g_hh_ppusim_vram[addr] = data; +void hh_ppu_vram_dwrite(uint8_t* data, size_t size) { + for (size_t i = 0; i < size; i += 4) { + if (i+4 > size) break; + hh_ppu_addr_t ppu_addr = (data[i+0] << 8) | (data[i+1] << 0); + hh_ppu_data_t ppu_data = (data[i+2] << 8) | (data[i+3] << 0); + // printf("%04x: %04x\n", ppu_addr, ppu_data); + if (!hh_ppu_vram_valid_address(ppu_addr)) continue; + g_hh_ppusim_vram[ppu_addr] = ppu_data; + } } + diff --git a/src/stm32/main.c b/src/stm32/main.c index 84288c3..d815154 100644 --- a/src/stm32/main.c +++ b/src/stm32/main.c @@ -6,6 +6,8 @@ void hh_ppu_load_tilemap() {} void hh_loop() { - HAL_Delay(1e3); - hh_ppu_vblank_interrupt(); + while (1) { + hh_ppu_vblank_interrupt(); + HAL_Delay(1e3); + } } diff --git a/test/ppu-stm-integration-demo/data2test.awk b/test/ppu-stm-integration-demo/data2test.awk new file mode 100755 index 0000000..286a388 --- /dev/null +++ b/test/ppu-stm-integration-demo/data2test.awk @@ -0,0 +1,15 @@ +#!/bin/awk -f +BEGIN { + print "#pragma once" + print "#include <stdint.h>" + printf("const uint8_t HH_PPUINTDEMO_ARR[] = { ") +} + +length($1) == 4 && length($2) == 4 { + printf "0x"substr($1,1,2)", 0x"substr($1,3,2)", 0x"substr($2,1,2)", 0x"substr($2,3,2)", " +} + +END { + printf("};\n") # close array + printf("#define HH_PPUINTDEMO_LENGTH %d\n", NR*4) # calculate array length +} diff --git a/test/ppu-stm-integration-demo/makefile b/test/ppu-stm-integration-demo/makefile index 7d7a7c8..2f4b6f4 100644 --- a/test/ppu-stm-integration-demo/makefile +++ b/test/ppu-stm-integration-demo/makefile @@ -4,12 +4,8 @@ TARGETS := test-background-color.h test-image.h test-image.tb.vhd all: $(TARGETS) -%.h: %.txt - echo "#pragma once" > $@ - echo "#include <stdint.h>" >> $@ - (printf "#define HH_PPUINTDEMO_LENGTH "; wc -l < $<) >> $@ - tr -d ':' < $< | awk 'BEGIN { printf "const uint16_t HH_PPUINTDEMO_ADDR[] = { " } 1 { printf "0x"$$1", " } END { print "};" }' >> $@ - tr -d ':' < $< | awk 'BEGIN { printf "const uint16_t HH_PPUINTDEMO_DATA[] = { " } 1 { printf "0x"$$2", " } END { print "};" }' >> $@ +%.h: %.txt ./data2test.awk + tr -d ':' < $< | ./data2test.awk > $@ test-%.tb.vhd: test-%.txt ./data2vhdltb.awk tr -d ':' < $< | ./data2vhdltb.awk > $@ |