--------------------------------------------------------------------------------
-- Company: 
-- Engineer:
--
-- Create Date:    11:25:45 10/15/05
-- Design Name:    
-- Module Name:    vga_backend - Behavioral
-- Project Name:   
-- Target Device:  
-- Tool versions:  
-- Description:
--
-- Dependencies:
-- 
-- Revision:
-- Revision 0.01 - File Created
-- Additional Comments:
-- 
--------------------------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;

use work.utils_pkg.all;
use work.vga_types.all;

entity vga_frontend64 is
	Generic
	(
		fifo_depth					: integer    		:= 4096;
		fifo_almost_full_thresh		: natural 			:= 4000;
		fifo_almost_empty_thresh	: natural 			:= 800;
		BLIT_CHUNK_SIZE				: natural 			:= 512;
		BLIT_CMD_FIFO_DEPTH			: natural 			:= 256;
		tsvga						: vga_timespec_t	:= ts_vga_800_600_72
	);
	Port
	(
		-- System signals
		RST_I			: in  STD_LOGIC;
		CLK_I			: in  STD_LOGIC;

		-- JBUS Master signals
		CYC_O			: out STD_LOGIC;
		STB_O			: out STD_LOGIC;
		WE_O			: out STD_LOGIC;
		SEL_O			: out unsigned(7 downto 0);
		ACK_I			: in  STD_LOGIC;
		SRDY_I			: in  STD_LOGIC;
		MRDY_O			: out STD_LOGIC;
		ADDR_O			: out unsigned(31 downto 0);
		MDAT_I			: in  unsigned(63 downto 0);
		MDAT_O			: out unsigned(63 downto 0);
		
		-- JBUS Slave signals
		INT_O			: out STD_LOGIC;
		CYC_I			: in  STD_LOGIC;
		STB_I			: in  STD_LOGIC;
		WE_I			: in  STD_LOGIC;
		SEL_I			: in  unsigned(3 downto 0);
		ACK_O			: out STD_LOGIC;
		SRDY_O			: out STD_LOGIC;
		MRDY_I			: in  STD_LOGIC;
		ADDR_I			: in  unsigned(31 downto 0);
		SDAT_I			: in  unsigned(31 downto 0);
		SDAT_O			: out unsigned(31 downto 0);
		
		-- VGA signals
		vga_clk_in		: in  std_logic;
		vga_clk_ce		: in  std_logic;
		vga_red			: out unsigned(7 downto 0);
		vga_green		: out unsigned(7 downto 0);
		vga_blue		: out unsigned(7 downto 0);
		vga_blank_n		: out std_logic;
		vga_sync_n		: out std_logic;
		vga_hsync		: out std_logic;
		vga_vsync		: out std_logic
	);
end vga_frontend64;

