library IEEE;
use IEEE.std_logic_1164.all;  
use IEEE.numeric_std.all; 
use STD.textio.all;

library mem;
use work.pGPU.all;

entity gpu is
   port 
   (
      clk1x                : in  std_logic;
      clk2x                : in  std_logic;
      clk2xIndex           : in  std_logic;
      clkvid               : in  std_logic;
      ce                   : in  std_logic;
      reset                : in  std_logic;
      
      allowunpause         : out std_logic;
      savestate_busy       : in  std_logic;
      system_paused        : in  std_logic;
      
      ditherOff            : in  std_logic;
      interlaced480pHack   : in  std_logic;
      REPRODUCIBLEGPUTIMING: in  std_logic;
      videoout_on          : in  std_logic;
      isPal                : in  std_logic;
      pal60                : in  std_logic;
      fpscountOn           : in  std_logic;
      noTexture            : in  std_logic;
      textureFilter        : in  std_logic_vector(1 downto 0);
      textureFilterStrength: in  std_logic_vector(1 downto 0);
      textureFilter2DOff   : in  std_logic;
      dither24             : in  std_logic;
      render24             : in  std_logic;
      drawSlow             : in  std_logic;
      debugmodeOn          : in  std_logic;
      syncVideoOut         : in  std_logic;
      syncInterlace        : in  std_logic;
      rotate180            : in  std_logic;
      fixedVBlank          : in  std_logic;
      vCrop                : in  std_logic_vector(1 downto 0);
      hCrop                : in  std_logic;

      Gun1CrosshairOn      : in  std_logic;
      Gun1X                : in  unsigned(7 downto 0);
      Gun1Y_scanlines      : in  unsigned(8 downto 0);
      Gun1offscreen        : in  std_logic;
      Gun1IRQ10            : out std_logic;

      Gun2CrosshairOn      : in  std_logic;
      Gun2X                : in  unsigned(7 downto 0);
      Gun2Y_scanlines      : in  unsigned(8 downto 0);
      Gun2offscreen        : in  std_logic;
      Gun2IRQ10            : out std_logic;
      
      cdSlow               : in  std_logic;
      
      errorOn              : in  std_logic;
      errorEna             : in  std_logic;
      errorCode            : in  unsigned(3 downto 0);
      
      LBAOn                : in  std_logic;
      LBAdisplay           : in  unsigned(19 downto 0);
      
      errorLINE            : out std_logic;
      errorRECT            : out std_logic;
      errorPOLY            : out std_logic;
      errorGPU             : out std_logic;
      errorMASK            : out std_logic;
      errorFIFO            : out std_logic;
      
      bus_addr             : in  unsigned(3 downto 0); 
      bus_dataWrite        : in  std_logic_vector(31 downto 0);
      bus_read             : in  std_logic;
      bus_write            : in  std_logic;
      bus_dataRead         : out std_logic_vector(31 downto 0);
      bus_stall            : out std_logic := '0';
      
      dmaOn                : in  std_logic;
      gpu_dmaRequest       : out std_logic;
      DMA_GPU_waiting      : in  std_logic;
      DMA_GPU_writeEna     : in  std_logic;
      DMA_GPU_readEna      : in  std_logic;
      DMA_GPU_write        : in  std_logic_vector(31 downto 0);
      DMA_GPU_read         : out std_logic_vector(31 downto 0);
      
      irq_VBLANK           : out std_logic := '0';
      irq_GPU              : out std_logic := '0';
           
      vram_pause           : in  std_logic;
      vram_paused          : out std_logic := '0';
      vram_BUSY            : in  std_logic;                    
      vram_DOUT            : in  std_logic_vector(63 downto 0);
      vram_DOUT_READY      : in  std_logic;
      vram_BURSTCNT        : out std_logic_vector(7 downto 0) := (others => '0'); 
      vram_ADDR            : out std_logic_vector(27 downto 0) := (others => '0');                       
      vram_DIN             : out std_logic_vector(63 downto 0) := (others => '0');
      vram_BE              : out std_logic_vector(7 downto 0) := (others => '0'); 
      vram_WE              : out std_logic := '0';
      vram_RD              : out std_logic := '0';     

      hblank_tmr           : out std_logic := '0';
      vblank_tmr           : out std_logic := '0';
      dotclock             : out std_logic;
      
      video_hsync          : out std_logic := '0';
      video_vsync          : out std_logic := '0';
      video_hblank         : out std_logic := '0';
      video_vblank         : out std_logic := '0';
      video_DisplayWidth   : out unsigned(10 downto 0);
      video_DisplayHeight  : out unsigned( 9 downto 0);
      video_DisplayOffsetX : out unsigned( 9 downto 0) := (others => '0'); 
      video_DisplayOffsetY : out unsigned( 8 downto 0) := (others => '0'); 
      video_ce             : out std_logic;
      video_interlace      : out std_logic;
      video_r              : out std_logic_vector(7 downto 0);
      video_g              : out std_logic_vector(7 downto 0);
      video_b              : out std_logic_vector(7 downto 0);
      video_isPal          : out std_logic;
      video_fbmode         : out std_logic;
      video_fb24           : out std_logic;
      video_hResMode       : out std_logic_vector(2 downto 0);
      video_frameindex     : out std_logic_vector(3 downto 0);
      
-- synthesis translate_off
      export_gtm           : out unsigned(11 downto 0);
      export_line          : out unsigned(11 downto 0);
      export_gpus          : out unsigned(31 downto 0);
      export_gobj          : out unsigned(15 downto 0) := (others => '0');
-- synthesis translate_on
      
      loading_savestate    : in  std_logic;
      SS_reset             : in  std_logic;
      SS_DataWrite         : in  std_logic_vector(31 downto 0);
      SS_Adr               : in  unsigned(2 downto 0);
      SS_wren_GPU          : in  std_logic;
      SS_wren_Timing       : in  std_logic;
      SS_rden_GPU          : in  std_logic;
      SS_rden_Timing       : in  std_logic;
      SS_DataRead_GPU      : out std_logic_vector(31 downto 0);
      SS_DataRead_Timing   : out std_logic_vector(31 downto 0);
      SS_Idle              : out std_logic
   );
end entity;

