-------------------------------------------------------------------------------
--
-- Component: MUX21
--
-------------------------------------------------------------------------------
library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.std_logic_arith.all;
use IEEE.std_logic_unsigned.all;

entity mux21 is
  port(
    sel : in std_logic;
    input1, input0 : in std_logic;
    output : out std_logic
  );
end mux21;

architecture mux21_arch of mux21 is
begin
  process(sel)
    begin
      if sel = '1' then
        output <= input1;
      else
        output <= input0;
      end if;
  end process;
end mux21_arch;

-------------------------------------------------------------------------------
--
-- Component: MUX21_20 for 20 bits
--
-------------------------------------------------------------------------------
library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.std_logic_arith.all;
use IEEE.std_logic_unsigned.all;

entity mux21_20 is
  port(
    sel : in std_logic;
    input1, input0 : in std_logic_vector( 19 downto 0 );
    output : out std_logic_vector( 19 downto 0 )
  );
end mux21_20;

architecture mux21_20_arch of mux21_20 is
begin
  process(sel)
    begin
      if sel = '1' then
        output <= input1;
      else
        output <= input0;
      end if;
  end process;
end mux21_20_arch;

-------------------------------------------------------------------------------
--
-- Component: FSM for Bresenham's Algorithm
--
-------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;
use ieee.std_logic_unsigned.all;

entity fsm_bresenhams is
   port (
    -- OPB signals
     X0      : in std_logic_vector (15 downto 0);
     X1      : in std_logic_vector (15 downto 0);
     Y0      : in std_logic_vector (15 downto 0);
     Y1      : in std_logic_vector (15 downto 0);
     -- start : in std_logic;
     --
      : out std_logic;
     OPB_Clk : in std_logic;
     OPB_Rst : in std_logic;

     stall   : in std_logic;
     wr      : out std_logic;
     A       : out std_logic_vector (19 downto 0);
     D       : out std_logic_vector (15 downto 0)
   );

end fsm_bresenhams;

architecture fsm_bresenhams_arch of fsm_bresenhams is

   signal address : std_logic_vector(19 downto 0):=X"00000";
   signal data : std_logic_vector(15 downto 0):= X"0000";
begin

   draw: process (OPB_Clk,OPB_Rst)

 begin

        if OPB_Rst = '1' then
          data <= ( others => '0');
          address <= ( others => '0');
        elsif OPB_Clk'event and OPB_Clk = '1' and stall = '0' then
			address <= address + 1;
			data <= data + 1;

			if address >= 320*480 then
				address <= ( others => '0');
				data <= ( others => '0');
			end if;

		end if;

  end process draw;

  wr <= '1';
                        
  A<=address;
  D<=data;


                        
end fsm_bresenhams_arch;

-------------------------------------------------------------------------------
--
-- Text-mode VGA controller for the XESS-300E
--
-- Uses an OPB interface, e.g., for use with the Microblaze soft core
--
-- Stephen A. Edwards
-- sedwards@cs.columbia.edu
--
-------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;
use ieee.std_logic_unsigned.all;

entity opb_xsb300e_vga is
  
  generic (
    C_OPB_AWIDTH : integer                   := 32;
    C_OPB_DWIDTH : integer                   := 32;
    C_BASEADDR   : std_logic_vector(31 downto 0) := X"FEFF1000";
    C_HIGHADDR   : std_logic_vector(31 downto 0) := X"FEFF1FFF"
  );

  port (
    -- OPB signals
    OPB_Clk        : in std_logic;
    OPB_Rst        : in std_logic;
    OPB_ABus       : in std_logic_vector (31 downto 0);
    OPB_BE         : in std_logic_vector (3 downto 0);
    OPB_DBus       : in std_logic_vector (31 downto 0);
    OPB_RNW        : in std_logic;
    OPB_select     : in std_logic;
    OPB_seqAddr    : in std_logic;

    VGA_DBus       : out std_logic_vector (31 downto 0);
    VGA_errAck     : out std_logic;
    VGA_retry      : out std_logic;
    VGA_toutSup    : out std_logic;
    VGA_xferAck    : out std_logic;

    Pixel_Clock    : in std_logic;

    -- PAD IO Output signals
    PB_A : out std_logic_vector(19 downto 0);
    PB_UB_N : out std_logic;
    PB_LB_N : out std_logic;
    PB_WE_N : out std_logic;
    PB_OE_N : out std_logic;
    RAM_CE_N : out std_logic;
    PB_D : inout std_logic_vector(15 downto 0);
 
    -- Video Output signals
    VIDOUT_CLK     : out std_logic;
    VIDOUT_RED     : out std_logic_vector(9 downto 0);
    VIDOUT_GREEN   : out std_logic_vector(9 downto 0);
    VIDOUT_BLUE    : out std_logic_vector(9 downto 0);
    VIDOUT_BLANK_N : out std_logic;
    VIDOUT_HSYNC_N : out std_logic;
    VIDOUT_VSYNC_N : out std_logic
  );

