OpenCores
URL https://opencores.org/ocsvn/z80soc/z80soc/trunk

Subversion Repositories z80soc

[/] [z80soc/] [tags/] [z80soc05/] [S3E/] [T80_ALU.vhd] - Blame information for rev 20

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 18 rrred
-- ****
2
-- T80(b) core. In an effort to merge and maintain bug fixes ....
3 11 rrred
--
4 18 rrred
--
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 11 rrred
-- Z80 compatible microprocessor core
13
--
14
-- Version : 0247
15 18 rrred
--
16 11 rrred
-- Copyright (c) 2001-2002 Daniel Wallner (jesus@opencores.org)
17 18 rrred
--
18 11 rrred
-- 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 18 rrred
--      http://www.opencores.org/cvsweb.shtml/t80/
52 11 rrred
--
53
-- Limitations :
54
--
55
-- File history :
56
--
57 18 rrred
--      0214 : Fixed mostly flags, only the block instructions now fail the zex regression test
58 11 rrred
--
59 18 rrred
--      0238 : Fixed zero flag for 16 bit SBC and ADC
60 11 rrred
--
61 18 rrred
--      0240 : Added GB operations
62 11 rrred
--
63 18 rrred
--      0242 : Cleanup
64 11 rrred
--
65 18 rrred
--      0247 : Cleanup
66 11 rrred
--
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 18 rrred
                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 11 rrred
        );
96
end T80_ALU;
97
 
98
architecture rtl of T80_ALU is
99
 
100 18 rrred
        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 11 rrred
        begin
110
                if Sub = '1' then
111
                        B_i := not unsigned(B);
112
                else
113 18 rrred
                        B_i :=     unsigned(B);
114 11 rrred
                end if;
115 18 rrred
 
116 11 rrred
                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 18 rrred
        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 11 rrred
 
129 18 rrred
        signal BitMask                 : std_logic_vector(7 downto 0);
130 11 rrred
 
131
begin
132
 
133
        with IR(5 downto 3) select BitMask <= "00000001" when "000",
134 18 rrred
                                                                                  "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 11 rrred
 
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 18 rrred
        -- 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 11 rrred
        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 18 rrred
                                        F_Out(Flag_Z) <= F_In(Flag_Z);      -- 16 bit ADC,SBC
201 11 rrred
                                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;

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.