architecture arch of gpu is
  
   signal softReset                 : std_logic := '0';
   signal drawer_reset              : std_logic := '0';
   
   signal videoout_settings         : tvideoout_settings;
   signal videoout_reports          : tvideoout_reports;
   signal videoout_out              : tvideoout_out;
   
   signal GPUREAD                   : std_logic_vector(31 downto 0) := (others => '0');
   signal GPUSTAT                   : std_logic_vector(31 downto 0) := (others => '0');
   signal GPUSTAT_TextPageX         : std_logic_vector(3 downto 0);
   signal GPUSTAT_TextPageY         : std_logic;
   signal GPUSTAT_Transparency      : std_logic_vector(1 downto 0);
   signal GPUSTAT_TextPageColors    : std_logic_vector(1 downto 0);
   signal GPUSTAT_Dither            : std_logic;
   signal GPUSTAT_DrawToDisplay     : std_logic;
   signal GPUSTAT_SetMask           : std_logic;
   signal GPUSTAT_DrawPixelsMask    : std_logic;
   signal GPUSTAT_ReverseFlag       : std_logic;
   signal GPUSTAT_TextureDisable    : std_logic;
   signal GPUSTAT_HorRes2           : std_logic := '0';
   signal GPUSTAT_HorRes1           : std_logic_vector(1 downto 0) := "00";
   signal GPUSTAT_VerRes            : std_logic := '0';
   signal GPUSTAT_PalVideoMode      : std_logic := '0';
   signal GPUSTAT_ColorDepth24      : std_logic := '0';
   signal GPUSTAT_VertInterlace     : std_logic := '0';
   signal GPUSTAT_DisplayDisable    : std_logic := '1';
   signal GPUSTAT_IRQRequest        : std_logic;
   signal GPUSTAT_DMADataRequest    : std_logic;
   signal GPUSTAT_ReadyRecCmd       : std_logic;
   signal GPUSTAT_ReadySendVRAM     : std_logic;
   signal GPUSTAT_ReadyRecDMA       : std_logic;
   signal GPUSTAT_DMADirection      : std_logic_vector(1 downto 0);
      
   signal vramRange                 : unsigned(18 downto 0) := (others => '0');
   signal hDisplayRange             : unsigned(23 downto 0) := x"C60260";
   signal vDisplayRange             : unsigned(19 downto 0) := x"3FC10";
      
   signal drawMode                  : unsigned(13 downto 0) := (others => '0');
      
   signal textureWindow             : unsigned(19 downto 0) := (others => '0');
   signal textureWindow_AND_X       : unsigned(7 downto 0) := (others => '0');
   signal textureWindow_AND_Y       : unsigned(7 downto 0) := (others => '0');   
   signal textureWindow_OR_X        : unsigned(7 downto 0) := (others => '0');
   signal textureWindow_OR_Y        : unsigned(7 downto 0) := (others => '0');
      
   signal drawingAreaLeft           : unsigned(9 downto 0) := (others => '0');
   signal drawingAreaRight          : unsigned(9 downto 0) := (others => '0');
   signal drawingAreaTop            : unsigned(8 downto 0) := (others => '0');
   signal drawingAreaBottom         : unsigned(8 downto 0) := (others => '0');
   signal drawingOffsetX            : signed(10 downto 0) := (others => '0');
   signal drawingOffsetY            : signed(10 downto 0) := (others => '0');
   signal interlacedDrawing         : std_logic;
      
   -- FIFO IN  
   signal fifoIn_reset              : std_logic; 
   signal fifoIn_Din                : std_logic_vector(31 downto 0);
   signal fifoIn_Wr                 : std_logic; 
   signal fifoIn_Dout               : std_logic_vector(31 downto 0);
   signal fifoIn_Rd                 : std_logic;
   signal fifoIn_Empty              : std_logic;
   signal fifoIn_Valid              : std_logic;
      
   -- Processing  
   signal proc_idle                 : std_logic;
   signal proc_done                 : std_logic;
   --signal proc_CmdDone              : std_logic;
   signal proc_requestFifo          : std_logic;
   signal timeout                   : integer range 0 to 67108863 := 0;
   
   signal pixelStall                : std_logic;
   signal pixelColor                : std_logic_vector(15 downto 0);
   signal pixelColor2               : std_logic_vector(15 downto 0);
   signal pixelAddr                 : unsigned(19 downto 0);
   signal pixelWrite                : std_logic;
      
   signal pixel64data               : std_logic_vector(63 downto 0) := (others => '0');
   signal pixel64data2              : std_logic_vector(63 downto 0) := (others => '0');
   signal pixel64wordEna            : std_logic_vector(3 downto 0) := (others => '0');
   signal pixel64addr               : std_logic_vector(16 downto 0) := (others => '0');
   signal pixel64filled             : std_logic := '0';
   signal pixel64source             : std_logic := '0';
   signal pixel64timeout            : integer range 0 to 15;
      
   -- workers  
   type t_div_array is array(0 to 5) of div_type;
   signal div_array                 : t_div_array;
   
   signal vramFill_requestFifo      : std_logic; 
   signal vramFill_done             : std_logic; 
   --signal vramFill_CmdDone          : std_logic; 
   signal vramFill_pixelColor       : std_logic_vector(15 downto 0);
   signal vramFill_pixelAddr        : unsigned(19 downto 0);
   signal vramFill_pixelWrite       : std_logic;   
      
   signal cpu2vram_requestFifo      : std_logic; 
   signal cpu2vram_done             : std_logic; 
   --signal cpu2vram_CmdDone          : std_logic; 
   signal cpu2vram_pixelColor       : std_logic_vector(15 downto 0);
   signal cpu2vram_pixelAddr        : unsigned(19 downto 0);
   signal cpu2vram_pixelWrite       : std_logic;
      
   signal vram2vram_requestFifo     : std_logic; 
   signal vram2vram_done            : std_logic; 
   --signal vram2vram_CmdDone         : std_logic; 
   signal vram2vram_pixelColor      : std_logic_vector(15 downto 0);
   signal vram2vram_pixelAddr       : unsigned(19 downto 0);
   signal vram2vram_pixelWrite      : std_logic;
   signal vram2vram_reqVRAMEnable   : std_logic;
   signal vram2vram_reqVRAMXPos     : unsigned(9 downto 0);
   signal vram2vram_reqVRAMYPos     : unsigned(8 downto 0);
   signal vram2vram_reqVRAMSize     : unsigned(10 downto 0);
   signal vram2vram_vramLineEna     : std_logic;
   signal vram2vram_vramLineAddr    : unsigned(9 downto 0);
   
   signal vram2cpu_requestFifo      : std_logic; 
   signal vram2cpu_done             : std_logic; 
   --signal vram2cpu_CmdDone          : std_logic; 
   signal vram2cpu_reqVRAMEnable    : std_logic;
   signal vram2cpu_reqVRAMXPos      : unsigned(9 downto 0);
   signal vram2cpu_reqVRAMYPos      : unsigned(8 downto 0);
   signal vram2cpu_reqVRAMSize      : unsigned(10 downto 0);
   signal vram2cpu_vramLineEna      : std_logic;
   signal vram2cpu_vramLineAddr     : unsigned(9 downto 0);
   signal vram2cpu_Fifo_Dout        : std_logic_vector(31 downto 0);
   signal vram2cpu_Fifo_Rd          : std_logic;
   signal vram2cpu_Fifo_Empty       : std_logic;
   signal vram2cpu_Fifo_ready       : std_logic;
   
   signal line_requestFifo          : std_logic; 
   signal line_done                 : std_logic;
   --signal line_CmdDone              : std_logic;
   signal line_div                  : t_div_array;
   signal line_pipeline_new         : std_logic;
   signal line_pipeline_transparent : std_logic;
   signal line_pipeline_x           : unsigned(9 downto 0);
   signal line_pipeline_y           : unsigned(8 downto 0);
   signal line_pipeline_cr          : unsigned(7 downto 0);
   signal line_pipeline_cg          : unsigned(7 downto 0);
   signal line_pipeline_cb          : unsigned(7 downto 0);
   signal line_reqVRAMEnable        : std_logic;
   signal line_reqVRAMXPos          : unsigned(9 downto 0);
   signal line_reqVRAMYPos          : unsigned(8 downto 0);
   signal line_reqVRAMSize          : unsigned(10 downto 0);
   signal line_vramLineEna          : std_logic;
   signal line_vramLineAddr         : unsigned(9 downto 0);
   
   signal rect_requestFifo          : std_logic; 
   signal rect_done                 : std_logic;
   --signal rect_CmdDone              : std_logic;
   signal rect_pipeline_new         : std_logic;
   signal rect_pipeline_texture     : std_logic;
   signal rect_pipeline_transparent : std_logic;
   signal rect_pipeline_rawTexture  : std_logic;
   signal rect_pipeline_x           : unsigned(9 downto 0);
   signal rect_pipeline_y           : unsigned(8 downto 0);
   signal rect_pipeline_cr          : unsigned(7 downto 0);
   signal rect_pipeline_cg          : unsigned(7 downto 0);
   signal rect_pipeline_cb          : unsigned(7 downto 0);
   signal rect_pipeline_u           : unsigned(7 downto 0);
   signal rect_pipeline_v           : unsigned(7 downto 0);
   signal rect_reqVRAMEnable        : std_logic;
   signal rect_reqVRAMXPos          : unsigned(9 downto 0);
   signal rect_reqVRAMYPos          : unsigned(8 downto 0);
   signal rect_reqVRAMSize          : unsigned(10 downto 0);
   signal rect_vramLineEna          : std_logic;
   signal rect_vramLineAddr         : unsigned(9 downto 0);
   signal rect_textPalNew           : std_logic;
   signal rect_textPalX             : unsigned(9 downto 0);   
   signal rect_textPalY             : unsigned(8 downto 0); 
   
   signal poly_requestFifo          : std_logic; 
   signal poly_done                 : std_logic;
   --signal poly_CmdDone              : std_logic;
   signal poly_div                  : t_div_array;
   signal poly_pipeline_new         : std_logic;
   signal poly_pipeline_texture     : std_logic;
   signal poly_pipeline_transparent : std_logic;
   signal poly_pipeline_rawTexture  : std_logic;
   signal poly_pipeline_dithering   : std_logic;
   signal poly_pipeline_x           : unsigned(9 downto 0);
   signal poly_pipeline_y           : unsigned(8 downto 0);
   signal poly_pipeline_cr          : unsigned(7 downto 0);
   signal poly_pipeline_cg          : unsigned(7 downto 0);
   signal poly_pipeline_cb          : unsigned(7 downto 0);
   signal poly_pipeline_u           : unsigned(7 downto 0);
   signal poly_pipeline_v           : unsigned(7 downto 0);
   signal poly_pipeline_u11         : unsigned(7 downto 0);
   signal poly_pipeline_v11         : unsigned(7 downto 0);
   signal poly_reqVRAMEnable        : std_logic;
   signal poly_reqVRAMXPos          : unsigned(9 downto 0);
   signal poly_reqVRAMYPos          : unsigned(8 downto 0);
   signal poly_reqVRAMSize          : unsigned(10 downto 0);
   signal poly_vramLineEna          : std_logic;
   signal poly_vramLineAddr         : unsigned(9 downto 0);
   signal poly_drawModeRec          : unsigned(11 downto 0);
   signal poly_drawModeNew          : std_logic;
   signal poly_textPalNew           : std_logic;
   signal poly_textPalX             : unsigned(9 downto 0);   
   signal poly_textPalY             : unsigned(8 downto 0); 
   
   signal pipeline_pixelColor       : std_logic_vector(15 downto 0);
   signal pipeline_pixelColor2      : std_logic_vector(15 downto 0);
   signal pipeline_pixelAddr        : unsigned(19 downto 0);
   signal pipeline_pixelWrite       : std_logic;
   signal pipeline_reqVRAMEnable    : std_logic;
   signal pipeline_reqVRAMXPos      : unsigned(9 downto 0);
   signal pipeline_reqVRAMYPos      : unsigned(8 downto 0);
   signal pipeline_reqVRAMSize      : unsigned(10 downto 0);
   
   signal pipeline_busy             : std_logic;
   signal pipeline_stall            : std_logic;
   signal pipeline_new              : std_logic;
   signal pipeline_texture          : std_logic;
   signal pipeline_transparent      : std_logic;
   signal pipeline_rawTexture       : std_logic;
   signal pipeline_dithering        : std_logic;
   signal pipeline_x                : unsigned(9 downto 0);
   signal pipeline_y                : unsigned(8 downto 0);
   signal pipeline_cr               : unsigned(7 downto 0);
   signal pipeline_cg               : unsigned(7 downto 0);
   signal pipeline_cb               : unsigned(7 downto 0);
   signal pipeline_u                : unsigned(7 downto 0);
   signal pipeline_v                : unsigned(7 downto 0);
   signal pipeline_filter           : std_logic;   
   signal pipeline_u11              : unsigned(7 downto 0);
   signal pipeline_v11              : unsigned(7 downto 0);
   signal pipeline_uAcc             : unsigned(7 downto 0);
   signal pipeline_vAcc             : unsigned(7 downto 0);
   
   signal pipeline_clearCacheTexture: std_logic := '0';
   signal pipeline_clearCachePalette: std_logic := '0';
   
   signal pipeline_textPalNew       : std_logic;
   signal pipeline_textPalX         : unsigned(9 downto 0);   
   signal pipeline_textPalY         : unsigned(8 downto 0); 
      
   -- FIFO OUT 
   signal fifoOut_reset             : std_logic; 
   signal fifoOut_Din               : std_logic_vector(85 downto 0);
   signal fifoOut_Wr                : std_logic; 
   signal fifoOut_Wr_1              : std_logic; 
   signal fifoOut_NearFull          : std_logic;
   signal fifoOut_Dout              : std_logic_vector(85 downto 0);
   signal fifoOut_Rd                : std_logic;
   signal fifoOut_Empty             : std_logic;
   signal fifoOut_idle              : std_logic;
   
   signal fifoOut2_Din              : std_logic_vector(63 downto 0);
   signal fifoOut2_Dout             : std_logic_vector(63 downto 0);
   signal fifoOut2_Dout_1           : std_logic_vector(63 downto 0);
   
   -- vram access
   type tvramState is
   (
      IDLE,
      WRITESECOND,
      READSECOND,
      READVRAM,
      CLEARLINESTART,
      CLEARLINE
   );
   signal vramState : tvramState := IDLE;
   
   signal VRAMIdle                  : std_logic;
   signal reqVRAMIdle               : std_logic;
   signal reqVRAMDone               : std_logic;
   signal vram_pauseCnt             : integer range 0 to 3;
   
   signal reqVRAMEnable             : std_logic;
   signal reqVRAMXPos               : unsigned(9 downto 0);
   signal reqVRAMYPos               : unsigned(8 downto 0);
   signal reqVRAMSize               : unsigned(10 downto 0);
   signal reqVRAMremain             : unsigned(7 downto 0);
   signal reqVRAMremain2            : unsigned(7 downto 0);
   signal reqVRAMwait               : unsigned(7 downto 0);
   signal reqVRAMwrap               : unsigned(7 downto 0);
   signal reqVRAMnext               : unsigned(7 downto 0);
   signal reqVRAMaddr               : unsigned(7 downto 0) := (others => '0');
   signal reqVRAMaddr2              : unsigned(7 downto 0) := (others => '0');
   signal reqVRAMStore              : std_logic := '0';        
   signal reqVRAMStore2             : std_logic := '0';        
   signal reqVRAMtwice              : std_logic := '0';        
   
   signal vramLineAddr              : unsigned(9 downto 0);
   
   signal vramLineData              : std_logic_vector(15 downto 0);
   signal vramLineData2             : std_logic_vector(15 downto 0);
   
   -- videoout
   signal videoout_reqVRAMEnable    : std_logic;
   signal videoout_reqRAMMirror     : std_logic;
   signal videoout_reqVRAMXPos      : unsigned(9 downto 0);
   signal videoout_reqVRAMYPos      : unsigned(8 downto 0);
   signal videoout_reqVRAMSize      : unsigned(10 downto 0);
   
   -- direct framebuffer mode
   signal frameindex_current        : unsigned(1 downto 0) := (others => '0');
   signal frameindex_last           : unsigned(1 downto 0) := (others => '0');
   signal irq_VBLANK_1              : std_logic := '0';
   signal poly_requestFifo_1        : std_logic := '0';
   signal frameWriteCount           : integer := 0;
   signal framePolyCount            : integer range 0 to 16777215 := 0;
   signal frameFastCount            : integer range 0 to 3 := 0;
   signal frameFastmode             : std_logic := '0';
   signal frameVramType             : std_logic := '0';
   signal frameFirstChangedLine     : unsigned(8 downto 0) := (others => '0');
   signal frameLastChangedLine      : unsigned(8 downto 0) := (others => '0');
   
   signal frameClearRequest         : std_logic := '0';
   signal frameClearYPos            : unsigned(8 downto 0) := (others => '0');
   signal frameClearCnt             : unsigned(8 downto 0) := (others => '0');
   signal frameClearPosLow          : unsigned(8 downto 0) := (others => '0');
   signal frameClearPosHigh         : unsigned(8 downto 0) := (others => '0');
   signal frameClearXPos            : unsigned(9 downto 0) := (others => '0');
   
   -- fps counter
   signal fpscountBCD               : unsigned(7 downto 0) := (others => '0');
   signal fpscountBCD_next          : unsigned(7 downto 0) := (others => '0');
   signal fps_SecondCounter         : integer range 0 to 33868799 := 0;
   signal fps_vramRange_last        : unsigned(18 downto 0) := (others => '0');
   
   -- savestates
   type t_ssarray is array(0 to 7) of std_logic_vector(31 downto 0);
   signal ss_gpu_in     : t_ssarray := (others => (others => '0'));
   signal ss_timing_in  : t_ssarray := (others => (others => '0'));   
   signal ss_gpu_out    : t_ssarray := (others => (others => '0'));
   signal ss_timing_out : t_ssarray := (others => (others => '0'));
   
   signal videoout_ss_in  : tvideoout_ss;
   signal videoout_ss_out : tvideoout_ss;
   
begin 

-- synthesis translate_off
   export_gtm  <= unsigned(videoout_ss_out.nextHCount);
   export_line <= "000" & unsigned(videoout_ss_out.vpos);
   export_gpus <= unsigned(GPUSTAT);