end opb_xsb300e_vga;

architecture Behavioral of opb_xsb300e_vga is

  component vga
    port (
      clk : in std_logic;
      pix_clk : in std_logic;
      rst : in std_logic;
      video_data : in std_logic_vector(15 downto 0);
      video_addr : out std_logic_vector(19 downto 0);
      video_req : out std_logic;
      vidout_clk : out std_logic;
      vidout_RCR : out std_logic_vector(9 downto 0);
      vidout_GY : out std_logic_vector(9 downto 0);
      vidout_BCB : out std_logic_vector(9 downto 0);
      vidout_BLANK_N : out std_logic;
      vidout_HSYNC_N : out std_logic;
      vidout_VSYNC_N : out std_logic
    );
  end component;

  component pad_io
    port (
      clk : in std_logic;
      rst : in std_logic;
      PB_A : out std_logic_vector(19 downto 0);
      PB_UB_N : out std_logic;
      PB_LB_N : out std_logic;
      PB_WE_N : out std_logic;
      PB_OE_N : out std_logic;
      RAM_CE_N : out std_logic;
      PB_D : inout std_logic_vector(15 downto 0);
      pb_addr : in std_logic_vector(19 downto 0);
      pb_ub : in std_logic;
      pb_lb : in std_logic;
      pb_wr : in std_logic;
      pb_rd : in std_logic;
      ram_ce : in std_logic;
      pb_dread : out std_logic_vector(15 downto 0);
      pb_dwrite : in std_logic_vector(15 downto 0)
    );
  end component;

  component mux21
    port (
      sel : in std_logic;
      input1, input0 : in std_logic;
      output : out std_logic
    );
  end component;
  
  component mux21_20
    port (
      sel : in std_logic;
      input1, input0 : in std_logic_vector( 19 downto 0 );
      output : out std_logic_vector( 19 downto 0 )
    );
  end component;
  
  component fsm_bresenhams
    port (
      X0      : in std_logic_vector (15 downto 0);
      X1      : in std_logic_vector (15 downto 0);
      Y0      : in std_logic_vector (15 downto 0);
      Y1      : in std_logic_vector (15 downto 0);
      OPB_Clk : in std_logic;
      OPB_Rst : in std_logic;

      stall   : in std_logic;
      wr      : out std_logic;
      A       : out std_logic_vector (19 downto 0);
      D       : out std_logic_vector (15 downto 0)
    );
  end component;

  -----------------------------------------------------------------------------
  --
  -- OPB-RAM controller
  --
  -----------------------------------------------------------------------------

 -- Signals for OPB
 signal opb_A, opb_D : std_logic_vector(31 downto 0);
 signal opb_RW : std_logic;

 -- Signals for FSM
 signal fsm_WR : std_logic;
 signal fsm_A : std_logic_vector(19 downto 0);
 signal fsm_D : std_logic_vector(15 downto 0);

 -- Signals for VGA
 signal vga_A : std_logic_vector(19 downto 0);
 signal vga_D : std_logic_vector(15 downto 0);
 signal vga_request : std_logic;

 -- Signals for the MUXs
 signal mux_address_A : std_logic_vector(19 downto 0);
 signal mux_request_WR : std_logic;


signal vga_req_1, vga_req_2 : std_logic;
signal vga_D_int : std_logic_vector(15 downto 0);

signal X0, Y0, X1, Y1 : std_logic_vector(15 downto 0);
signal active : std_logic;

type opb_state is (IDLE, COMMON, XFER);
signal cstate, nxstate : opb_state;

