library IEEE;
use IEEE.std_logic_1164.All;
use IEEE.std_logic_unsigned.All;

-- line doubler

entity line_doubler is
  port (
    doubler_clk  : in std_logic;
    doubler_data : in std_logic_vector(7 downto 0);
    doubler_reset : in std_logic;
    double_r    : out std_logic_vector(9 downto 0);
    double_g    : out std_logic_vector(9 downto 0);
    double_b    : out std_logic_vector(9 downto 0));
end line_doubler;

architecture Behavioral of line_doubler is

  component RAMB4_S8_S8

  port (DIA    : in STD_LOGIC_VECTOR (7 downto 0);
        DIB    : in STD_LOGIC_VECTOR (7 downto 0);
        ENA    : in STD_logic;
        ENB    : in STD_logic;
        WEA    : in STD_logic;
        WEB    : in STD_logic;
        RSTA   : in STD_logic;
        RSTB   : in STD_logic;
        CLKA   : in STD_logic;
        CLKB   : in STD_logic;
        ADDRA  : in STD_LOGIC_VECTOR (8 downto 0);
        ADDRB  : in STD_LOGIC_VECTOR (8 downto 0);
        DOA    : out STD_LOGIC_VECTOR (7 downto 0);
        DOB    : out STD_LOGIC_VECTOR (7 downto 0));

end component;

  
  constant NES_WIDTH : integer := 256;
  constant NES_HEIGHT : integer := 240;
  constant DOUBLED_WIDTH : integer := 512;
  constant DOUBLED_HEIGHT : integer := 480;
  constant CENTER_OFFSET : integer := 64;
  constant HALF_CENTER_OFFSET : integer := 32;

  constant H_ACTIVE      : integer := 640;
  constant H_FRONT_PORCH : integer := 16;
  constant H_BACK_PORCH  : integer := 48;
  --may need to modify h_total because of the difference between
  --the nes clock and vga's clock
  constant H_TOTAL       : integer := 800;

  constant V_ACTIVE      : integer := 480;
  constant V_FRONT_PORCH : integer := 11;
  constant V_BACK_PORCH  : integer := 31;
  constant V_TOTAL       : integer := 524;

  signal d_bram_out : std_logic_vector(7 downto 0);

  --read from the input byte
  signal hor_read_in_bounds : std_logic := '1';
  signal ver_read_in_bounds : std_logic := '1';

  --write to the rgb signals
  signal hor_write_in_bounds : std_logic := '0';
  signal ver_write_in_bounds : std_logic := '0';

  signal ram_write_enable : std_logic;
  signal ram_read_enable : std_logic;

  signal address_a : std_logic_vector(8 downto 0);
  signal address_b : std_logic_vector(8 downto 0);

  signal pixel_count : std_logic_vector(10 downto 0);
  signal line_count : std_logic_vector(9 downto 0);

  signal r_temp : std_logic_vector(9 downto 0);
  signal g_temp : std_logic_vector(9 downto 0);
  signal b_temp : std_logic_vector(9 downto 0);

