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

Subversion Repositories t80

[/] [t80/] [trunk/] [rtl/] [vhdl/] [T80_ALU.vhd] - Blame information for rev 47

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 7 jesus
--
2
-- Z80 compatible microprocessor core
3
--
4 40 jesus
-- Version : 0247
5 7 jesus
--
6 35 jesus
-- Copyright (c) 2001-2002 Daniel Wallner (jesus@opencores.org)
7 7 jesus
--
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 35 jesus
--      http://www.opencores.org/cvsweb.shtml/t80/
42 7 jesus
--
43
-- Limitations :
44
--
45
-- File history :
46
--
47
--      0214 : Fixed mostly flags, only the block instructions now fail the zex regression test
48
--
49 25 jesus
--      0238 : Fixed zero flag for 16 bit SBC and ADC
50
--
51 29 jesus
--      0240 : Added GB operations
52
--
53 35 jesus
--      0242 : Cleanup
54
--
55 40 jesus
--      0247 : Cleanup
56
--
57 7 jesus
 
58
library IEEE;
59
use IEEE.std_logic_1164.all;
60
use IEEE.numeric_std.all;
61
 
62
entity T80_ALU is
63 29 jesus
        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 7 jesus
        port(
75
                Arith16         : in std_logic;
76 25 jesus
                Z16                     : in std_logic;
77 7 jesus
                ALU_Op          : in std_logic_vector(3 downto 0);
78 35 jesus
                IR                      : in std_logic_vector(5 downto 0);
79 7 jesus
                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 35 jesus
                F_Out           : out std_logic_vector(7 downto 0)
85 7 jesus
        );
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 40 jesus
                variable B_i            : unsigned(A'length - 1 downto 0);
97
                variable Res_i          : unsigned(A'length + 1 downto 0);
98 7 jesus
        begin
99
                if Sub = '1' then
100 40 jesus
                        B_i := not unsigned(B);
101 7 jesus
                else
102 40 jesus
                        B_i := unsigned(B);
103 7 jesus
                end if;
104 40 jesus
                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 7 jesus
        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 35 jesus
        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 7 jesus
        OverFlow_v <= Carry_v xor Carry7_v;
135
 
136 35 jesus
        process (Arith16, ALU_OP, F_In, BusA, BusB, IR, Q_v, Carry_v, HalfCarry_v, OverFlow_v, BitMask, ISet, Z16)
137 7 jesus
                variable Q_t : std_logic_vector(7 downto 0);
138
                variable DAA_Q : unsigned(8 downto 0);
139
        begin
140
                Q_t := "--------";
141 35 jesus
                F_Out <= F_In;
142 7 jesus
                DAA_Q := "---------";
143 35 jesus
                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 7 jesus
                        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 35 jesus
                when "1101" | "1110" =>
242
                        -- RLD, RRD
243 7 jesus
                        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 35 jesus
                when "1001" =>
262
                        -- BIT
263
                        Q_t(7 downto 0) := BusB and BitMask;
264
                        F_Out(Flag_S) <= Q_t(7);
265 7 jesus
                        if Q_t(7 downto 0) = "00000000" then
266
                                F_Out(Flag_Z) <= '1';
267 35 jesus
                                F_Out(Flag_P) <= '1';
268 7 jesus
                        else
269
                                F_Out(Flag_Z) <= '0';
270 35 jesus
                                F_Out(Flag_P) <= '0';
271 7 jesus
                        end if;
272 35 jesus
                        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 7 jesus
                        end if;
280 35 jesus
                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 7 jesus
                        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 29 jesus
                        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 7 jesus
                        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 35 jesus
                        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 7 jesus
                Q <= Q_t;
349
        end process;
350
 
351
end;

powered by: WebSVN 2.1.0

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