diff options
-rw-r--r-- | basys3/basys3.srcs/ppu_consts.vhd | 19 | ||||
-rw-r--r-- | basys3/basys3.srcs/ppu_dispctl.vhd | 76 | ||||
-rw-r--r-- | basys3/basys3.srcs/ppu_dispctl_tb.vhd | 63 | ||||
-rw-r--r-- | basys3/basys3.xpr | 27 |
4 files changed, 169 insertions, 16 deletions
diff --git a/basys3/basys3.srcs/ppu_consts.vhd b/basys3/basys3.srcs/ppu_consts.vhd index 48fab5a..c140b98 100644 --- a/basys3/basys3.srcs/ppu_consts.vhd +++ b/basys3/basys3.srcs/ppu_consts.vhd @@ -50,6 +50,25 @@ package ppu_consts is constant PPU_TMM_CACHE_FETCH_A_WIDTH : natural := ceil_log2(PPU_TMM_CACHE_FETCH_A_COUNT); constant PPU_ACCURATE_FG_SPRITE_COUNT : natural := 16; constant PPU_PL_TOTAL_STAGES : natural := 14; + -- VGA signal timings (https://tomverbeure.github.io/video_timings_calculator) + constant PPU_VGA_H_ACTIVE : natural := PPU_NATIVE_SCREEN_WIDTH; + constant PPU_VGA_H_PORCH_FRONT : natural := 16; + constant PPU_VGA_H_SYNC : natural := 64; + constant PPU_VGA_H_PORCH_BACK : natural := 80; + constant PPU_VGA_H_BLANK : natural := PPU_VGA_H_PORCH_FRONT + PPU_VGA_H_SYNC + PPU_VGA_H_PORCH_BACK; + constant PPU_VGA_H_TOTAL : natural := PPU_VGA_H_BLANK + PPU_VGA_H_ACTIVE; + constant PPU_VGA_V_ACTIVE : natural := PPU_NATIVE_SCREEN_HEIGHT; + constant PPU_VGA_V_PORCH_FRONT : natural := 3; + constant PPU_VGA_V_SYNC : natural := 4; + constant PPU_VGA_V_PORCH_BACK : natural := 13; + constant PPU_VGA_V_BLANK : natural := PPU_VGA_V_PORCH_FRONT + PPU_VGA_V_SYNC + PPU_VGA_V_PORCH_BACK; + constant PPU_VGA_V_TOTAL : natural := PPU_VGA_V_BLANK + PPU_VGA_V_ACTIVE; + constant PPU_VGA_SIGNAL_PIXEL_IDX_MAX : natural := PPU_VGA_V_TOTAL * PPU_VGA_H_TOTAL; -- horizontal and vertical pixel clock index + constant PPU_VGA_SIGNAL_PIXEL_WIDTH : natural := ceil_log2(PPU_VGA_SIGNAL_PIXEL_IDX_MAX); -- bit width to count total horizontal and vertical pixel clock index + constant PPU_SCREEN_T_POS_X_WIDTH : natural := ceil_log2(PPU_SCREEN_WIDTH); + constant PPU_SCREEN_T_POS_Y_WIDTH : natural := ceil_log2(PPU_SCREEN_HEIGHT); + constant PPU_SCREEN_N_POS_X_WIDTH : natural := ceil_log2(PPU_NATIVE_SCREEN_WIDTH); + constant PPU_SCREEN_N_POS_Y_WIDTH : natural := ceil_log2(PPU_NATIVE_SCREEN_HEIGHT); end package ppu_consts; package body ppu_consts is -- https://stackoverflow.com/questions/21783280/number-of-bits-to-represent-an-integer-in-vhdl diff --git a/basys3/basys3.srcs/ppu_dispctl.vhd b/basys3/basys3.srcs/ppu_dispctl.vhd index e1086b2..8f07f93 100644 --- a/basys3/basys3.srcs/ppu_dispctl.vhd +++ b/basys3/basys3.srcs/ppu_dispctl.vhd @@ -1,5 +1,6 @@ library ieee; use ieee.std_logic_1164.all; +use ieee.std_logic_unsigned.all; use ieee.numeric_std.all; use work.ppu_consts.all; @@ -30,19 +31,82 @@ architecture Behavioral of ppu_dispctl is rsta_busy : out std_logic; rstb_busy : out std_logic); end component; - signal RGB_COLOR : std_logic_vector(PPU_RGB_COLOR_OUTPUT_DEPTH-1 downto 0); + signal CLK25 : unsigned(1 downto 0) := (others => '0'); -- clock divider (100_000_000/4) + signal PCOUNT, HCOUNT, VCOUNT : unsigned(PPU_VGA_SIGNAL_PIXEL_WIDTH-1 downto 0) := (others => '0'); + signal ADDR_I, ADDR_O : std_logic_vector(PPU_DISPCTL_SLBUF_ADDR_WIDTH-1 downto 0); + signal DATA_I, DATA_O : std_logic_vector(PPU_RGB_COLOR_OUTPUT_DEPTH-1 downto 0); + signal T_POS_X : unsigned(PPU_SCREEN_T_POS_X_WIDTH-1 downto 0) := (others => '0'); + signal T_POS_Y : unsigned(PPU_SCREEN_T_POS_Y_WIDTH-1 downto 0) := (others => '0'); + signal N_POS_X : unsigned(PPU_SCREEN_N_POS_X_WIDTH-1 downto 0) := (others => '0'); + signal N_POS_Y : unsigned(PPU_SCREEN_N_POS_Y_WIDTH-1 downto 0) := (others => '0'); + signal ACTIVE, HACTIVE, VACTIVE : std_logic := '0'; begin - RGB_COLOR <= RI & GI & BI; + DATA_I <= RI & GI & BI; + ADDR_I <= std_logic_vector(resize(T_POS_X, ADDR_I'length)) when T_POS_Y(0) = '0' else std_logic_vector(resize(T_POS_X, ADDR_I'length) + PPU_SCREEN_WIDTH); + + X <= std_logic_vector(T_POS_X); + Y <= std_logic_vector(T_POS_Y); + + RO <= DATA_O(11 downto 8); + GO <= DATA_O(7 downto 4); + BO <= DATA_O(3 downto 0); + + HCOUNT <= PCOUNT mod PPU_VGA_H_TOTAL; + VCOUNT <= PCOUNT / PPU_VGA_H_TOTAL mod PPU_VGA_V_TOTAL; + + HACTIVE <= '1' when + (HCOUNT > (PPU_VGA_H_PORCH_BACK)) and + (HCOUNT <= (PPU_VGA_H_PORCH_BACK + PPU_VGA_H_ACTIVE)) else '0'; + VACTIVE <= '1' when + (VCOUNT > (PPU_VGA_V_PORCH_BACK)) and + (VCOUNT <= (PPU_VGA_V_PORCH_BACK + PPU_VGA_V_ACTIVE)) else '0'; + ACTIVE <= HACTIVE and VACTIVE; + + NVSYNC <= '1' when + (VCOUNT > (PPU_VGA_V_PORCH_BACK + PPU_VGA_V_ACTIVE)) and + (VCOUNT <= (PPU_VGA_V_PORCH_BACK + PPU_VGA_V_ACTIVE + PPU_VGA_V_SYNC)) else '0'; + NHSYNC <= '1' when VACTIVE = '1' and + (HCOUNT > (PPU_VGA_H_PORCH_BACK + PPU_VGA_H_ACTIVE)) and + (HCOUNT <= (PPU_VGA_H_PORCH_BACK + PPU_VGA_H_ACTIVE + PPU_VGA_H_SYNC)) else '0'; + + N_POS_X <= resize(HCOUNT - PPU_VGA_H_PORCH_BACK, N_POS_X'length); + N_POS_Y <= resize(VCOUNT - PPU_VGA_V_PORCH_BACK, N_POS_Y'length); + + T_POS_X <= resize(N_POS_X / 2, T_POS_X'length); + T_POS_Y <= resize(N_POS_Y / 2, T_POS_Y'length); scanline_buffer : component ppu_dispctl_slbuf port map( clka => CLK, wea => (others => PREADY), - addra => (others => '0'), - dina => RGB_COLOR, + addra => ADDR_I, + dina => DATA_I, clkb => CLK, rstb => RESET, - addrb => (others => '0'), - doutb => open, + addrb => ADDR_O, + doutb => DATA_O, rsta_busy => open, rstb_busy => open); + + process(CLK, RESET) + begin + if RESET = '1' then + CLK25 <= (others => '0'); + elsif rising_edge(CLK) then + CLK25 <= CLK25 + 1; + end if; + end process; + + process(CLK25(1), RESET) + variable V_PCOUNT : unsigned(PPU_VGA_SIGNAL_PIXEL_WIDTH-1 downto 0) := (others => '0'); + begin + PCOUNT <= V_PCOUNT; + if RESET = '1' then + V_PCOUNT := (others => '0'); + elsif rising_edge(CLK25(1)) then + V_PCOUNT := V_PCOUNT + 1; + if V_PCOUNT = PPU_VGA_SIGNAL_PIXEL_IDX_MAX then + V_PCOUNT := (others => '0'); + end if; + end if; + end process; end Behavioral; diff --git a/basys3/basys3.srcs/ppu_dispctl_tb.vhd b/basys3/basys3.srcs/ppu_dispctl_tb.vhd new file mode 100644 index 0000000..fa11655 --- /dev/null +++ b/basys3/basys3.srcs/ppu_dispctl_tb.vhd @@ -0,0 +1,63 @@ +library ieee; +library unisim; + +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; +use unisim.vcomponents.all; +use work.ppu_consts.all; + +entity ppu_dispctl_tb is +end ppu_dispctl_tb; + +architecture behavioral of ppu_dispctl_tb is + component ppu_dispctl port( + CLK : in std_logic; -- system clock + RESET : in std_logic; + + 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) + + RO,GO,BO : out std_logic_vector(PPU_COLOR_OUTPUT_DEPTH-1 downto 0); -- VGA color out + NVSYNC, NHSYNC : out std_logic; -- VGA sync out + THBLANK, TVBLANK : out std_logic); -- tiny sync signals + end component; + signal CLK : std_logic := '0'; + signal RESET : std_logic := '0'; + signal X : std_logic_vector(PPU_POS_H_WIDTH-1 downto 0) := (others => '0'); + signal Y : std_logic_vector(PPU_POS_V_WIDTH-1 downto 0) := (others => '0'); + signal RI,GI,BI : std_logic_vector(PPU_COLOR_OUTPUT_DEPTH-1 downto 0) := (others => '0'); + signal PREADY : std_logic := '0'; + signal RO,GO,BO : std_logic_vector(PPU_COLOR_OUTPUT_DEPTH-1 downto 0) := (others => '0'); + signal NVSYNC, NHSYNC : std_logic := '0'; + signal THBLANK, TVBLANK : std_logic := '0'; +begin + uut : component ppu_dispctl port map( + CLK => CLK, + RESET => RESET, + PREADY => PREADY, + X => X, + Y => Y, + RI => RI, + GI => GI, + BI => BI, + RO => RO, + GO => GO, + BO => BO, + NVSYNC => NVSYNC, + NHSYNC => NHSYNC, + TVBLANK => TVBLANK, + THBLANK => THBLANK); + + process + begin + for i in 0 to 3200000 loop + wait for 5 ps; + CLK <= '1'; + wait for 5 ps; + CLK <= '0'; + end loop; + wait; -- stop for simulator + end process; +end; diff --git a/basys3/basys3.xpr b/basys3/basys3.xpr index 4134b4d..97a30aa 100644 --- a/basys3/basys3.xpr +++ b/basys3/basys3.xpr @@ -61,7 +61,7 @@ <Option Name="IPStaticSourceDir" Val="$PIPUSERFILESDIR/ipstatic"/> <Option Name="EnableBDX" Val="FALSE"/> <Option Name="DSABoardId" Val="basys3"/> - <Option Name="WTXSimLaunchSim" Val="126"/> + <Option Name="WTXSimLaunchSim" Val="153"/> <Option Name="WTModelSimLaunchSim" Val="0"/> <Option Name="WTQuestaLaunchSim" Val="0"/> <Option Name="WTIesLaunchSim" Val="0"/> @@ -260,9 +260,15 @@ <Attr Name="UsedIn" Val="simulation"/> </FileInfo> </File> + <File Path="$PSRCDIR/ppu_dispctl_tb.vhd"> + <FileInfo> + <Attr Name="UsedIn" Val="synthesis"/> + <Attr Name="UsedIn" Val="simulation"/> + </FileInfo> + </File> <Config> <Option Name="DesignMode" Val="RTL"/> - <Option Name="TopModule" Val="ppu_pceg_tb"/> + <Option Name="TopModule" Val="ppu_dispctl_tb"/> <Option Name="TopLib" Val="xil_defaultlib"/> <Option Name="TransportPathDelay" Val="0"/> <Option Name="TransportIntDelay" Val="0"/> @@ -272,6 +278,7 @@ <Option Name="PamSignalDriverFile" Val="xil_bypass_driver"/> <Option Name="PamPseudoTop" Val="pseudo_tb"/> <Option Name="SrcSet" Val="sources_1"/> + <Option Name="xsim.simulate.runtime" Val="100 us"/> </Config> </FileSet> <FileSet Name="utils_1" Type="Utils" RelSrcDir="$PSRCDIR/utils_1" RelGenDir="$PGENDIR/utils_1"> @@ -354,7 +361,9 @@ <Runs Version="1" Minor="19"> <Run Id="synth_1" Type="Ft3:Synth" SrcSet="sources_1" Part="xc7a35tcpg236-1" ConstrsSet="constrs_1" Description="Vivado Synthesis Defaults" AutoIncrementalCheckpoint="true" IncrementalCheckpoint="$PSRCDIR/utils_1/imports/synth_1/ppu.dcp" WriteIncrSynthDcp="false" State="current" Dir="$PRUNDIR/synth_1" IncludeInArchive="true" IsChild="false" AutoIncrementalDir="$PSRCDIR/utils_1/imports/synth_1" AutoRQSDir="$PSRCDIR/utils_1/imports/synth_1"> <Strategy Version="1" Minor="2"> - <StratHandle Name="Vivado Synthesis Defaults" Flow="Vivado Synthesis 2022"/> + <StratHandle Name="Vivado Synthesis Defaults" Flow="Vivado Synthesis 2022"> + <Desc>Vivado Synthesis Defaults</Desc> + </StratHandle> <Step Id="synth_design"/> </Strategy> <GeneratedRun Dir="$PRUNDIR" File="gen_run.xml"/> @@ -384,9 +393,7 @@ </Run> <Run Id="ppu_dispctl_slbuf_synth_1" Type="Ft3:Synth" SrcSet="ppu_dispctl_slbuf" Part="xc7a35tcpg236-1" ConstrsSet="ppu_dispctl_slbuf" Description="Vivado Synthesis Defaults" AutoIncrementalCheckpoint="false" WriteIncrSynthDcp="false" Dir="$PRUNDIR/ppu_dispctl_slbuf_synth_1" IncludeInArchive="true" IsChild="false" AutoIncrementalDir="$PSRCDIR/utils_1/imports/ppu_dispctl_slbuf_synth_1" AutoRQSDir="$PSRCDIR/utils_1/imports/ppu_dispctl_slbuf_synth_1"> <Strategy Version="1" Minor="2"> - <StratHandle Name="Vivado Synthesis Defaults" Flow="Vivado Synthesis 2022"> - <Desc>Vivado Synthesis Defaults</Desc> - </StratHandle> + <StratHandle Name="Vivado Synthesis Defaults" Flow="Vivado Synthesis 2022"/> <Step Id="synth_design"/> </Strategy> <GeneratedRun Dir="$PRUNDIR" File="gen_run.xml"/> @@ -396,7 +403,9 @@ </Run> <Run Id="impl_1" Type="Ft2:EntireDesign" Part="xc7a35tcpg236-1" ConstrsSet="constrs_1" Description="Default settings for Implementation." AutoIncrementalCheckpoint="false" WriteIncrSynthDcp="false" State="current" Dir="$PRUNDIR/impl_1" SynthRun="synth_1" IncludeInArchive="true" IsChild="false" GenFullBitstream="true" AutoIncrementalDir="$PSRCDIR/utils_1/imports/impl_1" AutoRQSDir="$PSRCDIR/utils_1/imports/impl_1"> <Strategy Version="1" Minor="2"> - <StratHandle Name="Vivado Implementation Defaults" Flow="Vivado Implementation 2022"/> + <StratHandle Name="Vivado Implementation Defaults" Flow="Vivado Implementation 2022"> + <Desc>Default settings for Implementation.</Desc> + </StratHandle> <Step Id="init_design"/> <Step Id="opt_design"/> <Step Id="power_opt_design"/> @@ -448,9 +457,7 @@ </Run> <Run Id="ppu_dispctl_slbuf_impl_1" Type="Ft2:EntireDesign" Part="xc7a35tcpg236-1" ConstrsSet="ppu_dispctl_slbuf" Description="Default settings for Implementation." AutoIncrementalCheckpoint="false" WriteIncrSynthDcp="false" SynthRun="ppu_dispctl_slbuf_synth_1" IncludeInArchive="false" IsChild="false" GenFullBitstream="true" AutoIncrementalDir="$PSRCDIR/utils_1/imports/ppu_dispctl_slbuf_impl_1" AutoRQSDir="$PSRCDIR/utils_1/imports/ppu_dispctl_slbuf_impl_1"> <Strategy Version="1" Minor="2"> - <StratHandle Name="Vivado Implementation Defaults" Flow="Vivado Implementation 2022"> - <Desc>Default settings for Implementation.</Desc> - </StratHandle> + <StratHandle Name="Vivado Implementation Defaults" Flow="Vivado Implementation 2022"/> <Step Id="init_design"/> <Step Id="opt_design"/> <Step Id="power_opt_design"/> |