2 -- T80(b) core. In an effort to merge and maintain bug fixes ....
 
   5 -- Ver 301 parity flag is just parity for 8080, also overflow for Z80, by Sean Riddle
 
   6 -- Ver 300 started tidyup
 
   8 -- Latest version from www.fpgaarcade.com (original www.opencores.org)
 
  12 -- Z80 compatible microprocessor core
 
  16 -- Copyright (c) 2001-2002 Daniel Wallner (jesus@opencores.org)
 
  18 -- All rights reserved
 
  20 -- Redistribution and use in source and synthezised forms, with or without
 
  21 -- modification, are permitted provided that the following conditions are met:
 
  23 -- Redistributions of source code must retain the above copyright notice,
 
  24 -- this list of conditions and the following disclaimer.
 
  26 -- Redistributions in synthesized form must reproduce the above copyright
 
  27 -- notice, this list of conditions and the following disclaimer in the
 
  28 -- documentation and/or other materials provided with the distribution.
 
  30 -- Neither the name of the author nor the names of other contributors may
 
  31 -- be used to endorse or promote products derived from this software without
 
  32 -- specific prior written permission.
 
  34 -- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 
  35 -- AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 
  36 -- THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 
  37 -- PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE
 
  38 -- LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 
  39 -- CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 
  40 -- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 
  41 -- INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 
  42 -- CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 
  43 -- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 
  44 -- POSSIBILITY OF SUCH DAMAGE.
 
  46 -- Please report bugs to the author, but before you do so, please
 
  47 -- make sure that this is not a derivative work and that
 
  48 -- you have the latest version of this file.
 
  50 -- The latest version of this file can be found at:
 
  51 --      http://www.opencores.org/cvsweb.shtml/t80/
 
  57 --      0214 : Fixed mostly flags, only the block instructions now fail the zex regression test
 
  59 --      0238 : Fixed zero flag for 16 bit SBC and ADC
 
  61 --      0240 : Added GB operations
 
  69 use IEEE.std_logic_1164.all;
 
  70 use IEEE.numeric_std.all;
 
  75                 Flag_C : integer := 0;
 
  76                 Flag_N : integer := 1;
 
  77                 Flag_P : integer := 2;
 
  78                 Flag_X : integer := 3;
 
  79                 Flag_H : integer := 4;
 
  80                 Flag_Y : integer := 5;
 
  81                 Flag_Z : integer := 6;
 
  85                 Arith16         : in  std_logic;
 
  87                 ALU_Op          : in  std_logic_vector(3 downto 0);
 
  88                 IR              : in  std_logic_vector(5 downto 0);
 
  89                 ISet            : in  std_logic_vector(1 downto 0);
 
  90                 BusA            : in  std_logic_vector(7 downto 0);
 
  91                 BusB            : in  std_logic_vector(7 downto 0);
 
  92                 F_In            : in  std_logic_vector(7 downto 0);
 
  93                 Q               : out std_logic_vector(7 downto 0);
 
  94                 F_Out           : out std_logic_vector(7 downto 0)
 
  98 architecture rtl of T80_ALU is
 
 100         procedure AddSub(A        : std_logic_vector;
 
 101                                          B        : std_logic_vector;
 
 103                                          Carry_In : std_logic;
 
 104                           signal Res      : out std_logic_vector;
 
 105                           signal Carry    : out std_logic) is
 
 107                 variable B_i          : unsigned(A'length - 1 downto 0);
 
 108                 variable Res_i        : unsigned(A'length + 1 downto 0);
 
 111                         B_i := not unsigned(B);
 
 116                 Res_i := unsigned("0" & A & Carry_In) + unsigned("0" & B_i & "1");
 
 117                 Carry <= Res_i(A'length + 1);
 
 118                 Res <= std_logic_vector(Res_i(A'length downto 1));
 
 121         -- AddSub variables (temporary signals)
 
 122         signal UseCarry                : std_logic;
 
 123         signal Carry7_v                : std_logic;
 
 124         signal Overflow_v              : std_logic;
 
 125         signal HalfCarry_v             : std_logic;
 
 126         signal Carry_v                 : std_logic;
 
 127         signal Q_v                     : std_logic_vector(7 downto 0);
 
 129         signal BitMask                 : std_logic_vector(7 downto 0);
 
 133         with IR(5 downto 3) select BitMask <= "00000001" when "000",
 
 134                                                                                   "00000010" when "001",
 
 135                                                                                   "00000100" when "010",
 
 136                                                                                   "00001000" when "011",
 
 137                                                                                   "00010000" when "100",
 
 138                                                                                   "00100000" when "101",
 
 139                                                                                   "01000000" when "110",
 
 140                                                                                   "10000000" when others;
 
 142         UseCarry <= not ALU_Op(2) and ALU_Op(0);
 
 143         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);
 
 144         AddSub(BusA(6 downto 4), BusB(6 downto 4), ALU_Op(1), HalfCarry_v, Q_v(6 downto 4), Carry7_v);
 
 145         AddSub(BusA(7 downto 7), BusB(7 downto 7), ALU_Op(1), Carry7_v, Q_v(7 downto 7), Carry_v);
 
 147         -- bug fix - parity flag is just parity for 8080, also overflow for Z80
 
 148         process (Carry_v, Carry7_v, Q_v)
 
 151                         OverFlow_v <= not (Q_v(0) xor Q_v(1) xor Q_v(2) xor Q_v(3) xor
 
 152                                            Q_v(4) xor Q_v(5) xor Q_v(6) xor Q_v(7));  else
 
 153                         OverFlow_v <= Carry_v xor Carry7_v;
 
 157         process (Arith16, ALU_OP, F_In, BusA, BusB, IR, Q_v, Carry_v, HalfCarry_v, OverFlow_v, BitMask, ISet, Z16)
 
 158                 variable Q_t : std_logic_vector(7 downto 0);
 
 159                 variable DAA_Q : unsigned(8 downto 0);
 
 163                 DAA_Q := "---------";
 
 165                 when "0000" | "0001" |  "0010" | "0011" | "0100" | "0101" | "0110" | "0111" =>
 
 166                         F_Out(Flag_N) <= '0';
 
 167                         F_Out(Flag_C) <= '0';
 
 168                         case ALU_OP(2 downto 0) is
 
 169                         when "000" | "001" => -- ADD, ADC
 
 171                                 F_Out(Flag_C) <= Carry_v;
 
 172                                 F_Out(Flag_H) <= HalfCarry_v;
 
 173                                 F_Out(Flag_P) <= OverFlow_v;
 
 174                         when "010" | "011" | "111" => -- SUB, SBC, CP
 
 176                                 F_Out(Flag_N) <= '1';
 
 177                                 F_Out(Flag_C) <= not Carry_v;
 
 178                                 F_Out(Flag_H) <= not HalfCarry_v;
 
 179                                 F_Out(Flag_P) <= OverFlow_v;
 
 181                                 Q_t(7 downto 0) := BusA and BusB;
 
 182                                 F_Out(Flag_H) <= '1';
 
 184                                 Q_t(7 downto 0) := BusA xor BusB;
 
 185                                 F_Out(Flag_H) <= '0';
 
 186                         when others => -- OR "110"
 
 187                                 Q_t(7 downto 0) := BusA or BusB;
 
 188                                 F_Out(Flag_H) <= '0';
 
 190                         if ALU_Op(2 downto 0) = "111" then -- CP
 
 191                                 F_Out(Flag_X) <= BusB(3);
 
 192                                 F_Out(Flag_Y) <= BusB(5);
 
 194                                 F_Out(Flag_X) <= Q_t(3);
 
 195                                 F_Out(Flag_Y) <= Q_t(5);
 
 197                         if Q_t(7 downto 0) = "00000000" then
 
 198                                 F_Out(Flag_Z) <= '1';
 
 200                                         F_Out(Flag_Z) <= F_In(Flag_Z);      -- 16 bit ADC,SBC
 
 203                                 F_Out(Flag_Z) <= '0';
 
 205                         F_Out(Flag_S) <= Q_t(7);
 
 206                         case ALU_Op(2 downto 0) is
 
 207                         when "000" | "001" | "010" | "011" | "111" => -- ADD, ADC, SUB, SBC, CP
 
 209                                 F_Out(Flag_P) <= not (Q_t(0) xor Q_t(1) xor Q_t(2) xor Q_t(3) xor
 
 210                                         Q_t(4) xor Q_t(5) xor Q_t(6) xor Q_t(7));
 
 212                         if Arith16 = '1' then
 
 213                                 F_Out(Flag_S) <= F_In(Flag_S);
 
 214                                 F_Out(Flag_Z) <= F_In(Flag_Z);
 
 215                                 F_Out(Flag_P) <= F_In(Flag_P);
 
 219                         F_Out(Flag_H) <= F_In(Flag_H);
 
 220                         F_Out(Flag_C) <= F_In(Flag_C);
 
 221                         DAA_Q(7 downto 0) := unsigned(BusA);
 
 223                         if F_In(Flag_N) = '0' then
 
 226                                 if DAA_Q(3 downto 0) > 9 or F_In(Flag_H) = '1' then
 
 227                                         if (DAA_Q(3 downto 0) > 9) then
 
 228                                                 F_Out(Flag_H) <= '1';
 
 230                                                 F_Out(Flag_H) <= '0';
 
 234                                 -- new Ahigh > 9 or C = 1
 
 235                                 if DAA_Q(8 downto 4) > 9 or F_In(Flag_C) = '1' then
 
 236                                         DAA_Q := DAA_Q + 96; -- 0x60
 
 240                                 if DAA_Q(3 downto 0) > 9 or F_In(Flag_H) = '1' then
 
 241                                         if DAA_Q(3 downto 0) > 5 then
 
 242                                                 F_Out(Flag_H) <= '0';
 
 244                                         DAA_Q(7 downto 0) := DAA_Q(7 downto 0) - 6;
 
 246                                 if unsigned(BusA) > 153 or F_In(Flag_C) = '1' then
 
 247                                         DAA_Q := DAA_Q - 352; -- 0x160
 
 250                         F_Out(Flag_X) <= DAA_Q(3);
 
 251                         F_Out(Flag_Y) <= DAA_Q(5);
 
 252                         F_Out(Flag_C) <= F_In(Flag_C) or DAA_Q(8);
 
 253                         Q_t := std_logic_vector(DAA_Q(7 downto 0));
 
 254                         if DAA_Q(7 downto 0) = "00000000" then
 
 255                                 F_Out(Flag_Z) <= '1';
 
 257                                 F_Out(Flag_Z) <= '0';
 
 259                         F_Out(Flag_S) <= DAA_Q(7);
 
 260                         F_Out(Flag_P) <= not (DAA_Q(0) xor DAA_Q(1) xor DAA_Q(2) xor DAA_Q(3) xor
 
 261                                 DAA_Q(4) xor DAA_Q(5) xor DAA_Q(6) xor DAA_Q(7));
 
 262                 when "1101" | "1110" =>
 
 264                         Q_t(7 downto 4) := BusA(7 downto 4);
 
 265                         if ALU_Op(0) = '1' then
 
 266                                 Q_t(3 downto 0) := BusB(7 downto 4);
 
 268                                 Q_t(3 downto 0) := BusB(3 downto 0);
 
 270                         F_Out(Flag_H) <= '0';
 
 271                         F_Out(Flag_N) <= '0';
 
 272                         F_Out(Flag_X) <= Q_t(3);
 
 273                         F_Out(Flag_Y) <= Q_t(5);
 
 274                         if Q_t(7 downto 0) = "00000000" then
 
 275                                 F_Out(Flag_Z) <= '1';
 
 277                                 F_Out(Flag_Z) <= '0';
 
 279                         F_Out(Flag_S) <= Q_t(7);
 
 280                         F_Out(Flag_P) <= not (Q_t(0) xor Q_t(1) xor Q_t(2) xor Q_t(3) xor
 
 281                                 Q_t(4) xor Q_t(5) xor Q_t(6) xor Q_t(7));
 
 284                         Q_t(7 downto 0) := BusB and BitMask;
 
 285                         F_Out(Flag_S) <= Q_t(7);
 
 286                         if Q_t(7 downto 0) = "00000000" then
 
 287                                 F_Out(Flag_Z) <= '1';
 
 288                                 F_Out(Flag_P) <= '1';
 
 290                                 F_Out(Flag_Z) <= '0';
 
 291                                 F_Out(Flag_P) <= '0';
 
 293                         F_Out(Flag_H) <= '1';
 
 294                         F_Out(Flag_N) <= '0';
 
 295                         F_Out(Flag_X) <= '0';
 
 296                         F_Out(Flag_Y) <= '0';
 
 297                         if IR(2 downto 0) /= "110" then
 
 298                                 F_Out(Flag_X) <= BusB(3);
 
 299                                 F_Out(Flag_Y) <= BusB(5);
 
 303                         Q_t(7 downto 0) := BusB or BitMask;
 
 306                         Q_t(7 downto 0) := BusB and not BitMask;
 
 309                         case IR(5 downto 3) is
 
 311                                 Q_t(7 downto 1) := BusA(6 downto 0);
 
 313                                 F_Out(Flag_C) <= BusA(7);
 
 315                                 Q_t(7 downto 1) := BusA(6 downto 0);
 
 316                                 Q_t(0) := F_In(Flag_C);
 
 317                                 F_Out(Flag_C) <= BusA(7);
 
 319                                 Q_t(6 downto 0) := BusA(7 downto 1);
 
 321                                 F_Out(Flag_C) <= BusA(0);
 
 323                                 Q_t(6 downto 0) := BusA(7 downto 1);
 
 324                                 Q_t(7) := F_In(Flag_C);
 
 325                                 F_Out(Flag_C) <= BusA(0);
 
 327                                 Q_t(7 downto 1) := BusA(6 downto 0);
 
 329                                 F_Out(Flag_C) <= BusA(7);
 
 330                         when "110" => -- SLL (Undocumented) / SWAP
 
 332                                         Q_t(7 downto 4) := BusA(3 downto 0);
 
 333                                         Q_t(3 downto 0) := BusA(7 downto 4);
 
 334                                         F_Out(Flag_C) <= '0';
 
 336                                         Q_t(7 downto 1) := BusA(6 downto 0);
 
 338                                         F_Out(Flag_C) <= BusA(7);
 
 341                                 Q_t(6 downto 0) := BusA(7 downto 1);
 
 343                                 F_Out(Flag_C) <= BusA(0);
 
 344                         when others => -- SRL
 
 345                                 Q_t(6 downto 0) := BusA(7 downto 1);
 
 347                                 F_Out(Flag_C) <= BusA(0);
 
 349                         F_Out(Flag_H) <= '0';
 
 350                         F_Out(Flag_N) <= '0';
 
 351                         F_Out(Flag_X) <= Q_t(3);
 
 352                         F_Out(Flag_Y) <= Q_t(5);
 
 353                         F_Out(Flag_S) <= Q_t(7);
 
 354                         if Q_t(7 downto 0) = "00000000" then
 
 355                                 F_Out(Flag_Z) <= '1';
 
 357                                 F_Out(Flag_Z) <= '0';
 
 359                         F_Out(Flag_P) <= not (Q_t(0) xor Q_t(1) xor Q_t(2) xor Q_t(3) xor
 
 360                                 Q_t(4) xor Q_t(5) xor Q_t(6) xor Q_t(7));
 
 362                                 F_Out(Flag_P) <= F_In(Flag_P);
 
 363                                 F_Out(Flag_S) <= F_In(Flag_S);
 
 364                                 F_Out(Flag_Z) <= F_In(Flag_Z);