Fix userland ELF loader for zero sized BSS.
[qemu] / target-m68k / helper.c
1 /*
2  *  m68k op helpers
3  * 
4  *  Copyright (c) 2006 CodeSourcery
5  *  Written by Paul Brook
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20  */
21
22 #include <stdio.h>
23
24 #include "config.h"
25 #include "cpu.h"
26 #include "exec-all.h"
27
28 void cpu_m68k_flush_flags(CPUM68KState *env, int cc_op)
29 {
30     int flags;
31     uint32_t src;
32     uint32_t dest;
33     uint32_t tmp;
34
35 #define HIGHBIT 0x80000000u
36
37 #define SET_NZ(x) do { \
38     if ((x) == 0) \
39         flags |= CCF_Z; \
40     else if ((int32_t)(x) < 0) \
41         flags |= CCF_N; \
42     } while (0)
43
44 #define SET_FLAGS_SUB(type, utype) do { \
45     SET_NZ((type)dest); \
46     tmp = dest + src; \
47     if ((utype) tmp < (utype) src) \
48         flags |= CCF_C; \
49     if ((1u << (sizeof(type) * 8 - 1)) & (tmp ^ dest) & (tmp ^ src)) \
50         flags |= CCF_V; \
51     } while (0)
52
53     flags = 0;
54     src = env->cc_src;
55     dest = env->cc_dest;
56     switch (cc_op) {
57     case CC_OP_FLAGS:
58         flags = dest;
59         break;
60     case CC_OP_LOGIC:
61         SET_NZ(dest);
62         break;
63     case CC_OP_ADD:
64         SET_NZ(dest);
65         if (dest < src)
66             flags |= CCF_C;
67         tmp = dest - src;
68         if (HIGHBIT & (src ^ dest) & ~(tmp ^ src))
69             flags |= CCF_V;
70         break;
71     case CC_OP_SUB:
72         SET_FLAGS_SUB(int32_t, uint32_t);
73         break;
74     case CC_OP_CMPB:
75         SET_FLAGS_SUB(int8_t, uint8_t);
76         break;
77     case CC_OP_CMPW:
78         SET_FLAGS_SUB(int16_t, uint16_t);
79         break;
80     case CC_OP_ADDX:
81         SET_NZ(dest);
82         if (dest <= src)
83             flags |= CCF_C;
84         tmp = dest - src - 1;
85         if (HIGHBIT & (src ^ dest) & ~(tmp ^ src))
86             flags |= CCF_V;
87         break;
88     case CC_OP_SUBX:
89         SET_NZ(dest);
90         tmp = dest + src + 1;
91         if (tmp <= src)
92             flags |= CCF_C;
93         if (HIGHBIT & (tmp ^ dest) & (tmp ^ src))
94             flags |= CCF_V;
95         break;
96     case CC_OP_SHL:
97         if (src >= 32) {
98             SET_NZ(0);
99         } else {
100             tmp = dest << src;
101             SET_NZ(tmp);
102         }
103         if (src && src <= 32 && (dest & (1 << (32 - src))))
104             flags |= CCF_C;
105         break;
106     case CC_OP_SHR:
107         if (src >= 32) {
108             SET_NZ(0);
109         } else {
110             tmp = dest >> src;
111             SET_NZ(tmp);
112         }
113         if (src && src <= 32 && ((dest >> (src - 1)) & 1))
114             flags |= CCF_C;
115         break;
116     case CC_OP_SAR:
117         if (src >= 32) {
118             SET_NZ(-1);
119         } else {
120             tmp = (int32_t)dest >> src;
121             SET_NZ(tmp);
122         }
123         if (src && src <= 32 && (((int32_t)dest >> (src - 1)) & 1))
124             flags |= CCF_C;
125         break;
126     default:
127         cpu_abort(env, "Bad CC_OP %d", cc_op);
128     }
129     env->cc_op = CC_OP_FLAGS;
130     env->cc_dest = flags;
131 }
132
133 float64 helper_sub_cmpf64(CPUM68KState *env, float64 src0, float64 src1)
134 {
135     /* ??? This may incorrectly raise exceptions.  */
136     /* ??? Should flush denormals to zero.  */
137     float64 res;
138     res = float64_sub(src0, src1, &env->fp_status);
139     if (float64_is_nan(res)) {
140         /* +/-inf compares equal against itself, but sub returns nan.  */
141         if (!float64_is_nan(src0)
142             && !float64_is_nan(src1)) {
143             res = 0;
144             if (float64_lt_quiet(src0, res, &env->fp_status))
145                 res = float64_chs(res);
146         }
147     }
148     return res;
149 }