aboutsummaryrefslogtreecommitdiff
path: root/basys3/basys3.srcs/ppu.vhd
diff options
context:
space:
mode:
Diffstat (limited to 'basys3/basys3.srcs/ppu.vhd')
-rw-r--r--basys3/basys3.srcs/ppu.vhd235
1 files changed, 99 insertions, 136 deletions
diff --git a/basys3/basys3.srcs/ppu.vhd b/basys3/basys3.srcs/ppu.vhd
index d6407df..0955506 100644
--- a/basys3/basys3.srcs/ppu.vhd
+++ b/basys3/basys3.srcs/ppu.vhd
@@ -2,19 +2,17 @@ library ieee;
library work;
use ieee.std_logic_1164.all;
---use ieee.numeric_std.all;
use work.ppu_consts.all;
entity ppu is port(
CLK100 : in std_logic; -- system clock
RESET : in std_logic; -- global (async) system reset
- EN : in std_logic; -- PPU VRAM enable (enable ADDR and DATA tri-state drivers)
WEN : in std_logic; -- PPU VRAM write enable
ADDR : in std_logic_vector(PPU_RAM_BUS_ADDR_WIDTH-1 downto 0); -- PPU VRAM ADDR
DATA : in std_logic_vector(PPU_RAM_BUS_DATA_WIDTH-1 downto 0);
R,G,B : out std_logic_vector(PPU_COLOR_OUTPUT_DEPTH-1 downto 0);
- NVSYNC, NHSYNC : out std_logic; -- native VGA out
- TVBLANK, THBLANK : out std_logic); -- tiny VGA out
+ VSYNC, HSYNC : out std_logic; -- VGA sync out
+ VBLANK : out std_logic); -- vblank for synchronization
end ppu;
architecture Behavioral of ppu is
@@ -22,47 +20,48 @@ architecture Behavioral of ppu is
component ppu_pceg port( -- pipeline clock edge generator
CLK : in std_logic; -- system clock
RESET : in std_logic; -- async reset
- SPRITE : out std_logic; -- sprite info fetch + sprite pixel fetch
- COMP_PAL : out std_logic; -- compositor + palette lookup
- DONE : out std_logic); -- last pipeline stage done
+ SPRITE_BG : out std_logic; -- sprite info fetch + sprite pixel fetch
+ SPRITE_FG : out std_logic; -- sprite pixel fetch
+ DONE : out std_logic; -- last pipeline stage done
+ READY : out std_logic); -- rgb buffer propagation ready
end component;
- component ppu_addr_dec port( -- pipeline clock edge generator
+ component ppu_addr_dec port( -- address decoder
WEN : in std_logic; -- EXT write enable
TMM_WEN,
BAM_WEN,
FAM_WEN,
PAL_WEN,
AUX_WEN : out std_logic; -- write enable MUX
- EN : in std_logic; -- EXT *ADDR enable (switch *AO to ADDR instead of *AI)
ADDR : in std_logic_vector(PPU_RAM_BUS_ADDR_WIDTH-1 downto 0); -- address in
- TMM_AI : in std_logic_vector(PPU_TMM_ADDR_WIDTH-1 downto 0);
- BAM_AI : in std_logic_vector(PPU_BAM_ADDR_WIDTH-1 downto 0);
- FAM_AI : in std_logic_vector(PPU_FAM_ADDR_WIDTH-1 downto 0);
- PAL_AI : in std_logic_vector(PPU_PAL_ADDR_WIDTH-1 downto 0);
- AUX_AI : in std_logic_vector(PPU_AUX_ADDR_WIDTH-1 downto 0);
- TMM_AO : out std_logic_vector(PPU_TMM_ADDR_WIDTH-1 downto 0);
- BAM_AO : out std_logic_vector(PPU_BAM_ADDR_WIDTH-1 downto 0);
- FAM_AO : out std_logic_vector(PPU_FAM_ADDR_WIDTH-1 downto 0);
- PAL_AO : out std_logic_vector(PPU_PAL_ADDR_WIDTH-1 downto 0);
- AUX_AO : out std_logic_vector(PPU_AUX_ADDR_WIDTH-1 downto 0));
+ TMM_ADDR : out std_logic_vector(PPU_TMM_ADDR_WIDTH-1 downto 0);
+ BAM_ADDR : out std_logic_vector(PPU_BAM_ADDR_WIDTH-1 downto 0);
+ FAM_ADDR : out std_logic_vector(PPU_FAM_ADDR_WIDTH-1 downto 0);
+ PAL_ADDR : out std_logic_vector(PPU_PAL_ADDR_WIDTH-1 downto 0);
+ AUX_ADDR : out std_logic_vector(PPU_AUX_ADDR_WIDTH-1 downto 0));
end component;
component ppu_bam port( -- BAM block memory
clka : in std_logic;
- rsta : in std_logic;
- wea : in std_logic_vector(0 downto 0);
+ wea : in std_logic_vector(0 to 0);
addra : in std_logic_vector(PPU_BAM_ADDR_WIDTH-1 downto 0);
dina : in std_logic_vector(PPU_BAM_DATA_WIDTH-1 downto 0);
- douta : out std_logic_vector(PPU_BAM_DATA_WIDTH-1 downto 0);
- rsta_busy : out std_logic);
+ clkb : in std_logic;
+ rstb : in std_logic;
+ addrb : in std_logic_vector(PPU_BAM_ADDR_WIDTH-1 downto 0);
+ doutb : out std_logic_vector(PPU_BAM_DATA_WIDTH-1 downto 0);
+ rsta_busy : out std_logic;
+ rstb_busy : out std_logic);
end component;
component ppu_tmm port( -- TMM block memory
clka : in std_logic;
- rsta : in std_logic;
- wea : in std_logic_vector(0 downto 0);
+ wea : in std_logic_vector(0 to 0);
addra : in std_logic_vector(PPU_TMM_ADDR_WIDTH-1 downto 0);
dina : in std_logic_vector(PPU_TMM_DATA_WIDTH-1 downto 0);
- douta : out std_logic_vector(PPU_TMM_DATA_WIDTH-1 downto 0);
- rsta_busy : out std_logic);
+ clkb : in std_logic;
+ rstb : in std_logic;
+ addrb : in std_logic_vector(PPU_TMM_ADDR_WIDTH-1 downto 0);
+ doutb : out std_logic_vector(PPU_TMM_DATA_WIDTH-1 downto 0);
+ rsta_busy : out std_logic;
+ rstb_busy : out std_logic);
end component;
component ppu_aux port(
CLK : in std_logic; -- system clock
@@ -82,6 +81,7 @@ architecture Behavioral of ppu is
-- inputs
CLK : in std_logic; -- pipeline clock
RESET : in std_logic; -- reset clock counter
+ PL_RESET : in std_logic; -- reset pipeline clock counters
OE : in std_logic; -- output enable (of CIDX)
X : in std_logic_vector(PPU_POS_H_WIDTH-1 downto 0); -- current screen pixel x
Y : in std_logic_vector(PPU_POS_V_WIDTH-1 downto 0); -- current screen pixel y
@@ -106,6 +106,8 @@ architecture Behavioral of ppu is
-- inputs
CLK : in std_logic; -- system clock
RESET : in std_logic; -- reset internal memory and clock counters
+ PL_CLK : in std_logic; -- pipeline clock
+ PL_RESET : in std_logic; -- reset pipeline clock counters
OE : in std_logic; -- output enable (of CIDX)
X : in std_logic_vector(PPU_POS_H_WIDTH-1 downto 0); -- current screen pixel x
Y : in std_logic_vector(PPU_POS_V_WIDTH-1 downto 0); -- current screen pixel y
@@ -142,94 +144,68 @@ architecture Behavioral of ppu is
R,G,B : out std_logic_vector(PPU_COLOR_OUTPUT_DEPTH-1 downto 0)); -- VGA color out
end component;
- component ppu_vga_tiny port( -- tiny vga signal generator
- CLK : in std_logic; -- system clock
- RESET : in std_logic;
-
- X : out std_logic_vector(PPU_POS_H_WIDTH-1 downto 0); -- current screen pixel x
- Y : out std_logic_vector(PPU_POS_V_WIDTH-1 downto 0); -- current screen pixel y
-
- VSYNC, VBLANK,
- HSYNC, HBLANK : out std_logic); -- VGA sync outputs
- end component;
- component ppu_vga_native port( -- native vga signal generator (upscaler)
- CLK : in std_logic; -- system clock
+ component ppu_dispctl port(
+ SYSCLK : in std_logic; -- system clock
RESET : in std_logic;
- X : in std_logic_vector(PPU_POS_H_WIDTH-1 downto 0); -- current screen pixel x
- Y : in std_logic_vector(PPU_POS_V_WIDTH-1 downto 0); -- current screen pixel y
+ X : out std_logic_vector(PPU_POS_H_WIDTH-1 downto 0); -- tiny screen pixel x
+ Y : out std_logic_vector(PPU_POS_V_WIDTH-1 downto 0); -- tiny screen pixel y
+ RI,GI,BI : in std_logic_vector(PPU_COLOR_OUTPUT_DEPTH-1 downto 0); -- color in
PREADY : in std_logic; -- current pixel ready (pixel color is stable)
- RI,GI,BI : in std_logic_vector(PPU_COLOR_OUTPUT_DEPTH-1 downto 0); -- VGA color in
-
+
RO,GO,BO : out std_logic_vector(PPU_COLOR_OUTPUT_DEPTH-1 downto 0); -- VGA color out
- VSYNC, HSYNC : out std_logic); -- VGA sync outputs
+ NVSYNC, NHSYNC : out std_logic; -- VGA sync out
+ THBLANK, TVBLANK : out std_logic); -- tiny sync signals
end component;
-- signals
signal SYSCLK, SYSRST : std_logic; -- system clock and reset
- signal PL_SPRITE, PL_COMP_PAL, PL_DONE : std_logic; -- pipeline stages
+ signal PL_SPRITE_FG, PL_SPRITE_BG, PL_DONE, PL_READY : std_logic; -- pipeline stages
signal TMM_WEN, BAM_WEN, FAM_WEN, PAL_WEN, AUX_WEN : std_logic;
- signal TMM_AI, TMM_AO : std_logic_vector(PPU_TMM_ADDR_WIDTH-1 downto 0);
- signal BAM_AI, BAM_AO : std_logic_vector(PPU_BAM_ADDR_WIDTH-1 downto 0);
- signal FAM_AI, FAM_AO : std_logic_vector(PPU_FAM_ADDR_WIDTH-1 downto 0);
- signal PAL_AI, PAL_AO : std_logic_vector(PPU_PAL_ADDR_WIDTH-1 downto 0);
- signal AUX_AI, AUX_AO : std_logic_vector(PPU_AUX_ADDR_WIDTH-1 downto 0);
- signal TMM_DO : std_logic_vector(PPU_TMM_DATA_WIDTH-1 downto 0);
- signal BAM_DO : std_logic_vector(PPU_BAM_DATA_WIDTH-1 downto 0);
- signal FAM_DO : std_logic_vector(PPU_FAM_DATA_WIDTH-1 downto 0);
- signal PAL_DO : std_logic_vector(PPU_PAL_DATA_WIDTH-1 downto 0);
- signal AUX_DO : std_logic_vector(PPU_AUX_DATA_WIDTH-1 downto 0);
+ signal TMM_W_ADDR, TMM_R_ADDR : std_logic_vector(PPU_TMM_ADDR_WIDTH-1 downto 0); -- read/write TMM addr (dual port)
+ signal BAM_W_ADDR, BAM_R_ADDR : std_logic_vector(PPU_BAM_ADDR_WIDTH-1 downto 0); -- read/write BAM addr (dual port)
+ signal TMM_R_DATA : std_logic_vector(PPU_TMM_DATA_WIDTH-1 downto 0); -- internal read TMM data
+ signal BAM_R_DATA : std_logic_vector(PPU_BAM_DATA_WIDTH-1 downto 0); -- internal read BAM data
+ signal FAM_W_ADDR : std_logic_vector(PPU_FAM_ADDR_WIDTH-1 downto 0); -- write only FAM addr
+ signal PAL_W_ADDR : std_logic_vector(PPU_PAL_ADDR_WIDTH-1 downto 0); -- write only PAL addr
+ signal AUX_W_ADDR : std_logic_vector(PPU_AUX_ADDR_WIDTH-1 downto 0); -- write only AUX addr
signal CIDX : std_logic_vector(PPU_PALETTE_CIDX_WIDTH-1 downto 0);
signal BG_EN : std_logic;
signal FG_EN, FG_HIT : std_logic_vector(PPU_FG_SPRITE_COUNT-1 downto 0);
signal X : std_logic_vector(PPU_POS_H_WIDTH-1 downto 0); -- current screen pixel x
signal Y : std_logic_vector(PPU_POS_V_WIDTH-1 downto 0); -- current screen pixel y
- signal UR,UG,UB : std_logic_vector(PPU_COLOR_OUTPUT_DEPTH-1 downto 0); -- unstable RGB (to be buffered)
- signal SR,SG,SB : std_logic_vector(PPU_COLOR_OUTPUT_DEPTH-1 downto 0); -- stable RGB (buffered until PL_COMP_PAL)
+ signal UR,UG,UB : std_logic_vector(PPU_COLOR_OUTPUT_DEPTH-1 downto 0); -- palette lookup output RGB
signal BG_SHIFT_X : std_logic_vector(PPU_POS_H_WIDTH-1 downto 0);
signal BG_SHIFT_Y : std_logic_vector(PPU_POS_V_WIDTH-1 downto 0);
signal FG_FETCH : std_logic;
- signal TINY_VBLANK, TINY_HBLANK,
- NATIVE_VSYNC, NATIVE_HSYNC : std_logic;
+ signal NVSYNC, NHSYNC, THBLANK, TVBLANK : std_logic;
+ signal PCEG_RESET : std_logic;
begin
SYSCLK <= CLK100;
SYSRST <= RESET;
- -- internal unused lines
- --
- -- these lines would be used if components use memory blocks as RAM blocks
- -- (like how TMM and BAM work), the registers of these memory regions are
- -- directly exposed internally, and are as such not used as RAM blocks
- AUX_AI <= (others => '0');
- FAM_AI <= (others => '0');
- PAL_AI <= (others => '0');
+ VSYNC <= NVSYNC;
+ HSYNC <= NHSYNC;
- TVBLANK <= TINY_VBLANK;
- THBLANK <= TINY_HBLANK;
- NVSYNC <= NATIVE_VSYNC;
- NHSYNC <= NATIVE_HSYNC;
+ PCEG_RESET <= SYSRST or THBLANK;
+ VBLANK <= TVBLANK;
pipeline_clock_edge_generator : component ppu_pceg port map(
CLK => SYSCLK,
RESET => SYSRST,
- SPRITE => PL_SPRITE,
- COMP_PAL => PL_COMP_PAL,
- DONE => PL_DONE);
+ SPRITE_FG => PL_SPRITE_FG,
+ SPRITE_BG => PL_SPRITE_BG,
+ DONE => PL_DONE,
+ READY => PL_READY);
address_decoder : component ppu_addr_dec port map(
- EN => EN,
WEN => WEN,
ADDR => ADDR,
- TMM_AI => TMM_AI,
- BAM_AI => BAM_AI,
- FAM_AI => FAM_AI,
- PAL_AI => PAL_AI,
- AUX_AI => AUX_AI,
- TMM_AO => TMM_AO,
- BAM_AO => BAM_AO,
- FAM_AO => FAM_AO,
- PAL_AO => PAL_AO,
- AUX_AO => AUX_AO,
+ TMM_ADDR => TMM_W_ADDR,
+ BAM_ADDR => BAM_W_ADDR,
+ FAM_ADDR => FAM_W_ADDR,
+ PAL_ADDR => PAL_W_ADDR,
+ AUX_ADDR => AUX_W_ADDR,
TMM_WEN => TMM_WEN,
BAM_WEN => BAM_WEN,
FAM_WEN => FAM_WEN,
@@ -238,43 +214,50 @@ begin
background_attribute_memory : component ppu_bam port map(
clka => SYSCLK,
- rsta => SYSRST,
wea => (others => BAM_WEN),
- addra => BAM_AO,
+ addra => BAM_W_ADDR,
dina => DATA(PPU_BAM_DATA_WIDTH-1 downto 0),
- douta => BAM_DO,
- rsta_busy => open);
+ clkb => SYSCLK,
+ rstb => SYSRST,
+ addrb => BAM_R_ADDR,
+ doutb => BAM_R_DATA,
+ rsta_busy => open,
+ rstb_busy => open);
tilemap_memory : component ppu_tmm port map(
clka => SYSCLK,
- rsta => SYSRST,
wea => (others => TMM_WEN),
- addra => TMM_AO,
+ addra => TMM_W_ADDR,
dina => DATA(PPU_TMM_DATA_WIDTH-1 downto 0),
- douta => TMM_DO,
- rsta_busy => open);
+ clkb => SYSCLK,
+ rstb => SYSRST,
+ addrb => TMM_R_ADDR,
+ doutb => TMM_R_DATA,
+ rsta_busy => open,
+ rstb_busy => open);
aux : component ppu_aux port map(
CLK => SYSCLK,
RESET => SYSRST,
AUX_WEN => AUX_WEN,
- AUX_ADDR => AUX_AO,
+ AUX_ADDR => AUX_W_ADDR,
AUX_DATA => DATA(PPU_AUX_DATA_WIDTH-1 downto 0),
BG_SHIFT_X => BG_SHIFT_X,
BG_SHIFT_Y => BG_SHIFT_Y,
FG_FETCH => FG_FETCH);
background_sprite : component ppu_sprite_bg port map(
- CLK => PL_SPRITE,
+ CLK => PL_SPRITE_BG,
RESET => SYSRST,
+ PL_RESET => PL_READY,
OE => BG_EN,
X => X,
Y => Y,
BG_SHIFT_X => BG_SHIFT_X,
BG_SHIFT_Y => BG_SHIFT_Y,
- BAM_ADDR => BAM_AI,
- BAM_DATA => BAM_DO,
- TMM_ADDR => TMM_AI,
- TMM_DATA => TMM_DO,
+ BAM_ADDR => BAM_R_ADDR,
+ BAM_DATA => BAM_R_DATA,
+ TMM_ADDR => TMM_R_ADDR,
+ TMM_DATA => TMM_R_DATA,
CIDX => CIDX);
foreground_sprites : for FG_IDX in 0 to PPU_FG_SPRITE_COUNT-1 generate
@@ -283,16 +266,18 @@ begin
port map(
CLK => SYSCLK,
RESET => SYSRST,
+ PL_CLK => PL_SPRITE_FG,
+ PL_RESET => PL_READY,
OE => FG_EN(FG_IDX),
X => X,
Y => Y,
FETCH => FG_FETCH,
- VBLANK => TINY_VBLANK,
+ VBLANK => TVBLANK,
FAM_WEN => FAM_WEN,
- FAM_ADDR => FAM_AO,
+ FAM_ADDR => FAM_W_ADDR,
FAM_DATA => DATA(PPU_FAM_DATA_WIDTH-1 downto 0),
- TMM_ADDR => TMM_AI,
- TMM_DATA => TMM_DO,
+ TMM_ADDR => TMM_R_ADDR,
+ TMM_DATA => TMM_R_DATA,
CIDX => CIDX,
HIT => FG_HIT(FG_IDX));
end generate;
@@ -307,48 +292,26 @@ begin
CIDX => CIDX,
RESET => SYSRST,
PAL_WEN => PAL_WEN,
- PAL_ADDR => PAL_AO,
+ PAL_ADDR => PAL_W_ADDR,
PAL_DATA => DATA(PPU_PAL_DATA_WIDTH-1 downto 0),
R => UR,
G => UG,
B => UB);
- -- palette lookup output buffer (pipeline stage 5)
- process(PL_COMP_PAL, SYSRST)
- begin
- if SYSRST = '1' then
- SR <= x"0";
- SG <= x"0";
- SB <= x"0";
- elsif rising_edge(PL_COMP_PAL) then
- SR <= UR;
- SG <= UG;
- SB <= UB;
- end if;
- end process;
-
- tiny_vga_signal_generator : component ppu_vga_tiny port map( -- tiny vga signal generator
- CLK => SYSCLK,
- RESET => SYSRST,
- X => X,
- Y => Y,
- VSYNC => open,
- VBLANK => TINY_VBLANK,
- HSYNC => open,
- HBLANK => TINY_HBLANK);
-
- native_vga_signal_generator : component ppu_vga_native port map( -- native vga signal generator (upscaler)
- CLK => SYSCLK,
+ display_controller : component ppu_dispctl port map(
+ SYSCLK => SYSCLK,
RESET => SYSRST,
+ PREADY => PL_READY,
X => X,
Y => Y,
- PREADY => PL_DONE,
- RI => SR,
- GI => SG,
- BI => SB,
+ RI => UR,
+ GI => UG,
+ BI => UB,
RO => R,
GO => G,
BO => B,
- VSYNC => NATIVE_VSYNC,
- HSYNC => NATIVE_HSYNC);
+ NVSYNC => NVSYNC,
+ NHSYNC => NHSYNC,
+ TVBLANK => TVBLANK,
+ THBLANK => THBLANK);
end Behavioral;