signal cs, wr, rd : std_logic;
  
 --Signals for PadIO
 
 begin
 
 vga1 : vga
    port map (
      clk => OPB_Clk,
      pix_clk => Pixel_Clock,
      rst => OPB_Rst,
      --video_data => X"00FF",
      video_data => vga_D,
      video_addr => vga_A,
      video_req => vga_request,
      vidout_clk => VIDOUT_Clk,
      vidout_RCR => VIDOUT_RED,
      vidout_GY => VIDOUT_GREEN,
      vidout_BCB => VIDOUT_BLUE,
      vidout_BLANK_N => VIDOUT_BLANK_N,
      vidout_HSYNC_N => VIDOUT_HSYNC_N,
      vidout_VSYNC_N => VIDOUT_VSYNC_N
    );

  padio1 : pad_io
    port map (
      clk => OPB_Clk,
      rst => OPB_Rst,
      PB_A => PB_A,
      PB_UB_N => PB_UB_N,
      PB_LB_N => PB_LB_N,
      PB_WE_N => PB_WE_N,
      PB_OE_N => PB_OE_N,
      RAM_CE_N => RAM_CE_N,
      PB_D => PB_D,
      pb_addr => mux_address_A,
      pb_ub => '1',
      pb_lb => '1',
	  pb_wr => mux_request_WR,
      --pb_wr => '0',
      pb_rd => vga_request,
      ram_ce => '1',
	  --pb_dread => fsm_D,
      --pb_dwrite => vga_D
      pb_dread => vga_D_int,
      pb_dwrite => fsm_D
    );

  fsm: fsm_bresenhams
    port map(
      X0 => "1111111111111111",
      X1 => "1111111111111111",
      Y0 => "1111111111111111",
      Y1 => "1111111111111111",
      OPB_Clk => OPB_Clk,
      OPB_Rst => OPB_Rst,

      stall => vga_request,
      wr => fsm_WR,
      --wr => '1',
      A => fsm_A,
      D => fsm_D
    );

  mux_request : mux21
    port map (
      sel => vga_request,
      input1 => '0',
      input0 => fsm_WR,
      output => mux_request_WR
    );

  mux_address : mux21_20
    port map (
      sel => vga_request,
      input1 => vga_A,
      input0 => fsm_A,
      output => mux_address_A
    );

process(OPB_Clk)
begin
  if OPB_Clk'event and OPB_Clk='1' then
    vga_req_1 <= vga_request;
    vga_req_2 <= vga_req_1;
    if vga_req_2 = '1' then
      vga_D <= vga_D_int;
    end if;
  end if;
end process;




  -- Unused OPB control signals
  VGA_errAck <= '0';
  VGA_retry <= '0';
  VGA_toutSup <= '0';

  -- Latch the relevant OPB signals from the OPB, since they arrive late
  LatchOPB: process (OPB_Clk, OPB_Rst)
  begin
    if OPB_Rst = '1' then
      opb_A <= ( others => '0' );
      opb_D <= ( others => '0' );
      opb_RW <= '1';
      cstate <= IDLE;
    elsif OPB_Clk'event and OPB_Clk = '1' then
      opb_A <= OPB_ABus;
      opb_D <= OPB_DBus;
      opb_RW <= OPB_RW;
      cstate <= nxstate;
    end if;
  end process LatchOPB;

process (cstate, cs)
  begin
    nxstate <= cstate;
    wr <= '0';
    rd <= '0';
    VGA_xferAck  <= '0';

    case cstate is
      when IDLE => if cs = '1' then
        nxstate <= COMMON;
      end if;
      when COMMON =>
        if opb_RW = '0' then           -- write
          wr <= '1';
        else                            -- read
          rd <= '1';
        end if;
        nxstate <= XFER;
      when XFER =>
        VGA_xferAck  <= '1';
        nxstate <= IDLE;
    end case;

  end process;

 process (OPB_Clk, OPB_Rst)
  begin
    if OPB_Rst = '1' then
      VGA_Dbus <= ( others => '0');
      X0 <= (others => '0');
      Y0 <= (others => '0');
      X1 <= (others => '0');
      Y1 <= (others => '0');
      active <= '0';

    elsif OPB_Clk'event and OPB_Clk = '1' then
      if wr = '1' then
      -- write
        case opb_A(4 downto 2) is
          when "000" => X0 <= opb_d(15 downto 0);
          when "001" => X1 <= opb_d(15 downto 0);
          when "010" => Y0 <= opb_d(15 downto 0);
          when "011" => Y1 <= opb_d(15 downto 0);
          when "100" => active <= '1';
          when others => null;
        end case;
      end if;
      if rd = '1' then
        -- read
        case opb_A(4 downto 2) is
          when "100" =>  VGA_Dbus <= (active, others => '0');
          when others => null;
        end case;
      else
         VGA_Dbus <= ( others => '0');
      end if;

      if ready = '1' then
        active <= '0';
      end if;

    end if;
  end process;
 
 
end Behavioral;


