-- ****
-- T65(b) core. In an effort to merge and maintain bug fixes ....
--
--
-- Ver 303 ost(ML) July 2014
--   (Sorry for some scratchpad comments that may make little sense)
--   Mods and some 6502 undocumented instructions.
--   Undoc opcodes learnt from:
--   "Extra Instructions Of The 65XX Series CPU"
--   By: Adam Vardy (abe0084@infonet.st-johns.nf.ca)
--   [File created: 22, Aug. 1995... 27, Sept. 1996]
-- Ver 302 minor timing fixes
-- Ver 301 Jump timing fixed
-- Ver 300 Bugfixes by ehenciak added
-- Wolfgang January 2014
-- MikeJ March 2005
-- Latest version from www.fpgaarcade.com (original www.opencores.org)
--
-- ****
--
-- 65xx compatible microprocessor core
--
-- Version : 0246 + fix
--
-- Copyright (c) 2002 Daniel Wallner (jesus@opencores.org)
--
-- All rights reserved
--
-- Redistribution and use in source and synthezised forms, with or without
-- modification, are permitted provided that the following conditions are met:
--
-- Redistributions of source code must retain the above copyright notice,
-- this list of conditions and the following disclaimer.
--
-- Redistributions in synthesized form must reproduce the above copyright
-- notice, this list of conditions and the following disclaimer in the
-- documentation and/or other materials provided with the distribution.
--
-- Neither the name of the author nor the names of other contributors may
-- be used to endorse or promote products derived from this software without
-- specific prior written permission.
--
-- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-- AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
-- THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
-- PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE
-- LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-- CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-- INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-- CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-- POSSIBILITY OF SUCH DAMAGE.
--
-- Please report bugs to the author, but before you do so, please
-- make sure that this is not a derivative work and that
-- you have the latest version of this file.
--
-- The latest version of this file can be found at:
--      http://www.opencores.org/cvsweb.shtml/t65/
--
-- Limitations :
--
-- 65C02
-- supported : inc, dec, phx, plx, phy, ply
-- missing : bra, ora, lda, cmp, sbc, tsb*2, trb*2, stz*2, bit*2, wai, stp, jmp, bbr*8, bbs*8
--
-- File history :
--
--      0246 : First release
--

library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.numeric_std.all;
use ieee.std_logic_unsigned.all; 
use work.T65_Pack.all;

entity T65_MCode is
  port(
    Mode                    : in  std_logic_vector(1 downto 0);      -- "00" => 6502, "01" => 65C02, "10" => 65816
    IR                      : in  std_logic_vector(7 downto 0);
    MCycle                  : in  std_logic_vector(2 downto 0);
    P                       : in  std_logic_vector(7 downto 0);
    LCycle                  : out std_logic_vector(2 downto 0);
    ALU_Op                  : out T_ALU_Op;
    Set_BusA_To             : out T_Set_BusA_To;-- DI,A,X,Y,S,P
    Set_Addr_To             : out T_Set_Addr_To;-- PC Adder,S,AD,BA
    Write_Data              : out T_Write_Data;-- DL,A,X,Y,S,P,PCL,PCH,A&X
    Jump                    : out std_logic_vector(1 downto 0); -- PC,++,DIDL,Rel
    BAAdd                   : out std_logic_vector(1 downto 0);     -- None,DB Inc,BA Add,BA Adj
    BreakAtNA               : out std_logic;
    ADAdd                   : out std_logic;
    AddY                    : out std_logic;
    PCAdd                   : out std_logic;
    Inc_S                   : out std_logic;
    Dec_S                   : out std_logic;
    LDA                     : out std_logic;
    LDP                     : out std_logic;
    LDX                     : out std_logic;
    LDY                     : out std_logic;
    LDS                     : out std_logic;
    LDDI                    : out std_logic;
    LDALU                   : out std_logic;
    LDAD                    : out std_logic;
    LDBAL                   : out std_logic;
    LDBAH                   : out std_logic;
    SaveP                   : out std_logic;
    ALUmore                 : out std_logic;
    Write                   : out std_logic
  );
end T65_MCode;