begin
  
    -- Pixel counter

  process ( doubler_clk, doubler_reset )
  begin
    if doubler_reset = '1' then
      pixel_count <= "00000000000";
    elsif doubler_clk'event and doubler_clk = '1' then
      if pixel_count = (H_TOTAL - 1) then
        pixel_count <= "00000000000";
      else
        pixel_count <= pixel_count + 1;
      end if;
    end if;    
  end process;

  -- Line counter
  
  process ( doubler_clk, doubler_reset )
  begin
    if doubler_reset = '1' then
      line_count <= "0000000000";
    elsif doubler_clk'event and doubler_clk = '1' then
      if ((line_count = V_TOTAL - 1) and (pixel_count = H_TOTAL - 1)) then
        line_count <= "0000000000";
      elsif pixel_count = (H_TOTAL - 1) then
        line_count <= line_count + 1;
      end if;
    end if;
  end process;

  -- create a signal to determine whether we want to write to our output signals
  -- if we're in bounds vertically

  --we don't need to take into account the porches, so i deleted the vtotal-front-back
  --bill
  process(doubler_clk)
  begin
    if doubler_clk'event and doubler_clk = '1' then
      if ((line_count = (DOUBLED_HEIGHT - 1)) and (pixel_count = (H_TOTAL - 1))) then
        ver_write_in_bounds <= '0';
      elsif ((line_count = (V_TOTAL - 1)) and (pixel_count = (H_TOTAL - 1))) then
        ver_write_in_bounds <= '1';
      end if;
    end if;
  end process;

  -- create a signal to determine whether we want to read from our input signal
  -- if we're in bounds vertically

  --we don't need to take into account the porches, so i deleted the vtotal-front-back
  --bill
  process(doubler_clk)
  begin
    if doubler_clk'event and doubler_clk = '1' then
      if ((line_count = (DOUBLED_HEIGHT - 1)) and (pixel_count = (H_TOTAL - 1))) then
        ver_read_in_bounds <= '0';
      elsif ((line_count = (V_TOTAL - 1)) and (pixel_count = (H_TOTAL - 1))) then
        ver_read_in_bounds <= '1';
      end if;
    end if;
  end process;

    -- create a signal to determine whether we want to write to our output signals
  -- if we're in bounds horizontally
  process(doubler_clk)
  begin
    if doubler_clk'event and doubler_clk = '1' then
      if pixel_count = (DOUBLED_WIDTH + CENTER_OFFSET - 1) then
        hor_write_in_bounds <= '0';
      elsif pixel_count = (CENTER_OFFSET - 1) then
        hor_write_in_bounds <= '1';
      end if;
    end if;
  end process;


  -- create a signal to determine whether we want to read from our input signal
  -- if we're in bounds horizontally
  process(doubler_clk)
  begin
    if doubler_clk'event and doubler_clk = '1' then
      if pixel_count = (DOUBLED_WIDTH - 1) then
        hor_read_in_bounds <= '0';
      elsif pixel_count = (H_TOTAL - 1) then
        hor_read_in_bounds <= '1';
      end if;
    end if;
  end process;

  --create ram signals
  process(doubler_clk)
  begin
    if doubler_clk'event and doubler_clk = '1' then
      ram_write_enable <= hor_read_in_bounds and ver_read_in_bounds and pixel_count(0);
      address_a <= line_count(1) & pixel_count(8 downto 1);
      address_b <= not line_count(1) & pixel_count(8 downto 1) - HALF_CENTER_OFFSET + 1;      
    end if;
  end process;
  

 --BRAM
 line_bram : RAMB4_S8_S8 port map (
         DIA    => doubler_data ,
         ENA    => '1',
         WEA    => ram_write_enable,
         RSTA   => '0',
         CLKA   => doubler_clk,
         ADDRA  => address_a,
         DOA    => open,

         DIB    => X"00",
         ENB    => '1',
         WEB    => '0',
         RSTB   => '0',
         CLKB   => doubler_clk,
         ADDRB  => address_b,
         DOB    => d_bram_out
 );

  
  
  --assign the output signals
   double_r <= d_bram_out(7 downto 5) & "0000000"
               when ((hor_write_in_bounds = '1') and (ver_write_in_bounds = '1'))
               else "1111111111";-- when (hor_write_in_bounds = '0') else "0000000000";
   double_g <= d_bram_out(4 downto 2) & "0000000"
               when ((hor_write_in_bounds = '1') and (ver_write_in_bounds = '1'))
               else "1111111111";-- when (hor_write_in_bounds = '0') else "0000000000";
   double_b <= d_bram_out(1 downto 0) & "00000000"
               when ((hor_write_in_bounds = '1') and (ver_write_in_bounds = '1'))
               else "1111111111";-- when (hor_write_in_bounds = '0') else "0000000000";

       
end Behavioral;
