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

Subversion Repositories z80soc

[/] [z80soc/] [trunk/] [V0.7/] [S3E/] [vhdl/] [T80_ALU.vhd] - Blame information for rev 42

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

Line No. Rev Author Line
1 34 rrred
-- ****
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;

powered by: WebSVN 2.1.0

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