architecture Behavioral of vga_frontend64 is

	-- Color FIFO signals
	signal fifo_full					: std_logic;
	signal fifo_empty					: std_logic;
	signal fifo_almost_empty			: std_logic;
	signal fifo_almost_full				: std_logic;
	signal fifo_color_re				: std_logic;
	signal fifo_color_we				: std_logic;
	signal fifo_color_out				: unsigned(63 downto 0);
	signal fifo_color_in				: unsigned(63 downto 0);

	--	Backend signals
	signal scan_rdy						: std_logic;
	signal ctrl_scan_en					: std_logic;
	signal color_in						: color_array_t;
	signal color_op						: color_op_t;
	signal color_en						: unsigned (VGA_NUM_CH-1 downto 0);

	signal stat_vga_rdy					: std_logic;
	signal stat_hready					: std_logic;
	signal stat_vready					: std_logic;
	signal stat_scan					: std_logic;
	signal stat_hscan					: std_logic;
	signal stat_vscan					: std_logic;
	signal stat_hsync					: std_logic;
	signal stat_vsync					: std_logic;
	signal stat_hpos					: natural range 0 to tsvga.ts_h.ncyc_scan-1;
	signal stat_vpos					: natural range 0 to tsvga.ts_v.ncyc_scan-1;

	--	CG signals
	signal cg_en						: std_logic;
	signal cg_rdy						: std_logic;
	signal cg_draw						: std_logic;
	signal cg_clr_screen				: std_logic;
	signal cg_clr_line					: std_logic;
	signal cg_din						: unsigned(7 downto 0);
	signal cg_dout						: unsigned(7 downto 0);
	signal cg_ascii_we					: std_logic;
	signal cg_posy_we					: std_logic;
	signal cg_posx_we					: std_logic;
	signal cg_color						: color_t;
	signal cg_csr_pos_x					: natural range 0 to 80-1;
	signal cg_csr_pos_y					: natural range 0 to 32-1;

	-- Bus master signals
	constant MAX_REQUEST_CNT			: natural := tsvga.ts_h.ncyc_scan*tsvga.ts_v.ncyc_scan;

	signal reg_read_vld					: std_logic;
	signal bufchg						: std_logic;
	signal bufchg_irq_en				: std_logic;
	signal bufchg_flag					: std_logic;
	signal bufchg_flag_ack				: std_logic;
	signal vga_fb_back					: unsigned(31 downto 0);
	signal vga_fb_front					: unsigned(31 downto 0);
	signal host_fb_front				: unsigned(31 downto 0);
	signal host_fb_back					: unsigned(31 downto 0);
	signal blit_reg_addr_src_0			: unsigned(31 downto 0);
	signal blit_reg_addr_src_1			: unsigned(31 downto 0);
	signal blit_reg_addr_dst			: unsigned(31 downto 0);
	signal blit_reg_dimx_src_0			: unsigned(31 downto 0);
	signal blit_reg_dimx_src_1			: unsigned(31 downto 0);
	signal blit_reg_dimx_dst			: unsigned(31 downto 0);
	signal blit_reg_nx					: unsigned(31 downto 0);
	signal blit_reg_ny					: unsigned(31 downto 0);
	signal blit_reg_const_color			: unsigned(31 downto 0);
	signal blit_reg_func				: unsigned(7 downto 0);
	signal vga_scan_rdy					: std_logic;
	signal vga_scan_dma_en				: std_logic;
	signal vga_scan_dma_en2				: std_logic;
	signal request_cnt_rst				: std_logic;
	signal request_en					: std_logic;
	signal bus_read_en					: std_logic;
	signal request_cnt					: unsigned(28 downto 0);
	signal read_cnt						: unsigned(28 downto 0);
	signal bus_read_fin					: std_logic;
	signal bus_cycle_en					: std_logic;

	signal CYC_O_scan					: std_logic;
	signal STB_O_scan					: std_logic;
	signal ADDR_O_scan					: unsigned(31 downto 0);
	signal pixel_cnt					: natural range 0 to MAX_REQUEST_CNT/2-1;
	signal front						: unsigned(31 downto 0);
	signal back							: unsigned(31 downto 0);


	-- Blitter vars
	signal blit_reset					: std_logic;
	signal blit_request					: std_logic;
	signal blit_const_color_en			: std_logic;
	signal blit_request_set				: std_logic;
	signal blit_finish_strobe			: unsigned(2 downto 0);
	signal blit_complete_int			: std_logic;
	signal blit_complete_int_ack		: std_logic;
	signal blit_complete_int_en			: std_logic;
	signal blit_cmd_empty_int			: std_logic;
	signal blit_cmd_empty_int_ack		: std_logic;
	signal blit_cmd_empty_int_en		: std_logic;
	
	-- BLIT command FIFO
	constant BLIT_CMD_FIFO_WIDTH	: natural := 320;
	signal blit_cmd_din				: unsigned(BLIT_CMD_FIFO_WIDTH-1 downto 0);
	signal blit_cmd_dout			: unsigned(BLIT_CMD_FIFO_WIDTH-1 downto 0);
	signal blit_cmd_re				: std_logic;
	signal blit_cmd_we				: std_logic;
	signal blit_cmd_empty			: std_logic;
	signal blit_cmd_full			: std_logic;
	signal blit_cmd_bsy				: std_logic;
	signal blit_cmd_avail			: std_logic;
	
	signal blit_cmd_addr_src_0		: unsigned(31 downto 0);
	signal blit_cmd_addr_src_1		: unsigned(31 downto 0);
	signal blit_cmd_addr_dst		: unsigned(31 downto 0);
	signal blit_cmd_dimx_src_0		: unsigned(31 downto 0);
	signal blit_cmd_dimx_src_1		: unsigned(31 downto 0);
	signal blit_cmd_dimx_dst		: unsigned(31 downto 0);
	signal blit_cmd_nx				: unsigned(31 downto 0);
	signal blit_cmd_ny				: unsigned(31 downto 0);
	signal blit_cmd_CC				: unsigned(31 downto 0);
	signal blit_cmd_func			: unsigned(31 downto 0);

	signal blit_chunk_cnt			: natural range 0 to BLIT_CHUNK_SIZE-1;
	signal blit_chunk_full			: std_logic;
	
	-- Blitter FIFO signals
	signal blitfifo_dout_vld	: std_logic;
	signal blitfifo_write_en	: std_logic;
	signal blitfifo_read_en		: std_logic;
	signal blitfifo_full		: unsigned(1 downto 0);
	signal blitfifo_empty		: unsigned(1 downto 0);
	signal blitfifo_we			: unsigned(1 downto 0);
	signal blitfifo_re			: unsigned(1 downto 0);
	signal blitfifo_din			: unsigned(63 downto 0);
	signal blitfifo_dout_0		: unsigned(31 downto 0);
	signal blitfifo_dout_1		: unsigned(31 downto 0);
	

	-- BLIT Source register
	signal blit_src_cnt_x_next	: unsigned(32 downto 0);
	signal blit_src_cnt_y_next	: unsigned(32 downto 0);
	signal blit_src_cnt_x		: unsigned(31 downto 0);
	signal blit_src_cnt_y		: unsigned(31 downto 0);
	signal blit_src_offset		: unsigned(31 downto 0);
	signal blit_src_addr_next	: unsigned(31 downto 0);
	signal blit_src_finish		: std_logic;
	signal blit_src_START_U		: std_logic;
	signal blit_src_START_A		: std_logic;
	signal blit_src_STOP_U		: std_logic;
	signal blit_src_STOP_A		: std_logic;

	signal CYC_O_blit_src		: std_logic;
	signal STB_O_blit_src		: std_logic;
	signal ADDR_O_blit_src		: unsigned(31 downto 0);
	
	-- BLIT Destination register
	signal blit_dst_cnt_x_next	: unsigned(32 downto 0);
	signal blit_dst_cnt_y_next	: unsigned(32 downto 0);
	signal blit_dst_cnt_x		: unsigned(31 downto 0);
	signal blit_dst_cnt_y		: unsigned(31 downto 0);
	signal blit_dst_offset		: unsigned(31 downto 0);
	signal blit_dst_addr_next	: unsigned(31 downto 0);
	signal blit_dst_finish		: std_logic;
	signal blitfifo_empty_read	: std_logic;
	signal blit_dst_suspend		: std_logic;
	signal blit_dst_be			: unsigned(7 downto 0);
	
	-- BLIT Source Tracker
	signal blit_fill_cnt_x_next	: unsigned(32 downto 0);
	signal blit_fill_cnt_y_next	: unsigned(32 downto 0);
	signal blit_fill_cnt_x		: unsigned(31 downto 0);
	signal blit_fill_cnt_y		: unsigned(31 downto 0);
	signal blit_fill_offset		: unsigned(2 downto 0);
	signal blit_fill_finish		: std_logic;
	signal blit_fill_addr		: unsigned(2 downto 0);
	
	signal CYC_O_blit_dst		: std_logic;
	signal STB_O_blit_dst		: std_logic;
	signal ADDR_O_blit_dst		: unsigned(31 downto 0);

	signal odd_pixel			: unsigned(NextExpBaseTwo(tsvga.ts_h.ncyc_scan)-1 downto 0);

	
	-- Bus output FIFO
	signal busout_fifo_din		: unsigned(104 downto 0);
	signal busout_fifo_dout		: unsigned(104 downto 0);
	signal busout_fifo_re		: std_logic;
	signal busout_fifo_we		: std_logic;
	signal busout_fifo_full		: std_logic;
	signal busout_fifo_empty	: std_logic;
	signal busout_fifo_rdy		: std_logic;

	alias busout_fifo_addr_in is busout_fifo_din(31 downto 0);
	alias busout_fifo_data_in is busout_fifo_din(95 downto 32);
	alias busout_fifo_sel_in is busout_fifo_din(103 downto 96);
	alias busout_fifo_we_in is busout_fifo_din(104);
	
	alias busout_fifo_addr_out is busout_fifo_dout(31 downto 0);
	alias busout_fifo_data_out is busout_fifo_dout(95 downto 32);
	alias busout_fifo_sel_out is busout_fifo_dout(103 downto 96);
	alias busout_fifo_we_out is busout_fifo_dout(104);
	
	-- Bus input FIFO
	signal busin_fifo_din		: unsigned(63 downto 0);
	signal busin_fifo_dout		: unsigned(63 downto 0);
	signal busin_fifo_re		: std_logic;
	signal busin_fifo_we		: std_logic;
	signal busin_fifo_full		: std_logic;
	signal busin_fifo_empty		: std_logic;
	signal busin_fifo_rdy		: std_logic;
	signal busin_fifo_dout_vld	: std_logic;

	type vm_state_t is (init, rdy, scan_bus_request, scan_bus_read, blit_src_bus_request, blit_src_bus_read, blit_dst_bus_request, const_dst_bus_request, bus_fin);
	signal s, sn : vm_state_t;

	type debug_t is 
	record
		FIRST		: std_logic;
		LAST		: std_logic;
		UNALIGNED	: std_logic;
		PARTIAL		: std_logic;
	end record debug_t;
	
	signal src_dbg	: debug_t;
	signal fill_dbg	: debug_t;
	signal dst_dbg	: debug_t;
	
