diff options
Diffstat (limited to 'basys3/basys3.srcs/ppu_dispctl.vhd')
-rw-r--r-- | basys3/basys3.srcs/ppu_dispctl.vhd | 191 |
1 files changed, 131 insertions, 60 deletions
diff --git a/basys3/basys3.srcs/ppu_dispctl.vhd b/basys3/basys3.srcs/ppu_dispctl.vhd index a70a2e7..b03ea3f 100644 --- a/basys3/basys3.srcs/ppu_dispctl.vhd +++ b/basys3/basys3.srcs/ppu_dispctl.vhd @@ -5,7 +5,7 @@ use ieee.numeric_std.all; use work.ppu_consts.all; entity ppu_dispctl is port( - CLK : in std_logic; -- system clock + SYSCLK : 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 @@ -19,6 +19,12 @@ entity ppu_dispctl is port( end ppu_dispctl; architecture Behavioral of ppu_dispctl is + component ppu_dispctl_pixclk is port ( + clk_out1 : out std_logic; + clk_out2 : out std_logic; + reset : in std_logic; + clk_in1 : in std_logic); + end component; component ppu_dispctl_slbuf port( -- scanline buffer clka : in std_logic; wea : in std_logic_vector(0 to 0); @@ -31,8 +37,9 @@ architecture Behavioral of ppu_dispctl is rsta_busy : out std_logic; rstb_busy : out std_logic); end component; - signal CLK25 : unsigned(1 downto 0) := (others => '0'); -- clock divider (100_000_000/4) - signal PCOUNT, NHCOUNT, NVCOUNT, THCOUNT, TVCOUNT: unsigned(PPU_VGA_SIGNAL_PIXEL_WIDTH-1 downto 0) := (others => '0'); + signal NPIXCLK, TPIXCLK : std_logic; + signal NHCOUNT, NVCOUNT, + THCOUNT, TVCOUNT: 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'); -- real tiny x position @@ -41,82 +48,146 @@ architecture Behavioral of ppu_dispctl is signal U_POS_Y : unsigned(PPU_SCREEN_T_POS_Y_WIDTH-1 downto 0) := (others => '0'); -- upscaled tiny y position signal N_POS_X : unsigned(PPU_SCREEN_N_POS_X_WIDTH-1 downto 0) := (others => '0'); -- native x position signal N_POS_Y : unsigned(PPU_SCREEN_N_POS_Y_WIDTH-1 downto 0) := (others => '0'); -- native y position + signal TMP_X : std_logic_vector(PPU_POS_H_WIDTH-1 downto 0) := (others => '0'); -- tiny screen pixel x + signal TMP_Y : std_logic_vector(PPU_POS_V_WIDTH-1 downto 0) := (others => '0'); -- tiny screen pixel y + signal TMP_RO, TMP_GO, TMP_BO : std_logic_vector(PPU_COLOR_OUTPUT_DEPTH-1 downto 0) := (others => '0'); -- VGA color out + signal TMP_THBLANK, TMP_TVBLANK : std_logic := '0'; -- tiny sync signals + signal NACTIVE, NHACTIVE, NVACTIVE : std_logic := '0'; signal TACTIVE, THACTIVE, TVACTIVE : std_logic := '0'; begin - NHCOUNT <= PCOUNT mod PPU_VGA_H_TOTAL; - NVCOUNT <= (PCOUNT / PPU_VGA_H_TOTAL) mod PPU_VGA_V_TOTAL; - - THCOUNT <= (PCOUNT / 4) mod (PPU_VGA_H_TOTAL / 2); - TVCOUNT <= (PCOUNT / 4) / (PPU_VGA_H_TOTAL / 2) mod (PPU_VGA_V_TOTAL / 2); - - NHACTIVE <= '1' when - (NHCOUNT >= (PPU_VGA_H_PORCH_BACK)) and - (NHCOUNT < (PPU_VGA_H_PORCH_BACK + PPU_VGA_H_ACTIVE)) else '0'; - NVACTIVE <= '1' when - (NVCOUNT >= (PPU_VGA_V_PORCH_BACK)) and - (NVCOUNT < (PPU_VGA_V_PORCH_BACK + PPU_VGA_V_ACTIVE)) else '0'; - NACTIVE <= NHACTIVE and NVACTIVE; - - NVSYNC <= '1' when - (NVCOUNT >= (PPU_VGA_V_PORCH_BACK + PPU_VGA_V_ACTIVE)) and - (NVCOUNT < (PPU_VGA_V_PORCH_BACK + PPU_VGA_V_ACTIVE + PPU_VGA_V_SYNC)) else '0'; - NHSYNC <= '1' when NVACTIVE = '1' and - (NHCOUNT >= (PPU_VGA_H_PORCH_BACK + PPU_VGA_H_ACTIVE)) and - (NHCOUNT < (PPU_VGA_H_PORCH_BACK + PPU_VGA_H_ACTIVE + PPU_VGA_H_SYNC)) else '0'; - - N_POS_X <= resize(NHCOUNT - PPU_VGA_H_PORCH_BACK, N_POS_X'length) when NHACTIVE = '1' else (others => '0'); - N_POS_Y <= resize(NVCOUNT - PPU_VGA_V_PORCH_BACK, N_POS_Y'length) when NVACTIVE = '1' else (others => '0'); - - T_POS_X <= resize(THCOUNT - (PPU_VGA_H_PORCH_BACK / 4), T_POS_X'length) when N_POS_Y(0) = '0' else - resize(THCOUNT - ((PPU_VGA_H_PORCH_BACK + PPU_VGA_H_BLANK) / 4), T_POS_X'length); -- divide tiny x equally over two native scanlines - T_POS_Y <= resize(TVCOUNT - (PPU_VGA_V_PORCH_BACK / 2), T_POS_Y'length); - - 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) when NACTIVE = '1' else (others => '0'); - Y <= std_logic_vector(T_POS_Y) when NACTIVE = '1' else (others => '0'); - - U_POS_X <= resize(N_POS_X / 2, U_POS_X'length); - U_POS_Y <= resize(N_POS_Y / 2, U_POS_Y'length); + -- native (TODO: +upscaled) VCOUNT and HCOUNT + process(NPIXCLK, RESET) + variable TMP_NHCOUNT, TMP_NVCOUNT : unsigned(PPU_VGA_SIGNAL_PIXEL_WIDTH-1 downto 0) := (others => '0'); + variable TMP_NHACTIVE, TMP_NVACTIVE : std_logic := '0'; + variable TMP_NHSYNC, TMP_NVSYNC : std_logic := '0'; + begin + NVCOUNT <= TMP_NVCOUNT; + NHCOUNT <= TMP_NHCOUNT; + NHACTIVE <= TMP_NHACTIVE; + NVACTIVE <= TMP_NVACTIVE; + NACTIVE <= TMP_NHACTIVE and TMP_NVACTIVE; + NVSYNC <= TMP_NVSYNC; + NHSYNC <= TMP_NHSYNC; + N_POS_X <= resize(TMP_NHCOUNT - PPU_VGA_H_PORCH_BACK, N_POS_X'length) when TMP_NHACTIVE = '1' else (others => '0'); + N_POS_Y <= resize(TMP_NVCOUNT - PPU_VGA_V_PORCH_BACK, N_POS_Y'length) when TMP_NVACTIVE = '1' else (others => '0'); + + if RESET = '1' then + TMP_NHCOUNT := (others => '0'); + TMP_NVCOUNT := (others => '0'); + TMP_NHACTIVE := '0'; + TMP_NVACTIVE := '0'; + TMP_NVSYNC := '0'; + TMP_NHSYNC := '0'; + elsif rising_edge(NPIXCLK) then + -- horizontal count (pixel) + TMP_NHCOUNT := TMP_NHCOUNT + 1; + if TMP_NHCOUNT >= PPU_VGA_H_TOTAL then + TMP_NHCOUNT := (others => '0'); + + -- vertical count (scanline) + TMP_NVCOUNT := TMP_NVCOUNT + 1; + if TMP_NVCOUNT >= PPU_VGA_V_TOTAL then + TMP_NVCOUNT := (others => '0'); + end if; + + -- vertical display area (active) + if TMP_NVCOUNT = PPU_VGA_V_PORCH_BACK then TMP_NVACTIVE := '1'; end if; + if TMP_NVCOUNT = PPU_VGA_V_PORCH_BACK + PPU_VGA_V_ACTIVE then TMP_NVACTIVE := '0'; end if; + + -- vertical sync period + if TMP_NVCOUNT = PPU_VGA_V_PORCH_BACK + PPU_VGA_V_ACTIVE then TMP_NVSYNC := '1'; end if; + if TMP_NVCOUNT = PPU_VGA_V_PORCH_BACK + PPU_VGA_V_ACTIVE + PPU_VGA_V_SYNC then TMP_NVSYNC := '0'; end if; + end if; + + -- horizontal display area (active) + if TMP_NHCOUNT = PPU_VGA_H_PORCH_BACK then TMP_NHACTIVE := '1'; end if; + if TMP_NHCOUNT = PPU_VGA_H_PORCH_BACK + PPU_VGA_H_ACTIVE then TMP_NHACTIVE := '0'; end if; + + -- horizontal sync period + if TMP_NHCOUNT = PPU_VGA_H_PORCH_BACK + PPU_VGA_H_ACTIVE then TMP_NHSYNC := '1'; end if; + if TMP_NHCOUNT = PPU_VGA_H_PORCH_BACK + PPU_VGA_H_ACTIVE + PPU_VGA_H_SYNC then TMP_NHSYNC := '0'; end if; + end if; + end process; + + -- tiny VCOUNT and HCOUNT + process(TPIXCLK, RESET) + variable TMP_THCOUNT, TMP_TVCOUNT: unsigned(PPU_VGA_SIGNAL_PIXEL_WIDTH-1 downto 0) := (others => '0'); + begin + TVCOUNT <= TMP_TVCOUNT; + THCOUNT <= TMP_THCOUNT; + if RESET = '1' then + TMP_THCOUNT := (others => '0'); + TMP_TVCOUNT := (others => '0'); + elsif rising_edge(TPIXCLK) then + TMP_THCOUNT := TMP_THCOUNT + 1; + if TMP_THCOUNT >= PPU_VGA_H_TOTAL then + TMP_THCOUNT := (others => '0'); + + TMP_TVCOUNT := TMP_TVCOUNT + 1; + if TMP_TVCOUNT >= PPU_VGA_V_TOTAL then + TMP_TVCOUNT := (others => '0'); + end if; + end if; + end if; + end process; + + -- T_POS_X <= resize(THCOUNT - (PPU_VGA_H_PORCH_BACK / 4), T_POS_X'length) when N_POS_Y(0) = to_unsigned(PPU_VGA_V_PORCH_BACK, 1)(0) else + -- resize(THCOUNT - ((PPU_VGA_H_PORCH_BACK + PPU_VGA_H_BLANK) / 4), T_POS_X'length); -- divide tiny x equally over two native scanlines + -- T_POS_Y <= resize(TVCOUNT - (PPU_VGA_V_PORCH_BACK / 2), T_POS_Y'length); + + -- 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); + + -- TMP_X <= std_logic_vector(T_POS_X) when NACTIVE = '1' else (others => '0'); + -- TMP_Y <= std_logic_vector(T_POS_Y) when NACTIVE = '1' else (others => '0'); + + U_POS_X <= resize(N_POS_X(N_POS_X'length-1 downto 1), U_POS_X'length); + U_POS_Y <= resize(N_POS_Y(N_POS_Y'length-1 downto 1), U_POS_Y'length); + -- U_POS_X <= resize(N_POS_X / 2, U_POS_X'length); + -- U_POS_Y <= resize(N_POS_Y / 2, U_POS_Y'length); ADDR_O <= std_logic_vector(resize(U_POS_X, ADDR_I'length)) when U_POS_Y(0) = '0' else std_logic_vector(resize(U_POS_X, ADDR_I'length) + PPU_SCREEN_WIDTH); - RO <= DATA_O(11 downto 8) when NACTIVE = '1' else (others => '0'); - GO <= DATA_O(7 downto 4) when NACTIVE = '1' else (others => '0'); - BO <= DATA_O(3 downto 0) when NACTIVE = '1' else (others => '0'); + TMP_RO <= DATA_O(11 downto 8) when NACTIVE = '1' else (others => '0'); + TMP_GO <= DATA_O(7 downto 4) when NACTIVE = '1' else (others => '0'); + TMP_BO <= DATA_O(3 downto 0) when NACTIVE = '1' else (others => '0'); scanline_buffer : component ppu_dispctl_slbuf port map( - clka => CLK, + clka => SYSCLK, wea => (others => PREADY), addra => ADDR_I, dina => DATA_I, - clkb => CLK, + clkb => SYSCLK, rstb => RESET, 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; + pixel_clock: component ppu_dispctl_pixclk port map( + clk_in1 => SYSCLK, + reset => RESET, + clk_out1 => NPIXCLK, + clk_out2 => TPIXCLK); - process(CLK25(1), RESET) + process(NPIXCLK, RESET) begin if RESET = '1' then - PCOUNT <= (others => '0'); - elsif rising_edge(CLK25(1)) then - if PCOUNT + 1 >= PPU_VGA_SIGNAL_PIXEL_IDX_MAX then - PCOUNT <= (others => '0'); - else - PCOUNT <= PCOUNT + 1; - end if; + X <= (others => '0'); + Y <= (others => '0'); + RO <= (others => '0'); + GO <= (others => '0'); + BO <= (others => '0'); + THBLANK <= '0'; + TVBLANK <= '0'; + elsif rising_edge(NPIXCLK) then + X <= TMP_X; + Y <= TMP_Y; + RO <= TMP_RO; + GO <= TMP_GO; + BO <= TMP_BO; + THBLANK <= TMP_THBLANK; + TVBLANK <= TMP_TVBLANK; end if; end process; end Behavioral; |