update T80 ip
[fpga-games] / galaxian / t80_ip / T80_ALU.vhd
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;
Impressum, Datenschutz