]>
Commit | Line | Data |
---|---|---|
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 | ||
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( | |
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 | ); |
96 | end T80_ALU; | |
97 | ||
98 | architecture 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 | |
131 | begin | |
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 | 371 | end; |