-- TOP LEVEL


library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;
use ieee.std_logic_unsigned.all;
use ieee.math_real.all;
library toptest_v1_00_a;

package test_lib is
  component testsuite
  end component;
  
  component timer
    port (clk	:in std_logic;
          reset :in std_logic;
          enable:in std_logic;
          data  :in std_logic_vector (7 downto 0);
          addr  :in std_logic;  -- one bit only
          irq   :out std_logic
         );
  end component;
end test_lib;

-----------------------------------------------------------------------------
-----------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;
use ieee.std_logic_unsigned.all;
use ieee.math_real.all;
library toptest_v1_00_a;

package nes is
  component nes_ppu_still
    port (
      b : out std_logic_vector(7 downto 0);
      g : out std_logic_vector(7 downto 0);
      r : out std_logic_vector(7 downto 0);
      v_addr : out std_logic_vector(13 downto 0);
      v_data : out std_logic_vector(7 downto 0);
      v_read : out std_logic;
      v_write : out std_logic;
      ppu_go : out std_logic;
      addr : in std_logic_vector(15 downto 0);
      clock : in std_logic;
      cpu_data : in std_logic_vector(7 downto 0);
      cpu_r : in std_logic;
      cpu_w : in std_logic;
      rst : in std_logic;
      v_in : in std_logic_vector(7 downto 0)
      );
      
  end component;

  component sram_mux
    port (
      ppu_active    : in  std_logic;
      v_read        : in  std_logic;
      v_write       : in  std_logic;
      cpu_read      : in  std_logic;
      cpu_write     : in  std_logic;
      v_data        : in  std_logic_vector(7 downto 0);
      cpu_data      : in  std_logic_vector(7 downto 0);
      sram_addr_cpu : in  std_logic_vector(15 downto 0);
      sram_addr_ppu : in  std_logic_vector(13 downto 0);
      sram_data_out : out std_logic_vector(15 downto 0);
      sram_read     : out std_logic;
      sram_write    : out std_logic;
      sram_addr     : out std_logic_vector(17 downto 0)
      );
  end component;

  component mem_interface
    port (
      data_to_mem   : in    std_logic_vector(15 downto 0);
      write_to_mem  : in    std_logic;
      read_from_mem : in    std_logic;
      chip_enable   : out   std_logic;
      mem_bus       : inout std_logic_vector(15 downto 0);
      data_from_mem : out   std_logic_vector(15 downto 0);
      upper_en      : out   std_logic;
      lower_en      : out   std_logic;
      output_en     : out   std_logic;
      write_en      : out   std_logic
      );
  end component;

  component vga
    port (
      clk : in std_logic;
      pix_clk : in std_logic;
      rst : in std_logic;
      video_data : in std_logic_vector(7 downto 0);
--    r_data         : in std_logic_vector(7 downto 0);
--     g_data         : in std_logic_vector(7 downto 0);
--     b_data         : in std_logic_vector(7 downto 0);
      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;
end nes;
-----------------------------------------------------------------------------
-----------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;
use ieee.std_logic_unsigned.all;


entity timer is
    port (clk	:in std_logic;
          reset :in std_logic;
          enable:in std_logic;
          data  :in std_logic_vector (7 downto 0);
          addr  :in std_logic;  -- one bit only
          irq   :out std_logic
         );
end timer;

architecture arch_timer of timer is
  type STATES is (IDLE, RUNNING, TRIGGERED);
  signal state :STATES := IDLE;
  signal count :std_logic_vector (7 downto 0) := "00000000";

begin

  process (reset, clk, enable, data, addr)
  begin
    if reset='1' then
      state <= IDLE;
      count <= "00000000";
      irq <= '0';
    elsif clk'event and clk='1' then
      case state is
        when IDLE =>
            if enable='1' and addr='0' then
              count <= data;
              state <= RUNNING;
            end if;
          
        when RUNNING =>
            if count="00000000" then
              state <= TRIGGERED;
              irq <= '1';
            else
              count <= count - '1';
            end if;
          
        when TRIGGERED =>
            if enable='1' and addr='1' then
              state <= IDLE;
              irq <= '0';
            end if;
            
        when others =>
            state <= IDLE;
            irq <= '0';
            
      end case;
    end if;
  end process;

end arch_timer;

  


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


----------------------------------------------------------------------------
----------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
use ieee.std_logic_arith.all;
use ieee.math_real.all;
library toptest_v1_00_a;
use toptest_v1_00_a.test_lib.all;
use toptest_v1_00_a.nes.all;
use toptest_v1_00_a.free_6502.all;

entity toptest is
  
  port (
    OPB_Clk : in std_logic;
    OPB_Rst : in std_logic;
    pixel_clock : 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;
    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;
    PB_D : inout std_logic_vector (15 downto 0));
  
--     fpga_clk_suks                  : in    std_logic;
--     pixel_clk                 : in    std_logic;
--     reset                     : in    std_logic;
--     sram_addr                 : out   std_logic_vector(19 downto 0);
--     sram_data                 : inout std_logic_vector(15 downto 0);
--     sram_ce                   : out   std_logic;
--     sram_ue                   : out   std_logic;
--     sram_le, sram_we, sram_oe : out   std_logic;
--     vo_clk                    : out   std_logic;
--     vo_rcr, vo_gy, vo_bcb     : out   std_logic_vector(9 downto 0);
--     vo_blank                  : out   std_logic;
--     vo_hsync, vo_vsync        : out   std_logic);

end toptest;

