Top secrets sources NedoPC pentevo

Rev

Blame | Last modification | View Log | Download | RSS feed | ?url?

-- ****
-- T80(b) core. In an effort to merge and maintain bug fixes ....
--
--
-- Ver 301 parity flag is just parity for 8080, also overflow for Z80, by Sean Riddle
-- Ver 300 started tidyup
-- MikeJ March 2005
-- Latest version from www.fpgaarcade.com (original www.opencores.org)
--
-- ****
--
-- Z80 compatible microprocessor core
--
-- Version : 0247
--
-- Copyright (c) 2001-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/t80/
--
-- Limitations :
--
-- File history :
--
--      0214 : Fixed mostly flags, only the block instructions now fail the zex regression test
--
--      0238 : Fixed zero flag for 16 bit SBC and ADC
--
--      0240 : Added GB operations
--
--      0242 : Cleanup
--
--      0247 : Cleanup
--

library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.numeric_std.all;

entity T80_ALU is
        generic(
                Mode : integer := 0;
                Flag_C : integer := 0;
                Flag_N : integer := 1;
                Flag_P : integer := 2;
                Flag_X : integer := 3;
                Flag_H : integer := 4;
                Flag_Y : integer := 5;
                Flag_Z : integer := 6;
                Flag_S : integer := 7
        );
        port(
                Arith16         : in  std_logic;
                Z16             : in  std_logic;
                ALU_Op          : in  std_logic_vector(3 downto 0);
                IR              : in  std_logic_vector(5 downto 0);
                ISet            : in  std_logic_vector(1 downto 0);
                BusA            : in  std_logic_vector(7 downto 0);
                BusB            : in  std_logic_vector(7 downto 0);
                F_In            : in  std_logic_vector(7 downto 0);
                Q               : out std_logic_vector(7 downto 0);
                F_Out           : out std_logic_vector(7 downto 0)
        );
end T80_ALU;

