Files
PSX_MiSTer/rtl/gpu_poly.vhd
Robert Peip 378a400b1f - add filter strength option
- fix BIOS region select (broke with 2/8MB RAM selection)
2022-10-14 17:16:22 +02:00

1162 lines
53 KiB
VHDL

library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.numeric_std.all;
library mem;
use work.pGPU.all;
entity gpu_poly is
port
(
clk2x : in std_logic;
clk2xIndex : in std_logic;
ce : in std_logic;
reset : in std_logic;
REPRODUCIBLEGPUTIMING: in std_logic;
textureFilter : in std_logic_vector(1 downto 0);
textureFilterStrength: in std_logic_vector(1 downto 0);
textureFilter2DOff : 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);
drawModeRec : out unsigned(11 downto 0);
drawModeNew : out std_logic := '0';
drawmode_dithering : in std_logic := '0';
div1 : inout div_type;
div2 : inout div_type;
div3 : inout div_type;
div4 : inout div_type;
div5 : inout div_type;
div6 : inout div_type;
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_dithering : 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');
pipeline_filter : out std_logic := '0';
pipeline_u11 : out unsigned(7 downto 0) := (others => '0');
pipeline_v11 : out unsigned(7 downto 0) := (others => '0');
pipeline_uAcc : out unsigned(7 downto 0) := (others => '0');
pipeline_vAcc : 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_poly is
type tState is
(
IDLE,
REQUESTCOLOR,
REQUESTPOS,
REQUESTTEXTURE,
ISSUE,
SORTVERTICES,
CALCBOUNDARY1,
CALCBOUNDARY2,
CALCCOLOR1,
CALCCOLOR2,
CALCCOLOR3,
CALCCOLOR4,
CALCTEXTURE1,
CALCTEXTURE2,
CALCTEXTURE3,
CALCTEXTURE4,
PREPAREHALF,
PREPAREDECMODE,
PREPARELINE,
REQUESTFIRST,
REQUESTLINE,
READWAIT,
PROCPIXELS,
WAITIMING
);
signal state : tState := IDLE;
signal mulStep : integer range 0 to 7;
signal drawTiming : unsigned(31 downto 0);
signal targetTiming : unsigned(31 downto 0);
signal rec_shading : std_logic := '0';
signal rec_quad : std_logic := '0';
signal rec_texture : std_logic := '0';
signal rec_transparency : std_logic := '0';
signal rec_rawTexture : std_logic := '0';
signal rec_dithering : std_logic := '0';
type tVertex is record
x : integer range -2048 to 2047;
y : integer range -2048 to 2047;
r : unsigned(7 downto 0);
g : unsigned(7 downto 0);
b : unsigned(7 downto 0);
u : unsigned(7 downto 0);
v : unsigned(7 downto 0);
end record;
type tRecVertexArray is array(0 to 3) of tVertex;
signal rec_vertices : tRecVertexArray := (others => (0, 0, (others => '0') , (others => '0') , (others => '0') , (others => '0') , (others => '0')));
signal rec_index : integer range 0 to 3;
signal rec_textPalX : unsigned(9 downto 0) := (others => '0');
signal rec_textPalY : unsigned(8 downto 0) := (others => '0');
signal quadFirst : std_logic := '0';
signal nextQuad : std_logic := '0';
type tworkVertexArray is array(0 to 2) of tVertex;
signal vt : tworkVertexArray;
signal coreVertex : integer range 0 to 2;
signal vo : integer range 0 to 1;
signal vp : integer range 0 to 1;
signal denom : integer range -16777216 to 16777215;
signal rightFacing : integer range 0 to 1;
signal baseCoord : signed(44 downto 0) := (others => '0');
signal baseStep : signed(44 downto 0) := (others => '0');
signal boundCoordUs : signed(44 downto 0) := (others => '0');
signal boundCoordLs : signed(44 downto 0) := (others => '0');
signal firsthalf : std_logic := '0';
signal secondhalf : std_logic := '0';
signal diffX10 : signed(12 downto 0);
signal diffX21 : signed(12 downto 0);
signal diffY10 : signed(12 downto 0);
signal diffY21 : signed(12 downto 0);
signal diffR10 : signed(8 downto 0);
signal diffR21 : signed(8 downto 0);
signal diffG10 : signed(8 downto 0);
signal diffG21 : signed(8 downto 0);
signal diffB10 : signed(8 downto 0);
signal diffB21 : signed(8 downto 0);
signal diffU10 : signed(8 downto 0);
signal diffU21 : signed(8 downto 0);
signal diffV10 : signed(8 downto 0);
signal diffV21 : signed(8 downto 0);
signal dxR : unsigned(31 downto 0) := (others => '0');
signal dyR : unsigned(31 downto 0) := (others => '0');
signal dxG : unsigned(31 downto 0) := (others => '0');
signal dyG : unsigned(31 downto 0) := (others => '0');
signal dxB : unsigned(31 downto 0) := (others => '0');
signal dyB : unsigned(31 downto 0) := (others => '0');
signal dxU : unsigned(31 downto 0) := (others => '0');
signal dyU : unsigned(31 downto 0) := (others => '0');
signal dxV : unsigned(31 downto 0) := (others => '0');
signal dyV : unsigned(31 downto 0) := (others => '0');
signal base_R : unsigned(31 downto 0) := (others => '0');
signal base_G : unsigned(31 downto 0) := (others => '0');
signal base_B : unsigned(31 downto 0) := (others => '0');
signal base_U : unsigned(31 downto 0) := (others => '0');
signal base_V : unsigned(31 downto 0) := (others => '0');
signal muldiv1In1 : signed(8 downto 0);
signal muldiv1In2 : signed(12 downto 0);
signal muldivResult1 : signed(21 downto 0) := (others => '0');
signal muldivResult1clk : signed(21 downto 0) := (others => '0');
signal muldiv2In1 : signed(8 downto 0);
signal muldiv2In2 : signed(12 downto 0);
signal muldivResult2 : signed(21 downto 0) := (others => '0');
signal muldivResult2clk : signed(21 downto 0) := (others => '0');
signal mulIn1 : unsigned(31 downto 0);
signal mulIn2 : unsigned(31 downto 0);
signal mulResult32 : unsigned(31 downto 0) := (others => '0');
signal mulResult32clk : unsigned(31 downto 0) := (others => '0');
signal work_R : unsigned(31 downto 0) := (others => '0');
signal work_G : unsigned(31 downto 0) := (others => '0');
signal work_B : unsigned(31 downto 0) := (others => '0');
signal work_U : unsigned(31 downto 0) := (others => '0');
signal work_V : unsigned(31 downto 0) := (others => '0');
signal vo_diff : integer range -4096 to 4095;
signal vp_diff : integer range -4096 to 4095;
signal vo_diff_base : signed(44 downto 0) := (others => '0');
signal vp_diff_base : signed(44 downto 0) := (others => '0');
signal yCoord : integer range -2048 to 2047;
signal yBound : integer range -2048 to 2047;
signal xStart : signed(44 downto 0) := (others => '0');
signal xStepStart : signed(44 downto 0) := (others => '0');
signal xEnd : signed(44 downto 0) := (others => '0');
signal xStepEnd : signed(44 downto 0) := (others => '0');
signal decMode : integer range 0 to 1;
signal xPos : signed(11 downto 0) := (others => '0');
signal yPos : signed(10 downto 0) := (others => '0');
signal xStop : signed(11 downto 0) := (others => '0');
signal xSize : unsigned(10 downto 0) := (others => '0');
signal firstPixel : std_logic;
signal filterStrength : integer range 0 to 4;
signal filter_on : std_logic;
signal filter_maxU : unsigned(7 downto 0);
signal filter_maxV : unsigned(7 downto 0);
signal timeout : integer range 0 to 1048575 := 0;
begin
requestFifo <= '1' when (state = REQUESTCOLOR or state = REQUESTPOS or state = REQUESTTEXTURE) 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 <= xSize 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');
imul9s1 : entity work.mul9s
port map
(
mul1 => muldiv1In1,
mul2 => muldiv1In2,
result => muldivResult1
);
imul9s2 : entity work.mul9s
port map
(
mul1 => muldiv2In1,
mul2 => muldiv2In2,
result => muldivResult2
);
muldiv1In1 <= diffU10 when (state = CALCTEXTURE2 and mulStep = 0) else
diffU21 when (state = CALCTEXTURE2 and mulStep = 1) else
diffV10 when (state = CALCTEXTURE2 and mulStep = 2) else
diffV21 when (state = CALCTEXTURE2 and mulStep = 3) else
diffR10 when (mulStep = 0) else
diffR21 when (mulStep = 1) else
diffG10 when (mulStep = 2) else
diffG21 when (mulStep = 3) else
diffB10 when (mulStep = 4) else
diffB21;
muldiv1In2 <= diffY21 when (state = CALCTEXTURE2 and mulStep = 0) else
diffX10 when (state = CALCTEXTURE2 and mulStep = 1) else
diffY21 when (state = CALCTEXTURE2 and mulStep = 2) else
diffX10 when (state = CALCTEXTURE2 and mulStep = 3) else
diffY21 when (mulStep = 0) else
diffX10 when (mulStep = 1) else
diffY21 when (mulStep = 2) else
diffX10 when (mulStep = 3) else
diffY21 when (mulStep = 4) else
diffX10;
muldiv2In1 <= diffU21 when (state = CALCTEXTURE2 and mulStep = 0) else
diffU10 when (state = CALCTEXTURE2 and mulStep = 1) else
diffV21 when (state = CALCTEXTURE2 and mulStep = 2) else
diffV10 when (state = CALCTEXTURE2 and mulStep = 3) else
diffR21 when (mulStep = 0) else
diffR10 when (mulStep = 1) else
diffG21 when (mulStep = 2) else
diffG10 when (mulStep = 3) else
diffB21 when (mulStep = 4) else
diffB10;
muldiv2In2 <= diffY10 when (state = CALCTEXTURE2 and mulStep = 0) else
diffX21 when (state = CALCTEXTURE2 and mulStep = 1) else
diffY10 when (state = CALCTEXTURE2 and mulStep = 2) else
diffX21 when (state = CALCTEXTURE2 and mulStep = 3) else
diffY10 when (mulStep = 0) else
diffX21 when (mulStep = 1) else
diffY10 when (mulStep = 2) else
diffX21 when (mulStep = 3) else
diffY10 when (mulStep = 4) else
diffX21;
imul32u : entity work.mul32u
port map
(
mul1 => mulIn1,
mul2 => mulIn2,
result => mulResult32
);
mulIn1 <= dxU when (state = CALCTEXTURE4 and mulStep = 0) else
dxV when (state = CALCTEXTURE4 and mulStep = 1) else
dyU when (state = CALCTEXTURE4 and mulStep = 2) else
dyV when (state = CALCTEXTURE4 and mulStep = 3) else
dxR when (mulStep = 0) else
dxG when (mulStep = 1) else
dxB when (mulStep = 2) else
dyR when (mulStep = 3) else
dyG when (mulStep = 4) else
dyB;
mulIn2 <= unsigned(to_signed(-vt(coreVertex).x, 32)) when (state = CALCTEXTURE4 and mulStep = 0) else
unsigned(to_signed(-vt(coreVertex).x, 32)) when (state = CALCTEXTURE4 and mulStep = 1) else
unsigned(to_signed(-vt(coreVertex).y, 32)) when (state = CALCTEXTURE4 and mulStep = 2) else
unsigned(to_signed(-vt(coreVertex).y, 32)) when (state = CALCTEXTURE4 and mulStep = 3) else
unsigned(to_signed(-vt(coreVertex).x, 32)) when (mulStep = 0) else
unsigned(to_signed(-vt(coreVertex).x, 32)) when (mulStep = 1) else
unsigned(to_signed(-vt(coreVertex).x, 32)) when (mulStep = 2) else
unsigned(to_signed(-vt(coreVertex).y, 32)) when (mulStep = 3) else
unsigned(to_signed(-vt(coreVertex).y, 32)) when (mulStep = 4) else
unsigned(to_signed(-vt(coreVertex).y, 32));
process (clk2x)
variable xrec12 : signed(11 downto 0);
variable yrec12 : signed(11 downto 0);
variable cull : std_logic;
variable xMax : integer;
variable dx1 : signed(44 downto 0);
variable dx2 : signed(44 downto 0);
variable dx3 : signed(44 downto 0);
variable dy1 : signed(12 downto 0);
variable dy2 : signed(12 downto 0);
variable dy3 : signed(12 downto 0);
variable calc1 : signed(44 downto 0);
variable calc2 : signed(44 downto 0);
variable calc3 : signed(44 downto 0);
variable calc4 : signed(44 downto 0);
variable stop : std_logic;
variable skip : std_logic;
variable uFilter : unsigned(10 downto 0);
variable vFilter : unsigned(10 downto 0);
begin
if rising_edge(clk2x) then
filterStrength <= to_integer(unsigned(textureFilterStrength)) + 1;
-- 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';
drawModeNew <= '0';
textPalNew <= '0';
textPalX <= (others => '0');
textPalY <= (others => '0');
pipeline_new <= '0';
pipeline_texture <= '0';
pipeline_transparent <= '0';
pipeline_rawTexture <= '0';
pipeline_dithering <= '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');
pipeline_filter <= '0';
pipeline_u11 <= (others => '0');
pipeline_v11 <= (others => '0');
pipeline_uAcc <= (others => '0');
pipeline_vAcc <= (others => '0');
div1.start <= '0';
div2.start <= '0';
div3.start <= '0';
div4.start <= '0';
div5.start <= '0';
div6.start <= '0';
if (state /= CALCCOLOR2 and state /= CALCTEXTURE2) then
div1.dividend <= (others => '0');
div2.dividend <= (others => '0');
div3.dividend <= (others => '0');
div4.dividend <= (others => '0');
div5.dividend <= (others => '0');
div6.dividend <= (others => '0');
end if;
div1.divisor <= (others => '0');
div2.divisor <= (others => '0');
div3.divisor <= (others => '0');
div4.divisor <= (others => '0');
div5.divisor <= (others => '0');
div6.divisor <= (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');
targetTiming <= to_unsigned(500, 32);
firstPixel <= '1';
filter_maxU <= x"00";
filter_maxV <= x"00";
if (proc_idle = '1' and fifo_Valid = '1' and fifo_data(31 downto 29) = "001") then
state <= REQUESTPOS;
rec_index <= 0;
rec_shading <= fifo_data(28);
rec_quad <= fifo_data(27);
quadFirst <= fifo_data(27);
rec_texture <= fifo_data(26);
rec_transparency <= fifo_data(25);
rec_rawTexture <= fifo_data(24);
rec_dithering <= fifo_data(28) or (fifo_data(26) and (not fifo_data(24)));
for i in 0 to 3 loop
rec_vertices(i).r <= unsigned(fifo_data( 7 downto 0));
rec_vertices(i).g <= unsigned(fifo_data(15 downto 8));
rec_vertices(i).b <= unsigned(fifo_data(23 downto 16));
end loop;
end if;
when REQUESTCOLOR =>
drawTiming <= (others => '0');
if (fifo_Valid = '1') then
state <= REQUESTPOS;
rec_vertices(rec_index).r <= unsigned(fifo_data( 7 downto 0));
rec_vertices(rec_index).g <= unsigned(fifo_data(15 downto 8));
rec_vertices(rec_index).b <= unsigned(fifo_data(23 downto 16));
end if;
when REQUESTPOS =>
drawTiming <= (others => '0');
if (fifo_Valid = '1') then
if (drawingOffsetX < 0) then
xrec12 := resize(drawingOffsetX, 12) + signed('0' & fifo_data(10 downto 0));
rec_vertices(rec_index).x <= to_integer(xrec12(10 downto 0));
else
rec_vertices(rec_index).x <= to_integer(resize(signed(fifo_data(10 downto 0)),12) + resize(drawingOffsetX, 12));
end if;
if (drawingOffsetY < 0) then
yrec12 := resize(drawingOffsetY, 12) + signed('0' & fifo_data(26 downto 16));
rec_vertices(rec_index).y <= to_integer(yrec12(10 downto 0));
else
rec_vertices(rec_index).y <= to_integer(resize(signed(fifo_data(26 downto 16)),12) + resize(drawingOffsetY, 12));
end if;
if (rec_texture = '1') then
state <= REQUESTTEXTURE;
elsif ((rec_quad = '1' and rec_index = 3) or (rec_quad = '0' and rec_index = 2)) then
state <= ISSUE;
CmdDone <= '1';
else
rec_index <= rec_index +1;
if (rec_shading = '1') then
state <= REQUESTCOLOR;
else
state <= REQUESTPOS;
end if;
end if;
end if;
when REQUESTTEXTURE =>
drawTiming <= (others => '0');
if (fifo_Valid = '1') then
rec_vertices(rec_index).u <= unsigned(fifo_data( 7 downto 0));
rec_vertices(rec_index).v <= unsigned(fifo_data(15 downto 8));
if (rec_index = 0) then
rec_textPalX <= unsigned(fifo_data(21 downto 16)) & "0000";
rec_textPalY <= unsigned(fifo_data(30 downto 22));
end if;
if (rec_index = 1) then
drawModeRec <= unsigned(fifo_data(27 downto 16));
drawModeNew <= '1';
end if;
if (rec_index = 2) then
textPalX <= rec_textPalX;
textPalY <= rec_textPalY;
textPalNew <= '1';
end if;
if ((rec_quad = '1' and rec_index = 3) or (rec_quad = '0' and rec_index = 2)) then
state <= ISSUE;
CmdDone <= '1';
else
rec_index <= rec_index +1;
if (rec_shading = '1') then
state <= REQUESTCOLOR;
else
state <= REQUESTPOS;
end if;
end if;
end if;
when ISSUE =>
state <= SORTVERTICES;
nextQuad <= '0';
if (rec_quad = '0' or quadFirst = '1') then
vt(0) <= rec_vertices(0);
vt(1) <= rec_vertices(1);
vt(2) <= rec_vertices(2);
quadFirst <= '0';
if (rec_quad = '1') then
nextQuad <= '1';
end if;
else
vt(0) <= rec_vertices(2);
vt(1) <= rec_vertices(1);
vt(2) <= rec_vertices(3);
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 SORTVERTICES =>
state <= CALCBOUNDARY1;
firsthalf <= '1';
if (vt(0).y <= vt(2).y and vt(2).y <= vt(1).y) then -- 0 2 1
vt(0) <= vt(0);
vt(1) <= vt(2);
vt(2) <= vt(1);
elsif (vt(1).y <= vt(0).y and vt(0).y <= vt(2).y) then -- 1 0 2
vt(0) <= vt(1);
vt(1) <= vt(0);
vt(2) <= vt(2);
elsif (vt(1).y <= vt(2).y and vt(2).y <= vt(0).y) then -- 1 2 0
vt(0) <= vt(1);
vt(1) <= vt(2);
vt(2) <= vt(0);
elsif (vt(2).y <= vt(0).y and vt(0).y <= vt(1).y) then -- 2 0 1
vt(0) <= vt(2);
vt(1) <= vt(0);
vt(2) <= vt(1);
elsif (vt(2).y <= vt(1).y and vt(1).y <= vt(0).y) then -- 2 1 0
vt(0) <= vt(2);
vt(1) <= vt(1);
vt(2) <= vt(0);
end if; -- 0 1 2 requires no resorting
if (vt(0).u >= vt(1).u and vt(0).u >= vt(2).u) then
filter_maxU <= vt(0).u;
elsif (vt(1).u >= vt(0).u and vt(1).u >= vt(2).u) then
filter_maxU <= vt(1).u;
else
filter_maxU <= vt(2).u;
end if;
if (vt(0).v >= vt(1).v and vt(0).v >= vt(2).v) then
filter_maxV <= vt(0).v;
elsif (vt(1).v >= vt(0).v and vt(1).v >= vt(2).v) then
filter_maxV <= vt(1).v;
else
filter_maxV <= vt(2).v;
end if;
when CALCBOUNDARY1 =>
state <= CALCBOUNDARY2;
xMax := abs(vt(0).x - vt(1).x);
if (abs(vt(0).x - vt(2).x) > xMax) then xMax := abs(vt(0).x - vt(2).x); end if;
if (abs(vt(1).x - vt(2).x) > xMax) then xMax := abs(vt(1).x - vt(2).x); end if;
if (rec_transparency = '1' or rec_texture = '1') then
targetTiming <= targetTiming + (vt(2).y + 1 - vt(0).y) * xMax * 4;
else
targetTiming <= targetTiming + (vt(2).y + 1 - vt(0).y) * xMax * 2;
end if;
coreVertex <= 0;
vo <= 0;
vp <= 0;
if (vt(1).x <= vt(0).x) then
coreVertex <= 1;
vo <= 1;
if(vt(2).x <= vt(1).x) then
coreVertex <= 2;
vp <= 1;
end if;
elsif (vt(2).x < vt(0).x) then
coreVertex <= 2;
vo <= 1;
vp <= 1;
end if;
denom <= ((vt(1).x - vt(0).x) * (vt(2).y - vt(1).y)) - ((vt(2).x - vt(1).x) * (vt(1).y - vt(0).y));
baseCoord <= (to_signed(vt(0).x, 13) & x"00000000") + x"100000000" - 2048;
dy1 := (to_signed(vt(2).y, 13) - to_signed(vt(0).y, 13));
dx1 := (to_signed(vt(2).x, 13) - to_signed(vt(0).x, 13)) & x"00000000";
if (dx1 < 0) then dx1 := dx1 - (dy1 - 1);
elsif (dx1 > 0) then dx1 := dx1 + (dy1 - 1); end if;
div1.start <= '1';
div1.dividend <= dx1;
div1.divisor <= x"000" & dy1;
dy2 := (to_signed(vt(1).y, 13) - to_signed(vt(0).y, 13));
dx2 := (to_signed(vt(1).x, 13) - to_signed(vt(0).x, 13)) & x"00000000";
if (dx2 < 0) then dx2 := dx2 - (dy2 - 1);
elsif (dx2 > 0) then dx2 := dx2 + (dy2 - 1); end if;
div2.start <= '1';
div2.dividend <= dx2;
div2.divisor <= x"000" & dy2;
dy3 := (to_signed(vt(2).y, 13) - to_signed(vt(1).y, 13));
dx3 := (to_signed(vt(2).x, 13) - to_signed(vt(1).x, 13)) & x"00000000";
if (dx3 < 0) then dx3 := dx3 - (dy3 - 1);
elsif (dx3 > 0) then dx3 := dx3 + (dy3 - 1); end if;
div3.start <= '1';
div3.dividend <= dx3;
div3.divisor <= x"000" & dy3;
-- culling of large polygons
cull := '0';
if (vt(0).y = vt(2).y) then cull := '1'; end if;
if (abs(vt(2).x - vt(0).x) >= 16#400#) then cull := '1'; end if;
if (abs(vt(2).x - vt(1).x) >= 16#400#) then cull := '1'; end if;
if (abs(vt(1).x - vt(0).x) >= 16#400#) then cull := '1'; end if;
if (abs(vt(2).y - vt(0).y) >= 16#200#) then cull := '1'; end if;
if (cull = '1') then
div1.start <= '0';
div2.start <= '0';
div3.start <= '0';
if (nextQuad = '1') then
state <= ISSUE;
else
if (REPRODUCIBLEGPUTIMING = '1') then
state <= WAITIMING;
else
state <= IDLE;
done <= '1';
end if;
end if;
end if;
when CALCBOUNDARY2 =>
baseStep <= div1.quotient;
rightFacing <= 0;
if (vt(1).y = vt(0).y) then
boundCoordUs <= (others => '0');
if (vt(1).x > vt(0).x) then rightFacing <= 1; end if;
else
if (div2.quotient > div1.quotient) then rightFacing <= 1; end if;
boundCoordUs <= div2.quotient;
end if;
if (vt(2).y = vt(1).y) then
boundCoordLs <= (others => '0');
else
boundCoordLs <= div3.quotient;
end if;
vo_diff <= vt(vo).y - vt(0).y;
vp_diff <= vt(1 + vp).y - vt(0).y;
vo_diff_base <= resize(vo_diff * baseStep, 45);
vp_diff_base <= resize(vp_diff * baseStep, 45);
base_R <= x"000" & vt(coreVertex).r & x"800";
base_G <= x"000" & vt(coreVertex).g & x"800";
base_B <= x"000" & vt(coreVertex).b & x"800";
base_U <= x"000" & vt(coreVertex).u & x"800";
base_V <= x"000" & vt(coreVertex).v & x"800";
diffX10 <= to_signed(vt(1).x - vt(0).x, 13);
diffX21 <= to_signed(vt(2).x - vt(1).x, 13);
diffY10 <= to_signed(vt(1).y - vt(0).y, 13);
diffY21 <= to_signed(vt(2).y - vt(1).y, 13);
if (div1.done = '1') then
if (denom = 0) then
if (nextQuad = '1') then
state <= ISSUE;
else
if (REPRODUCIBLEGPUTIMING = '1') then
state <= WAITIMING;
else
state <= IDLE;
done <= '1';
end if;
end if;
elsif (rec_shading = '1') then
state <= CALCCOLOR1;
elsif (rec_texture = '1') then
state <= CALCTEXTURE1;
else
state <= PREPAREHALF;
end if;
end if;
when CALCCOLOR1 =>
mulStep <= 0;
state <= CALCCOLOR2;
diffR10 <= ('0' & signed(vt(1).r)) - ('0' & signed(vt(0).r));
diffR21 <= ('0' & signed(vt(2).r)) - ('0' & signed(vt(1).r));
diffG10 <= ('0' & signed(vt(1).g)) - ('0' & signed(vt(0).g));
diffG21 <= ('0' & signed(vt(2).g)) - ('0' & signed(vt(1).g));
diffB10 <= ('0' & signed(vt(1).b)) - ('0' & signed(vt(0).b));
diffB21 <= ('0' & signed(vt(2).b)) - ('0' & signed(vt(1).b));
when CALCCOLOR2 =>
mulStep <= mulStep + 1;
div1.divisor <= to_signed(denom, 25);
div2.divisor <= to_signed(denom, 25);
div3.divisor <= to_signed(denom, 25);
div4.divisor <= to_signed(denom, 25);
div5.divisor <= to_signed(denom, 25);
div6.divisor <= to_signed(denom, 25);
case (mulStep) is
when 0 => muldivResult1clk <= muldivResult1; muldivResult2clk <= muldivResult2;
when 1 => muldivResult1clk <= muldivResult1; muldivResult2clk <= muldivResult2; div1.dividend <= resize(muldivResult1clk - muldivResult2clk, 33) & x"000";
when 2 => muldivResult1clk <= muldivResult1; muldivResult2clk <= muldivResult2; div2.dividend <= resize(muldivResult1clk - muldivResult2clk, 33) & x"000";
when 3 => muldivResult1clk <= muldivResult1; muldivResult2clk <= muldivResult2; div3.dividend <= resize(muldivResult1clk - muldivResult2clk, 33) & x"000";
when 4 => muldivResult1clk <= muldivResult1; muldivResult2clk <= muldivResult2; div4.dividend <= resize(muldivResult1clk - muldivResult2clk, 33) & x"000";
when 5 => muldivResult1clk <= muldivResult1; muldivResult2clk <= muldivResult2; div5.dividend <= resize(muldivResult1clk - muldivResult2clk, 33) & x"000";
when 6 =>
div6.dividend <= resize(muldivResult1clk - muldivResult2clk, 33) & x"000";
state <= CALCCOLOR3;
div1.start <= '1';
div2.start <= '1';
div3.start <= '1';
div4.start <= '1';
div5.start <= '1';
div6.start <= '1';
when others => null;
end case;
when CALCCOLOR3 =>
dxR <= unsigned(div1.quotient(31 downto 0));
dyR <= unsigned(div2.quotient(31 downto 0));
dxG <= unsigned(div3.quotient(31 downto 0));
dyG <= unsigned(div4.quotient(31 downto 0));
dxB <= unsigned(div5.quotient(31 downto 0));
dyB <= unsigned(div6.quotient(31 downto 0));
mulStep <= 0;
if (div1.done = '1') then
state <= CALCCOLOR4;
end if;
when CALCCOLOR4 =>
mulStep <= mulStep + 1;
case (mulStep) is
when 0 => mulResult32clk <= mulResult32;
when 1 => mulResult32clk <= mulResult32; base_R <= base_R + mulResult32clk;
when 2 => mulResult32clk <= mulResult32; base_G <= base_G + mulResult32clk;
when 3 => mulResult32clk <= mulResult32; base_B <= base_B + mulResult32clk;
when 4 => mulResult32clk <= mulResult32; base_R <= base_R + mulResult32clk;
when 5 => mulResult32clk <= mulResult32; base_G <= base_G + mulResult32clk;
when 6 =>
base_B <= base_B + mulResult32clk;
if (rec_texture = '1') then
state <= CALCTEXTURE1;
else
state <= PREPAREHALF;
end if;
when others => null;
end case;
when CALCTEXTURE1 =>
mulStep <= 0;
state <= CALCTEXTURE2;
diffU10 <= ('0' & signed(vt(1).u)) - ('0' & signed(vt(0).u));
diffU21 <= ('0' & signed(vt(2).u)) - ('0' & signed(vt(1).u));
diffV10 <= ('0' & signed(vt(1).v)) - ('0' & signed(vt(0).v));
diffV21 <= ('0' & signed(vt(2).v)) - ('0' & signed(vt(1).v));
when CALCTEXTURE2 =>
mulStep <= mulStep + 1;
div1.divisor <= to_signed(denom, 25);
div2.divisor <= to_signed(denom, 25);
div3.divisor <= to_signed(denom, 25);
div4.divisor <= to_signed(denom, 25);
case (mulStep) is
when 0 => muldivResult1clk <= muldivResult1; muldivResult2clk <= muldivResult2;
when 1 => muldivResult1clk <= muldivResult1; muldivResult2clk <= muldivResult2; div1.dividend <= resize(muldivResult1clk - muldivResult2clk, 33) & x"000";
when 2 => muldivResult1clk <= muldivResult1; muldivResult2clk <= muldivResult2; div2.dividend <= resize(muldivResult1clk - muldivResult2clk, 33) & x"000";
when 3 => muldivResult1clk <= muldivResult1; muldivResult2clk <= muldivResult2; div3.dividend <= resize(muldivResult1clk - muldivResult2clk, 33) & x"000";
when 4 =>
div4.dividend <= resize(muldivResult1clk - muldivResult2clk, 33) & x"000";
state <= CALCTEXTURE3;
div1.start <= '1';
div2.start <= '1';
div3.start <= '1';
div4.start <= '1';
when others => null;
end case;
when CALCTEXTURE3 =>
dxU <= unsigned(div1.quotient(31 downto 0));
dyU <= unsigned(div2.quotient(31 downto 0));
dxV <= unsigned(div3.quotient(31 downto 0));
dyV <= unsigned(div4.quotient(31 downto 0));
mulStep <= 0;
if (div1.done = '1') then
state <= CALCTEXTURE4;
end if;
when CALCTEXTURE4 =>
mulStep <= mulStep + 1;
case (mulStep) is
when 0 => mulResult32clk <= mulResult32;
when 1 => mulResult32clk <= mulResult32; base_U <= base_U + mulResult32clk;
when 2 => mulResult32clk <= mulResult32; base_V <= base_V + mulResult32clk;
when 3 => mulResult32clk <= mulResult32; base_U <= base_U + mulResult32clk;
when 4 =>
base_V <= base_V + mulResult32clk;
state <= PREPAREHALF;
when others => null;
end case;
when PREPAREHALF =>
state <= PREPARELINE;
if (firsthalf = '1') then
firsthalf <= '0';
secondhalf <= '1';
yCoord <= vt(vo).y;
yBound <= vt(1-vo).y;
calc1 := (to_signed(vt(vo).x, 13) & x"00000000") + x"100000000" - 2048;
calc2 := baseCoord + vo_diff_base;
if (rightFacing = 0) then
xStart <= calc1;
xStepStart <= boundCoordUs;
xEnd <= calc2;
xStepEnd <= baseStep;
else
xStart <= calc2;
xStepStart <= baseStep;
xEnd <= calc1;
xStepEnd <= boundCoordUs;
end if;
decMode <= vo;
if (vo = 1) then
state <= PREPAREDECMODE;
end if;
else
secondhalf <= '0';
yCoord <= vt(1 + vp).y;
yBound <= vt(2 - vp).y;
calc3 := (to_signed(vt(1 + vp).x, 13) & x"00000000") + x"100000000" - 2048;
calc4 := baseCoord + vp_diff_base;
if (rightFacing = 0) then
xStart <= calc3;
xStepStart <= boundCoordLs;
xEnd <= calc4;
xStepEnd <= baseStep;
else
xStart <= calc4;
xStepStart <= baseStep;
xEnd <= calc3;
xStepEnd <= boundCoordLs;
end if;
decMode <= vp;
if (vp = 1) then
state <= PREPAREDECMODE;
end if;
end if;
filter_on <= '0';
if (textureFilter = "01") then -- always on
filter_on <= '1';
elsif (textureFilter = "10" and rec_dithering = '1' and drawmode_dithering = '1') then -- dithered
filter_on <= '1';
elsif (textureFilter = "11" and rec_dithering = '1' and drawmode_dithering = '1' and rec_shading = '1') then -- dith + shaded
filter_on <= '1';
end if;
if (textureFilter2DOff = '1' and dyU = 0 and dxV = 0) then
if (dxU = 4096 or dyV = 4096) then
filter_on <= '0';
end if;
end if;
when PREPAREDECMODE =>
state <= PREPARELINE;
yCoord <= yCoord - 1;
xStart <= xStart - xStepStart;
xEnd <= xEnd - xStepEnd;
when PREPARELINE =>
if (xStart(43 downto 32) < 0) then
xPos <= (others => '0');
else
xPos <= xStart(43 downto 32);
end if;
yPos <= to_signed(yCoord, 11);
xStop <= xEnd(43 downto 32);
if (xStart(43 downto 32) < 0 and xEnd(43 downto 32) > 1023) then
xSize <= to_unsigned(1024, 11);
elsif (xStart(43 downto 32) >= 0 and xEnd(43 downto 32) > 1023) then
xSize <= to_unsigned(1024, 11) - unsigned(xStart(41 downto 32));
else
xSize <= ('0' & (unsigned(xEnd(41 downto 32)) - unsigned(xStart(41 downto 32)))) + 1;
end if;
if (rec_transparency = '1' or DrawPixelsMask = '1') then
if (firstPixel = '1') then
state <= REQUESTFIRST;
else
state <= REQUESTLINE;
end if;
else
state <= PROCPIXELS;
end if;
-- check required to prevent simulation errors for multiplying negative value with unsigned
-- synthesis translate_off
if (yCoord >= 0) then
-- synthesis translate_on
if (rec_shading = '1') then
if (xStart(43 downto 32) < 0) then
work_R <= base_R + resize(dyR * yCoord, 32);
work_G <= base_G + resize(dyG * yCoord, 32);
work_B <= base_B + resize(dyB * yCoord, 32);
else
work_R <= base_R + resize(dxR * to_integer(xStart(43 downto 32)), 32) + resize(dyR * yCoord, 32);
work_G <= base_G + resize(dxG * to_integer(xStart(43 downto 32)), 32) + resize(dyG * yCoord, 32);
work_B <= base_B + resize(dxB * to_integer(xStart(43 downto 32)), 32) + resize(dyB * yCoord, 32);
end if;
else
work_R <= base_R;
work_G <= base_G;
work_B <= base_B;
end if;
if (rec_texture = '1') then
if (xStart(43 downto 32) < 0) then
work_U <= base_U + resize(dyU * yCoord, 32);
work_V <= base_V + resize(dyV * yCoord, 32);
else
work_U <= base_U + resize(dxU * to_integer(xStart(43 downto 32)), 32) + resize(dyU * yCoord, 32);
work_V <= base_V + resize(dxV * to_integer(xStart(43 downto 32)), 32) + resize(dyV * yCoord, 32);
end if;
else
work_U <= base_U;
work_V <= base_V;
end if;
-- synthesis translate_off
end if;
-- synthesis translate_on
stop := '0';
skip := '0';
if (xStart(43 downto 32) = xEnd(43 downto 32)) then
skip := '1';
end if;
if (to_integer(xStart(43 downto 32)) > drawingAreaRight) then
skip := '1';
end if;
if (xEnd(43 downto 32) <= 0) then
skip := '1';
end if;
if (interlacedDrawing = '1' and (activeLineLSB = to_signed(yCoord, 12)(0))) then
skip := '1';
end if;
if (decMode = 1) then
if (to_signed(yCoord, 11) < to_integer(drawingAreaTop)) then stop := '1'; end if;
if (to_signed(yCoord, 11) > to_integer(drawingAreaBottom)) then skip := '1'; end if;
else
if (to_signed(yCoord, 11) > to_integer(drawingAreaBottom)) then stop := '1'; end if;
if (to_signed(yCoord, 11) < to_integer(drawingAreaTop)) then skip := '1'; end if;
end if;
if (skip = '1') then
state <= PREPARELINE;
if (decMode = 1) then
yCoord <= yCoord - 1;
xStart <= xStart - xStepStart;
xEnd <= xEnd - xStepEnd;
else
yCoord <= yCoord + 1;
xStart <= xStart + xStepStart;
xEnd <= xEnd + xStepEnd;
end if;
end if;
if (decMode = 1) then
if (yCoord < yBound) then stop := '1'; end if;
else
if (yCoord >= yBound) then stop := '1'; end if;
end if;
if (stop = '1') then
if (secondhalf = '1') then
state <= PREPAREHALF;
else
if (nextQuad = '1') then
state <= ISSUE;
else
if (REPRODUCIBLEGPUTIMING = '1') then
state <= WAITIMING;
else
state <= IDLE;
done <= '1';
end if;
end if;
end if;
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';
xPos <= xPos + 1;
if (rec_shading = '1') then
work_R <= work_R + dxR;
work_G <= work_G + dxG;
work_B <= work_B + dxB;
end if;
if (rec_texture = '1') then
work_U <= work_U + dxU;
work_V <= work_V + dxV;
end if;
if (xPos + 1 >= xStop) then
if (decMode = 1) then
yCoord <= yCoord - 1;
xStart <= xStart - xStepStart;
xEnd <= xEnd - xStepEnd;
state <= PREPARELINE;
else
yCoord <= yCoord + 1;
xStart <= xStart + xStepStart;
xEnd <= xEnd + xStepEnd;
state <= PREPARELINE;
end if;
end if;
if (xPos >= to_integer(drawingAreaLeft) and xPos <= to_integer(drawingAreaRight)) then
pipeline_new <= '1';
pipeline_texture <= rec_texture;
pipeline_transparent <= rec_transparency;
pipeline_rawTexture <= rec_rawTexture;
pipeline_dithering <= rec_dithering;
pipeline_x <= unsigned(xPos(9 downto 0));
pipeline_y <= unsigned(yPos(8 downto 0));
pipeline_cr <= work_R(19 downto 12);
pipeline_cg <= work_G(19 downto 12);
pipeline_cb <= work_B(19 downto 12);
pipeline_u <= work_U(19 downto 12);
pipeline_v <= work_V(19 downto 12);
pipeline_u11 <= work_U(19 downto 12);
pipeline_v11 <= work_V(19 downto 12);
pipeline_uAcc <= work_U(11 downto 4);
pipeline_vAcc <= work_V(11 downto 4);
if (filter_on = '1') then
pipeline_filter <= '1';
uFilter := resize(work_U(19 downto 10), 11) + filterStrength;
vFilter := resize(work_V(19 downto 10), 11) + filterStrength;
if (uFilter(10 downto 2) <= ('0' & filter_maxU)) then pipeline_u11 <= uFilter(9 downto 2); end if;
if (vFilter(10 downto 2) <= ('0' & filter_maxV)) then pipeline_v11 <= vFilter(9 downto 2); end if;
end if;
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;