architecture rtl of T65_MCode is

  signal Branch : std_logic;
  --ML:I need the Lcycle locally, so I made it a signal.
  signal tLcycle:std_logic_vector(Lcycle'range);
  signal tALUmore:std_logic;

  --Some simulation debug values. Put an unique number for each assignment and identify it in simulation.
  signal dbg_Set_BusA_To	:integer:=0;	--sim debug value to find where Set_BusA_To gets set.
  signal dbg_LCycle			:integer:=0;	--sim debug value to fin where tLCycle gets set.
  signal dbg_Set_Addr_To	:integer:=0;	--sim debug value to fin where Set_Addr_To gets set.

begin

  with IR(7 downto 5) select
    Branch <= not P(Flag_N) when "000",
            P(Flag_N) when "001",
          not P(Flag_V) when "010",
            P(Flag_V) when "011",
          not P(Flag_C) when "100",
            P(Flag_C) when "101",
          not P(Flag_Z) when "110",
            P(Flag_Z) when others;

  LCycle<=tLCycle;
  ALUmore<=tALUmore;

  process (IR, MCycle, P, Branch, Mode,tALUmore)
  begin
    tLCycle      <= "001";
    Set_BusA_To <= Set_BusA_To_ABC;
    Set_Addr_To <= Set_Addr_To_PBR;
    Write_Data  <= Write_Data_DL;
    Jump        <= (others => '0');
    BAAdd       <= "00";
    BreakAtNA   <= '0';
    ADAdd       <= '0';
    PCAdd       <= '0';
    Inc_S       <= '0';
    Dec_S       <= '0';
    LDA         <= '0';
    LDP         <= '0';
    LDX         <= '0';
    LDY         <= '0';
    LDS         <= '0';
    LDDI        <= '0';
    LDALU       <= '0';
    LDAD        <= '0';
    LDBAL       <= '0';
    LDBAH       <= '0';
    SaveP       <= '0';
    Write       <= '0';
    AddY        <= '0';
    tALUmore    <='0';

    case IR(7 downto 5) is
    when "100" =>--covers 8x,9x
    --{{{
      case IR(1 downto 0) is
      when "00" =>
        Set_BusA_To <= Set_BusA_To_Y;
        dbg_Set_BusA_To<=1;
        Write_Data <= Write_Data_Y;
      when "10" =>
        Set_BusA_To <= Set_BusA_To_X;
        dbg_Set_BusA_To<=2;
        Write_Data <= Write_Data_X;
      when others =>
        Write_Data <= Write_Data_ABC;
      end case;
    --}}}
    when "101" =>--covers ax,bx
    --{{{
      case IR(1 downto 0) is
      when "00" =>
        if IR(4) /= '1' or IR(2) /= '0' then--only for ax or b4,bc
          LDY <= '1';
        end if;
      when "10" =>
        LDX <= '1';
      when "11" =>--undoc (beware OAL(ab),LAS(bb)=>Dont know what will happen)
      	LDX<='1';
      	LDA<='1';
      when others =>
        LDA <= '1';
      end case;
      Set_BusA_To <= Set_BusA_To_DI;
      dbg_Set_BusA_To<=4;
    --}}}
    when "110" =>--covers cx,dx
    --{{{
      case IR(1 downto 0) is
      when "00" =>
        if IR(4) = '0' then--only for cx
          LDY <= '1';
        end if;
        Set_BusA_To <= Set_BusA_To_Y;
        dbg_Set_BusA_To<=5;
      when others =>
        Set_BusA_To <= Set_BusA_To_ABC;
        dbg_Set_BusA_To<=6;
      end case;
    --}}}
    when "111" =>--covers ex,fx
    --{{{
      case IR(1 downto 0) is
      when "00" =>
        if IR(4) = '0' then--only ex
          LDX <= '1';
        end if;
        Set_BusA_To <= Set_BusA_To_X;
        dbg_Set_BusA_To<=7;
      when others =>
        Set_BusA_To <= Set_BusA_To_ABC;
        dbg_Set_BusA_To<=8;
      end case;
    --}}}
    when others =>
    end case;

--    if IR(7 downto 6) /= "10" and IR(1 downto 0) = "10" then--covers 0x-7x,cx-fx x=2,6,a,e
    if IR(7 downto 6) /= "10" and IR(1) = '1' and (mode="00" or IR(0)='0') then--covers 0x-7x,cx-fx x=2,3,6,7,a,b,e,f, for 6502 undocs
--      if Mode="00" and IR(0)='1' and ((IR(3 downto 2)="11" and MCycle = "101") or (IR(3 downto 2)="01" and MCycle = "100"))then
      --if Mode="00" and IR(0)='1' and MCycle+1 = tLCycle then
      if tALUmore='1' then 
        Set_BusA_To <= Set_BusA_To_ABC;--For added compare to DCP/DCM
        dbg_Set_BusA_To<=99;
      else
        Set_BusA_To <= Set_BusA_To_DI;
        dbg_Set_BusA_To<=9;
      end if;
    end if;

    case IR(4 downto 0) is
    when "00000" | "01000" | "01010" | "11000" | "11010" =>
    --{{{
      -- Implied
      case IR is
      when "00000000" =>
        -- BRK
        tLCycle <= "110";
        dbg_LCycle<=1;
        case to_integer(unsigned(MCycle)) is
        when 1 =>
          Set_Addr_To <= Set_Addr_To_S;
          dbg_Set_Addr_To<=1;
          Write_Data <= Write_Data_PCH;
          Write <= '1';
        when 2 =>
          Dec_S <= '1';
          Set_Addr_To <= Set_Addr_To_S;
          dbg_Set_Addr_To<=2;
          Write_Data <= Write_Data_PCL;
          Write <= '1';
        when 3 =>
          Dec_S <= '1';
          Set_Addr_To <= Set_Addr_To_S;
          dbg_Set_Addr_To<=3;
          Write_Data <= Write_Data_P;
          Write <= '1';
        when 4 =>
          Dec_S <= '1';
          Set_Addr_To <= Set_Addr_To_BA;
          dbg_Set_Addr_To<=4;
        when 5 =>
          LDDI <= '1';
          Set_Addr_To <= Set_Addr_To_BA;
          dbg_Set_Addr_To<=5;
        when 6 =>
          Jump <= "10"; -- DIDL
        when others =>
        end case;
      when "00100000" =>
        -- JSR
        tLCycle <= "101";
        dbg_LCycle<=2;
        case to_integer(unsigned(MCycle)) is
        when 1 =>
          Jump <= "01";
          LDDI <= '1';
          Set_Addr_To <= Set_Addr_To_S;
          dbg_Set_Addr_To<=6;
        when 2 =>
          Set_Addr_To <= Set_Addr_To_S;
          dbg_Set_Addr_To<=7;
          Write_Data <= Write_Data_PCH;
          Write <= '1';
        when 3 =>
          Dec_S <= '1';
          Set_Addr_To <= Set_Addr_To_S;
          dbg_Set_Addr_To<=8;
          Write_Data <= Write_Data_PCL;
          Write <= '1';
        when 4 =>
          Dec_S <= '1';
        when 5 =>
          Jump <= "10"; -- DIDL
        when others =>
        end case;
      when "01000000" =>
        -- RTI
        tLCycle <= "101";
        dbg_LCycle<=3;
        case to_integer(unsigned(MCycle)) is
        when 1 =>
          Set_Addr_To <= Set_Addr_To_S;
          dbg_Set_Addr_To<=9;
        when 2 =>
          Inc_S <= '1';
          Set_Addr_To <= Set_Addr_To_S;
          dbg_Set_Addr_To<=10;
        when 3 =>
          Inc_S <= '1';
          Set_Addr_To <= Set_Addr_To_S;
          dbg_Set_Addr_To<=11;
          Set_BusA_To <= Set_BusA_To_DI;
          dbg_Set_BusA_To<=10;
        when 4 =>
          LDP <= '1';
          Inc_S <= '1';
          LDDI <= '1';
          Set_Addr_To <= Set_Addr_To_S;
          dbg_Set_Addr_To<=12;
        when 5 =>
          Jump <= "10"; -- DIDL
        when others =>
        end case;
      when "01100000" =>
        -- RTS
        tLCycle <= "101";
        dbg_LCycle<=4;
        case to_integer(unsigned(MCycle)) is
        when 1 =>
          Set_Addr_To <= Set_Addr_To_S;
          dbg_Set_Addr_To<=13;
        when 2 =>
          Inc_S <= '1';
          Set_Addr_To <= Set_Addr_To_S;
          dbg_Set_Addr_To<=14;
        when 3 =>
          Inc_S <= '1';
          LDDI <= '1';
          Set_Addr_To <= Set_Addr_To_S;
          dbg_Set_Addr_To<=15;
        when 4 =>
          Jump <= "10"; -- DIDL
        when 5 =>
          Jump <= "01";
        when others =>
        end case;
      when "00001000" | "01001000" | "01011010" | "11011010" =>
        -- PHP, PHA, PHY*, PHX*
        tLCycle <= "010";
        dbg_LCycle<=5;
        if Mode = "00" and IR(1) = '1' then--2 cycle nop
          tLCycle <= "001";
          dbg_LCycle<=6;
        end if;
        case to_integer(unsigned(MCycle)) is
        when 1 =>
          if mode/="00" or IR(1)='0' then --wrong on 6502
            Write <= '1';
            case IR(7 downto 4) is
            when "0000" =>
              Write_Data <= Write_Data_P;
            when "0100" =>
              Write_Data <= Write_Data_ABC;
            when "0101" =>	--not correct unsupporte
              if Mode /= "00" then
                Write_Data <= Write_Data_Y;
              else
                Write <= '0';
              end if;
            when "1101" =>
              if Mode /= "00" then
                Write_Data <= Write_Data_X;
              else
                Write <= '0';
              end if;
            when others =>
            end case;
            Set_Addr_To <= Set_Addr_To_S;
          dbg_Set_Addr_To<=16;
          end if;
        when 2 =>
          Dec_S <= '1';
        when others =>
        end case;
      when "00101000" | "01101000" | "01111010" | "11111010" =>
        -- PLP, PLA, PLY*, PLX*
        tLCycle <= "011";
        dbg_LCycle<=7;
        if Mode = "00" and IR(1) = '1' then--2 cycle nop
          tLCycle <= "001";
          dbg_LCycle<=8;
        end if;
        case IR(7 downto 4) is
        when "0010" =>--plp
          LDP <= '1';
        when "0110" =>--pla
          LDA <= '1';
        when "0111" =>--ply not for 6502
          if Mode /= "00" then
            LDY <= '1';
          end if;
        when "1111" =>--plx not for 6502
          if Mode /= "00" then
            LDX <= '1';
          end if;
        when others =>
        end case;

        case to_integer(unsigned(MCycle)) is
        when 0 =>
          if Mode /= "00" or IR(1) = '0' then--wrong on 6502
            SaveP <= '1';
          end if;
        when 1 =>
          if Mode /= "00" or IR(1) = '0' then--wrong on 6502
            Set_Addr_To <= Set_Addr_To_S;
            dbg_Set_Addr_To<=17;
             -- MWW This is wrong, ALU_OP is not populated yet, so previous op's P_out can be saved (This was caused by ROL followed by PLA - THE ISSUE MAY BE DEEPER!)
            --SaveP <= '1'; --MWW
            LDP <= '0';--MWW
          end if;
        when 2 =>
          Inc_S <= '1';
          Set_Addr_To <= Set_Addr_To_S;
          dbg_Set_Addr_To<=18;
          --SaveP <= '1';--MWW
          LDP <= '0';      --MWW    
        when 3 =>
          Set_BusA_To <= Set_BusA_To_DI;
          dbg_Set_BusA_To<=11;
        when others =>
        end case;
      when "10100000" | "11000000" | "11100000" =>
        -- LDY, CPY, CPX
        -- Immediate
        case to_integer(unsigned(MCycle)) is
        when 0 =>
        when 1 =>
          Jump <= "01";
        when others =>
        end case;
      when "10001000" =>
        -- DEY
        LDY <= '1';
        case to_integer(unsigned(MCycle)) is
        when 0 =>
        when 1 =>
          Set_BusA_To <= Set_BusA_To_Y;
          dbg_Set_BusA_To<=12;
        when others =>
        end case;
      when "11001010" =>
        -- DEX
        LDX <= '1';
        case to_integer(unsigned(MCycle)) is
        when 0 =>
        when 1 =>
          Set_BusA_To <= Set_BusA_To_X;
          dbg_Set_BusA_To<=13;
        when others =>
        end case;
      when "00011010" | "00111010" =>
        -- INC*, DEC*
        if Mode /= "00" then
          LDA <= '1'; -- A
        else
          tLCycle <= "001";--undoc 2 cycle nop..can I just load tLCycle counter like this?
          dbg_LCycle<=9;
        end if;
        case to_integer(unsigned(MCycle)) is
        when 0 =>
        when 1 =>
          Set_BusA_To <= Set_BusA_To_S;
          dbg_Set_BusA_To<=14;
        when others =>
        end case;
      when "00001010" | "00101010" | "01001010" | "01101010" =>
        -- ASL, ROL, LSR, ROR
        LDA <= '1'; -- A
        Set_BusA_To <= Set_BusA_To_ABC;
        dbg_Set_BusA_To<=15;
        case to_integer(unsigned(MCycle)) is
        when 0 =>
        when 1 =>
        when others =>
        end case;
      when "10001010" | "10011000" =>
        -- TYA, TXA
        LDA <= '1'; -- A
        case to_integer(unsigned(MCycle)) is
        when 0 =>
        when 1 =>
        when others =>
        end case;
      when "10101010" | "10101000" =>
        -- TAX, TAY
        case to_integer(unsigned(MCycle)) is
        when 0 =>
        when 1 =>
          Set_BusA_To <= Set_BusA_To_ABC;
          dbg_Set_BusA_To<=16;
        when others =>
        end case;
      when "10011010" =>
        -- TXS
        case to_integer(unsigned(MCycle)) is
        when 0 =>
          LDS <= '1';
        when 1 =>
        when others =>
        end case;
      when "10111010" =>
        -- TSX
        LDX <= '1';
        case to_integer(unsigned(MCycle)) is
        when 0 =>
        when 1 =>
          Set_BusA_To <= Set_BusA_To_S;
          dbg_Set_BusA_To<=17;
        when others =>
        end case;

    --                      when "00011000" | "00111000" | "01011000" | "01111000" | "10111000" | "11011000" | "11111000" | "11001000" | "11101000" =>
    --                              -- CLC, SEC, CLI, SEI, CLV, CLD, SED, INY, INX
    --                              case to_integer(unsigned(MCycle)) is
    --                              when 1 =>
    --                              when others =>
    --                              end case;
      when others =>
        case to_integer(unsigned(MCycle)) is
        when 0 =>
        when others =>
        end case;
      end case;
    --}}}

    when "00001" | "00011" =>
    --{{{
      -- Zero Page Indexed Indirect (d,x)
      tLCycle <= "101";
      dbg_LCycle<=10;
      if IR(7 downto 6) /= "10" then
        LDA <= '1';
        if Mode="00" and IR(1)='1' then--b3
          LDX <= '1';--undoc, can load both A and X
        end if;
      end if;
      case to_integer(unsigned(MCycle)) is
      when 1 =>
        Jump <= "01";
        LDAD <= '1';
        Set_Addr_To <= Set_Addr_To_AD;
        dbg_Set_Addr_To<=19;
      when 2 =>
        ADAdd <= '1';
        Set_Addr_To <= Set_Addr_To_AD;
        dbg_Set_Addr_To<=20;
      when 3 =>
        BAAdd <= "01";  -- DB Inc
        LDBAL <= '1';
        Set_Addr_To <= Set_Addr_To_AD;
        dbg_Set_Addr_To<=21;
      when 4 =>
        LDBAH <= '1';
        if IR(7 downto 5) = "100" then
          Write <= '1';
        end if;
        Set_Addr_To <= Set_Addr_To_BA;
        dbg_Set_Addr_To<=22;
      when 5 =>
        if Mode="00" and IR(1)='1' then
          tALUmore <= '1';--ML:For undoc ASO support
        end if;
      when 0 =>
        if Mode="00" and IR(1)='1' then
          SaveP <= '1';--ML:For undoc DCP/DCM support, save again after compare
        end if;
      when others =>
      end case;
    --}}}

    when "01001" | "01011" =>
    --{{{
      -- Immediate
      LDA <= '1';
      case to_integer(unsigned(MCycle)) is
      when 0 =>
      when 1 =>
        Jump <= "01";
      when others =>
      end case;

    --}}}

    when "00010" | "10010" =>
    --{{{
      -- Immediate, SKB, KIL

      case to_integer(unsigned(MCycle)) is
      when 0 =>
      when 1 =>
        if IR = "10100010" then
          -- LDX
          Jump <= "01";
          LDX <= '1';--ML:Moved, Lorenz test showed X changing on SKB (NOPx)
        elsif IR(7 downto 4)="1000" or IR(7 downto 4)="1100" or IR(7 downto 4)="1110" then
          -- SKB skip next byte undoc
        else
          -- KIL !!!!!!!!!!!!!!!!!!!!!!!!!!!!!
        end if;
      when others =>
      end case;
    --}}}

    when "00100" =>
    --{{{
      -- Zero Page
      tLCycle <= "010";
      dbg_LCycle<=11;
      case to_integer(unsigned(MCycle)) is
      when 0 =>
        if IR(7 downto 5) = "001" then--24=BIT zpg
          SaveP <= '1';
        end if;
      when 1 =>
        Jump <= "01";
        LDAD <= '1';
        if IR(7 downto 5) = "100" then--84=sty zpg (the only write in this group)
          Write <= '1';
        end if;
        Set_Addr_To <= Set_Addr_To_AD;
        dbg_Set_Addr_To<=23;
      when 2 =>
      when others =>
      end case;
    --}}}

    when "00101" | "00110" | "00111" =>
    --{{{
      -- Zero Page
--    if IR(7 downto 6) /= "10" and IR(1 downto 0) = "10" then--0x-7x,cx-fx, x=2,6,a,e
      if IR(7 downto 6) /= "10" and IR(1) = '1' and (mode="00" or IR(0)='0') then--covers 0x-7x,cx-fx x=2,3,6,7,a,b,e,f, for 6502 undocs
        -- Read-Modify-Write
        if Mode="00" and IR(0)='1' then
          LDA<='1';
        end if;
        tLCycle <= "100";
        dbg_LCycle<=12;
        case to_integer(unsigned(MCycle)) is
        when 1 =>
          Jump <= "01";
          LDAD <= '1';
          Set_Addr_To <= Set_Addr_To_AD;
        dbg_Set_Addr_To<=24;
        when 2 =>
          LDDI <= '1';
          if Mode="00"  then--The old 6500 writes back what is just read, before changing. The 65c does another read
            Write <= '1';
          end if;
          Set_Addr_To <= Set_Addr_To_AD;
          dbg_Set_Addr_To<=25;
        when 3 =>
          LDALU <= '1';
          SaveP <= '1';
          Write <= '1';
          Set_Addr_To <= Set_Addr_To_AD;
          dbg_Set_Addr_To<=26;
        when 4 =>
          if Mode="00" and IR(0)='1' then
            tALUmore <= '1';--ML:For undoc DCP/DCM support
          end if;
        when 0 =>
          if Mode="00" and IR(0)='1' then
            SaveP <= '1';--ML:For undoc DCP/DCM support, save again after compare
          end if;
        when others =>
        end case;
      else
        tLCycle <= "010";
        dbg_LCycle<=13;
        if IR(7 downto 6) /= "10" then
          LDA <= '1';
          if Mode="00" and IR(1)='1' then--b3
            LDX <= '1';--undoc, can load both A and X
          end if;
        end if;
        case to_integer(unsigned(MCycle)) is
        when 0 =>
        when 1 =>
          Jump <= "01";
          LDAD <= '1';
          if IR(7 downto 5) = "100" then
            Write <= '1';
          end if;
          Set_Addr_To <= Set_Addr_To_AD;
          dbg_Set_Addr_To<=27;
        when 2 =>
        when others =>
        end case;
      end if;
    --}}}

    when "01100" =>
    --{{{
      -- Absolute
      if IR(7 downto 6) = "01" and IR(4 downto 0) = "01100" then--4c,6c
        -- JMP
        if IR(5) = '0' then
          --tLCycle <= "011";
          tLCycle <= "010";
          dbg_LCycle<=14;
          case to_integer(unsigned(MCycle)) is
          when 1 =>
            Jump <= "01";
            LDDI <= '1';
          when 2 =>
            Jump <= "10"; -- DIDL
          when others =>
          end case;
        else
          --tLCycle <= "101";
          tLCycle <= "100"; -- mikej
          dbg_LCycle<=15;
          case to_integer(unsigned(MCycle)) is
          when 1 =>
            Jump <= "01";
            LDDI <= '1';
            LDBAL <= '1';
          when 2 =>
            LDBAH <= '1';
            if Mode /= "00" then
              Jump <= "10"; -- DIDL
            end if;
            if Mode = "00" then
              Set_Addr_To <= Set_Addr_To_BA;
              dbg_Set_Addr_To<=28;
            end if;
          when 3 =>
            LDDI <= '1';
            if Mode = "00" then
              Set_Addr_To <= Set_Addr_To_BA;
              dbg_Set_Addr_To<=29;
              BAAdd <= "01";      -- DB Inc
            else
              Jump <= "01";
            end if;
          when 4 =>
            Jump <= "10"; -- DIDL
          when others =>
          end case;
        end if;
      else
        tLCycle <= "011";
        dbg_LCycle<=16;
        case to_integer(unsigned(MCycle)) is
        when 0 =>
          if IR(7 downto 5) = "001" then--2c-BIT
            SaveP <= '1';
          end if;
        when 1 =>
          Jump <= "01";
          LDBAL <= '1';
        when 2 =>
          Jump <= "01";
          LDBAH <= '1';
          if IR(7 downto 5) = "100" then--80, sty, the only write in this group
            Write <= '1';
          end if;
          Set_Addr_To <= Set_Addr_To_BA;
          dbg_Set_Addr_To<=30;
        when 3 =>
        when others =>
        end case;
      end if;
    --}}}

    when "01101" | "01110" | "01111" =>
    --{{{
      -- Absolute
--      if IR(7 downto 6) /= "10" and IR(1 downto 0) = "10" then--0x-7x,cx-fx, x=2,6,a,e
      if IR(7 downto 6) /= "10" and IR(1) = '1' and (mode="00" or IR(0)='0') then--covers 0x-7x,cx-fx x=2,3,6,7,a,b,e,f, for 6502 undocs
        -- Read-Modify-Write
        tLCycle <= "101";
        dbg_LCycle<=17;
        case to_integer(unsigned(MCycle)) is
        when 1 =>
          Jump <= "01";
          LDBAL <= '1';
        when 2 =>
          Jump <= "01";
          LDBAH <= '1';
          Set_Addr_To <= Set_Addr_To_BA;
          dbg_Set_Addr_To<=31;
        when 3 =>
          LDDI <= '1';
          if Mode="00" then--The old 6500 writes back what is just read, before changing. The 65c does another read
          	Write <= '1';
          end if;
          Set_Addr_To <= Set_Addr_To_BA;
          dbg_Set_Addr_To<=32;
        when 4 =>
          Write <= '1';
          LDALU <= '1';
          SaveP <= '1';
          Set_Addr_To <= Set_Addr_To_BA;
          dbg_Set_Addr_To<=33;
        when 5 =>
          --SaveP <= '0'; -- MIKEJ was 1
          if Mode="00" and IR(0)='1' then
            tALUmore <= '1';--ML:For undoc DCP/DCM support
          end if;
        when 0 =>
          if Mode="00" and IR(0)='1' then
            SaveP <= '1';--ML:For undoc DCP/DCM support, save again after compare
          end if;
        when others =>
        end case;
      else
        tLCycle <= "011";
        dbg_LCycle<=18;
        if IR(7 downto 6) /= "10" then
          LDA <= '1';
          if Mode="00" and IR(1)='1' then--b3
            LDX <= '1';--undoc, can load both A and X
          end if;
        end if;
        case to_integer(unsigned(MCycle)) is
        when 0 =>
        when 1 =>
          Jump <= "01";
          LDBAL <= '1';
        when 2 =>
          Jump <= "01";
          LDBAH <= '1';
          if IR(7 downto 5) = "100" then
            Write <= '1';
          end if;
          Set_Addr_To <= Set_Addr_To_BA;
          dbg_Set_Addr_To<=34;
        when 3 =>
        when others =>
        end case;
      end if;
    --}}}

    when "10000" =>
    --{{{
      -- Relative

            -- This circuit dictates when the last
            -- microcycle occurs for the branch depending on
            -- whether or not the branch is taken and if a page
            -- is crossed...
      if (Branch = '1') then
               tLCycle <= "011"; -- We're done @ T3 if branching...upper
                        -- level logic will stop at T2 if no page cross
                        -- (See the Break signal)
               dbg_LCycle<=19;
      else
               tLCycle <= "001";
               dbg_LCycle<=20;

      end if;

            -- This decodes the current microcycle and takes the
            -- proper course of action...
      case to_integer(unsigned(MCycle)) is

              -- On the T1 microcycle, increment the program counter
              -- and instruct the upper level logic to fetch the offset
              -- from the Din bus and store it in the data latches. This
              -- will be the last microcycle if the branch isn't taken.
        when 1 =>

          Jump <= "01"; -- Increments the PC by one (PC will now be PC+2)
                        -- from microcycle T0.

        LDDI <= '1';  -- Tells logic in top level (T65.vhd) to route
                        -- the Din bus to the memory data latch (DL)
                        -- so that the branch offset is fetched.

              -- In microcycle T2, tell the logic in the top level to
              -- add the offset.  If the most significant byte of the
              -- program counter (i.e. the current "page") does not need
              -- updating, we are done here...the Break signal at the
              -- T65.vhd level takes care of that...
        when 2 =>

        Jump    <= "11"; -- Tell the PC Jump logic to use relative mode.

        PCAdd   <= '1';  -- This tells the PC adder to update itself with
                         -- the current offset recently fetched from
                         -- memory.

              -- The following is microcycle T3 :
              -- The program counter should be completely updated
              -- on this cycle after the page cross is detected.
              -- We don't need to do anything here...
        when 3 =>


        when others => null; -- Do nothing.

      end case;
    --}}}

    when "10001" | "10011" =>
    --{{{
      -- Zero Page Indirect Indexed (d),y
      tLCycle <= "101";
      dbg_LCycle<=21;
      if IR(7 downto 6) /= "10" then--91,b1,93,b3 only
        LDA <= '1';
        if Mode="00" and IR(1)='1' then--b3
          LDX <= '1';--undoc, can load both A and X
        end if;
      end if;
      case to_integer(unsigned(MCycle)) is
      when 1 =>
        Jump <= "01";
        LDAD <= '1';
        Set_Addr_To <= Set_Addr_To_AD;
        dbg_Set_Addr_To<=35;
      when 2 =>
        LDBAL <= '1';
        BAAdd <= "01";  -- DB Inc
        Set_Addr_To <= Set_Addr_To_AD;
        dbg_Set_Addr_To<=36;
      when 3 =>
        Set_BusA_To <= Set_BusA_To_Y;
        dbg_Set_BusA_To<=18;
        BAAdd <= "10";  -- BA Add
        LDBAH <= '1';
        Set_Addr_To <= Set_Addr_To_BA;
        dbg_Set_Addr_To<=37;
      when 4 =>
        BAAdd <= "11";  -- BA Adj
        if IR(7 downto 5) = "100" or IR(1)='1' then
          Write <= '1';
        else
          BreakAtNA <= '1';
          if Mode="00" and IR(1)='1' then
            tALUmore <= '1';--ML:For undoc 
          end if;
        end if;
        Set_Addr_To <= Set_Addr_To_BA;
        dbg_Set_Addr_To<=38;
      when 5 =>
        if Mode="00" and IR(1)='1' then
          tALUmore <= '1';--ML:For undoc 
        end if;
      when 0 =>
        if Mode="00" and IR(1)='1' then
          SaveP <= '1';--ML:For undoc 
        end if;
      when others =>
      end case;
    --}}}

    when "10100" | "10101" | "10110" | "10111" =>
    --{{{
      -- Zero Page, X
--      if IR(7 downto 6) /= "10" and IR(1 downto 0) = "10" then--16,36,56,76,d6,f6
      if IR(7 downto 6) /= "10" and IR(1) = '1' and (Mode="00" or IR(0)='0') then--covers 0x-7x,cx-fx x=2,3,6,7,a,b,e,f, for 6502 undocs
        -- Read-Modify-Write
        if Mode="00" and IR(0)='1' then
          LDA<='1';
        end if;
        tLCycle <= "101";
        dbg_LCycle<=22;
        case to_integer(unsigned(MCycle)) is
        when 1 =>
          Jump <= "01";
          LDAD <= '1';
          Set_Addr_To <= Set_Addr_To_AD;
          dbg_Set_Addr_To<=39;
        when 2 =>
          ADAdd <= '1';
          Set_Addr_To <= Set_Addr_To_AD;
          dbg_Set_Addr_To<=40;
        when 3 =>
          LDDI <= '1';
          if Mode="00" then--The old 6500 writes back what is just read, before changing. The 65c does another read
          	Write <= '1';
          end if;
          Set_Addr_To <= Set_Addr_To_AD;
          dbg_Set_Addr_To<=41;
        when 4 =>
          LDALU <= '1';
          SaveP <= '1';
          Write <= '1';
          Set_Addr_To <= Set_Addr_To_AD;
          dbg_Set_Addr_To<=42;
        when 5 =>
          if Mode="00" and IR(0)='1' then
            tALUmore <= '1';--ML:For undoc DCP/DCM support
          end if;
        when 0 =>
          if Mode="00" and IR(0)='1' then
            SaveP <= '1';--ML:For undoc DCP/DCM support, save again after compare
          end if;
        when others =>
        end case;
      elsif Mode="00" and IR(7 downto 6)/="10" and IR(4)='1' and IR(1 downto 0)="00" then --covers 1x,3x,5x,7x,dx,fx, for skb/nopzx 6502 undocs
        tLCycle <= "011";--SKB's at x4
        dbg_LCycle<=222;
        case to_integer(unsigned(MCycle)) is
        when 1 =>
          Jump <= "01";--skip a byte
        when others=>
		end case;
      else
        tLCycle <= "011";
        dbg_LCycle<=23;
        if IR(7 downto 6) /= "10" then
          LDA <= '1';
          if Mode="00" and IR(1 downto 0)="11" then--x7
            LDX <= '1';--undoc, can load both A and X
          end if;
        end if;
        case to_integer(unsigned(MCycle)) is
        when 0 =>
        when 1 =>
          Jump <= "01";
          LDAD <= '1';
          Set_Addr_To <= Set_Addr_To_AD;
          dbg_Set_Addr_To<=43;
        when 2 =>
          ADAdd <= '1';
          -- Added this check for Y reg. use...
          if (IR(3 downto 0) = "0110") then--96,b6
            AddY <= '1';
          end if;

          if IR(7 downto 5) = "100" then--94,95,96,97 the only write instruction
            Write <= '1';
          end if;
          Set_Addr_To <= Set_Addr_To_AD;
          dbg_Set_Addr_To<=44;
        when 3 => null;
        when others =>
        end case;
      end if;
    --}}}

    when "11001" | "11011" =>
    --{{{
      -- Absolute Y
      tLCycle <= "100";
      dbg_LCycle<=24;
      if IR(7 downto 6) /= "10" then
        LDA <= '1';
        if Mode="00" and IR(1 downto 0)="11" then--xb
          LDX <= '1';--undoc, can load both A and X
        end if;
      end if;
      case to_integer(unsigned(MCycle)) is
      when 1 =>
        Jump <= "01";
        LDBAL <= '1';
      when 2 =>
        Jump <= "01";
        Set_BusA_To <= Set_BusA_To_Y;
        dbg_Set_BusA_To<=19;
        BAAdd <= "10";  -- BA Add
        LDBAH <= '1';
        Set_Addr_To <= Set_Addr_To_BA;
        dbg_Set_Addr_To<=45;
      when 3 =>
        BAAdd <= "11";  -- BA adj
--        if IR(7 downto 5) = "100" then--99/9b
        if IR(7 downto 5) = "100" or IR(1)='1' then
          Write <= '1';
        else
          BreakAtNA <= '1';
        end if;
        Set_Addr_To <= Set_Addr_To_BA;
        dbg_Set_Addr_To<=46;
      when 4 =>
        if Mode="00" and IR(1)='1' then
          tALUmore <= '1';--ML:For undoc 
        end if;
      when 0 =>
        if Mode="00" and IR(1)='1' then
          SaveP <= '1';--ML:For undoc 
        end if;
      when others =>
      end case;
    --}}}

    when "11100" | "11101" | "11110" | "11111" =>
    --{{{
      -- Absolute X

--      if IR(7 downto 6) /= "10" and IR(1 downto 0) = "10" then--1x,3x,5x,7x,dx,fx, x=c,d,e,f
        if IR(7 downto 6) /= "10" and IR(1) = '1' and (Mode="00" or IR(0)='0') then--covers 0x-7x,cx-fx x=2,3,6,7,a,b,e,f, for 6502 undocs
        -- Read-Modify-Write
        tLCycle <= "110";
        dbg_LCycle<=25;
        case to_integer(unsigned(MCycle)) is
        when 1 =>
          Jump <= "01";
          LDBAL <= '1';
        when 2 =>
          Jump <= "01";
          Set_BusA_To <= Set_BusA_To_X;
          dbg_Set_BusA_To<=20;
          BAAdd <= "10";      -- BA Add
          LDBAH <= '1';
          Set_Addr_To <= Set_Addr_To_BA;
          dbg_Set_Addr_To<=47;
        when 3 =>
          BAAdd <= "11";      -- BA adj
          Set_Addr_To <= Set_Addr_To_BA;
          dbg_Set_Addr_To<=48;
        when 4 =>
          LDDI <= '1';
          if Mode="00" then--The old 6500 writes back what is just read, before changing. The 65c does another read
          	Write <= '1';
          end if;
          Set_Addr_To <= Set_Addr_To_BA;
          dbg_Set_Addr_To<=49;
        when 5 =>
          LDALU <= '1';
          SaveP <= '1';
          Write <= '1';
          Set_Addr_To <= Set_Addr_To_BA;
          dbg_Set_Addr_To<=50;
        when 6 =>
          if Mode="00" and IR(0)='1' then
            tALUmore <= '1';--ML:For undoc DCP/DCM support
          end if;
        when 0 =>
          if Mode="00" and IR(0)='1' then
            SaveP <= '1';--ML:For undoc DCP/DCM support, save again after compare
          end if;
        when others =>
        end case;
--      elsif Mode="00" and IR(7 downto 6)/="10" and IR(4)='1' and IR(1 downto 0)="00" then --covers 1x,3x,5x,7x,dx,fx, for 6502 skw/nopax undocs
--        tLCycle <= "100";--SKW's at xc
--        dbg_LCycle<=260;
--        case to_integer(unsigned(MCycle)) is
--        when 1 =>
--          Jump <= "01";--skip a byte
--        when 2 =>
--          Jump <= "01";--skip a byte
--        when 3 =>
--          BreakAtNA <= '1';
--        when others=>
--		end case;
      else--9c,9d,9e,9f,bc,bd,be,bf
        tLCycle <= "100";
        dbg_LCycle<=26;
        if IR(7 downto 6) /= "10" then
          if Mode/="00" or IR(4)='0' or IR(1 downto 0)/="00" then --covers 1x,3x,5x,7x,dx,fx, for 6502 skw/nopax undocs
            LDA <= '1';
            if Mode="00" and IR(1 downto 0)="11" then--9f,bf
              LDX <= '1';--undoc, can load both A and X
            end if;
          end if;
        end if;
        case to_integer(unsigned(MCycle)) is
        when 0 =>
        when 1 =>
          Jump <= "01";
          LDBAL <= '1';
        when 2 =>
          Jump <= "01";
          -- mikej
          -- special case 0xBE which uses Y reg as index!! (added undoc 9e,9f,bf)
--          if (IR = "10-1111-") then
          if(IR(7 downto 6)="10" and IR(4 downto 1)="1111") then
            Set_BusA_To <= Set_BusA_To_Y;
            dbg_Set_BusA_To<=21;
          else
            Set_BusA_To <= Set_BusA_To_X;
            dbg_Set_BusA_To<=22;
          end if;
          BAAdd <= "10";      -- BA Add
          LDBAH <= '1';
          Set_Addr_To <= Set_Addr_To_BA;
          dbg_Set_Addr_To<=51;
        when 3 =>
          BAAdd <= "11";      -- BA adj
          if IR(7 downto 5) = "100" then--9x
            Write <= '1';
          else
            BreakAtNA <= '1';
          end if;
          Set_Addr_To <= Set_Addr_To_BA;
          dbg_Set_Addr_To<=52;
        when 4 =>
        when others =>
        end case;
      end if;
    --}}}
    when others =>
    end case;
  end process;

  process (IR, MCycle, Mode,tALUmore)
  begin
    -- ORA, AND, EOR, ADC, NOP, LD, CMP, SBC
    -- ASL, ROL, LSR, ROR, BIT, LD, DEC, INC
    case IR(1 downto 0) is
    when "00" =>
    --{{{
      case IR(4 downto 2) is
      when "000" | "001" | "011" =>--	"---0 xx00", xx!="10"
        case IR(7 downto 5) is
        when "110" | "111" =>--c0,c4,cc,e0,e5,ec
          -- CP
          ALU_Op <= ALU_OP_CMP;
        when "101" =>--a0,a4,ac
          -- LD
          ALU_Op <= ALU_OP_EQ2;
        when "001" =>--20,24,2c (20 is ignored, as its a jmp)
          -- BIT
          ALU_Op <= ALU_OP_BIT;
        when others =>--other x0,x4,xc
          -- NOP/ST
          ALU_Op <= ALU_OP_EQ1;
        end case;
      when "010" =>--	"---0 1000"
        case IR(7 downto 5) is
        when "111" | "110" =>--c8,e8
          -- IN
          ALU_Op <= ALU_OP_INC;
        when "100" =>--88
          -- DEY
          ALU_Op <= ALU_OP_DEC;
        when others =>
          -- LD
          ALU_Op <= ALU_OP_EQ3;
        end case;
      when "110" =>--	"---1 1000"
        case IR(7 downto 5) is
        when "100" =>--98
          -- TYA
          ALU_Op <= ALU_OP_EQ3;
        when others =>
          ALU_Op <= ALU_OP_UNDEF;
        end case;
      when others =>--	"---x xx00"
        case IR(7 downto 5) is
        when "101" =>--ax,bx
          -- LD
          ALU_Op <= ALU_OP_EQ3;
        when others =>
          ALU_Op <= ALU_OP_EQ1;
        end case;
      end case;
    --}}}
    when "01" => -- OR
    --{{{
      case(to_integer(unsigned(IR(7 downto 5)))) is
      when 0=>
        ALU_Op<=ALU_OP_OR;
      when 1=>
        ALU_Op<=ALU_OP_AND;
      when 2=>
        ALU_Op<=ALU_OP_EOR;
      when 3=>
        ALU_Op<=ALU_OP_ADC;
      when 4=>
        ALU_Op<=ALU_OP_EQ1;--sta
      when 5=>
        ALU_Op<=ALU_OP_EQ2;--lda
      when 6=>
        ALU_Op<=ALU_OP_CMP;
      when others=>
        ALU_Op<=ALU_OP_SBC;
      end case;
--ML:replaced by above case()
--      ALU_Op(3) <= '0';
--      ALU_Op(2 downto 0) <= IR(7 downto 5);
    --}}}
    when "10" =>
    --{{{
      case(to_integer(unsigned(IR(7 downto 5)))) is
      when 0=>
        ALU_Op<=ALU_OP_ASL;
      when 1=>
        ALU_Op<=ALU_OP_ROL;
      when 2=>
        ALU_Op<=ALU_OP_LSR;
      when 3=>
        ALU_Op<=ALU_OP_ROR;
      when 4=>
        ALU_Op<=ALU_OP_BIT;
      when 5=>
        ALU_Op<=ALU_OP_EQ3;--ldx
      when 6=>
        ALU_Op<=ALU_OP_DEC;
      when others=>
        ALU_Op<=ALU_OP_INC;
      end case;
--ML:replaced by above case()
--      ALU_Op(3) <= '1';
--      ALU_Op(2 downto 0) <= IR(7 downto 5);
      case IR(7 downto 5) is
      when "000" =>
        if IR(4 downto 2) = "110" and Mode/="00" then--ML:00011010,1a->inc acc, not on 6502
          -- INC
          ALU_Op <= ALU_OP_INC;
        end if;
      when "001" =>
        if IR(4 downto 2) = "110" and Mode/="00" then--ML:00111010,3a->dec acc, not on 6502
          -- DEC
          ALU_Op <= ALU_OP_DEC;
        end if;
      when "100" =>
        if IR(4 downto 2) = "010" then	--10001010,8a->TXA
          -- TXA
          ALU_Op <= ALU_OP_EQ2;
        else							--100xxx10, 82,86,8e,92,96,9a,9e
          ALU_Op <= ALU_OP_EQ1;
        end if;
      when others =>
      end case;
    --}}}
    when others =>--"11" undoc double alu ops
    --{{{
      case IR(7 downto 5) is
      when "101" =>--ax,bx
        ALU_Op <= ALU_OP_EQ1;
      when others =>
--        if MCycle >= tLCycle then
        if tALUmore='1' then 
         case(to_integer(unsigned(IR(7 downto 5)))) is
         when 0=>
             ALU_Op<=ALU_OP_OR;
         when 1=>
            ALU_Op<=ALU_OP_AND;
         when 2=>
            ALU_Op<=ALU_OP_EOR;
         when 3=>
            ALU_Op<=ALU_OP_ADC;
         when 4=>
            ALU_Op<=ALU_OP_EQ1;--sta
         when 5=>
            ALU_Op<=ALU_OP_EQ2;--lda
         when 6=>
            ALU_Op<=ALU_OP_CMP;
         when others=>
            ALU_Op<=ALU_OP_SBC;
         end case;
--replaced by above case()
--          ALU_Op(3) <= '0';
--          ALU_Op(2 downto 0) <= IR(7 downto 5);
        else
         case(to_integer(unsigned(IR(7 downto 5)))) is
         when 0=>
            ALU_Op<=ALU_OP_ASL;
         when 1=>
            ALU_Op<=ALU_OP_ROL;
         when 2=>
            ALU_Op<=ALU_OP_LSR;
         when 3=>
            ALU_Op<=ALU_OP_ROR;
         when 4=>
            ALU_Op<=ALU_OP_BIT;
         when 5=>
            ALU_Op<=ALU_OP_EQ3;--ldx
         when 6=>
            ALU_Op<=ALU_OP_DEC;
         when others=>
            ALU_Op<=ALU_OP_INC;
         end case;
--replaced by above case()
--          ALU_Op(3) <= '1';
--          ALU_Op(2 downto 0) <= IR(7 downto 5);
        end if;
      end case;
    --}}}
    end case;
  end process;

end;
