Subversion Repositories KoE_projects

Rev

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

  1. --------------------------------------------------------------------------------
  2. -- ****
  3. -- T80(c) core. Attempt to finish all undocumented features and provide
  4. --              accurate timings.
  5. -- Version 350.
  6. -- Copyright (c) 2018 Sorgelig
  7. --  Test passed: ZEXDOC, ZEXALL, Z80Full(*), Z80memptr
  8. --  (*) Currently only SCF and CCF instructions aren't passed X/Y flags check as
  9. --      correct implementation is still unclear.
  10. --
  11. -- ****
  12. -- T80(b) core. In an effort to merge and maintain bug fixes ....
  13. --
  14. -- Ver 301 parity flag is just parity for 8080, also overflow for Z80, by Sean Riddle
  15. -- Ver 300 started tidyup
  16. -- MikeJ March 2005
  17. -- Latest version from www.fpgaarcade.com (original www.opencores.org)
  18. --
  19. -- ****
  20. -- Z80 compatible microprocessor core
  21. --
  22. -- Version : 0247
  23. -- Copyright (c) 2001-2002 Daniel Wallner (jesus@opencores.org)
  24. -- All rights reserved
  25. --
  26. -- Redistribution and use in source and synthezised forms, with or without
  27. -- modification, are permitted provided that the following conditions are met:
  28. --
  29. -- Redistributions of source code must retain the above copyright notice,
  30. -- this list of conditions and the following disclaimer.
  31. --
  32. -- Redistributions in synthesized form must reproduce the above copyright
  33. -- notice, this list of conditions and the following disclaimer in the
  34. -- documentation and/or other materials provided with the distribution.
  35. --
  36. -- Neither the name of the author nor the names of other contributors may
  37. -- be used to endorse or promote products derived from this software without
  38. -- specific prior written permission.
  39. --
  40. -- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  41. -- AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
  42. -- THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  43. -- PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE
  44. -- LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  45. -- CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  46. -- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  47. -- INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  48. -- CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  49. -- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  50. -- POSSIBILITY OF SUCH DAMAGE.
  51. --
  52. -- Please report bugs to the author, but before you do so, please
  53. -- make sure that this is not a derivative work and that
  54. -- you have the latest version of this file.
  55. --
  56. -- The latest version of this file can be found at:
  57. --      http://www.opencores.org/cvsweb.shtml/t80/
  58. --
  59. -- Limitations :
  60. --
  61. -- File history :
  62. --
  63. --      0214 : Fixed mostly flags, only the block instructions now fail the zex regression test
  64. --      0238 : Fixed zero flag for 16 bit SBC and ADC
  65. --      0240 : Added GB operations
  66. --      0242 : Cleanup
  67. --      0247 : Cleanup
  68. --
  69.  
  70. library IEEE;
  71. use IEEE.std_logic_1164.all;
  72. use IEEE.numeric_std.all;
  73.  
  74. entity T80_ALU is
  75.         generic(
  76.                 Mode : integer := 0;
  77.                 Flag_C : integer := 0;
  78.                 Flag_N : integer := 1;
  79.                 Flag_P : integer := 2;
  80.                 Flag_X : integer := 3;
  81.                 Flag_H : integer := 4;
  82.                 Flag_Y : integer := 5;
  83.                 Flag_Z : integer := 6;
  84.                 Flag_S : integer := 7
  85.         );
  86.         port(
  87.                 Arith16         : in  std_logic;
  88.                 Z16             : in  std_logic;
  89.                 WZ              : in  std_logic_vector(15 downto 0);
  90.                 XY_State                    : in  std_logic_vector(1 downto 0);
  91.                 ALU_Op          : in  std_logic_vector(3 downto 0);
  92.                 IR              : in  std_logic_vector(5 downto 0);
  93.                 ISet            : in  std_logic_vector(1 downto 0);
  94.                 BusA            : in  std_logic_vector(7 downto 0);
  95.                 BusB            : in  std_logic_vector(7 downto 0);
  96.                 F_In            : in  std_logic_vector(7 downto 0);
  97.                 Q               : out std_logic_vector(7 downto 0);
  98.                 F_Out           : out std_logic_vector(7 downto 0)
  99.         );
  100. end T80_ALU;
  101.  
  102. architecture rtl of T80_ALU is
  103.  
  104.         procedure AddSub(A        : std_logic_vector;
  105.                                          B        : std_logic_vector;
  106.                                          Sub      : std_logic;
  107.                                          Carry_In : std_logic;
  108.                           signal Res      : out std_logic_vector;
  109.                           signal Carry    : out std_logic) is
  110.  
  111.                 variable B_i          : unsigned(A'length - 1 downto 0);
  112.                 variable Res_i        : unsigned(A'length + 1 downto 0);
  113.         begin
  114.                 if Sub = '1' then
  115.                         B_i := not unsigned(B);
  116.                 else
  117.                         B_i :=     unsigned(B);
  118.                 end if;
  119.  
  120.                 Res_i := unsigned("0" & A & Carry_In) + unsigned("0" & B_i & "1");
  121.                 Carry <= Res_i(A'length + 1);
  122.                 Res <= std_logic_vector(Res_i(A'length downto 1));
  123.         end;
  124.  
  125.         -- AddSub variables (temporary signals)
  126.         signal UseCarry                : std_logic;
  127.         signal Carry7_v                : std_logic;
  128.         signal Overflow_v              : std_logic;
  129.         signal HalfCarry_v             : std_logic;
  130.         signal Carry_v                 : std_logic;
  131.         signal Q_v                     : std_logic_vector(7 downto 0);
  132.  
  133.         signal BitMask                 : std_logic_vector(7 downto 0);
  134.  
  135. begin
  136.  
  137.         with IR(5 downto 3) select BitMask <= "00000001" when "000",
  138.                                                                                   "00000010" when "001",
  139.                                                                                   "00000100" when "010",
  140.                                                                                   "00001000" when "011",
  141.                                                                                   "00010000" when "100",
  142.                                                                                   "00100000" when "101",
  143.                                                                                   "01000000" when "110",
  144.                                                                                   "10000000" when others;
  145.  
  146.         UseCarry <= not ALU_Op(2) and ALU_Op(0);
  147.         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);
  148.         AddSub(BusA(6 downto 4), BusB(6 downto 4), ALU_Op(1), HalfCarry_v, Q_v(6 downto 4), Carry7_v);
  149.         AddSub(BusA(7 downto 7), BusB(7 downto 7), ALU_Op(1), Carry7_v, Q_v(7 downto 7), Carry_v);
  150.  
  151.         -- bug fix - parity flag is just parity for 8080, also overflow for Z80
  152.         process (Carry_v, Carry7_v, Q_v)
  153.         begin
  154.                 if(Mode=2) then
  155.                         OverFlow_v <= not (Q_v(0) xor Q_v(1) xor Q_v(2) xor Q_v(3) xor
  156.                                            Q_v(4) xor Q_v(5) xor Q_v(6) xor Q_v(7));  else
  157.                         OverFlow_v <= Carry_v xor Carry7_v;
  158.                 end if;
  159.         end process;
  160.  
  161.         process (Arith16, ALU_OP, F_In, BusA, BusB, IR, Q_v, Carry_v, HalfCarry_v, OverFlow_v, BitMask, ISet, Z16, WZ, XY_State)
  162.                 variable Q_t : std_logic_vector(7 downto 0);
  163.                 variable DAA_Q : unsigned(8 downto 0);
  164.         begin
  165.                 Q_t := "--------";
  166.                 F_Out <= F_In;
  167.                 DAA_Q := "---------";
  168.                 case ALU_Op is
  169.                 when "0000" | "0001" |  "0010" | "0011" | "0100" | "0101" | "0110" | "0111" =>
  170.                         F_Out(Flag_N) <= '0';
  171.                         F_Out(Flag_C) <= '0';
  172.                         case ALU_OP(2 downto 0) is
  173.                         when "000" | "001" => -- ADD, ADC
  174.                                 Q_t := Q_v;
  175.                                 F_Out(Flag_C) <= Carry_v;
  176.                                 F_Out(Flag_H) <= HalfCarry_v;
  177.                                 F_Out(Flag_P) <= OverFlow_v;
  178.                         when "010" | "011" | "111" => -- SUB, SBC, CP
  179.                                 Q_t := Q_v;
  180.                                 F_Out(Flag_N) <= '1';
  181.                                 F_Out(Flag_C) <= not Carry_v;
  182.                                 F_Out(Flag_H) <= not HalfCarry_v;
  183.                                 F_Out(Flag_P) <= OverFlow_v;
  184.                         when "100" => -- AND
  185.                                 Q_t(7 downto 0) := BusA and BusB;
  186.                                 F_Out(Flag_H) <= '1';
  187.                         when "101" => -- XOR
  188.                                 Q_t(7 downto 0) := BusA xor BusB;
  189.                                 F_Out(Flag_H) <= '0';
  190.                         when others => -- OR "110"
  191.                                 Q_t(7 downto 0) := BusA or BusB;
  192.                                 F_Out(Flag_H) <= '0';
  193.                         end case;
  194.                         if ALU_Op(2 downto 0) = "111" then -- CP
  195.                                 F_Out(Flag_X) <= BusB(3);
  196.                                 F_Out(Flag_Y) <= BusB(5);
  197.                         else
  198.                                 F_Out(Flag_X) <= Q_t(3);
  199.                                 F_Out(Flag_Y) <= Q_t(5);
  200.                         end if;
  201.                         if Q_t(7 downto 0) = "00000000" then
  202.                                 F_Out(Flag_Z) <= '1';
  203.                                 if Z16 = '1' then
  204.                                         F_Out(Flag_Z) <= F_In(Flag_Z);      -- 16 bit ADC,SBC
  205.                                 end if;
  206.                         else
  207.                                 F_Out(Flag_Z) <= '0';
  208.                         end if;
  209.                         F_Out(Flag_S) <= Q_t(7);
  210.                         case ALU_Op(2 downto 0) is
  211.                         when "000" | "001" | "010" | "011" | "111" => -- ADD, ADC, SUB, SBC, CP
  212.                         when others =>
  213.                                 F_Out(Flag_P) <= not (Q_t(0) xor Q_t(1) xor Q_t(2) xor Q_t(3) xor
  214.                                         Q_t(4) xor Q_t(5) xor Q_t(6) xor Q_t(7));
  215.                         end case;
  216.                         if Arith16 = '1' then
  217.                                 F_Out(Flag_S) <= F_In(Flag_S);
  218.                                 F_Out(Flag_Z) <= F_In(Flag_Z);
  219.                                 F_Out(Flag_P) <= F_In(Flag_P);
  220.                         end if;
  221.                 when "1100" =>
  222.                         -- DAA
  223.                         F_Out(Flag_H) <= F_In(Flag_H);
  224.                         F_Out(Flag_C) <= F_In(Flag_C);
  225.                         DAA_Q(7 downto 0) := unsigned(BusA);
  226.                         DAA_Q(8) := '0';
  227.                         if F_In(Flag_N) = '0' then
  228.                                 -- After addition
  229.                                 -- Alow > 9 or H = 1
  230.                                 if DAA_Q(3 downto 0) > 9 or F_In(Flag_H) = '1' then
  231.                                         if (DAA_Q(3 downto 0) > 9) then
  232.                                                 F_Out(Flag_H) <= '1';
  233.                                         else
  234.                                                 F_Out(Flag_H) <= '0';
  235.                                         end if;
  236.                                         DAA_Q := DAA_Q + 6;
  237.                                 end if;
  238.                                 -- new Ahigh > 9 or C = 1
  239.                                 if DAA_Q(8 downto 4) > 9 or F_In(Flag_C) = '1' then
  240.                                         DAA_Q := DAA_Q + 96; -- 0x60
  241.                                 end if;
  242.                         else
  243.                                 -- After subtraction
  244.                                 if DAA_Q(3 downto 0) > 9 or F_In(Flag_H) = '1' then
  245.                                         if DAA_Q(3 downto 0) > 5 then
  246.                                                 F_Out(Flag_H) <= '0';
  247.                                         end if;
  248.                                         DAA_Q(7 downto 0) := DAA_Q(7 downto 0) - 6;
  249.                                 end if;
  250.                                 if unsigned(BusA) > 153 or F_In(Flag_C) = '1' then
  251.                                         DAA_Q := DAA_Q - 352; -- 0x160
  252.                                 end if;
  253.                         end if;
  254.                         F_Out(Flag_X) <= DAA_Q(3);
  255.                         F_Out(Flag_Y) <= DAA_Q(5);
  256.                         F_Out(Flag_C) <= F_In(Flag_C) or DAA_Q(8);
  257.                         Q_t := std_logic_vector(DAA_Q(7 downto 0));
  258.                         if DAA_Q(7 downto 0) = "00000000" then
  259.                                 F_Out(Flag_Z) <= '1';
  260.                         else
  261.                                 F_Out(Flag_Z) <= '0';
  262.                         end if;
  263.                         F_Out(Flag_S) <= DAA_Q(7);
  264.                         F_Out(Flag_P) <= not (DAA_Q(0) xor DAA_Q(1) xor DAA_Q(2) xor DAA_Q(3) xor
  265.                                 DAA_Q(4) xor DAA_Q(5) xor DAA_Q(6) xor DAA_Q(7));
  266.                 when "1101" | "1110" =>
  267.                         -- RLD, RRD
  268.                         Q_t(7 downto 4) := BusA(7 downto 4);
  269.                         if ALU_Op(0) = '1' then
  270.                                 Q_t(3 downto 0) := BusB(7 downto 4);
  271.                         else
  272.                                 Q_t(3 downto 0) := BusB(3 downto 0);
  273.                         end if;
  274.                         F_Out(Flag_H) <= '0';
  275.                         F_Out(Flag_N) <= '0';
  276.                         F_Out(Flag_X) <= Q_t(3);
  277.                         F_Out(Flag_Y) <= Q_t(5);
  278.                         if Q_t(7 downto 0) = "00000000" then
  279.                                 F_Out(Flag_Z) <= '1';
  280.                         else
  281.                                 F_Out(Flag_Z) <= '0';
  282.                         end if;
  283.                         F_Out(Flag_S) <= Q_t(7);
  284.                         F_Out(Flag_P) <= not (Q_t(0) xor Q_t(1) xor Q_t(2) xor Q_t(3) xor
  285.                                 Q_t(4) xor Q_t(5) xor Q_t(6) xor Q_t(7));
  286.                 when "1001" =>
  287.                         -- BIT
  288.                         Q_t(7 downto 0) := BusB and BitMask;
  289.                         F_Out(Flag_S) <= Q_t(7);
  290.                         if Q_t(7 downto 0) = "00000000" then
  291.                                 F_Out(Flag_Z) <= '1';
  292.                                 F_Out(Flag_P) <= '1';
  293.                         else
  294.                                 F_Out(Flag_Z) <= '0';
  295.                                 F_Out(Flag_P) <= '0';
  296.                         end if;
  297.                         F_Out(Flag_H) <= '1';
  298.                         F_Out(Flag_N) <= '0';
  299.                         if IR(2 downto 0) = "110" or XY_State /= "00" then
  300.                                 F_Out(Flag_X) <= WZ(11);
  301.                                 F_Out(Flag_Y) <= WZ(13);
  302.                         else
  303.                                 F_Out(Flag_X) <= BusB(3);
  304.                                 F_Out(Flag_Y) <= BusB(5);
  305.                         end if;
  306.                 when "1010" =>
  307.                         -- SET
  308.                         Q_t(7 downto 0) := BusB or BitMask;
  309.                 when "1011" =>
  310.                         -- RES
  311.                         Q_t(7 downto 0) := BusB and not BitMask;
  312.                 when "1000" =>
  313.                         -- ROT
  314.                         case IR(5 downto 3) is
  315.                         when "000" => -- RLC
  316.                                 Q_t(7 downto 1) := BusA(6 downto 0);
  317.                                 Q_t(0) := BusA(7);
  318.                                 F_Out(Flag_C) <= BusA(7);
  319.                         when "010" => -- RL
  320.                                 Q_t(7 downto 1) := BusA(6 downto 0);
  321.                                 Q_t(0) := F_In(Flag_C);
  322.                                 F_Out(Flag_C) <= BusA(7);
  323.                         when "001" => -- RRC
  324.                                 Q_t(6 downto 0) := BusA(7 downto 1);
  325.                                 Q_t(7) := BusA(0);
  326.                                 F_Out(Flag_C) <= BusA(0);
  327.                         when "011" => -- RR
  328.                                 Q_t(6 downto 0) := BusA(7 downto 1);
  329.                                 Q_t(7) := F_In(Flag_C);
  330.                                 F_Out(Flag_C) <= BusA(0);
  331.                         when "100" => -- SLA
  332.                                 Q_t(7 downto 1) := BusA(6 downto 0);
  333.                                 Q_t(0) := '0';
  334.                                 F_Out(Flag_C) <= BusA(7);
  335.                         when "110" => -- SLL (Undocumented) / SWAP
  336.                                 if Mode = 3 then
  337.                                         Q_t(7 downto 4) := BusA(3 downto 0);
  338.                                         Q_t(3 downto 0) := BusA(7 downto 4);
  339.                                         F_Out(Flag_C) <= '0';
  340.                                 else
  341.                                         Q_t(7 downto 1) := BusA(6 downto 0);
  342.                                         Q_t(0) := '1';
  343.                                         F_Out(Flag_C) <= BusA(7);
  344.                                 end if;
  345.                         when "101" => -- SRA
  346.                                 Q_t(6 downto 0) := BusA(7 downto 1);
  347.                                 Q_t(7) := BusA(7);
  348.                                 F_Out(Flag_C) <= BusA(0);
  349.                         when others => -- SRL
  350.                                 Q_t(6 downto 0) := BusA(7 downto 1);
  351.                                 Q_t(7) := '0';
  352.                                 F_Out(Flag_C) <= BusA(0);
  353.                         end case;
  354.                         F_Out(Flag_H) <= '0';
  355.                         F_Out(Flag_N) <= '0';
  356.                         F_Out(Flag_X) <= Q_t(3);
  357.                         F_Out(Flag_Y) <= Q_t(5);
  358.                         F_Out(Flag_S) <= Q_t(7);
  359.                         if Q_t(7 downto 0) = "00000000" then
  360.                                 F_Out(Flag_Z) <= '1';
  361.                         else
  362.                                 F_Out(Flag_Z) <= '0';
  363.                         end if;
  364.                         F_Out(Flag_P) <= not (Q_t(0) xor Q_t(1) xor Q_t(2) xor Q_t(3) xor
  365.                                 Q_t(4) xor Q_t(5) xor Q_t(6) xor Q_t(7));
  366.                         if ISet = "00" then
  367.                                 F_Out(Flag_P) <= F_In(Flag_P);
  368.                                 F_Out(Flag_S) <= F_In(Flag_S);
  369.                                 F_Out(Flag_Z) <= F_In(Flag_Z);
  370.                         end if;
  371.                 when others =>
  372.                         null;
  373.                 end case;
  374.                 Q <= Q_t;
  375.         end process;
  376. end;
  377.