library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

use work.vbs_graphics_controller_pkg.all;
use work.ram_pkg.all;
use work.math_pkg.all;
use work.gfx_util_pkg.all;
use work.gfx_if_pkg.all;

entity vbs_graphics_controller is
	generic (
		CLK_FREQ : integer := 50_000_000
	);
	port (
		clk   : in std_logic;
		res_n : in std_logic;
		
		--instruction interface
		gfx_instr       : in std_logic_vector(GFX_INSTR_WIDTH-1 downto 0);
		gfx_instr_wr    : in std_logic;
		gfx_instr_full  : out std_logic;
		gfx_data        : in std_logic_vector(GFX_DATA_WIDTH-1 downto 0);
		gfx_data_wr     : in std_logic;
		gfx_data_full   : out std_logic;
		
		gfx_frame_sync    : out std_logic;
		
		-- interface to ADV7123
		vga_r : out std_logic_vector(7 downto 0);
		vga_g : out std_logic_vector(7 downto 0);
		vga_b : out std_logic_vector(7 downto 0);
		vga_clk : out std_logic;
		vga_sync_n : out std_logic;
		vga_blank_n : out std_logic
	);
end entity;

architecture vbs_graphics_controller_arch of vbs_graphics_controller is
	constant COLOR_WIDTH : integer := 2;
	-- gfx bounding box
	constant WIDTH  : integer := 400;
	constant HEIGHT : integer := 240;
	-- fifo element count
	constant FIFO_DATA_DEPTH  : integer := 8;
	constant FIFO_INSTR_DEPTH : integer := 8;
	-- fifo element width
	constant FIFO_DATA_WIDTH  : integer := 16;
	constant FIFO_INSTR_WIDTH : integer := 8;
	-- dpram
	-- factor 2 due to double buffering
	constant VRAM_ADDR_WIDTH : integer := log2c(2 * WIDTH * HEIGHT);
	constant VRAM_DATA_WIDTH : integer := 2;

	signal vram_wr      : std_logic;
	signal vram_wr_addr : std_logic_vector(VRAM_ADDR_WIDTH - 1 downto 0);
	signal vram_wr_data : std_logic_vector(VRAM_DATA_WIDTH - 1 downto 0);
	signal vram_rd      : std_logic;
	signal vram_rd_addr : std_logic_vector(VRAM_ADDR_WIDTH - 1 downto 0);
	signal vram_rd_data : std_logic_vector(VRAM_DATA_WIDTH - 1 downto 0);

	signal vram_base_addr : std_logic_vector(VRAM_ADDR_WIDTH - 1 downto 0);
	signal frame_start : std_logic;

	signal pix_rd   : std_logic;
	signal pix_data : std_logic_vector(VRAM_DATA_WIDTH - 1 downto 0);
begin

	vram_inst : dp_ram_1c1r1w
	generic map (
		ADDR_WIDTH => VRAM_ADDR_WIDTH,
		DATA_WIDTH => VRAM_DATA_WIDTH
	)
	port map (
		clk   => clk,

		rd1_addr => vram_rd_addr,
		rd1_data => vram_rd_data,
		rd1      => vram_rd,

		wr2_addr => vram_wr_addr,
		wr2_data => vram_wr_data,
		wr2      => vram_wr
	);

	frame_reader_inst : frame_reader
	generic map (
		WIDTH  => WIDTH,
		HEIGHT => HEIGHT,
		-- ram
		VRAM_ADDR_WIDTH => VRAM_ADDR_WIDTH,
		VRAM_DATA_WIDTH => VRAM_DATA_WIDTH
	)
	port map (
		clk   => clk,
		res_n => res_n,
		
		-- frame synchronization signal
		frame_start    => frame_start,
		vram_base_addr => vram_base_addr,
		
		-- interface to the video RAM
		vram_rd   => vram_rd,
		vram_addr => vram_rd_addr,
		vram_data => vram_rd_data,
		
		pix_rd   => pix_rd,
		pix_data => pix_data
		--pix_rd   => open,
		--pix_data => open
	);

/*
	tpg_inst : tpg
	generic map (
		WIDTH  => WIDTH,
		HEIGHT => HEIGHT
	)
	port map (
		clk   => clk,
		res_n => res_n,
		
		pix_rd   => pix_rd,
		pix_data => pix_data
	);
*/

	rasterizer_inst : rasterizer
	generic map (
		-- how many bits downto 0 are stored for the color of a pixel
		COLOR_WIDTH => COLOR_WIDTH,
		-- gfx bounding box
		WIDTH  => WIDTH,
		HEIGHT => HEIGHT,
		--  FIFO element count
		FIFO_DATA_DEPTH  => FIFO_DATA_DEPTH,
		FIFO_INSTR_DEPTH => FIFO_INSTR_DEPTH,
		-- FIFO elementh width
		FIFO_DATA_WIDTH  => FIFO_DATA_WIDTH,
		FIFO_INSTR_WIDTH => FIFO_INSTR_WIDTH,
		-- DP RAM 
		-- double buffering requires a factor 2
		VRAM_ADDR_WIDTH => VRAM_ADDR_WIDTH,
		VRAM_DATA_WIDTH => VRAM_DATA_WIDTH
	)
	port map (
		clk   => clk,
		res_n => res_n,

		gfx_instr      => gfx_instr,
		gfx_instr_wr   => gfx_instr_wr,
		gfx_instr_full => gfx_instr_full,
		gfx_data       => gfx_data,
		gfx_data_wr    => gfx_data_wr,
		gfx_data_full  => gfx_data_full,
		gfx_frame_sync => gfx_frame_sync,

		-- frame synchronization signal
		frame_start    => frame_start,
		vram_base_addr => vram_base_addr,

		-- exposed dp ram storage
		-- (only write buffers! read buffers managed by frame_reader)
		vram_wr   => vram_wr,
		vram_addr => vram_wr_addr,
		vram_data => vram_wr_data
	);

	adv7123 : dac
	generic map (
		CLK_FREQ        => CLK_FREQ,
		VRAM_DATA_WIDTH => VRAM_DATA_WIDTH
	)
	port map (
		clk   => clk,
		res_n => res_n,

		rd   => pix_rd,
		data => pix_data,

		-- ADV7123 interface
		vga_r   => vga_r,
		vga_g   => vga_g,
		vga_b   => vga_b,
		vga_clk => vga_clk,
		-- low active
		vga_sync_n  => vga_sync_n,
		-- low active
		vga_blank_n => vga_blank_n
	);

end architecture;
