3 * Run instruction encodings through combinations and record changes to registers and flags.
5 * This code is licensed under the LGPL.
6 * <insert LGPL legal text here>
11 #include <conio.h> /* this is where Open Watcom hides the outp() etc. functions */
21 #include <hw/cpu/cpu.h>
22 #include <hw/cpu/libgrind.h>
25 # define WINFCON_STOCK_WIN_MAIN
26 # include <hw/dos/winfcon.h>
29 static unsigned int min_i=0,max_i=511;
30 static unsigned int min_j=0,max_j=511;
32 static unsigned char asm_buf[64];
34 static char *log_filename = NULL;
36 #if TARGET_MSDOS == 32
37 static unsigned char log_buf[63*1024]; // 63KB
39 static unsigned char log_buf[30*1024]; // 30KB
42 static int log_reopen_counter=0;
43 static unsigned int log_bufi=0;
44 static int log_fd = -1;
46 static void do_pause() {
48 if (isatty(1)) { do { read(0,&c,1); } while (c != 13); }
51 static void log_close();
52 static int log_reopen();
53 static int log_open(const char *path);
55 static void log_incname() {
59 if (log_filename == NULL)
63 while (*n && n[1] != 0) n++; // scan until n = last char
66 num = ++log_reopen_counter;
69 *n = ((char)(num % 10U)) + '0';
72 if (n < log_filename) break;
77 static void log_flush() {
78 if (log_fd >= 0 && log_bufi != 0) {
79 unsigned int wd,wr,wo=0;
82 assert(wo < log_bufi);
84 wd = write(log_fd,log_buf+wo,wr);
85 if (/*another way to check for wd == -1*/wd > sizeof(log_buf)) wd = 0;
87 // note what we could write
91 // make sure DOS flushes to disk
97 // strange behavior in MS-DOS 5.0: if there is not enough disk space for X bytes, then it will
98 // write 0 bytes and return to us that it wrote 0 bytes. not what I expected, coming from the
99 // Linux world that would write as much as it can before giving up. --J.C.
100 if (errno == ENOSPC) {
101 printf("\nWrite: out of space (%u / %u written)\n",wd,wr);
102 printf("Unable to write full log. Swap floppies and hit ENTER or CTRL+C to quit.\n");
103 printf("You will have to assemble the full file from fragments when this is done.\n");
108 printf("Unable to reopen log.\n");
113 printf("\nError writing log: %s.\n",strerror(errno));
120 } while (wo < log_bufi);
126 static void log_lazy_flush(size_t extra) {
127 if (log_fd >= 0 && (extra >= sizeof(log_buf) || log_bufi >= (sizeof(log_buf)-extra)))
131 static void log_close() {
139 static int log_reopen() {
140 if (log_fd >= 0) return 1;
141 if (log_filename == NULL) return 0;
143 log_fd = open(log_filename,O_WRONLY|O_CREAT|O_TRUNC|O_BINARY,0644);
144 if (log_fd < 0) return 0;
149 static int log_open(const char *path) {
157 log_reopen_counter = 0;
159 log_fd = open(path,O_WRONLY|O_CREAT|O_TRUNC|O_BINARY,0644);
160 if (log_fd < 0) return 0;
162 log_filename = strdup(path);
166 static inline grind_ADDw() {
167 const unsigned int FL_mask = 0x8D5U; // CF(0),PF(2),AF(4),ZF(6),SF(7),OF(11) 1000 1101 0101
174 if (!grind_alloc_buf()) {
178 if (!grind_lock_buf()) {
183 log_open("gr_add.bin");
185 *((uint32_t*)(log_buf+log_bufi)) = 0x444E5247; // 'GRND'
187 *((uint32_t*)(log_buf+log_bufi)) = 0x77444441; // 'ADDw'
189 *((uint8_t*)(log_buf+log_bufi)) = sizeof(unsigned int); // sizeof unsigned int (2 or 4)
191 *((uint8_t*)(log_buf+log_bufi)) = cpu_flags; // CPU flags
193 *((unsigned int*)(log_buf+log_bufi)) = min_i; // min-max i inclusive
194 log_bufi += sizeof(unsigned int);
195 *((unsigned int*)(log_buf+log_bufi)) = max_i; // min-max i inclusive
196 log_bufi += sizeof(unsigned int);
197 *((unsigned int*)(log_buf+log_bufi)) = min_j; // min-max j inclusive
198 log_bufi += sizeof(unsigned int);
199 *((unsigned int*)(log_buf+log_bufi)) = max_j; // min-max j inclusive
200 log_bufi += sizeof(unsigned int);
201 *((unsigned int*)(log_buf+log_bufi)) = FL_mask; // flag test mask
202 log_bufi += sizeof(unsigned int);
208 printf("i=%u j=%u..%u",i,min_j,max_j);
213 grind_buf_ptr_t w = grind_buf;
215 *((grind_imm_t*)(asm_buf+0)) = 0; // ADD result
216 *((grind_imm_t*)(asm_buf+4)) = 0; // ADD result (2)
217 *((grind_imm_t*)(asm_buf+8)) = 0; // FLAGS before (after init)
218 *((grind_imm_t*)(asm_buf+12)) = 0; // FLAGS after
219 *((grind_imm_t*)(asm_buf+16)) = 0; // FLAGS before (after init)
220 *((grind_imm_t*)(asm_buf+20)) = 0; // FLAGS after
222 // *w++ = GRIND_INT3_INS; // INT3
224 // save DS, EAX, FLAGS
225 w=grind_buf_w__push_Sreg(w,GRIND_SEG_DS); // PUSH DS
226 w=grind_buf_w__push_Reg(w,GRIND_REG_AX); // PUSH (E)AX
227 w=grind_buf_w__push_Flags(w); // PUSHF(D)
229 // DS = segment of asm_buf
230 w=grind_buf_w__mov_Reg16_const(w,GRIND_REG_AX,FP_SEG(asm_buf)); // MOV AX,const
231 w=grind_buf_w__mov_Seg_from_Reg(w,GRIND_SEG_DS,GRIND_REG_AX); // MOV <seg>,<reg>
233 // set EFLAGS to known state
234 w=grind_buf_w__push_Flags(w); // PUSHF(D)
235 w=grind_buf_w__pop_Reg(w,GRIND_REG_AX); // POP (E)AX
236 w=grind_buf_w__and_Reg_const(w,GRIND_REG_AX,~FL_mask); // AND AX,<mask off CF(0),PF(2),AF(4),ZF(6),SF(7),IF(9),OF(11)> 1010 1101 0101
237 w=grind_buf_w__push_Reg(w,GRIND_REG_AX); // PUSH (E)AX
238 w=grind_buf_w__pop_Flags(w); // POPF(D)
239 w=grind_buf_w__push_Flags(w); // PUSHF(D)
240 w=grind_buf_w__pop_Reg(w,GRIND_REG_AX); // POP (E)AX
242 // store state of EFLAGS now, store result in asm_buf+8
243 w=grind_buf_w__push_Flags(w); // PUSHF(D)
244 w=grind_buf_w__pop_Reg(w,GRIND_REG_AX); // POP (E)AX
245 w=grind_buf_w__mov_memoff_from_reg(w,FP_OFF(asm_buf)+8,GRIND_REG_AX); // MOV [offset],(E)AX
247 // asm_buf+0 = i + j, store result in asm_buf+0
248 w=grind_buf_w__mov_Reg_const(w,GRIND_REG_AX,i); // MOV (E)AX,const
249 w=grind_buf_w__mov_Add_const(w,GRIND_REG_AX,j); // ADD (E)AX,const
250 w=grind_buf_w__mov_memoff_from_reg(w,FP_OFF(asm_buf)+0,GRIND_REG_AX); // MOV [offset],(E)AX
252 // store state of EFLAGS now, in asm_buf+12
253 w=grind_buf_w__push_Flags(w); // PUSHF(D)
254 w=grind_buf_w__pop_Reg(w,GRIND_REG_AX); // POP (E)AX
255 w=grind_buf_w__mov_memoff_from_reg(w,FP_OFF(asm_buf)+12,GRIND_REG_AX); // MOV [offset],(E)AX
257 // set EFLAGS to known state
258 w=grind_buf_w__push_Flags(w); // PUSHF(D)
259 w=grind_buf_w__pop_Reg(w,GRIND_REG_AX); // POP (E)AX
260 w=grind_buf_w__or_Reg_const(w,GRIND_REG_AX,FL_mask); // OR AX,<set CF(0),PF(2),AF(4),ZF(6),SF(7),IF(9),OF(11)> 1010 1101 0101
261 w=grind_buf_w__push_Reg(w,GRIND_REG_AX); // PUSH (E)AX
262 w=grind_buf_w__pop_Flags(w); // POPF(D)
263 w=grind_buf_w__push_Flags(w); // PUSHF(D)
264 w=grind_buf_w__pop_Reg(w,GRIND_REG_AX); // POP (E)AX
266 // store state of EFLAGS now, store result in asm_buf+16
267 w=grind_buf_w__push_Flags(w); // PUSHF(D)
268 w=grind_buf_w__pop_Reg(w,GRIND_REG_AX); // POP (E)AX
269 w=grind_buf_w__mov_memoff_from_reg(w,FP_OFF(asm_buf)+16,GRIND_REG_AX); // MOV [offset],(E)AX
271 // asm_buf+0 = i + j, store result in asm_buf+4
272 w=grind_buf_w__mov_Reg_const(w,GRIND_REG_AX,i); // MOV (E)AX,const
273 w=grind_buf_w__mov_Add_const(w,GRIND_REG_AX,j); // ADD (E)AX,const
274 w=grind_buf_w__mov_memoff_from_reg(w,FP_OFF(asm_buf)+4,GRIND_REG_AX); // MOV [offset],(E)AX
276 // store state of EFLAGS now, store result in asm_buf+20
277 w=grind_buf_w__push_Flags(w); // PUSHF(D)
278 w=grind_buf_w__pop_Reg(w,GRIND_REG_AX); // POP (E)AX
279 w=grind_buf_w__mov_memoff_from_reg(w,FP_OFF(asm_buf)+20,GRIND_REG_AX); // MOV [offset],(E)AX
281 // restore FLAGS, EAX, DS, exit subroutine
282 w=grind_buf_w__pop_Flags(w); // POPF(D)
283 w=grind_buf_w__pop_Reg(w,GRIND_REG_AX); // POP (E)AX
284 w=grind_buf_w__pop_Sreg(w,GRIND_SEG_DS); // POP DS
285 *w++ = GRIND_RET_INS; // RET
288 if (w > (grind_buf + grind_buf_size)) {
289 printf("<--BUFFER OVERRUN\n");
295 if (!grind_execute_buf()) {
302 if (*((grind_imm_t*)(asm_buf+0)) != *((grind_imm_t*)(asm_buf+4))) {
303 printf("WARNING: Two ADD passes with different sums 0x%x != 0x%x\n",
304 *((grind_imm_t*)(asm_buf+0)),
305 *((grind_imm_t*)(asm_buf+4)));
310 *((unsigned int*)(log_buf+log_bufi)) = i; // I
311 log_bufi += sizeof(unsigned int);
312 *((unsigned int*)(log_buf+log_bufi)) = j; // J
313 log_bufi += sizeof(unsigned int);
314 *((unsigned int*)(log_buf+log_bufi)) = *((grind_imm_t*)(asm_buf+0)); // I+J
315 log_bufi += sizeof(unsigned int);
316 *((unsigned int*)(log_buf+log_bufi)) = *((grind_imm_t*)(asm_buf+8)); // FLAGS before init #1
317 log_bufi += sizeof(unsigned int);
318 *((unsigned int*)(log_buf+log_bufi)) = *((grind_imm_t*)(asm_buf+12)); // FLAGS after init #1
319 log_bufi += sizeof(unsigned int);
320 *((unsigned int*)(log_buf+log_bufi)) = *((grind_imm_t*)(asm_buf+16)); // FLAGS before init #2
321 log_bufi += sizeof(unsigned int);
322 *((unsigned int*)(log_buf+log_bufi)) = *((grind_imm_t*)(asm_buf+20)); // FLAGS after init #2
323 log_bufi += sizeof(unsigned int);
326 } while ((j++) != max_j);
330 } while ((i++) != max_i);
339 static inline grind_SUBw() {
340 const unsigned int FL_mask = 0x8D5U; // CF(0),PF(2),AF(4),ZF(6),SF(7),OF(11) 1000 1101 0101
347 if (!grind_alloc_buf()) {
351 if (!grind_lock_buf()) {
356 log_open("gr_sub.bin");
358 *((uint32_t*)(log_buf+log_bufi)) = 0x444E5247; // 'GRND'
360 *((uint32_t*)(log_buf+log_bufi)) = 0x77425553; // 'SUBw'
362 *((uint8_t*)(log_buf+log_bufi)) = sizeof(unsigned int); // sizeof unsigned int (2 or 4)
364 *((uint8_t*)(log_buf+log_bufi)) = cpu_flags; // CPU flags
366 *((unsigned int*)(log_buf+log_bufi)) = min_i; // min-max i inclusive
367 log_bufi += sizeof(unsigned int);
368 *((unsigned int*)(log_buf+log_bufi)) = max_i; // min-max i inclusive
369 log_bufi += sizeof(unsigned int);
370 *((unsigned int*)(log_buf+log_bufi)) = min_j; // min-max j inclusive
371 log_bufi += sizeof(unsigned int);
372 *((unsigned int*)(log_buf+log_bufi)) = max_j; // min-max j inclusive
373 log_bufi += sizeof(unsigned int);
374 *((unsigned int*)(log_buf+log_bufi)) = FL_mask; // flag test mask
375 log_bufi += sizeof(unsigned int);
381 printf("i=%u j=%u..%u",i,min_j,max_j);
386 grind_buf_ptr_t w = grind_buf;
388 *((grind_imm_t*)(asm_buf+0)) = 0; // ADD result
389 *((grind_imm_t*)(asm_buf+4)) = 0; // ADD result (2)
390 *((grind_imm_t*)(asm_buf+8)) = 0; // FLAGS before (after init)
391 *((grind_imm_t*)(asm_buf+12)) = 0; // FLAGS after
392 *((grind_imm_t*)(asm_buf+16)) = 0; // FLAGS before (after init)
393 *((grind_imm_t*)(asm_buf+20)) = 0; // FLAGS after
395 // *w++ = GRIND_INT3_INS; // INT3
397 // save DS, EAX, FLAGS
398 w=grind_buf_w__push_Sreg(w,GRIND_SEG_DS); // PUSH DS
399 w=grind_buf_w__push_Reg(w,GRIND_REG_AX); // PUSH (E)AX
400 w=grind_buf_w__push_Flags(w); // PUSHF(D)
402 // DS = segment of asm_buf
403 w=grind_buf_w__mov_Reg16_const(w,GRIND_REG_AX,FP_SEG(asm_buf)); // MOV AX,const
404 w=grind_buf_w__mov_Seg_from_Reg(w,GRIND_SEG_DS,GRIND_REG_AX); // MOV <seg>,<reg>
406 // set EFLAGS to known state
407 w=grind_buf_w__push_Flags(w); // PUSHF(D)
408 w=grind_buf_w__pop_Reg(w,GRIND_REG_AX); // POP (E)AX
409 w=grind_buf_w__and_Reg_const(w,GRIND_REG_AX,~FL_mask); // AND AX,<mask off CF(0),PF(2),AF(4),ZF(6),SF(7),IF(9),OF(11)> 1010 1101 0101
410 w=grind_buf_w__push_Reg(w,GRIND_REG_AX); // PUSH (E)AX
411 w=grind_buf_w__pop_Flags(w); // POPF(D)
412 w=grind_buf_w__push_Flags(w); // PUSHF(D)
413 w=grind_buf_w__pop_Reg(w,GRIND_REG_AX); // POP (E)AX
415 // store state of EFLAGS now, store result in asm_buf+8
416 w=grind_buf_w__push_Flags(w); // PUSHF(D)
417 w=grind_buf_w__pop_Reg(w,GRIND_REG_AX); // POP (E)AX
418 w=grind_buf_w__mov_memoff_from_reg(w,FP_OFF(asm_buf)+8,GRIND_REG_AX); // MOV [offset],(E)AX
420 // asm_buf+0 = i + j, store result in asm_buf+0
421 w=grind_buf_w__mov_Reg_const(w,GRIND_REG_AX,i); // MOV (E)AX,const
422 w=grind_buf_w__mov_Sub_const(w,GRIND_REG_AX,j); // SUB (E)AX,const
423 w=grind_buf_w__mov_memoff_from_reg(w,FP_OFF(asm_buf)+0,GRIND_REG_AX); // MOV [offset],(E)AX
425 // store state of EFLAGS now, in asm_buf+12
426 w=grind_buf_w__push_Flags(w); // PUSHF(D)
427 w=grind_buf_w__pop_Reg(w,GRIND_REG_AX); // POP (E)AX
428 w=grind_buf_w__mov_memoff_from_reg(w,FP_OFF(asm_buf)+12,GRIND_REG_AX); // MOV [offset],(E)AX
430 // set EFLAGS to known state
431 w=grind_buf_w__push_Flags(w); // PUSHF(D)
432 w=grind_buf_w__pop_Reg(w,GRIND_REG_AX); // POP (E)AX
433 w=grind_buf_w__or_Reg_const(w,GRIND_REG_AX,FL_mask); // OR AX,<set CF(0),PF(2),AF(4),ZF(6),SF(7),IF(9),OF(11)> 1010 1101 0101
434 w=grind_buf_w__push_Reg(w,GRIND_REG_AX); // PUSH (E)AX
435 w=grind_buf_w__pop_Flags(w); // POPF(D)
436 w=grind_buf_w__push_Flags(w); // PUSHF(D)
437 w=grind_buf_w__pop_Reg(w,GRIND_REG_AX); // POP (E)AX
439 // store state of EFLAGS now, store result in asm_buf+16
440 w=grind_buf_w__push_Flags(w); // PUSHF(D)
441 w=grind_buf_w__pop_Reg(w,GRIND_REG_AX); // POP (E)AX
442 w=grind_buf_w__mov_memoff_from_reg(w,FP_OFF(asm_buf)+16,GRIND_REG_AX); // MOV [offset],(E)AX
444 // asm_buf+0 = i + j, store result in asm_buf+4
445 w=grind_buf_w__mov_Reg_const(w,GRIND_REG_AX,i); // MOV (E)AX,const
446 w=grind_buf_w__mov_Sub_const(w,GRIND_REG_AX,j); // SUB (E)AX,const
447 w=grind_buf_w__mov_memoff_from_reg(w,FP_OFF(asm_buf)+4,GRIND_REG_AX); // MOV [offset],(E)AX
449 // store state of EFLAGS now, store result in asm_buf+20
450 w=grind_buf_w__push_Flags(w); // PUSHF(D)
451 w=grind_buf_w__pop_Reg(w,GRIND_REG_AX); // POP (E)AX
452 w=grind_buf_w__mov_memoff_from_reg(w,FP_OFF(asm_buf)+20,GRIND_REG_AX); // MOV [offset],(E)AX
454 // restore FLAGS, EAX, DS, exit subroutine
455 w=grind_buf_w__pop_Flags(w); // POPF(D)
456 w=grind_buf_w__pop_Reg(w,GRIND_REG_AX); // POP (E)AX
457 w=grind_buf_w__pop_Sreg(w,GRIND_SEG_DS); // POP DS
458 *w++ = GRIND_RET_INS; // RET
461 if (w > (grind_buf + grind_buf_size)) {
462 printf("<--BUFFER OVERRUN\n");
468 if (!grind_execute_buf()) {
475 if (*((grind_imm_t*)(asm_buf+0)) != *((grind_imm_t*)(asm_buf+4))) {
476 printf("WARNING: Two SUB passes with different results 0x%x != 0x%x\n",
477 *((grind_imm_t*)(asm_buf+0)),
478 *((grind_imm_t*)(asm_buf+4)));
483 *((unsigned int*)(log_buf+log_bufi)) = i; // I
484 log_bufi += sizeof(unsigned int);
485 *((unsigned int*)(log_buf+log_bufi)) = j; // J
486 log_bufi += sizeof(unsigned int);
487 *((unsigned int*)(log_buf+log_bufi)) = *((grind_imm_t*)(asm_buf+0)); // I-J
488 log_bufi += sizeof(unsigned int);
489 *((unsigned int*)(log_buf+log_bufi)) = *((grind_imm_t*)(asm_buf+8)); // FLAGS before init #1
490 log_bufi += sizeof(unsigned int);
491 *((unsigned int*)(log_buf+log_bufi)) = *((grind_imm_t*)(asm_buf+12)); // FLAGS after init #1
492 log_bufi += sizeof(unsigned int);
493 *((unsigned int*)(log_buf+log_bufi)) = *((grind_imm_t*)(asm_buf+16)); // FLAGS before init #2
494 log_bufi += sizeof(unsigned int);
495 *((unsigned int*)(log_buf+log_bufi)) = *((grind_imm_t*)(asm_buf+20)); // FLAGS after init #2
496 log_bufi += sizeof(unsigned int);
499 } while ((j++) != max_j);
503 } while ((i++) != max_i);
512 static inline grind_MULw() {
513 const unsigned int FL_mask = 0x8D5U; // CF(0),PF(2),AF(4),ZF(6),SF(7),OF(11) 1000 1101 0101
520 if (!grind_alloc_buf()) {
524 if (!grind_lock_buf()) {
529 log_open("gr_mul.bin");
531 *((uint32_t*)(log_buf+log_bufi)) = 0x444E5247; // 'GRND'
533 *((uint32_t*)(log_buf+log_bufi)) = 0x774C554D; // 'MULw'
535 *((uint8_t*)(log_buf+log_bufi)) = sizeof(unsigned int); // sizeof unsigned int (2 or 4)
537 *((uint8_t*)(log_buf+log_bufi)) = cpu_flags; // CPU flags
539 *((unsigned int*)(log_buf+log_bufi)) = min_i; // min-max i inclusive
540 log_bufi += sizeof(unsigned int);
541 *((unsigned int*)(log_buf+log_bufi)) = max_i; // min-max i inclusive
542 log_bufi += sizeof(unsigned int);
543 *((unsigned int*)(log_buf+log_bufi)) = min_j; // min-max j inclusive
544 log_bufi += sizeof(unsigned int);
545 *((unsigned int*)(log_buf+log_bufi)) = max_j; // min-max j inclusive
546 log_bufi += sizeof(unsigned int);
547 *((unsigned int*)(log_buf+log_bufi)) = FL_mask; // flag test mask
548 log_bufi += sizeof(unsigned int);
554 printf("i=%u j=%u..%u",i,min_j,max_j);
559 grind_buf_ptr_t w = grind_buf;
561 *((grind_imm_t*)(asm_buf+0)) = 0; // MUL result (AX)
562 *((grind_imm_t*)(asm_buf+4)) = 0; // MUL result (DX)
563 *((grind_imm_t*)(asm_buf+8)) = 0; // MUL result 2 (AX)
564 *((grind_imm_t*)(asm_buf+12)) = 0; // MUL result 2 (DX)
565 *((grind_imm_t*)(asm_buf+16)) = 0; // FLAGS before (after init)
566 *((grind_imm_t*)(asm_buf+20)) = 0; // FLAGS after
567 *((grind_imm_t*)(asm_buf+24)) = 0; // FLAGS before (after init)
568 *((grind_imm_t*)(asm_buf+28)) = 0; // FLAGS after
570 // *w++ = GRIND_INT3_INS; // INT3
572 // save DS, EAX, FLAGS
573 w=grind_buf_w__push_Sreg(w,GRIND_SEG_DS); // PUSH DS
574 w=grind_buf_w__push_Reg(w,GRIND_REG_AX); // PUSH (E)AX
575 w=grind_buf_w__push_Reg(w,GRIND_REG_BX); // PUSH (E)BX
576 w=grind_buf_w__push_Flags(w); // PUSHF(D)
578 // DS = segment of asm_buf
579 w=grind_buf_w__mov_Reg16_const(w,GRIND_REG_AX,FP_SEG(asm_buf)); // MOV AX,const
580 w=grind_buf_w__mov_Seg_from_Reg(w,GRIND_SEG_DS,GRIND_REG_AX); // MOV <seg>,<reg>
582 // set EFLAGS to known state
583 w=grind_buf_w__push_Flags(w); // PUSHF(D)
584 w=grind_buf_w__pop_Reg(w,GRIND_REG_AX); // POP (E)AX
585 w=grind_buf_w__and_Reg_const(w,GRIND_REG_AX,~FL_mask); // AND AX,<mask off CF(0),PF(2),AF(4),ZF(6),SF(7),IF(9),OF(11)> 1010 1101 0101
586 w=grind_buf_w__push_Reg(w,GRIND_REG_AX); // PUSH (E)AX
587 w=grind_buf_w__pop_Flags(w); // POPF(D)
588 w=grind_buf_w__push_Flags(w); // PUSHF(D)
589 w=grind_buf_w__pop_Reg(w,GRIND_REG_AX); // POP (E)AX
591 // store state of EFLAGS now, store result in asm_buf+16
592 w=grind_buf_w__push_Flags(w); // PUSHF(D)
593 w=grind_buf_w__pop_Reg(w,GRIND_REG_AX); // POP (E)AX
594 w=grind_buf_w__mov_memoff_from_reg(w,FP_OFF(asm_buf)+16,GRIND_REG_AX); // MOV [offset],(E)AX
596 // asm_buf+0 = i + j, store result in asm_buf+0
597 w=grind_buf_w__mov_Reg_const(w,GRIND_REG_AX,i); // MOV (E)AX,const
598 w=grind_buf_w__mov_Reg_const(w,GRIND_REG_BX,j); // MOV (E)BX,const
599 w=grind_buf_w__mul_Reg(w,GRIND_REG_BX); // MUL (E)BX
600 w=grind_buf_w__mov_memoff_from_reg(w,FP_OFF(asm_buf)+0,GRIND_REG_AX); // MOV [offset],(E)AX
601 w=grind_buf_w__mov_memoff_from_reg(w,FP_OFF(asm_buf)+4,GRIND_REG_DX); // MOV [offset],(E)AX
603 // store state of EFLAGS now, in asm_buf+20
604 w=grind_buf_w__push_Flags(w); // PUSHF(D)
605 w=grind_buf_w__pop_Reg(w,GRIND_REG_AX); // POP (E)AX
606 w=grind_buf_w__mov_memoff_from_reg(w,FP_OFF(asm_buf)+20,GRIND_REG_AX); // MOV [offset],(E)AX
608 // set EFLAGS to known state
609 w=grind_buf_w__push_Flags(w); // PUSHF(D)
610 w=grind_buf_w__pop_Reg(w,GRIND_REG_AX); // POP (E)AX
611 w=grind_buf_w__or_Reg_const(w,GRIND_REG_AX,FL_mask); // OR AX,<set CF(0),PF(2),AF(4),ZF(6),SF(7),IF(9),OF(11)> 1010 1101 0101
612 w=grind_buf_w__push_Reg(w,GRIND_REG_AX); // PUSH (E)AX
613 w=grind_buf_w__pop_Flags(w); // POPF(D)
614 w=grind_buf_w__push_Flags(w); // PUSHF(D)
615 w=grind_buf_w__pop_Reg(w,GRIND_REG_AX); // POP (E)AX
617 // store state of EFLAGS now, store result in asm_buf+24
618 w=grind_buf_w__push_Flags(w); // PUSHF(D)
619 w=grind_buf_w__pop_Reg(w,GRIND_REG_AX); // POP (E)AX
620 w=grind_buf_w__mov_memoff_from_reg(w,FP_OFF(asm_buf)+24,GRIND_REG_AX); // MOV [offset],(E)AX
622 // asm_buf+0 = i + j, store result in asm_buf+4
623 w=grind_buf_w__mov_Reg_const(w,GRIND_REG_AX,i); // MOV (E)AX,const
624 w=grind_buf_w__mov_Reg_const(w,GRIND_REG_BX,j); // MOV (E)BX,const
625 w=grind_buf_w__mul_Reg(w,GRIND_REG_BX); // MUL (E)BX
626 w=grind_buf_w__mov_memoff_from_reg(w,FP_OFF(asm_buf)+8,GRIND_REG_AX); // MOV [offset],(E)AX
627 w=grind_buf_w__mov_memoff_from_reg(w,FP_OFF(asm_buf)+12,GRIND_REG_DX); // MOV [offset],(E)DX
629 // store state of EFLAGS now, store result in asm_buf+28
630 w=grind_buf_w__push_Flags(w); // PUSHF(D)
631 w=grind_buf_w__pop_Reg(w,GRIND_REG_AX); // POP (E)AX
632 w=grind_buf_w__mov_memoff_from_reg(w,FP_OFF(asm_buf)+28,GRIND_REG_AX); // MOV [offset],(E)AX
634 // restore FLAGS, EAX, DS, exit subroutine
635 w=grind_buf_w__pop_Flags(w); // POPF(D)
636 w=grind_buf_w__pop_Reg(w,GRIND_REG_BX); // POP (E)BX
637 w=grind_buf_w__pop_Reg(w,GRIND_REG_AX); // POP (E)AX
638 w=grind_buf_w__pop_Sreg(w,GRIND_SEG_DS); // POP DS
639 *w++ = GRIND_RET_INS; // RET
642 if (w > (grind_buf + grind_buf_size)) {
643 printf("<--BUFFER OVERRUN\n");
649 if (!grind_execute_buf()) {
656 if (*((grind_imm_t*)(asm_buf+0)) != *((grind_imm_t*)(asm_buf+8)) ||
657 *((grind_imm_t*)(asm_buf+4)) != *((grind_imm_t*)(asm_buf+12))) {
658 printf("WARNING: Two MUL passes with different products %x:%x != %x:%x\n",
659 *((grind_imm_t*)(asm_buf+4)), *((grind_imm_t*)(asm_buf+0)),
660 *((grind_imm_t*)(asm_buf+12)), *((grind_imm_t*)(asm_buf+8)));
665 *((unsigned int*)(log_buf+log_bufi)) = i; // I
666 log_bufi += sizeof(unsigned int);
667 *((unsigned int*)(log_buf+log_bufi)) = j; // J
668 log_bufi += sizeof(unsigned int);
669 *((unsigned int*)(log_buf+log_bufi)) = *((grind_imm_t*)(asm_buf+0)); // I*J (low word)
670 log_bufi += sizeof(unsigned int);
671 *((unsigned int*)(log_buf+log_bufi)) = *((grind_imm_t*)(asm_buf+4)); // I*J (high word)
672 log_bufi += sizeof(unsigned int);
673 *((unsigned int*)(log_buf+log_bufi)) = *((grind_imm_t*)(asm_buf+16)); // FLAGS before init #1
674 log_bufi += sizeof(unsigned int);
675 *((unsigned int*)(log_buf+log_bufi)) = *((grind_imm_t*)(asm_buf+20)); // FLAGS after init #1
676 log_bufi += sizeof(unsigned int);
677 *((unsigned int*)(log_buf+log_bufi)) = *((grind_imm_t*)(asm_buf+24)); // FLAGS before init #2
678 log_bufi += sizeof(unsigned int);
679 *((unsigned int*)(log_buf+log_bufi)) = *((grind_imm_t*)(asm_buf+28)); // FLAGS after init #2
680 log_bufi += sizeof(unsigned int);
683 } while ((j++) != max_j);
687 } while ((i++) != max_i);
696 static inline grind_DIVw() {
697 const unsigned int FL_mask = 0x8D5U; // CF(0),PF(2),AF(4),ZF(6),SF(7),OF(11) 1000 1101 0101
704 if (!grind_alloc_buf()) {
708 if (!grind_lock_buf()) {
713 log_open("gr_div.bin");
715 *((uint32_t*)(log_buf+log_bufi)) = 0x444E5247; // 'GRND'
717 *((uint32_t*)(log_buf+log_bufi)) = 0x77564944; // 'DIVw'
719 *((uint8_t*)(log_buf+log_bufi)) = sizeof(unsigned int); // sizeof unsigned int (2 or 4)
721 *((uint8_t*)(log_buf+log_bufi)) = cpu_flags; // CPU flags
723 *((unsigned int*)(log_buf+log_bufi)) = min_i; // min-max i inclusive
724 log_bufi += sizeof(unsigned int);
725 *((unsigned int*)(log_buf+log_bufi)) = max_i; // min-max i inclusive
726 log_bufi += sizeof(unsigned int);
727 *((unsigned int*)(log_buf+log_bufi)) = min_j; // min-max j inclusive
728 log_bufi += sizeof(unsigned int);
729 *((unsigned int*)(log_buf+log_bufi)) = max_j; // min-max j inclusive
730 log_bufi += sizeof(unsigned int);
731 *((unsigned int*)(log_buf+log_bufi)) = FL_mask; // flag test mask
732 log_bufi += sizeof(unsigned int);
738 printf("i=%u j=%u..%u",i,min_j,max_j);
743 grind_buf_ptr_t w = grind_buf;
745 *((grind_imm_t*)(asm_buf+0)) = 0; // DIV result (AX)
746 *((grind_imm_t*)(asm_buf+4)) = 0; // DIV result (DX)
747 *((grind_imm_t*)(asm_buf+8)) = 0; // DIV result 2 (AX)
748 *((grind_imm_t*)(asm_buf+12)) = 0; // DIV result 2 (DX)
749 *((grind_imm_t*)(asm_buf+16)) = 0; // FLAGS before (after init)
750 *((grind_imm_t*)(asm_buf+20)) = 0; // FLAGS after
751 *((grind_imm_t*)(asm_buf+24)) = 0; // FLAGS before (after init)
752 *((grind_imm_t*)(asm_buf+28)) = 0; // FLAGS after
754 // do NOT divide by zero!
756 // *w++ = GRIND_INT3_INS; // INT3
758 // save DS, EAX, FLAGS
759 w=grind_buf_w__push_Sreg(w,GRIND_SEG_DS); // PUSH DS
760 w=grind_buf_w__push_Reg(w,GRIND_REG_AX); // PUSH (E)AX
761 w=grind_buf_w__push_Reg(w,GRIND_REG_BX); // PUSH (E)BX
762 w=grind_buf_w__push_Reg(w,GRIND_REG_DX); // PUSH (E)DX
763 w=grind_buf_w__push_Flags(w); // PUSHF(D)
765 // DS = segment of asm_buf
766 w=grind_buf_w__mov_Reg16_const(w,GRIND_REG_AX,FP_SEG(asm_buf)); // MOV AX,const
767 w=grind_buf_w__mov_Seg_from_Reg(w,GRIND_SEG_DS,GRIND_REG_AX); // MOV <seg>,<reg>
769 // set EFLAGS to known state
770 w=grind_buf_w__push_Flags(w); // PUSHF(D)
771 w=grind_buf_w__pop_Reg(w,GRIND_REG_AX); // POP (E)AX
772 w=grind_buf_w__and_Reg_const(w,GRIND_REG_AX,~FL_mask); // AND AX,<mask off CF(0),PF(2),AF(4),ZF(6),SF(7),IF(9),OF(11)> 1010 1101 0101
773 w=grind_buf_w__push_Reg(w,GRIND_REG_AX); // PUSH (E)AX
774 w=grind_buf_w__pop_Flags(w); // POPF(D)
775 w=grind_buf_w__push_Flags(w); // PUSHF(D)
776 w=grind_buf_w__pop_Reg(w,GRIND_REG_AX); // POP (E)AX
778 // store state of EFLAGS now, store result in asm_buf+16
779 w=grind_buf_w__push_Flags(w); // PUSHF(D)
780 w=grind_buf_w__pop_Reg(w,GRIND_REG_AX); // POP (E)AX
781 w=grind_buf_w__mov_memoff_from_reg(w,FP_OFF(asm_buf)+16,GRIND_REG_AX); // MOV [offset],(E)AX
783 // asm_buf+0 = i + j, store result in asm_buf+0
784 w=grind_buf_w__mov_Reg_const(w,GRIND_REG_AX,i); // MOV (E)AX,const
785 w=grind_buf_w__mov_Reg_const(w,GRIND_REG_BX,j); // MOV (E)BX,const
786 w=grind_buf_w__xor_Reg_Reg(w,GRIND_REG_DX,GRIND_REG_DX); // XOR (E)DX,(E)DX
787 w=grind_buf_w__div_Reg(w,GRIND_REG_BX); // DIV (E)BX
788 w=grind_buf_w__mov_memoff_from_reg(w,FP_OFF(asm_buf)+0,GRIND_REG_AX); // MOV [offset],(E)AX
789 w=grind_buf_w__mov_memoff_from_reg(w,FP_OFF(asm_buf)+4,GRIND_REG_DX); // MOV [offset],(E)AX
791 // store state of EFLAGS now, in asm_buf+20
792 w=grind_buf_w__push_Flags(w); // PUSHF(D)
793 w=grind_buf_w__pop_Reg(w,GRIND_REG_AX); // POP (E)AX
794 w=grind_buf_w__mov_memoff_from_reg(w,FP_OFF(asm_buf)+20,GRIND_REG_AX); // MOV [offset],(E)AX
796 // set EFLAGS to known state
797 w=grind_buf_w__push_Flags(w); // PUSHF(D)
798 w=grind_buf_w__pop_Reg(w,GRIND_REG_AX); // POP (E)AX
799 w=grind_buf_w__or_Reg_const(w,GRIND_REG_AX,FL_mask); // OR AX,<set CF(0),PF(2),AF(4),ZF(6),SF(7),IF(9),OF(11)> 1010 1101 0101
800 w=grind_buf_w__push_Reg(w,GRIND_REG_AX); // PUSH (E)AX
801 w=grind_buf_w__pop_Flags(w); // POPF(D)
802 w=grind_buf_w__push_Flags(w); // PUSHF(D)
803 w=grind_buf_w__pop_Reg(w,GRIND_REG_AX); // POP (E)AX
805 // store state of EFLAGS now, store result in asm_buf+24
806 w=grind_buf_w__push_Flags(w); // PUSHF(D)
807 w=grind_buf_w__pop_Reg(w,GRIND_REG_AX); // POP (E)AX
808 w=grind_buf_w__mov_memoff_from_reg(w,FP_OFF(asm_buf)+24,GRIND_REG_AX); // MOV [offset],(E)AX
810 // asm_buf+0 = i + j, store result in asm_buf+4
811 w=grind_buf_w__mov_Reg_const(w,GRIND_REG_AX,i); // MOV (E)AX,const
812 w=grind_buf_w__mov_Reg_const(w,GRIND_REG_BX,j); // MOV (E)BX,const
813 w=grind_buf_w__xor_Reg_Reg(w,GRIND_REG_DX,GRIND_REG_DX); // XOR (E)DX,(E)DX
814 w=grind_buf_w__div_Reg(w,GRIND_REG_BX); // DIV (E)BX
815 w=grind_buf_w__mov_memoff_from_reg(w,FP_OFF(asm_buf)+8,GRIND_REG_AX); // MOV [offset],(E)AX
816 w=grind_buf_w__mov_memoff_from_reg(w,FP_OFF(asm_buf)+12,GRIND_REG_DX); // MOV [offset],(E)DX
818 // store state of EFLAGS now, store result in asm_buf+28
819 w=grind_buf_w__push_Flags(w); // PUSHF(D)
820 w=grind_buf_w__pop_Reg(w,GRIND_REG_AX); // POP (E)AX
821 w=grind_buf_w__mov_memoff_from_reg(w,FP_OFF(asm_buf)+28,GRIND_REG_AX); // MOV [offset],(E)AX
823 // restore FLAGS, EAX, DS, exit subroutine
824 w=grind_buf_w__pop_Flags(w); // POPF(D)
825 w=grind_buf_w__pop_Reg(w,GRIND_REG_DX); // POP (E)DX
826 w=grind_buf_w__pop_Reg(w,GRIND_REG_BX); // POP (E)BX
827 w=grind_buf_w__pop_Reg(w,GRIND_REG_AX); // POP (E)AX
828 w=grind_buf_w__pop_Sreg(w,GRIND_SEG_DS); // POP DS
829 *w++ = GRIND_RET_INS; // RET
832 if (w > (grind_buf + grind_buf_size)) {
833 printf("<--BUFFER OVERRUN\n");
839 if (!grind_execute_buf()) {
846 if (*((grind_imm_t*)(asm_buf+0)) != *((grind_imm_t*)(asm_buf+8)) ||
847 *((grind_imm_t*)(asm_buf+4)) != *((grind_imm_t*)(asm_buf+12))) {
848 printf("WARNING: Two DIV passes with different results (rem:res) %x:%x != %x:%x\n",
849 *((grind_imm_t*)(asm_buf+4)), *((grind_imm_t*)(asm_buf+0)),
850 *((grind_imm_t*)(asm_buf+12)), *((grind_imm_t*)(asm_buf+8)));
856 *((unsigned int*)(log_buf+log_bufi)) = i; // I
857 log_bufi += sizeof(unsigned int);
858 *((unsigned int*)(log_buf+log_bufi)) = j; // J
859 log_bufi += sizeof(unsigned int);
860 *((unsigned int*)(log_buf+log_bufi)) = *((grind_imm_t*)(asm_buf+0)); // I/J (result)
861 log_bufi += sizeof(unsigned int);
862 *((unsigned int*)(log_buf+log_bufi)) = *((grind_imm_t*)(asm_buf+4)); // I%J (remainder)
863 log_bufi += sizeof(unsigned int);
864 *((unsigned int*)(log_buf+log_bufi)) = *((grind_imm_t*)(asm_buf+16)); // FLAGS before init #1
865 log_bufi += sizeof(unsigned int);
866 *((unsigned int*)(log_buf+log_bufi)) = *((grind_imm_t*)(asm_buf+20)); // FLAGS after init #1
867 log_bufi += sizeof(unsigned int);
868 *((unsigned int*)(log_buf+log_bufi)) = *((grind_imm_t*)(asm_buf+24)); // FLAGS before init #2
869 log_bufi += sizeof(unsigned int);
870 *((unsigned int*)(log_buf+log_bufi)) = *((grind_imm_t*)(asm_buf+28)); // FLAGS after init #2
871 log_bufi += sizeof(unsigned int);
874 } while ((j++) != max_j);
878 } while ((i++) != max_i);
890 printf("Testing ADDw x+y (%u <= x <= %u)+(%u <= y <= %u)\n",min_i,max_i,min_j,max_j);
894 printf("Testing SUBw x-y (%u <= x <= %u)+(%u <= y <= %u)\n",min_i,max_i,min_j,max_j);
898 printf("Testing MULw x*y (%u <= x <= %u)+(%u <= y <= %u)\n",min_i,max_i,min_j,max_j);
902 printf("Testing DIVw x*y (%u <= x <= %u)+(%u <= y <= %u)\n",min_i,max_i,min_j,max_j);