added CPUID code from rbench and get_cpl to be used by the
[dosdemo] / src / util.h
1 #ifndef UTIL_H_
2 #define UTIL_H_
3
4 #include "inttypes.h"
5
6 #ifdef __GNUC__
7 #define INLINE __inline
8 #define PACKED __attribute__((packed))
9
10 #elif defined(__WATCOMC__)
11 #define INLINE __inline
12 #define PACKED
13
14 #else
15 #define INLINE
16 #define PACKED
17 #endif
18
19 #define BSWAP16(x)      ((((x) >> 8) & 0xff) | (((x) & 0xff) << 8))
20 #define BSWAP32(x)      \
21         ((((x) >> 24) & 0xff) | \
22          (((x) >> 8) & 0xff00) | \
23          (((x) << 8) & 0xff0000) | \
24          ((x) << 24))
25
26 #if defined(__i386__) || defined(__x86_64__) || defined(__386__) || defined(MSDOS)
27 /* fast conversion of double -> 32bit int
28  * for details see:
29  *  - http://chrishecker.com/images/f/fb/Gdmfp.pdf
30  *  - http://stereopsis.com/FPU.html#convert
31  */
32 static INLINE int32_t cround64(double val)
33 {
34         val += 6755399441055744.0;
35         return *(int32_t*)&val;
36 }
37 #else
38 #define cround64(x)     ((int32_t)(x))
39 #endif
40
41 static INLINE float rsqrt(float x)
42 {
43         float xhalf = x * 0.5f;
44         int32_t i = *(int32_t*)&x;
45         i = 0x5f3759df - (i >> 1);
46         x = *(float*)&i;
47         x = x * (1.5f - xhalf * x * x);
48         return x;
49 }
50
51 extern uint32_t perf_start_count, perf_interval_count;
52
53 #ifdef __WATCOMC__
54 void memset16(void *dest, uint16_t val, int count);
55 #pragma aux memset16 = \
56         "cld" \
57         "test ecx, 1" \
58         "jz memset16_dwords" \
59         "rep stosw" \
60         "jmp memset16_done" \
61         "memset16_dwords:" \
62         "shr ecx, 1" \
63         "push ax" \
64         "shl eax, 16" \
65         "pop ax" \
66         "rep stosd" \
67         "memset16_done:" \
68         parm[edi][ax][ecx];
69
70 #ifdef USE_MMX
71 void memcpy64(void *dest, void *src, int count);
72 #pragma aux memcpy64 = \
73         "cploop:" \
74         "movq mm0, [edx]" \
75         "movq [ebx], mm0" \
76         "add edx, 8" \
77         "add ebx, 8" \
78         "dec ecx" \
79         "jnz cploop" \
80         "emms" \
81         parm[ebx][edx][ecx] \
82         modify[8087];
83 #else
84 #define memcpy64(dest, src, count)      memcpy(dest, src, (count) << 3)
85 #endif
86
87 void perf_start(void);
88 #pragma aux perf_start = \
89         "xor eax, eax" \
90         "cpuid" \
91         "rdtsc" \
92         "mov [perf_start_count], eax" \
93         modify[eax ebx ecx edx];
94
95 void perf_end(void);
96 #pragma aux perf_end = \
97         "xor eax, eax" \
98         "cpuid" \
99         "rdtsc" \
100         "sub eax, [perf_start_count]" \
101         "mov [perf_interval_count], eax" \
102         modify [eax ebx ecx edx];
103
104 void debug_break(void);
105 #pragma aux debug_break = "int 3";
106
107 void halt(void);
108 #pragma aux halt = "hlt";
109
110 unsigned int get_cs(void);
111 #pragma aux get_cs = \
112         "xor eax, eax" \
113         "mov ax, cs" \
114         value[eax];
115 #endif
116
117 #ifdef __GNUC__
118 #if defined(__i386__) || defined(__x86_64__)
119 #define memset16(dest, val, count) asm volatile ( \
120         "cld\n\t" \
121         "test $1, %2\n\t" \
122         "jz 0f\n\t" \
123         "rep stosw\n\t" \
124         "jmp 1f\n\t" \
125         "0:\n\t" \
126         "shr $1, %2\n\t" \
127         "push %%ax\n\t" \
128         "shl $16, %%eax\n\t" \
129         "pop %%ax\n\t" \
130         "rep stosl\n\t" \
131         "1:\n\t"\
132         :: "D"(dest), "a"((uint16_t)(val)), "c"(count) \
133         : "memory")
134 #else
135 static void INLINE memset16(void *dest, uint16_t val, int count)
136 {
137         uint16_t *ptr = dest;
138         while(count--) *ptr++ = val;
139 }
140 #endif
141
142 #ifdef USE_MMX
143 #define memcpy64(dest, src, count) asm volatile ( \
144         "0:\n\t" \
145         "movq (%1), %%mm0\n\t" \
146         "movq %%mm0, (%0)\n\t" \
147         "add $8, %1\n\t" \
148         "add $8, %0\n\t" \
149         "dec %2\n\t" \
150         "jnz 0b\n\t" \
151         "emms\n\t" \
152         :: "r"(dest), "r"(src), "r"(count) \
153         : "%mm0")
154 #else
155 #define memcpy64(dest, src, count)      memcpy(dest, src, (count) << 3)
156 #endif
157
158 #define perf_start()  asm volatile ( \
159         "xor %%eax, %%eax\n" \
160         "cpuid\n" \
161         "rdtsc\n" \
162         "mov %%eax, %0\n" \
163         : "=m"(perf_start_count) \
164         :: "%eax", "%ebx", "%ecx", "%edx")
165
166 #define perf_end() asm volatile ( \
167         "xor %%eax, %%eax\n" \
168         "cpuid\n" \
169         "rdtsc\n" \
170         "sub %1, %%eax\n" \
171         "mov %%eax, %0\n" \
172         : "=m"(perf_interval_count) \
173         : "m"(perf_start_count) \
174         : "%eax", "%ebx", "%ecx", "%edx")
175
176 #define debug_break() \
177         asm volatile("int $3")
178
179 #define halt() \
180         asm volatile("hlt")
181
182 static unsigned int INLINE get_cs(void)
183 {
184         unsigned int res;
185         asm volatile (
186                 "xor %%eax, %%eax\n\t"
187                 "mov %%cs, %0\n\t"
188                 : "=a"(res)
189         );
190         return res;
191 }
192 #endif
193
194 #ifdef _MSC_VER
195 static void __inline memset16(void *dest, uint16_t val, int count)
196 {
197         __asm {
198                 cld
199                 mov ax, val
200                 mov edi, dest
201                 mov ecx, count
202                 test ecx, 1
203                 jz memset16_dwords
204                 rep stosw
205                 jmp memset16_done
206                 memset16_dwords:
207                 shr ecx, 1
208                 push ax
209                 shl eax, 16
210                 pop ax
211                 rep stosd
212                 memset16_done:
213         }
214 }
215
216 #define perf_start() \
217         do { \
218                 __asm { \
219                         xor eax, eax \
220                         cpuid \
221                         rdtsc \
222                         mov [perf_start_count], eax \
223                 } \
224         } while(0)
225
226 #define perf_end() \
227         do { \
228                 __asm { \
229                         xor eax, eax \
230                         cpuid \
231                         rdtsc \
232                         sub eax, [perf_start_count] \
233                         mov [perf_interval_count], eax \
234                 } \
235         } while(0)
236
237 #define debug_break() \
238         do { \
239                 __asm { int 3 } \
240         } while(0)
241
242 static unsigned int __inline get_cs(void)
243 {
244         unsigned int res;
245         __asm {
246                 xor eax, eax
247                 mov ax, cs
248                 mov [res], ax
249         }
250         return res;
251 }
252 #endif
253
254 #define get_cpl()       ((int)(get_cs() & 7))
255
256 #endif  /* UTIL_H_ */