| 1 | /**************************************************************************** |
| 2 | * |
| 3 | * Realmode X86 Emulator Library |
| 4 | * |
| 5 | * Copyright (C) 1996-1999 SciTech Software, Inc. |
| 6 | * Copyright (C) David Mosberger-Tang |
| 7 | * Copyright (C) 1999 Egbert Eich |
| 8 | * |
| 9 | * ======================================================================== |
| 10 | * |
| 11 | * Permission to use, copy, modify, distribute, and sell this software and |
| 12 | * its documentation for any purpose is hereby granted without fee, |
| 13 | * provided that the above copyright notice appear in all copies and that |
| 14 | * both that copyright notice and this permission notice appear in |
| 15 | * supporting documentation, and that the name of the authors not be used |
| 16 | * in advertising or publicity pertaining to distribution of the software |
| 17 | * without specific, written prior permission. The authors makes no |
| 18 | * representations about the suitability of this software for any purpose. |
| 19 | * It is provided "as is" without express or implied warranty. |
| 20 | * |
| 21 | * THE AUTHORS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, |
| 22 | * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO |
| 23 | * EVENT SHALL THE AUTHORS BE LIABLE FOR ANY SPECIAL, INDIRECT OR |
| 24 | * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF |
| 25 | * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR |
| 26 | * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR |
| 27 | * PERFORMANCE OF THIS SOFTWARE. |
| 28 | * |
| 29 | * ======================================================================== |
| 30 | * |
| 31 | * Language: Watcom C 10.6 or later |
| 32 | * Environment: 32-bit DOS |
| 33 | * Developer: Kendall Bennett |
| 34 | * |
| 35 | * Description: Program to validate the x86 emulator library for |
| 36 | * correctness. We run the emulator primitive operations |
| 37 | * functions against the real x86 CPU, and compare the result |
| 38 | * and flags to ensure correctness. |
| 39 | * |
| 40 | * We use inline assembler to compile and build this program. |
| 41 | * |
| 42 | ****************************************************************************/ |
| 43 | |
| 44 | #include <stdio.h> |
| 45 | #include <stdlib.h> |
| 46 | #include <string.h> |
| 47 | #include <stdarg.h> |
| 48 | #include "x86emu.h" |
| 49 | #include "x86emu/prim_asm.h" |
| 50 | |
| 51 | /*-------------------------- Implementation -------------------------------*/ |
| 52 | |
| 53 | #define true 1 |
| 54 | #define false 0 |
| 55 | |
| 56 | #define ALL_FLAGS (F_CF | F_PF | F_AF | F_ZF | F_SF | F_OF) |
| 57 | |
| 58 | #define VAL_START_BINARY(parm_type,res_type,dmax,smax,dincr,sincr) \ |
| 59 | { \ |
| 60 | parm_type d,s; \ |
| 61 | res_type r,r_asm; \ |
| 62 | ulong flags,inflags; \ |
| 63 | int f,failed = false; \ |
| 64 | char buf1[80],buf2[80]; \ |
| 65 | for (d = 0; d < dmax; d += dincr) { \ |
| 66 | for (s = 0; s < smax; s += sincr) { \ |
| 67 | M.x86.R_EFLG = inflags = flags = def_flags; \ |
| 68 | for (f = 0; f < 2; f++) { |
| 69 | |
| 70 | #define VAL_TEST_BINARY(name) \ |
| 71 | r_asm = name##_asm(&flags,d,s); \ |
| 72 | r = name(d,s); \ |
| 73 | if (r != r_asm || M.x86.R_EFLG != flags) \ |
| 74 | failed = true; \ |
| 75 | if (failed || trace) { |
| 76 | |
| 77 | #define VAL_TEST_BINARY_VOID(name) \ |
| 78 | name##_asm(&flags,d,s); \ |
| 79 | name(d,s); \ |
| 80 | r = r_asm = 0; \ |
| 81 | if (M.x86.R_EFLG != flags) \ |
| 82 | failed = true; \ |
| 83 | if (failed || trace) { |
| 84 | |
| 85 | #define VAL_FAIL_BYTE_BYTE_BINARY(name) \ |
| 86 | if (failed) \ |
| 87 | printk("fail\n"); \ |
| 88 | printk("0x%02X = %-15s(0x%02X,0x%02X), flags = %s -> %s\n", \ |
| 89 | r, #name, d, s, print_flags(buf1,inflags), print_flags(buf2,M.x86.R_EFLG)); \ |
| 90 | printk("0x%02X = %-15s(0x%02X,0x%02X), flags = %s -> %s\n", \ |
| 91 | r_asm, #name"_asm", d, s, print_flags(buf1,inflags), print_flags(buf2,flags)); |
| 92 | |
| 93 | #define VAL_FAIL_WORD_WORD_BINARY(name) \ |
| 94 | if (failed) \ |
| 95 | printk("fail\n"); \ |
| 96 | printk("0x%04X = %-15s(0x%04X,0x%04X), flags = %s -> %s\n", \ |
| 97 | r, #name, d, s, print_flags(buf1,inflags), print_flags(buf2,M.x86.R_EFLG)); \ |
| 98 | printk("0x%04X = %-15s(0x%04X,0x%04X), flags = %s -> %s\n", \ |
| 99 | r_asm, #name"_asm", d, s, print_flags(buf1,inflags), print_flags(buf2,flags)); |
| 100 | |
| 101 | #define VAL_FAIL_LONG_LONG_BINARY(name) \ |
| 102 | if (failed) \ |
| 103 | printk("fail\n"); \ |
| 104 | printk("0x%08X = %-15s(0x%08X,0x%08X), flags = %s -> %s\n", \ |
| 105 | r, #name, d, s, print_flags(buf1,inflags), print_flags(buf2,M.x86.R_EFLG)); \ |
| 106 | printk("0x%08X = %-15s(0x%08X,0x%08X), flags = %s -> %s\n", \ |
| 107 | r_asm, #name"_asm", d, s, print_flags(buf1,inflags), print_flags(buf2,flags)); |
| 108 | |
| 109 | #define VAL_END_BINARY() \ |
| 110 | } \ |
| 111 | M.x86.R_EFLG = inflags = flags = def_flags | (ALL_FLAGS & ~F_OF); \ |
| 112 | if (failed) \ |
| 113 | break; \ |
| 114 | } \ |
| 115 | if (failed) \ |
| 116 | break; \ |
| 117 | } \ |
| 118 | if (failed) \ |
| 119 | break; \ |
| 120 | } \ |
| 121 | if (!failed) \ |
| 122 | printk("passed\n"); \ |
| 123 | } |
| 124 | |
| 125 | #define VAL_BYTE_BYTE_BINARY(name) \ |
| 126 | printk("Validating %s ... ", #name); \ |
| 127 | VAL_START_BINARY(u8,u8,0xFF,0xFF,1,1) \ |
| 128 | VAL_TEST_BINARY(name) \ |
| 129 | VAL_FAIL_BYTE_BYTE_BINARY(name) \ |
| 130 | VAL_END_BINARY() |
| 131 | |
| 132 | #define VAL_WORD_WORD_BINARY(name) \ |
| 133 | printk("Validating %s ... ", #name); \ |
| 134 | VAL_START_BINARY(u16,u16,0xFF00,0xFF00,0x100,0x100) \ |
| 135 | VAL_TEST_BINARY(name) \ |
| 136 | VAL_FAIL_WORD_WORD_BINARY(name) \ |
| 137 | VAL_END_BINARY() |
| 138 | |
| 139 | #define VAL_LONG_LONG_BINARY(name) \ |
| 140 | printk("Validating %s ... ", #name); \ |
| 141 | VAL_START_BINARY(u32,u32,0xFF000000,0xFF000000,0x1000000,0x1000000) \ |
| 142 | VAL_TEST_BINARY(name) \ |
| 143 | VAL_FAIL_LONG_LONG_BINARY(name) \ |
| 144 | VAL_END_BINARY() |
| 145 | |
| 146 | #define VAL_VOID_BYTE_BINARY(name) \ |
| 147 | printk("Validating %s ... ", #name); \ |
| 148 | VAL_START_BINARY(u8,u8,0xFF,0xFF,1,1) \ |
| 149 | VAL_TEST_BINARY_VOID(name) \ |
| 150 | VAL_FAIL_BYTE_BYTE_BINARY(name) \ |
| 151 | VAL_END_BINARY() |
| 152 | |
| 153 | #define VAL_VOID_WORD_BINARY(name) \ |
| 154 | printk("Validating %s ... ", #name); \ |
| 155 | VAL_START_BINARY(u16,u16,0xFF00,0xFF00,0x100,0x100) \ |
| 156 | VAL_TEST_BINARY_VOID(name) \ |
| 157 | VAL_FAIL_WORD_WORD_BINARY(name) \ |
| 158 | VAL_END_BINARY() |
| 159 | |
| 160 | #define VAL_VOID_LONG_BINARY(name) \ |
| 161 | printk("Validating %s ... ", #name); \ |
| 162 | VAL_START_BINARY(u32,u32,0xFF000000,0xFF000000,0x1000000,0x1000000) \ |
| 163 | VAL_TEST_BINARY_VOID(name) \ |
| 164 | VAL_FAIL_LONG_LONG_BINARY(name) \ |
| 165 | VAL_END_BINARY() |
| 166 | |
| 167 | #define VAL_BYTE_ROTATE(name) \ |
| 168 | printk("Validating %s ... ", #name); \ |
| 169 | VAL_START_BINARY(u8,u8,0xFF,8,1,1) \ |
| 170 | VAL_TEST_BINARY(name) \ |
| 171 | VAL_FAIL_BYTE_BYTE_BINARY(name) \ |
| 172 | VAL_END_BINARY() |
| 173 | |
| 174 | #define VAL_WORD_ROTATE(name) \ |
| 175 | printk("Validating %s ... ", #name); \ |
| 176 | VAL_START_BINARY(u16,u16,0xFF00,16,0x100,1) \ |
| 177 | VAL_TEST_BINARY(name) \ |
| 178 | VAL_FAIL_WORD_WORD_BINARY(name) \ |
| 179 | VAL_END_BINARY() |
| 180 | |
| 181 | #define VAL_LONG_ROTATE(name) \ |
| 182 | printk("Validating %s ... ", #name); \ |
| 183 | VAL_START_BINARY(u32,u32,0xFF000000,32,0x1000000,1) \ |
| 184 | VAL_TEST_BINARY(name) \ |
| 185 | VAL_FAIL_LONG_LONG_BINARY(name) \ |
| 186 | VAL_END_BINARY() |
| 187 | |
| 188 | #define VAL_START_TERNARY(parm_type,res_type,dmax,smax,dincr,sincr,maxshift)\ |
| 189 | { \ |
| 190 | parm_type d,s; \ |
| 191 | res_type r,r_asm; \ |
| 192 | u8 shift; \ |
| 193 | u32 flags,inflags; \ |
| 194 | int f,failed = false; \ |
| 195 | char buf1[80],buf2[80]; \ |
| 196 | for (d = 0; d < dmax; d += dincr) { \ |
| 197 | for (s = 0; s < smax; s += sincr) { \ |
| 198 | for (shift = 0; shift < maxshift; shift += 1) { \ |
| 199 | M.x86.R_EFLG = inflags = flags = def_flags; \ |
| 200 | for (f = 0; f < 2; f++) { |
| 201 | |
| 202 | #define VAL_TEST_TERNARY(name) \ |
| 203 | r_asm = name##_asm(&flags,d,s,shift); \ |
| 204 | r = name(d,s,shift); \ |
| 205 | if (r != r_asm || M.x86.R_EFLG != flags) \ |
| 206 | failed = true; \ |
| 207 | if (failed || trace) { |
| 208 | |
| 209 | #define VAL_FAIL_WORD_WORD_TERNARY(name) \ |
| 210 | if (failed) \ |
| 211 | printk("fail\n"); \ |
| 212 | printk("0x%04X = %-15s(0x%04X,0x%04X,%d), flags = %s -> %s\n", \ |
| 213 | r, #name, d, s, shift, print_flags(buf1,inflags), print_flags(buf2,M.x86.R_EFLG)); \ |
| 214 | printk("0x%04X = %-15s(0x%04X,0x%04X,%d), flags = %s -> %s\n", \ |
| 215 | r_asm, #name"_asm", d, s, shift, print_flags(buf1,inflags), print_flags(buf2,flags)); |
| 216 | |
| 217 | #define VAL_FAIL_LONG_LONG_TERNARY(name) \ |
| 218 | if (failed) \ |
| 219 | printk("fail\n"); \ |
| 220 | printk("0x%08X = %-15s(0x%08X,0x%08X,%d), flags = %s -> %s\n", \ |
| 221 | r, #name, d, s, shift, print_flags(buf1,inflags), print_flags(buf2,M.x86.R_EFLG)); \ |
| 222 | printk("0x%08X = %-15s(0x%08X,0x%08X,%d), flags = %s -> %s\n", \ |
| 223 | r_asm, #name"_asm", d, s, shift, print_flags(buf1,inflags), print_flags(buf2,flags)); |
| 224 | |
| 225 | #define VAL_END_TERNARY() \ |
| 226 | } \ |
| 227 | M.x86.R_EFLG = inflags = flags = def_flags | (ALL_FLAGS & ~F_OF); \ |
| 228 | if (failed) \ |
| 229 | break; \ |
| 230 | } \ |
| 231 | if (failed) \ |
| 232 | break; \ |
| 233 | } \ |
| 234 | if (failed) \ |
| 235 | break; \ |
| 236 | } \ |
| 237 | if (failed) \ |
| 238 | break; \ |
| 239 | } \ |
| 240 | if (!failed) \ |
| 241 | printk("passed\n"); \ |
| 242 | } |
| 243 | |
| 244 | #define VAL_WORD_ROTATE_DBL(name) \ |
| 245 | printk("Validating %s ... ", #name); \ |
| 246 | VAL_START_TERNARY(u16,u16,0xFF00,0xFF00,0x100,0x100,16) \ |
| 247 | VAL_TEST_TERNARY(name) \ |
| 248 | VAL_FAIL_WORD_WORD_TERNARY(name) \ |
| 249 | VAL_END_TERNARY() |
| 250 | |
| 251 | #define VAL_LONG_ROTATE_DBL(name) \ |
| 252 | printk("Validating %s ... ", #name); \ |
| 253 | VAL_START_TERNARY(u32,u32,0xFF000000,0xFF000000,0x1000000,0x1000000,32) \ |
| 254 | VAL_TEST_TERNARY(name) \ |
| 255 | VAL_FAIL_LONG_LONG_TERNARY(name) \ |
| 256 | VAL_END_TERNARY() |
| 257 | |
| 258 | #define VAL_START_UNARY(parm_type,max,incr) \ |
| 259 | { \ |
| 260 | parm_type d,r,r_asm; \ |
| 261 | u32 flags,inflags; \ |
| 262 | int f,failed = false; \ |
| 263 | char buf1[80],buf2[80]; \ |
| 264 | for (d = 0; d < max; d += incr) { \ |
| 265 | M.x86.R_EFLG = inflags = flags = def_flags; \ |
| 266 | for (f = 0; f < 2; f++) { |
| 267 | |
| 268 | #define VAL_TEST_UNARY(name) \ |
| 269 | r_asm = name##_asm(&flags,d); \ |
| 270 | r = name(d); \ |
| 271 | if (r != r_asm || M.x86.R_EFLG != flags) { \ |
| 272 | failed = true; |
| 273 | |
| 274 | #define VAL_FAIL_BYTE_UNARY(name) \ |
| 275 | printk("fail\n"); \ |
| 276 | printk("0x%02X = %-15s(0x%02X), flags = %s -> %s\n", \ |
| 277 | r, #name, d, print_flags(buf1,inflags), print_flags(buf2,M.x86.R_EFLG)); \ |
| 278 | printk("0x%02X = %-15s(0x%02X), flags = %s -> %s\n", \ |
| 279 | r_asm, #name"_asm", d, print_flags(buf1,inflags), print_flags(buf2,flags)); |
| 280 | |
| 281 | #define VAL_FAIL_WORD_UNARY(name) \ |
| 282 | printk("fail\n"); \ |
| 283 | printk("0x%04X = %-15s(0x%04X), flags = %s -> %s\n", \ |
| 284 | r, #name, d, print_flags(buf1,inflags), print_flags(buf2,M.x86.R_EFLG)); \ |
| 285 | printk("0x%04X = %-15s(0x%04X), flags = %s -> %s\n", \ |
| 286 | r_asm, #name"_asm", d, print_flags(buf1,inflags), print_flags(buf2,flags)); |
| 287 | |
| 288 | #define VAL_FAIL_LONG_UNARY(name) \ |
| 289 | printk("fail\n"); \ |
| 290 | printk("0x%08X = %-15s(0x%08X), flags = %s -> %s\n", \ |
| 291 | r, #name, d, print_flags(buf1,inflags), print_flags(buf2,M.x86.R_EFLG)); \ |
| 292 | printk("0x%08X = %-15s(0x%08X), flags = %s -> %s\n", \ |
| 293 | r_asm, #name"_asm", d, print_flags(buf1,inflags), print_flags(buf2,flags)); |
| 294 | |
| 295 | #define VAL_END_UNARY() \ |
| 296 | } \ |
| 297 | M.x86.R_EFLG = inflags = flags = def_flags | ALL_FLAGS; \ |
| 298 | if (failed) \ |
| 299 | break; \ |
| 300 | } \ |
| 301 | if (failed) \ |
| 302 | break; \ |
| 303 | } \ |
| 304 | if (!failed) \ |
| 305 | printk("passed\n"); \ |
| 306 | } |
| 307 | |
| 308 | #define VAL_BYTE_UNARY(name) \ |
| 309 | printk("Validating %s ... ", #name); \ |
| 310 | VAL_START_UNARY(u8,0xFF,0x1) \ |
| 311 | VAL_TEST_UNARY(name) \ |
| 312 | VAL_FAIL_BYTE_UNARY(name) \ |
| 313 | VAL_END_UNARY() |
| 314 | |
| 315 | #define VAL_WORD_UNARY(name) \ |
| 316 | printk("Validating %s ... ", #name); \ |
| 317 | VAL_START_UNARY(u16,0xFF00,0x100) \ |
| 318 | VAL_TEST_UNARY(name) \ |
| 319 | VAL_FAIL_WORD_UNARY(name) \ |
| 320 | VAL_END_UNARY() |
| 321 | |
| 322 | #define VAL_WORD_BYTE_UNARY(name) \ |
| 323 | printk("Validating %s ... ", #name); \ |
| 324 | VAL_START_UNARY(u16,0xFF,0x1) \ |
| 325 | VAL_TEST_UNARY(name) \ |
| 326 | VAL_FAIL_WORD_UNARY(name) \ |
| 327 | VAL_END_UNARY() |
| 328 | |
| 329 | #define VAL_LONG_UNARY(name) \ |
| 330 | printk("Validating %s ... ", #name); \ |
| 331 | VAL_START_UNARY(u32,0xFF000000,0x1000000) \ |
| 332 | VAL_TEST_UNARY(name) \ |
| 333 | VAL_FAIL_LONG_UNARY(name) \ |
| 334 | VAL_END_UNARY() |
| 335 | |
| 336 | #define VAL_BYTE_MUL(name) \ |
| 337 | printk("Validating %s ... ", #name); \ |
| 338 | { \ |
| 339 | u8 d,s; \ |
| 340 | u16 r,r_asm; \ |
| 341 | u32 flags,inflags; \ |
| 342 | int f,failed = false; \ |
| 343 | char buf1[80],buf2[80]; \ |
| 344 | for (d = 0; d < 0xFF; d += 1) { \ |
| 345 | for (s = 0; s < 0xFF; s += 1) { \ |
| 346 | M.x86.R_EFLG = inflags = flags = def_flags; \ |
| 347 | for (f = 0; f < 2; f++) { \ |
| 348 | name##_asm(&flags,&r_asm,d,s); \ |
| 349 | M.x86.R_AL = d; \ |
| 350 | name(s); \ |
| 351 | r = M.x86.R_AX; \ |
| 352 | if (r != r_asm || M.x86.R_EFLG != flags) \ |
| 353 | failed = true; \ |
| 354 | if (failed || trace) { \ |
| 355 | if (failed) \ |
| 356 | printk("fail\n"); \ |
| 357 | printk("0x%04X = %-15s(0x%02X,0x%02X), flags = %s -> %s\n", \ |
| 358 | r, #name, d, s, print_flags(buf1,inflags), print_flags(buf2,M.x86.R_EFLG)); \ |
| 359 | printk("0x%04X = %-15s(0x%02X,0x%02X), flags = %s -> %s\n", \ |
| 360 | r_asm, #name"_asm", d, s, print_flags(buf1,inflags), print_flags(buf2,flags)); \ |
| 361 | } \ |
| 362 | M.x86.R_EFLG = inflags = flags = def_flags | (ALL_FLAGS & ~F_OF); \ |
| 363 | if (failed) \ |
| 364 | break; \ |
| 365 | } \ |
| 366 | if (failed) \ |
| 367 | break; \ |
| 368 | } \ |
| 369 | if (failed) \ |
| 370 | break; \ |
| 371 | } \ |
| 372 | if (!failed) \ |
| 373 | printk("passed\n"); \ |
| 374 | } |
| 375 | |
| 376 | #define VAL_WORD_MUL(name) \ |
| 377 | printk("Validating %s ... ", #name); \ |
| 378 | { \ |
| 379 | u16 d,s; \ |
| 380 | u16 r_lo,r_asm_lo; \ |
| 381 | u16 r_hi,r_asm_hi; \ |
| 382 | u32 flags,inflags; \ |
| 383 | int f,failed = false; \ |
| 384 | char buf1[80],buf2[80]; \ |
| 385 | for (d = 0; d < 0xFF00; d += 0x100) { \ |
| 386 | for (s = 0; s < 0xFF00; s += 0x100) { \ |
| 387 | M.x86.R_EFLG = inflags = flags = def_flags; \ |
| 388 | for (f = 0; f < 2; f++) { \ |
| 389 | name##_asm(&flags,&r_asm_lo,&r_asm_hi,d,s); \ |
| 390 | M.x86.R_AX = d; \ |
| 391 | name(s); \ |
| 392 | r_lo = M.x86.R_AX; \ |
| 393 | r_hi = M.x86.R_DX; \ |
| 394 | if (r_lo != r_asm_lo || r_hi != r_asm_hi || M.x86.R_EFLG != flags)\ |
| 395 | failed = true; \ |
| 396 | if (failed || trace) { \ |
| 397 | if (failed) \ |
| 398 | printk("fail\n"); \ |
| 399 | printk("0x%04X:0x%04X = %-15s(0x%04X,0x%04X), flags = %s -> %s\n", \ |
| 400 | r_hi,r_lo, #name, d, s, print_flags(buf1,inflags), print_flags(buf2,M.x86.R_EFLG)); \ |
| 401 | printk("0x%04X:0x%04X = %-15s(0x%04X,0x%04X), flags = %s -> %s\n", \ |
| 402 | r_asm_hi,r_asm_lo, #name"_asm", d, s, print_flags(buf1,inflags), print_flags(buf2,flags)); \ |
| 403 | } \ |
| 404 | M.x86.R_EFLG = inflags = flags = def_flags | (ALL_FLAGS & ~F_OF); \ |
| 405 | if (failed) \ |
| 406 | break; \ |
| 407 | } \ |
| 408 | if (failed) \ |
| 409 | break; \ |
| 410 | } \ |
| 411 | if (failed) \ |
| 412 | break; \ |
| 413 | } \ |
| 414 | if (!failed) \ |
| 415 | printk("passed\n"); \ |
| 416 | } |
| 417 | |
| 418 | #define VAL_LONG_MUL(name) \ |
| 419 | printk("Validating %s ... ", #name); \ |
| 420 | { \ |
| 421 | u32 d,s; \ |
| 422 | u32 r_lo,r_asm_lo; \ |
| 423 | u32 r_hi,r_asm_hi; \ |
| 424 | u32 flags,inflags; \ |
| 425 | int f,failed = false; \ |
| 426 | char buf1[80],buf2[80]; \ |
| 427 | for (d = 0; d < 0xFF000000; d += 0x1000000) { \ |
| 428 | for (s = 0; s < 0xFF000000; s += 0x1000000) { \ |
| 429 | M.x86.R_EFLG = inflags = flags = def_flags; \ |
| 430 | for (f = 0; f < 2; f++) { \ |
| 431 | name##_asm(&flags,&r_asm_lo,&r_asm_hi,d,s); \ |
| 432 | M.x86.R_EAX = d; \ |
| 433 | name(s); \ |
| 434 | r_lo = M.x86.R_EAX; \ |
| 435 | r_hi = M.x86.R_EDX; \ |
| 436 | if (r_lo != r_asm_lo || r_hi != r_asm_hi || M.x86.R_EFLG != flags)\ |
| 437 | failed = true; \ |
| 438 | if (failed || trace) { \ |
| 439 | if (failed) \ |
| 440 | printk("fail\n"); \ |
| 441 | printk("0x%08X:0x%08X = %-15s(0x%08X,0x%08X), flags = %s -> %s\n", \ |
| 442 | r_hi,r_lo, #name, d, s, print_flags(buf1,inflags), print_flags(buf2,M.x86.R_EFLG)); \ |
| 443 | printk("0x%08X:0x%08X = %-15s(0x%08X,0x%08X), flags = %s -> %s\n", \ |
| 444 | r_asm_hi,r_asm_lo, #name"_asm", d, s, print_flags(buf1,inflags), print_flags(buf2,flags)); \ |
| 445 | } \ |
| 446 | M.x86.R_EFLG = inflags = flags = def_flags | (ALL_FLAGS & ~F_OF); \ |
| 447 | if (failed) \ |
| 448 | break; \ |
| 449 | } \ |
| 450 | if (failed) \ |
| 451 | break; \ |
| 452 | } \ |
| 453 | if (failed) \ |
| 454 | break; \ |
| 455 | } \ |
| 456 | if (!failed) \ |
| 457 | printk("passed\n"); \ |
| 458 | } |
| 459 | |
| 460 | #define VAL_BYTE_DIV(name) \ |
| 461 | printk("Validating %s ... ", #name); \ |
| 462 | { \ |
| 463 | u16 d,s; \ |
| 464 | u8 r_quot,r_rem,r_asm_quot,r_asm_rem; \ |
| 465 | u32 flags,inflags; \ |
| 466 | int f,failed = false; \ |
| 467 | char buf1[80],buf2[80]; \ |
| 468 | for (d = 0; d < 0xFF00; d += 0x100) { \ |
| 469 | for (s = 1; s < 0xFF; s += 1) { \ |
| 470 | M.x86.R_EFLG = inflags = flags = def_flags; \ |
| 471 | for (f = 0; f < 2; f++) { \ |
| 472 | M.x86.intr = 0; \ |
| 473 | M.x86.R_AX = d; \ |
| 474 | name(s); \ |
| 475 | r_quot = M.x86.R_AL; \ |
| 476 | r_rem = M.x86.R_AH; \ |
| 477 | if (M.x86.intr & INTR_SYNCH) \ |
| 478 | continue; \ |
| 479 | name##_asm(&flags,&r_asm_quot,&r_asm_rem,d,s); \ |
| 480 | if (r_quot != r_asm_quot || r_rem != r_asm_rem || M.x86.R_EFLG != flags) \ |
| 481 | failed = true; \ |
| 482 | if (failed || trace) { \ |
| 483 | if (failed) \ |
| 484 | printk("fail\n"); \ |
| 485 | printk("0x%02X:0x%02X = %-15s(0x%04X,0x%02X), flags = %s -> %s\n", \ |
| 486 | r_quot, r_rem, #name, d, s, print_flags(buf1,inflags), print_flags(buf2,M.x86.R_EFLG)); \ |
| 487 | printk("0x%02X:0x%02X = %-15s(0x%04X,0x%02X), flags = %s -> %s\n", \ |
| 488 | r_asm_quot, r_asm_rem, #name"_asm", d, s, print_flags(buf1,inflags), print_flags(buf2,flags)); \ |
| 489 | } \ |
| 490 | M.x86.R_EFLG = inflags = flags = def_flags | (ALL_FLAGS & ~F_OF); \ |
| 491 | if (failed) \ |
| 492 | break; \ |
| 493 | } \ |
| 494 | if (failed) \ |
| 495 | break; \ |
| 496 | } \ |
| 497 | if (failed) \ |
| 498 | break; \ |
| 499 | } \ |
| 500 | if (!failed) \ |
| 501 | printk("passed\n"); \ |
| 502 | } |
| 503 | |
| 504 | #define VAL_WORD_DIV(name) \ |
| 505 | printk("Validating %s ... ", #name); \ |
| 506 | { \ |
| 507 | u32 d,s; \ |
| 508 | u16 r_quot,r_rem,r_asm_quot,r_asm_rem; \ |
| 509 | u32 flags,inflags; \ |
| 510 | int f,failed = false; \ |
| 511 | char buf1[80],buf2[80]; \ |
| 512 | for (d = 0; d < 0xFF000000; d += 0x1000000) { \ |
| 513 | for (s = 0x100; s < 0xFF00; s += 0x100) { \ |
| 514 | M.x86.R_EFLG = inflags = flags = def_flags; \ |
| 515 | for (f = 0; f < 2; f++) { \ |
| 516 | M.x86.intr = 0; \ |
| 517 | M.x86.R_AX = d & 0xFFFF; \ |
| 518 | M.x86.R_DX = d >> 16; \ |
| 519 | name(s); \ |
| 520 | r_quot = M.x86.R_AX; \ |
| 521 | r_rem = M.x86.R_DX; \ |
| 522 | if (M.x86.intr & INTR_SYNCH) \ |
| 523 | continue; \ |
| 524 | name##_asm(&flags,&r_asm_quot,&r_asm_rem,d & 0xFFFF,d >> 16,s);\ |
| 525 | if (r_quot != r_asm_quot || r_rem != r_asm_rem || M.x86.R_EFLG != flags) \ |
| 526 | failed = true; \ |
| 527 | if (failed || trace) { \ |
| 528 | if (failed) \ |
| 529 | printk("fail\n"); \ |
| 530 | printk("0x%04X:0x%04X = %-15s(0x%08X,0x%04X), flags = %s -> %s\n", \ |
| 531 | r_quot, r_rem, #name, d, s, print_flags(buf1,inflags), print_flags(buf2,M.x86.R_EFLG)); \ |
| 532 | printk("0x%04X:0x%04X = %-15s(0x%08X,0x%04X), flags = %s -> %s\n", \ |
| 533 | r_asm_quot, r_asm_rem, #name"_asm", d, s, print_flags(buf1,inflags), print_flags(buf2,flags)); \ |
| 534 | } \ |
| 535 | M.x86.R_EFLG = inflags = flags = def_flags | (ALL_FLAGS & ~F_OF); \ |
| 536 | if (failed) \ |
| 537 | break; \ |
| 538 | } \ |
| 539 | if (failed) \ |
| 540 | break; \ |
| 541 | } \ |
| 542 | if (failed) \ |
| 543 | break; \ |
| 544 | } \ |
| 545 | if (!failed) \ |
| 546 | printk("passed\n"); \ |
| 547 | } |
| 548 | |
| 549 | #define VAL_LONG_DIV(name) \ |
| 550 | printk("Validating %s ... ", #name); \ |
| 551 | { \ |
| 552 | u32 d,s; \ |
| 553 | u32 r_quot,r_rem,r_asm_quot,r_asm_rem; \ |
| 554 | u32 flags,inflags; \ |
| 555 | int f,failed = false; \ |
| 556 | char buf1[80],buf2[80]; \ |
| 557 | for (d = 0; d < 0xFF000000; d += 0x1000000) { \ |
| 558 | for (s = 0x100; s < 0xFF00; s += 0x100) { \ |
| 559 | M.x86.R_EFLG = inflags = flags = def_flags; \ |
| 560 | for (f = 0; f < 2; f++) { \ |
| 561 | M.x86.intr = 0; \ |
| 562 | M.x86.R_EAX = d; \ |
| 563 | M.x86.R_EDX = 0; \ |
| 564 | name(s); \ |
| 565 | r_quot = M.x86.R_EAX; \ |
| 566 | r_rem = M.x86.R_EDX; \ |
| 567 | if (M.x86.intr & INTR_SYNCH) \ |
| 568 | continue; \ |
| 569 | name##_asm(&flags,&r_asm_quot,&r_asm_rem,d,0,s); \ |
| 570 | if (r_quot != r_asm_quot || r_rem != r_asm_rem || M.x86.R_EFLG != flags) \ |
| 571 | failed = true; \ |
| 572 | if (failed || trace) { \ |
| 573 | if (failed) \ |
| 574 | printk("fail\n"); \ |
| 575 | printk("0x%08X:0x%08X = %-15s(0x%08X:0x%08X,0x%08X), flags = %s -> %s\n", \ |
| 576 | r_quot, r_rem, #name, 0, d, s, print_flags(buf1,inflags), print_flags(buf2,M.x86.R_EFLG)); \ |
| 577 | printk("0x%08X:0x%08X = %-15s(0x%08X:0x%08X,0x%08X), flags = %s -> %s\n", \ |
| 578 | r_asm_quot, r_asm_rem, #name"_asm", 0, d, s, print_flags(buf1,inflags), print_flags(buf2,flags)); \ |
| 579 | } \ |
| 580 | M.x86.R_EFLG = inflags = flags = def_flags | (ALL_FLAGS & ~F_OF); \ |
| 581 | if (failed) \ |
| 582 | break; \ |
| 583 | } \ |
| 584 | if (failed) \ |
| 585 | break; \ |
| 586 | } \ |
| 587 | if (failed) \ |
| 588 | break; \ |
| 589 | } \ |
| 590 | if (!failed) \ |
| 591 | printk("passed\n"); \ |
| 592 | } |
| 593 | |
| 594 | void |
| 595 | printk(const char *fmt, ...) |
| 596 | { |
| 597 | va_list argptr; |
| 598 | |
| 599 | va_start(argptr, fmt); |
| 600 | vfprintf(stdout, fmt, argptr); |
| 601 | fflush(stdout); |
| 602 | va_end(argptr); |
| 603 | } |
| 604 | |
| 605 | char * |
| 606 | print_flags(char *buf, ulong flags) |
| 607 | { |
| 608 | char *separator = ""; |
| 609 | |
| 610 | buf[0] = 0; |
| 611 | if (flags & F_CF) { |
| 612 | strcat(buf, separator); |
| 613 | strcat(buf, "CF"); |
| 614 | separator = ","; |
| 615 | } |
| 616 | if (flags & F_PF) { |
| 617 | strcat(buf, separator); |
| 618 | strcat(buf, "PF"); |
| 619 | separator = ","; |
| 620 | } |
| 621 | if (flags & F_AF) { |
| 622 | strcat(buf, separator); |
| 623 | strcat(buf, "AF"); |
| 624 | separator = ","; |
| 625 | } |
| 626 | if (flags & F_ZF) { |
| 627 | strcat(buf, separator); |
| 628 | strcat(buf, "ZF"); |
| 629 | separator = ","; |
| 630 | } |
| 631 | if (flags & F_SF) { |
| 632 | strcat(buf, separator); |
| 633 | strcat(buf, "SF"); |
| 634 | separator = ","; |
| 635 | } |
| 636 | if (flags & F_OF) { |
| 637 | strcat(buf, separator); |
| 638 | strcat(buf, "OF"); |
| 639 | separator = ","; |
| 640 | } |
| 641 | if (separator[0] == 0) |
| 642 | strcpy(buf, "None"); |
| 643 | return buf; |
| 644 | } |
| 645 | |
| 646 | int |
| 647 | main(int argc) |
| 648 | { |
| 649 | ulong def_flags; |
| 650 | int trace = false; |
| 651 | |
| 652 | if (argc > 1) |
| 653 | trace = true; |
| 654 | memset(&M, 0, sizeof(M)); |
| 655 | def_flags = get_flags_asm() & ~ALL_FLAGS; |
| 656 | |
| 657 | VAL_WORD_UNARY(aaa_word); |
| 658 | VAL_WORD_UNARY(aas_word); |
| 659 | |
| 660 | VAL_WORD_UNARY(aad_word); |
| 661 | VAL_WORD_UNARY(aam_word); |
| 662 | |
| 663 | VAL_BYTE_BYTE_BINARY(adc_byte); |
| 664 | VAL_WORD_WORD_BINARY(adc_word); |
| 665 | VAL_LONG_LONG_BINARY(adc_long); |
| 666 | |
| 667 | VAL_BYTE_BYTE_BINARY(add_byte); |
| 668 | VAL_WORD_WORD_BINARY(add_word); |
| 669 | VAL_LONG_LONG_BINARY(add_long); |
| 670 | |
| 671 | VAL_BYTE_BYTE_BINARY(and_byte); |
| 672 | VAL_WORD_WORD_BINARY(and_word); |
| 673 | VAL_LONG_LONG_BINARY(and_long); |
| 674 | |
| 675 | VAL_BYTE_BYTE_BINARY(cmp_byte); |
| 676 | VAL_WORD_WORD_BINARY(cmp_word); |
| 677 | VAL_LONG_LONG_BINARY(cmp_long); |
| 678 | |
| 679 | VAL_BYTE_UNARY(daa_byte); |
| 680 | VAL_BYTE_UNARY(das_byte); /* Fails for 0x9A (out of range anyway) */ |
| 681 | |
| 682 | VAL_BYTE_UNARY(dec_byte); |
| 683 | VAL_WORD_UNARY(dec_word); |
| 684 | VAL_LONG_UNARY(dec_long); |
| 685 | |
| 686 | VAL_BYTE_UNARY(inc_byte); |
| 687 | VAL_WORD_UNARY(inc_word); |
| 688 | VAL_LONG_UNARY(inc_long); |
| 689 | |
| 690 | VAL_BYTE_BYTE_BINARY(or_byte); |
| 691 | VAL_WORD_WORD_BINARY(or_word); |
| 692 | VAL_LONG_LONG_BINARY(or_long); |
| 693 | |
| 694 | VAL_BYTE_UNARY(neg_byte); |
| 695 | VAL_WORD_UNARY(neg_word); |
| 696 | VAL_LONG_UNARY(neg_long); |
| 697 | |
| 698 | VAL_BYTE_UNARY(not_byte); |
| 699 | VAL_WORD_UNARY(not_word); |
| 700 | VAL_LONG_UNARY(not_long); |
| 701 | |
| 702 | VAL_BYTE_ROTATE(rcl_byte); |
| 703 | VAL_WORD_ROTATE(rcl_word); |
| 704 | VAL_LONG_ROTATE(rcl_long); |
| 705 | |
| 706 | VAL_BYTE_ROTATE(rcr_byte); |
| 707 | VAL_WORD_ROTATE(rcr_word); |
| 708 | VAL_LONG_ROTATE(rcr_long); |
| 709 | |
| 710 | VAL_BYTE_ROTATE(rol_byte); |
| 711 | VAL_WORD_ROTATE(rol_word); |
| 712 | VAL_LONG_ROTATE(rol_long); |
| 713 | |
| 714 | VAL_BYTE_ROTATE(ror_byte); |
| 715 | VAL_WORD_ROTATE(ror_word); |
| 716 | VAL_LONG_ROTATE(ror_long); |
| 717 | |
| 718 | VAL_BYTE_ROTATE(shl_byte); |
| 719 | VAL_WORD_ROTATE(shl_word); |
| 720 | VAL_LONG_ROTATE(shl_long); |
| 721 | |
| 722 | VAL_BYTE_ROTATE(shr_byte); |
| 723 | VAL_WORD_ROTATE(shr_word); |
| 724 | VAL_LONG_ROTATE(shr_long); |
| 725 | |
| 726 | VAL_BYTE_ROTATE(sar_byte); |
| 727 | VAL_WORD_ROTATE(sar_word); |
| 728 | VAL_LONG_ROTATE(sar_long); |
| 729 | |
| 730 | VAL_WORD_ROTATE_DBL(shld_word); |
| 731 | VAL_LONG_ROTATE_DBL(shld_long); |
| 732 | |
| 733 | VAL_WORD_ROTATE_DBL(shrd_word); |
| 734 | VAL_LONG_ROTATE_DBL(shrd_long); |
| 735 | |
| 736 | VAL_BYTE_BYTE_BINARY(sbb_byte); |
| 737 | VAL_WORD_WORD_BINARY(sbb_word); |
| 738 | VAL_LONG_LONG_BINARY(sbb_long); |
| 739 | |
| 740 | VAL_BYTE_BYTE_BINARY(sub_byte); |
| 741 | VAL_WORD_WORD_BINARY(sub_word); |
| 742 | VAL_LONG_LONG_BINARY(sub_long); |
| 743 | |
| 744 | VAL_BYTE_BYTE_BINARY(xor_byte); |
| 745 | VAL_WORD_WORD_BINARY(xor_word); |
| 746 | VAL_LONG_LONG_BINARY(xor_long); |
| 747 | |
| 748 | VAL_VOID_BYTE_BINARY(test_byte); |
| 749 | VAL_VOID_WORD_BINARY(test_word); |
| 750 | VAL_VOID_LONG_BINARY(test_long); |
| 751 | |
| 752 | VAL_BYTE_MUL(imul_byte); |
| 753 | VAL_WORD_MUL(imul_word); |
| 754 | VAL_LONG_MUL(imul_long); |
| 755 | |
| 756 | VAL_BYTE_MUL(mul_byte); |
| 757 | VAL_WORD_MUL(mul_word); |
| 758 | VAL_LONG_MUL(mul_long); |
| 759 | |
| 760 | VAL_BYTE_DIV(idiv_byte); |
| 761 | VAL_WORD_DIV(idiv_word); |
| 762 | VAL_LONG_DIV(idiv_long); |
| 763 | |
| 764 | VAL_BYTE_DIV(div_byte); |
| 765 | VAL_WORD_DIV(div_word); |
| 766 | VAL_LONG_DIV(div_long); |
| 767 | |
| 768 | return 0; |
| 769 | } |