]> 4ch.mooo.com Git - 16.git/blob - src/lib/doslib/hw/cpu/gr_add.c
added a bunch of things~ and midi stuff~
[16.git] / src / lib / doslib / hw / cpu / gr_add.c
1 /* grind.c
2  *
3  * Run instruction encodings through combinations and record changes to registers and flags.
4  *
5  * This code is licensed under the LGPL.
6  * <insert LGPL legal text here>
7  *
8  */
9
10 #include <stdio.h>
11 #include <conio.h> /* this is where Open Watcom hides the outp() etc. functions */
12 #include <string.h>
13 #include <stdlib.h>
14 #include <unistd.h>
15 #include <assert.h>
16 #include <malloc.h>
17 #include <errno.h>
18 #include <fcntl.h>
19 #include <dos.h>
20
21 #include <hw/cpu/cpu.h>
22 #include <hw/cpu/libgrind.h>
23
24 #ifdef TARGET_WINDOWS
25 # define WINFCON_STOCK_WIN_MAIN
26 # include <hw/dos/winfcon.h>
27 #endif
28
29 static unsigned int min_i=0,max_i=511;
30 static unsigned int min_j=0,max_j=511;
31
32 static unsigned char asm_buf[64];
33
34 static char *log_filename = NULL;
35
36 #if TARGET_MSDOS == 32
37 static unsigned char log_buf[63*1024];          // 63KB
38 #else
39 static unsigned char log_buf[30*1024];          // 30KB
40 #endif
41
42 static int log_reopen_counter=0;
43 static unsigned int log_bufi=0;
44 static int log_fd = -1;
45
46 static void do_pause() {
47         unsigned char c;
48         if (isatty(1)) { do { read(0,&c,1); } while (c != 13); }
49 }
50
51 static void log_close();
52 static int log_reopen();
53 static int log_open(const char *path);
54
55 static void log_incname() {
56         unsigned int num;
57         char *n;
58
59         if (log_filename == NULL)
60                 return;
61
62         n = log_filename;
63         while (*n && n[1] != 0) n++; // scan until n = last char
64         if (*n == 0) return;
65
66         num = ++log_reopen_counter;
67
68         do {
69                 *n = ((char)(num % 10U)) + '0';
70                 num /= 10U;
71                 n--;
72                 if (n < log_filename) break;
73                 if (*n == '.') break;
74         } while (num != 0U);
75 }
76
77 static void log_flush() {
78         if (log_fd >= 0 && log_bufi != 0) {
79                 unsigned int wd,wr,wo=0;
80
81                 do {
82                         assert(wo < log_bufi);
83                         wr = log_bufi - wo;
84                         wd = write(log_fd,log_buf+wo,wr);
85                         if (/*another way to check for wd == -1*/wd > sizeof(log_buf)) wd = 0;
86
87                         // note what we could write
88                         if (wd > 0) wo += wd;
89
90                         if (wd < wr) {
91                                 // make sure DOS flushes to disk
92                                 if (log_fd >= 0) {
93                                         close(log_fd);
94                                         log_fd = -1;
95                                 }
96
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");
104                                         do_pause();
105
106                                         log_incname();
107                                         if (!log_reopen()) {
108                                                 printf("Unable to reopen log.\n");
109                                                 exit(1);
110                                         }
111                                 }
112                                 else {
113                                         printf("\nError writing log: %s.\n",strerror(errno));
114                                         exit(1);
115                                 }
116                         }
117                         else {
118                                 break;
119                         }
120                 } while (wo < log_bufi);
121         }
122
123         log_bufi = 0;
124 }
125
126 static void log_lazy_flush(size_t extra) {
127         if (log_fd >= 0 && (extra >= sizeof(log_buf) || log_bufi >= (sizeof(log_buf)-extra)))
128                 log_flush();
129 }
130
131 static void log_close() {
132         log_flush();
133         if (log_fd >= 0) {
134                 close(log_fd);
135                 log_fd = -1;
136         }
137 }
138
139 static int log_reopen() {
140         if (log_fd >= 0) return 1;
141         if (log_filename == NULL) return 0;
142
143         log_fd = open(log_filename,O_WRONLY|O_CREAT|O_TRUNC|O_BINARY,0644);
144         if (log_fd < 0) return 0;
145
146         return 1;
147 }
148
149 static int log_open(const char *path) {
150         log_close();
151
152         if (log_filename) {
153                 free(log_filename);
154                 log_filename = NULL;
155         }
156
157         log_reopen_counter = 0;
158
159         log_fd = open(path,O_WRONLY|O_CREAT|O_TRUNC|O_BINARY,0644);
160         if (log_fd < 0) return 0;
161
162         log_filename = strdup(path);
163         return 1;
164 }
165
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
168         unsigned int i,j;
169
170         if (!grind_init()) {
171                 grind_free();
172                 return 1;
173         }
174         if (!grind_alloc_buf()) {
175                 grind_free();
176                 return 1;
177         }
178         if (!grind_lock_buf()) {
179                 grind_free();
180                 return 1;
181         }
182
183         log_open("gr_add.bin");
184         // header
185         *((uint32_t*)(log_buf+log_bufi)) = 0x444E5247;                  // 'GRND'
186         log_bufi += 4;
187         *((uint32_t*)(log_buf+log_bufi)) = 0x77444441;                  // 'ADDw'
188         log_bufi += 4;
189         *((uint8_t*)(log_buf+log_bufi)) = sizeof(unsigned int);         // sizeof unsigned int (2 or 4)
190         log_bufi += 1;
191         *((uint8_t*)(log_buf+log_bufi)) = cpu_flags;                    // CPU flags
192         log_bufi += 1;
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);
203
204         log_lazy_flush(32);
205
206         i = min_i;
207         do {
208                 printf("i=%u j=%u..%u",i,min_j,max_j);
209                 fflush(stdout);
210
211                 j = min_j;
212                 do {
213                         grind_buf_ptr_t w = grind_buf;
214
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
221
222 //                      *w++ = GRIND_INT3_INS;                                                  // INT3
223
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)
228
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>
232
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
241
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
246
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
251
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
256
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
265
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
270
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
275
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
280
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
286
287                         // SANITY CHECK
288                         if (w > (grind_buf + grind_buf_size)) {
289                                 printf("<--BUFFER OVERRUN\n");
290                                 grind_free();
291                                 return 1;
292                         }
293
294                         // EXECUTE IT
295                         if (!grind_execute_buf()) {
296                                 printf("<--FAIL\n");
297                                 grind_free();
298                                 return 1;
299                         }
300
301                         // sanity check
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)));
306                         }
307
308                         // log results
309                         log_lazy_flush(64);
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);
324                         // log entry finish
325                         log_lazy_flush(16);
326                 } while ((j++) != max_j);
327
328                 printf("\x0D");
329                 fflush(stdout);
330         } while ((i++) != max_i);
331
332         grind_unlock_buf();
333         grind_free_buf();
334         grind_free();
335         log_flush();
336         return 0;
337 }
338
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
341         unsigned int i,j;
342
343         if (!grind_init()) {
344                 grind_free();
345                 return 1;
346         }
347         if (!grind_alloc_buf()) {
348                 grind_free();
349                 return 1;
350         }
351         if (!grind_lock_buf()) {
352                 grind_free();
353                 return 1;
354         }
355
356         log_open("gr_sub.bin");
357         // header
358         *((uint32_t*)(log_buf+log_bufi)) = 0x444E5247;                  // 'GRND'
359         log_bufi += 4;
360         *((uint32_t*)(log_buf+log_bufi)) = 0x77425553;                  // 'SUBw'
361         log_bufi += 4;
362         *((uint8_t*)(log_buf+log_bufi)) = sizeof(unsigned int);         // sizeof unsigned int (2 or 4)
363         log_bufi += 1;
364         *((uint8_t*)(log_buf+log_bufi)) = cpu_flags;                    // CPU flags
365         log_bufi += 1;
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);
376
377         log_lazy_flush(32);
378
379         i = min_i;
380         do {
381                 printf("i=%u j=%u..%u",i,min_j,max_j);
382                 fflush(stdout);
383
384                 j = min_j;
385                 do {
386                         grind_buf_ptr_t w = grind_buf;
387
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
394
395 //                      *w++ = GRIND_INT3_INS;                                                  // INT3
396
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)
401
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>
405
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
414
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
419
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
424
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
429
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
438
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
443
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
448
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
453
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
459
460                         // SANITY CHECK
461                         if (w > (grind_buf + grind_buf_size)) {
462                                 printf("<--BUFFER OVERRUN\n");
463                                 grind_free();
464                                 return 1;
465                         }
466
467                         // EXECUTE IT
468                         if (!grind_execute_buf()) {
469                                 printf("<--FAIL\n");
470                                 grind_free();
471                                 return 1;
472                         }
473
474                         // sanity check
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)));
479                         }
480
481                         // log results
482                         log_lazy_flush(64);
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);
497                         // log entry finish
498                         log_lazy_flush(16);
499                 } while ((j++) != max_j);
500
501                 printf("\x0D");
502                 fflush(stdout);
503         } while ((i++) != max_i);
504
505         grind_unlock_buf();
506         grind_free_buf();
507         grind_free();
508         log_flush();
509         return 0;
510 }
511
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
514         unsigned int i,j;
515
516         if (!grind_init()) {
517                 grind_free();
518                 return 1;
519         }
520         if (!grind_alloc_buf()) {
521                 grind_free();
522                 return 1;
523         }
524         if (!grind_lock_buf()) {
525                 grind_free();
526                 return 1;
527         }
528
529         log_open("gr_mul.bin");
530         // header
531         *((uint32_t*)(log_buf+log_bufi)) = 0x444E5247;                  // 'GRND'
532         log_bufi += 4;
533         *((uint32_t*)(log_buf+log_bufi)) = 0x774C554D;                  // 'MULw'
534         log_bufi += 4;
535         *((uint8_t*)(log_buf+log_bufi)) = sizeof(unsigned int);         // sizeof unsigned int (2 or 4)
536         log_bufi += 1;
537         *((uint8_t*)(log_buf+log_bufi)) = cpu_flags;                    // CPU flags
538         log_bufi += 1;
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);
549
550         log_lazy_flush(32);
551
552         i = min_i;
553         do {
554                 printf("i=%u j=%u..%u",i,min_j,max_j);
555                 fflush(stdout);
556
557                 j = min_j;
558                 do {
559                         grind_buf_ptr_t w = grind_buf;
560
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
569
570 //                      *w++ = GRIND_INT3_INS;                                                  // INT3
571
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)
577
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>
581
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
590
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
595
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
602
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
607
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
616
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
621
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
628
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
633
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
640
641                         // SANITY CHECK
642                         if (w > (grind_buf + grind_buf_size)) {
643                                 printf("<--BUFFER OVERRUN\n");
644                                 grind_free();
645                                 return 1;
646                         }
647
648                         // EXECUTE IT
649                         if (!grind_execute_buf()) {
650                                 printf("<--FAIL\n");
651                                 grind_free();
652                                 return 1;
653                         }
654
655                         // sanity check
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)));
661                         }
662
663                         // log results
664                         log_lazy_flush(64);
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);
681                         // log entry finish
682                         log_lazy_flush(16);
683                 } while ((j++) != max_j);
684
685                 printf("\x0D");
686                 fflush(stdout);
687         } while ((i++) != max_i);
688
689         grind_unlock_buf();
690         grind_free_buf();
691         grind_free();
692         log_flush();
693         return 0;
694 }
695
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
698         unsigned int i,j;
699
700         if (!grind_init()) {
701                 grind_free();
702                 return 1;
703         }
704         if (!grind_alloc_buf()) {
705                 grind_free();
706                 return 1;
707         }
708         if (!grind_lock_buf()) {
709                 grind_free();
710                 return 1;
711         }
712
713         log_open("gr_div.bin");
714         // header
715         *((uint32_t*)(log_buf+log_bufi)) = 0x444E5247;                  // 'GRND'
716         log_bufi += 4;
717         *((uint32_t*)(log_buf+log_bufi)) = 0x77564944;                  // 'DIVw'
718         log_bufi += 4;
719         *((uint8_t*)(log_buf+log_bufi)) = sizeof(unsigned int);         // sizeof unsigned int (2 or 4)
720         log_bufi += 1;
721         *((uint8_t*)(log_buf+log_bufi)) = cpu_flags;                    // CPU flags
722         log_bufi += 1;
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);
733
734         log_lazy_flush(32);
735
736         i = min_i;
737         do {
738                 printf("i=%u j=%u..%u",i,min_j,max_j);
739                 fflush(stdout);
740
741                 j = min_j;
742                 do {
743                         grind_buf_ptr_t w = grind_buf;
744
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
753
754                         // do NOT divide by zero!
755                         if (j != 0) {
756 //                      *w++ = GRIND_INT3_INS;                                                  // INT3
757
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)
764
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>
768
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
777
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
782
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
790
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
795
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
804
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
809
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
817
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
822
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
830
831                         // SANITY CHECK
832                         if (w > (grind_buf + grind_buf_size)) {
833                                 printf("<--BUFFER OVERRUN\n");
834                                 grind_free();
835                                 return 1;
836                         }
837
838                         // EXECUTE IT
839                         if (!grind_execute_buf()) {
840                                 printf("<--FAIL\n");
841                                 grind_free();
842                                 return 1;
843                         }
844
845                         // sanity check
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)));
851                         }
852                         }//end j != 0
853
854                         // log results
855                         log_lazy_flush(64);
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);
872                         // log entry finish
873                         log_lazy_flush(16);
874                 } while ((j++) != max_j);
875
876                 printf("\x0D");
877                 fflush(stdout);
878         } while ((i++) != max_i);
879
880         grind_unlock_buf();
881         grind_free_buf();
882         grind_free();
883         log_flush();
884         return 0;
885 }
886
887 int main() {
888         cpu_probe();
889
890         printf("Testing ADDw x+y (%u <= x <= %u)+(%u <= y <= %u)\n",min_i,max_i,min_j,max_j);
891         grind_ADDw();
892         log_close();
893
894         printf("Testing SUBw x-y (%u <= x <= %u)+(%u <= y <= %u)\n",min_i,max_i,min_j,max_j);
895         grind_SUBw();
896         log_close();
897
898         printf("Testing MULw x*y (%u <= x <= %u)+(%u <= y <= %u)\n",min_i,max_i,min_j,max_j);
899         grind_MULw();
900         log_close();
901
902         printf("Testing DIVw x*y (%u <= x <= %u)+(%u <= y <= %u)\n",min_i,max_i,min_j,max_j);
903         grind_DIVw();
904         log_close();
905         return 0;
906 }
907