a65aedf80ebf8e0a2f99e65ab28ec9bcca9a2aeb
[reactos.git] / lib / 3rdparty / softx86 / softx86 / softx86.c
1 /*
2 * softx86.c
3 *
4 * Copyright (C) 2003, 2004 Jonathan Campbell <jcampbell@mdjk.com>
5 *
6 * Softx86 library API.
7 *
8 * Initialization, de-initialization, register modification, and default
9 * routines for callbacks (in case they weren't set by the host app).
10 *
11 * Internal to this library, there are also functions to take care of
12 * fetching the current opcode (as referred to by CS:IP), fetching
13 * the current opcode for the decompiler (as referred to by a separate
14 * pair CS:IP), and pushing/popping data to/from the stack (SS:SP).
15 *
16 ***********************************************************************************
17 * This program is free software; you can redistribute it and/or
18 * modify it under the terms of the GNU General Public License
19 * as published by the Free Software Foundation; either version 2
20 * of the License, or (at your option) any later version.
21 *
22 * This program is distributed in the hope that it will be useful,
23 * but WITHOUT ANY WARRANTY; without even the implied warranty of
24 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25 * GNU General Public License for more details.
26 *
27 * You should have received a copy of the GNU General Public License
28 * along with this program; if not, write to the Free Software
29 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
30 ************************************************************************************/
31
32 #include <softx86.h>
33 #include <malloc.h>
34 #include <memory.h>
35 #include <string.h>
36 #include <stdio.h>
37 #include "optable.h"
38
39 /* softx86_setsegment(context,segid,val)
40 Sets a segment register and all hidden register information */
41 int softx86_setsegval(softx86_ctx* ctx,int sreg_id,sx86_udword x)
42 {
43 if (sreg_id > 7 || sreg_id < 0) return 0;
44
45 /* TODO: In 286/386 protected mode fetch limit from GDT/LDT */
46 ctx->state->segment_reg[sreg_id].val = x;
47 ctx->state->segment_reg[sreg_id].cached_linear = SEGMENT_TO_LINEAR(x);
48 ctx->state->segment_reg[sreg_id].cached_limit = 0xFFFF;
49
50 return 1; /* success */
51 }
52
53 /* softx86_reset(context)
54 Resets a CPU
55
56 return value:
57 0 = failed
58 1 = success */
59 int softx86_reset(softx86_ctx* ctx)
60 {
61 if (!ctx) return 0;
62
63 if (ctx->__private->level >= SX86_CPULEVEL_80286)
64 ctx->__private->addr_mask = 0xFFFFFF; /* 80286 24-bit addressing */
65 else
66 ctx->__private->addr_mask = 0xFFFFF; /* 8086/8088/80186 20-bit addressing */
67
68 ctx->state->general_reg[SX86_REG_AX].val = 0;
69 ctx->state->general_reg[SX86_REG_BX].val = 0;
70 ctx->state->general_reg[SX86_REG_CX].val = 0;
71 ctx->state->general_reg[SX86_REG_DX].val = 0;
72 ctx->state->general_reg[SX86_REG_SI].val = 0;
73 ctx->state->general_reg[SX86_REG_DI].val = 0;
74 ctx->state->general_reg[SX86_REG_SP].val = 0;
75 ctx->state->general_reg[SX86_REG_BP].val = 0;
76 ctx->state->reg_flags.val = SX86_CPUFLAG_RESERVED_01;
77 softx86_setsegval(ctx,SX86_SREG_DS,0xF000);
78 softx86_setsegval(ctx,SX86_SREG_ES,0xF000);
79 softx86_setsegval(ctx,SX86_SREG_SS,0xF000);
80
81 ctx->__private->ptr_regs_8reg[0] = (sx86_ubyte*)(&ctx->state->general_reg[SX86_REG_AX].b.lo); // AL
82 ctx->__private->ptr_regs_8reg[1] = (sx86_ubyte*)(&ctx->state->general_reg[SX86_REG_CX].b.lo); // CL
83 ctx->__private->ptr_regs_8reg[2] = (sx86_ubyte*)(&ctx->state->general_reg[SX86_REG_DX].b.lo); // DL
84 ctx->__private->ptr_regs_8reg[3] = (sx86_ubyte*)(&ctx->state->general_reg[SX86_REG_BX].b.lo); // BL
85 ctx->__private->ptr_regs_8reg[4] = (sx86_ubyte*)(&ctx->state->general_reg[SX86_REG_AX].b.hi); // AH
86 ctx->__private->ptr_regs_8reg[5] = (sx86_ubyte*)(&ctx->state->general_reg[SX86_REG_CX].b.hi); // CH
87 ctx->__private->ptr_regs_8reg[6] = (sx86_ubyte*)(&ctx->state->general_reg[SX86_REG_DX].b.hi); // DH
88 ctx->__private->ptr_regs_8reg[7] = (sx86_ubyte*)(&ctx->state->general_reg[SX86_REG_BX].b.hi); // BH
89
90 /* initial CPU instruction pointer in BIOS area on older machines: 0xF000:0xFFF0 (as far as I know) */
91 softx86_setsegval(ctx,SX86_SREG_CS,0xF000);
92 ctx->state->reg_ip = 0xFFF0;
93 ctx->state->int_hw_flag = 0;
94 ctx->state->int_nmi = 0;
95
96 /* switch on/off bugs */
97 ctx->bugs->preemptible_after_prefix = (ctx->__private->level <= SX86_CPULEVEL_8086)?1:0;
98 ctx->bugs->decrement_sp_before_store = (ctx->__private->level <= SX86_CPULEVEL_80186)?1:0;
99 ctx->bugs->mask_5bit_shiftcount = (ctx->__private->level >= SX86_CPULEVEL_80286)?1:0;
100
101 /* CPU mode flags */
102 ctx->state->reg_cr0 = 0;
103
104 /* opcode table */
105 ctx->__private->opcode_table = (void*)(&optab8086);
106 ctx->__private->opcode_table_sub_0Fh = (void*)(&optab8086_0Fh);
107
108 /* we were just reset */
109 ctx->callbacks->on_reset(ctx);
110
111 return 1; /* success */
112 }
113
114 int softx86_getversion(int *major,int *minor,int *subminor)
115 {
116 if (!minor || !major || !subminor) return 0;
117
118 *major = SOFTX86_VERSION_HI;
119 *minor = SOFTX86_VERSION_LO;
120 *subminor = SOFTX86_VERSION_SUBLO;
121 return 1;
122 }
123
124 /* softx86_init(context)
125 Initialize a CPU context structure.
126
127 return value:
128 0 = failed
129 1 = success
130 2 = beta development advisory (CPU level emulation not quite stable) */
131 int softx86_init(softx86_ctx* ctx,int level)
132 {
133 int ret;
134
135 ret=1;
136 if (!ctx) return 0;
137 if (level > SX86_CPULEVEL_80286) return 0; /* we currently support up to the 80286 */
138 if (level < 0) return 0; /* apparently the host wants an 80(-1)86? :) */
139 if (level > SX86_CPULEVEL_8086) ret=2; /* 80186 or higher emulation is not stable yet */
140
141 /* set up pointers */
142 ctx->__private = (softx86_internal*)malloc(sizeof(softx86_internal));
143 ctx->bugs = (softx86_bugs*)malloc(sizeof(softx86_bugs));
144 ctx->callbacks = (softx86_callbacks*)malloc(sizeof(softx86_callbacks));
145 ctx->state = (softx86_cpustate*)malloc(sizeof(softx86_cpustate));
146 if ((!ctx->__private) || (!ctx->bugs) || (!ctx->callbacks) || (!ctx->state)) {
147 softx86_free(ctx);
148 return 0;
149 }
150
151 /* store settings */
152 ctx->__private->level = level;
153
154 /* store version in the structure */
155 ctx->version_hi = SOFTX86_VERSION_HI;
156 ctx->version_lo = SOFTX86_VERSION_LO;
157 ctx->version_sublo = SOFTX86_VERSION_SUBLO;
158
159 /* default callbacks */
160 ctx->callbacks->on_read_io = softx86_step_def_on_read_io;
161 ctx->callbacks->on_read_memory = softx86_step_def_on_read_memory;
162 ctx->callbacks->on_write_io = softx86_step_def_on_write_io;
163 ctx->callbacks->on_write_memory = softx86_step_def_on_write_memory;
164 ctx->callbacks->on_hw_int = softx86_step_def_on_hw_int;
165 ctx->callbacks->on_hw_int_ack = softx86_step_def_on_hw_int_ack;
166 ctx->callbacks->on_sw_int = softx86_step_def_on_sw_int;
167 ctx->callbacks->on_idle_cycle = softx86_step_def_on_idle_cycle;
168 ctx->callbacks->on_nmi_int = softx86_step_def_on_nmi_int;
169 ctx->callbacks->on_nmi_int_ack = softx86_step_def_on_nmi_int_ack;
170 ctx->callbacks->on_fpu_opcode_dec = softx86_step_def_on_fpu_opcode_dec;
171 ctx->callbacks->on_fpu_opcode_exec = softx86_step_def_on_fpu_opcode_exec;
172 ctx->callbacks->on_reset = softx86_step_def_on_reset;
173
174 /* default pointers */
175 ctx->ref_softx87_ctx = NULL;
176
177 /* now reset */
178 if (!softx86_reset(ctx)) return 0;
179
180 return ret; /* success */
181 }
182
183 /* softx86_free(context)
184 Free a CPU context structure */
185 int softx86_free(softx86_ctx* ctx)
186 {
187 if (!ctx) return 0;
188 if (ctx->__private) free(ctx->__private);
189 if (ctx->bugs) free(ctx->bugs);
190 if (ctx->callbacks) free(ctx->callbacks);
191 if (ctx->state) free(ctx->state);
192 ctx->__private = NULL;
193 ctx->bugs = NULL;
194 ctx->callbacks = NULL;
195 ctx->state = NULL;
196 return 1; /* success */
197 }
198
199 /* fetch byte at executioneer CS:IP, increment pointer */
200 sx86_ubyte softx86_fetch_exec_byte(softx86_ctx* ctx)
201 {
202 sx86_ubyte opcode;
203
204 if (!ctx) return 0;
205
206 softx86_fetch(ctx,NULL,ctx->state->segment_reg[SX86_SREG_CS].cached_linear+ctx->state->reg_ip,&opcode,1);
207 ctx->state->reg_ip++;
208 /* TODO: If IP passes 0xFFFF generate an exception */
209
210 return opcode;
211 }
212
213 /* fetch byte at decompiler CS:IP, increment pointer */
214 sx86_ubyte softx86_fetch_dec_byte(softx86_ctx* ctx)
215 {
216 sx86_ubyte opcode;
217
218 if (!ctx) return 0;
219
220 softx86_fetch(ctx,NULL,SEGMENT_TO_LINEAR(ctx->state->reg_cs_decompiler)+(ctx->state->reg_ip_decompiler),&opcode,1);
221 ctx->state->reg_ip_decompiler++;
222 return opcode;
223 }
224
225 /* retrieve a word value from the stack pointer SS:SP */
226 sx86_uword softx86_stack_popw(softx86_ctx* ctx)
227 {
228 sx86_uword data;
229
230 if (!ctx) return 0;
231
232 /* TODO: If SP == 0xFFFF generate an exception */
233 softx86_fetch(ctx,NULL,ctx->state->segment_reg[SX86_SREG_SS].cached_linear+ctx->state->general_reg[SX86_REG_SP].w.lo,&data,2);
234 SWAP_WORD_FROM_LE(data);
235 ctx->state->general_reg[SX86_REG_SP].w.lo += 2;
236 /* TODO: If SP passes 0xFFFF generate an exception */
237
238 return data;
239 }
240
241 /* discard n bytes from stack pointer SS:SP */
242 void softx86_stack_discard_n(softx86_ctx* ctx,int bytez)
243 {
244 if (!ctx) return;
245
246 ctx->state->general_reg[SX86_REG_SP].w.lo += bytez;
247 /* TODO: If SP passes 0xFFFF generate an exception */
248 }
249
250 /* adds n bytes to stack pointer SS:SP */
251 void softx86_stack_add_n(softx86_ctx* ctx,int bytez)
252 {
253 if (!ctx) return;
254
255 ctx->state->general_reg[SX86_REG_SP].w.lo -= bytez;
256 /* TODO: If SP passes 0xFFFF generate an exception */
257 }
258
259 /* store a word value to the stack pointer SS:SP */
260 void softx86_stack_pushw(softx86_ctx* ctx,sx86_uword data)
261 {
262 SWAP_WORD_TO_LE(data);
263 /* TODO: If SP == 0x0001 generate an exception */
264 ctx->state->general_reg[SX86_REG_SP].w.lo -= 2;
265 softx86_write(ctx,NULL,ctx->state->segment_reg[SX86_SREG_SS].cached_linear+ctx->state->general_reg[SX86_REG_SP].w.lo,&data,2);
266 }
267
268 /* set stack pointer SS:SP */
269 int softx86_set_stack_ptr(softx86_ctx* ctx,sx86_udword ss,sx86_udword sp)
270 {
271 if (!ctx) return 0;
272
273 /* TODO: Check SS:SP for validity */
274 ctx->state->general_reg[SX86_REG_SP].w.lo = sp;
275 softx86_setsegval(ctx,SX86_SREG_SS,ss);
276
277 return 1;
278 }
279
280 /* set executioneer CS:IP */
281 int softx86_set_instruction_ptr(softx86_ctx* ctx,sx86_udword cs,sx86_udword ip)
282 {
283 if (!ctx) return 0;
284
285 /* TODO: Check CS:IP for validity */
286 ctx->state->reg_ip = ip;
287 softx86_setsegval(ctx,SX86_SREG_CS,cs);
288
289 return 1;
290 }
291
292 /* set executioneer IP (not CS). used for emulating near jumps. */
293 int softx86_set_near_instruction_ptr(softx86_ctx* ctx,sx86_udword ip)
294 {
295 if (!ctx) return 0;
296
297 /* TODO: Check IP for validity */
298 ctx->state->reg_ip = ip;
299
300 return 1;
301 }
302
303 /* set decompiler CS:IP */
304 int softx86_set_instruction_dec_ptr(softx86_ctx* ctx,sx86_udword cs,sx86_udword ip)
305 {
306 if (!ctx) return 0;
307
308 /* TODO: Check CS:IP for validity */
309 ctx->state->reg_ip_decompiler = ip;
310 ctx->state->reg_cs_decompiler = cs;
311
312 return 1;
313 }
314
315 /* create a stack frame for simple near procedural calls and set the instruction pointer (if ip != NULL) */
316 int softx86_make_simple_near_call(softx86_ctx* ctx,sx86_udword* ip)
317 {
318 if (!ctx) return 0;
319
320 softx86_stack_pushw(ctx,ctx->state->reg_ip);
321 if (ip != NULL) return softx86_set_near_instruction_ptr(ctx,*ip);
322 return 1;
323 }
324
325 /* create a stack frame for simple far procedural calls and set the instruction pointer (if ip != NULL) */
326 int softx86_make_simple_far_call(softx86_ctx* ctx,sx86_udword* cs,sx86_udword* ip)
327 {
328 if (!ctx) return 0;
329
330 softx86_stack_pushw(ctx,ctx->state->segment_reg[SX86_SREG_CS].val);
331 softx86_stack_pushw(ctx,ctx->state->reg_ip);
332 if (cs != NULL && ip != NULL) return softx86_set_instruction_ptr(ctx,*cs,*ip);
333 return 1;
334 }
335
336 /* create a stack frame for simple interrupt procedural calls and set the instruction pointer (if ip != NULL) */
337 int softx86_make_simple_interrupt_call(softx86_ctx* ctx,sx86_udword* cs,sx86_udword* ip)
338 {
339 if (!ctx) return 0;
340
341 softx86_stack_pushw(ctx,ctx->state->reg_flags.w.lo);
342 softx86_stack_pushw(ctx,ctx->state->segment_reg[SX86_SREG_CS].val);
343 softx86_stack_pushw(ctx,ctx->state->reg_ip);
344 if (cs != NULL && ip != NULL) return softx86_set_instruction_ptr(ctx,*cs,*ip);
345 return 1;
346 }
347
348 /* retrieves an interrupt vector */
349 int softx86_get_intvect(softx86_ctx* ctx,sx86_ubyte i,sx86_uword *seg,sx86_uword *ofs)
350 {
351 sx86_uword _seg,_ofs;
352 sx86_udword o;
353
354 if (!ctx) return 0;
355
356 /* obtain the interrupt vector */
357 o = (i<<2);
358 softx86_fetch(ctx,NULL,o,(void*)(&_ofs),2);
359 SWAP_WORD_FROM_LE(_ofs);
360 *ofs = _ofs;
361
362 o += 2;
363 softx86_fetch(ctx,NULL,o,(void*)(&_seg),2);
364 SWAP_WORD_FROM_LE(_seg);
365 *seg = _seg;
366
367 return 1;
368 }
369
370 /* sets an interrupt vector */
371 int softx86_set_intvect(softx86_ctx* ctx,sx86_ubyte i,sx86_uword seg,sx86_uword ofs)
372 {
373 sx86_udword o;
374
375 if (!ctx) return 0;
376
377 /* obtain the interrupt vector */
378 o = (i<<2);
379 SWAP_WORD_TO_LE(ofs);
380 softx86_write(ctx,NULL,o,(void*)(&ofs),2);
381
382 o += 2;
383 SWAP_WORD_TO_LE(seg);
384 softx86_write(ctx,NULL,o,(void*)(&seg),2);
385
386 return 1;
387 }
388
389 /* create interrupt frame and manipulate registers */
390 void softx86_go_int_frame(softx86_ctx* ctx,sx86_ubyte i)
391 {
392 sx86_uword seg,ofs;
393
394 /* get interrupt vector */
395 if (!softx86_get_intvect(ctx,i,&seg,&ofs)) return;
396
397 /* save old address */
398 softx86_stack_pushw(ctx,ctx->state->reg_flags.val);
399 softx86_stack_pushw(ctx,ctx->state->segment_reg[SX86_SREG_CS].val);
400 softx86_stack_pushw(ctx,ctx->state->reg_ip);
401
402 /* disable interrupts */
403 ctx->state->reg_flags.val &= ~SX86_CPUFLAG_INTENABLE;
404
405 /* go! */
406 if (!softx86_set_instruction_ptr(ctx,seg,ofs)) return;
407 }
408
409 /* enable/disable emulation of specific bugs. */
410 int softx86_setbug(softx86_ctx* ctx,sx86_udword bug_id,sx86_ubyte on_off)
411 {
412 if (bug_id == SX86_BUG_PREEMPTIBLE_AFTER_PREFIX) {
413 ctx->bugs->preemptible_after_prefix = on_off;
414 return 1;
415 }
416 else if (bug_id == SX86_BUG_SP_DECREMENT_BEFORE_STORE) {
417 ctx->bugs->decrement_sp_before_store = on_off;
418 }
419
420 return 0;
421 }
422
423 /* simulate external hardware interrupt from host app. */
424 int softx86_ext_hw_signal(softx86_ctx* ctx,sx86_ubyte i)
425 {
426 if (!ctx) return 0;
427
428 /* make sure the poor CPU isn't getting deluged by interrupts.
429 as far as I know, every system using the x86 with an interrupt
430 system has some sort of moderator for the #int line. The x86 PC
431 platform for instance, has a "programmable interrupt controller"
432 that is responsible for handling 16 interrupt signals (IRQ 0
433 thru 15) and presenting them one at a time to the CPU. */
434 if (ctx->state->int_hw_flag) return 0;
435
436 ctx->callbacks->on_hw_int(ctx,i);
437 ctx->state->int_hw_flag = 1;
438 ctx->state->int_hw = i;
439
440 return 1;
441 }
442
443 /* simulate external hardware NMI interrupt from host app. */
444 int softx86_ext_hw_nmi_signal(softx86_ctx* ctx)
445 {
446 if (!ctx) return 0;
447
448 /* only one #NMI at a time! */
449 /* TODO: Is the #NMI interrupt number fixed or variable? */
450 if (ctx->state->int_nmi) return 0;
451
452 ctx->state->int_nmi = 1;
453 ctx->callbacks->on_nmi_int(ctx);
454
455 return 1;
456 }
457
458 /* simulate internal software interrupt. */
459 int softx86_int_sw_signal(softx86_ctx* ctx,sx86_ubyte i)
460 {
461 if (!ctx) return 0;
462
463 ctx->callbacks->on_sw_int(ctx,i);
464 softx86_go_int_frame(ctx,i);
465
466 return 1;
467 }
468
469 /* INTERNAL USE: used by this library to send acknowledgement back
470 to host application for the given interrupt signal. */
471 int softx86_ext_hw_ack(softx86_ctx* ctx)
472 {
473 if (!ctx) return 0;
474 if (!ctx->state->int_hw_flag) return 0;
475
476 ctx->callbacks->on_hw_int_ack(ctx,ctx->state->int_hw);
477 ctx->state->int_hw_flag = 0;
478 ctx->state->int_hw = 0;
479
480 return 1;
481 }
482
483 /* INTERNAL USE: used by this library to send acknowledgement back
484 to host application for the given interrupt signal. */
485 int softx86_ext_hw_nmi_ack(softx86_ctx* ctx)
486 {
487 if (!ctx) return 0;
488 if (!ctx->state->int_nmi) return 0;
489
490 ctx->callbacks->on_nmi_int_ack(ctx);
491 ctx->state->int_nmi = 0;
492
493 return 1;
494 }
495
496 /* softx86_step(context)
497 Executes ONE instruction at CS:IP
498
499 return value:
500 0 = failed
501 1 = success */
502 int softx86_step(softx86_ctx* ctx)
503 {
504 Sfx86OpcodeTable* sop;
505 sx86_ubyte opcode;
506 int lp,x,restart,err,count;
507 int can_hwint;
508
509 if (!ctx) return 0;
510 sop = (Sfx86OpcodeTable*)(ctx->__private->opcode_table);
511 if (!sop) return 0;
512
513 ctx->state->is_segment_override = 0;
514 ctx->state->segment_override = 0;
515 ctx->state->rep_flag = 0;
516 ctx->state->reg_cs_exec_initial = ctx->state->segment_reg[SX86_SREG_CS].val;
517 ctx->state->reg_ip_exec_initial = ctx->state->reg_ip;
518
519 lp = 1;
520 err = 0;
521 count = 16;
522 restart = 0;
523 can_hwint = 1;
524 while (lp && count-- > 0) {
525 /* if now is a good time to allow an interrupt and interrupts enabled, so be it */
526 if (can_hwint || ctx->bugs->preemptible_after_prefix) {
527 if (ctx->state->int_nmi) { /* #NMI pin has priority */
528 softx86_go_int_frame(ctx,2);
529 softx86_ext_hw_nmi_ack(ctx);
530 }
531 else if (ctx->state->reg_flags.val & SX86_CPUFLAG_INTENABLE) {
532 if (ctx->state->int_hw_flag) {
533 softx86_go_int_frame(ctx,ctx->state->int_hw);
534 softx86_ext_hw_ack(ctx);
535 }
536 }
537
538 can_hwint=0;
539 }
540
541 /* fetch opcode */
542 opcode = softx86_fetch_exec_byte(ctx);
543 /* execute opcode */
544 x = sop->table[opcode].exec(opcode,ctx);
545 /* what happened? */
546 if (x == 0) { /* opcode not recognized? stop! */
547 lp = 0;
548 restart = 1;
549 err = 1;
550 }
551 else if (x == 1) { /* opcode recognized? */
552 lp = 0;
553 }
554 else if (x == 2) { /* opcode recognized but more parsing needed (i.e. instruction prefix)? */
555 }
556 else if (x == 3) { /* opcode recognized, looping action in progress do not advance (i.e. REP MOVSB or HLT/WAIT)? */
557 restart = 1;
558 lp = 0;
559 }
560 else { /* this indicates a bug in this library */
561 lp = 0;
562 restart = 1; /* huh? */
563 err = 1;
564 }
565 }
566
567 if (count <= 0) {
568 err = 1;
569 restart = 1;
570 }
571
572 if (restart) {
573 ctx->state->segment_reg[SX86_SREG_CS].val = ctx->state->reg_cs_exec_initial;
574 ctx->state->reg_ip = ctx->state->reg_ip_exec_initial;
575 }
576
577 return !err; /* success */
578 }
579
580 /* softx86_decompile(context)
581 Decompiles ONE instruction at decoder CS:IP
582
583 return value:
584 0 = failed
585 1 = success */
586 int softx86_decompile(softx86_ctx* ctx,char asmbuf[256])
587 {
588 Sfx86OpcodeTable* sop;
589 sx86_ubyte opcode;
590 int lp,x,err,count,asmx;
591 char buf[256];
592
593 if (!ctx) return 0;
594 sop = (Sfx86OpcodeTable*)(ctx->__private->opcode_table);
595 if (!sop) return 0;
596
597 lp = 1;
598 err = 0;
599 asmx = 0;
600 asmbuf[0] = 0;
601 count = 16;
602 while (lp && count-- > 0) {
603 /* fetch opcode */
604 opcode = softx86_fetch_dec_byte(ctx);
605 /* execute opcode */
606 x = sop->table[opcode].dec(opcode,ctx,buf);
607 /* what happened? */
608 if (x == 0) { /* opcode not recognized? stop! */
609 lp = 0;
610 err = 1;
611 }
612 else if (x == 1) { /* opcode recognized? */
613 strcpy(asmbuf+asmx,buf);
614 lp = 0;
615 }
616 else if (x == 2) { /* opcode recognized but more parsing needed? */
617 strcpy(asmbuf+asmx,buf); /* this is why asmbuf[] is 256 bytes :) */
618 asmbuf += strlen(asmbuf+asmx);
619 }
620 else { /* this indicates a bug in this library */
621 lp = 0;
622 err = 1;
623 }
624 }
625
626 if (count <= 0) {
627 err = 1;
628 }
629
630 return !err; /* success */
631 }
632
633 /* softx86_decompile_exec_cs_ip(context)
634 Point decompiler instructor ptr to where the executioneer CS:IP is */
635 int softx86_decompile_exec_cs_ip(softx86_ctx* ctx)
636 {
637 if (!ctx) return 0;
638
639 /* set decompiler CS:IP to executioneer CS:IP */
640 ctx->state->reg_cs_decompiler = ctx->state->segment_reg[SX86_SREG_CS].val;
641 ctx->state->reg_ip_decompiler = ctx->state->reg_ip;
642
643 return 1; /* success */
644 }
645
646 /*--------------------------------------------------------------------------------
647 default callbacks
648 --------------------------------------------------------------------------------*/
649
650 void softx86_step_def_on_read_memory(void* _ctx,sx86_udword address,sx86_ubyte *buf,int size)
651 {
652 softx86_ctx *ctx = ((softx86_ctx*)_ctx);
653 if (!ctx || !buf || size < 1) return;
654 memset(buf,0xFF,size);
655 }
656
657 void softx86_step_def_on_read_io(void* _ctx,sx86_udword address,sx86_ubyte *buf,int size)
658 {
659 softx86_ctx *ctx = ((softx86_ctx*)_ctx);
660 if (!ctx || !buf || size < 1) return;
661 memset(buf,0xFF,size);
662 }
663
664 void softx86_step_def_on_write_memory(void* _ctx,sx86_udword address,sx86_ubyte *buf,int size)
665 {
666 softx86_ctx *ctx = ((softx86_ctx*)_ctx);
667 if (!ctx || !buf || size < 1) return;
668 }
669
670 void softx86_step_def_on_write_io(void* _ctx,sx86_udword address,sx86_ubyte *buf,int size)
671 {
672 softx86_ctx *ctx = ((softx86_ctx*)_ctx);
673 if (!ctx || !buf || size < 1) return;
674 }
675
676 void softx86_step_def_on_hw_int(void* _ctx,sx86_ubyte i)
677 {
678 }
679
680 void softx86_step_def_on_sw_int(void* _ctx,sx86_ubyte i)
681 {
682 }
683
684 void softx86_step_def_on_hw_int_ack(void* _ctx,sx86_ubyte i)
685 {
686 }
687
688 void softx86_step_def_on_idle_cycle(void* _ctx)
689 {
690 }
691
692 void softx86_step_def_on_nmi_int(void* _ctx)
693 {
694 }
695
696 void softx86_step_def_on_nmi_int_ack(void* _ctx)
697 {
698 }
699
700 int softx86_step_def_on_fpu_opcode_exec(void* _ctx86,void* _ctx87,sx86_ubyte opcode)
701 {
702 return 0;
703 }
704
705 int softx86_step_def_on_fpu_opcode_dec(void* _ctx86,void* _ctx87,sx86_ubyte opcode,char buf[128])
706 {
707 return 0;
708 }
709
710 void softx86_step_def_on_reset(/* softx86_ctx */ void* _ctx)
711 {
712 }
713
714 /*--------------------------------------------------------------------------------
715 API for CPU itself to fetch data through a cache.
716 --------------------------------------------------------------------------------*/
717 int softx86_fetch(softx86_ctx* ctx,void *reserved,sx86_udword addr,void *_buf,int sz)
718 {
719 sx86_ubyte *buf = (sx86_ubyte*)(_buf);
720 int rsz;
721 sx86_udword raddr;
722
723 if (!ctx || !buf || sz < 1) return 0;
724
725 rsz = sz;
726 raddr = addr;
727
728 /* TODO: fetching from cache can be implemented at this point, filling in by reassigning ratter, buf and rsz. */
729
730 /* save host application the aggrivation of dealing with 32-bit address wrap-arounds */
731 if ((raddr+rsz) > 0 && (raddr+rsz) < rsz) {
732 ctx->callbacks->on_read_memory(ctx,raddr,buf,(sx86_udword)((0x100000000L-raddr)&0xFFFFFFFF));
733 raddr += (sx86_udword)((0x100000000L-raddr)&0xFFFFFFFF);
734 rsz -= (sx86_udword)((0x100000000L-raddr)&0xFFFFFFFF);
735 buf += (sx86_udword)((0x100000000L-raddr)&0xFFFFFFFF);
736 ctx->callbacks->on_read_memory(ctx,raddr,buf,rsz);
737 return 1;
738 }
739
740 ctx->callbacks->on_read_memory(ctx,raddr,buf,rsz);
741
742 return 1;
743 }
744
745 int softx86_write(softx86_ctx* ctx,void *reserved,sx86_udword addr,void *_buf,int sz)
746 {
747 sx86_ubyte *buf = (sx86_ubyte*)(_buf);
748 int rsz;
749 sx86_udword raddr;
750
751 if (!ctx || !buf || sz < 1) return 0;
752
753 rsz = sz;
754 raddr = addr;
755
756 /* TODO: writing to/through the cache can be implemented at this point, filling in by reassigning ratter, buf and rsz. */
757
758 /* save host application the aggrivation of dealing with 32-bit address wrap-arounds */
759 if ((raddr+rsz) > 0 && (raddr+rsz) < rsz) {
760 ctx->callbacks->on_write_memory(ctx,raddr,buf,(sx86_udword)((0x100000000L-raddr)&0xFFFFFFFF));
761 raddr += (sx86_udword)((0x100000000L-raddr)&0xFFFFFFFF);
762 rsz -= (sx86_udword)((0x100000000L-raddr)&0xFFFFFFFF);
763 buf += (sx86_udword)((0x100000000L-raddr)&0xFFFFFFFF);
764 ctx->callbacks->on_write_memory(ctx,raddr,buf,rsz);
765 return 1;
766 }
767
768 ctx->callbacks->on_write_memory(ctx,raddr,buf,rsz);
769
770 return 1;
771 }
772
773 void softx86_bswap2(sx86_ubyte *x)
774 {
775 sx86_ubyte t;
776
777 t=x[0]; x[0]=x[1]; x[1]=t;
778 }
779
780 void softx86_bswap4(sx86_ubyte *x)
781 {
782 sx86_ubyte t;
783
784 t=x[0]; x[0]=x[3]; x[3]=t;
785 t=x[1]; x[1]=x[2]; x[2]=t;
786 }
787
788 /* general purpose mod/reg/rm executioneer helper for LEA.
789
790 this is provided to avoid copy and pasting this source code into the emulation
791 code for *EVERY* instruction.
792
793 ctx = CPU context
794 d32 = 386+ 32-bit data size override
795 mod/reg/rm = mod/reg/rm unpacked byte
796
797 Example of instructions that fit this format:
798
799 LEA AX,[AX+2] (apparently a substitute for add ax,2?)
800 LEA BX,[SP] (seen sometimes as an alternative to mov bx,sp)
801 LEA EBX,[ESI+ECX] (surprisingly, often seen in Win32 code)
802 */
803 void sx86_exec_full_modregrm_lea(softx86_ctx* ctx,sx86_ubyte d32,sx86_ubyte mod,sx86_ubyte reg,sx86_ubyte rm)
804 {
805 if (mod == 3) { /* register <- register */
806 /* TODO: Invalid opcode exception. */
807 }
808 else { /* register <- memory */
809 sx86_uword ofs;
810
811 /* don't calculate segment value because LEA does not fetch memory, it only stores
812 the offset into the destination register */
813
814 /* figure out the memory address */
815 if (mod == 0) {
816 if (rm == 6) {
817 ofs = softx86_fetch_exec_byte(ctx);
818 ofs |= softx86_fetch_exec_byte(ctx)<<8;
819 }
820 else if (rm == 0)
821 ofs = ctx->state->general_reg[SX86_REG_BX].w.lo +
822 ctx->state->general_reg[SX86_REG_SI].w.lo;
823 else if (rm == 1)
824 ofs = ctx->state->general_reg[SX86_REG_BX].w.lo +
825 ctx->state->general_reg[SX86_REG_DI].w.lo;
826 else if (rm == 2)
827 ofs = ctx->state->general_reg[SX86_REG_BP].w.lo +
828 ctx->state->general_reg[SX86_REG_SI].w.lo;
829 else if (rm == 3)
830 ofs = ctx->state->general_reg[SX86_REG_BP].w.lo +
831 ctx->state->general_reg[SX86_REG_DI].w.lo;
832 else if (rm == 4)
833 ofs = ctx->state->general_reg[SX86_REG_SI].w.lo;
834 else if (rm == 5)
835 ofs = ctx->state->general_reg[SX86_REG_DI].w.lo;
836 else if (rm == 7)
837 ofs = ctx->state->general_reg[SX86_REG_BX].w.lo;
838 }
839 else {
840 sx86_uword xx;
841
842 if (rm == 0)
843 ofs = ctx->state->general_reg[SX86_REG_BX].w.lo +
844 ctx->state->general_reg[SX86_REG_SI].w.lo;
845 else if (rm == 1)
846 ofs = ctx->state->general_reg[SX86_REG_BX].w.lo +
847 ctx->state->general_reg[SX86_REG_DI].w.lo;
848 else if (rm == 2)
849 ofs = ctx->state->general_reg[SX86_REG_BP].w.lo +
850 ctx->state->general_reg[SX86_REG_SI].w.lo;
851 else if (rm == 3)
852 ofs = ctx->state->general_reg[SX86_REG_BP].w.lo +
853 ctx->state->general_reg[SX86_REG_DI].w.lo;
854 else if (rm == 4)
855 ofs = ctx->state->general_reg[SX86_REG_SI].w.lo;
856 else if (rm == 5)
857 ofs = ctx->state->general_reg[SX86_REG_DI].w.lo;
858 else if (rm == 6)
859 ofs = ctx->state->general_reg[SX86_REG_BP].w.lo;
860 else if (rm == 7)
861 ofs = ctx->state->general_reg[SX86_REG_BX].w.lo;
862
863 if (mod == 1) {
864 xx = softx86_fetch_exec_byte(ctx);
865 if (xx & 0x80) xx |= 0xFF00;
866 }
867 else {
868 xx = softx86_fetch_exec_byte(ctx);
869 xx |= softx86_fetch_exec_byte(ctx)<<8;
870 }
871
872 ofs = FORCE_WORD_SIZE(ofs + xx);
873 }
874
875 // TODO: For 386+ 32-bit instructions... if (d32) {...}
876 ctx->state->general_reg[reg].w.lo = ofs;
877 }
878 }
879
880 /* general purpose mod/reg/rm executioneer helper for
881 instructions that modify the destination operand.
882
883 this is provided to avoid copy and pasting this source code into the emulation
884 code for *EVERY* instruction.
885
886 ctx = CPU context
887 w16 = 16-bit operand flag
888 d32 = 386+ 32-bit data size override (ignored if w16 == 0)
889 mod/reg/rm = mod/reg/rm unpacked byte
890 op8 = function to call for emulation of instruction, given 8-bit operands "src" and "dst"
891 op16 = function to call for emulation of instruction, given 16-bit operands "src" and "dst"
892 op32 = function to call for emulation of instruction, given 32-bit operands "src" and "dst"
893
894 Example of instructions that fit this format:
895
896 MOV AX,CX
897 MOV WORD PTR [3456h],DX
898 MOV SI,DI
899 MOV BX,WORD PTR [1246h]
900 */
901 void sx86_exec_full_modregrm_rw(softx86_ctx* ctx,sx86_ubyte w16,sx86_ubyte d32,sx86_ubyte mod,sx86_ubyte reg,sx86_ubyte rm,sx86_ubyte opswap,sx86_ubyte (*op8)(softx86_ctx* ctx,sx86_ubyte src,sx86_ubyte val),sx86_uword (*op16)(softx86_ctx* ctx,sx86_uword src,sx86_uword val),sx86_udword (*op32)(softx86_ctx* ctx,sx86_udword src,sx86_udword val))
902 {
903 if (mod == 3) { /* register <-> register */
904 // TODO: For 386+ 32-bit instructions... if (d32) {...}
905 if (w16) {
906 sx86_uword regv,rmv;
907
908 regv = ctx->state->general_reg[reg].w.lo;
909 rmv = ctx->state->general_reg[rm].w.lo;
910
911 if (opswap)
912 ctx->state->general_reg[reg].w.lo =
913 op16(ctx,regv,rmv);
914 else
915 ctx->state->general_reg[rm].w.lo =
916 op16(ctx,rmv,regv);
917 }
918 else {
919 sx86_ubyte regv,rmv;
920
921 regv = *(ctx->__private->ptr_regs_8reg[reg]);
922 rmv = *(ctx->__private->ptr_regs_8reg[rm]);
923
924 if (opswap)
925 *(ctx->__private->ptr_regs_8reg[reg]) =
926 op8(ctx,regv,rmv);
927 else
928 *(ctx->__private->ptr_regs_8reg[rm]) =
929 op8(ctx,rmv,regv);
930 }
931 }
932 else { /* register <-> memory */
933 sx86_uword seg,ofs;
934 sx86_udword lo;
935
936 if (!ctx->state->is_segment_override)
937 /* apparently if BP is used (i.e. [BP+BX]) the stack segment is assumed. */
938 if ((rm == 2 || rm == 3) || (rm == 6 && (mod == 1 || mod == 2)))
939 seg = ctx->state->segment_reg[SX86_SREG_SS].val;
940 else
941 seg = ctx->state->segment_reg[SX86_SREG_DS].val;
942 else
943 seg = ctx->state->segment_override;
944
945 /* figure out the memory address */
946 if (mod == 0) {
947 if (rm == 6) {
948 ofs = softx86_fetch_exec_byte(ctx);
949 ofs |= softx86_fetch_exec_byte(ctx)<<8;
950 }
951 else if (rm == 0)
952 ofs = ctx->state->general_reg[SX86_REG_BX].w.lo +
953 ctx->state->general_reg[SX86_REG_SI].w.lo;
954 else if (rm == 1)
955 ofs = ctx->state->general_reg[SX86_REG_BX].w.lo +
956 ctx->state->general_reg[SX86_REG_DI].w.lo;
957 else if (rm == 2)
958 ofs = ctx->state->general_reg[SX86_REG_BP].w.lo +
959 ctx->state->general_reg[SX86_REG_SI].w.lo;
960 else if (rm == 3)
961 ofs = ctx->state->general_reg[SX86_REG_BP].w.lo +
962 ctx->state->general_reg[SX86_REG_DI].w.lo;
963 else if (rm == 4)
964 ofs = ctx->state->general_reg[SX86_REG_SI].w.lo;
965 else if (rm == 5)
966 ofs = ctx->state->general_reg[SX86_REG_DI].w.lo;
967 else if (rm == 7)
968 ofs = ctx->state->general_reg[SX86_REG_BX].w.lo;
969 }
970 else {
971 sx86_uword xx;
972
973 if (rm == 0)
974 ofs = ctx->state->general_reg[SX86_REG_BX].w.lo +
975 ctx->state->general_reg[SX86_REG_SI].w.lo;
976 else if (rm == 1)
977 ofs = ctx->state->general_reg[SX86_REG_BX].w.lo +
978 ctx->state->general_reg[SX86_REG_DI].w.lo;
979 else if (rm == 2)
980 ofs = ctx->state->general_reg[SX86_REG_BP].w.lo +
981 ctx->state->general_reg[SX86_REG_SI].w.lo;
982 else if (rm == 3)
983 ofs = ctx->state->general_reg[SX86_REG_BP].w.lo +
984 ctx->state->general_reg[SX86_REG_DI].w.lo;
985 else if (rm == 4)
986 ofs = ctx->state->general_reg[SX86_REG_SI].w.lo;
987 else if (rm == 5)
988 ofs = ctx->state->general_reg[SX86_REG_DI].w.lo;
989 else if (rm == 6)
990 ofs = ctx->state->general_reg[SX86_REG_BP].w.lo;
991 else if (rm == 7)
992 ofs = ctx->state->general_reg[SX86_REG_BX].w.lo;
993
994 if (mod == 1) {
995 xx = softx86_fetch_exec_byte(ctx);
996 if (xx & 0x80) xx |= 0xFF00;
997 }
998 else {
999 xx = softx86_fetch_exec_byte(ctx);
1000 xx |= softx86_fetch_exec_byte(ctx)<<8;
1001 }
1002
1003 ofs = FORCE_WORD_SIZE(ofs + xx);
1004 }
1005
1006 // TODO: For 386+ 32-bit instructions... if (d32) {...}
1007 if (w16) {
1008 sx86_uword regv,rmv;
1009
1010 regv = ctx->state->general_reg[reg].w.lo;
1011 lo = sx86_far_to_linear(ctx,seg,ofs);
1012 softx86_fetch(ctx,NULL,lo,&rmv,2);
1013 SWAP_WORD_FROM_LE(rmv);
1014
1015 if (opswap) {
1016 ctx->state->general_reg[reg].w.lo =
1017 op16(ctx,regv,rmv);
1018 }
1019 else {
1020 rmv = op16(ctx,rmv,regv);
1021 SWAP_WORD_TO_LE(rmv);
1022 softx86_write(ctx,NULL,lo,&rmv,2);
1023 }
1024 }
1025 else {
1026 sx86_ubyte regv,rmv;
1027
1028 regv = *(ctx->__private->ptr_regs_8reg[reg]);
1029 lo = sx86_far_to_linear(ctx,seg,ofs);
1030 softx86_fetch(ctx,NULL,lo,&rmv,1);
1031
1032 if (opswap) {
1033 *(ctx->__private->ptr_regs_8reg[reg]) =
1034 op8(ctx,regv,rmv);
1035 }
1036 else {
1037 rmv = op8(ctx,rmv,regv);
1038 softx86_write(ctx,NULL,lo,&rmv,1);
1039 }
1040 }
1041 }
1042 }
1043
1044 /* general purpose mod/reg/rm executioneer helper for
1045 instructions that do not modify the destination operand.
1046
1047 this is provided to avoid copy and pasting this source code into the emulation
1048 code for *EVERY* instruction.
1049
1050 ctx = CPU context
1051 w16 = 16-bit operand flag
1052 d32 = 386+ 32-bit data size override (ignored if w16 == 0)
1053 mod/reg/rm = mod/reg/rm unpacked byte
1054 op8 = function to call for emulation of instruction, given 8-bit operands "src" and "dst"
1055 op16 = function to call for emulation of instruction, given 16-bit operands "src" and "dst"
1056 op32 = function to call for emulation of instruction, given 32-bit operands "src" and "dst"
1057
1058 Example of instructions that fit this format:
1059
1060 TEST AX,CX
1061 TEST WORD PTR [3456h],DX
1062 TEST SI,DI
1063 TEST BX,WORD PTR [1246h]
1064 */
1065 void sx86_exec_full_modregrm_ro(softx86_ctx* ctx,sx86_ubyte w16,sx86_ubyte d32,sx86_ubyte mod,sx86_ubyte reg,sx86_ubyte rm,sx86_ubyte opswap,sx86_ubyte (*op8)(softx86_ctx* ctx,sx86_ubyte src,sx86_ubyte val),sx86_uword (*op16)(softx86_ctx* ctx,sx86_uword src,sx86_uword val),sx86_udword (*op32)(softx86_ctx* ctx,sx86_udword src,sx86_udword val))
1066 {
1067 if (mod == 3) { /* register <-> register */
1068 // TODO: For 386+ 32-bit instructions... if (d32) {...}
1069 if (w16) {
1070 sx86_uword regv,rmv;
1071
1072 regv = ctx->state->general_reg[reg].w.lo;
1073 rmv = ctx->state->general_reg[rm].w.lo;
1074
1075 if (opswap)
1076 op16(ctx,regv,rmv);
1077 else
1078 op16(ctx,rmv,regv);
1079 }
1080 else {
1081 sx86_ubyte regv,rmv;
1082
1083 regv = *(ctx->__private->ptr_regs_8reg[reg]);
1084 rmv = *(ctx->__private->ptr_regs_8reg[rm]);
1085
1086 if (opswap)
1087 op8(ctx,regv,rmv);
1088 else
1089 op8(ctx,rmv,regv);
1090 }
1091 }
1092 else { /* register <-> memory */
1093 sx86_uword seg,ofs;
1094 sx86_udword lo;
1095
1096 if (!ctx->state->is_segment_override)
1097 /* apparently if BP is used (i.e. [BP+BX]) the stack segment is assumed. */
1098 if ((rm == 2 || rm == 3) || (rm == 6 && (mod == 1 || mod == 2)))
1099 seg = ctx->state->segment_reg[SX86_SREG_SS].val;
1100 else
1101 seg = ctx->state->segment_reg[SX86_SREG_DS].val;
1102 else
1103 seg = ctx->state->segment_override;
1104
1105 /* figure out the memory address */
1106 if (mod == 0) {
1107 if (rm == 6) {
1108 ofs = softx86_fetch_exec_byte(ctx);
1109 ofs |= softx86_fetch_exec_byte(ctx)<<8;
1110 }
1111 else if (rm == 0)
1112 ofs = ctx->state->general_reg[SX86_REG_BX].w.lo +
1113 ctx->state->general_reg[SX86_REG_SI].w.lo;
1114 else if (rm == 1)
1115 ofs = ctx->state->general_reg[SX86_REG_BX].w.lo +
1116 ctx->state->general_reg[SX86_REG_DI].w.lo;
1117 else if (rm == 2)
1118 ofs = ctx->state->general_reg[SX86_REG_BP].w.lo +
1119 ctx->state->general_reg[SX86_REG_SI].w.lo;
1120 else if (rm == 3)
1121 ofs = ctx->state->general_reg[SX86_REG_BP].w.lo +
1122 ctx->state->general_reg[SX86_REG_DI].w.lo;
1123 else if (rm == 4)
1124 ofs = ctx->state->general_reg[SX86_REG_SI].w.lo;
1125 else if (rm == 5)
1126 ofs = ctx->state->general_reg[SX86_REG_DI].w.lo;
1127 else if (rm == 7)
1128 ofs = ctx->state->general_reg[SX86_REG_BX].w.lo;
1129 }
1130 else {
1131 sx86_uword xx;
1132
1133 if (rm == 0)
1134 ofs = ctx->state->general_reg[SX86_REG_BX].w.lo +
1135 ctx->state->general_reg[SX86_REG_SI].w.lo;
1136 else if (rm == 1)
1137 ofs = ctx->state->general_reg[SX86_REG_BX].w.lo +
1138 ctx->state->general_reg[SX86_REG_DI].w.lo;
1139 else if (rm == 2)
1140 ofs = ctx->state->general_reg[SX86_REG_BP].w.lo +
1141 ctx->state->general_reg[SX86_REG_SI].w.lo;
1142 else if (rm == 3)
1143 ofs = ctx->state->general_reg[SX86_REG_BP].w.lo +
1144 ctx->state->general_reg[SX86_REG_DI].w.lo;
1145 else if (rm == 4)
1146 ofs = ctx->state->general_reg[SX86_REG_SI].w.lo;
1147 else if (rm == 5)
1148 ofs = ctx->state->general_reg[SX86_REG_DI].w.lo;
1149 else if (rm == 6)
1150 ofs = ctx->state->general_reg[SX86_REG_BP].w.lo;
1151 else if (rm == 7)
1152 ofs = ctx->state->general_reg[SX86_REG_BX].w.lo;
1153
1154 if (mod == 1) {
1155 xx = softx86_fetch_exec_byte(ctx);
1156 if (xx & 0x80) xx |= 0xFF00;
1157 }
1158 else {
1159 xx = softx86_fetch_exec_byte(ctx);
1160 xx |= softx86_fetch_exec_byte(ctx)<<8;
1161 }
1162
1163 ofs = FORCE_WORD_SIZE(ofs + xx);
1164 }
1165
1166 // TODO: For 386+ 32-bit instructions... if (d32) {...}
1167 if (w16) {
1168 sx86_uword regv,rmv;
1169
1170 regv = ctx->state->general_reg[reg].w.lo;
1171 lo = sx86_far_to_linear(ctx,seg,ofs);
1172 softx86_fetch(ctx,NULL,lo,&rmv,2);
1173 SWAP_WORD_FROM_LE(rmv);
1174
1175 if (opswap) {
1176 op16(ctx,regv,rmv);
1177 }
1178 else {
1179 op16(ctx,rmv,regv);
1180 }
1181 }
1182 else {
1183 sx86_ubyte regv,rmv;
1184
1185 regv = *(ctx->__private->ptr_regs_8reg[reg]);
1186 lo = sx86_far_to_linear(ctx,seg,ofs);
1187 softx86_fetch(ctx,NULL,lo,&rmv,1);
1188
1189 if (opswap) {
1190 op8(ctx,regv,rmv);
1191 }
1192 else {
1193 op8(ctx,rmv,regv);
1194 }
1195 }
1196 }
1197 }
1198
1199 /* general purpose mod/reg/rm executioneer helper for
1200 instructions that do modify the destination operand
1201 and need a FAR pointer
1202
1203 this is provided to avoid copy and pasting this source code into the emulation
1204 code for *EVERY* instruction.
1205
1206 ctx = CPU context
1207 d32 = 386+ 32-bit data size override (ignored if w16 == 0)
1208 mod/reg/rm = mod/reg/rm unpacked byte
1209 op16 = function to call for emulation of instruction, given 16-bit operands "src" and "dst"
1210 op32 = function to call for emulation of instruction, given 32-bit operands "src" and "dst"
1211
1212 Example of instructions that fit this format:
1213
1214 LES BX,WORD PTR [5256h]
1215 */
1216 void sx86_exec_full_modregrm_far(softx86_ctx* ctx,sx86_ubyte d32,sx86_ubyte mod,sx86_ubyte reg,sx86_ubyte rm,sx86_uword (*op16)(softx86_ctx* ctx,sx86_uword seg,sx86_uword ofs),sx86_udword (*op32)(softx86_ctx* ctx,sx86_udword seg,sx86_udword ofs))
1217 {
1218 if (mod == 3) { /* register <-> register */
1219 /* illegal */
1220 }
1221 else { /* register <-> memory */
1222 sx86_uword seg,ofs;
1223 sx86_udword lo;
1224
1225 if (!ctx->state->is_segment_override)
1226 /* apparently if BP is used (i.e. [BP+BX]) the stack segment is assumed. */
1227 if ((rm == 2 || rm == 3) || (rm == 6 && (mod == 1 || mod == 2)))
1228 seg = ctx->state->segment_reg[SX86_SREG_SS].val;
1229 else
1230 seg = ctx->state->segment_reg[SX86_SREG_DS].val;
1231 else
1232 seg = ctx->state->segment_override;
1233
1234 /* figure out the memory address */
1235 if (mod == 0) {
1236 if (rm == 6) {
1237 ofs = softx86_fetch_exec_byte(ctx);
1238 ofs |= softx86_fetch_exec_byte(ctx)<<8;
1239 }
1240 else if (rm == 0)
1241 ofs = ctx->state->general_reg[SX86_REG_BX].w.lo +
1242 ctx->state->general_reg[SX86_REG_SI].w.lo;
1243 else if (rm == 1)
1244 ofs = ctx->state->general_reg[SX86_REG_BX].w.lo +
1245 ctx->state->general_reg[SX86_REG_DI].w.lo;
1246 else if (rm == 2)
1247 ofs = ctx->state->general_reg[SX86_REG_BP].w.lo +
1248 ctx->state->general_reg[SX86_REG_SI].w.lo;
1249 else if (rm == 3)
1250 ofs = ctx->state->general_reg[SX86_REG_BP].w.lo +
1251 ctx->state->general_reg[SX86_REG_DI].w.lo;
1252 else if (rm == 4)
1253 ofs = ctx->state->general_reg[SX86_REG_SI].w.lo;
1254 else if (rm == 5)
1255 ofs = ctx->state->general_reg[SX86_REG_DI].w.lo;
1256 else if (rm == 7)
1257 ofs = ctx->state->general_reg[SX86_REG_BX].w.lo;
1258 }
1259 else {
1260 sx86_uword xx;
1261
1262 if (rm == 0)
1263 ofs = ctx->state->general_reg[SX86_REG_BX].w.lo +
1264 ctx->state->general_reg[SX86_REG_SI].w.lo;
1265 else if (rm == 1)
1266 ofs = ctx->state->general_reg[SX86_REG_BX].w.lo +
1267 ctx->state->general_reg[SX86_REG_DI].w.lo;
1268 else if (rm == 2)
1269 ofs = ctx->state->general_reg[SX86_REG_BP].w.lo +
1270 ctx->state->general_reg[SX86_REG_SI].w.lo;
1271 else if (rm == 3)
1272 ofs = ctx->state->general_reg[SX86_REG_BP].w.lo +
1273 ctx->state->general_reg[SX86_REG_DI].w.lo;
1274 else if (rm == 4)
1275 ofs = ctx->state->general_reg[SX86_REG_SI].w.lo;
1276 else if (rm == 5)
1277 ofs = ctx->state->general_reg[SX86_REG_DI].w.lo;
1278 else if (rm == 6)
1279 ofs = ctx->state->general_reg[SX86_REG_BP].w.lo;
1280 else if (rm == 7)
1281 ofs = ctx->state->general_reg[SX86_REG_BX].w.lo;
1282
1283 if (mod == 1) {
1284 xx = softx86_fetch_exec_byte(ctx);
1285 if (xx & 0x80) xx |= 0xFF00;
1286 }
1287 else {
1288 xx = softx86_fetch_exec_byte(ctx);
1289 xx |= softx86_fetch_exec_byte(ctx)<<8;
1290 }
1291
1292 ofs = FORCE_WORD_SIZE(ofs + xx);
1293 }
1294
1295 // TODO: For 386+ 32-bit instructions... if (d32) {...}
1296 {
1297 sx86_uword rmv,rmv2;
1298
1299 lo = sx86_far_to_linear(ctx,seg,ofs);
1300 softx86_fetch(ctx,NULL,lo,&rmv,2);
1301 lo += 2;
1302 softx86_fetch(ctx,NULL,lo,&rmv2,2);
1303 SWAP_WORD_FROM_LE(rmv);
1304 SWAP_WORD_FROM_LE(rmv2);
1305 ctx->state->general_reg[reg].w.lo = op16(ctx,rmv2,rmv);
1306 }
1307 }
1308 }
1309
1310 /* general purpose mod/reg/rm executioneer helper for
1311 instructions that do not modify the destination operand
1312 but need a FAR pointer and the register operand
1313
1314 this is provided to avoid copy and pasting this source code into the emulation
1315 code for *EVERY* instruction.
1316
1317 ctx = CPU context
1318 d32 = 386+ 32-bit data size override (ignored if w16 == 0)
1319 mod/reg/rm = mod/reg/rm unpacked byte
1320 op16 = function to call for emulation of instruction, given 16-bit operands "src" and "dst"
1321 op32 = function to call for emulation of instruction, given 32-bit operands "src" and "dst"
1322
1323 Example of instructions that fit this format:
1324
1325 BOUND BX,WORD PTR [9874h]
1326 */
1327 void sx86_exec_full_modregrm_far_ro3(softx86_ctx* ctx,sx86_ubyte d32,sx86_ubyte mod,sx86_ubyte reg,sx86_ubyte rm,sx86_sword (*op16)(softx86_ctx* ctx,sx86_sword idx,sx86_sword upper,sx86_sword lower),sx86_sdword (*op32)(softx86_ctx* ctx,sx86_sdword idx,sx86_sdword upper,sx86_sdword lower))
1328 {
1329 if (mod == 3) { /* register <-> register */
1330 /* illegal */
1331 }
1332 else { /* register <-> memory */
1333 sx86_uword seg,ofs;
1334 sx86_udword lo;
1335
1336 if (!ctx->state->is_segment_override)
1337 /* apparently if BP is used (i.e. [BP+BX]) the stack segment is assumed. */
1338 if ((rm == 2 || rm == 3) || (rm == 6 && (mod == 1 || mod == 2)))
1339 seg = ctx->state->segment_reg[SX86_SREG_SS].val;
1340 else
1341 seg = ctx->state->segment_reg[SX86_SREG_DS].val;
1342 else
1343 seg = ctx->state->segment_override;
1344
1345 /* figure out the memory address */
1346 if (mod == 0) {
1347 if (rm == 6) {
1348 ofs = softx86_fetch_exec_byte(ctx);
1349 ofs |= softx86_fetch_exec_byte(ctx)<<8;
1350 }
1351 else if (rm == 0)
1352 ofs = ctx->state->general_reg[SX86_REG_BX].w.lo +
1353 ctx->state->general_reg[SX86_REG_SI].w.lo;
1354 else if (rm == 1)
1355 ofs = ctx->state->general_reg[SX86_REG_BX].w.lo +
1356 ctx->state->general_reg[SX86_REG_DI].w.lo;
1357 else if (rm == 2)
1358 ofs = ctx->state->general_reg[SX86_REG_BP].w.lo +
1359 ctx->state->general_reg[SX86_REG_SI].w.lo;
1360 else if (rm == 3)
1361 ofs = ctx->state->general_reg[SX86_REG_BP].w.lo +
1362 ctx->state->general_reg[SX86_REG_DI].w.lo;
1363 else if (rm == 4)
1364 ofs = ctx->state->general_reg[SX86_REG_SI].w.lo;
1365 else if (rm == 5)
1366 ofs = ctx->state->general_reg[SX86_REG_DI].w.lo;
1367 else if (rm == 7)
1368 ofs = ctx->state->general_reg[SX86_REG_BX].w.lo;
1369 }
1370 else {
1371 sx86_uword xx;
1372
1373 if (rm == 0)
1374 ofs = ctx->state->general_reg[SX86_REG_BX].w.lo +
1375 ctx->state->general_reg[SX86_REG_SI].w.lo;
1376 else if (rm == 1)
1377 ofs = ctx->state->general_reg[SX86_REG_BX].w.lo +
1378 ctx->state->general_reg[SX86_REG_DI].w.lo;
1379 else if (rm == 2)
1380 ofs = ctx->state->general_reg[SX86_REG_BP].w.lo +
1381 ctx->state->general_reg[SX86_REG_SI].w.lo;
1382 else if (rm == 3)
1383 ofs = ctx->state->general_reg[SX86_REG_BP].w.lo +
1384 ctx->state->general_reg[SX86_REG_DI].w.lo;
1385 else if (rm == 4)
1386 ofs = ctx->state->general_reg[SX86_REG_SI].w.lo;
1387 else if (rm == 5)
1388 ofs = ctx->state->general_reg[SX86_REG_DI].w.lo;
1389 else if (rm == 6)
1390 ofs = ctx->state->general_reg[SX86_REG_BP].w.lo;
1391 else if (rm == 7)
1392 ofs = ctx->state->general_reg[SX86_REG_BX].w.lo;
1393
1394 if (mod == 1) {
1395 xx = softx86_fetch_exec_byte(ctx);
1396 if (xx & 0x80) xx |= 0xFF00;
1397 }
1398 else {
1399 xx = softx86_fetch_exec_byte(ctx);
1400 xx |= softx86_fetch_exec_byte(ctx)<<8;
1401 }
1402
1403 ofs = FORCE_WORD_SIZE(ofs + xx);
1404 }
1405
1406 // TODO: For 386+ 32-bit instructions... if (d32) {...}
1407 {
1408 sx86_sword rmv,rmv2;
1409
1410 lo = sx86_far_to_linear(ctx,seg,ofs);
1411 softx86_fetch(ctx,NULL,lo,&rmv,2);
1412 lo += 2;
1413 softx86_fetch(ctx,NULL,lo,&rmv2,2);
1414 SWAP_WORD_FROM_LE(rmv);
1415 SWAP_WORD_FROM_LE(rmv2);
1416 op16(ctx,ctx->state->general_reg[reg].w.lo,rmv2,rmv);
1417 }
1418 }
1419 }
1420
1421 /* general purpose mod/rm executioneer helper for
1422 instructions that modify the destination operand
1423 and have an immediate operand of specified size.
1424
1425 this is provided to avoid copy and pasting this source code into the emulation
1426 code for *EVERY* instruction.
1427
1428 ctx = CPU context
1429 w16 = 16-bit operand flag
1430 d32 = 386+ 32-bit data size override (ignored if w16 == 0)
1431 mod/rm = mod/reg/rm unpacked byte
1432 op8 = function to call for emulation of instruction, given 8-bit operands "src" and "dst"
1433 op16 = function to call for emulation of instruction, given 16-bit operands "src" and "dst"
1434 op32 = function to call for emulation of instruction, given 32-bit operands "src" and "dst"
1435
1436 Example of instructions that fit this format:
1437
1438 MOV AH,2456h
1439 MOV WORD PTR [1334h],2222h
1440 */
1441 void sx86_exec_full_modrmonly_rw_imm(softx86_ctx* ctx,sx86_ubyte w16,sx86_ubyte d32,sx86_ubyte mod,sx86_ubyte rm,sx86_ubyte (*op8)(softx86_ctx* ctx,sx86_ubyte src,sx86_ubyte val),sx86_uword (*op16)(softx86_ctx* ctx,sx86_uword src,sx86_uword val),sx86_udword (*op32)(softx86_ctx* ctx,sx86_udword src,sx86_udword val),int sx)
1442 {
1443 sx86_uword imm;
1444
1445 if (mod == 3) { /* immediate <-> register */
1446 imm = softx86_fetch_exec_byte(ctx);
1447 if (w16)
1448 if (sx) imm |= (imm&0x80) ? 0xFF80 : 0;
1449 else imm |= softx86_fetch_exec_byte(ctx)<<8;
1450
1451 // TODO: For 386+ 32-bit instructions... if (d32) {...}
1452 if (w16) {
1453 sx86_uword rmv;
1454
1455 rmv = ctx->state->general_reg[rm].w.lo;
1456
1457 ctx->state->general_reg[rm].w.lo =
1458 op16(ctx,rmv,(sx86_uword)imm);
1459 }
1460 else {
1461 sx86_ubyte rmv;
1462
1463 rmv = *(ctx->__private->ptr_regs_8reg[rm]);
1464
1465 *(ctx->__private->ptr_regs_8reg[rm]) =
1466 op8(ctx,rmv,(sx86_ubyte)imm);
1467 }
1468 }
1469 else { /* immediate <-> memory */
1470 sx86_uword seg,ofs;
1471 sx86_udword lo;
1472
1473 if (!ctx->state->is_segment_override)
1474 /* apparently if BP is used (i.e. [BP+BX]) the stack segment is assumed. */
1475 if ((rm == 2 || rm == 3) || (rm == 6 && (mod == 1 || mod == 2)))
1476 seg = ctx->state->segment_reg[SX86_SREG_SS].val;
1477 else
1478 seg = ctx->state->segment_reg[SX86_SREG_DS].val;
1479 else
1480 seg = ctx->state->segment_override;
1481
1482 /* figure out the memory address */
1483 if (mod == 0) {
1484 if (rm == 6) {
1485 ofs = softx86_fetch_exec_byte(ctx);
1486 ofs |= softx86_fetch_exec_byte(ctx)<<8;
1487 }
1488 else if (rm == 0)
1489 ofs = ctx->state->general_reg[SX86_REG_BX].w.lo +
1490 ctx->state->general_reg[SX86_REG_SI].w.lo;
1491 else if (rm == 1)
1492 ofs = ctx->state->general_reg[SX86_REG_BX].w.lo +
1493 ctx->state->general_reg[SX86_REG_DI].w.lo;
1494 else if (rm == 2)
1495 ofs = ctx->state->general_reg[SX86_REG_BP].w.lo +
1496 ctx->state->general_reg[SX86_REG_SI].w.lo;
1497 else if (rm == 3)
1498 ofs = ctx->state->general_reg[SX86_REG_BP].w.lo +
1499 ctx->state->general_reg[SX86_REG_DI].w.lo;
1500 else if (rm == 4)
1501 ofs = ctx->state->general_reg[SX86_REG_SI].w.lo;
1502 else if (rm == 5)
1503 ofs = ctx->state->general_reg[SX86_REG_DI].w.lo;
1504 else if (rm == 7)
1505 ofs = ctx->state->general_reg[SX86_REG_BX].w.lo;
1506 }
1507 else {
1508 sx86_uword xx;
1509
1510 if (rm == 0)
1511 ofs = ctx->state->general_reg[SX86_REG_BX].w.lo +
1512 ctx->state->general_reg[SX86_REG_SI].w.lo;
1513 else if (rm == 1)
1514 ofs = ctx->state->general_reg[SX86_REG_BX].w.lo +
1515 ctx->state->general_reg[SX86_REG_DI].w.lo;
1516 else if (rm == 2)
1517 ofs = ctx->state->general_reg[SX86_REG_BP].w.lo +
1518 ctx->state->general_reg[SX86_REG_SI].w.lo;
1519 else if (rm == 3)
1520 ofs = ctx->state->general_reg[SX86_REG_BP].w.lo +
1521 ctx->state->general_reg[SX86_REG_DI].w.lo;
1522 else if (rm == 4)
1523 ofs = ctx->state->general_reg[SX86_REG_SI].w.lo;
1524 else if (rm == 5)
1525 ofs = ctx->state->general_reg[SX86_REG_DI].w.lo;
1526 else if (rm == 6)
1527 ofs = ctx->state->general_reg[SX86_REG_BP].w.lo;
1528 else if (rm == 7)
1529 ofs = ctx->state->general_reg[SX86_REG_BX].w.lo;
1530
1531 if (mod == 1) {
1532 xx = softx86_fetch_exec_byte(ctx);
1533 if (xx & 0x80) xx |= 0xFF00;
1534 }
1535 else {
1536 xx = softx86_fetch_exec_byte(ctx);
1537 xx |= softx86_fetch_exec_byte(ctx)<<8;
1538 }
1539
1540 ofs = FORCE_WORD_SIZE(ofs + xx);
1541 }
1542
1543 imm = softx86_fetch_exec_byte(ctx);
1544 if (w16)
1545 if (sx) imm |= (imm&0x80) ? 0xFF80 : 0;
1546 else imm |= softx86_fetch_exec_byte(ctx)<<8;
1547
1548 // TODO: For 386+ 32-bit instructions... if (d32) {...}
1549 if (w16) {
1550 sx86_uword rmv;
1551
1552 lo = sx86_far_to_linear(ctx,seg,ofs);
1553 softx86_fetch(ctx,NULL,lo,&rmv,2);
1554 SWAP_WORD_FROM_LE(rmv);
1555
1556 rmv = op16(ctx,rmv,(sx86_uword)imm);
1557 SWAP_WORD_TO_LE(rmv);
1558 softx86_write(ctx,NULL,lo,&rmv,2);
1559 }
1560 else {
1561 sx86_ubyte rmv;
1562
1563 lo = sx86_far_to_linear(ctx,seg,ofs);
1564 softx86_fetch(ctx,NULL,lo,&rmv,1);
1565
1566 rmv = op8(ctx,rmv,(sx86_ubyte)imm);
1567 softx86_write(ctx,NULL,lo,&rmv,1);
1568 }
1569 }
1570 }
1571
1572 /* general purpose mod/rm executioneer helper for
1573 instructions that modify the destination operand
1574 and have an immediate operand of specified size.
1575
1576 this is provided to avoid copy and pasting this source code into the emulation
1577 code for *EVERY* instruction.
1578
1579 ctx = CPU context
1580 w16 = 16-bit operand flag
1581 d32 = 386+ 32-bit data size override (ignored if w16 == 0)
1582 mod/rm = mod/reg/rm unpacked byte
1583 op8 = function to call for emulation of instruction, given 8-bit operands "src" and "dst"
1584 op16 = function to call for emulation of instruction, given 16-bit operands "src" and "dst"
1585 op32 = function to call for emulation of instruction, given 32-bit operands "src" and "dst"
1586
1587 Example of instructions that fit this format:
1588
1589 MOV AH,2456h
1590 MOV WORD PTR [1334h],2222h
1591 */
1592 void sx86_exec_full_modrmonly_rw_imm8(softx86_ctx* ctx,sx86_ubyte w16,sx86_ubyte d32,sx86_ubyte mod,sx86_ubyte rm,sx86_ubyte (*op8)(softx86_ctx* ctx,sx86_ubyte src,sx86_ubyte val),sx86_uword (*op16)(softx86_ctx* ctx,sx86_uword src,sx86_uword val),sx86_udword (*op32)(softx86_ctx* ctx,sx86_udword src,sx86_udword val))
1593 {
1594 sx86_uword imm;
1595
1596 if (mod == 3) { /* immediate <-> register */
1597 imm = softx86_fetch_exec_byte(ctx);
1598
1599 // TODO: For 386+ 32-bit instructions... if (d32) {...}
1600 if (w16) {
1601 sx86_uword rmv;
1602
1603 rmv = ctx->state->general_reg[rm].w.lo;
1604
1605 ctx->state->general_reg[rm].w.lo =
1606 op16(ctx,rmv,(sx86_uword)imm);
1607 }
1608 else {
1609 sx86_ubyte rmv;
1610
1611 rmv = *(ctx->__private->ptr_regs_8reg[rm]);
1612
1613 *(ctx->__private->ptr_regs_8reg[rm]) =
1614 op8(ctx,rmv,(sx86_ubyte)imm);
1615 }
1616 }
1617 else { /* immediate <-> memory */
1618 sx86_uword seg,ofs;
1619 sx86_udword lo;
1620
1621 if (!ctx->state->is_segment_override)
1622 /* apparently if BP is used (i.e. [BP+BX]) the stack segment is assumed. */
1623 if ((rm == 2 || rm == 3) || (rm == 6 && (mod == 1 || mod == 2)))
1624 seg = ctx->state->segment_reg[SX86_SREG_SS].val;
1625 else
1626 seg = ctx->state->segment_reg[SX86_SREG_DS].val;
1627 else
1628 seg = ctx->state->segment_override;
1629
1630 /* figure out the memory address */
1631 if (mod == 0) {
1632 if (rm == 6) {
1633 ofs = softx86_fetch_exec_byte(ctx);
1634 ofs |= softx86_fetch_exec_byte(ctx)<<8;
1635 }
1636 else if (rm == 0)
1637 ofs = ctx->state->general_reg[SX86_REG_BX].w.lo +
1638 ctx->state->general_reg[SX86_REG_SI].w.lo;
1639 else if (rm == 1)
1640 ofs = ctx->state->general_reg[SX86_REG_BX].w.lo +
1641 ctx->state->general_reg[SX86_REG_DI].w.lo;
1642 else if (rm == 2)
1643 ofs = ctx->state->general_reg[SX86_REG_BP].w.lo +
1644 ctx->state->general_reg[SX86_REG_SI].w.lo;
1645 else if (rm == 3)
1646 ofs = ctx->state->general_reg[SX86_REG_BP].w.lo +
1647 ctx->state->general_reg[SX86_REG_DI].w.lo;
1648 else if (rm == 4)
1649 ofs = ctx->state->general_reg[SX86_REG_SI].w.lo;
1650 else if (rm == 5)
1651 ofs = ctx->state->general_reg[SX86_REG_DI].w.lo;
1652 else if (rm == 7)
1653 ofs = ctx->state->general_reg[SX86_REG_BX].w.lo;
1654 }
1655 else {
1656 sx86_uword xx;
1657
1658 if (rm == 0)
1659 ofs = ctx->state->general_reg[SX86_REG_BX].w.lo +
1660 ctx->state->general_reg[SX86_REG_SI].w.lo;
1661 else if (rm == 1)
1662 ofs = ctx->state->general_reg[SX86_REG_BX].w.lo +
1663 ctx->state->general_reg[SX86_REG_DI].w.lo;
1664 else if (rm == 2)
1665 ofs = ctx->state->general_reg[SX86_REG_BP].w.lo +
1666 ctx->state->general_reg[SX86_REG_SI].w.lo;
1667 else if (rm == 3)
1668 ofs = ctx->state->general_reg[SX86_REG_BP].w.lo +
1669 ctx->state->general_reg[SX86_REG_DI].w.lo;
1670 else if (rm == 4)
1671 ofs = ctx->state->general_reg[SX86_REG_SI].w.lo;
1672 else if (rm == 5)
1673 ofs = ctx->state->general_reg[SX86_REG_DI].w.lo;
1674 else if (rm == 6)
1675 ofs = ctx->state->general_reg[SX86_REG_BP].w.lo;
1676 else if (rm == 7)
1677 ofs = ctx->state->general_reg[SX86_REG_BX].w.lo;
1678
1679 if (mod == 1) {
1680 xx = softx86_fetch_exec_byte(ctx);
1681 if (xx & 0x80) xx |= 0xFF00;
1682 }
1683 else {
1684 xx = softx86_fetch_exec_byte(ctx);
1685 xx |= softx86_fetch_exec_byte(ctx)<<8;
1686 }
1687
1688 ofs = FORCE_WORD_SIZE(ofs + xx);
1689 }
1690
1691 imm = softx86_fetch_exec_byte(ctx);
1692 if (w16) imm |= softx86_fetch_exec_byte(ctx)<<8;
1693
1694 // TODO: For 386+ 32-bit instructions... if (d32) {...}
1695 if (w16) {
1696 sx86_uword rmv;
1697
1698 lo = sx86_far_to_linear(ctx,seg,ofs);
1699 softx86_fetch(ctx,NULL,lo,&rmv,2);
1700 SWAP_WORD_FROM_LE(rmv);
1701
1702 rmv = op16(ctx,rmv,(sx86_uword)imm);
1703 SWAP_WORD_TO_LE(rmv);
1704 softx86_write(ctx,NULL,lo,&rmv,2);
1705 }
1706 else {
1707 sx86_ubyte rmv;
1708
1709 lo = sx86_far_to_linear(ctx,seg,ofs);
1710 softx86_fetch(ctx,NULL,lo,&rmv,1);
1711
1712 rmv = op8(ctx,rmv,(sx86_ubyte)imm);
1713 softx86_write(ctx,NULL,lo,&rmv,1);
1714 }
1715 }
1716 }
1717
1718 /* general purpose mod/rm executioneer helper for
1719 instructions that DO NOT modify the destination operand
1720 and have an immediate operand of specified size.
1721
1722 this is provided to avoid copy and pasting this source code into the emulation
1723 code for *EVERY* instruction.
1724
1725 ctx = CPU context
1726 w16 = 16-bit operand flag
1727 d32 = 386+ 32-bit data size override (ignored if w16 == 0)
1728 mod/rm = mod/reg/rm unpacked byte
1729 op8 = function to call for emulation of instruction, given 8-bit operands "src" and "dst"
1730 op16 = function to call for emulation of instruction, given 16-bit operands "src" and "dst"
1731 op32 = function to call for emulation of instruction, given 32-bit operands "src" and "dst"
1732
1733 Example of instructions that fit this format:
1734
1735 MOV AH,2456h
1736 MOV WORD PTR [1334h],2222h
1737 */
1738 void sx86_exec_full_modrmonly_ro_imm(softx86_ctx* ctx,sx86_ubyte w16,sx86_ubyte d32,sx86_ubyte mod,sx86_ubyte rm,sx86_ubyte (*op8)(softx86_ctx* ctx,sx86_ubyte src,sx86_ubyte val),sx86_uword (*op16)(softx86_ctx* ctx,sx86_uword src,sx86_uword val),sx86_udword (*op32)(softx86_ctx* ctx,sx86_udword src,sx86_udword val),int sx)
1739 {
1740 sx86_uword imm;
1741
1742 if (mod == 3) { /* immediate <-> register */
1743 imm = softx86_fetch_exec_byte(ctx);
1744 if (w16)
1745 if (sx) imm |= (imm&0x80) ? 0xFF80 : 0;
1746 else imm |= softx86_fetch_exec_byte(ctx)<<8;
1747
1748 // TODO: For 386+ 32-bit instructions... if (d32) {...}
1749 if (w16) {
1750 sx86_uword rmv;
1751
1752 rmv = ctx->state->general_reg[rm].w.lo;
1753 op16(ctx,rmv,(sx86_uword)imm);
1754 }
1755 else {
1756 sx86_ubyte rmv;
1757
1758 rmv = *(ctx->__private->ptr_regs_8reg[rm]);
1759 op8(ctx,rmv,(sx86_ubyte)imm);
1760 }
1761 }
1762 else { /* immediate <-> memory */
1763 sx86_uword seg,ofs;
1764 sx86_udword lo;
1765
1766 if (!ctx->state->is_segment_override)
1767 /* apparently if BP is used (i.e. [BP+BX]) the stack segment is assumed. */
1768 if ((rm == 2 || rm == 3) || (rm == 6 && (mod == 1 || mod == 2)))
1769 seg = ctx->state->segment_reg[SX86_SREG_SS].val;
1770 else
1771 seg = ctx->state->segment_reg[SX86_SREG_DS].val;
1772 else
1773 seg = ctx->state->segment_override;
1774
1775 /* figure out the memory address */
1776 if (mod == 0) {
1777 if (rm == 6) {
1778 ofs = softx86_fetch_exec_byte(ctx);
1779 ofs |= softx86_fetch_exec_byte(ctx)<<8;
1780 }
1781 else if (rm == 0)
1782 ofs = ctx->state->general_reg[SX86_REG_BX].w.lo +
1783 ctx->state->general_reg[SX86_REG_SI].w.lo;
1784 else if (rm == 1)
1785 ofs = ctx->state->general_reg[SX86_REG_BX].w.lo +
1786 ctx->state->general_reg[SX86_REG_DI].w.lo;
1787 else if (rm == 2)
1788 ofs = ctx->state->general_reg[SX86_REG_BP].w.lo +
1789 ctx->state->general_reg[SX86_REG_SI].w.lo;
1790 else if (rm == 3)
1791 ofs = ctx->state->general_reg[SX86_REG_BP].w.lo +
1792 ctx->state->general_reg[SX86_REG_DI].w.lo;
1793 else if (rm == 4)
1794 ofs = ctx->state->general_reg[SX86_REG_SI].w.lo;
1795 else if (rm == 5)
1796 ofs = ctx->state->general_reg[SX86_REG_DI].w.lo;
1797 else if (rm == 7)
1798 ofs = ctx->state->general_reg[SX86_REG_BX].w.lo;
1799 }
1800 else {
1801 sx86_uword xx;
1802
1803 if (rm == 0)
1804 ofs = ctx->state->general_reg[SX86_REG_BX].w.lo +
1805 ctx->state->general_reg[SX86_REG_SI].w.lo;
1806 else if (rm == 1)
1807 ofs = ctx->state->general_reg[SX86_REG_BX].w.lo +
1808 ctx->state->general_reg[SX86_REG_DI].w.lo;
1809 else if (rm == 2)
1810 ofs = ctx->state->general_reg[SX86_REG_BP].w.lo +
1811 ctx->state->general_reg[SX86_REG_SI].w.lo;
1812 else if (rm == 3)
1813 ofs = ctx->state->general_reg[SX86_REG_BP].w.lo +
1814 ctx->state->general_reg[SX86_REG_DI].w.lo;
1815 else if (rm == 4)
1816 ofs = ctx->state->general_reg[SX86_REG_SI].w.lo;
1817 else if (rm == 5)
1818 ofs = ctx->state->general_reg[SX86_REG_DI].w.lo;
1819 else if (rm == 6)
1820 ofs = ctx->state->general_reg[SX86_REG_BP].w.lo;
1821 else if (rm == 7)
1822 ofs = ctx->state->general_reg[SX86_REG_BX].w.lo;
1823
1824 if (mod == 1) {
1825 xx = softx86_fetch_exec_byte(ctx);
1826 if (xx & 0x80) xx |= 0xFF00;
1827 }
1828 else {
1829 xx = softx86_fetch_exec_byte(ctx);
1830 xx |= softx86_fetch_exec_byte(ctx)<<8;
1831 }
1832
1833 ofs = FORCE_WORD_SIZE(ofs + xx);
1834 }
1835
1836 imm = softx86_fetch_exec_byte(ctx);
1837 if (w16)
1838 if (sx) imm |= (imm&0x80) ? 0xFF80 : 0;
1839 else imm |= softx86_fetch_exec_byte(ctx)<<8;
1840
1841 // TODO: For 386+ 32-bit instructions... if (d32) {...}
1842 if (w16) {
1843 sx86_uword rmv;
1844
1845 lo = sx86_far_to_linear(ctx,seg,ofs);
1846 softx86_fetch(ctx,NULL,lo,&rmv,2);
1847 SWAP_WORD_FROM_LE(rmv);
1848
1849 op16(ctx,rmv,(sx86_uword)imm);
1850 }
1851 else {
1852 sx86_ubyte rmv;
1853
1854 lo = sx86_far_to_linear(ctx,seg,ofs);
1855 softx86_fetch(ctx,NULL,lo,&rmv,1);
1856
1857 op8(ctx,rmv,(sx86_ubyte)imm);
1858 }
1859 }
1860 }
1861
1862 /* general purpose mod/rm executioneer helper for
1863 instructions that modify the destination operand
1864 and do not have an immediate operand of specified size.
1865
1866 this is provided to avoid copy and pasting this source code into the emulation
1867 code for *EVERY* instruction.
1868
1869 ctx = CPU context
1870 w16 = 16-bit operand flag
1871 d32 = 386+ 32-bit data size override (ignored if w16 == 0)
1872 mod/rm = mod/reg/rm unpacked byte
1873 op8 = function to call for emulation of instruction, given 8-bit operand "src"
1874 op16 = function to call for emulation of instruction, given 16-bit operand "src"
1875 op32 = function to call for emulation of instruction, given 32-bit operand "src"
1876
1877 INC BX
1878 INC WORD PTR [2045h]
1879 */
1880 void sx86_exec_full_modrmonly_rw(softx86_ctx* ctx,sx86_ubyte w16,sx86_ubyte d32,sx86_ubyte mod,sx86_ubyte rm,sx86_ubyte (*op8)(softx86_ctx* ctx,sx86_ubyte src),sx86_uword (*op16)(softx86_ctx* ctx,sx86_uword src),sx86_udword (*op32)(softx86_ctx* ctx,sx86_udword src))
1881 {
1882 if (mod == 3) { /* immediate <-> register */
1883 // TODO: For 386+ 32-bit instructions... if (d32) {...}
1884 if (w16) {
1885 sx86_uword rmv;
1886
1887 rmv = ctx->state->general_reg[rm].w.lo;
1888
1889 ctx->state->general_reg[rm].w.lo =
1890 op16(ctx,rmv);
1891 }
1892 else {
1893 sx86_ubyte rmv;
1894
1895 rmv = *(ctx->__private->ptr_regs_8reg[rm]);
1896
1897 *(ctx->__private->ptr_regs_8reg[rm]) =
1898 op8(ctx,rmv);
1899 }
1900 }
1901 else { /* immediate <-> memory */
1902 sx86_uword seg,ofs;
1903 sx86_udword lo;
1904
1905 if (!ctx->state->is_segment_override)
1906 /* apparently if BP is used (i.e. [BP+BX]) the stack segment is assumed. */
1907 if ((rm == 2 || rm == 3) || (rm == 6 && (mod == 1 || mod == 2)))
1908 seg = ctx->state->segment_reg[SX86_SREG_SS].val;
1909 else
1910 seg = ctx->state->segment_reg[SX86_SREG_DS].val;
1911 else
1912 seg = ctx->state->segment_override;
1913
1914 /* figure out the memory address */
1915 if (mod == 0) {
1916 if (rm == 6) {
1917 ofs = softx86_fetch_exec_byte(ctx);
1918 ofs |= softx86_fetch_exec_byte(ctx)<<8;
1919 }
1920 else if (rm == 0)
1921 ofs = ctx->state->general_reg[SX86_REG_BX].w.lo +
1922 ctx->state->general_reg[SX86_REG_SI].w.lo;
1923 else if (rm == 1)
1924 ofs = ctx->state->general_reg[SX86_REG_BX].w.lo +
1925 ctx->state->general_reg[SX86_REG_DI].w.lo;
1926 else if (rm == 2)
1927 ofs = ctx->state->general_reg[SX86_REG_BP].w.lo +
1928 ctx->state->general_reg[SX86_REG_SI].w.lo;
1929 else if (rm == 3)
1930 ofs = ctx->state->general_reg[SX86_REG_BP].w.lo +
1931 ctx->state->general_reg[SX86_REG_DI].w.lo;
1932 else if (rm == 4)
1933 ofs = ctx->state->general_reg[SX86_REG_SI].w.lo;
1934 else if (rm == 5)
1935 ofs = ctx->state->general_reg[SX86_REG_DI].w.lo;
1936 else if (rm == 7)
1937 ofs = ctx->state->general_reg[SX86_REG_BX].w.lo;
1938 }
1939 else {
1940 sx86_uword xx;
1941
1942 if (rm == 0)
1943 ofs = ctx->state->general_reg[SX86_REG_BX].w.lo +
1944 ctx->state->general_reg[SX86_REG_SI].w.lo;
1945 else if (rm == 1)
1946 ofs = ctx->state->general_reg[SX86_REG_BX].w.lo +
1947 ctx->state->general_reg[SX86_REG_DI].w.lo;
1948 else if (rm == 2)
1949 ofs = ctx->state->general_reg[SX86_REG_BP].w.lo +
1950 ctx->state->general_reg[SX86_REG_SI].w.lo;
1951 else if (rm == 3)
1952 ofs = ctx->state->general_reg[SX86_REG_BP].w.lo +
1953 ctx->state->general_reg[SX86_REG_DI].w.lo;
1954 else if (rm == 4)
1955 ofs = ctx->state->general_reg[SX86_REG_SI].w.lo;
1956 else if (rm == 5)
1957 ofs = ctx->state->general_reg[SX86_REG_DI].w.lo;
1958 else if (rm == 6)
1959 ofs = ctx->state->general_reg[SX86_REG_BP].w.lo;
1960 else if (rm == 7)
1961 ofs = ctx->state->general_reg[SX86_REG_BX].w.lo;
1962
1963 if (mod == 1) {
1964 xx = softx86_fetch_exec_byte(ctx);
1965 if (xx & 0x80) xx |= 0xFF00;
1966 }
1967 else {
1968 xx = softx86_fetch_exec_byte(ctx);
1969 xx |= softx86_fetch_exec_byte(ctx)<<8;
1970 }
1971
1972 ofs = FORCE_WORD_SIZE(ofs + xx);
1973 }
1974
1975 // TODO: For 386+ 32-bit instructions... if (d32) {...}
1976 if (w16) {
1977 sx86_uword rmv;
1978
1979 lo = sx86_far_to_linear(ctx,seg,ofs);
1980 softx86_fetch(ctx,NULL,lo,&rmv,2);
1981 SWAP_WORD_FROM_LE(rmv);
1982
1983 rmv = op16(ctx,rmv);
1984 SWAP_WORD_TO_LE(rmv);
1985 softx86_write(ctx,NULL,lo,&rmv,2);
1986 }
1987 else {
1988 sx86_ubyte rmv;
1989
1990 lo = sx86_far_to_linear(ctx,seg,ofs);
1991 softx86_fetch(ctx,NULL,lo,&rmv,1);
1992
1993 rmv = op8(ctx,rmv);
1994 softx86_write(ctx,NULL,lo,&rmv,1);
1995 }
1996 }
1997 }
1998
1999 /* general purpose mod/rm executioneer helper for
2000 instructions that do not modify the destination operand
2001 and do not have an immediate operand of specified size.
2002
2003 this is provided to avoid copy and pasting this source code into the emulation
2004 code for *EVERY* instruction.
2005
2006 ctx = CPU context
2007 w16 = 16-bit operand flag
2008 d32 = 386+ 32-bit data size override (ignored if w16 == 0)
2009 mod/rm = mod/reg/rm unpacked byte
2010 op8 = function to call for emulation of instruction, given 8-bit operand "src"
2011 op16 = function to call for emulation of instruction, given 16-bit operand "src"
2012 op32 = function to call for emulation of instruction, given 32-bit operand "src"
2013
2014 CALL WORD PTR [2045h]
2015 */
2016 void sx86_exec_full_modrmonly_ro(softx86_ctx* ctx,sx86_ubyte w16,sx86_ubyte d32,sx86_ubyte mod,sx86_ubyte rm,sx86_ubyte (*op8)(softx86_ctx* ctx,sx86_ubyte src),sx86_uword (*op16)(softx86_ctx* ctx,sx86_uword src),sx86_udword (*op32)(softx86_ctx* ctx,sx86_udword src))
2017 {
2018 if (mod == 3) { /* immediate <-> register */
2019 // TODO: For 386+ 32-bit instructions... if (d32) {...}
2020 if (w16) {
2021 op16(ctx,ctx->state->general_reg[rm].w.lo);
2022 }
2023 else {
2024 op8(ctx,*(ctx->__private->ptr_regs_8reg[rm]));
2025 }
2026 }
2027 else { /* immediate <-> memory */
2028 sx86_uword seg,ofs;
2029 sx86_udword lo;
2030
2031 if (!ctx->state->is_segment_override)
2032 /* apparently if BP is used (i.e. [BP+BX]) the stack segment is assumed. */
2033 if ((rm == 2 || rm == 3) || (rm == 6 && (mod == 1 || mod == 2)))
2034 seg = ctx->state->segment_reg[SX86_SREG_SS].val;
2035 else
2036 seg = ctx->state->segment_reg[SX86_SREG_DS].val;
2037 else
2038 seg = ctx->state->segment_override;
2039
2040 /* figure out the memory address */
2041 if (mod == 0) {
2042 if (rm == 6) {
2043 ofs = softx86_fetch_exec_byte(ctx);
2044 ofs |= softx86_fetch_exec_byte(ctx)<<8;
2045 }
2046 else if (rm == 0)
2047 ofs = ctx->state->general_reg[SX86_REG_BX].w.lo +
2048 ctx->state->general_reg[SX86_REG_SI].w.lo;
2049 else if (rm == 1)
2050 ofs = ctx->state->general_reg[SX86_REG_BX].w.lo +
2051 ctx->state->general_reg[SX86_REG_DI].w.lo;
2052 else if (rm == 2)
2053 ofs = ctx->state->general_reg[SX86_REG_BP].w.lo +
2054 ctx->state->general_reg[SX86_REG_SI].w.lo;
2055 else if (rm == 3)
2056 ofs = ctx->state->general_reg[SX86_REG_BP].w.lo +
2057 ctx->state->general_reg[SX86_REG_DI].w.lo;
2058 else if (rm == 4)
2059 ofs = ctx->state->general_reg[SX86_REG_SI].w.lo;
2060 else if (rm == 5)
2061 ofs = ctx->state->general_reg[SX86_REG_DI].w.lo;
2062 else if (rm == 7)
2063 ofs = ctx->state->general_reg[SX86_REG_BX].w.lo;
2064 }
2065 else {
2066 sx86_uword xx;
2067
2068 if (rm == 0)
2069 ofs = ctx->state->general_reg[SX86_REG_BX].w.lo +
2070 ctx->state->general_reg[SX86_REG_SI].w.lo;
2071 else if (rm == 1)
2072 ofs = ctx->state->general_reg[SX86_REG_BX].w.lo +
2073 ctx->state->general_reg[SX86_REG_DI].w.lo;
2074 else if (rm == 2)
2075 ofs = ctx->state->general_reg[SX86_REG_BP].w.lo +
2076 ctx->state->general_reg[SX86_REG_SI].w.lo;
2077 else if (rm == 3)
2078 ofs = ctx->state->general_reg[SX86_REG_BP].w.lo +
2079 ctx->state->general_reg[SX86_REG_DI].w.lo;
2080 else if (rm == 4)
2081 ofs = ctx->state->general_reg[SX86_REG_SI].w.lo;
2082 else if (rm == 5)
2083 ofs = ctx->state->general_reg[SX86_REG_DI].w.lo;
2084 else if (rm == 6)
2085 ofs = ctx->state->general_reg[SX86_REG_BP].w.lo;
2086 else if (rm == 7)
2087 ofs = ctx->state->general_reg[SX86_REG_BX].w.lo;
2088
2089 if (mod == 1) {
2090 xx = softx86_fetch_exec_byte(ctx);
2091 if (xx & 0x80) xx |= 0xFF00;
2092 }
2093 else {
2094 xx = softx86_fetch_exec_byte(ctx);
2095 xx |= softx86_fetch_exec_byte(ctx)<<8;
2096 }
2097
2098 ofs = FORCE_WORD_SIZE(ofs + xx);
2099 }
2100
2101 // TODO: For 386+ 32-bit instructions... if (d32) {...}
2102 if (w16) {
2103 sx86_uword rmv;
2104
2105 lo = sx86_far_to_linear(ctx,seg,ofs);
2106 softx86_fetch(ctx,NULL,lo,&rmv,2);
2107 SWAP_WORD_FROM_LE(rmv);
2108 op16(ctx,rmv);
2109 }
2110 else {
2111 sx86_ubyte rmv;
2112
2113 lo = sx86_far_to_linear(ctx,seg,ofs);
2114 softx86_fetch(ctx,NULL,lo,&rmv,1);
2115 op8(ctx,rmv);
2116 }
2117 }
2118 }
2119
2120 /* general purpose mod/rm executioneer helper for
2121 instructions that modify the destination operand
2122 and do not have an immediate operand of specified size.
2123 these functions do not consider the previous value.
2124
2125 this is provided to avoid copy and pasting this source code into the emulation
2126 code for *EVERY* instruction.
2127
2128 ctx = CPU context
2129 w16 = 16-bit operand flag
2130 d32 = 386+ 32-bit data size override (ignored if w16 == 0)
2131 mod/rm = mod/reg/rm unpacked byte
2132 op8 = function to call for emulation of instruction, given 8-bit operand "src"
2133 op16 = function to call for emulation of instruction, given 16-bit operand "src"
2134 op32 = function to call for emulation of instruction, given 32-bit operand "src"
2135
2136 POP WORD PTR [2045h]
2137 */
2138 void sx86_exec_full_modrmonly_wo(softx86_ctx* ctx,sx86_ubyte w16,sx86_ubyte d32,sx86_ubyte mod,sx86_ubyte rm,sx86_ubyte (*op8)(softx86_ctx* ctx),sx86_uword (*op16)(softx86_ctx* ctx),sx86_udword (*op32)(softx86_ctx* ctx))
2139 {
2140 if (mod == 3) { /* immediate <-> register */
2141 // TODO: For 386+ 32-bit instructions... if (d32) {...}
2142 if (w16) {
2143 ctx->state->general_reg[rm].w.lo = op16(ctx);
2144 }
2145 else {
2146 *(ctx->__private->ptr_regs_8reg[rm]) = op8(ctx);
2147 }
2148 }
2149 else { /* immediate <-> memory */
2150 sx86_uword seg,ofs;
2151 sx86_udword lo;
2152
2153 if (!ctx->state->is_segment_override)
2154 /* apparently if BP is used (i.e. [BP+BX]) the stack segment is assumed. */
2155 if ((rm == 2 || rm == 3) || (rm == 6 && (mod == 1 || mod == 2)))
2156 seg = ctx->state->segment_reg[SX86_SREG_SS].val;
2157 else
2158 seg = ctx->state->segment_reg[SX86_SREG_DS].val;
2159 else
2160 seg = ctx->state->segment_override;
2161
2162 /* figure out the memory address */
2163 if (mod == 0) {
2164 if (rm == 6) {
2165 ofs = softx86_fetch_exec_byte(ctx);
2166 ofs |= softx86_fetch_exec_byte(ctx)<<8;
2167 }
2168 else if (rm == 0)
2169 ofs = ctx->state->general_reg[SX86_REG_BX].w.lo +
2170 ctx->state->general_reg[SX86_REG_SI].w.lo;
2171 else if (rm == 1)
2172 ofs = ctx->state->general_reg[SX86_REG_BX].w.lo +
2173 ctx->state->general_reg[SX86_REG_DI].w.lo;
2174 else if (rm == 2)
2175 ofs = ctx->state->general_reg[SX86_REG_BP].w.lo +
2176 ctx->state->general_reg[SX86_REG_SI].w.lo;
2177 else if (rm == 3)
2178 ofs = ctx->state->general_reg[SX86_REG_BP].w.lo +
2179 ctx->state->general_reg[SX86_REG_DI].w.lo;
2180 else if (rm == 4)
2181 ofs = ctx->state->general_reg[SX86_REG_SI].w.lo;
2182 else if (rm == 5)
2183 ofs = ctx->state->general_reg[SX86_REG_DI].w.lo;
2184 else if (rm == 7)
2185 ofs = ctx->state->general_reg[SX86_REG_BX].w.lo;
2186 }
2187 else {
2188 sx86_uword xx;
2189
2190 if (rm == 0)
2191 ofs = ctx->state->general_reg[SX86_REG_BX].w.lo +
2192 ctx->state->general_reg[SX86_REG_SI].w.lo;
2193 else if (rm == 1)
2194 ofs = ctx->state->general_reg[SX86_REG_BX].w.lo +
2195 ctx->state->general_reg[SX86_REG_DI].w.lo;
2196 else if (rm == 2)
2197 ofs = ctx->state->general_reg[SX86_REG_BP].w.lo +
2198 ctx->state->general_reg[SX86_REG_SI].w.lo;
2199 else if (rm == 3)
2200 ofs = ctx->state->general_reg[SX86_REG_BP].w.lo +
2201 ctx->state->general_reg[SX86_REG_DI].w.lo;
2202 else if (rm == 4)
2203 ofs = ctx->state->general_reg[SX86_REG_SI].w.lo;
2204 else if (rm == 5)
2205 ofs = ctx->state->general_reg[SX86_REG_DI].w.lo;
2206 else if (rm == 6)
2207 ofs = ctx->state->general_reg[SX86_REG_BP].w.lo;
2208 else if (rm == 7)
2209 ofs = ctx->state->general_reg[SX86_REG_BX].w.lo;
2210
2211 if (mod == 1) {
2212 xx = softx86_fetch_exec_byte(ctx);
2213 if (xx & 0x80) xx |= 0xFF00;
2214 }
2215 else {
2216 xx = softx86_fetch_exec_byte(ctx);
2217 xx |= softx86_fetch_exec_byte(ctx)<<8;
2218 }
2219
2220 ofs = FORCE_WORD_SIZE(ofs + xx);
2221 }
2222
2223 // TODO: For 386+ 32-bit instructions... if (d32) {...}
2224 if (w16) {
2225 sx86_uword rmv;
2226
2227 lo = sx86_far_to_linear(ctx,seg,ofs);
2228 rmv = op16(ctx);
2229 SWAP_WORD_TO_LE(rmv);
2230 softx86_write(ctx,NULL,lo,&rmv,2);
2231 }
2232 else {
2233 sx86_ubyte rmv;
2234
2235 lo = sx86_far_to_linear(ctx,seg,ofs);
2236 rmv = op8(ctx);
2237 softx86_write(ctx,NULL,lo,&rmv,1);
2238 }
2239 }
2240 }
2241
2242 /* general purpose mod/rm executioneer helper for
2243 instructions that need a segment:offset pair
2244 and do not have an immediate operand of specified size.
2245
2246 this is provided to avoid copy and pasting this source code into the emulation
2247 code for *EVERY* instruction.
2248
2249 ctx = CPU context
2250 d32 = 386+ 32-bit data size override (ignored if w16 == 0)
2251 mod/rm = mod/reg/rm unpacked byte
2252 op8 = function to call for emulation of instruction, given 8-bit operand "src"
2253 op16 = function to call for emulation of instruction, given 16-bit operand "src"
2254 op32 = function to call for emulation of instruction, given 32-bit operand "src"
2255
2256 CALL FAR WORD PTR [2045h]
2257 */
2258 void sx86_exec_full_modrmonly_callfar(softx86_ctx* ctx,sx86_ubyte d32,sx86_ubyte mod,sx86_ubyte rm,void (*op16)(softx86_ctx* ctx,sx86_uword seg,sx86_uword ofs),void (*op32)(softx86_ctx* ctx,sx86_udword seg,sx86_udword ofs))
2259 {
2260 if (mod == 3) { /* immediate <-> register */
2261 // invalid, since a seg:off pair does not fit in a register
2262 }
2263 else { /* immediate <-> memory */
2264 sx86_uword seg,ofs;
2265 sx86_udword lo;
2266
2267 if (!ctx->state->is_segment_override)
2268 /* apparently if BP is used (i.e. [BP+BX]) the stack segment is assumed. */
2269 if ((rm == 2 || rm == 3) || (rm == 6 && (mod == 1 || mod == 2)))
2270 seg = ctx->state->segment_reg[SX86_SREG_SS].val;
2271 else
2272 seg = ctx->state->segment_reg[SX86_SREG_DS].val;
2273 else
2274 seg = ctx->state->segment_override;
2275
2276 /* figure out the memory address */
2277 if (mod == 0) {
2278 if (rm == 6) {
2279 ofs = softx86_fetch_exec_byte(ctx);
2280 ofs |= softx86_fetch_exec_byte(ctx)<<8;
2281 }
2282 else if (rm == 0)
2283 ofs = ctx->state->general_reg[SX86_REG_BX].w.lo +
2284 ctx->state->general_reg[SX86_REG_SI].w.lo;
2285 else if (rm == 1)
2286 ofs = ctx->state->general_reg[SX86_REG_BX].w.lo +
2287 ctx->state->general_reg[SX86_REG_DI].w.lo;
2288 else if (rm == 2)
2289 ofs = ctx->state->general_reg[SX86_REG_BP].w.lo +
2290 ctx->state->general_reg[SX86_REG_SI].w.lo;
2291 else if (rm == 3)
2292 ofs = ctx->state->general_reg[SX86_REG_BP].w.lo +
2293 ctx->state->general_reg[SX86_REG_DI].w.lo;
2294 else if (rm == 4)
2295 ofs = ctx->state->general_reg[SX86_REG_SI].w.lo;
2296 else if (rm == 5)
2297 ofs = ctx->state->general_reg[SX86_REG_DI].w.lo;
2298 else if (rm == 7)
2299 ofs = ctx->state->general_reg[SX86_REG_BX].w.lo;
2300 }
2301 else {
2302 sx86_uword xx;
2303
2304 if (rm == 0)
2305 ofs = ctx->state->general_reg[SX86_REG_BX].w.lo +
2306 ctx->state->general_reg[SX86_REG_SI].w.lo;
2307 else if (rm == 1)
2308 ofs = ctx->state->general_reg[SX86_REG_BX].w.lo +
2309 ctx->state->general_reg[SX86_REG_DI].w.lo;
2310 else if (rm == 2)
2311 ofs = ctx->state->general_reg[SX86_REG_BP].w.lo +
2312 ctx->state->general_reg[SX86_REG_SI].w.lo;
2313 else if (rm == 3)
2314 ofs = ctx->state->general_reg[SX86_REG_BP].w.lo +
2315 ctx->state->general_reg[SX86_REG_DI].w.lo;
2316 else if (rm == 4)
2317 ofs = ctx->state->general_reg[SX86_REG_SI].w.lo;
2318 else if (rm == 5)
2319 ofs = ctx->state->general_reg[SX86_REG_DI].w.lo;
2320 else if (rm == 6)
2321 ofs = ctx->state->general_reg[SX86_REG_BP].w.lo;
2322 else if (rm == 7)
2323 ofs = ctx->state->general_reg[SX86_REG_BX].w.lo;
2324
2325 if (mod == 1) {
2326 xx = softx86_fetch_exec_byte(ctx);
2327 if (xx & 0x80) xx |= 0xFF00;
2328 }
2329 else {
2330 xx = softx86_fetch_exec_byte(ctx);
2331 xx |= softx86_fetch_exec_byte(ctx)<<8;
2332 }
2333
2334 ofs = FORCE_WORD_SIZE(ofs + xx);
2335 }
2336
2337 // TODO: For 386+ 32-bit instructions... if (d32) {...}
2338 {
2339 sx86_uword rmv,rmv2;
2340
2341 lo = sx86_far_to_linear(ctx,seg,ofs);
2342 softx86_fetch(ctx,NULL,lo,&rmv,2); lo += 2;
2343 softx86_fetch(ctx,NULL,lo,&rmv2,2);
2344 SWAP_WORD_FROM_LE(rmv);
2345 SWAP_WORD_FROM_LE(rmv2);
2346 op16(ctx,rmv2,rmv);
2347 }
2348 }
2349 }
2350
2351 /* general purpose mod/reg/rm executioneer helper for
2352 the XCHG instruction.
2353
2354 this is provided to avoid copy and pasting this source code into the emulation
2355 code for *EVERY* instruction.
2356
2357 ctx = CPU context
2358 w16 = 16-bit operand flag
2359 d32 = 386+ 32-bit data size override (ignored if w16 == 0)
2360 mod/reg/rm = mod/reg/rm unpacked byte
2361 */
2362 void sx86_exec_full_modregrm_xchg(softx86_ctx* ctx,sx86_ubyte w16,sx86_ubyte d32,sx86_ubyte mod,sx86_ubyte reg,sx86_ubyte rm)
2363 {
2364 if (mod == 3) { /* register <-> register */
2365 // TODO: For 386+ 32-bit instructions... if (d32) {...}
2366 if (w16) {
2367 sx86_uword tmp;
2368
2369 tmp = ctx->state->general_reg[reg].w.lo;
2370 ctx->state->general_reg[reg].w.lo = ctx->state->general_reg[rm].w.lo;
2371 ctx->state->general_reg[rm].w.lo = tmp;
2372 }
2373 else {
2374 sx86_ubyte tmp;
2375
2376 tmp = *(ctx->__private->ptr_regs_8reg[reg]);
2377 *(ctx->__private->ptr_regs_8reg[reg]) = *(ctx->__private->ptr_regs_8reg[rm]);
2378 *(ctx->__private->ptr_regs_8reg[rm]) = tmp;
2379 }
2380 }
2381 else { /* register <-> memory */
2382 sx86_uword seg,ofs;
2383 sx86_udword lo;
2384
2385 if (!ctx->state->is_segment_override)
2386 /* apparently if BP is used (i.e. [BP+BX]) the stack segment is assumed. */
2387 if ((rm == 2 || rm == 3) || (rm == 6 && (mod == 1 || mod == 2)))
2388 seg = ctx->state->segment_reg[SX86_SREG_SS].val;
2389 else
2390 seg = ctx->state->segment_reg[SX86_SREG_DS].val;
2391 else
2392 seg = ctx->state->segment_override;
2393
2394 /* figure out the memory address */
2395 if (mod == 0) {
2396 if (rm == 6) {
2397 ofs = softx86_fetch_exec_byte(ctx);
2398 ofs |= softx86_fetch_exec_byte(ctx)<<8;
2399 }
2400 else if (rm == 0)
2401 ofs = ctx->state->general_reg[SX86_REG_BX].w.lo +
2402 ctx->state->general_reg[SX86_REG_SI].w.lo;
2403 else if (rm == 1)
2404 ofs = ctx->state->general_reg[SX86_REG_BX].w.lo +
2405 ctx->state->general_reg[SX86_REG_DI].w.lo;
2406 else if (rm == 2)
2407 ofs = ctx->state->general_reg[SX86_REG_BP].w.lo +
2408 ctx->state->general_reg[SX86_REG_SI].w.lo;
2409 else if (rm == 3)
2410 ofs = ctx->state->general_reg[SX86_REG_BP].w.lo +
2411 ctx->state->general_reg[SX86_REG_DI].w.lo;
2412 else if (rm == 4)
2413 ofs = ctx->state->general_reg[SX86_REG_SI].w.lo;
2414 else if (rm == 5)
2415 ofs = ctx->state->general_reg[SX86_REG_DI].w.lo;
2416 else if (rm == 7)
2417 ofs = ctx->state->general_reg[SX86_REG_BX].w.lo;
2418 }
2419 else {
2420 sx86_uword xx;
2421
2422 if (rm == 0)
2423 ofs = ctx->state->general_reg[SX86_REG_BX].w.lo +
2424 ctx->state->general_reg[SX86_REG_SI].w.lo;
2425 else if (rm == 1)
2426 ofs = ctx->state->general_reg[SX86_REG_BX].w.lo +
2427 ctx->state->general_reg[SX86_REG_DI].w.lo;
2428 else if (rm == 2)
2429 ofs = ctx->state->general_reg[SX86_REG_BP].w.lo +
2430 ctx->state->general_reg[SX86_REG_SI].w.lo;
2431 else if (rm == 3)
2432 ofs = ctx->state->general_reg[SX86_REG_BP].w.lo +
2433 ctx->state->general_reg[SX86_REG_DI].w.lo;
2434 else if (rm == 4)
2435 ofs = ctx->state->general_reg[SX86_REG_SI].w.lo;
2436 else if (rm == 5)
2437 ofs = ctx->state->general_reg[SX86_REG_DI].w.lo;
2438 else if (rm == 6)
2439 ofs = ctx->state->general_reg[SX86_REG_BP].w.lo;
2440 else if (rm == 7)
2441 ofs = ctx->state->general_reg[SX86_REG_BX].w.lo;
2442
2443 if (mod == 1) {
2444 xx = softx86_fetch_exec_byte(ctx);
2445 if (xx & 0x80) xx |= 0xFF00;
2446 }
2447 else {
2448 xx = softx86_fetch_exec_byte(ctx);
2449 xx |= softx86_fetch_exec_byte(ctx)<<8;
2450 }
2451
2452 ofs = FORCE_WORD_SIZE(ofs + xx);
2453 }
2454
2455 // TODO: For 386+ 32-bit instructions... if (d32) {...}
2456 if (w16) {
2457 sx86_uword tmp,mem;
2458
2459 lo = sx86_far_to_linear(ctx,seg,ofs);
2460 softx86_fetch(ctx,NULL,lo,&mem,2);
2461 SWAP_WORD_FROM_LE(mem);
2462 tmp = ctx->state->general_reg[reg].w.lo;
2463 SWAP_WORD_TO_LE(tmp);
2464 softx86_write(ctx,NULL,lo,&tmp,2);
2465 ctx->state->general_reg[reg].w.lo = mem;
2466 }
2467 else {
2468 sx86_ubyte tmp,mem;
2469
2470 lo = sx86_far_to_linear(ctx,seg,ofs);
2471 softx86_fetch(ctx,NULL,lo,&mem,1);
2472 tmp = *(ctx->__private->ptr_regs_8reg[reg]);
2473 softx86_write(ctx,NULL,lo,&tmp,1);
2474 *(ctx->__private->ptr_regs_8reg[reg]) = mem;
2475 }
2476 }
2477 }
2478
2479 int softx86_parity8(sx86_ubyte ret)
2480 {
2481 int b,p;
2482
2483 p=1;
2484 for (b=0;b < 8;b++) {
2485 p ^= (ret&1);
2486 ret >>= 1;
2487 }
2488
2489 return p;
2490 }
2491
2492 int softx86_parity16(sx86_uword ret)
2493 {
2494 int b,p;
2495
2496 p=1;
2497 for (b=0;b < 16;b++) {
2498 p ^= (ret&1);
2499 ret >>= 1;
2500 }
2501
2502 return p;
2503 }
2504
2505 int softx86_parity32(sx86_udword ret)
2506 {
2507 int b,p;
2508
2509 p=1;
2510 for (b=0;b < 32;b++) {
2511 p ^= (ret&1);
2512 ret >>= 1;
2513 }
2514
2515 return p;
2516 }
2517
2518 int softx86_parity64(sx86_uldword ret)
2519 {
2520 int b,p;
2521
2522 p=1;
2523 for (b=0;b < 64;b++) {
2524 p ^= (ret&1);
2525 ret >>= 1;
2526 }
2527
2528 return p;
2529 }
2530
2531 void sx86_exec_full_modrmonly_memx(softx86_ctx* ctx,sx86_ubyte mod,sx86_ubyte rm,int sz,void (*op64)(softx86_ctx* ctx,char *datz,int sz))
2532 {
2533 if (sz > 16)
2534 return;
2535
2536 if (mod == 3) { /* immediate <-> register */
2537 // invalid
2538 }
2539 else { /* immediate <-> memory */
2540 sx86_uword seg,ofs;
2541 sx86_udword lo;
2542
2543 if (!ctx->state->is_segment_override)
2544 /* apparently if BP is used (i.e. [BP+BX]) the stack segment is assumed. */
2545 if ((rm == 2 || rm == 3) || (rm == 6 && (mod == 1 || mod == 2)))
2546 seg = ctx->state->segment_reg[SX86_SREG_SS].val;
2547 else
2548 seg = ctx->state->segment_reg[SX86_SREG_DS].val;
2549 else
2550 seg = ctx->state->segment_override;
2551
2552 /* figure out the memory address */
2553 if (mod == 0) {
2554 if (rm == 6) {
2555 ofs = softx86_fetch_exec_byte(ctx);
2556 ofs |= softx86_fetch_exec_byte(ctx)<<8;
2557 }
2558 else if (rm == 0)
2559 ofs = ctx->state->general_reg[SX86_REG_BX].w.lo +
2560 ctx->state->general_reg[SX86_REG_SI].w.lo;
2561 else if (rm == 1)
2562 ofs = ctx->state->general_reg[SX86_REG_BX].w.lo +
2563 ctx->state->general_reg[SX86_REG_DI].w.lo;
2564 else if (rm == 2)
2565 ofs = ctx->state->general_reg[SX86_REG_BP].w.lo +
2566 ctx->state->general_reg[SX86_REG_SI].w.lo;
2567 else if (rm == 3)
2568 ofs = ctx->state->general_reg[SX86_REG_BP].w.lo +
2569 ctx->state->general_reg[SX86_REG_DI].w.lo;
2570 else if (rm == 4)
2571 ofs = ctx->state->general_reg[SX86_REG_SI].w.lo;
2572 else if (rm == 5)
2573 ofs = ctx->state->general_reg[SX86_REG_DI].w.lo;
2574 else if (rm == 7)
2575 ofs = ctx->state->general_reg[SX86_REG_BX].w.lo;
2576 }
2577 else {
2578 sx86_uword xx;
2579
2580 if (rm == 0)
2581 ofs = ctx->state->general_reg[SX86_REG_BX].w.lo +
2582 ctx->state->general_reg[SX86_REG_SI].w.lo;
2583 else if (rm == 1)
2584 ofs = ctx->state->general_reg[SX86_REG_BX].w.lo +
2585 ctx->state->general_reg[SX86_REG_DI].w.lo;
2586 else if (rm == 2)
2587 ofs = ctx->state->general_reg[SX86_REG_BP].w.lo +
2588 ctx->state->general_reg[SX86_REG_SI].w.lo;
2589 else if (rm == 3)
2590 ofs = ctx->state->general_reg[SX86_REG_BP].w.lo +
2591 ctx->state->general_reg[SX86_REG_DI].w.lo;
2592 else if (rm == 4)
2593 ofs = ctx->state->general_reg[SX86_REG_SI].w.lo;
2594 else if (rm == 5)
2595 ofs = ctx->state->general_reg[SX86_REG_DI].w.lo;
2596 else if (rm == 6)
2597 ofs = ctx->state->general_reg[SX86_REG_BP].w.lo;
2598 else if (rm == 7)
2599 ofs = ctx->state->general_reg[SX86_REG_BX].w.lo;
2600
2601 if (mod == 1) {
2602 xx = softx86_fetch_exec_byte(ctx);
2603 if (xx & 0x80) xx |= 0xFF00;
2604 }
2605 else {
2606 xx = softx86_fetch_exec_byte(ctx);
2607 xx |= softx86_fetch_exec_byte(ctx)<<8;
2608 }
2609
2610 ofs = FORCE_WORD_SIZE(ofs + xx);
2611 }
2612
2613 // TODO: For 386+ 32-bit instructions... if (d32) {...}
2614 {
2615 sx86_ubyte tmp[16];
2616
2617 lo = sx86_far_to_linear(ctx,seg,ofs);
2618 softx86_fetch(ctx,NULL,lo,tmp,sz);
2619 op64(ctx,tmp,sz);
2620 }
2621 }
2622 }
2623
2624 void sx86_exec_full_modrw_memx(softx86_ctx* ctx,sx86_ubyte mod,sx86_ubyte rm,int sz,void (*op64)(softx86_ctx* ctx,char *datz,int sz))
2625 {
2626 if (sz > 16)
2627 return;
2628
2629 if (mod == 3) { /* immediate <-> register */
2630 // invalid
2631 }
2632 else { /* immediate <-> memory */
2633 sx86_uword seg,ofs;
2634 sx86_udword lo;
2635
2636 if (!ctx->state->is_segment_override)
2637 /* apparently if BP is used (i.e. [BP+BX]) the stack segment is assumed. */
2638 if ((rm == 2 || rm == 3) || (rm == 6 && (mod == 1 || mod == 2)))
2639 seg = ctx->state->segment_reg[SX86_SREG_SS].val;
2640 else
2641 seg = ctx->state->segment_reg[SX86_SREG_DS].val;
2642 else
2643 seg = ctx->state->segment_override;
2644
2645 /* figure out the memory address */
2646 if (mod == 0) {
2647 if (rm == 6) {
2648 ofs = softx86_fetch_exec_byte(ctx);
2649 ofs |= softx86_fetch_exec_byte(ctx)<<8;
2650 }
2651 else if (rm == 0)
2652 ofs = ctx->state->general_reg[SX86_REG_BX].w.lo +
2653 ctx->state->general_reg[SX86_REG_SI].w.lo;
2654 else if (rm == 1)
2655 ofs = ctx->state->general_reg[SX86_REG_BX].w.lo +
2656 ctx->state->general_reg[SX86_REG_DI].w.lo;
2657 else if (rm == 2)
2658 ofs = ctx->state->general_reg[SX86_REG_BP].w.lo +
2659 ctx->state->general_reg[SX86_REG_SI].w.lo;
2660 else if (rm == 3)
2661 ofs = ctx->state->general_reg[SX86_REG_BP].w.lo +
2662 ctx->state->general_reg[SX86_REG_DI].w.lo;
2663 else if (rm == 4)
2664 ofs = ctx->state->general_reg[SX86_REG_SI].w.lo;
2665 else if (rm == 5)
2666 ofs = ctx->state->general_reg[SX86_REG_DI].w.lo;
2667 else if (rm == 7)
2668 ofs = ctx->state->general_reg[SX86_REG_BX].w.lo;
2669 }
2670 else {
2671 sx86_uword xx;
2672
2673 if (rm == 0)
2674 ofs = ctx->state->general_reg[SX86_REG_BX].w.lo +
2675 ctx->state->general_reg[SX86_REG_SI].w.lo;
2676 else if (rm == 1)
2677 ofs = ctx->state->general_reg[SX86_REG_BX].w.lo +
2678 ctx->state->general_reg[SX86_REG_DI].w.lo;
2679 else if (rm == 2)
2680 ofs = ctx->state->general_reg[SX86_REG_BP].w.lo +
2681 ctx->state->general_reg[SX86_REG_SI].w.lo;
2682 else if (rm == 3)
2683 ofs = ctx->state->general_reg[SX86_REG_BP].w.lo +
2684 ctx->state->general_reg[SX86_REG_DI].w.lo;
2685 else if (rm == 4)
2686 ofs = ctx->state->general_reg[SX86_REG_SI].w.lo;
2687 else if (rm == 5)
2688 ofs = ctx->state->general_reg[SX86_REG_DI].w.lo;
2689 else if (rm == 6)
2690 ofs = ctx->state->general_reg[SX86_REG_BP].w.lo;
2691 else if (rm == 7)
2692 ofs = ctx->state->general_reg[SX86_REG_BX].w.lo;
2693
2694 if (mod == 1) {
2695 xx = softx86_fetch_exec_byte(ctx);
2696 if (xx & 0x80) xx |= 0xFF00;
2697 }
2698 else {
2699 xx = softx86_fetch_exec_byte(ctx);
2700 xx |= softx86_fetch_exec_byte(ctx)<<8;
2701 }
2702
2703 ofs = FORCE_WORD_SIZE(ofs + xx);
2704 }
2705
2706 // TODO: For 386+ 32-bit instructions... if (d32) {...}
2707 {
2708 sx86_ubyte tmp[16];
2709
2710 lo = sx86_far_to_linear(ctx,seg,ofs);
2711 softx86_fetch(ctx,NULL,lo,tmp,sz);
2712 op64(ctx,tmp,sz);
2713 softx86_write(ctx,NULL,lo,tmp,sz);
2714 }
2715 }
2716 }
2717
2718 /* general purpose mod/segreg/rm executioneer helper for
2719 instructions that modify the destination operand.
2720
2721 this is provided to avoid copy and pasting this source code into the emulation
2722 of *EVERY* instruction.
2723
2724 ctx = CPU context
2725 mod/reg/rm = mod/reg/rm unpacked byte
2726 op16 = function to call for emulation of instruction, given 16-bit operands "src" and "dst"
2727
2728 MOV AX,ES
2729 MOV CS,BX
2730 MOV ES,WORD PTR [3939h]
2731 MOV WORD PTR [9393h],DS
2732 */
2733 void sx86_exec_full_modsregrm_rw(softx86_ctx* ctx,sx86_ubyte mod,sx86_ubyte reg,sx86_ubyte rm,sx86_ubyte opswap,sx86_uword (*op16)(softx86_ctx* ctx,sx86_uword src,sx86_uword val))
2734 {
2735 sx86_uword regv,rmv;
2736
2737 /* because not all segreg values are valid, check validity now! */
2738 if (reg >= 4) { /* the 8086 does not have FS and GS */
2739 /* TODO: Invalid opcode exception */
2740 return;
2741 }
2742
2743 if (mod == 3) { /* segment register <-> register */
2744 regv = ctx->state->segment_reg[reg].val;
2745 rmv = ctx->state->general_reg[rm].w.lo;
2746
2747 if (opswap) {
2748 /* REMEMBER: WE NEVER DIRECTLY MODIFY THE SEGMENT REGISTER VALUES! */
2749 /* *(ctx->ptr_segregs[reg]) =
2750 op16(ctx,rmv,regv); */
2751 softx86_setsegval(ctx,reg,rmv);
2752 }
2753 else {
2754 ctx->state->general_reg[rm].w.lo =
2755 op16(ctx,rmv,regv);
2756 }
2757 }
2758 else { /* segment register <-> memory */
2759 sx86_uword seg,ofs;
2760 sx86_udword lo;
2761
2762 if (!ctx->state->is_segment_override)
2763 /* apparently if BP is used (i.e. [BP+BX]) the stack segment is assumed. */
2764 if ((rm == 2 || rm == 3) || (rm == 6 && (mod == 1 || mod == 2)))
2765 seg = ctx->state->segment_reg[SX86_SREG_SS].val;
2766 else
2767 seg = ctx->state->segment_reg[SX86_SREG_DS].val;
2768 else
2769 seg = ctx->state->segment_override;
2770
2771 /* figure out the memory address */
2772 if (mod == 0) {
2773 if (rm == 6) {
2774 ofs = softx86_fetch_exec_byte(ctx);
2775 ofs |= softx86_fetch_exec_byte(ctx)<<8;
2776 }
2777 else if (rm == 0)
2778 ofs = ctx->state->general_reg[SX86_REG_BX].w.lo +
2779 ctx->state->general_reg[SX86_REG_SI].w.lo;
2780 else if (rm == 1)
2781 ofs = ctx->state->general_reg[SX86_REG_BX].w.lo +
2782 ctx->state->general_reg[SX86_REG_DI].w.lo;
2783 else if (rm == 2)
2784 ofs = ctx->state->general_reg[SX86_REG_BP].w.lo +
2785 ctx->state->general_reg[SX86_REG_SI].w.lo;
2786 else if (rm == 3)
2787 ofs = ctx->state->general_reg[SX86_REG_BP].w.lo +
2788 ctx->state->general_reg[SX86_REG_DI].w.lo;
2789 else if (rm == 4)
2790 ofs = ctx->state->general_reg[SX86_REG_SI].w.lo;
2791 else if (rm == 5)
2792 ofs = ctx->state->general_reg[SX86_REG_DI].w.lo;
2793 else if (rm == 7)
2794 ofs = ctx->state->general_reg[SX86_REG_BX].w.lo;
2795 }
2796 else {
2797 sx86_uword xx;
2798
2799 if (rm == 0)
2800 ofs = ctx->state->general_reg[SX86_REG_BX].w.lo +
2801 ctx->state->general_reg[SX86_REG_SI].w.lo;
2802 else if (rm == 1)
2803 ofs = ctx->state->general_reg[SX86_REG_BX].w.lo +
2804 ctx->state->general_reg[SX86_REG_DI].w.lo;
2805 else if (rm == 2)
2806 ofs = ctx->state->general_reg[SX86_REG_BP].w.lo +
2807 ctx->state->general_reg[SX86_REG_SI].w.lo;
2808 else if (rm == 3)
2809 ofs = ctx->state->general_reg[SX86_REG_BP].w.lo +
2810 ctx->state->general_reg[SX86_REG_DI].w.lo;
2811 else if (rm == 4)
2812 ofs = ctx->state->general_reg[SX86_REG_SI].w.lo;
2813 else if (rm == 5)
2814 ofs = ctx->state->general_reg[SX86_REG_DI].w.lo;
2815 else if (rm == 6)
2816 ofs = ctx->state->general_reg[SX86_REG_BP].w.lo;
2817 else if (rm == 7)
2818 ofs = ctx->state->general_reg[SX86_REG_BX].w.lo;
2819
2820 if (mod == 1) {
2821 xx = softx86_fetch_exec_byte(ctx);
2822 if (xx & 0x80) xx |= 0xFF00;
2823 }
2824 else {
2825 xx = softx86_fetch_exec_byte(ctx);
2826 xx |= softx86_fetch_exec_byte(ctx)<<8;
2827 }
2828
2829 ofs = FORCE_WORD_SIZE(ofs + xx);
2830 }
2831
2832 regv = ctx->state->segment_reg[reg].val;
2833 lo = sx86_far_to_linear(ctx,seg,ofs);
2834 softx86_fetch(ctx,NULL,lo,&rmv,2);
2835 SWAP_WORD_FROM_LE(rmv);
2836
2837 if (opswap) {
2838 /* REMEMBER: WE NEVER DIRECTLY MODIFY THE SEGMENT REGISTER VALUES! */
2839 /* *(ctx->ptr_segregs[reg]) =
2840 op16(ctx,rmv,regv); */
2841 softx86_setsegval(ctx,reg,rmv);
2842 }
2843 else {
2844 rmv = op16(ctx,rmv,regv);
2845 SWAP_WORD_TO_LE(rmv);
2846 softx86_write(ctx,NULL,lo,&rmv,2);
2847 }
2848 }
2849 }
2850
2851 /* basic mod/reg/rm full-use decompiling.
2852 ctx = CPU context struct
2853 is_word = word value
2854 dat32 = 32-bit 386+ data override
2855 mod/reg/rm
2856 op1 = buffer for r/m
2857 op2 = buffer for reg */
2858 void sx86_dec_full_modregrm(softx86_ctx* ctx,sx86_ubyte is_word,sx86_ubyte dat32,sx86_ubyte mod,sx86_ubyte reg,sx86_ubyte rm,char* op1,char* op2)
2859 {
2860 sx86_uword o;
2861
2862 if (is_word)
2863 if (dat32)
2864 sprintf(op2,"%s",sx86_regs32[reg]);
2865 else
2866 sprintf(op2,"%s",sx86_regs16[reg]);
2867 else
2868 sprintf(op2,"%s",sx86_regs8[reg]);
2869
2870 if (mod == 3) { /* destination: register */
2871 if (is_word)
2872 if (dat32)
2873 sprintf(op1,"%s",sx86_regs32[rm]);
2874 else
2875 sprintf(op1,"%s",sx86_regs16[rm]);
2876 else
2877 sprintf(op1,"%s",sx86_regs8[rm]);
2878 }
2879 else if (mod == 0) { /* destination: memory address */
2880 if (rm == 6) {
2881 o = softx86_fetch_dec_byte(ctx);
2882 o |= softx86_fetch_dec_byte(ctx)<<8;
2883 sprintf(op1,"[%04Xh]",o);
2884 }
2885 else {
2886 sprintf(op1,"[%s]",sx86_regsaddr16_16[rm]);
2887 }
2888 }
2889 else { /* destination: memory address + offset */
2890 if (mod == 1) {
2891 o = softx86_fetch_dec_byte(ctx);
2892 if (o & 0x80) o |= 0xFF00;
2893 }
2894 else if (mod == 2) {
2895 o = softx86_fetch_dec_byte(ctx);
2896 o |= softx86_fetch_dec_byte(ctx)<<8;
2897 }
2898
2899 sprintf(op1,"[%s+%04Xh]",sx86_regsaddr16_16[rm],o);
2900 }
2901 }
2902
2903 /* basic mod/rm full-use decompiling (reg used for another purpose)
2904 ctx = CPU context struct
2905 is_word = word value
2906 dat32 = 32-bit 386+ data override
2907 mod/rm
2908 op1 = buffer for r/m */
2909 void sx86_dec_full_modrmonly(softx86_ctx* ctx,sx86_ubyte is_word,sx86_ubyte dat32,sx86_ubyte mod,sx86_ubyte rm,char* op1)
2910 {
2911 sx86_uword o;
2912
2913 if (mod == 3) { /* destination: register */
2914 if (is_word)
2915 if (dat32)
2916 sprintf(op1,"%s",sx86_regs32[rm]);
2917 else
2918 sprintf(op1,"%s",sx86_regs16[rm]);
2919 else
2920 sprintf(op1,"%s",sx86_regs8[rm]);
2921 }
2922 else if (mod == 0) { /* destination: memory address */
2923 if (rm == 6) {
2924 o = softx86_fetch_dec_byte(ctx);
2925 o |= softx86_fetch_dec_byte(ctx)<<8;
2926 sprintf(op1,"[%04Xh]",o);
2927 }
2928 else {
2929 sprintf(op1,"[%s]",sx86_regsaddr16_16[rm]);
2930 }
2931 }
2932 else { /* destination: memory address + offset */
2933 if (mod == 1) {
2934 o = softx86_fetch_dec_byte(ctx);
2935 if (o & 0x80) o |= 0xFF00;
2936 }
2937 else if (mod == 2) {
2938 o = softx86_fetch_dec_byte(ctx);
2939 o |= softx86_fetch_dec_byte(ctx)<<8;
2940 }
2941
2942 sprintf(op1,"[%s+%04Xh]",sx86_regsaddr16_16[rm],o);
2943 }
2944 }
2945
2946 /* basic mod/segreg/rm full-use decompiling.
2947 ctx = CPU context struct
2948 is_word = word value
2949 dat32 = 32-bit 386+ data override
2950 mod/reg/rm where "reg" refers to a segment register
2951 op1 = buffer for r/m
2952 op2 = buffer for reg */
2953 void sx86_dec_full_modsregrm(softx86_ctx* ctx,sx86_ubyte mod,sx86_ubyte reg,sx86_ubyte rm,char* op1,char* op2)
2954 {
2955 sx86_uword o;
2956
2957 sprintf(op2,"%s",sx86_segregs[reg]);
2958
2959 if (mod == 3) { /* destination: register */
2960 sprintf(op1,"%s",sx86_regs16[rm]);
2961 }
2962 else if (mod == 0) { /* destination: memory address */
2963 if (rm == 6) {
2964 o = softx86_fetch_dec_byte(ctx);
2965 o |= softx86_fetch_dec_byte(ctx)<<8;
2966 sprintf(op1,"[%04Xh]",o);
2967 }
2968 else {
2969 sprintf(op1,"[%s]",sx86_regsaddr16_16[rm]);
2970 }
2971 }
2972 else { /* destination: memory address + offset */
2973 if (mod == 1) {
2974 o = softx86_fetch_dec_byte(ctx);
2975 if (o & 0x80) o |= 0xFF00;
2976 }
2977 else if (mod == 2) {
2978 o = softx86_fetch_dec_byte(ctx);
2979 o |= softx86_fetch_dec_byte(ctx)<<8;
2980 }
2981
2982 sprintf(op1,"[%s+%04Xh]",sx86_regsaddr16_16[rm],o);
2983 }
2984 }
2985