]> git.zerfleddert.de Git - fpga-games/blame - galaxian/t80_ip/T80_ALU.vhd
clocks...
[fpga-games] / galaxian / t80_ip / T80_ALU.vhd
CommitLineData
be8a9b96
MG
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-- ****
782690d0
MG
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:
be8a9b96 51-- http://www.opencores.org/cvsweb.shtml/t80/
782690d0
MG
52--
53-- Limitations :
54--
55-- File history :
56--
be8a9b96 57-- 0214 : Fixed mostly flags, only the block instructions now fail the zex regression test
782690d0 58--
be8a9b96 59-- 0238 : Fixed zero flag for 16 bit SBC and ADC
782690d0 60--
be8a9b96 61-- 0240 : Added GB operations
782690d0 62--
be8a9b96 63-- 0242 : Cleanup
782690d0 64--
be8a9b96 65-- 0247 : Cleanup
782690d0
MG
66--
67
68library IEEE;
69use IEEE.std_logic_1164.all;
70use IEEE.numeric_std.all;
71
72entity 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(
be8a9b96
MG
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)
782690d0
MG
95 );
96end T80_ALU;
97
98architecture rtl of T80_ALU is
99
be8a9b96
MG
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);
782690d0
MG
109 begin
110 if Sub = '1' then
111 B_i := not unsigned(B);
112 else
be8a9b96 113 B_i := unsigned(B);
782690d0 114 end if;
be8a9b96 115
782690d0
MG
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)
be8a9b96
MG
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);
782690d0 128
be8a9b96 129 signal BitMask : std_logic_vector(7 downto 0);
782690d0
MG
130
131begin
132
133 with IR(5 downto 3) select BitMask <= "00000001" when "000",
be8a9b96
MG
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;
782690d0
MG
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);
be8a9b96
MG
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;
782690d0
MG
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
be8a9b96 200 F_Out(Flag_Z) <= F_In(Flag_Z); -- 16 bit ADC,SBC
782690d0
MG
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;
782690d0 371end;
Impressum, Datenschutz