-- **** -- T65(b) core. In an effort to merge and maintain bug fixes .... -- -- -- Ver 301 more merging -- Ver 300 Bugfixes by ehenciak added, started tidyup *bust* -- MikeJ March 2005 -- Latest version from www.fpgaarcade.com (original www.opencores.org) -- -- **** -- -- 65xx compatible microprocessor core -- -- Version : 0246 -- -- 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 and 65C816 modes are incomplete -- Undocumented instructions are not supported -- Some interface signals behaves incorrect -- -- File history : -- -- 0246 : First release -- library IEEE; use IEEE.std_logic_1164.all; use IEEE.numeric_std.all; use work.T65_Pack.all; -- ehenciak 2-23-2005 : Added the enable signal so that one doesn't have to use -- the ready signal to limit the CPU. entity T65 is port( Mode : in std_logic_vector(1 downto 0); -- "00" => 6502, "01" => 65C02, "10" => 65C816 Res_n : in std_logic; Enable : in std_logic; Clk : in std_logic; Rdy : in std_logic; Abort_n : in std_logic; IRQ_n : in std_logic; NMI_n : in std_logic; SO_n : in std_logic; R_W_n : out std_logic; Sync : out std_logic; EF : out std_logic; MF : out std_logic; XF : out std_logic; ML_n : out std_logic; VP_n : out std_logic; VDA : out std_logic; VPA : out std_logic; A : out std_logic_vector(23 downto 0); DI : in std_logic_vector(7 downto 0); DO : out std_logic_vector(7 downto 0) ); end T65; architecture rtl of T65 is -- Registers signal ABC, X, Y, D : std_logic_vector(15 downto 0); signal P, AD, DL : std_logic_vector(7 downto 0) := x"00"; signal BAH : std_logic_vector(7 downto 0); signal BAL : std_logic_vector(8 downto 0); signal PBR : std_logic_vector(7 downto 0); signal DBR : std_logic_vector(7 downto 0); signal PC : unsigned(15 downto 0); signal S : unsigned(15 downto 0); signal EF_i : std_logic; signal MF_i : std_logic; signal XF_i : std_logic; signal IR : std_logic_vector(7 downto 0); signal MCycle : std_logic_vector(2 downto 0); signal Mode_r : std_logic_vector(1 downto 0); signal ALU_Op_r : std_logic_vector(3 downto 0); signal Write_Data_r : std_logic_vector(2 downto 0); signal Set_Addr_To_r : std_logic_vector(1 downto 0); signal PCAdder : unsigned(8 downto 0); signal RstCycle : std_logic; signal IRQCycle : std_logic; signal NMICycle : std_logic; signal B_o : std_logic; signal SO_n_o : std_logic; signal IRQ_n_o : std_logic; signal NMI_n_o : std_logic; signal NMIAct : std_logic; signal Break : std_logic; -- ALU signals signal BusA : std_logic_vector(7 downto 0); signal BusA_r : std_logic_vector(7 downto 0); signal BusB : std_logic_vector(7 downto 0); signal ALU_Q : std_logic_vector(7 downto 0); signal P_Out : std_logic_vector(7 downto 0); -- Micro code outputs signal LCycle : std_logic_vector(2 downto 0); signal ALU_Op : std_logic_vector(3 downto 0); signal Set_BusA_To : std_logic_vector(2 downto 0); signal Set_Addr_To : std_logic_vector(1 downto 0); signal Write_Data : std_logic_vector(2 downto 0); signal Jump : std_logic_vector(1 downto 0); signal BAAdd : std_logic_vector(1 downto 0); signal BreakAtNA : std_logic; signal ADAdd : std_logic; signal AddY : std_logic; signal PCAdd : std_logic; signal Inc_S : std_logic; signal Dec_S : std_logic; signal LDA : std_logic; signal LDP : std_logic; signal LDX : std_logic; signal LDY : std_logic; signal LDS : std_logic; signal LDDI : std_logic; signal LDALU : std_logic; signal LDAD : std_logic; signal LDBAL : std_logic; signal LDBAH : std_logic; signal SaveP : std_logic; signal Write : std_logic; signal really_rdy : std_logic; signal R_W_n_i : std_logic; begin -- ehenciak : gate Rdy with read/write to make an "OK, it's -- really OK to stop the processor now if Rdy is -- deasserted" signal really_rdy <= Rdy or not(R_W_n_i); -- ehenciak : Drive R_W_n_i off chip. R_W_n <= R_W_n_i; Sync <= '1' when MCycle = "000" else '0'; EF <= EF_i; MF <= MF_i; XF <= XF_i; ML_n <= '0' when IR(7 downto 6) /= "10" and IR(2 downto 1) = "11" and MCycle(2 downto 1) /= "00" else '1'; VP_n <= '0' when IRQCycle = '1' and (MCycle = "101" or MCycle = "110") else '1'; VDA <= '1' when Set_Addr_To_r /= "00" else '0'; -- Incorrect !!!!!!!!!!!! VPA <= '1' when Jump(1) = '0' else '0'; -- Incorrect !!!!!!!!!!!! mcode : T65_MCode port map( Mode => Mode_r, IR => IR, MCycle => MCycle, P => P, LCycle => LCycle, ALU_Op => ALU_Op, Set_BusA_To => Set_BusA_To, Set_Addr_To => Set_Addr_To, Write_Data => Write_Data, Jump => Jump, BAAdd => BAAdd, BreakAtNA => BreakAtNA, ADAdd => ADAdd, AddY => AddY, PCAdd => PCAdd, Inc_S => Inc_S, Dec_S => Dec_S, LDA => LDA, LDP => LDP, LDX => LDX, LDY => LDY, LDS => LDS, LDDI => LDDI, LDALU => LDALU, LDAD => LDAD, LDBAL => LDBAL, LDBAH => LDBAH, SaveP => SaveP, Write => Write ); alu : T65_ALU port map( Mode => Mode_r, Op => ALU_Op_r, BusA => BusA_r, BusB => BusB, P_In => P, P_Out => P_Out, Q => ALU_Q ); process (Res_n, Clk) begin if Res_n = '0' then PC <= (others => '0'); -- Program Counter IR <= "00000000"; S <= (others => '0'); -- Dummy !!!!!!!!!!!!!!!!!!!!! D <= (others => '0'); PBR <= (others => '0'); DBR <= (others => '0'); Mode_r <= (others => '0'); ALU_Op_r <= "1100"; Write_Data_r <= "000"; Set_Addr_To_r <= "00"; R_W_n_i <= '1'; EF_i <= '1'; MF_i <= '1'; XF_i <= '1'; elsif Clk'event and Clk = '1' then if (Enable = '1') then if (really_rdy = '1') then R_W_n_i <= not Write or RstCycle; D <= (others => '1'); -- Dummy PBR <= (others => '1'); -- Dummy DBR <= (others => '1'); -- Dummy EF_i <= '0'; -- Dummy MF_i <= '0'; -- Dummy XF_i <= '0'; -- Dummy if MCycle = "000" then Mode_r <= Mode; if IRQCycle = '0' and NMICycle = '0' then PC <= PC + 1; end if; if IRQCycle = '1' or NMICycle = '1' then IR <= "00000000"; else IR <= DI; end if; end if; ALU_Op_r <= ALU_Op; Write_Data_r <= Write_Data; if Break = '1' then Set_Addr_To_r <= "00"; else Set_Addr_To_r <= Set_Addr_To; end if; if Inc_S = '1' then S <= S + 1; end if; if Dec_S = '1' and RstCycle = '0' then S <= S - 1; end if; if LDS = '1' then S(7 downto 0) <= unsigned(ALU_Q); end if; if IR = "00000000" and MCycle = "001" and IRQCycle = '0' and NMICycle = '0' then PC <= PC + 1; end if; -- -- jump control logic -- case Jump is when "01" => PC <= PC + 1; when "10" => PC <= unsigned(DI & DL); when "11" => if PCAdder(8) = '1' then if DL(7) = '0' then PC(15 downto 8) <= PC(15 downto 8) + 1; else PC(15 downto 8) <= PC(15 downto 8) - 1; end if; end if; PC(7 downto 0) <= PCAdder(7 downto 0); when others => null; end case; end if; end if; end if; end process; PCAdder <= resize(PC(7 downto 0),9) + resize(unsigned(DL(7) & DL),9) when PCAdd = '1' else "0" & PC(7 downto 0); process (Clk) begin if Clk'event and Clk = '1' then if (Enable = '1') then if (really_rdy = '1') then if MCycle = "000" then if LDA = '1' then ABC(7 downto 0) <= ALU_Q; end if; if LDX = '1' then X(7 downto 0) <= ALU_Q; end if; if LDY = '1' then Y(7 downto 0) <= ALU_Q; end if; if (LDA or LDX or LDY) = '1' then P <= P_Out; end if; end if; if SaveP = '1' then P <= P_Out; end if; if LDP = '1' then P <= ALU_Q; end if; if IR(4 downto 0) = "11000" then case IR(7 downto 5) is when "000" => P(Flag_C) <= '0'; when "001" => P(Flag_C) <= '1'; when "010" => P(Flag_I) <= '0'; when "011" => P(Flag_I) <= '1'; when "101" => P(Flag_V) <= '0'; when "110" => P(Flag_D) <= '0'; when "111" => P(Flag_D) <= '1'; when others => end case; end if; --if IR = "00000000" and MCycle = "011" and RstCycle = '0' and NMICycle = '0' and IRQCycle = '0' then -- P(Flag_B) <= '1'; --end if; --if IR = "00000000" and MCycle = "100" and RstCycle = '0' and (NMICycle = '1' or IRQCycle = '1') then -- P(Flag_I) <= '1'; -- P(Flag_B) <= B_o; --end if; -- B=1 always on the 6502 P(Flag_B) <= '1'; if IR = "00000000" and RstCycle = '0' and (NMICycle = '1' or IRQCycle = '1') then if MCycle = "011" then -- B=0 in *copy* of P pushed onto the stack P(Flag_B) <= '0'; elsif MCycle = "100" then P(Flag_I) <= '1'; end if; end if; if SO_n_o = '1' and SO_n = '0' then P(Flag_V) <= '1'; end if; if RstCycle = '1' and Mode_r /= "00" then P(Flag_1) <= '1'; P(Flag_D) <= '0'; P(Flag_I) <= '1'; end if; P(Flag_1) <= '1'; B_o <= P(Flag_B); SO_n_o <= SO_n; IRQ_n_o <= IRQ_n; NMI_n_o <= NMI_n; end if; end if; end if; end process; --------------------------------------------------------------------------- -- -- Buses -- --------------------------------------------------------------------------- process (Res_n, Clk) begin if Res_n = '0' then BusA_r <= (others => '0'); BusB <= (others => '0'); AD <= (others => '0'); BAL <= (others => '0'); BAH <= (others => '0'); DL <= (others => '0'); elsif Clk'event and Clk = '1' then if (Enable = '1') then if (Rdy = '1') then BusA_r <= BusA; BusB <= DI; case BAAdd is when "01" => -- BA Inc AD <= std_logic_vector(unsigned(AD) + 1); BAL <= std_logic_vector(unsigned(BAL) + 1); when "10" => -- BA Add BAL <= std_logic_vector(resize(unsigned(BAL(7 downto 0)),9) + resize(unsigned(BusA),9)); when "11" => -- BA Adj if BAL(8) = '1' then BAH <= std_logic_vector(unsigned(BAH) + 1); end if; when others => end case; -- ehenciak : modified to use Y register as well (bugfix) if ADAdd = '1' then if (AddY = '1') then AD <= std_logic_vector(unsigned(AD) + unsigned(Y(7 downto 0))); else AD <= std_logic_vector(unsigned(AD) + unsigned(X(7 downto 0))); end if; end if; if IR = "00000000" then BAL <= (others => '1'); BAH <= (others => '1'); if RstCycle = '1' then BAL(2 downto 0) <= "100"; elsif NMICycle = '1' then BAL(2 downto 0) <= "010"; else BAL(2 downto 0) <= "110"; end if; if Set_addr_To_r = "11" then BAL(0) <= '1'; end if; end if; if LDDI = '1' then DL <= DI; end if; if LDALU = '1' then DL <= ALU_Q; end if; if LDAD = '1' then AD <= DI; end if; if LDBAL = '1' then BAL(7 downto 0) <= DI; end if; if LDBAH = '1' then BAH <= DI; end if; end if; end if; end if; end process; Break <= (BreakAtNA and not BAL(8)) or (PCAdd and not PCAdder(8)); with Set_BusA_To select BusA <= DI when "000", ABC(7 downto 0) when "001", X(7 downto 0) when "010", Y(7 downto 0) when "011", std_logic_vector(S(7 downto 0)) when "100", P when "101", (others => '-') when others; with Set_Addr_To_r select A <= "0000000000000001" & std_logic_vector(S(7 downto 0)) when "01", DBR & "00000000" & AD when "10", "00000000" & BAH & BAL(7 downto 0) when "11", PBR & std_logic_vector(PC(15 downto 8)) & std_logic_vector(PCAdder(7 downto 0)) when others; with Write_Data_r select DO <= DL when "000", ABC(7 downto 0) when "001", X(7 downto 0) when "010", Y(7 downto 0) when "011", std_logic_vector(S(7 downto 0)) when "100", P when "101", std_logic_vector(PC(7 downto 0)) when "110", std_logic_vector(PC(15 downto 8)) when others; ------------------------------------------------------------------------- -- -- Main state machine -- ------------------------------------------------------------------------- process (Res_n, Clk) begin if Res_n = '0' then MCycle <= "001"; RstCycle <= '1'; IRQCycle <= '0'; NMICycle <= '0'; NMIAct <= '0'; elsif Clk'event and Clk = '1' then if (Enable = '1') then if (really_rdy = '1') then if MCycle = LCycle or Break = '1' then MCycle <= "000"; RstCycle <= '0'; IRQCycle <= '0'; NMICycle <= '0'; if NMIAct = '1' then NMICycle <= '1'; elsif IRQ_n_o = '0' and P(Flag_I) = '0' then IRQCycle <= '1'; end if; else MCycle <= std_logic_vector(unsigned(MCycle) + 1); end if; if NMICycle = '1' then NMIAct <= '0'; end if; if NMI_n_o = '1' and NMI_n = '0' then NMIAct <= '1'; end if; end if; end if; end if; end process; end;