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