architecture rtl of T80_ALU is

        procedure AddSub(A        : std_logic_vector;
                                         B        : std_logic_vector;
                                         Sub      : std_logic;
                                         Carry_In : std_logic;
                          signal Res      : out std_logic_vector;
                          signal Carry    : out std_logic) is

                variable B_i          : unsigned(A'length - 1 downto 0);
                variable Res_i        : unsigned(A'length + 1 downto 0);
        begin
                if Sub = '1' then
                        B_i := not unsigned(B);
                else
                        B_i :=     unsigned(B);
                end if;

                Res_i := unsigned("0" & A & Carry_In) + unsigned("0" & B_i & "1");
                Carry <= Res_i(A'length + 1);
                Res <= std_logic_vector(Res_i(A'length downto 1));
        end;

        -- AddSub variables (temporary signals)
        signal UseCarry                : std_logic;
        signal Carry7_v                : std_logic;
        signal Overflow_v              : std_logic;
        signal HalfCarry_v             : std_logic;
        signal Carry_v                 : std_logic;
        signal Q_v                     : std_logic_vector(7 downto 0);

        signal BitMask                 : std_logic_vector(7 downto 0);

begin

        with IR(5 downto 3) select BitMask <= "00000001" when "000",
                                                                                  "00000010" when "001",
                                                                                  "00000100" when "010",
                                                                                  "00001000" when "011",
                                                                                  "00010000" when "100",
                                                                                  "00100000" when "101",
                                                                                  "01000000" when "110",
                                                                                  "10000000" when others;

        UseCarry <= not ALU_Op(2) and ALU_Op(0);
        AddSub(BusA(3 downto 0), BusB(3 downto 0), ALU_Op(1), ALU_Op(1) xor (UseCarry and F_In(Flag_C)), Q_v(3 downto 0), HalfCarry_v);
        AddSub(BusA(6 downto 4), BusB(6 downto 4), ALU_Op(1), HalfCarry_v, Q_v(6 downto 4), Carry7_v);
        AddSub(BusA(7 downto 7), BusB(7 downto 7), ALU_Op(1), Carry7_v, Q_v(7 downto 7), Carry_v);

        -- bug fix - parity flag is just parity for 8080, also overflow for Z80
        process (Carry_v, Carry7_v, Q_v)
        begin
                if(Mode=2) then
                        OverFlow_v <= not (Q_v(0) xor Q_v(1) xor Q_v(2) xor Q_v(3) xor
                                           Q_v(4) xor Q_v(5) xor Q_v(6) xor Q_v(7));  else
                        OverFlow_v <= Carry_v xor Carry7_v;
                end if;
        end process;

        process (Arith16, ALU_OP, F_In, BusA, BusB, IR, Q_v, Carry_v, HalfCarry_v, OverFlow_v, BitMask, ISet, Z16)
                variable Q_t : std_logic_vector(7 downto 0);
                variable DAA_Q : unsigned(8 downto 0);
        begin
                Q_t := "--------";
                F_Out <= F_In;
                DAA_Q := "---------";
                case ALU_Op is
                when "0000" | "0001" |  "0010" | "0011" | "0100" | "0101" | "0110" | "0111" =>
                        F_Out(Flag_N) <= '0';
                        F_Out(Flag_C) <= '0';
                        case ALU_OP(2 downto 0) is
                        when "000" | "001" => -- ADD, ADC
                                Q_t := Q_v;
                                F_Out(Flag_C) <= Carry_v;
                                F_Out(Flag_H) <= HalfCarry_v;
                                F_Out(Flag_P) <= OverFlow_v;
                        when "010" | "011" | "111" => -- SUB, SBC, CP
                                Q_t := Q_v;
                                F_Out(Flag_N) <= '1';
                                F_Out(Flag_C) <= not Carry_v;
                                F_Out(Flag_H) <= not HalfCarry_v;
                                F_Out(Flag_P) <= OverFlow_v;
                        when "100" => -- AND
                                Q_t(7 downto 0) := BusA and BusB;
                                F_Out(Flag_H) <= '1';
                        when "101" => -- XOR
                                Q_t(7 downto 0) := BusA xor BusB;
                                F_Out(Flag_H) <= '0';
                        when others => -- OR "110"
                                Q_t(7 downto 0) := BusA or BusB;
                                F_Out(Flag_H) <= '0';
                        end case;
                        if ALU_Op(2 downto 0) = "111" then -- CP
                                F_Out(Flag_X) <= BusB(3);
                                F_Out(Flag_Y) <= BusB(5);
                        else
                                F_Out(Flag_X) <= Q_t(3);
                                F_Out(Flag_Y) <= Q_t(5);
                        end if;
                        if Q_t(7 downto 0) = "00000000" then
                                F_Out(Flag_Z) <= '1';
                                if Z16 = '1' then
                                        F_Out(Flag_Z) <= F_In(Flag_Z);      -- 16 bit ADC,SBC
                                end if;
                        else
                                F_Out(Flag_Z) <= '0';
                        end if;
                        F_Out(Flag_S) <= Q_t(7);
                        case ALU_Op(2 downto 0) is
                        when "000" | "001" | "010" | "011" | "111" => -- ADD, ADC, SUB, SBC, CP
                        when others =>
                                F_Out(Flag_P) <= not (Q_t(0) xor Q_t(1) xor Q_t(2) xor Q_t(3) xor
                                        Q_t(4) xor Q_t(5) xor Q_t(6) xor Q_t(7));
                        end case;
                        if Arith16 = '1' then
                                F_Out(Flag_S) <= F_In(Flag_S);
                                F_Out(Flag_Z) <= F_In(Flag_Z);
                                F_Out(Flag_P) <= F_In(Flag_P);
                        end if;
                when "1100" =>
                        -- DAA
                        F_Out(Flag_H) <= F_In(Flag_H);
                        F_Out(Flag_C) <= F_In(Flag_C);
                        DAA_Q(7 downto 0) := unsigned(BusA);
                        DAA_Q(8) := '0';
                        if F_In(Flag_N) = '0' then
                                -- After addition
                                -- Alow > 9 or H = 1
                                if DAA_Q(3 downto 0) > 9 or F_In(Flag_H) = '1' then
                                        if (DAA_Q(3 downto 0) > 9) then
                                                F_Out(Flag_H) <= '1';
                                        else
                                                F_Out(Flag_H) <= '0';
                                        end if;
                                        DAA_Q := DAA_Q + 6;
                                end if;
                                -- new Ahigh > 9 or C = 1
                                if DAA_Q(8 downto 4) > 9 or F_In(Flag_C) = '1' then
                                        DAA_Q := DAA_Q + 96; -- 0x60
                                end if;
                        else
                                -- After subtraction
                                if DAA_Q(3 downto 0) > 9 or F_In(Flag_H) = '1' then
                                        if DAA_Q(3 downto 0) > 5 then
                                                F_Out(Flag_H) <= '0';
                                        end if;
                                        DAA_Q(7 downto 0) := DAA_Q(7 downto 0) - 6;
                                end if;
                                if unsigned(BusA) > 153 or F_In(Flag_C) = '1' then
                                        DAA_Q := DAA_Q - 352; -- 0x160
                                end if;
                        end if;
                        F_Out(Flag_X) <= DAA_Q(3);
                        F_Out(Flag_Y) <= DAA_Q(5);
                        F_Out(Flag_C) <= F_In(Flag_C) or DAA_Q(8);
                        Q_t := std_logic_vector(DAA_Q(7 downto 0));
                        if DAA_Q(7 downto 0) = "00000000" then
                                F_Out(Flag_Z) <= '1';
                        else
                                F_Out(Flag_Z) <= '0';
                        end if;
                        F_Out(Flag_S) <= DAA_Q(7);
                        F_Out(Flag_P) <= not (DAA_Q(0) xor DAA_Q(1) xor DAA_Q(2) xor DAA_Q(3) xor
                                DAA_Q(4) xor DAA_Q(5) xor DAA_Q(6) xor DAA_Q(7));
                when "1101" | "1110" =>
                        -- RLD, RRD
                        Q_t(7 downto 4) := BusA(7 downto 4);
                        if ALU_Op(0) = '1' then
                                Q_t(3 downto 0) := BusB(7 downto 4);
                        else
                                Q_t(3 downto 0) := BusB(3 downto 0);
                        end if;
                        F_Out(Flag_H) <= '0';
                        F_Out(Flag_N) <= '0';
                        F_Out(Flag_X) <= Q_t(3);
                        F_Out(Flag_Y) <= Q_t(5);
                        if Q_t(7 downto 0) = "00000000" then
                                F_Out(Flag_Z) <= '1';
                        else
                                F_Out(Flag_Z) <= '0';
                        end if;
                        F_Out(Flag_S) <= Q_t(7);
                        F_Out(Flag_P) <= not (Q_t(0) xor Q_t(1) xor Q_t(2) xor Q_t(3) xor
                                Q_t(4) xor Q_t(5) xor Q_t(6) xor Q_t(7));
                when "1001" =>
                        -- BIT
                        Q_t(7 downto 0) := BusB and BitMask;
                        F_Out(Flag_S) <= Q_t(7);
                        if Q_t(7 downto 0) = "00000000" then
                                F_Out(Flag_Z) <= '1';
                                F_Out(Flag_P) <= '1';
                        else
                                F_Out(Flag_Z) <= '0';
                                F_Out(Flag_P) <= '0';
                        end if;
                        F_Out(Flag_H) <= '1';
                        F_Out(Flag_N) <= '0';
                        F_Out(Flag_X) <= '0';
                        F_Out(Flag_Y) <= '0';
                        if IR(2 downto 0) /= "110" then
                                F_Out(Flag_X) <= BusB(3);
                                F_Out(Flag_Y) <= BusB(5);
                        end if;
                when "1010" =>
                        -- SET
                        Q_t(7 downto 0) := BusB or BitMask;
                when "1011" =>
                        -- RES
                        Q_t(7 downto 0) := BusB and not BitMask;
                when "1000" =>
                        -- ROT
                        case IR(5 downto 3) is
                        when "000" => -- RLC
                                Q_t(7 downto 1) := BusA(6 downto 0);
                                Q_t(0) := BusA(7);
                                F_Out(Flag_C) <= BusA(7);
                        when "010" => -- RL
                                Q_t(7 downto 1) := BusA(6 downto 0);
                                Q_t(0) := F_In(Flag_C);
                                F_Out(Flag_C) <= BusA(7);
                        when "001" => -- RRC
                                Q_t(6 downto 0) := BusA(7 downto 1);
                                Q_t(7) := BusA(0);
                                F_Out(Flag_C) <= BusA(0);
                        when "011" => -- RR
                                Q_t(6 downto 0) := BusA(7 downto 1);
                                Q_t(7) := F_In(Flag_C);
                                F_Out(Flag_C) <= BusA(0);
                        when "100" => -- SLA
                                Q_t(7 downto 1) := BusA(6 downto 0);
                                Q_t(0) := '0';
                                F_Out(Flag_C) <= BusA(7);
                        when "110" => -- SLL (Undocumented) / SWAP
                                if Mode = 3 then
                                        Q_t(7 downto 4) := BusA(3 downto 0);
                                        Q_t(3 downto 0) := BusA(7 downto 4);
                                        F_Out(Flag_C) <= '0';
                                else
                                        Q_t(7 downto 1) := BusA(6 downto 0);
                                        Q_t(0) := '1';
                                        F_Out(Flag_C) <= BusA(7);
                                end if;
                        when "101" => -- SRA
                                Q_t(6 downto 0) := BusA(7 downto 1);
                                Q_t(7) := BusA(7);
                                F_Out(Flag_C) <= BusA(0);
                        when others => -- SRL
                                Q_t(6 downto 0) := BusA(7 downto 1);
                                Q_t(7) := '0';
                                F_Out(Flag_C) <= BusA(0);
                        end case;
                        F_Out(Flag_H) <= '0';
                        F_Out(Flag_N) <= '0';
                        F_Out(Flag_X) <= Q_t(3);
                        F_Out(Flag_Y) <= Q_t(5);
                        F_Out(Flag_S) <= Q_t(7);
                        if Q_t(7 downto 0) = "00000000" then
                                F_Out(Flag_Z) <= '1';
                        else
                                F_Out(Flag_Z) <= '0';
                        end if;
                        F_Out(Flag_P) <= not (Q_t(0) xor Q_t(1) xor Q_t(2) xor Q_t(3) xor
                                Q_t(4) xor Q_t(5) xor Q_t(6) xor Q_t(7));
                        if ISet = "00" then
                                F_Out(Flag_P) <= F_In(Flag_P);
                                F_Out(Flag_S) <= F_In(Flag_S);
                                F_Out(Flag_Z) <= F_In(Flag_Z);
                        end if;
                when others =>
                        null;
                end case;
                Q <= Q_t;
        end process;
end;