Subversion Repositories pentevo

Rev

Rev 896 | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed | ?url?

  1. -- ****
  2. -- T80(b) core. In an effort to merge and maintain bug fixes ....
  3. --
  4. --
  5. -- Ver 301 parity flag is just parity for 8080, also overflow for Z80, by Sean Riddle
  6. -- Ver 300 started tidyup
  7. -- MikeJ March 2005
  8. -- Latest version from www.fpgaarcade.com (original www.opencores.org)
  9. --
  10. -- ****
  11. --
  12. -- Z80 compatible microprocessor core
  13. --
  14. -- Version : 0247
  15. --
  16. -- Copyright (c) 2001-2002 Daniel Wallner (jesus@opencores.org)
  17. --
  18. -- All rights reserved
  19. --
  20. -- Redistribution and use in source and synthezised forms, with or without
  21. -- modification, are permitted provided that the following conditions are met:
  22. --
  23. -- Redistributions of source code must retain the above copyright notice,
  24. -- this list of conditions and the following disclaimer.
  25. --
  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.
  29. --
  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.
  33. --
  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.
  45. --
  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.
  49. --
  50. -- The latest version of this file can be found at:
  51. --      http://www.opencores.org/cvsweb.shtml/t80/
  52. --
  53. -- Limitations :
  54. --
  55. -- File history :
  56. --
  57. --      0214 : Fixed mostly flags, only the block instructions now fail the zex regression test
  58. --
  59. --      0238 : Fixed zero flag for 16 bit SBC and ADC
  60. --
  61. --      0240 : Added GB operations
  62. --
  63. --      0242 : Cleanup
  64. --
  65. --      0247 : Cleanup
  66. --
  67.  
  68. library IEEE;
  69. use IEEE.std_logic_1164.all;
  70. use IEEE.numeric_std.all;
  71.  
  72. entity T80_ALU is
  73.         generic(
  74.                 Mode : integer := 0;
  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;
  82.                 Flag_S : integer := 7
  83.         );
  84.         port(
  85.                 Arith16         : in  std_logic;
  86.                 Z16             : 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)
  95.         );
  96. end T80_ALU;
  97.  
  98. architecture rtl of T80_ALU is
  99.  
  100.         procedure AddSub(A        : std_logic_vector;
  101.                                          B        : std_logic_vector;
  102.                                          Sub      : std_logic;
  103.                                          Carry_In : std_logic;
  104.                           signal Res      : out std_logic_vector;
  105.                           signal Carry    : out std_logic) is
  106.  
  107.                 variable B_i          : unsigned(A'length - 1 downto 0);
  108.                 variable Res_i        : unsigned(A'length + 1 downto 0);
  109.         begin
  110.                 if Sub = '1' then
  111.                         B_i := not unsigned(B);
  112.                 else
  113.                         B_i :=     unsigned(B);
  114.                 end if;
  115.  
  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));
  119.         end;
  120.  
  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);
  128.  
  129.         signal BitMask                 : std_logic_vector(7 downto 0);
  130.  
  131. begin
  132.  
  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;
  141.  
  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);
  146.  
  147.         -- bug fix - parity flag is just parity for 8080, also overflow for Z80
  148.         process (Carry_v, Carry7_v, Q_v)
  149.         begin
  150.                 if(Mode=2) then
  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;
  154.                 end if;
  155.         end process;
  156.  
  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);
  160.         begin
  161.                 Q_t := "--------";
  162.                 F_Out <= F_In;
  163.                 DAA_Q := "---------";
  164.                 case ALU_Op is
  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
  170.                                 Q_t := Q_v;
  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
  175.                                 Q_t := Q_v;
  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;
  180.                         when "100" => -- AND
  181.                                 Q_t(7 downto 0) := BusA and BusB;
  182.                                 F_Out(Flag_H) <= '1';
  183.                         when "101" => -- XOR
  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';
  189.                         end case;
  190.                         if ALU_Op(2 downto 0) = "111" then -- CP
  191.                                 F_Out(Flag_X) <= BusB(3);
  192.                                 F_Out(Flag_Y) <= BusB(5);
  193.                         else
  194.                                 F_Out(Flag_X) <= Q_t(3);
  195.                                 F_Out(Flag_Y) <= Q_t(5);
  196.                         end if;
  197.                         if Q_t(7 downto 0) = "00000000" then
  198.                                 F_Out(Flag_Z) <= '1';
  199.                                 if Z16 = '1' then
  200.                                         F_Out(Flag_Z) <= F_In(Flag_Z);      -- 16 bit ADC,SBC
  201.                                 end if;
  202.                         else
  203.                                 F_Out(Flag_Z) <= '0';
  204.                         end if;
  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
  208.                         when others =>
  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));
  211.                         end case;
  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);
  216.                         end if;
  217.                 when "1100" =>
  218.                         -- DAA
  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);
  222.                         DAA_Q(8) := '0';
  223.                         if F_In(Flag_N) = '0' then
  224.                                 -- After addition
  225.                                 -- Alow > 9 or H = 1
  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';
  229.                                         else
  230.                                                 F_Out(Flag_H) <= '0';
  231.                                         end if;
  232.                                         DAA_Q := DAA_Q + 6;
  233.                                 end if;
  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
  237.                                 end if;
  238.                         else
  239.                                 -- After subtraction
  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';
  243.                                         end if;
  244.                                         DAA_Q(7 downto 0) := DAA_Q(7 downto 0) - 6;
  245.                                 end if;
  246.                                 if unsigned(BusA) > 153 or F_In(Flag_C) = '1' then
  247.                                         DAA_Q := DAA_Q - 352; -- 0x160
  248.                                 end if;
  249.                         end if;
  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';
  256.                         else
  257.                                 F_Out(Flag_Z) <= '0';
  258.                         end if;
  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" =>
  263.                         -- RLD, RRD
  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);
  267.                         else
  268.                                 Q_t(3 downto 0) := BusB(3 downto 0);
  269.                         end if;
  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';
  276.                         else
  277.                                 F_Out(Flag_Z) <= '0';
  278.                         end if;
  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));
  282.                 when "1001" =>
  283.                         -- BIT
  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';
  289.                         else
  290.                                 F_Out(Flag_Z) <= '0';
  291.                                 F_Out(Flag_P) <= '0';
  292.                         end if;
  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);
  300.                         end if;
  301.                 when "1010" =>
  302.                         -- SET
  303.                         Q_t(7 downto 0) := BusB or BitMask;
  304.                 when "1011" =>
  305.                         -- RES
  306.                         Q_t(7 downto 0) := BusB and not BitMask;
  307.                 when "1000" =>
  308.                         -- ROT
  309.                         case IR(5 downto 3) is
  310.                         when "000" => -- RLC
  311.                                 Q_t(7 downto 1) := BusA(6 downto 0);
  312.                                 Q_t(0) := BusA(7);
  313.                                 F_Out(Flag_C) <= BusA(7);
  314.                         when "010" => -- RL
  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);
  318.                         when "001" => -- RRC
  319.                                 Q_t(6 downto 0) := BusA(7 downto 1);
  320.                                 Q_t(7) := BusA(0);
  321.                                 F_Out(Flag_C) <= BusA(0);
  322.                         when "011" => -- RR
  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);
  326.                         when "100" => -- SLA
  327.                                 Q_t(7 downto 1) := BusA(6 downto 0);
  328.                                 Q_t(0) := '0';
  329.                                 F_Out(Flag_C) <= BusA(7);
  330.                         when "110" => -- SLL (Undocumented) / SWAP
  331.                                 if Mode = 3 then
  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';
  335.                                 else
  336.                                         Q_t(7 downto 1) := BusA(6 downto 0);
  337.                                         Q_t(0) := '1';
  338.                                         F_Out(Flag_C) <= BusA(7);
  339.                                 end if;
  340.                         when "101" => -- SRA
  341.                                 Q_t(6 downto 0) := BusA(7 downto 1);
  342.                                 Q_t(7) := BusA(7);
  343.                                 F_Out(Flag_C) <= BusA(0);
  344.                         when others => -- SRL
  345.                                 Q_t(6 downto 0) := BusA(7 downto 1);
  346.                                 Q_t(7) := '0';
  347.                                 F_Out(Flag_C) <= BusA(0);
  348.                         end case;
  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';
  356.                         else
  357.                                 F_Out(Flag_Z) <= '0';
  358.                         end if;
  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));
  361.                         if ISet = "00" then
  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);
  365.                         end if;
  366.                 when others =>
  367.                         null;
  368.                 end case;
  369.                 Q <= Q_t;
  370.         end process;
  371. end;
  372.