mirror of
https://github.com/MiSTer-devel/PSX_MiSTer.git
synced 2026-04-19 03:04:52 +00:00
- GPU: restructure most GPU modules to complete VRAM request even when core is paused - GPU: don't reread fetched vram data after unpausing - Digital pad can now use left Analog Stick as virtual DPad - SNAC input pins clocked in twice to prevent metastability
391 lines
16 KiB
VHDL
391 lines
16 KiB
VHDL
library IEEE;
|
|
use IEEE.std_logic_1164.all;
|
|
use IEEE.numeric_std.all;
|
|
|
|
library mem;
|
|
|
|
entity gpu_rect is
|
|
port
|
|
(
|
|
clk2x : in std_logic;
|
|
clk2xIndex : in std_logic;
|
|
ce : in std_logic;
|
|
reset : in std_logic;
|
|
|
|
REPRODUCIBLEGPUTIMING: in std_logic;
|
|
|
|
error : out std_logic;
|
|
|
|
DrawPixelsMask : in std_logic;
|
|
interlacedDrawing : in std_logic;
|
|
activeLineLSB : in std_logic;
|
|
drawingOffsetX : in signed(10 downto 0);
|
|
drawingOffsetY : in signed(10 downto 0);
|
|
drawingAreaLeft : in unsigned(9 downto 0);
|
|
drawingAreaRight : in unsigned(9 downto 0);
|
|
drawingAreaTop : in unsigned(8 downto 0);
|
|
drawingAreaBottom : in unsigned(8 downto 0);
|
|
|
|
fifoOut_idle : in std_logic;
|
|
pipeline_busy : in std_logic;
|
|
pipeline_stall : in std_logic;
|
|
pipeline_new : out std_logic := '0';
|
|
pipeline_texture : out std_logic := '0';
|
|
pipeline_transparent : out std_logic := '0';
|
|
pipeline_rawTexture : out std_logic := '0';
|
|
pipeline_x : out unsigned(9 downto 0) := (others => '0');
|
|
pipeline_y : out unsigned(8 downto 0) := (others => '0');
|
|
pipeline_cr : out unsigned(7 downto 0) := (others => '0');
|
|
pipeline_cg : out unsigned(7 downto 0) := (others => '0');
|
|
pipeline_cb : out unsigned(7 downto 0) := (others => '0');
|
|
pipeline_u : out unsigned(7 downto 0) := (others => '0');
|
|
pipeline_v : out unsigned(7 downto 0) := (others => '0');
|
|
|
|
proc_idle : in std_logic;
|
|
fifo_Valid : in std_logic;
|
|
fifo_data : in std_logic_vector(31 downto 0);
|
|
requestFifo : out std_logic := '0';
|
|
done : out std_logic := '0';
|
|
CmdDone : out std_logic := '0';
|
|
|
|
requestVRAMEnable : out std_logic;
|
|
requestVRAMXPos : out unsigned(9 downto 0);
|
|
requestVRAMYPos : out unsigned(8 downto 0);
|
|
requestVRAMSize : out unsigned(10 downto 0);
|
|
requestVRAMIdle : in std_logic;
|
|
requestVRAMDone : in std_logic;
|
|
|
|
textPalNew : out std_logic := '0';
|
|
textPalX : out unsigned(9 downto 0) := (others => '0');
|
|
textPalY : out unsigned(8 downto 0) := (others => '0');
|
|
|
|
vramLineEna : out std_logic;
|
|
vramLineAddr : out unsigned(9 downto 0)
|
|
);
|
|
end entity;
|
|
|
|
architecture arch of gpu_rect is
|
|
|
|
type tState is
|
|
(
|
|
IDLE,
|
|
REQUESTPOS,
|
|
REQUESTTEXTURE,
|
|
REQUESTSIZE,
|
|
CHECKPOS,
|
|
REQUESTFIRST,
|
|
REQUESTLINE,
|
|
READWAIT,
|
|
PROCPIXELS,
|
|
WAITIMING
|
|
);
|
|
signal state : tState := IDLE;
|
|
|
|
signal drawTiming : unsigned(31 downto 0);
|
|
signal targetTiming : unsigned(31 downto 0);
|
|
|
|
signal rec_texture : std_logic := '0';
|
|
signal rec_size : std_logic_vector(1 downto 0) := "00";
|
|
signal rec_transparency : std_logic := '0';
|
|
signal rec_rawTexture : std_logic := '0';
|
|
|
|
signal rec_color : std_logic_vector(23 downto 0) := (others => '0');
|
|
|
|
signal rec_posx : signed(11 downto 0) := (others => '0');
|
|
signal rec_sizex : unsigned(9 downto 0) := (others => '0');
|
|
signal rec_sizey : unsigned(8 downto 0) := (others => '0');
|
|
|
|
signal rec_u : unsigned(7 downto 0) := (others => '0');
|
|
|
|
signal xPos : signed(11 downto 0) := (others => '0');
|
|
signal yPos : signed(11 downto 0) := (others => '0');
|
|
signal xCnt : unsigned(9 downto 0) := (others => '0');
|
|
signal yCnt : unsigned(8 downto 0) := (others => '0');
|
|
signal uWork : unsigned(7 downto 0) := (others => '0');
|
|
signal vWork : unsigned(7 downto 0) := (others => '0');
|
|
|
|
signal firstPixel : std_logic;
|
|
|
|
signal timeout : integer range 0 to 1048575 := 0;
|
|
|
|
begin
|
|
|
|
requestFifo <= '1' when (state = REQUESTPOS or state = REQUESTTEXTURE or state = REQUESTSIZE) else '0';
|
|
|
|
requestVRAMEnable <= '1' when (state = REQUESTLINE and requestVRAMIdle = '1' and pipeline_stall = '0') else '0';
|
|
requestVRAMXPos <= unsigned(xPos(9 downto 0)) when (state = REQUESTLINE and requestVRAMIdle = '1' and pipeline_stall = '0') else (others => '0');
|
|
requestVRAMYPos <= unsigned(yPos(8 downto 0)) when (state = REQUESTLINE and requestVRAMIdle = '1' and pipeline_stall = '0') else (others => '0');
|
|
requestVRAMSize <= '0' & rec_sizex when (state = REQUESTLINE and requestVRAMIdle = '1' and pipeline_stall = '0') else (others => '0');
|
|
|
|
vramLineEna <= '1' when (state = PROCPIXELS) else '0';
|
|
vramLineAddr <= unsigned(xPos(9 downto 0)) when (state = PROCPIXELS) else (others => '0');
|
|
|
|
process (clk2x)
|
|
variable xrec12 : signed(11 downto 0);
|
|
variable yrec12 : signed(11 downto 0);
|
|
variable xsize : signed(11 downto 0);
|
|
variable ysize : signed(11 downto 0);
|
|
variable xdiff : signed(11 downto 0);
|
|
variable ydiff : signed(11 downto 0);
|
|
variable ynew : signed(11 downto 0);
|
|
variable yAdd : integer range 1 to 2;
|
|
begin
|
|
if rising_edge(clk2x) then
|
|
|
|
-- must be done here, so it also is effected when ce is off = paused
|
|
if (state = READWAIT) then
|
|
if (requestVRAMDone = '1') then
|
|
state <= PROCPIXELS;
|
|
end if;
|
|
end if;
|
|
|
|
if (reset = '1') then
|
|
|
|
state <= IDLE;
|
|
|
|
elsif (ce = '1') then
|
|
|
|
done <= '0';
|
|
CmdDone <= '0';
|
|
|
|
pipeline_new <= '0';
|
|
pipeline_texture <= '0';
|
|
pipeline_transparent <= '0';
|
|
pipeline_rawTexture <= '0';
|
|
pipeline_x <= (others => '0');
|
|
pipeline_y <= (others => '0');
|
|
pipeline_cr <= (others => '0');
|
|
pipeline_cg <= (others => '0');
|
|
pipeline_cb <= (others => '0');
|
|
pipeline_u <= (others => '0');
|
|
pipeline_v <= (others => '0');
|
|
|
|
textPalNew <= '0';
|
|
textPalX <= (others => '0');
|
|
textPalY <= (others => '0');
|
|
|
|
if (state /= IDLE) then
|
|
drawTiming <= drawTiming + 1;
|
|
end if;
|
|
|
|
error <= '0';
|
|
if (state = IDLE) then
|
|
timeout <= 0;
|
|
elsif (timeout < 1048575) then
|
|
timeout <= timeout + 1;
|
|
else
|
|
error <= '1';
|
|
state <= IDLE;
|
|
done <= '1';
|
|
end if;
|
|
|
|
case (state) is
|
|
|
|
when IDLE =>
|
|
drawTiming <= (others => '0');
|
|
firstPixel <= '1';
|
|
if (proc_idle = '1' and fifo_Valid = '1' and fifo_data(31 downto 29) = "011") then
|
|
state <= REQUESTPOS;
|
|
rec_texture <= fifo_data(26);
|
|
rec_size <= fifo_data(28 downto 27);
|
|
rec_transparency <= fifo_data(25);
|
|
rec_rawTexture <= fifo_data(24);
|
|
rec_color <= fifo_data(23 downto 0);
|
|
end if;
|
|
|
|
when REQUESTPOS =>
|
|
xCnt <= (others => '0');
|
|
yCnt <= (others => '0');
|
|
case (rec_size) is
|
|
when "01" =>
|
|
rec_sizex <= to_unsigned(1, 10);
|
|
rec_sizey <= to_unsigned(1, 9);
|
|
|
|
when "10" =>
|
|
rec_sizex <= to_unsigned(8, 10);
|
|
rec_sizey <= to_unsigned(8, 9);
|
|
|
|
when "11" =>
|
|
rec_sizex <= to_unsigned(16, 10);
|
|
rec_sizey <= to_unsigned(16, 9);
|
|
|
|
when others => null;
|
|
end case;
|
|
|
|
if (fifo_Valid = '1') then
|
|
xrec12 := resize(drawingOffsetX, 12) + signed('0' & fifo_data(10 downto 0));
|
|
yrec12 := resize(drawingOffsetY, 12) + signed('0' & fifo_data(26 downto 16));
|
|
rec_posx <= resize(xrec12(10 downto 0), 12);
|
|
yPos <= resize(yrec12(10 downto 0), 12);
|
|
|
|
if (rec_texture = '1') then
|
|
state <= REQUESTTEXTURE;
|
|
elsif (rec_size = "00") then
|
|
state <= REQUESTSIZE;
|
|
else
|
|
state <= CHECKPOS;
|
|
CmdDone <= '1';
|
|
end if;
|
|
end if;
|
|
|
|
when REQUESTTEXTURE =>
|
|
if (fifo_Valid = '1') then
|
|
uWork <= unsigned(fifo_data( 7 downto 0));
|
|
vWork <= unsigned(fifo_data(15 downto 8));
|
|
rec_u <= unsigned(fifo_data( 7 downto 0));
|
|
textPalX <= unsigned(fifo_data(21 downto 16)) & "0000";
|
|
textPalY <= unsigned(fifo_data(30 downto 22));
|
|
textPalNew <= '1';
|
|
if (rec_size = "00") then
|
|
state <= REQUESTSIZE;
|
|
else
|
|
state <= CHECKPOS;
|
|
CmdDone <= '1';
|
|
end if;
|
|
end if;
|
|
|
|
when REQUESTSIZE =>
|
|
if (fifo_Valid = '1') then
|
|
rec_sizex <= unsigned(fifo_data(9 downto 0));
|
|
rec_sizey <= unsigned(fifo_data(24 downto 16));
|
|
state <= CHECKPOS;
|
|
CmdDone <= '1';
|
|
end if;
|
|
|
|
when CHECKPOS =>
|
|
if (rec_transparency = '1' or rec_texture = '1') then
|
|
targetTiming <= to_unsigned(50 + to_integer(rec_sizex * rec_sizey * to_unsigned(4, 4)), 32);
|
|
else
|
|
targetTiming <= to_unsigned(50 + to_integer(rec_sizex * rec_sizey * to_unsigned(2, 4)), 32);
|
|
end if;
|
|
|
|
xsize := to_signed(to_integer(rec_sizex), 12);
|
|
xdiff := (others => '0');
|
|
if (rec_posx < to_integer(drawingAreaLeft)) then
|
|
xdiff := to_signed(to_integer(drawingAreaLeft), 12) - rec_posx;
|
|
xsize := xsize - xdiff;
|
|
end if;
|
|
rec_posx <= rec_posx + xdiff;
|
|
xPos <= rec_posx + xdiff;
|
|
uWork <= uWork + unsigned(xdiff(7 downto 0));
|
|
rec_u <= rec_u + unsigned(xdiff(7 downto 0));
|
|
rec_sizex <= unsigned(xsize(9 downto 0));
|
|
|
|
ysize := to_signed(to_integer(rec_sizey), 12);
|
|
ydiff := (others => '0');
|
|
if (to_integer(yPos) < to_integer(drawingAreaTop)) then
|
|
ydiff := to_signed(to_integer(drawingAreaTop), 12) - yPos;
|
|
ysize := ysize - ydiff;
|
|
end if;
|
|
ynew := yPos + ydiff;
|
|
if (interlacedDrawing = '1' and (activeLineLSB = ynew(0))) then
|
|
ydiff := ydiff + 1;
|
|
ysize := ysize - 1;
|
|
end if;
|
|
yPos <= yPos + ydiff;
|
|
vWork <= vWork + unsigned(ydiff(7 downto 0));
|
|
rec_sizey <= unsigned(ysize(8 downto 0));
|
|
|
|
if (xsize < 1 or ysize < 1 or rec_posx > to_integer(drawingAreaRight) or yPos > to_integer(drawingAreaBottom)) then
|
|
if (REPRODUCIBLEGPUTIMING = '1') then
|
|
state <= WAITIMING;
|
|
else
|
|
state <= IDLE;
|
|
done <= '1';
|
|
end if;
|
|
elsif (rec_transparency = '1' or DrawPixelsMask = '1') then
|
|
state <= REQUESTFIRST;
|
|
else
|
|
state <= PROCPIXELS;
|
|
end if;
|
|
|
|
when REQUESTFIRST =>
|
|
if (pipeline_busy = '0' and fifoOut_idle = '1') then
|
|
state <= REQUESTLINE;
|
|
end if;
|
|
|
|
when REQUESTLINE =>
|
|
if (pipeline_stall = '0' and requestVRAMIdle = '1') then
|
|
state <= READWAIT;
|
|
end if;
|
|
|
|
when READWAIT => null; -- handled outside due to ce
|
|
|
|
when PROCPIXELS =>
|
|
if (pipeline_stall = '0' and (firstPixel = '0' or pipeline_busy = '0')) then
|
|
firstPixel <= '0';
|
|
|
|
xCnt <= xCnt + 1;
|
|
xPos <= xPos + 1;
|
|
uWork <= uWork + 1;
|
|
|
|
if (xCnt + 1 >= rec_sizex or xPos + 1 > to_integer(drawingAreaRight)) then
|
|
yAdd := 1;
|
|
if (interlacedDrawing = '1') then
|
|
yAdd := 2;
|
|
end if;
|
|
yCnt <= yCnt + yAdd;
|
|
ypos <= yPos + yAdd;
|
|
vWork <= vWork + yAdd;
|
|
if (yCnt + yAdd >= rec_sizey or ypos + yAdd > to_integer(drawingAreaBottom)) then
|
|
if (REPRODUCIBLEGPUTIMING = '1') then
|
|
state <= WAITIMING;
|
|
else
|
|
state <= IDLE;
|
|
done <= '1';
|
|
end if;
|
|
else
|
|
xPos <= rec_posx;
|
|
xCnt <= (others => '0');
|
|
uWork <= rec_u;
|
|
if (rec_transparency = '1' or DrawPixelsMask = '1') then
|
|
state <= REQUESTLINE;
|
|
end if;
|
|
end if;
|
|
end if;
|
|
|
|
if (xPos >= to_integer(drawingAreaLeft) and xPos <= to_integer(drawingAreaRight) and ypos >= to_integer(drawingAreaTop) and ypos <= to_integer(drawingAreaBottom)) then
|
|
pipeline_new <= '1';
|
|
pipeline_texture <= rec_texture;
|
|
pipeline_transparent <= rec_transparency;
|
|
pipeline_rawTexture <= rec_rawTexture;
|
|
pipeline_x <= unsigned(xPos(9 downto 0));
|
|
pipeline_y <= unsigned(yPos(8 downto 0));
|
|
pipeline_cr <= unsigned(rec_color( 7 downto 0));
|
|
pipeline_cg <= unsigned(rec_color(15 downto 8));
|
|
pipeline_cb <= unsigned(rec_color(23 downto 16));
|
|
pipeline_u <= uWork;
|
|
pipeline_v <= vWork;
|
|
end if;
|
|
end if;
|
|
|
|
if (drawingAreaLeft > drawingAreaRight or drawingAreaTop > drawingAreaBottom) then
|
|
if (REPRODUCIBLEGPUTIMING = '1') then
|
|
state <= WAITIMING;
|
|
else
|
|
state <= IDLE;
|
|
done <= '1';
|
|
end if;
|
|
end if;
|
|
|
|
when WAITIMING =>
|
|
if (clk2xIndex = '0' and drawTiming + 4 >= targetTiming) then
|
|
state <= IDLE;
|
|
done <= '1';
|
|
end if;
|
|
|
|
end case;
|
|
|
|
end if;
|
|
|
|
end if;
|
|
end process;
|
|
|
|
|
|
end architecture;
|
|
|
|
|
|
|
|
|
|
|