T80_ALU.vhd 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371
  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. library IEEE;
  68. use IEEE.std_logic_1164.all;
  69. use IEEE.numeric_std.all;
  70. entity T80_ALU is
  71. generic(
  72. Mode : integer := 0;
  73. Flag_C : integer := 0;
  74. Flag_N : integer := 1;
  75. Flag_P : integer := 2;
  76. Flag_X : integer := 3;
  77. Flag_H : integer := 4;
  78. Flag_Y : integer := 5;
  79. Flag_Z : integer := 6;
  80. Flag_S : integer := 7
  81. );
  82. port(
  83. Arith16 : in std_logic;
  84. Z16 : in std_logic;
  85. ALU_Op : in std_logic_vector(3 downto 0);
  86. IR : in std_logic_vector(5 downto 0);
  87. ISet : in std_logic_vector(1 downto 0);
  88. BusA : in std_logic_vector(7 downto 0);
  89. BusB : in std_logic_vector(7 downto 0);
  90. F_In : in std_logic_vector(7 downto 0);
  91. Q : out std_logic_vector(7 downto 0);
  92. F_Out : out std_logic_vector(7 downto 0)
  93. );
  94. end T80_ALU;
  95. architecture rtl of T80_ALU is
  96. procedure AddSub(A : std_logic_vector;
  97. B : std_logic_vector;
  98. Sub : std_logic;
  99. Carry_In : std_logic;
  100. signal Res : out std_logic_vector;
  101. signal Carry : out std_logic) is
  102. variable B_i : unsigned(A'length - 1 downto 0);
  103. variable Res_i : unsigned(A'length + 1 downto 0);
  104. begin
  105. if Sub = '1' then
  106. B_i := not unsigned(B);
  107. else
  108. B_i := unsigned(B);
  109. end if;
  110. Res_i := unsigned("0" & A & Carry_In) + unsigned("0" & B_i & "1");
  111. Carry <= Res_i(A'length + 1);
  112. Res <= std_logic_vector(Res_i(A'length downto 1));
  113. end;
  114. -- AddSub variables (temporary signals)
  115. signal UseCarry : std_logic;
  116. signal Carry7_v : std_logic;
  117. signal Overflow_v : std_logic;
  118. signal HalfCarry_v : std_logic;
  119. signal Carry_v : std_logic;
  120. signal Q_v : std_logic_vector(7 downto 0);
  121. signal BitMask : std_logic_vector(7 downto 0);
  122. begin
  123. with IR(5 downto 3) select BitMask <= "00000001" when "000",
  124. "00000010" when "001",
  125. "00000100" when "010",
  126. "00001000" when "011",
  127. "00010000" when "100",
  128. "00100000" when "101",
  129. "01000000" when "110",
  130. "10000000" when others;
  131. UseCarry <= not ALU_Op(2) and ALU_Op(0);
  132. 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);
  133. AddSub(BusA(6 downto 4), BusB(6 downto 4), ALU_Op(1), HalfCarry_v, Q_v(6 downto 4), Carry7_v);
  134. AddSub(BusA(7 downto 7), BusB(7 downto 7), ALU_Op(1), Carry7_v, Q_v(7 downto 7), Carry_v);
  135. -- bug fix - parity flag is just parity for 8080, also overflow for Z80
  136. process (Carry_v, Carry7_v, Q_v)
  137. begin
  138. if(Mode=2) then
  139. OverFlow_v <= not (Q_v(0) xor Q_v(1) xor Q_v(2) xor Q_v(3) xor
  140. Q_v(4) xor Q_v(5) xor Q_v(6) xor Q_v(7)); else
  141. OverFlow_v <= Carry_v xor Carry7_v;
  142. end if;
  143. end process;
  144. process (Arith16, ALU_OP, F_In, BusA, BusB, IR, Q_v, Carry_v, HalfCarry_v, OverFlow_v, BitMask, ISet, Z16)
  145. variable Q_t : std_logic_vector(7 downto 0);
  146. variable DAA_Q : unsigned(8 downto 0);
  147. begin
  148. Q_t := "--------";
  149. F_Out <= F_In;
  150. DAA_Q := "---------";
  151. case ALU_Op is
  152. when "0000" | "0001" | "0010" | "0011" | "0100" | "0101" | "0110" | "0111" =>
  153. F_Out(Flag_N) <= '0';
  154. F_Out(Flag_C) <= '0';
  155. case ALU_OP(2 downto 0) is
  156. when "000" | "001" => -- ADD, ADC
  157. Q_t := Q_v;
  158. F_Out(Flag_C) <= Carry_v;
  159. F_Out(Flag_H) <= HalfCarry_v;
  160. F_Out(Flag_P) <= OverFlow_v;
  161. when "010" | "011" | "111" => -- SUB, SBC, CP
  162. Q_t := Q_v;
  163. F_Out(Flag_N) <= '1';
  164. F_Out(Flag_C) <= not Carry_v;
  165. F_Out(Flag_H) <= not HalfCarry_v;
  166. F_Out(Flag_P) <= OverFlow_v;
  167. when "100" => -- AND
  168. Q_t(7 downto 0) := BusA and BusB;
  169. F_Out(Flag_H) <= '1';
  170. when "101" => -- XOR
  171. Q_t(7 downto 0) := BusA xor BusB;
  172. F_Out(Flag_H) <= '0';
  173. when others => -- OR "110"
  174. Q_t(7 downto 0) := BusA or BusB;
  175. F_Out(Flag_H) <= '0';
  176. end case;
  177. if ALU_Op(2 downto 0) = "111" then -- CP
  178. F_Out(Flag_X) <= BusB(3);
  179. F_Out(Flag_Y) <= BusB(5);
  180. else
  181. F_Out(Flag_X) <= Q_t(3);
  182. F_Out(Flag_Y) <= Q_t(5);
  183. end if;
  184. if Q_t(7 downto 0) = "00000000" then
  185. F_Out(Flag_Z) <= '1';
  186. if Z16 = '1' then
  187. F_Out(Flag_Z) <= F_In(Flag_Z); -- 16 bit ADC,SBC
  188. end if;
  189. else
  190. F_Out(Flag_Z) <= '0';
  191. end if;
  192. F_Out(Flag_S) <= Q_t(7);
  193. case ALU_Op(2 downto 0) is
  194. when "000" | "001" | "010" | "011" | "111" => -- ADD, ADC, SUB, SBC, CP
  195. when others =>
  196. F_Out(Flag_P) <= not (Q_t(0) xor Q_t(1) xor Q_t(2) xor Q_t(3) xor
  197. Q_t(4) xor Q_t(5) xor Q_t(6) xor Q_t(7));
  198. end case;
  199. if Arith16 = '1' then
  200. F_Out(Flag_S) <= F_In(Flag_S);
  201. F_Out(Flag_Z) <= F_In(Flag_Z);
  202. F_Out(Flag_P) <= F_In(Flag_P);
  203. end if;
  204. when "1100" =>
  205. -- DAA
  206. F_Out(Flag_H) <= F_In(Flag_H);
  207. F_Out(Flag_C) <= F_In(Flag_C);
  208. DAA_Q(7 downto 0) := unsigned(BusA);
  209. DAA_Q(8) := '0';
  210. if F_In(Flag_N) = '0' then
  211. -- After addition
  212. -- Alow > 9 or H = 1
  213. if DAA_Q(3 downto 0) > 9 or F_In(Flag_H) = '1' then
  214. if (DAA_Q(3 downto 0) > 9) then
  215. F_Out(Flag_H) <= '1';
  216. else
  217. F_Out(Flag_H) <= '0';
  218. end if;
  219. DAA_Q := DAA_Q + 6;
  220. end if;
  221. -- new Ahigh > 9 or C = 1
  222. if DAA_Q(8 downto 4) > 9 or F_In(Flag_C) = '1' then
  223. DAA_Q := DAA_Q + 96; -- 0x60
  224. end if;
  225. else
  226. -- After subtraction
  227. if DAA_Q(3 downto 0) > 9 or F_In(Flag_H) = '1' then
  228. if DAA_Q(3 downto 0) > 5 then
  229. F_Out(Flag_H) <= '0';
  230. end if;
  231. DAA_Q(7 downto 0) := DAA_Q(7 downto 0) - 6;
  232. end if;
  233. if unsigned(BusA) > 153 or F_In(Flag_C) = '1' then
  234. DAA_Q := DAA_Q - 352; -- 0x160
  235. end if;
  236. end if;
  237. F_Out(Flag_X) <= DAA_Q(3);
  238. F_Out(Flag_Y) <= DAA_Q(5);
  239. F_Out(Flag_C) <= F_In(Flag_C) or DAA_Q(8);
  240. Q_t := std_logic_vector(DAA_Q(7 downto 0));
  241. if DAA_Q(7 downto 0) = "00000000" then
  242. F_Out(Flag_Z) <= '1';
  243. else
  244. F_Out(Flag_Z) <= '0';
  245. end if;
  246. F_Out(Flag_S) <= DAA_Q(7);
  247. F_Out(Flag_P) <= not (DAA_Q(0) xor DAA_Q(1) xor DAA_Q(2) xor DAA_Q(3) xor
  248. DAA_Q(4) xor DAA_Q(5) xor DAA_Q(6) xor DAA_Q(7));
  249. when "1101" | "1110" =>
  250. -- RLD, RRD
  251. Q_t(7 downto 4) := BusA(7 downto 4);
  252. if ALU_Op(0) = '1' then
  253. Q_t(3 downto 0) := BusB(7 downto 4);
  254. else
  255. Q_t(3 downto 0) := BusB(3 downto 0);
  256. end if;
  257. F_Out(Flag_H) <= '0';
  258. F_Out(Flag_N) <= '0';
  259. F_Out(Flag_X) <= Q_t(3);
  260. F_Out(Flag_Y) <= Q_t(5);
  261. if Q_t(7 downto 0) = "00000000" then
  262. F_Out(Flag_Z) <= '1';
  263. else
  264. F_Out(Flag_Z) <= '0';
  265. end if;
  266. F_Out(Flag_S) <= Q_t(7);
  267. F_Out(Flag_P) <= not (Q_t(0) xor Q_t(1) xor Q_t(2) xor Q_t(3) xor
  268. Q_t(4) xor Q_t(5) xor Q_t(6) xor Q_t(7));
  269. when "1001" =>
  270. -- BIT
  271. Q_t(7 downto 0) := BusB and BitMask;
  272. F_Out(Flag_S) <= Q_t(7);
  273. if Q_t(7 downto 0) = "00000000" then
  274. F_Out(Flag_Z) <= '1';
  275. F_Out(Flag_P) <= '1';
  276. else
  277. F_Out(Flag_Z) <= '0';
  278. F_Out(Flag_P) <= '0';
  279. end if;
  280. F_Out(Flag_H) <= '1';
  281. F_Out(Flag_N) <= '0';
  282. F_Out(Flag_X) <= '0';
  283. F_Out(Flag_Y) <= '0';
  284. if IR(2 downto 0) /= "110" then
  285. F_Out(Flag_X) <= BusB(3);
  286. F_Out(Flag_Y) <= BusB(5);
  287. end if;
  288. when "1010" =>
  289. -- SET
  290. Q_t(7 downto 0) := BusB or BitMask;
  291. when "1011" =>
  292. -- RES
  293. Q_t(7 downto 0) := BusB and not BitMask;
  294. when "1000" =>
  295. -- ROT
  296. case IR(5 downto 3) is
  297. when "000" => -- RLC
  298. Q_t(7 downto 1) := BusA(6 downto 0);
  299. Q_t(0) := BusA(7);
  300. F_Out(Flag_C) <= BusA(7);
  301. when "010" => -- RL
  302. Q_t(7 downto 1) := BusA(6 downto 0);
  303. Q_t(0) := F_In(Flag_C);
  304. F_Out(Flag_C) <= BusA(7);
  305. when "001" => -- RRC
  306. Q_t(6 downto 0) := BusA(7 downto 1);
  307. Q_t(7) := BusA(0);
  308. F_Out(Flag_C) <= BusA(0);
  309. when "011" => -- RR
  310. Q_t(6 downto 0) := BusA(7 downto 1);
  311. Q_t(7) := F_In(Flag_C);
  312. F_Out(Flag_C) <= BusA(0);
  313. when "100" => -- SLA
  314. Q_t(7 downto 1) := BusA(6 downto 0);
  315. Q_t(0) := '0';
  316. F_Out(Flag_C) <= BusA(7);
  317. when "110" => -- SLL (Undocumented) / SWAP
  318. if Mode = 3 then
  319. Q_t(7 downto 4) := BusA(3 downto 0);
  320. Q_t(3 downto 0) := BusA(7 downto 4);
  321. F_Out(Flag_C) <= '0';
  322. else
  323. Q_t(7 downto 1) := BusA(6 downto 0);
  324. Q_t(0) := '1';
  325. F_Out(Flag_C) <= BusA(7);
  326. end if;
  327. when "101" => -- SRA
  328. Q_t(6 downto 0) := BusA(7 downto 1);
  329. Q_t(7) := BusA(7);
  330. F_Out(Flag_C) <= BusA(0);
  331. when others => -- SRL
  332. Q_t(6 downto 0) := BusA(7 downto 1);
  333. Q_t(7) := '0';
  334. F_Out(Flag_C) <= BusA(0);
  335. end case;
  336. F_Out(Flag_H) <= '0';
  337. F_Out(Flag_N) <= '0';
  338. F_Out(Flag_X) <= Q_t(3);
  339. F_Out(Flag_Y) <= Q_t(5);
  340. F_Out(Flag_S) <= Q_t(7);
  341. if Q_t(7 downto 0) = "00000000" then
  342. F_Out(Flag_Z) <= '1';
  343. else
  344. F_Out(Flag_Z) <= '0';
  345. end if;
  346. F_Out(Flag_P) <= not (Q_t(0) xor Q_t(1) xor Q_t(2) xor Q_t(3) xor
  347. Q_t(4) xor Q_t(5) xor Q_t(6) xor Q_t(7));
  348. if ISet = "00" then
  349. F_Out(Flag_P) <= F_In(Flag_P);
  350. F_Out(Flag_S) <= F_In(Flag_S);
  351. F_Out(Flag_Z) <= F_In(Flag_Z);
  352. end if;
  353. when others =>
  354. null;
  355. end case;
  356. Q <= Q_t;
  357. end process;
  358. end;