-- synthesis translate_on
   
   gpu_dmaRequest <= GPUSTAT_DMADataRequest;

   GPUSTAT(3 downto 0)     <= GPUSTAT_TextPageX;
   GPUSTAT(4)              <= GPUSTAT_TextPageY;
   GPUSTAT(6 downto 5)     <= GPUSTAT_Transparency;
   GPUSTAT(8 downto 7)     <= GPUSTAT_TextPageColors;
   GPUSTAT(9)              <= GPUSTAT_Dither;
   GPUSTAT(10)             <= GPUSTAT_DrawToDisplay;
   GPUSTAT(11)             <= GPUSTAT_SetMask;
   GPUSTAT(12)             <= GPUSTAT_DrawPixelsMask;
   GPUSTAT(13)             <= not videoout_reports.GPUSTAT_InterlaceField;
   GPUSTAT(14)             <= GPUSTAT_ReverseFlag;
   GPUSTAT(15)             <= GPUSTAT_TextureDisable;
   GPUSTAT(16)             <= GPUSTAT_HorRes2;
   GPUSTAT(18 downto 17)   <= GPUSTAT_HorRes1;
   GPUSTAT(19)             <= GPUSTAT_VerRes;
   GPUSTAT(20)             <= GPUSTAT_PalVideoMode;
   GPUSTAT(21)             <= GPUSTAT_ColorDepth24;
   GPUSTAT(22)             <= GPUSTAT_VertInterlace;
   GPUSTAT(23)             <= GPUSTAT_DisplayDisable;
   GPUSTAT(24)             <= GPUSTAT_IRQRequest;
   GPUSTAT(25)             <= GPUSTAT_DMADataRequest;
   GPUSTAT(26)             <= GPUSTAT_ReadyRecCmd and ((not gpu_dmaRequest) or (not DMA_GPU_waiting));
   GPUSTAT(27)             <= GPUSTAT_ReadySendVRAM;
   GPUSTAT(28)             <= GPUSTAT_ReadyRecDMA;
   GPUSTAT(30 downto 29)   <= GPUSTAT_DMADirection;
   GPUSTAT(31)             <= videoout_reports.GPUSTAT_DrawingOddline;

   GPUSTAT_DMADataRequest <= '0' when (GPUSTAT_DMADirection = "00") else
                             GPUSTAT_ReadyRecDMA when (GPUSTAT_DMADirection = "01") else
                             GPUSTAT_ReadyRecDMA when (GPUSTAT_DMADirection = "10") else
                             not vram2cpu_Fifo_Empty; -- GPUSTAT_ReadySendVRAM cannot be used, because data is read earlier                

   -- video out
   irq_VBLANK             <= videoout_reports.irq_VBLANK;
   hblank_tmr             <= videoout_reports.hblank_tmr;

   -- savestates

   ss_gpu_out(0)  <= GPUREAD;                
   ss_gpu_out(1)  <= GPUSTAT;                

   ss_timing_out(4)(19)            <= videoout_ss_out.interlacedDisplayField;
   ss_timing_out(2)(18 downto 0)   <= std_logic_vector(vramRange);    
   ss_timing_out(1)(23 downto 0)   <= std_logic_vector(hDisplayRange);
   ss_timing_out(0)(19 downto 0)   <= std_logic_vector(vDisplayRange);
   ss_timing_out(4)(11 downto 0)   <= videoout_ss_out.nextHCount;
   ss_timing_out(3)(24 downto 16)  <= videoout_ss_out.vpos;      
   ss_timing_out(4)(17)            <= videoout_ss_out.inVsync;      
   ss_timing_out(4)(20)            <= videoout_ss_out.activeLineLSB;
   ss_timing_out(4)(29 downto 21)  <= videoout_ss_out.vdisp;

   process (clk1x)
      variable cmdNew           : unsigned(7 downto 0);
      variable frameWriteLineY  : unsigned(8 downto 0);    
   begin
      if rising_edge(clk1x) then
      
         fifoIn_reset  <= '0';
         fifoOut_reset <= '0';
         
         drawer_reset  <= '0';
         
         vblank_tmr <= videoout_reports.inVsync;

         if (reset = '1') then
               
            softReset               <= not loading_savestate;
            bus_stall               <= '0';
            
            fifoIn_reset            <= '1';
            fifoOut_reset           <= '1';
            
            vramRange               <= unsigned(ss_timing_in(2)(18 downto 0));
            hDisplayRange           <= unsigned(ss_timing_in(1)(23 downto 0)); -- x"C60260";
            vDisplayRange           <= unsigned(ss_timing_in(0)(19 downto 0)); -- x"3FC10";
      
            GPUSTAT_ReverseFlag     <= ss_gpu_in(1)(14);
            GPUSTAT_HorRes2         <= ss_gpu_in(1)(16);
            GPUSTAT_HorRes1         <= ss_gpu_in(1)(18 downto 17);
            GPUSTAT_VerRes          <= ss_gpu_in(1)(19);
            GPUSTAT_PalVideoMode    <= ss_gpu_in(1)(20); --isPal;
            GPUSTAT_ColorDepth24    <= ss_gpu_in(1)(21);
            GPUSTAT_VertInterlace   <= ss_gpu_in(1)(22);
            GPUSTAT_DisplayDisable  <= ss_gpu_in(1)(23);
            GPUSTAT_IRQRequest      <= ss_gpu_in(1)(24);
            GPUSTAT_DMADirection    <= ss_gpu_in(1)(30 downto 29);
            GPUREAD                 <= ss_gpu_in(0);       
            
            fpscountBCD_next        <= (others => '0');
            
            frameFastCount          <= 0;
            frameFastmode           <= '0';

         elsif (ce = '1') then
         
            bus_dataRead <= (others => '0');
            softReset    <= '0';
            
            -- bus read
            if (bus_read = '1') then
               if (bus_addr(3 downto 2) = "00") then
               
                  if (vram2cpu_Fifo_Empty = '0') then
                     bus_dataRead <= vram2cpu_Fifo_Dout;
                     GPUREAD      <= vram2cpu_Fifo_Dout;
                  else
                     bus_dataRead <= GPUREAD;
                  end if;
                  
                  if (vram2cpu_Fifo_ready = '0') then
                     bus_stall <= '1';
                  end if;
                  
               elsif (bus_addr(3 downto 2) = "01") then
                  bus_dataRead <= GPUSTAT;
               else
                  bus_dataRead <= x"FFFFFFFF";
               end if;
            end if;
            
            if (bus_stall = '1' and vram2cpu_Fifo_ready = '1') then
               bus_dataRead <= vram2cpu_Fifo_Dout;
               GPUREAD      <= vram2cpu_Fifo_Dout;
               bus_stall    <= '0';
            end if;

            -- bus write
            if (bus_write = '1') then
            
               if (bus_addr = 4) then
                  
                  case (to_integer(unsigned(bus_dataWrite(29 downto 24)))) is
                     when 16#00# => -- reset
                        softReset    <= '1';
                        fifoIn_reset <= '1'; 
                        
                     when 16#01# => -- clear fifo
                        fifoIn_reset <= '1';   
                        drawer_reset <= '1';
                        -- todo: must reset drawing units to idle? -> ridge racer triggers that in the middle of a rectangle command clearing the screen
                        -- reset CLUT cache?
                        
                     when 16#02# => -- ack irq
                        GPUSTAT_IRQRequest <= '0';
                        
                     when 16#03# => -- display on/off
                        GPUSTAT_DisplayDisable <= bus_dataWrite(0);
                        
                     when 16#04# => -- DMA direction
                        GPUSTAT_DMADirection <= bus_dataWrite(1 downto 0);
                        
                     when 16#05# => -- Start of Display area (in VRAM)
                        vramRange <= unsigned(bus_dataWrite(18 downto 1)) & '0';
                        
                     when 16#06# => -- horizontal diplay range
                        hDisplayRange <= unsigned(bus_dataWrite(23 downto 0));
                        
                     when 16#07# => -- vertical diplay range
                        vDisplayRange <= unsigned(bus_dataWrite(19 downto 0));
                        
                     when 16#08# => -- Set display mode
                        GPUSTAT_HorRes1       <= bus_dataWrite(1 downto 0);
                        GPUSTAT_VerRes        <= bus_dataWrite(2);
                        GPUSTAT_PalVideoMode  <= bus_dataWrite(3);
                        GPUSTAT_ColorDepth24  <= bus_dataWrite(4);
                        GPUSTAT_VertInterlace <= bus_dataWrite(5);
                        GPUSTAT_HorRes2       <= bus_dataWrite(6);
                        GPUSTAT_ReverseFlag   <= bus_dataWrite(7);
                        
                     when 16#09# => -- Allow texture disable
                        -- todo
                          
                     when 16#10# | 16#11# | 16#12# | 16#13# | 16#14# | 16#15# | 16#16# | 16#17# | 16#18# | 16#19# | 16#1A# | 16#1B# | 16#1C# | 16#1D# | 16#1E# | 16#1F# => -- GPUInfo
                        case (to_integer(unsigned(bus_dataWrite(2 downto 0)))) is
                           when 2 => --Get Texture Window
                              GPUREAD <= x"000" & std_logic_vector(textureWindow);
                           
                           when 3 => --Get Draw Area Top Left
                              GPUREAD <= x"000" & '0' & std_logic_vector(drawingAreaTop) & std_logic_vector(drawingAreaLeft);
                           
                           when 4 => --Get Draw Area Bottom Right
                              GPUREAD <= x"000" & '0' & std_logic_vector(drawingAreaBottom) & std_logic_vector(drawingAreaRight);
                           
                           when 5 => --Get Drawing Offset
                              GPUREAD <= x"00" & "00" & std_logic_vector(drawingOffsetY) & std_logic_vector(drawingOffsetX);
                           
                           when others => null;
                        end case;
                     
                     when others => report "GP1 Command not implemented" severity failure; 
                  end case;
               
               end if;
            
            end if;
            
            if (irq_GPU = '1') then
               GPUSTAT_IRQRequest <= '1';
            end if;
            
            -- 480i framebuffer logic
            frameWriteLineY := unsigned(vram_ADDR(19 downto 11)) - videoout_out.DisplayOffsetY;
            
            if (vram_we = '1' and frameVramType = '1') then
               if (unsigned(vram_ADDR(19 downto 11)) >= videoout_out.DisplayOffsetY) then
                  if (unsigned(vram_ADDR(19 downto 11)) < (videoout_out.DisplayOffsetY + videoout_out.DisplayHeightReal)) then
                     
                     if (frameWriteLineY < frameFirstChangedLine) then
                        frameFirstChangedLine <= frameWriteLineY;
                     end if;
                     
                     if (frameWriteLineY > frameLastChangedLine) then
                        frameLastChangedLine <= frameWriteLineY;
                     end if;
                  
                     if (unsigned(vram_ADDR(10 downto 1)) >= videoout_out.DisplayOffsetX) then
                        if (unsigned(vram_ADDR(10 downto 1)) < (videoout_out.DisplayOffsetX + videoout_out.DisplayWidthReal)) then
                           frameWriteCount <= frameWriteCount + 1;
                        end if;
                     end if;
                  
                  end if;
               end if;

            end if;
            
            poly_requestFifo_1 <= poly_requestFifo;
            if (poly_requestFifo_1 = '0' and poly_requestFifo = '1') then
               framePolyCount <= framePolyCount + 1;
            end if;

            irq_VBLANK_1 <= videoout_reports.irq_VBLANK;
            if (videoout_reports.irq_VBLANK = '1' and irq_VBLANK_1 = '0') then
               frameFastmode    <= '0';
               frameWriteCount  <= 0;
               framePolyCount   <= 0;
               frameFirstChangedLine <= (others => '1');
               frameLastChangedLine  <= (others => '0');
               if (GPUSTAT_VertInterlace = '1' and GPUSTAT_VerRes = '1') then
                  -- condition to allow 480p hack: game is in 480i mode and draws most of the screen every frame
                  if (frameWriteCount > 40000 and framePolyCount > 31 and frameFirstChangedLine < 40 and (videoout_out.DisplayHeightReal - frameLastChangedLine) < 30) then 
                     if (frameFastCount < 3) then
                        frameFastCount <= frameFastCount + 1;
                     else
                        frameFastmode <= interlaced480pHack;
                     end if;
                     frameindex_last <= frameindex_current;
                     if (frameindex_current = 2) then
                        frameindex_current <= (others => '0');
                     else
                        frameindex_current <= frameindex_current + 1;
                     end if;
                  end if;
               else
                  frameFastCount <= 0;
                  frameFastmode  <= '0';
               end if;
            end if;
            
            -- fps counter
            if (videoout_reports.irq_VBLANK = '1') then
               fps_vramRange_last <= vramRange;
               if (vramRange /= fps_vramRange_last) then
                  if (fpscountBCD_next(3 downto 0) = x"9") then
                     fpscountBCD_next(7 downto 4) <= fpscountBCD_next(7 downto 4) + 1;
                     fpscountBCD_next(3 downto 0) <= x"0";
                  else
                     fpscountBCD_next(3 downto 0) <= fpscountBCD_next(3 downto 0) + 1;
                  end if;
               end if;
            end if;
            
            if (fps_SecondCounter = 33868799) then
               fps_SecondCounter <= 0;
               fpscountBCD       <= fpscountBCD_next;
               fpscountBCD_next  <= (others => '0');       
            else
               fps_SecondCounter <= fps_SecondCounter + 1;            
            end if;

            -- softreset
            if (softReset = '1') then
               vramRange              <= (others => '0');
               hDisplayRange          <= x"C60260";
               vDisplayRange          <= x"3FC10";
                     
               GPUSTAT_ReverseFlag    <= '0';
               GPUSTAT_HorRes2        <= '0';
               GPUSTAT_HorRes1        <= "00";
               GPUSTAT_VerRes         <= '0';
               GPUSTAT_PalVideoMode   <= isPal;
               GPUSTAT_ColorDepth24   <= '0';
               GPUSTAT_VertInterlace  <= '0';
               GPUSTAT_DisplayDisable <= '1';
               GPUSTAT_IRQRequest     <= '0';
               GPUSTAT_DMADirection   <= "00";

            end if;

         end if;
      end if;
   end process;
   
   video_fbmode <= frameFastmode;
   video_fb24   <= frameFastmode and GPUSTAT_ColorDepth24;
   
   iSyncFifo_IN: entity mem.SyncFifo
   generic map
   (
      --SIZE             => 32, -- 16 is correct, but only allows 15 entries -> use nearfull or allow this big for broken homebrew -> some games seem to exceed it also with DMA, how is that possible?
      SIZE             => 256, -- using larger fifo because of broken homebrew depending on it, shouldn't matter for official games, simply unused there and the full blockram is free anyway
      DATAWIDTH        => 32,
      NEARFULLDISTANCE => 16
   )
   port map
   ( 
      clk      => clk2x,
      reset    => fifoIn_reset,  
      Din      => fifoIn_Din,     
      Wr       => fifoIn_Wr,      
      Full     => ERRORFIFO,    
      NearFull => open,
      Dout     => fifoIn_Dout,    
      Rd       => fifoIn_Rd,      
      Empty    => fifoIn_Empty   
   );
   
   fifoIn_Rd <= '1' when (ce = '1' and (proc_idle = '1' or proc_requestFifo = '1') and pipeline_busy = '0' and fifoIn_Empty = '0' and fifoIn_Valid = '0' and (clk2xIndex = '0' or REPRODUCIBLEGPUTIMING = '0')) else '0';
   
   process (clk2x)
   begin
      if rising_edge(clk2x) then
      
         if (reset = '1') then
            
         elsif (ce = '1') then
         
            fifoIn_Wr  <= '0';
         
            if (clk2xIndex = '1' and bus_write = '1' and bus_addr = 0) then
               fifoIn_Wr  <= '1';
               fifoIn_Din <= bus_dataWrite;
            end if;
            
            if (clk2xIndex = '1' and DMA_GPU_writeEna = '1') then
               fifoIn_Wr  <= '1';
               fifoIn_Din <= DMA_GPU_write;
            end if;
            
         end if;

      end if;
   end process;

   ss_gpu_out(2)(19 downto 0)   <= std_logic_vector(textureWindow);
   ss_gpu_out(4)(9 downto 0)    <= std_logic_vector(drawingAreaLeft);  
   ss_gpu_out(5)(9 downto 0)    <= std_logic_vector(drawingAreaRight); 
   ss_gpu_out(4)(24 downto 16)  <= std_logic_vector(drawingAreaTop);   
   ss_gpu_out(5)(24 downto 16)  <= std_logic_vector(drawingAreaBottom);
   ss_gpu_out(6)(10 downto 0)   <= std_logic_vector(drawingOffsetX);   
   ss_gpu_out(6)(26 downto 16)  <= std_logic_vector(drawingOffsetY);   
   ss_gpu_out(3)(13 downto 0)   <= std_logic_vector(drawMode);         
   ss_gpu_out(3)(16)            <= GPUSTAT_DrawPixelsMask;         
   ss_gpu_out(3)(17)            <= GPUSTAT_TextureDisable;         
   
   process (clk2x)
      variable cmdNew : unsigned(7 downto 0);
   begin
      if rising_edge(clk2x) then
      
         textureWindow_AND_X     <= not (textureWindow(4 downto 0) & "000");
         textureWindow_AND_Y     <= not (textureWindow(9 downto 5) & "000");            
         textureWindow_OR_X      <= (textureWindow(4 downto 0) and textureWindow(14 downto 10)) & "000";
         textureWindow_OR_Y      <= (textureWindow(9 downto 5) and textureWindow(19 downto 15)) & "000";
      
         errorGPU <= '0';
         if (proc_idle = '1') then
            timeout <= 0;
         elsif (timeout < 67108863) then
            timeout  <= timeout + 1;
         else
            errorGPU <= '1';
         end if;
      
         if (reset = '1') then
         
            proc_idle <= '1';
            
            textureWindow           <= unsigned(ss_gpu_in(2)(19 downto 0));   
            
            drawingAreaLeft         <= unsigned(ss_gpu_in(4)(9 downto 0)); 
            drawingAreaRight        <= unsigned(ss_gpu_in(5)(9 downto 0)); 
            drawingAreaTop          <= unsigned(ss_gpu_in(4)(24 downto 16)); 
            drawingAreaBottom       <= unsigned(ss_gpu_in(5)(24 downto 16)); 
            drawingOffsetX          <= signed(ss_gpu_in(6)(10 downto 0)); 
            drawingOffsetY          <= signed(ss_gpu_in(6)(26 downto 16)); 
            
            drawMode                <= unsigned(ss_gpu_in(3)(13 downto 0));  
            
            --GPUSTAT_DrawPixelsMask  <= ss_gpu_in(3)(16);
            --GPUSTAT_TextureDisable  <= ss_gpu_in(3)(17);
            
            GPUSTAT_TextPageX       <= ss_gpu_in(1)(3 downto 0);
            GPUSTAT_TextPageY       <= ss_gpu_in(1)(4);
            GPUSTAT_Transparency    <= ss_gpu_in(1)(6 downto 5);
            GPUSTAT_TextPageColors  <= ss_gpu_in(1)(8 downto 7);
            GPUSTAT_Dither          <= ss_gpu_in(1)(9);
            GPUSTAT_DrawToDisplay   <= ss_gpu_in(1)(10);
            GPUSTAT_SetMask         <= ss_gpu_in(1)(11);
            GPUSTAT_DrawPixelsMask  <= ss_gpu_in(1)(12);
            GPUSTAT_TextureDisable  <= ss_gpu_in(1)(15);
            GPUSTAT_ReadyRecCmd     <= '1'; --ss_gpu_in(1)(26); -- in savestate should never be busy
            GPUSTAT_ReadyRecDMA     <= '1'; --ss_gpu_in(1)(28);
            
            fifoIn_Valid            <= '0';
            
         elsif (ce = '1') then
         
            fifoIn_Valid <= fifoIn_Rd and not fifoIn_reset;
            
            pipeline_clearCacheTexture <= '0';
            pipeline_clearCachePalette <= '0';
         
            if (poly_drawModeNew = '1') then
               drawMode(8 downto 0) <= poly_drawModeRec(8 downto 0);
               drawMode(11)         <= poly_drawModeRec(11);
            end if;
            
            if (clk2xIndex = '1') then
               irq_GPU <= '0';
            end if;
         
            if (fifoIn_Valid = '1' and proc_idle = '1') then
               
               cmdNew := unsigned(fifoIn_Dout(31 downto 24));
               
               if ((cmdNew >= 16#20# and cmdNew <=16#DF#) or cmdNew = 16#02#) then
                  
                  proc_idle           <= '0';
                  GPUSTAT_ReadyRecCmd <= '0';
                  
               elsif (cmdNew = 16#01#) then -- clear cache
                  pipeline_clearCacheTexture <= '1';
                  pipeline_clearCachePalette <= '1';
                  
               elsif (cmdNew = 16#1F#) then -- irq request
                  if (GPUSTAT_IRQRequest = '0') then
                     irq_GPU <= '1';
                  end if;
                  
               elsif (cmdNew = 16#E1#) then -- Draw Mode setting
                  GPUSTAT_TextPageX      <= fifoIn_Dout(3 downto 0);
                  GPUSTAT_TextPageY      <= fifoIn_Dout(4);
                  GPUSTAT_Transparency   <= fifoIn_Dout(6 downto 5);
                  GPUSTAT_TextPageColors <= fifoIn_Dout(8 downto 7);
                  GPUSTAT_Dither         <= fifoIn_Dout(9);
                  GPUSTAT_DrawToDisplay  <= fifoIn_Dout(10);
                  GPUSTAT_TextureDisable <= fifoIn_Dout(11);
                  drawMode               <= unsigned(fifoIn_Dout(13 downto 0));
                  
               elsif (cmdNew = 16#E2#) then -- Set Texture window
                  textureWindow <= unsigned(fifoIn_Dout(19 downto 0));
                  
               elsif (cmdNew = 16#E3#) then -- Set Drawing Area top left (X1,Y1)
                  drawingAreaLeft <= unsigned(fifoIn_Dout(9 downto 0));
                  drawingAreaTop  <= unsigned(fifoIn_Dout(18 downto 10));
                  
               elsif (cmdNew = 16#E4#) then -- Set Drawing Area bottom right (X2,Y2)
                  drawingAreaRight  <= unsigned(fifoIn_Dout(9 downto 0));
                  drawingAreaBottom <= unsigned(fifoIn_Dout(18 downto 10));
                  
               elsif (cmdNew = 16#E5#) then -- Set Drawing Offset (X,Y)
                  drawingOffsetX <= signed(fifoIn_Dout(10 downto 0));
                  drawingOffsetY <= signed(fifoIn_Dout(21 downto 11));
                  
               elsif (cmdNew = 16#E6#) then -- Mask Bit Setting
                  GPUSTAT_SetMask        <= fifoIn_Dout(0);
                  GPUSTAT_DrawPixelsMask <= fifoIn_Dout(1);
                  
               end if;
            
            end if;
            
            if (proc_idle = '1') then
               interlacedDrawing <= GPUSTAT_VertInterlace and GPUSTAT_VerRes and not GPUSTAT_DrawToDisplay;
            end if;

            GPUSTAT_ReadyRecDMA <= fifoIn_Empty;
            
            if (proc_done = '1') then
-- synthesis translate_off
               export_gobj          <= export_gobj + 1;
-- synthesis translate_on
               proc_idle            <= '1';
               GPUSTAT_ReadyRecCmd  <= '1';
            end if;
            
            if (vramFill_done = '1' or cpu2vram_done = '1' or vram2vram_done = '1') then
               pipeline_clearCacheTexture <= '1';
            end if;
            
            if (softReset = '1') then
               proc_idle              <= '1';
               drawMode               <= (others => '0');
               GPUSTAT_TextPageX      <= "0000";
               GPUSTAT_TextPageY      <= '0';
               GPUSTAT_Transparency   <= "00";
               GPUSTAT_TextPageColors <= "00";
               GPUSTAT_Dither         <= '0';
               GPUSTAT_DrawToDisplay  <= '0';
               GPUSTAT_SetMask        <= '0';
               GPUSTAT_DrawPixelsMask <= '0';
               GPUSTAT_TextureDisable <= '0';
               GPUSTAT_ReadyRecCmd    <= '1';
               GPUSTAT_ReadyRecDMA    <= '1';
               drawingAreaLeft        <= (others => '0');
               drawingAreaTop         <= (others => '0');
               drawingAreaRight       <= (others => '0');
               drawingAreaBottom      <= (others => '0');
               drawingOffsetX         <= (others => '0');
               drawingOffsetY         <= (others => '0');
            end if;
            
         end if;
         
      end if;
   end process; 
   
   proc_done        <= vramFill_done        or cpu2vram_done        or vram2vram_done        or vram2cpu_done        or line_done        or rect_done        or poly_done       ;
   --proc_CmdDone     <= vramFill_CmdDone     or cpu2vram_CmdDone     or vram2vram_CmdDone     or vram2cpu_CmdDone     or line_CmdDone     or rect_CmdDone     or poly_CmdDone    ;
   proc_requestFifo <= vramFill_requestFifo or cpu2vram_requestFifo or vram2vram_requestFifo or vram2cpu_requestFifo or line_requestFifo or rect_requestFifo or poly_requestFifo;
   
   pixelStall <= fifoOut_NearFull;
   
   -- workers
   igpu_fillVram : entity work.gpu_fillVram
   port map
   (
      clk2x                => clk2x,     
      clk2xIndex           => clk2xIndex,
      ce                   => ce,        
      reset                => softreset or SS_reset, 

      REPRODUCIBLEGPUTIMING=> REPRODUCIBLEGPUTIMING,      
      
      interlacedDrawing    => interlacedDrawing and (not interlaced480pHack),
      activeLineLSB        => videoout_reports.activeLineLSB,    
      
      proc_idle            => proc_idle,
      fifo_Valid           => fifoIn_Valid, 
      fifo_data            => fifoIn_Dout,
      requestFifo          => vramFill_requestFifo,
      done                 => vramFill_done,
      --CmdDone              => vramFill_CmdDone,
      
      pixelStall           => pixelStall,
      pixelColor           => vramFill_pixelColor,
      pixelAddr            => vramFill_pixelAddr, 
      pixelWrite           => vramFill_pixelWrite
   );
   
   igpu_cpu2vram : entity work.gpu_cpu2vram
   port map
   (
      clk2x                => clk2x,     
      clk2xIndex           => clk2xIndex,
      ce                   => ce,        
      reset                => softreset or SS_reset,    
      drawer_reset         => drawer_reset,
      
      DrawPixelsMask       => GPUSTAT_DrawPixelsMask,
      SetMask              => GPUSTAT_SetMask,
      errorMASK            => errorMASK,
      
      proc_idle            => proc_idle,
      fifo_Valid           => fifoIn_Valid, 
      fifo_data            => fifoIn_Dout,
      requestFifo          => cpu2vram_requestFifo,
      done                 => cpu2vram_done,
      --CmdDone              => cpu2vram_CmdDone,
      
      pixelStall           => pixelStall,
      pixelColor           => cpu2vram_pixelColor,
      pixelAddr            => cpu2vram_pixelAddr, 
      pixelWrite           => cpu2vram_pixelWrite
   );
   
   igpu_vram2vram : entity work.gpu_vram2vram
   port map
   (
      clk2x                => clk2x,     
      clk2xIndex           => clk2xIndex,
      ce                   => ce,        
      reset                => softreset or SS_reset,     
      
      DrawPixelsMask       => GPUSTAT_DrawPixelsMask,
      SetMask              => GPUSTAT_SetMask,
      
      REPRODUCIBLEGPUTIMING=> REPRODUCIBLEGPUTIMING,  
      
      proc_idle            => proc_idle,
      fifo_Valid           => fifoIn_Valid, 
      fifo_data            => fifoIn_Dout,
      requestFifo          => vram2vram_requestFifo,
      done                 => vram2vram_done,
      --CmdDone              => vram2vram_CmdDone,
      
      pipeline_busy        => pipeline_busy,
      fifoOut_idle         => fifoOut_idle,
      requestVRAMEnable    => vram2vram_reqVRAMEnable,
      requestVRAMXPos      => vram2vram_reqVRAMXPos,  
      requestVRAMYPos      => vram2vram_reqVRAMYPos,  
      requestVRAMSize      => vram2vram_reqVRAMSize,  
      requestVRAMIdle      => reqVRAMIdle,
      requestVRAMDone      => reqVRAMDone,
      
      vramLineEna          => vram2vram_vramLineEna, 
      vramLineAddr         => vram2vram_vramLineAddr,
      vramLineData         => vramLineData,
      
      pixelEmpty           => fifoOut_Empty,
      pixelStall           => pixelStall,
      pixelColor           => vram2vram_pixelColor,
      pixelAddr            => vram2vram_pixelAddr, 
      pixelWrite           => vram2vram_pixelWrite
   );
   
   vram2cpu_Fifo_Rd <= '1' when (vram2cpu_Fifo_Empty = '0' and clk2xIndex = '0' and DMA_GPU_readEna = '1') else
                       '1' when (vram2cpu_Fifo_Empty = '0' and clk2xIndex = '0' and bus_read = '1' and bus_addr(3 downto 2) = "00") else
                       '1' when (vram2cpu_Fifo_Empty = '0' and clk2xIndex = '0' and bus_stall = '1') else
                       '0';
   
   DMA_GPU_read <= vram2cpu_Fifo_Dout when (vram2cpu_Fifo_Empty = '0') else (others => '1');
   
   GPUSTAT_ReadySendVRAM <= not vram2cpu_Fifo_Empty;
   
   igpu_vram2cpu : entity work.gpu_vram2cpu
   port map
   (
      clk2x                => clk2x,     
      ce                   => ce,        
      reset                => softreset or SS_reset,   
      drawer_reset         => drawer_reset,

      REPRODUCIBLEGPUTIMING=> REPRODUCIBLEGPUTIMING, 

      proc_idle            => proc_idle,
      fifo_Valid           => fifoIn_Valid, 
      fifo_data            => fifoIn_Dout,
      requestFifo          => vram2cpu_requestFifo,
      done                 => vram2cpu_done,
      --CmdDone              => vram2cpu_CmdDone,
      
      pipeline_busy        => pipeline_busy,
      fifoOut_idle         => fifoOut_idle,
      requestVRAMEnable    => vram2cpu_reqVRAMEnable,
      requestVRAMXPos      => vram2cpu_reqVRAMXPos,  
      requestVRAMYPos      => vram2cpu_reqVRAMYPos,  
      requestVRAMSize      => vram2cpu_reqVRAMSize,  
      requestVRAMIdle      => reqVRAMIdle,
      requestVRAMDone      => reqVRAMDone,
      
      vramLineEna          => vram2cpu_vramLineEna, 
      vramLineAddr         => vram2cpu_vramLineAddr,
      vramLineData         => vramLineData,
      
      Fifo_Dout            => vram2cpu_Fifo_Dout, 
      Fifo_Rd              => vram2cpu_Fifo_Rd,   
      Fifo_Empty           => vram2cpu_Fifo_Empty,
      Fifo_ready           => vram2cpu_Fifo_ready
   );
   
   igpu_line : entity work.gpu_line
   port map
   (
      clk2x                => clk2x,     
      clk2xIndex           => clk2xIndex,
      ce                   => ce,        
      reset                => softreset or SS_reset,

      REPRODUCIBLEGPUTIMING=> REPRODUCIBLEGPUTIMING,

      error                => errorLINE,
      
      DrawPixelsMask       => GPUSTAT_DrawPixelsMask,
      interlacedDrawing    => interlacedDrawing and (not interlaced480pHack),
      activeLineLSB        => videoout_reports.activeLineLSB,    
      drawingOffsetX       => drawingOffsetX,   
      drawingOffsetY       => drawingOffsetY,   
      drawingAreaLeft      => drawingAreaLeft,  
      drawingAreaRight     => drawingAreaRight, 
      drawingAreaTop       => drawingAreaTop,   
      drawingAreaBottom    => drawingAreaBottom,
      
      div1                 => line_div(0), 
      div2                 => line_div(1), 
      div3                 => line_div(2), 
      div4                 => line_div(3), 
      div5                 => line_div(4), 
      div6                 => line_div(5), 
      
      fifoOut_idle         => fifoOut_idle,
      pipeline_busy        => pipeline_busy,
      pipeline_stall       => pipeline_stall,      
      pipeline_new         => line_pipeline_new,        
      pipeline_transparent => line_pipeline_transparent,
      pipeline_x           => line_pipeline_x,          
      pipeline_y           => line_pipeline_y,          
      pipeline_cr          => line_pipeline_cr,         
      pipeline_cg          => line_pipeline_cg,         
      pipeline_cb          => line_pipeline_cb,         
      
      proc_idle            => proc_idle,
      fifo_Valid           => fifoIn_Valid, 
      fifo_data            => fifoIn_Dout,
      requestFifo          => line_requestFifo,
      done                 => line_done,
      --CmdDone              => line_CmdDone,
      
      requestVRAMEnable    => line_reqVRAMEnable,
      requestVRAMXPos      => line_reqVRAMXPos,  
      requestVRAMYPos      => line_reqVRAMYPos,  
      requestVRAMSize      => line_reqVRAMSize,  
      requestVRAMIdle      => reqVRAMIdle,
      requestVRAMDone      => reqVRAMDone,
      
      vramLineEna          => line_vramLineEna, 
      vramLineAddr         => line_vramLineAddr
   );
   
   igpu_rect : entity work.gpu_rect
   port map
   (
      clk2x                => clk2x,  
      clk2xIndex           => clk2xIndex,      
      ce                   => ce,        
      reset                => softreset or SS_reset,     
      
      REPRODUCIBLEGPUTIMING=> REPRODUCIBLEGPUTIMING,
      
      error                => errorRECT,
      
      DrawPixelsMask       => GPUSTAT_DrawPixelsMask,
      interlacedDrawing    => interlacedDrawing and (not interlaced480pHack),
      activeLineLSB        => videoout_reports.activeLineLSB,    
      drawingOffsetX       => drawingOffsetX,   
      drawingOffsetY       => drawingOffsetY,   
      drawingAreaLeft      => drawingAreaLeft,  
      drawingAreaRight     => drawingAreaRight, 
      drawingAreaTop       => drawingAreaTop,   
      drawingAreaBottom    => drawingAreaBottom,
      
      fifoOut_idle         => fifoOut_idle,
      pipeline_busy        => pipeline_busy,
      pipeline_stall       => pipeline_stall,      
      pipeline_new         => rect_pipeline_new,        
      pipeline_texture     => rect_pipeline_texture,
      pipeline_transparent => rect_pipeline_transparent,
      pipeline_rawTexture  => rect_pipeline_rawTexture,
      pipeline_x           => rect_pipeline_x,          
      pipeline_y           => rect_pipeline_y,          
      pipeline_cr          => rect_pipeline_cr,         
      pipeline_cg          => rect_pipeline_cg,         
      pipeline_cb          => rect_pipeline_cb,         
      pipeline_u           => rect_pipeline_u,         
      pipeline_v           => rect_pipeline_v,         
      
      proc_idle            => proc_idle,
      fifo_Valid           => fifoIn_Valid, 
      fifo_data            => fifoIn_Dout,
      requestFifo          => rect_requestFifo,
      done                 => rect_done,
      --CmdDone              => rect_CmdDone,
      
      requestVRAMEnable    => rect_reqVRAMEnable,
      requestVRAMXPos      => rect_reqVRAMXPos,  
      requestVRAMYPos      => rect_reqVRAMYPos,  
      requestVRAMSize      => rect_reqVRAMSize,  
      requestVRAMIdle      => reqVRAMIdle,
      requestVRAMDone      => reqVRAMDone,
      
      textPalNew           => rect_textPalNew,
      textPalX             => rect_textPalX,  
      textPalY             => rect_textPalY,  
      
      vramLineEna          => rect_vramLineEna, 
      vramLineAddr         => rect_vramLineAddr
   );
   
   igpu_poly : entity work.gpu_poly
   port map
   (
      clk2x                => clk2x,     
      clk2xIndex           => clk2xIndex,
      ce                   => ce,        
      reset                => softreset or SS_reset,   

      REPRODUCIBLEGPUTIMING=> REPRODUCIBLEGPUTIMING,    
      textureFilter        => textureFilter,
      textureFilterStrength=> textureFilterStrength,
      textureFilter2DOff   => textureFilter2DOff,

      error                => errorPOLY,
      
      DrawPixelsMask       => GPUSTAT_DrawPixelsMask,
      interlacedDrawing    => interlacedDrawing and (not interlaced480pHack),
      activeLineLSB        => videoout_reports.activeLineLSB,    
      drawingOffsetX       => drawingOffsetX,   
      drawingOffsetY       => drawingOffsetY,   
      drawingAreaLeft      => drawingAreaLeft,  
      drawingAreaRight     => drawingAreaRight, 
      drawingAreaTop       => drawingAreaTop,   
      drawingAreaBottom    => drawingAreaBottom,
      
      drawModeRec          => poly_drawModeRec,
      drawModeNew          => poly_drawModeNew,
      drawmode_dithering   => drawMode(9),
      
      div1                 => poly_div(0), 
      div2                 => poly_div(1), 
      div3                 => poly_div(2), 
      div4                 => poly_div(3), 
      div5                 => poly_div(4), 
      div6                 => poly_div(5), 
      
      fifoOut_idle         => fifoOut_idle,
      pipeline_busy        => pipeline_busy,
      pipeline_stall       => pipeline_stall,      
      pipeline_new         => poly_pipeline_new,        
      pipeline_texture     => poly_pipeline_texture,
      pipeline_transparent => poly_pipeline_transparent,
      pipeline_rawTexture  => poly_pipeline_rawTexture,
      pipeline_dithering   => poly_pipeline_dithering,
      pipeline_x           => poly_pipeline_x,          
      pipeline_y           => poly_pipeline_y,          
      pipeline_cr          => poly_pipeline_cr,         
      pipeline_cg          => poly_pipeline_cg,         
      pipeline_cb          => poly_pipeline_cb,         
      pipeline_u           => poly_pipeline_u,         
      pipeline_v           => poly_pipeline_v, 
      pipeline_filter      => pipeline_filter,
      pipeline_u11         => poly_pipeline_u11,   
      pipeline_v11         => poly_pipeline_v11,         
      pipeline_uAcc        => pipeline_uAcc,
      pipeline_vAcc        => pipeline_vAcc,
      
      proc_idle            => proc_idle,
      fifo_Valid           => fifoIn_Valid, 
      fifo_data            => fifoIn_Dout,
      requestFifo          => poly_requestFifo,
      done                 => poly_done,
      --CmdDone              => poly_CmdDone,
      
      requestVRAMEnable    => poly_reqVRAMEnable,
      requestVRAMXPos      => poly_reqVRAMXPos,  
      requestVRAMYPos      => poly_reqVRAMYPos,  
      requestVRAMSize      => poly_reqVRAMSize,  
      requestVRAMIdle      => reqVRAMIdle,
      requestVRAMDone      => reqVRAMDone,
      
      textPalNew           => poly_textPalNew,
      textPalX             => poly_textPalX,  
      textPalY             => poly_textPalY,  
      
      vramLineEna          => poly_vramLineEna, 
      vramLineAddr         => poly_vramLineAddr
   );
   
   pipeline_new         <= line_pipeline_new         or rect_pipeline_new         or poly_pipeline_new        ;       
   pipeline_texture     <= '0'                       or rect_pipeline_texture     or poly_pipeline_texture    ;
   pipeline_transparent <= line_pipeline_transparent or rect_pipeline_transparent or poly_pipeline_transparent;          
   pipeline_rawTexture  <= '0'                       or rect_pipeline_rawTexture  or poly_pipeline_rawTexture ; 
   pipeline_dithering   <= (line_pipeline_new        or '0'                       or poly_pipeline_dithering  ) and drawMode(9) and (not ditherOff);
   pipeline_x           <= line_pipeline_x           or rect_pipeline_x           or poly_pipeline_x          ;       
   pipeline_y           <= line_pipeline_y           or rect_pipeline_y           or poly_pipeline_y          ;     
   pipeline_cr          <= line_pipeline_cr          or rect_pipeline_cr          or poly_pipeline_cr         ;
   pipeline_cg          <= line_pipeline_cg          or rect_pipeline_cg          or poly_pipeline_cg         ;
   pipeline_cb          <= line_pipeline_cb          or rect_pipeline_cb          or poly_pipeline_cb         ;
   
   pipeline_u           <= ((rect_pipeline_u or poly_pipeline_u) and textureWindow_AND_X) or textureWindow_OR_X;
   pipeline_v           <= ((rect_pipeline_v or poly_pipeline_v) and textureWindow_AND_Y) or textureWindow_OR_Y;
   
   pipeline_u11         <= (poly_pipeline_u11 and textureWindow_AND_X) or textureWindow_OR_X;
   pipeline_v11         <= (poly_pipeline_v11 and textureWindow_AND_Y) or textureWindow_OR_Y;
   
   
   pipeline_textPalNew  <= rect_textPalNew or poly_textPalNew;
   pipeline_textPalX    <= rect_textPalX   or poly_textPalX  ;
   pipeline_textPalY    <= rect_textPalY   or poly_textPalY  ;
   
   igpu_pixelpipeline : entity work.gpu_pixelpipeline
   port map
   (
      clk2x                => clk2x,     
      clk2xIndex           => clk2xIndex,
      ce                   => ce,        
      reset                => softreset or SS_reset,

      noTexture            => noTexture,     
      render24             => render24,
      drawSlow             => drawSlow,

      drawMode_in          => drawMode,
      DrawPixelsMask_in    => GPUSTAT_DrawPixelsMask,
      SetMask_in           => GPUSTAT_SetMask,
      
      clearCacheTexture    => pipeline_clearCacheTexture,
      clearCachePalette    => pipeline_clearCachePalette,
      
      fifoOut_idle         => fifoOut_idle,
      pipeline_busy        => pipeline_busy,
      pipeline_stall       => pipeline_stall,      
      pipeline_new         => pipeline_new,        
      pipeline_texture     => pipeline_texture,    
      pipeline_transparent => pipeline_transparent,
      pipeline_rawTexture  => pipeline_rawTexture, 
      pipeline_dithering   => pipeline_dithering,
      pipeline_x           => pipeline_x,          
      pipeline_y           => pipeline_y,          
      pipeline_cr          => pipeline_cr,         
      pipeline_cg          => pipeline_cg,         
      pipeline_cb          => pipeline_cb,         
      pipeline_u           => pipeline_u,          
      pipeline_v           => pipeline_v, 
      pipeline_filter      => pipeline_filter,
      pipeline_u11         => pipeline_u11,   
      pipeline_v11         => pipeline_v11, 
      pipeline_uAcc        => pipeline_uAcc,
      pipeline_vAcc        => pipeline_vAcc,      
      
      requestVRAMEnable    => pipeline_reqVRAMEnable,
      requestVRAMXPos      => pipeline_reqVRAMXPos,  
      requestVRAMYPos      => pipeline_reqVRAMYPos,  
      requestVRAMSize      => pipeline_reqVRAMSize,  
      requestVRAMIdle      => reqVRAMIdle,
      requestVRAMDone      => reqVRAMDone,
      vram_DOUT            => vram_DOUT,      
      vram_DOUT_READY      => vram_DOUT_READY,
      
      vramLineData         => vramLineData,
      vramLineData2        => vramLineData2,
      
      textPalInNew         => pipeline_textPalNew,
      textPalInX           => pipeline_textPalX,  
      textPalInY           => pipeline_textPalY,  
      
      pixelStall           => pixelStall,
      pixelColor           => pipeline_pixelColor,
      pixelColor2          => pipeline_pixelColor2,
      pixelAddr            => pipeline_pixelAddr, 
      pixelWrite           => pipeline_pixelWrite
   );
   
   gdividers: for i in 0 to 5 generate
   begin
   
      div_array(i).start    <= line_div(i).start    or poly_div(i).start;
      div_array(i).dividend <= line_div(i).dividend or poly_div(i).dividend;
      div_array(i).divisor  <= line_div(i).divisor  or poly_div(i).divisor;
      
      line_div(i).done      <= div_array(i).done;     
      line_div(i).quotient  <= div_array(i).quotient; 
      line_div(i).remainder <= div_array(i).remainder;
      
      poly_div(i).done      <= div_array(i).done;     
      poly_div(i).quotient  <= div_array(i).quotient; 
      poly_div(i).remainder <= div_array(i).remainder;
      
      idivider : entity work.divider
      port map
      (
         clk       => clk2x,      
         start     => div_array(i).start,
         done      => div_array(i).done,          
         dividend  => div_array(i).dividend, 
         divisor   => div_array(i).divisor,  
         quotient  => div_array(i).quotient, 
         remainder => div_array(i).remainder
      );
   end generate;
   
   pixelColor  <= cpu2vram_pixelColor or vram2vram_pixelColor or pipeline_pixelColor;
   pixelColor2 <=                                                pipeline_pixelColor2;
   pixelAddr   <= cpu2vram_pixelAddr  or vram2vram_pixelAddr  or pipeline_pixelAddr ;
   pixelWrite  <= cpu2vram_pixelWrite or vram2vram_pixelWrite or pipeline_pixelWrite;
   
   -- pixel writing fifo
   iSyncFifo_OUT: entity mem.SyncFifoFallThrough
   generic map
   (
      SIZE             => 256,
      DATAWIDTH        => 64 + 17 + 4 + 1,  -- 64bit data + 17 bit address + 4bit word enable + 1bit source=pipeline
      NEARFULLDISTANCE => 250
   )
   port map
   ( 
      clk      => clk2x,
      reset    => fifoOut_reset,  
      Din      => fifoOut_Din,     
      Wr       => fifoOut_Wr,      
      Full     => open,    
      NearFull => fifoOut_NearFull,
      Dout     => fifoOut_Dout,    
      Rd       => fifoOut_Rd,      
      Empty    => fifoOut_Empty   
   );
   
   iSyncFifo_OUT2: entity mem.SyncFifoFallThrough
   generic map
   (
      SIZE             => 256,
      DATAWIDTH        => 64,
      NEARFULLDISTANCE => 250
   )
   port map
   ( 
      clk      => clk2x,
      reset    => fifoOut_reset,  
      Din      => fifoOut2_Din,     
      Wr       => fifoOut_Wr,      
      Full     => open,    
      NearFull => open,
      Dout     => fifoOut2_Dout,    
      Rd       => fifoOut_Rd,      
      Empty    => open
   );
   
   process (clk2x)
   begin
      if rising_edge(clk2x) then
      
         fifoOut_Wr_1 <= fifoOut_Wr;
      
         fifoOut_Wr   <= '0';
         fifoOut_Din  <= pixel64source & pixel64wordEna & pixel64Addr & pixel64data;
         
         fifoOut2_Din <= pixel64data2;
      
         if (reset = '1') then
            
            pixel64filled <= '0';
            
         elsif (ce = '1') then
         
            if (vramFill_pixelWrite = '1') then
            
               fifoOut_Wr    <= '1';
               fifoOut_Din   <=  '1' & "1111" & std_logic_vector(vramFill_pixelAddr(19 downto 3)) & vramFill_pixelColor & vramFill_pixelColor & vramFill_pixelColor & vramFill_pixelColor;
               pixel64filled <= '0';
         
               fifoOut2_Din  <= x"0000000000000000";
         
            elsif (pixelWrite = '1') then
            
               pixel64timeout <= 15;
            
               if (pixel64filled = '0' or pixelAddr(19 downto 3) /= unsigned(pixel64Addr)) then
               
                  fifoOut_Wr <= pixel64filled;
               
                  pixel64Addr <= std_logic_vector(pixelAddr(19 downto 3));
                  case (pixelAddr(2 downto 1)) is
                     when "00" => pixel64data(15 downto  0) <= pixelColor; pixel64data2(15 downto  0) <= pixelColor2; pixel64wordEna <= "0001";
                     when "01" => pixel64data(31 downto 16) <= pixelColor; pixel64data2(31 downto 16) <= pixelColor2; pixel64wordEna <= "0010";
                     when "10" => pixel64data(47 downto 32) <= pixelColor; pixel64data2(47 downto 32) <= pixelColor2; pixel64wordEna <= "0100";
                     when "11" => pixel64data(63 downto 48) <= pixelColor; pixel64data2(63 downto 48) <= pixelColor2; pixel64wordEna <= "1000";
                     when others => null;
                  end case;
                  
                  pixel64filled <= '1';
               
               else
                  
                  case (pixelAddr(2 downto 1)) is
                     when "00" => pixel64data(15 downto  0) <= pixelColor; pixel64data2(15 downto  0) <= pixelColor2; pixel64wordEna(0) <= '1';
                     when "01" => pixel64data(31 downto 16) <= pixelColor; pixel64data2(31 downto 16) <= pixelColor2; pixel64wordEna(1) <= '1';
                     when "10" => pixel64data(47 downto 32) <= pixelColor; pixel64data2(47 downto 32) <= pixelColor2; pixel64wordEna(2) <= '1';
                     when "11" => pixel64data(63 downto 48) <= pixelColor; pixel64data2(63 downto 48) <= pixelColor2; pixel64wordEna(3) <= '1';
                     when others => null;
                  end case;

               end if;
               
               pixel64source <= pipeline_pixelWrite;
            
            elsif (pixel64timeout > 0) then
            
               pixel64timeout <= pixel64timeout - 1;
               if (pixel64timeout = 1 or pipeline_busy = '0') then
                  pixel64filled  <= '0';
                  fifoOut_Wr     <= '1';
                  pixel64timeout <= 0;
               end if;
               
            end if;
            
         end if;

      end if;
   end process;
   
   fifoOut_Rd <= '1' when (ce = '1' and vramState = IDLE and (vram_WE = '0' or vram_BUSY = '0') and fifoOut_Empty = '0' and reqVRAMEnable = '0' and vram_pause = '0') else '0';
   
   fifoOut_idle <= '1' when (fifoOut_Empty = '1' and fifoOut_Wr = '0' and fifoOut_Wr_1 = '0' and pixel64filled = '0') else '0';
   
   VRAMIdle    <= '1' when (vramState = IDLE and (vram_WE = '0' or vram_BUSY = '0')) else '0';
   reqVRAMIdle <= VRAMIdle and (not videoout_reqVRAMEnable) and (not vram_pause);
   
   reqVRAMEnable <= vram2vram_reqVRAMEnable or vram2cpu_reqVRAMEnable or line_reqVRAMEnable or rect_reqVRAMEnable or poly_reqVRAMEnable or pipeline_reqVRAMEnable or videoout_reqVRAMEnable;
   reqVRAMXPos   <= vram2vram_reqVRAMXPos   or vram2cpu_reqVRAMXPos   or line_reqVRAMXPos   or rect_reqVRAMXPos   or poly_reqVRAMXPos   or pipeline_reqVRAMXPos   or videoout_reqVRAMXPos  ;  
   reqVRAMYPos   <= vram2vram_reqVRAMYPos   or vram2cpu_reqVRAMYPos   or line_reqVRAMYPos   or rect_reqVRAMYPos   or poly_reqVRAMYPos   or pipeline_reqVRAMYPos   or videoout_reqVRAMYPos  ;  
   reqVRAMSize   <= vram2vram_reqVRAMSize   or vram2cpu_reqVRAMSize   or line_reqVRAMSize   or rect_reqVRAMSize   or poly_reqVRAMSize   or pipeline_reqVRAMSize   or videoout_reqVRAMSize  ;  
   
   vramLineAddr  <= vram2vram_vramLineAddr when vram2vram_vramLineEna else 
                    vram2cpu_vramLineAddr when vram2cpu_vramLineEna else 
                    line_vramLineAddr  when line_vramLineEna else
                    rect_vramLineAddr  when rect_vramLineEna else
                    poly_vramLineAddr  when poly_vramLineEna else
                    (others => '0');
   
   video_frameindex <= "01" & std_logic_vector(frameindex_last) when (interlaced480pHack = '1') else x"0";
   
   -- vram access
   process (clk2x)
      variable reqVRAMSizeRounded : unsigned(10 downto 0);
   begin
      if rising_edge(clk2x) then
      
         if (vram_BUSY = '0') then
            vram_WE <= '0';
            vram_RD <= '0';
         end if;
         
         vram_paused <= '0';
         if (VRAMIdle = '1' and vram_pause = '1' and vram_WE = '0') then
            if (vram_pauseCnt = 3) then
               vram_paused <= '1';
            else
               vram_pauseCnt <= vram_pauseCnt + 1;
            end if;
         else
            vram_pauseCnt <= 0;
         end if;
         
         if (videoout_reports.irq_VBLANK = '1' and irq_VBLANK_1 = '0') then
            if (frameFastCount > 0 and interlaced480pHack = '1') then
               frameClearRequest <= '1';
               frameClearYPos    <= videoout_out.DisplayOffsetY;
               frameClearCnt     <= (others => '0');
               frameClearPosLow  <= frameFirstChangedLine;
               frameClearPosHigh <= frameLastChangedLine;
            end if;
         end if;
         
         if (reset = '1') then
            
            vramState   <= IDLE;
            reqVRAMDone <= '0';
            
         else
         
            reqVRAMDone <= '0';
         
            case (vramState) is
               when IDLE =>
                  if ((ce = '1' or (videoout_reqVRAMEnable = '1' and savestate_busy = '0')) and (vram_WE = '0' or vram_BUSY = '0') and vram_pause = '0') then
                     if (reqVRAMEnable = '1') then
                        reqVRAMStore  <= (not pipeline_reqVRAMEnable) and (not videoout_reqVRAMEnable);
                        reqVRAMSizeRounded := reqVRAMSize;
                        if (reqVRAMSize(1 downto 0) /= "00") then -- round up read size to full 4*16bit
                           reqVRAMSizeRounded(10 downto 2) := reqVRAMSizeRounded(10 downto 2) + 1;
                        end if;
                        if (reqVRAMXPos(1 downto 0) /= "00" and ((to_integer(reqVRAMXPos(1 downto 0)) + to_integer(reqVRAMSize) > 4))) then 
                           reqVRAMSizeRounded(10 downto 2) := reqVRAMSizeRounded(10 downto 2) + 1;
                        end if;
                        if (reqVRAMSizeRounded > 1024) then reqVRAMSizeRounded := to_unsigned(1024, 11); end if;
                        vramState     <= READVRAM;
                        vram_ADDR     <= x"00" & std_logic_vector(reqVRAMYPos) & std_logic_vector(reqVRAMXPos(9 downto 2)) & "000";
                        if (videoout_reqVRAMEnable = '1' and videoout_reqRAMMirror = '1') then
                           vram_ADDR(27 downto 20) <= x"04";
                        end if;
                        reqVRAMtwice   <= '0';
                        reqVRAMStore2  <= '0';
                        if (render24 = '1' and (line_reqVRAMEnable = '1' or rect_reqVRAMEnable = '1' or poly_reqVRAMEnable = '1')) then
                           vramState               <= READSECOND;
                           reqVRAMStore2           <= '1';
                           reqVRAMtwice            <= '1';  
                           vram_ADDR(27 downto 20) <= x"04";
                        end if;
                        vram_RD       <= '1';
                        reqVRAMaddr   <= reqVRAMXPos(9 downto 2);
                        reqVRAMaddr2  <= reqVRAMXPos(9 downto 2);
                        if (reqVRAMSizeRounded > 512) then
                           vram_BURSTCNT  <= x"80";
                           reqVRAMremain  <= x"80" - 1;
                           reqVRAMremain2 <= x"80" - 1;
                           reqVRAMnext    <= resize((reqVRAMSizeRounded - 512) / 4, 8);
                        else
                           vram_BURSTCNT  <= std_logic_vector(reqVRAMSizeRounded(9 downto 2));
                           reqVRAMremain  <= reqVRAMSizeRounded(9 downto 2) - 1;
                           reqVRAMremain2 <= reqVRAMSizeRounded(9 downto 2) - 1;
                           reqVRAMnext    <= (others => '0');
                        end if;
                        reqVRAMwrap <= (others => '0');
                        if (vram2vram_reqVRAMEnable = '1' or vram2cpu_reqVRAMEnable = '1') then
                           if (reqVRAMXPos + reqVRAMSizeRounded > 1024) then
                              reqVRAMwrap <= resize(((reqVRAMXPos + reqVRAMSizeRounded) - 1024) / 4, 8);
                           end if;
                        end if;
                     elsif (fifoOut_Empty = '0') then
                        if (render24 = '1' or interlaced480pHack = '1') then
                           vramState   <= WRITESECOND;
                        end if;
                        vram_WE         <= '1';
                        vram_ADDR       <= x"00" & fifoOut_Dout(80 downto 64) & "000";
                        vram_BE         <= fifoOut_Dout(84) & fifoOut_Dout(84) & fifoOut_Dout(83) & fifoOut_Dout(83) & fifoOut_Dout(82) & fifoOut_Dout(82) & fifoOut_Dout(81) & fifoOut_Dout(81);
                        vram_DIN        <= fifoOut_Dout(63 downto 0);
                        vram_BURSTCNT   <= x"01";
                        frameVramType   <= fifoOut_Dout(85);
                        fifoOut2_Dout_1 <= fifoOut2_Dout;
                        if (interlacedDrawing = '1' and interlaced480pHack = '1' and videoout_reports.activeLineLSB = fifoOut_Dout(72) and fifoOut_Dout(85) = '1') then
                           vram_WE    <= '0';
                        end if;
                     elsif (frameClearRequest = '1' and SS_Idle = '1') then
                        vramState      <= CLEARLINESTART;
                     end if;
                  end if;
                  
               when WRITESECOND =>
                  if (vram_BUSY = '0') then
                     vramState     <= IDLE;
                     vram_WE       <= '1';
                     if (render24 = '1') then
                        vram_ADDR(27 downto 20) <= x"04";
                        vram_DIN      <= fifoOut2_Dout_1;
                     elsif (interlaced480pHack = '1') then
                        vram_ADDR(27 downto 20) <= "000001" & std_logic_vector(frameindex_current);
                     end if;
                  end if;
                  
               when READSECOND =>
                  if (vram_DOUT_READY = '1') then
                     reqVRAMaddr2 <= reqVRAMaddr2 + 1;
                     if (reqVRAMremain2 > 0) then
                        reqVRAMremain2 <= reqVRAMremain2 - 1;
                     else
                        vramState               <= READVRAM;
                        reqVRAMStore2           <= '0';
                        vram_RD                 <= '1';
                        vram_ADDR(27 downto 20) <= x"00";
                     end if;
                  end if;
                  
               when READVRAM =>
                  if (vram_DOUT_READY = '1') then
                     reqVRAMaddr <= reqVRAMaddr + 1;
                     if (reqVRAMremain > 0) then
                        reqVRAMremain <= reqVRAMremain - 1;
                     else
                        if (reqVRAMtwice = '1') then
                           vramState               <= READSECOND;
                           reqVRAMStore2           <= '1';
                           vram_ADDR(27 downto 20) <= x"04";
                        end if;
                        if (reqVRAMnext > 0) then
                           vram_ADDR(10)  <= '1';
                           vram_RD        <= '1';
                           vram_BURSTCNT  <= std_logic_vector(reqVRAMnext);
                           reqVRAMnext    <= (others => '0');
                           reqVRAMremain  <= (reqVRAMnext - 1);
                           reqVRAMremain2 <= (reqVRAMnext - 1);
                        elsif (reqVRAMwrap > 0) then
                           vram_ADDR(10 downto 0) <= (others => '0');
                           vram_RD        <= '1';
                           vram_BURSTCNT  <= std_logic_vector(reqVRAMwrap);
                           reqVRAMwrap    <= (others => '0');
                           reqVRAMaddr    <= (others => '0');
                           reqVRAMremain  <= (reqVRAMwrap - 1);
                           reqVRAMremain2 <= (reqVRAMwrap - 1);
                           if (reqVRAMwrap > 128) then
                              vram_BURSTCNT  <= x"80";
                              reqVRAMremain  <= x"80" - 1;
                              reqVRAMremain2 <= x"80" - 1;
                              reqVRAMnext    <= reqVRAMwrap - 128;
                           end if;
                        else
                           vramState   <= IDLE;
                           reqVRAMDone <= '1';
                        end if;
                     end if;
                  end if;
                  
               when CLEARLINESTART =>
                  vramState      <= IDLE;
                  frameClearCnt  <= frameClearCnt + 1;
                  frameClearXPos <= videoout_out.DisplayOffsetX(9 downto 2) & "00";
                  if (frameClearCnt = videoout_out.DisplayHeightReal) then
                     frameClearRequest <= '0';
                  elsif (frameClearCnt < frameClearPosLow or frameClearCnt > frameClearPosHigh) then
                     vramState      <= CLEARLINE;
                  else
                     frameClearYPos <= frameClearYPos + 1;
                  end if;
              
               when CLEARLINE =>
                  if (frameClearXPos > videoout_out.DisplayWidthReal + 3) then
                     vramState      <= IDLE;
                     frameClearYPos <= frameClearYPos + 1;
                  elsif (vram_BUSY = '0') then
                     vram_WE        <= '1';
                     vram_ADDR      <= "000001" & std_logic_vector(frameindex_current) & std_logic_vector(frameClearYPos) & std_logic_vector(frameClearXPos(9 downto 2)) & "000";
                     vram_BE        <= x"FF";
                     vram_DIN       <= (others => '0');
                     vram_BURSTCNT  <= x"01";
                     frameClearXPos <= frameClearXPos + 4;
                  end if;

            end case;
            
         end if;

      end if;
   end process;
   
   ilineram: entity mem.dpram_dif
   generic map 
   ( 
      addr_width_a  => 8,
      data_width_a  => 64,
      addr_width_b  => 10,
      data_width_b  => 16
   )
   port map
   (
      clock_a     => clk2x,
      address_a   => std_logic_vector(reqVRAMaddr),
      data_a      => vram_DOUT,
      wren_a      => (vram_DOUT_READY and reqVRAMStore and (not reqVRAMStore2)),
      
      clock_b     => clk2x,
      address_b   => std_logic_vector(vramLineAddr),
      data_b      => x"0000",
      wren_b      => '0',
      q_b         => vramLineData
   );
   
   ilineram2: entity mem.dpram_dif
   generic map 
   ( 
      addr_width_a  => 8,
      data_width_a  => 64,
      addr_width_b  => 10,
      data_width_b  => 16
   )
   port map
   (
      clock_a     => clk2x,
      address_a   => std_logic_vector(reqVRAMaddr2),
      data_a      => vram_DOUT,
      wren_a      => (vram_DOUT_READY and reqVRAMStore2),
      
      clock_b     => clk2x,
      address_b   => std_logic_vector(vramLineAddr),
      data_b      => x"0000",
      wren_b      => '0',
      q_b         => vramLineData2
   );
   
--##############################################################
--############################### video out
--##############################################################
   
   videoout_settings.GPUSTAT_VerRes          <= GPUSTAT_VerRes;
   videoout_settings.GPUSTAT_PalVideoMode    <= GPUSTAT_PalVideoMode;
   videoout_settings.GPUSTAT_VertInterlace   <= GPUSTAT_VertInterlace;
   videoout_settings.GPUSTAT_HorRes2         <= GPUSTAT_HorRes2;
   videoout_settings.GPUSTAT_HorRes1         <= GPUSTAT_HorRes1;
   videoout_settings.GPUSTAT_ColorDepth24    <= GPUSTAT_ColorDepth24;
   videoout_settings.GPUSTAT_DisplayDisable  <= GPUSTAT_DisplayDisable;
   videoout_settings.vramRange               <= vramRange;
   videoout_settings.hDisplayRange           <= hDisplayRange;
   videoout_settings.vDisplayRange           <= vDisplayRange;
   videoout_settings.pal60                   <= pal60;
   videoout_settings.syncInterlace           <= syncInterlace;
   videoout_settings.rotate180               <= rotate180;
   videoout_settings.fixedVBlank             <= fixedVBlank;
   videoout_settings.vCrop                   <= vCrop;
   videoout_settings.hCrop                   <= hCrop;
   videoout_settings.dither24                <= dither24;
   videoout_settings.render24                <= render24;
   
   videoout_ss_in.interlacedDisplayField  <= ss_timing_in(4)(19);
   videoout_ss_in.nextHCount              <= ss_timing_in(4)(11 downto 0);
   videoout_ss_in.vpos                    <= ss_timing_in(3)(24 downto 16);
   videoout_ss_in.vdisp                   <= ss_timing_in(4)(29 downto 21);
   videoout_ss_in.inVsync                 <= ss_timing_in(4)(17);
   videoout_ss_in.activeLineLSB           <= ss_timing_in(4)(20);
   videoout_ss_in.GPUSTAT_InterlaceField  <= ss_gpu_in(1)(13);
   videoout_ss_in.GPUSTAT_DrawingOddline  <= ss_gpu_in(1)(31);
   
   igpu_videoout : entity work.gpu_videoout
   port map
   (
      clk1x                      => clk1x,
      clk2x                      => clk2x,
      clkvid                     => clkvid,
      ce                         => ce,   
      reset                      => reset,
      softReset                  => softReset,
               
      allowunpause               => allowunpause,
      savestate_pause            => savestate_busy,
      system_paused              => system_paused,
               
      videoout_settings          => videoout_settings,
      videoout_reports           => videoout_reports,
         
      videoout_on                => videoout_on,
      syncVideoOut               => syncVideoOut,
            
      debugmodeOn                => debugmodeOn,
            
      fpscountOn                 => fpscountOn,
      fpscountBCD                => fpscountBCD,
   
      Gun1CrosshairOn            => Gun1CrosshairOn,
      Gun1X                      => Gun1X,
      Gun1Y_scanlines            => Gun1Y_scanlines,
      Gun1offscreen              => Gun1offscreen,
      Gun1IRQ10                  => Gun1IRQ10,
   
      Gun2CrosshairOn            => Gun2CrosshairOn,
      Gun2X                      => Gun2X,
      Gun2Y_scanlines            => Gun2Y_scanlines,
      Gun2offscreen              => Gun2offscreen,
      Gun2IRQ10                  => Gun2IRQ10,
            
      cdSlow                     => cdSlow,      
                                 
      errorOn                    => errorOn,  
      errorEna                   => errorEna, 
      errorCode                  => errorCode, 
      
      LBAOn                      => LBAOn,
      LBAdisplay                 => LBAdisplay,
                                 
      requestVRAMEnable          => videoout_reqVRAMEnable,
      requestVRAMMirror          => videoout_reqRAMMirror,
      requestVRAMXPos            => videoout_reqVRAMXPos,  
      requestVRAMYPos            => videoout_reqVRAMYPos,  
      requestVRAMSize            => videoout_reqVRAMSize,  
      requestVRAMIdle            => VRAMIdle and (not vram_pause),
      requestVRAMDone            => reqVRAMDone,
                                 
      vram_DOUT                  => vram_DOUT,      
      vram_DOUT_READY            => vram_DOUT_READY,
          
      videoout_out               => videoout_out,
      
      videoout_ss_in             => videoout_ss_in,
      videoout_ss_out            => videoout_ss_out
   );
   
   video_hsync          <= videoout_out.hsync;         
   video_vsync          <= videoout_out.vsync;         
   video_hblank         <= videoout_out.hblank;        
   video_vblank         <= videoout_out.vblank;        
   video_DisplayOffsetX <= videoout_out.DisplayOffsetX;
   video_DisplayOffsetY <= videoout_out.DisplayOffsetY;
   video_DisplayWidth   <= videoout_out.DisplayWidthReal; 
   video_DisplayHeight  <= videoout_out.DisplayHeightReal;
   video_ce             <= videoout_out.ce;            
   video_interlace      <= videoout_out.interlace;     
   video_r              <= videoout_out.r;             
   video_g              <= videoout_out.g;             
   video_b              <= videoout_out.b;             
   video_isPal          <= videoout_out.isPal;
   video_hResMode       <= videoout_out.hResMode;
   
   dotclock             <= videoout_reports.dotclock;
   
--##############################################################
--############################### savestates
--##############################################################

   process (clk1x)
   begin
      if (rising_edge(clk1x)) then
      
         if (SS_reset = '1') then
         
            for i in 0 to 7 loop
               ss_gpu_in(i)    <= (others => '0');
               ss_timing_in(i) <= (others => '0');
            end loop;
            
            ss_timing_in(0) <= x"0003FC10"; -- vDisplayRange
            ss_timing_in(1) <= x"00C60260"; -- hDisplayRange
            
         else
            if (SS_wren_GPU = '1') then
               ss_gpu_in(to_integer(SS_Adr)) <= SS_DataWrite;
            end if;
            if (SS_wren_Timing = '1') then
               ss_timing_in(to_integer(SS_Adr)) <= SS_DataWrite;
            end if;
         end if;
         
         SS_Idle <= '0';
         if (proc_idle = '1' and fifoIn_Empty = '1' and fifoOut_Empty = '1' and vramState = IDLE and pipeline_busy = '0' and fifoOut_Wr = '0' and pixelWrite = '0') then
            SS_Idle <= '1';
         end if;     

         if (SS_rden_GPU = '1') then
            SS_DataRead_GPU <= ss_gpu_out(to_integer(SS_Adr));
         end if;
         
         if (SS_rden_Timing = '1') then
            SS_DataRead_Timing <= ss_timing_out(to_integer(SS_Adr));
         end if;
      
      end if;
   end process;

   -- synthesis translate_off
   
   goutput : if 1 = 1 generate
      signal gpuFifoCount     : integer := 0;
      signal gpuDMAFifoCount  : integer := 0;
      signal gpuCPUFifoCount  : integer := 0;
   begin
   
      process
         file outfile      : text;
         variable f_status : FILE_OPEN_STATUS;
         variable line_out : line;
      begin
   
         file_open(f_status, outfile, "R:\\debug_gpufifo_sim.txt", write_mode);
         file_close(outfile);
         
         file_open(f_status, outfile, "R:\\debug_gpufifo_sim.txt", append_mode);
         
         while (true) loop
            
            wait until rising_edge(clk1x);
            
            if (DMA_GPU_writeEna = '1' and gpuFifoCount >= 0 and gpuDMAFifoCount >= 0) then
               write(line_out, string'("Fifo: ")); 
               write(line_out, to_hstring(DMA_GPU_write));
               writeline(outfile, line_out);
               gpuFifoCount    <= gpuFifoCount + 1;
               gpuDMAFifoCount <= gpuDMAFifoCount + 1;
            end if;
            
            if (bus_write = '1' and bus_addr = 0 and gpuCPUFifoCount >= 0) then
               write(line_out, string'("Fifo: ")); 
               write(line_out, to_hstring(bus_dataWrite));
               writeline(outfile, line_out);
               gpuFifoCount    <= gpuFifoCount + 1;
               gpuCPUFifoCount <= gpuCPUFifoCount + 1;
            end if;
            
         end loop;
         
      end process;
   
   end generate goutput;
   
   goutput2 : if 1 = 1 generate
      signal pixelCount          : integer := 0;
   begin
   
      process
         file outfile      : text;
         variable f_status : FILE_OPEN_STATUS;
         variable line_out : line;
      begin
   
         file_open(f_status, outfile, "R:\\debug_pixel_sim.txt", write_mode);
         file_close(outfile);
         
         file_open(f_status, outfile, "R:\\debug_pixel_sim.txt", append_mode);
         
         while (true) loop
            
            wait until rising_edge(clk2x);
            
            if (pixelWrite = '1' and pixelCount >= 0) then
            
               write(line_out, to_integer(pixelAddr(10 downto 1)));
               write(line_out, string'(" ")); 
               write(line_out, to_integer(pixelAddr(19 downto 11)));
               write(line_out, string'(" ")); 
               write(line_out, to_integer(unsigned(pixelColor)));
               writeline(outfile, line_out);
               pixelCount <= pixelCount + 1;
               
               if (render24 = '1') then
                  write(line_out, to_integer(pixelAddr(10 downto 1)));
                  write(line_out, string'(" ")); 
                  write(line_out, to_integer(pixelAddr(19 downto 11)));
                  write(line_out, string'(" ")); 
                  write(line_out, to_integer(unsigned(pixelColor(4 downto 0)) & unsigned(pixelColor2(2 downto 0))));
                  writeline(outfile, line_out);
                  
                  write(line_out, to_integer(pixelAddr(10 downto 1)));
                  write(line_out, string'(" ")); 
                  write(line_out, to_integer(pixelAddr(19 downto 11)));
                  write(line_out, string'(" ")); 
                  write(line_out, to_integer(unsigned(pixelColor(9 downto 5)) & unsigned(pixelColor2(5 downto 3))));
                  writeline(outfile, line_out);
                  
                  write(line_out, to_integer(pixelAddr(10 downto 1)));
                  write(line_out, string'(" ")); 
                  write(line_out, to_integer(pixelAddr(19 downto 11)));
                  write(line_out, string'(" ")); 
                  write(line_out, to_integer(unsigned(pixelColor(14 downto 10)) & unsigned(pixelColor2(8 downto 6))));
                  writeline(outfile, line_out);
                  
                  pixelCount <= pixelCount + 4;
               end if;
   
            end if;
            
         end loop;
         
      end process;
   
   end generate goutput2;
   
   
   -- synthesis translate_on

end architecture;





