aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorlonkaars <loek@pipeframe.xyz>2023-03-30 15:10:17 +0200
committerlonkaars <loek@pipeframe.xyz>2023-03-30 15:10:17 +0200
commit6292c1101121bc8ba2db752cab3cbe41469b29d0 (patch)
treeb8cc9ac68b2c972b67d8aa4c9da84ea8c415a759
parent54b6ca70a74b3beb1331fd0b0bed28c665ed1f4d (diff)
new spi system
-rw-r--r--basys3/basys3.srcs/io.xdc4
-rw-r--r--basys3/basys3.srcs/ppu_addr_dec.vhd13
-rw-r--r--basys3/basys3.srcs/spi.vhd39
-rw-r--r--basys3/basys3.srcs/spi_tb.vhd78
-rw-r--r--basys3/basys3.srcs/top.vhd22
-rw-r--r--basys3/basys3.xpr10
-rw-r--r--docs/hardware/pinout.md3
-rw-r--r--src/main.c12
-rw-r--r--src/ppu/consts.h6
-rw-r--r--src/ppu/internals.c29
-rw-r--r--src/ppu/internals.h10
-rw-r--r--src/ppu/stm.c15
-rw-r--r--src/ppusim/mem.c14
-rw-r--r--src/stm32/main.c6
-rwxr-xr-xtest/ppu-stm-integration-demo/data2test.awk15
-rw-r--r--test/ppu-stm-integration-demo/makefile8
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|
||
diff --git a/src/main.c b/src/main.c
index bbb6001..658fc94 100644
--- a/src/main.c
+++ b/src/main.c
@@ -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 > $@