--------------------------------------------------------------------------
begin

	blit_cmd_din(BLIT_CMD_FIFO_WIDTH-1 downto BLIT_CMD_FIFO_WIDTH-32)		 <= blit_reg_addr_src_0;
	blit_cmd_din(BLIT_CMD_FIFO_WIDTH-32-1 downto BLIT_CMD_FIFO_WIDTH-64)	 <= blit_reg_dimx_src_0;
	blit_cmd_din(BLIT_CMD_FIFO_WIDTH-64-1 downto BLIT_CMD_FIFO_WIDTH-96)	 <= blit_reg_addr_src_1;
	blit_cmd_din(BLIT_CMD_FIFO_WIDTH-96-1 downto BLIT_CMD_FIFO_WIDTH-128)	 <= blit_reg_dimx_src_1;
	blit_cmd_din(BLIT_CMD_FIFO_WIDTH-128-1 downto BLIT_CMD_FIFO_WIDTH-160)	 <= blit_reg_addr_dst;
	blit_cmd_din(BLIT_CMD_FIFO_WIDTH-160-1 downto BLIT_CMD_FIFO_WIDTH-192)	 <= blit_reg_dimx_dst;
	blit_cmd_din(BLIT_CMD_FIFO_WIDTH-192-1 downto BLIT_CMD_FIFO_WIDTH-224)	 <= blit_reg_nx;
	blit_cmd_din(BLIT_CMD_FIFO_WIDTH-224-1 downto BLIT_CMD_FIFO_WIDTH-256)	 <= blit_reg_ny;
	blit_cmd_din(BLIT_CMD_FIFO_WIDTH-256-1 downto BLIT_CMD_FIFO_WIDTH-288)	 <= blit_reg_const_color;
	blit_cmd_din(BLIT_CMD_FIFO_WIDTH-288-1 downto BLIT_CMD_FIFO_WIDTH-320)	 <= (31 downto 8 => '0') & blit_reg_func;

	blit_cmd_addr_src_0			<= blit_cmd_dout(BLIT_CMD_FIFO_WIDTH-1 downto BLIT_CMD_FIFO_WIDTH-32);
	blit_cmd_dimx_src_0			<= blit_cmd_dout(BLIT_CMD_FIFO_WIDTH-32-1 downto BLIT_CMD_FIFO_WIDTH-64);
	blit_cmd_addr_src_1			<= blit_cmd_dout(BLIT_CMD_FIFO_WIDTH-64-1 downto BLIT_CMD_FIFO_WIDTH-96);
	blit_cmd_dimx_src_1			<= blit_cmd_dout(BLIT_CMD_FIFO_WIDTH-96-1 downto BLIT_CMD_FIFO_WIDTH-128);
	blit_cmd_addr_dst 			<= blit_cmd_dout(BLIT_CMD_FIFO_WIDTH-128-1 downto BLIT_CMD_FIFO_WIDTH-160);
	blit_cmd_dimx_dst			<= blit_cmd_dout(BLIT_CMD_FIFO_WIDTH-160-1 downto BLIT_CMD_FIFO_WIDTH-192);
	blit_cmd_nx					<= blit_cmd_dout(BLIT_CMD_FIFO_WIDTH-192-1 downto BLIT_CMD_FIFO_WIDTH-224);
	blit_cmd_ny					<= blit_cmd_dout(BLIT_CMD_FIFO_WIDTH-224-1 downto BLIT_CMD_FIFO_WIDTH-256);
	blit_cmd_CC					<= blit_cmd_dout(BLIT_CMD_FIFO_WIDTH-256-1 downto BLIT_CMD_FIFO_WIDTH-288);
	blit_cmd_func				<= blit_cmd_dout(BLIT_CMD_FIFO_WIDTH-288-1 downto BLIT_CMD_FIFO_WIDTH-320);

	blit_cmd_avail 				<= not blit_cmd_empty;
	blit_cmd_bsy				<= blit_cmd_full;
	blit_cmd_re					<= blit_finish_strobe(0);
	blit_cmd_we 				<= blit_request_set;

-- Command FIFO
inst_blit_cmd_fifo: entity work.fifo_sync
	GENERIC MAP
	(
		addr_width	=> NextExpBaseTwo(BLIT_CMD_FIFO_DEPTH),
		data_width	=> BLIT_CMD_FIFO_WIDTH,
		do_last_read_update	=> false
	)
	PORT MAP
	(
		rst			=>	RST_I,
		clk			=>	CLK_I,
		we			=>	blit_cmd_we,
		re			=>	blit_cmd_re,
		fifo_full	=>	blit_cmd_full,
		fifo_empty	=>	blit_cmd_empty,
		fifo_afull	=>	open,
		fifo_aempty	=>	open,
		data_w		=>  blit_cmd_din,
		data_r		=>  blit_cmd_dout
	);

proc_synced_vga_scan_en:
	process(CLK_I)
	begin
		if rising_edge(CLK_I) then
			if RST_I = '1' then
				vga_scan_dma_en2 <= '0';
			elsif vga_scan_rdy = '1' then
				vga_scan_dma_en2 <= vga_scan_dma_en;
			end if;				
		end if;
	end process;	

	ADDR_O_scan			<= front + (to_unsigned(pixel_cnt, 29) & "000");

proc_scan_addr:
	process(CLK_I)
	begin
		if rising_edge(CLK_I) then
			bufchg			<= '0';
			if vga_scan_dma_en2 = '0' then
				pixel_cnt	<= 0;
				front		<= host_fb_front;
			elsif STB_O_scan = '1' and busout_fifo_rdy = '1' then
				if pixel_cnt /= MAX_REQUEST_CNT/2-1 then
					pixel_cnt 	<= pixel_cnt + 1;
				else
					pixel_cnt	<= 0;
					front		<= host_fb_back;
					bufchg		<= '1';
				end if;	
 			end if;	
			vga_fb_front	<= front;
 			vga_fb_back		<= back;
		end if;
	end process;	
	