architecture arch_testsuite of toptest is
  signal clk		:std_logic ;
  signal clk2           : std_logic;
  
  signal reset		:std_logic := '1';
  signal irq		:std_logic := '0';
  signal nmi		:std_logic := '0';
  signal addr		:std_logic_vector (15 downto 0) := "0000000000000000";
  signal din		:std_logic_vector (7 downto 0) := "00000000";
  signal dout		:std_logic_vector (7 downto 0) := "00000000";
  signal dout_oe	:std_logic := '0';
  signal we		:std_logic := '0';
  signal re		:std_logic := '0';
  signal sync		:std_logic := '0';
  signal rv, bv, gv : std_logic_vector(7 downto 0);
  signal vram_in : std_logic_vector(7 downto 0);
  
--  signal ppu_addr : std_logic_vector(15 downto 0);
  

  signal rom_data	:std_logic_vector (7 downto 0) := "00000000";
  signal ram_data	:std_logic_vector (7 downto 0) := "00000000";
  signal ram_we		:std_logic  := '0';

  signal postcode	:std_logic_vector (7 downto 0) := "00000000";
  signal video_dat : std_logic_vector(7 downto 0);
  signal vram_addr : std_logic_vector(13 downto 0);
  signal vram_data : std_logic_vector(7 downto 0);
  signal vram_rd, vram_wr, pp_go : std_logic;
  signal irq_timer_sel  :std_logic := '0';
  signal nmi_timer_sel  :std_logic := '0';
  signal s_do : std_logic_vector(15 downto 0);
  signal s_r, s_w : std_logic;
  signal s_addr : std_logic_vector(17 downto 0);
  signal control_poll : std_logic := '0';
  signal ppu_select : std_logic := '0';
  signal ppu_2006 : std_logic := '0';
  signal ppu_2000, ppu_2001, ppu_2002, ppu_2003, ppu_2004, ppu_2005, ppu_2007, ppu_2008 : std_logic := '0';
  signal vramin : std_logic_vector(7 downto 0);
  signal r4014 : std_logic := '0';
  signal sram_in : std_logic_vector(15 downto 0);



-- BEGINNING OF TEST!

begin

  process(pixel_clock, OPB_Rst)
    begin
      if OPB_Rst = '1' then
        clk2 <= '0';      
      elsif pixel_clock'event and pixel_clock = '1' then
        clk2 <= not(clk2);
      end if;
    end process;
      
  U1: core_6502 port map
    (clk2, OPB_Rst, irq, nmi, addr, din, dout, dout_oe, we, re, sync);

  PPU: nes_ppu_still port map (bv, gv, rv, vram_addr, vram_data, vram_rd, vram_wr, pp_go, addr, clk2, dout, re, we, OPB_Rst, vramin);

  S_MUX: sram_mux port map (pp_go, vram_rd, vram_wr, re, we, vram_data, dout, addr, vram_addr, s_do, s_r, s_w, s_addr);

  MEM_INT: mem_interface port map (s_do, s_w, s_r, RAM_CE_N, PB_D, sram_in, PB_UB_N, PB_LB_N, PB_OE_N, PB_WE_N);
  
  ram_we <= '1' when we='1' else '0';
  
  din <= sram_in(7 downto 0) when re = '1';

  vramin <= sram_in(7 downto 0) when vram_rd = '1';

  

  video_dat <= rv(7 downto 5) & gv(7 downto 5) & bv(7 downto 6);

  --vga_instance: vga port map (OPB_Clk, pixel_clock, OPB_Rst, video_dat, rv, gv, bv, VIDOUT_CLK, VIDOUT_RCR, VIDOUT_GY, VIDOUT_BCB, VIDOUT_BLANK_N, VIDOUT_HSYNC_N, VIDOUT_VSYNC_N);
    vga_instance: vga port map (OPB_Clk, pixel_clock, OPB_Rst, video_dat, VIDOUT_CLK, VIDOUT_RCR, VIDOUT_GY, VIDOUT_BCB, VIDOUT_BLANK_N, VIDOUT_HSYNC_N, VIDOUT_VSYNC_N);

--          ram_data when addr(15)='0' and re='1' else
--          rom_data when addr(14)='1' and re='1' else
--          ram_data when re = '1' else
--          "00000000";
  

  irq_timer_sel <= '1' when addr(15 downto 1)="100000000000010" and we='1' else '0';
  nmi_timer_sel <= '1' when addr(15 downto 1)="100000000000011" and we='1' else '0';

  IRQ_TIMER0:  timer port map (clk, reset, irq_timer_sel, dout, addr(0), irq);
  NMI_TIMER0:  timer port map (clk, reset, nmi_timer_sel, dout, addr(0), nmi);


  -- Handle the special registers
  -- 0x8000 = HALT
  -- 0x8001 = POSTCODE
  -- 0x8002 = LOGFILE
  process (clk)
    variable d	:integer := 0;
    variable i	:integer range 0 to 10 := 0;
  begin
    if clk'event and clk='0' then
      if we='1' then
        case addr is
          when "1000000000000000" => 	-- HALT simulation
                assert 1=0
                    report "Simulation Ended via 6502 software command"
                    severity failure;
                  
          when "1000000000000001" => 	-- Postcode write
              postcode <= dout;
              
          when "1000000000000010" => 	-- Log file output
	      case i is
        	  when 0 =>		d := conv_integer(dout);
          			        i := i + 1;
	          when 1 =>             d := d + (conv_integer(dout) * 256);
        	  		        i := i + 1;
	          when 2 =>             d := d + (conv_integer(dout) * 256 * 256);
        	  		        i := i + 1;
	          when 3 =>             d := d + (conv_integer(dout) * 256 * 256 * 256);
        	                        i := 0;
                	                --write (log, d);
	          when others =>	d := 0;
        	                        i := 0;
	        end case;

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


  
end arch_testsuite;




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