---------------------------------------------------------------------------------
inst_vga_backend : entity work.vga_backend
	GENERIC MAP
	(
		tsvga			=> tsvga
	)
	PORT MAP
	(
		-- System signals
		sys_rst			=> RST_I,
		sys_clk			=> CLK_I,
		
		-- Color channels
		color_in		=> color_in,
		color_op		=> color_op,
		color_en		=> color_en,

		-- Control signals
		ctrl_scan_en	=> ctrl_scan_en,

		-- Status signals
		stat_vga_rdy	=> stat_vga_rdy,
		stat_scan		=> stat_scan,
		stat_hsync		=> stat_hsync,
		stat_vsync		=> stat_vsync,
		stat_hready		=> stat_hready,
		stat_vready		=> stat_vready,
		stat_hscan		=> stat_hscan,
		stat_vscan		=> stat_vscan,
		stat_hpos		=> stat_hpos,
		stat_vpos		=> stat_vpos,
		
		-- VGA domain signals
		vga_clk_in		=> vga_clk_in,
		vga_clk_ce		=> vga_clk_ce,
		vga_red			=> vga_red,
		vga_green		=> vga_green,
		vga_blue		=> vga_blue,
		vga_blank_n		=> vga_blank_n,
		vga_sync_n		=> vga_sync_n,
		vga_hsync		=> vga_hsync,
		vga_vsync		=> vga_vsync
	);
	
	SRDY_O			<= CYC_I; -- and cg_rdy;
	MRDY_O			<= busin_fifo_rdy; --not fifo_full;
	STB_O			<= not busout_fifo_empty;
	ADDR_O			<= busout_fifo_addr_out;
	MDAT_O			<= busout_fifo_data_out;
	SEL_O			<= busout_fifo_sel_out;
	WE_O			<= busout_fifo_we_out;

	odd_pixel		<= to_unsigned(stat_hpos, odd_pixel'length);
	ctrl_scan_en	<= '1';
	color_en(0)		<= not fifo_empty;
	color_en(1)		<= cg_draw;
	color_in(0)		<= to_color_t(fifo_color_out(31 downto 0)) when odd_pixel(0) = '0' else to_color_t(fifo_color_out(63 downto 32));
	color_in(1)		<= cg_color; --(X"FF", X"FF", X"FF", X"FF");	-- white opaque
	color_op		<= op_over;
	vga_scan_rdy	<= stat_hready and stat_vready;
	
-- SCAN line FIFO
inst_linefifo: entity work.fifo_async
	GENERIC MAP 
	(
		addr_width			=> NextExpBaseTwo(fifo_depth),
		data_width			=> 64,
		almost_full_thresh	=> fifo_almost_full_thresh,
		almost_empty_thresh	=> fifo_almost_empty_thresh
	)
	PORT MAP
	(
		rst				=> RST_I,
		clk_w			=> CLK_I,
		clk_r			=> vga_clk_in,
		we				=> fifo_color_we,
		re				=> fifo_color_re,
		data_w			=> fifo_color_in,
		data_r			=> fifo_color_out,
		fifo_full		=> fifo_full,
		fifo_empty		=> fifo_empty,
		fifo_afull		=> fifo_almost_full,
		fifo_aempty		=> fifo_almost_empty
		
	);

	fifo_color_in		<= busin_fifo_dout;
	fifo_color_re		<= stat_scan and odd_pixel(0);
	fifo_color_we		<= busin_fifo_dout_vld and CYC_O_scan;		-- TODO:


-- Bus input FIFO
inst_busin_fifo: entity work.fifo_sync
	GENERIC MAP
	(
		addr_width			=> 2,
		data_width			=> busin_fifo_din'length,
		do_last_read_update	=> true
	)
	PORT MAP
	(
		rst			=>	RST_I,
		clk			=>	CLK_I,
		we			=>	busin_fifo_we,
		re			=>	busin_fifo_re,
		fifo_full	=>	busin_fifo_full,
		fifo_empty	=>	busin_fifo_empty,
		fifo_afull	=>	open,
		fifo_aempty	=>	open,
		data_w		=>  busin_fifo_din,
		data_r		=>  busin_fifo_dout
	);
	busin_fifo_rdy		<= not busin_fifo_full;
	busin_fifo_din		<= MDAT_I;
	busin_fifo_we		<= ACK_I and bus_cycle_en and bus_read_en;
	busin_fifo_dout_vld	<= not busin_fifo_empty;
	busin_fifo_re		<= not fifo_full when CYC_O_scan = '1' else CYC_O_blit_src;
	
-- Bus output FIFO
inst_busout_fifo: entity work.fifo_sync
	GENERIC MAP
	(
		addr_width			=> 2,
		data_width			=> busout_fifo_din'length,
		do_last_read_update	=> false
	)
	PORT MAP
	(
		rst			=>	RST_I,
		clk			=>	CLK_I,
		we			=>	busout_fifo_we,
		re			=>	busout_fifo_re,
		fifo_full	=>	busout_fifo_full,
		fifo_empty	=>	busout_fifo_empty,
		fifo_afull	=>	open,
		fifo_aempty	=>	open,
		data_w		=>  busout_fifo_din,
		data_r		=>  busout_fifo_dout
	);

	blit_const_color_en	<= blit_cmd_func(0);

	busout_fifo_rdy		<= not busout_fifo_full;
	busout_fifo_re		<= not busout_fifo_empty and SRDY_I;
	busout_fifo_we		<= bus_cycle_en and (STB_O_scan or STB_O_blit_src or STB_O_blit_dst);
	busout_fifo_data_in	<= (blitfifo_dout_1 & blitfifo_dout_0) when blit_const_color_en = '0' else (blit_cmd_CC & blit_cmd_CC);
	busout_fifo_addr_in	<= 	ADDR_O_blit_src when CYC_O_blit_src = '1' else
							ADDR_O_blit_dst when CYC_O_blit_dst = '1' else
							ADDR_O_scan;
	busout_fifo_sel_in	<= blit_dst_be;
	busout_fifo_we_in	<= CYC_O_blit_dst;
	request_en			<= bus_cycle_en and busout_fifo_we and busout_fifo_rdy;
	CYC_O				<= bus_cycle_en;
	
------------------------------------------------------------------------------------
-- Bus request counter
------------------------------------------------------------------------------------
proc_bus_request_counter:
	process(CLK_I)
	begin
		if rising_edge(CLK_I) then
			if request_cnt_rst = '1' then
				request_cnt	<= (others => '0');
			elsif request_en = '1' then
				request_cnt <= request_cnt + 1;
			end if;	
		end if;
	end process;	
		
proc_bus_read_counter:
	process(CLK_I)
	begin
		if rising_edge(CLK_I) then
			if request_cnt_rst = '1' then
				read_cnt	<= (others => '0');
			elsif busin_fifo_dout_vld = '1' then
				read_cnt <= read_cnt + 1;
			end if;	
		end if;
	end process;	

proc_bus_read_finish:
	process(CLK_I)
	begin
		if rising_edge(CLK_I) then
			bus_read_fin <= '0';
			if read_cnt = request_cnt then
				bus_read_fin <= '1';
			end if;
		end if;
	end process;	

------------------------------------------------------------------------------------
-- VGA master FSM	
------------------------------------------------------------------------------------
vga_master_next:
	process(CLK_I)
	begin
		if rising_edge(CLK_I) then
			if RST_I = '1' then
				s	<= init;
			else
				s	<= sn;
			end if;
		end if;
	end process;	

vga_master:
	process(s, stat_vga_rdy, vga_scan_dma_en2, fifo_almost_empty, fifo_almost_full, bus_read_fin, busout_fifo_empty, blit_request, blit_dst_suspend, blit_chunk_full, blitfifo_dout_vld, blit_src_finish, blitfifo_empty_read, blit_dst_finish, blit_const_color_en)
	begin
	
	CYC_O_scan		<= '0';
	STB_O_scan		<= '0';
	CYC_O_blit_src	<= '0';
	STB_O_blit_src	<= '0';
	CYC_O_blit_dst	<= '0';
	STB_O_blit_dst	<= '0';
	request_cnt_rst	<= '0';
	bus_read_en		<= '0';
	bus_cycle_en	<= '0';
	
	sn				<= s;
	case s is
		when init =>
		if stat_vga_rdy = '1' then
			sn	<= rdy;
		end if;
		
		when rdy =>
		request_cnt_rst	<= '1';
		if fifo_almost_empty = '1' and vga_scan_dma_en2 = '1' then
			sn				<= scan_bus_request;
		elsif blit_request = '1' then	-- ToDo: richtig prüfen anhand eines states wer dran ist. Nicht auf FIFO state prüfen
			sn	<= blit_dst_bus_request;
			if blitfifo_dout_vld = '0' or blit_dst_suspend = '1' then
				sn	<= blit_src_bus_request;
				if blit_const_color_en = '1' then
					sn	<= const_dst_bus_request;
				end if;
			end if;
		end if;
		
		when scan_bus_request =>
			bus_cycle_en	<= '1';
			CYC_O_scan		<= '1';
			STB_O_scan		<= '1';
			bus_read_en		<= '1';
			if fifo_almost_full = '1' then
				sn <= scan_bus_read;
			end if;	
			
		when scan_bus_read =>
			bus_cycle_en	<= '1';
			CYC_O_scan		<= '1';
			bus_read_en		<= '1';
			if bus_read_fin = '1' then
				sn	<= rdy;
			end if;	

		when blit_src_bus_request =>
			bus_cycle_en	<= '1';
			bus_read_en		<= '1';
			CYC_O_blit_src	<= '1';
			STB_O_blit_src	<= '1';
			if blit_chunk_full = '1' or blit_src_finish = '1' then
				STB_O_blit_src	<= '0';
				sn 				<= blit_src_bus_read;
			end if;	

		when blit_src_bus_read =>
			bus_cycle_en	<= '1';
			bus_read_en		<= '1';
			CYC_O_blit_src	<= '1';
			if bus_read_fin = '1' then
				sn	<= rdy;
			end if;	

		when blit_dst_bus_request =>
			bus_cycle_en	<= '1';
			CYC_O_blit_dst	<= '1';
			STB_O_blit_dst	<= '1';
			if blitfifo_empty_read = '1' or blitfifo_dout_vld = '0' or blit_dst_finish = '1' then
				STB_O_blit_dst	<= '0';
				sn				<= bus_fin;
			end if;	

		when const_dst_bus_request =>
			bus_cycle_en	<= '1';
			CYC_O_blit_dst	<= '1';
			STB_O_blit_dst	<= '1';
			if blit_chunk_full = '1' or blit_dst_finish = '1' then
				STB_O_blit_dst	<= '0';
				sn 				<= bus_fin;
			end if;	

		when bus_fin =>
			bus_cycle_en	<= '1';
			if busout_fifo_empty = '1' then
				sn	<= rdy;
			end if;	

		when others =>
			sn	<= rdy;
		
		end case;
	end process;
	
---------------------------------------------------------------------------------
-- BLITTER
---------------------------------------------------------------------------------
proc_blit_complete_int_flag:
	process(CLK_I)
	begin
		if rising_edge(CLK_I) then
			if RST_I = '1' or (blit_complete_int = '1' and blit_complete_int_ack = '1') then
				blit_complete_int	<= '0';
			elsif blit_finish_strobe(2) = '1' or (blit_complete_int = '0' and blit_complete_int_ack = '1') then
				blit_complete_int	<= '1';
			end if;
		end if;
	end process;	

proc_blit_cmd_empty_int_flag:
	process(CLK_I)
	begin
		if rising_edge(CLK_I) then
			if RST_I = '1' or (blit_cmd_empty_int = '1' and blit_cmd_empty_int_ack = '1') then
				blit_cmd_empty_int	<= '0';
			elsif (blit_finish_strobe(2) = '1' and blit_cmd_avail = '0') or (blit_cmd_empty_int = '0' and blit_cmd_empty_int_ack = '1') then
				blit_cmd_empty_int	<= '1';
			end if;
		end if;
	end process;	

proc_irq:
	process(CLK_I)
	begin
		if rising_edge(CLK_I) then
			if vga_scan_dma_en2 = '0' or bufchg_flag_ack = '1' then
				bufchg_flag	<= '0';
			elsif bufchg = '1' then
				bufchg_flag	<= '1';
			end if;
			INT_O		<= (bufchg_flag and bufchg_irq_en)
						or (blit_complete_int and blit_complete_int_en)
						or (blit_cmd_empty_int and blit_cmd_empty_int_en);
		end if;
	end process;	

proc_blit_reset:
	process(CLK_I)
	begin
		if rising_edge(CLK_I) then
			if RST_I = '1' then
				blit_reset		<= '1';
				blit_request	<= '0';
			else
				blit_reset		<= (blit_cmd_avail and not blit_request) or (blit_request and blit_finish_strobe(0));
				blit_request	<= blit_cmd_avail;
			end if;
		end if;
	end process;	

proc_blit_chunk_counter:
	process(CLK_I)
	begin
		if rising_edge(CLK_I) then
			if request_cnt_rst = '1' then
				blit_chunk_full <= '0';
				blit_chunk_cnt	<= BLIT_CHUNK_SIZE-2;
			elsif request_en = '1' then
				if blit_chunk_cnt = 0 then
					blit_chunk_full <= '1';
				else
					blit_chunk_cnt 		<= blit_chunk_cnt - 1;
				end if;
			end if;
		end if;
	end process;	

-- BLIT buffer low
inst_blitfifo_src0: entity work.fifo_sync
	GENERIC MAP 
	(
		addr_width			=> NextExpBaseTwo(BLIT_CHUNK_SIZE),
		data_width			=> 32,
		
		do_last_read_update	=> false

	)
	PORT MAP
	(
		rst				=> blit_reset,
		clk				=> CLK_I,
		we				=> blitfifo_we(0),
		re				=> blitfifo_re(0),
		data_w			=> blitfifo_din(31 downto 0),
		data_r			=> blitfifo_dout_0,
		fifo_full		=> blitfifo_full(0),
		fifo_empty		=> blitfifo_empty(0),
		fifo_afull		=> open,
		fifo_aempty		=> open
		
	);

-- BLIT buffer high
inst_blitfifo_src1: entity work.fifo_sync
	GENERIC MAP 
	(
		addr_width			=> NextExpBaseTwo(BLIT_CHUNK_SIZE),
		data_width			=> 32,
		
		do_last_read_update	=> false

	)
	PORT MAP
	(
		rst				=> blit_reset,
		clk				=> CLK_I,
		we				=> blitfifo_we(1),
		re				=> blitfifo_re(1),
		data_w			=> blitfifo_din(63 downto 32),
		data_r			=> blitfifo_dout_1,
		fifo_full		=> blitfifo_full(1),
		fifo_empty		=> blitfifo_empty(1),
		fifo_afull		=> open,
		fifo_aempty		=> open
		
	);

	blitfifo_din		<= busin_fifo_dout;
	blitfifo_write_en	<= busin_fifo_dout_vld and CYC_O_blit_src;
	blitfifo_read_en	<= busout_fifo_rdy and CYC_O_blit_dst;
	blitfifo_dout_vld	<= not (blitfifo_empty(0) and blitfifo_empty(1));
	
---------------------------------------------------------------------------------
blit_dst_be_gen:
	process(dst_dbg)
	begin
		blit_dst_be <= "11111111";
		if dst_dbg.UNALIGNED = '1' then
			if dst_dbg.FIRST = '1' then
				blit_dst_be <= "00001111";
			elsif dst_dbg.LAST = '1' then
				if dst_dbg.PARTIAL = '1' then
					blit_dst_be <= "11110000";
				end if;
			end if;
		elsif dst_dbg.LAST = '1' then
			if dst_dbg.PARTIAL = '1' then
				blit_dst_be <= "00001111";
			end if;
		end if;
	end process;

blitfifo_we_gen:
	process(fill_dbg, blitfifo_write_en)
	begin
		blitfifo_we <= (blitfifo_write_en & blitfifo_write_en);
		if fill_dbg.UNALIGNED = '1' then
			if fill_dbg.FIRST = '1' then
				blitfifo_we <= ('0' & blitfifo_write_en);
			elsif fill_dbg.LAST = '1' then
				if fill_dbg.PARTIAL = '1' then
					blitfifo_we <= (blitfifo_write_en & '0');
				end if;
			end if;
		elsif fill_dbg.LAST = '1' then
			if fill_dbg.PARTIAL = '1' then
				blitfifo_we <= ('0' & blitfifo_write_en);
			end if;
		end if;
	end process;
	
blitfifo_re_gen:
	process(dst_dbg, blitfifo_empty, blitfifo_read_en)
	variable fifo_re : unsigned(1 downto 0);
	variable empty_read : std_logic;
	begin
		fifo_re := (blitfifo_read_en & blitfifo_read_en);
		if dst_dbg.UNALIGNED = '1' then
			if dst_dbg.FIRST = '1' then
				fifo_re := ('0' & blitfifo_read_en);
			elsif dst_dbg.LAST = '1' then
				if dst_dbg.PARTIAL = '1' then
					fifo_re := (blitfifo_read_en & '0');
				end if;
			end if;
		elsif dst_dbg.LAST = '1' then
			if dst_dbg.PARTIAL = '1' then
				fifo_re := ('0' & blitfifo_read_en);
			end if;
		end if;
		empty_read			:= (blitfifo_empty(0) and fifo_re(0)) or (blitfifo_empty(1) and fifo_re(1));
		blitfifo_re			<= fifo_re and not (empty_read & empty_read);
		blitfifo_empty_read	<= empty_read;
	end process;

blit_dst_suspend_gen:
	process(CLK_I)
	begin
		if rising_edge(CLK_I) then
			if RST_I = '1' or blit_dst_finish = '1' or CYC_O_blit_src = '1' then
				blit_dst_suspend <= '0';
			elsif blitfifo_read_en = '1' and blitfifo_empty_read = '1' then
				blit_dst_suspend <= not (blitfifo_empty(0) and blitfifo_empty(1));
			end if;
		end if;
	end process;	

	fill_dbg.LAST		<= '1' when blit_fill_cnt_x_next = '0' & X"0000_0000" or blit_fill_cnt_x_next(32) = '1' else '0';
	fill_dbg.PARTIAL	<= blit_fill_cnt_x_next(32);

	blit_fill_cnt_x_next	<= ('0' & blit_fill_cnt_x - 1) when fill_dbg.FIRST = '1' and fill_dbg.UNALIGNED = '1' else ('0' & blit_fill_cnt_x - 2);
	blit_fill_cnt_y_next	<= ('0' & blit_fill_cnt_y) - 1;

-- BLIT Buffer fill address generator
blitfifo_fill_src_0:
	process(CLK_I)
	variable addr_next : unsigned(31 downto 0);
	begin
		if rising_edge(CLK_I) then
			if RST_I = '1' or blit_reset = '1' then
				blit_fill_addr		<= blit_cmd_addr_src_0(2) & "00";
				blit_fill_cnt_x		<= blit_cmd_nx;
				blit_fill_cnt_y		<= blit_cmd_ny;
				blit_fill_offset	<= blit_cmd_dimx_src_0(2 downto 0);
				blit_fill_finish	<= '0';
				fill_dbg.FIRST		<= '1';
				fill_dbg.UNALIGNED	<= blit_cmd_addr_src_0(2);
			elsif blit_request = '1' and blit_fill_finish = '0' and blit_const_color_en = '0' and blitfifo_write_en = '1' then
				fill_dbg.FIRST		<= '0';
				if fill_dbg.LAST = '1' then
					if blit_fill_cnt_y_next = ('0' & X"0000_0000") or blit_fill_cnt_y_next(32) = '1' then
						blit_fill_finish	<= '1';
					else
						addr_next			:= (blit_cmd_addr_src_0(31 downto 2) & "00") + blit_fill_offset;
						blit_fill_addr		<= addr_next(2 downto 0);
						blit_fill_offset	<= blit_fill_offset + blit_cmd_dimx_src_0(2 downto 0);
						blit_fill_cnt_x		<= blit_cmd_nx;
						blit_fill_cnt_y 	<= blit_fill_cnt_y_next(31 downto 0);
						fill_dbg.FIRST		<= '1';
						fill_dbg.UNALIGNED	<= addr_next(2);
					end if;
				else
					blit_fill_cnt_x		<= blit_fill_cnt_x_next(31 downto 0);
					blit_fill_addr 		<= (others => '0');
				end if;
			end if;
		end if;
	end process;	

	src_dbg.LAST		<= '1' when blit_src_cnt_x_next = '0' & X"0000_0000" or blit_src_cnt_x_next(32) = '1' else '0';
	src_dbg.PARTIAL		<= blit_src_cnt_x_next(32);
	
	blit_src_addr_next	<= ADDR_O_blit_src + 8;
	blit_src_cnt_x_next	<= ('0' & blit_src_cnt_x - 1) when src_dbg.FIRST = '1' and src_dbg.UNALIGNED = '1' else ('0' & blit_src_cnt_x - 2);
	blit_src_cnt_y_next	<= ('0' & blit_src_cnt_y) - 1;

-- BLIT Source address generator
blit_request_addr_src:
	process(CLK_I)
	variable addr_next : unsigned(31 downto 0);
	begin
		if rising_edge(CLK_I) then
			if RST_I = '1' or blit_reset = '1' then
				ADDR_O_blit_src		<= blit_cmd_addr_src_0(31 downto 2) & "00";
				blit_src_cnt_x		<= blit_cmd_nx;
				blit_src_cnt_y		<= blit_cmd_ny;
				blit_src_offset		<= blit_cmd_dimx_src_0;
				blit_src_finish		<= '0';
				src_dbg.FIRST		<= '1';
				src_dbg.UNALIGNED	<= blit_cmd_addr_src_0(2);
			elsif blit_request = '1' and blit_src_finish = '0' and blit_const_color_en = '0' and (STB_O_blit_src = '1' and busout_fifo_rdy = '1') then
				src_dbg.FIRST		<= '0';
				if src_dbg.LAST = '1' then
					if blit_src_cnt_y_next = ('0' & X"0000_0000") or blit_src_cnt_y_next(32) = '1' then
						blit_src_finish	<= '1';
					else
						addr_next			:= (blit_cmd_addr_src_0(31 downto 2) & "00") + blit_src_offset;
						ADDR_O_blit_src		<= addr_next;
						blit_src_offset		<= blit_src_offset + blit_cmd_dimx_src_0;
						blit_src_cnt_x		<= blit_cmd_nx;
						blit_src_cnt_y 		<= blit_src_cnt_y_next(31 downto 0);
						src_dbg.FIRST		<= '1';
						src_dbg.UNALIGNED	<= addr_next(2);
					end if;
				else
					ADDR_O_blit_src 	<= blit_src_addr_next;
					blit_src_cnt_x 		<= blit_src_cnt_x_next(31 downto 0);
				end if;
			end if;
		end if;
	end process;	


	dst_dbg.LAST		<= '1' when blit_dst_cnt_x_next = '0' & X"0000_0000" or blit_dst_cnt_x_next(32) = '1' else '0';
	dst_dbg.PARTIAL		<= blit_dst_cnt_x_next(32);

	blit_dst_addr_next	<= ADDR_O_blit_dst + 8;
	blit_dst_cnt_x_next	<= ('0' & blit_dst_cnt_x - 1) when dst_dbg.FIRST = '1' and dst_dbg.UNALIGNED = '1' else ('0' & blit_dst_cnt_x - 2);
	blit_dst_cnt_y_next	<= ('0' & blit_dst_cnt_y) - 1;
	
-- BLIT Destination address generator
blit_request_addr_dst:
	process(CLK_I)
	variable addr_next : unsigned(31 downto 0);
	begin
		if rising_edge(CLK_I) then
			blit_finish_strobe	<= blit_finish_strobe(blit_finish_strobe'left-1 downto 0) & '0';
			if RST_I = '1' then
				blit_finish_strobe	<= (others =>'0');
			elsif blit_reset = '1' then
				ADDR_O_blit_dst		<= blit_cmd_addr_dst(31 downto 2) & "00";
				blit_dst_cnt_x		<= blit_cmd_nx;
				blit_dst_cnt_y		<= blit_cmd_ny;
				blit_dst_offset		<= blit_cmd_dimx_dst;
				blit_dst_finish		<= '0';
				dst_dbg.FIRST		<= '1';
				dst_dbg.UNALIGNED	<= blit_cmd_addr_dst(2);
			elsif blit_request = '1' and blit_dst_finish = '0' and (STB_O_blit_dst = '1' and busout_fifo_rdy = '1') then
				dst_dbg.FIRST		<= '0';
				if dst_dbg.LAST = '1' then
					if blit_dst_cnt_y_next = ('0' & X"0000_0000") or blit_dst_cnt_y_next(32) = '1' then
						blit_dst_finish			<= '1';
						blit_finish_strobe(0)	<= '1';
					else
						addr_next			:= (blit_cmd_addr_dst(31 downto 2) & "00") + blit_dst_offset;
						ADDR_O_blit_dst		<= addr_next;
						blit_dst_offset		<= blit_dst_offset + blit_cmd_dimx_dst;
						blit_dst_cnt_x		<= blit_cmd_nx;
						blit_dst_cnt_y 		<= blit_dst_cnt_y_next(31 downto 0);
						dst_dbg.FIRST		<= '1';
						dst_dbg.UNALIGNED		<= addr_next(2);
					end if;
				else
					ADDR_O_blit_dst 	<= blit_dst_addr_next;
					blit_dst_cnt_x 		<= blit_dst_cnt_x_next(31 downto 0);
				end if;
			end if;
		end if;
	end process;	

---------------------------------------------------------------------------------
-- Character generator
---------------------------------------------------------------------------------
inst_char_gen : entity work.char_gen
	GENERIC MAP
	(
		tsvga				=> tsvga,
		CHARACTER_SCALE		=> 1,
		CHAR_ROM_SIZE_X		=> 8,	-- Pixels
		CHAR_ROM_SIZE_Y		=> 16,	-- Pixels
		CHAR_ROM_DEPTH		=> 256,	-- Chars
		MAX_CHAR_PER_LINE	=> 80,	-- Chars
		MAX_LINE_PER_FRAME	=> 32,	-- Chars
		CHAR_SPACING_X		=> 0, 	-- Pixels
		CHAR_SPACING_Y		=> 0,	-- Pixels
		SCREEN_OFFSET_X		=> 16,	-- Pixels
		SCREEN_OFFSET_Y		=> 16	-- Pixels
	)		
	PORT MAP
	(
	    rst				=> RST_I,
	    sys_clk			=> CLK_I,
	    vga_clk			=> vga_clk_in,
	    ce				=> cg_en,
	    frame_pulse		=> scan_rdy,
	    clr_screen		=> cg_clr_screen,
	    clr_line		=> cg_clr_line,
	    din				=> cg_din,
	    dout			=> cg_dout,
	    ascii_we		=> cg_ascii_we,
	    posy_we			=> cg_posy_we,
	    posx_we			=> cg_posx_we,
	    ready			=> cg_rdy,
	    scan_pos_x_in	=> stat_hpos,
	    scan_pos_y_in	=> stat_vpos,
	   	csr_pos_x_out	=> cg_csr_pos_x,
	   	csr_pos_y_out	=> cg_csr_pos_y,
	    char_draw_en	=> cg_draw
    );
	scan_rdy			<= stat_hready and stat_vready;
	cg_en				<= stat_scan;

---------------------------------------------------------------------------------
-- JBUS registers
---------------------------------------------------------------------------------
registers_read: 
	process(CLK_I)
	begin
		if rising_edge(CLK_I) then
			ACK_O			<= '0';
			reg_read_vld	<= '0';
			if CYC_I = '1' and WE_I = '0' then
				ACK_O			<= reg_read_vld;
				reg_read_vld	<= STB_I;
				
				SDAT_O		<= (others => '0');
				case ADDR_I(6 downto 2) is

				-- sys_vga_ctrl
				-- 0x00
				when "00000" =>
					SDAT_O(0)				<= cg_rdy;
					SDAT_O(1)				<= vga_scan_dma_en;
					SDAT_O(2)				<= bufchg_irq_en;
					SDAT_O(3)				<= bufchg_flag;
					SDAT_O(8)				<= blit_cmd_bsy;
					SDAT_O(9)				<= blit_complete_int;
					SDAT_O(10)				<= blit_complete_int_en;
					SDAT_O(11)				<= blit_cmd_empty_int;
					SDAT_O(12)				<= blit_cmd_empty_int_en;
					SDAT_O(23 downto 16)	<= blit_reg_func(7 downto 0);
					SDAT_O(31)				<= blit_request;				-- RO: Blitter is active. Blit jobs avaliable in CMD-FIFO
					
				-- sys_vga_ascii
				-- 0x04
				when "00001" =>
					SDAT_O(7 downto 0)	<= cg_dout;
					
				-- sys_vga_posx
				-- 0x08
				when "00010" =>
					SDAT_O(7 downto 0)	<= to_unsigned(cg_csr_pos_x, 8);

				-- sys_vga_posy
				-- 0x0C
				when "00011" =>
					SDAT_O(7 downto 0)	<= to_unsigned(cg_csr_pos_y, 8);

				-- sys_vga_cgcol
				-- 0x10
				when "00100" =>
					SDAT_O				<= to_unsigned(cg_color);

				-- sys_vga_res
				-- 0x14
				when "00101" =>
					SDAT_O				<= to_unsigned(tsvga.nfps, 8) & to_unsigned(tsvga.ts_v.ncyc_scan, 12) & to_unsigned(tsvga.ts_h.ncyc_scan, 12);

				-- sys_vga_fb_front
				-- 0x18
				when "00110" =>
					SDAT_O				<= vga_fb_front;

				-- sys_vga_fb_back
				-- 0x1C
				when "00111" =>
					SDAT_O				<= vga_fb_back;

				-- sys_blit_descr_src_0
				-- 0x20
				when "01000" =>
					SDAT_O				<= blit_reg_addr_src_0;

				-- 0x24
				when "01001" =>
					SDAT_O				<= blit_reg_dimx_src_0;

				-- sys_blit_descr_src_1
				-- 0x30
				when "01100" =>
					SDAT_O				<= blit_reg_addr_src_1;

				-- 0x34
				when "01101" =>
					SDAT_O				<= blit_reg_dimx_src_1;

				-- sys_blit_descr_dst
				-- 0x40
				when "10000" =>
					SDAT_O				<= blit_reg_addr_dst;

				-- 0x44
				when "10001" =>
					SDAT_O				<= blit_reg_dimx_dst;

				-- sys_blit_reg_nx
				-- 0x50
				when "10100" =>
					SDAT_O				<= blit_reg_nx;

				-- sys_blit_reg_ny
				-- 0x54
				when "10101" =>
					SDAT_O				<= blit_reg_ny;

				-- sys_blit_color
				-- 0x58
				when "10110" =>
					SDAT_O				<= blit_reg_const_color;

				when others => null;
				end case;
			end if;
		end if;	
	end process;

	
registers_write:
	process(CLK_I)
	begin
		if rising_edge(CLK_I) then
			cg_ascii_we				<= '0';
			cg_posy_we				<= '0';
			cg_posx_we				<= '0';
			cg_clr_screen			<= '0';
			cg_clr_line				<= '0';
			bufchg_flag_ack			<= '0';
			blit_request_set		<= '0';
			blit_complete_int_ack	<= '0';
			blit_cmd_empty_int_ack	<= '0';
			if RST_I = '1' then
				cg_din					<= (others => '0');
				vga_scan_dma_en			<= '0';
				bufchg_irq_en			<= '0';
				blit_complete_int_en	<= '0';
				blit_cmd_empty_int_en	<= '0';
				blit_reg_func			<= (others => '0');
				blit_reg_addr_src_0		<= (others => '0');
				blit_reg_addr_src_1		<= (others => '0');
				blit_reg_dimx_src_0		<= (others => '0');
				blit_reg_dimx_src_1		<= (others => '0');
				blit_reg_addr_dst		<= (others => '0');
				blit_reg_dimx_dst		<= (others => '0');
				blit_reg_nx				<= (others => '0');
				blit_reg_ny				<= (others => '0');
				host_fb_front			<= (others => '0');
				host_fb_back			<= (others => '0');
				cg_color				<= (X"FF", X"FF", X"FF", X"FF");
			elsif (STB_I and CYC_I and WE_I) = '1' then
				case ADDR_I(6 downto 2) is
				
				-- sys_vga_ctrl
				-- 0x00
				when "00000" =>
					vga_scan_dma_en			<= SDAT_I(1);
					bufchg_irq_en			<= SDAT_I(2);
					bufchg_flag_ack			<= SDAT_I(3);
					cg_clr_screen			<= SDAT_I(4);
					cg_clr_line				<= SDAT_I(5);
					blit_request_set		<= SDAT_I(8);
					blit_complete_int_ack	<= SDAT_I(9);
					blit_complete_int_en	<= SDAT_I(10);
					blit_cmd_empty_int_ack	<= SDAT_I(11);
					blit_cmd_empty_int_en	<= SDAT_I(12);
					blit_reg_func			<= SDAT_I(23 downto 16);
					
				-- sys_vga_ascii
				-- 0x04
				when "00001" =>
					cg_ascii_we		<= '1';
					cg_din					<= SDAT_I(7 downto 0);
					
				-- sys_vga_posx
				-- 0x08
				when "00010" =>
					cg_posx_we				<= '1';
					cg_din					<= SDAT_I(7 downto 0);

				-- sys_vga_posy
				-- 0x0C
				when "00011" =>
					cg_posy_we				<= '1';
					cg_din					<= SDAT_I(7 downto 0);

				-- sys_vga_cgcol
				-- 0x10
				when "00100" =>
					cg_color				<= to_color_t(SDAT_I(31 downto 0));

				-- sys_vga_fb_front
				-- 0x18
				when "00110" =>
					host_fb_front			<= SDAT_I(31 downto 3) & "000";
					
				-- sys_vga_fb_back
				-- 0x1C
				when "00111" =>
					bufchg_flag_ack	<= '1';
					host_fb_back			<= SDAT_I(31 downto 3) & "000";
					
				-- sys_blit_descr_src_0
				-- 0x20
				when "01000" =>
					blit_reg_addr_src_0		<= SDAT_I(31 downto 0);

				-- 0x24
				when "01001" =>
					blit_reg_dimx_src_0		<= SDAT_I(29 downto 0) & "00";

				-- sys_blit_descr_src_1
				-- 0x30
				when "01100" =>
					blit_reg_addr_src_1		<= SDAT_I(31 downto 0);

				-- 0x34
				when "01101" =>
					blit_reg_dimx_src_1		<= SDAT_I(29 downto 0) & "00";

				-- sys_blit_descr_dst
				-- 0x40
				when "10000" =>
					blit_reg_addr_dst		<= SDAT_I(31 downto 0);
					
				-- 0x44
				when "10001" =>
					blit_reg_dimx_dst		<= SDAT_I(29 downto 0) & "00";

				-- sys_blit_reg_nx
				-- 0x50
				when "10100" =>
					blit_reg_nx				<= SDAT_I;

				-- sys_blit_reg_ny
				-- 0x54
				when "10101" =>
					blit_reg_ny				<= SDAT_I;
									
				-- sys_blit_color
				-- 0x58
				when "10110" =>
					blit_reg_const_color	<= SDAT_I;

				when others => null;
				end case;

			end if;
		end if;
	end process;

	---------------------------------------------------------------------------------------------

end Behavioral;
