da6150189f8dd12517ed29597a3b2e16021a0c1d
[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 {
1449 if (sx) imm |= (imm&0x80) ? 0xFF80 : 0;
1450 else imm |= softx86_fetch_exec_byte(ctx)<<8;
1451 }
1452
1453 // TODO: For 386+ 32-bit instructions... if (d32) {...}
1454 if (w16) {
1455 sx86_uword rmv;
1456
1457 rmv = ctx->state->general_reg[rm].w.lo;
1458
1459 ctx->state->general_reg[rm].w.lo =
1460 op16(ctx,rmv,(sx86_uword)imm);
1461 }
1462 else {
1463 sx86_ubyte rmv;
1464
1465 rmv = *(ctx->__private->ptr_regs_8reg[rm]);
1466
1467 *(ctx->__private->ptr_regs_8reg[rm]) =
1468 op8(ctx,rmv,(sx86_ubyte)imm);
1469 }
1470 }
1471 else { /* immediate <-> memory */
1472 sx86_uword seg,ofs;
1473 sx86_udword lo;
1474
1475 if (!ctx->state->is_segment_override)
1476 /* apparently if BP is used (i.e. [BP+BX]) the stack segment is assumed. */
1477 if ((rm == 2 || rm == 3) || (rm == 6 && (mod == 1 || mod == 2)))
1478 seg = ctx->state->segment_reg[SX86_SREG_SS].val;
1479 else
1480 seg = ctx->state->segment_reg[SX86_SREG_DS].val;
1481 else
1482 seg = ctx->state->segment_override;
1483
1484 /* figure out the memory address */
1485 if (mod == 0) {
1486 if (rm == 6) {
1487 ofs = softx86_fetch_exec_byte(ctx);
1488 ofs |= softx86_fetch_exec_byte(ctx)<<8;
1489 }
1490 else if (rm == 0)
1491 ofs = ctx->state->general_reg[SX86_REG_BX].w.lo +
1492 ctx->state->general_reg[SX86_REG_SI].w.lo;
1493 else if (rm == 1)
1494 ofs = ctx->state->general_reg[SX86_REG_BX].w.lo +
1495 ctx->state->general_reg[SX86_REG_DI].w.lo;
1496 else if (rm == 2)
1497 ofs = ctx->state->general_reg[SX86_REG_BP].w.lo +
1498 ctx->state->general_reg[SX86_REG_SI].w.lo;
1499 else if (rm == 3)
1500 ofs = ctx->state->general_reg[SX86_REG_BP].w.lo +
1501 ctx->state->general_reg[SX86_REG_DI].w.lo;
1502 else if (rm == 4)
1503 ofs = ctx->state->general_reg[SX86_REG_SI].w.lo;
1504 else if (rm == 5)
1505 ofs = ctx->state->general_reg[SX86_REG_DI].w.lo;
1506 else if (rm == 7)
1507 ofs = ctx->state->general_reg[SX86_REG_BX].w.lo;
1508 }
1509 else {
1510 sx86_uword xx;
1511
1512 if (rm == 0)
1513 ofs = ctx->state->general_reg[SX86_REG_BX].w.lo +
1514 ctx->state->general_reg[SX86_REG_SI].w.lo;
1515 else if (rm == 1)
1516 ofs = ctx->state->general_reg[SX86_REG_BX].w.lo +
1517 ctx->state->general_reg[SX86_REG_DI].w.lo;
1518 else if (rm == 2)
1519 ofs = ctx->state->general_reg[SX86_REG_BP].w.lo +
1520 ctx->state->general_reg[SX86_REG_SI].w.lo;
1521 else if (rm == 3)
1522 ofs = ctx->state->general_reg[SX86_REG_BP].w.lo +
1523 ctx->state->general_reg[SX86_REG_DI].w.lo;
1524 else if (rm == 4)
1525 ofs = ctx->state->general_reg[SX86_REG_SI].w.lo;
1526 else if (rm == 5)
1527 ofs = ctx->state->general_reg[SX86_REG_DI].w.lo;
1528 else if (rm == 6)
1529 ofs = ctx->state->general_reg[SX86_REG_BP].w.lo;
1530 else if (rm == 7)
1531 ofs = ctx->state->general_reg[SX86_REG_BX].w.lo;
1532
1533 if (mod == 1) {
1534 xx = softx86_fetch_exec_byte(ctx);
1535 if (xx & 0x80) xx |= 0xFF00;
1536 }
1537 else {
1538 xx = softx86_fetch_exec_byte(ctx);
1539 xx |= softx86_fetch_exec_byte(ctx)<<8;
1540 }
1541
1542 ofs = FORCE_WORD_SIZE(ofs + xx);
1543 }
1544
1545 imm = softx86_fetch_exec_byte(ctx);
1546 if (w16)
1547 {
1548 if (sx) imm |= (imm&0x80) ? 0xFF80 : 0;
1549 else imm |= softx86_fetch_exec_byte(ctx)<<8;
1550 }
1551
1552 // TODO: For 386+ 32-bit instructions... if (d32) {...}
1553 if (w16) {
1554 sx86_uword rmv;
1555
1556 lo = sx86_far_to_linear(ctx,seg,ofs);
1557 softx86_fetch(ctx,NULL,lo,&rmv,2);
1558 SWAP_WORD_FROM_LE(rmv);
1559
1560 rmv = op16(ctx,rmv,(sx86_uword)imm);
1561 SWAP_WORD_TO_LE(rmv);
1562 softx86_write(ctx,NULL,lo,&rmv,2);
1563 }
1564 else {
1565 sx86_ubyte rmv;
1566
1567 lo = sx86_far_to_linear(ctx,seg,ofs);
1568 softx86_fetch(ctx,NULL,lo,&rmv,1);
1569
1570 rmv = op8(ctx,rmv,(sx86_ubyte)imm);
1571 softx86_write(ctx,NULL,lo,&rmv,1);
1572 }
1573 }
1574 }
1575
1576 /* general purpose mod/rm executioneer helper for
1577 instructions that modify the destination operand
1578 and have an immediate operand of specified size.
1579
1580 this is provided to avoid copy and pasting this source code into the emulation
1581 code for *EVERY* instruction.
1582
1583 ctx = CPU context
1584 w16 = 16-bit operand flag
1585 d32 = 386+ 32-bit data size override (ignored if w16 == 0)
1586 mod/rm = mod/reg/rm unpacked byte
1587 op8 = function to call for emulation of instruction, given 8-bit operands "src" and "dst"
1588 op16 = function to call for emulation of instruction, given 16-bit operands "src" and "dst"
1589 op32 = function to call for emulation of instruction, given 32-bit operands "src" and "dst"
1590
1591 Example of instructions that fit this format:
1592
1593 MOV AH,2456h
1594 MOV WORD PTR [1334h],2222h
1595 */
1596 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))
1597 {
1598 sx86_uword imm;
1599
1600 if (mod == 3) { /* immediate <-> register */
1601 imm = softx86_fetch_exec_byte(ctx);
1602
1603 // TODO: For 386+ 32-bit instructions... if (d32) {...}
1604 if (w16) {
1605 sx86_uword rmv;
1606
1607 rmv = ctx->state->general_reg[rm].w.lo;
1608
1609 ctx->state->general_reg[rm].w.lo =
1610 op16(ctx,rmv,(sx86_uword)imm);
1611 }
1612 else {
1613 sx86_ubyte rmv;
1614
1615 rmv = *(ctx->__private->ptr_regs_8reg[rm]);
1616
1617 *(ctx->__private->ptr_regs_8reg[rm]) =
1618 op8(ctx,rmv,(sx86_ubyte)imm);
1619 }
1620 }
1621 else { /* immediate <-> memory */
1622 sx86_uword seg,ofs;
1623 sx86_udword lo;
1624
1625 if (!ctx->state->is_segment_override)
1626 /* apparently if BP is used (i.e. [BP+BX]) the stack segment is assumed. */
1627 if ((rm == 2 || rm == 3) || (rm == 6 && (mod == 1 || mod == 2)))
1628 seg = ctx->state->segment_reg[SX86_SREG_SS].val;
1629 else
1630 seg = ctx->state->segment_reg[SX86_SREG_DS].val;
1631 else
1632 seg = ctx->state->segment_override;
1633
1634 /* figure out the memory address */
1635 if (mod == 0) {
1636 if (rm == 6) {
1637 ofs = softx86_fetch_exec_byte(ctx);
1638 ofs |= softx86_fetch_exec_byte(ctx)<<8;
1639 }
1640 else if (rm == 0)
1641 ofs = ctx->state->general_reg[SX86_REG_BX].w.lo +
1642 ctx->state->general_reg[SX86_REG_SI].w.lo;
1643 else if (rm == 1)
1644 ofs = ctx->state->general_reg[SX86_REG_BX].w.lo +
1645 ctx->state->general_reg[SX86_REG_DI].w.lo;
1646 else if (rm == 2)
1647 ofs = ctx->state->general_reg[SX86_REG_BP].w.lo +
1648 ctx->state->general_reg[SX86_REG_SI].w.lo;
1649 else if (rm == 3)
1650 ofs = ctx->state->general_reg[SX86_REG_BP].w.lo +
1651 ctx->state->general_reg[SX86_REG_DI].w.lo;
1652 else if (rm == 4)
1653 ofs = ctx->state->general_reg[SX86_REG_SI].w.lo;
1654 else if (rm == 5)
1655 ofs = ctx->state->general_reg[SX86_REG_DI].w.lo;
1656 else if (rm == 7)
1657 ofs = ctx->state->general_reg[SX86_REG_BX].w.lo;
1658 }
1659 else {
1660 sx86_uword xx;
1661
1662 if (rm == 0)
1663 ofs = ctx->state->general_reg[SX86_REG_BX].w.lo +
1664 ctx->state->general_reg[SX86_REG_SI].w.lo;
1665 else if (rm == 1)
1666 ofs = ctx->state->general_reg[SX86_REG_BX].w.lo +
1667 ctx->state->general_reg[SX86_REG_DI].w.lo;
1668 else if (rm == 2)
1669 ofs = ctx->state->general_reg[SX86_REG_BP].w.lo +
1670 ctx->state->general_reg[SX86_REG_SI].w.lo;
1671 else if (rm == 3)
1672 ofs = ctx->state->general_reg[SX86_REG_BP].w.lo +
1673 ctx->state->general_reg[SX86_REG_DI].w.lo;
1674 else if (rm == 4)
1675 ofs = ctx->state->general_reg[SX86_REG_SI].w.lo;
1676 else if (rm == 5)
1677 ofs = ctx->state->general_reg[SX86_REG_DI].w.lo;
1678 else if (rm == 6)
1679 ofs = ctx->state->general_reg[SX86_REG_BP].w.lo;
1680 else if (rm == 7)
1681 ofs = ctx->state->general_reg[SX86_REG_BX].w.lo;
1682
1683 if (mod == 1) {
1684 xx = softx86_fetch_exec_byte(ctx);
1685 if (xx & 0x80) xx |= 0xFF00;
1686 }
1687 else {
1688 xx = softx86_fetch_exec_byte(ctx);
1689 xx |= softx86_fetch_exec_byte(ctx)<<8;
1690 }
1691
1692 ofs = FORCE_WORD_SIZE(ofs + xx);
1693 }
1694
1695 imm = softx86_fetch_exec_byte(ctx);
1696 if (w16) imm |= softx86_fetch_exec_byte(ctx)<<8;
1697
1698 // TODO: For 386+ 32-bit instructions... if (d32) {...}
1699 if (w16) {
1700 sx86_uword rmv;
1701
1702 lo = sx86_far_to_linear(ctx,seg,ofs);
1703 softx86_fetch(ctx,NULL,lo,&rmv,2);
1704 SWAP_WORD_FROM_LE(rmv);
1705
1706 rmv = op16(ctx,rmv,(sx86_uword)imm);
1707 SWAP_WORD_TO_LE(rmv);
1708 softx86_write(ctx,NULL,lo,&rmv,2);
1709 }
1710 else {
1711 sx86_ubyte rmv;
1712
1713 lo = sx86_far_to_linear(ctx,seg,ofs);
1714 softx86_fetch(ctx,NULL,lo,&rmv,1);
1715
1716 rmv = op8(ctx,rmv,(sx86_ubyte)imm);
1717 softx86_write(ctx,NULL,lo,&rmv,1);
1718 }
1719 }
1720 }
1721
1722 /* general purpose mod/rm executioneer helper for
1723 instructions that DO NOT modify the destination operand
1724 and have an immediate operand of specified size.
1725
1726 this is provided to avoid copy and pasting this source code into the emulation
1727 code for *EVERY* instruction.
1728
1729 ctx = CPU context
1730 w16 = 16-bit operand flag
1731 d32 = 386+ 32-bit data size override (ignored if w16 == 0)
1732 mod/rm = mod/reg/rm unpacked byte
1733 op8 = function to call for emulation of instruction, given 8-bit operands "src" and "dst"
1734 op16 = function to call for emulation of instruction, given 16-bit operands "src" and "dst"
1735 op32 = function to call for emulation of instruction, given 32-bit operands "src" and "dst"
1736
1737 Example of instructions that fit this format:
1738
1739 MOV AH,2456h
1740 MOV WORD PTR [1334h],2222h
1741 */
1742 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)
1743 {
1744 sx86_uword imm;
1745
1746 if (mod == 3) { /* immediate <-> register */
1747 imm = softx86_fetch_exec_byte(ctx);
1748 if (w16)
1749 {
1750 if (sx) imm |= (imm&0x80) ? 0xFF80 : 0;
1751 else imm |= softx86_fetch_exec_byte(ctx)<<8;
1752 }
1753
1754 // TODO: For 386+ 32-bit instructions... if (d32) {...}
1755 if (w16) {
1756 sx86_uword rmv;
1757
1758 rmv = ctx->state->general_reg[rm].w.lo;
1759 op16(ctx,rmv,(sx86_uword)imm);
1760 }
1761 else {
1762 sx86_ubyte rmv;
1763
1764 rmv = *(ctx->__private->ptr_regs_8reg[rm]);
1765 op8(ctx,rmv,(sx86_ubyte)imm);
1766 }
1767 }
1768 else { /* immediate <-> memory */
1769 sx86_uword seg,ofs;
1770 sx86_udword lo;
1771
1772 if (!ctx->state->is_segment_override)
1773 /* apparently if BP is used (i.e. [BP+BX]) the stack segment is assumed. */
1774 if ((rm == 2 || rm == 3) || (rm == 6 && (mod == 1 || mod == 2)))
1775 seg = ctx->state->segment_reg[SX86_SREG_SS].val;
1776 else
1777 seg = ctx->state->segment_reg[SX86_SREG_DS].val;
1778 else
1779 seg = ctx->state->segment_override;
1780
1781 /* figure out the memory address */
1782 if (mod == 0) {
1783 if (rm == 6) {
1784 ofs = softx86_fetch_exec_byte(ctx);
1785 ofs |= softx86_fetch_exec_byte(ctx)<<8;
1786 }
1787 else if (rm == 0)
1788 ofs = ctx->state->general_reg[SX86_REG_BX].w.lo +
1789 ctx->state->general_reg[SX86_REG_SI].w.lo;
1790 else if (rm == 1)
1791 ofs = ctx->state->general_reg[SX86_REG_BX].w.lo +
1792 ctx->state->general_reg[SX86_REG_DI].w.lo;
1793 else if (rm == 2)
1794 ofs = ctx->state->general_reg[SX86_REG_BP].w.lo +
1795 ctx->state->general_reg[SX86_REG_SI].w.lo;
1796 else if (rm == 3)
1797 ofs = ctx->state->general_reg[SX86_REG_BP].w.lo +
1798 ctx->state->general_reg[SX86_REG_DI].w.lo;
1799 else if (rm == 4)
1800 ofs = ctx->state->general_reg[SX86_REG_SI].w.lo;
1801 else if (rm == 5)
1802 ofs = ctx->state->general_reg[SX86_REG_DI].w.lo;
1803 else if (rm == 7)
1804 ofs = ctx->state->general_reg[SX86_REG_BX].w.lo;
1805 }
1806 else {
1807 sx86_uword xx;
1808
1809 if (rm == 0)
1810 ofs = ctx->state->general_reg[SX86_REG_BX].w.lo +
1811 ctx->state->general_reg[SX86_REG_SI].w.lo;
1812 else if (rm == 1)
1813 ofs = ctx->state->general_reg[SX86_REG_BX].w.lo +
1814 ctx->state->general_reg[SX86_REG_DI].w.lo;
1815 else if (rm == 2)
1816 ofs = ctx->state->general_reg[SX86_REG_BP].w.lo +
1817 ctx->state->general_reg[SX86_REG_SI].w.lo;
1818 else if (rm == 3)
1819 ofs = ctx->state->general_reg[SX86_REG_BP].w.lo +
1820 ctx->state->general_reg[SX86_REG_DI].w.lo;
1821 else if (rm == 4)
1822 ofs = ctx->state->general_reg[SX86_REG_SI].w.lo;
1823 else if (rm == 5)
1824 ofs = ctx->state->general_reg[SX86_REG_DI].w.lo;
1825 else if (rm == 6)
1826 ofs = ctx->state->general_reg[SX86_REG_BP].w.lo;
1827 else if (rm == 7)
1828 ofs = ctx->state->general_reg[SX86_REG_BX].w.lo;
1829
1830 if (mod == 1) {
1831 xx = softx86_fetch_exec_byte(ctx);
1832 if (xx & 0x80) xx |= 0xFF00;
1833 }
1834 else {
1835 xx = softx86_fetch_exec_byte(ctx);
1836 xx |= softx86_fetch_exec_byte(ctx)<<8;
1837 }
1838
1839 ofs = FORCE_WORD_SIZE(ofs + xx);
1840 }
1841
1842 imm = softx86_fetch_exec_byte(ctx);
1843 if (w16)
1844 {
1845 if (sx) imm |= (imm&0x80) ? 0xFF80 : 0;
1846 else imm |= softx86_fetch_exec_byte(ctx)<<8;
1847 }
1848
1849 // TODO: For 386+ 32-bit instructions... if (d32) {...}
1850 if (w16) {
1851 sx86_uword rmv;
1852
1853 lo = sx86_far_to_linear(ctx,seg,ofs);
1854 softx86_fetch(ctx,NULL,lo,&rmv,2);
1855 SWAP_WORD_FROM_LE(rmv);
1856
1857 op16(ctx,rmv,(sx86_uword)imm);
1858 }
1859 else {
1860 sx86_ubyte rmv;
1861
1862 lo = sx86_far_to_linear(ctx,seg,ofs);
1863 softx86_fetch(ctx,NULL,lo,&rmv,1);
1864
1865 op8(ctx,rmv,(sx86_ubyte)imm);
1866 }
1867 }
1868 }
1869
1870 /* general purpose mod/rm executioneer helper for
1871 instructions that modify the destination operand
1872 and do not have an immediate operand of specified size.
1873
1874 this is provided to avoid copy and pasting this source code into the emulation
1875 code for *EVERY* instruction.
1876
1877 ctx = CPU context
1878 w16 = 16-bit operand flag
1879 d32 = 386+ 32-bit data size override (ignored if w16 == 0)
1880 mod/rm = mod/reg/rm unpacked byte
1881 op8 = function to call for emulation of instruction, given 8-bit operand "src"
1882 op16 = function to call for emulation of instruction, given 16-bit operand "src"
1883 op32 = function to call for emulation of instruction, given 32-bit operand "src"
1884
1885 INC BX
1886 INC WORD PTR [2045h]
1887 */
1888 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))
1889 {
1890 if (mod == 3) { /* immediate <-> register */
1891 // TODO: For 386+ 32-bit instructions... if (d32) {...}
1892 if (w16) {
1893 sx86_uword rmv;
1894
1895 rmv = ctx->state->general_reg[rm].w.lo;
1896
1897 ctx->state->general_reg[rm].w.lo =
1898 op16(ctx,rmv);
1899 }
1900 else {
1901 sx86_ubyte rmv;
1902
1903 rmv = *(ctx->__private->ptr_regs_8reg[rm]);
1904
1905 *(ctx->__private->ptr_regs_8reg[rm]) =
1906 op8(ctx,rmv);
1907 }
1908 }
1909 else { /* immediate <-> memory */
1910 sx86_uword seg,ofs;
1911 sx86_udword lo;
1912
1913 if (!ctx->state->is_segment_override)
1914 /* apparently if BP is used (i.e. [BP+BX]) the stack segment is assumed. */
1915 if ((rm == 2 || rm == 3) || (rm == 6 && (mod == 1 || mod == 2)))
1916 seg = ctx->state->segment_reg[SX86_SREG_SS].val;
1917 else
1918 seg = ctx->state->segment_reg[SX86_SREG_DS].val;
1919 else
1920 seg = ctx->state->segment_override;
1921
1922 /* figure out the memory address */
1923 if (mod == 0) {
1924 if (rm == 6) {
1925 ofs = softx86_fetch_exec_byte(ctx);
1926 ofs |= softx86_fetch_exec_byte(ctx)<<8;
1927 }
1928 else if (rm == 0)
1929 ofs = ctx->state->general_reg[SX86_REG_BX].w.lo +
1930 ctx->state->general_reg[SX86_REG_SI].w.lo;
1931 else if (rm == 1)
1932 ofs = ctx->state->general_reg[SX86_REG_BX].w.lo +
1933 ctx->state->general_reg[SX86_REG_DI].w.lo;
1934 else if (rm == 2)
1935 ofs = ctx->state->general_reg[SX86_REG_BP].w.lo +
1936 ctx->state->general_reg[SX86_REG_SI].w.lo;
1937 else if (rm == 3)
1938 ofs = ctx->state->general_reg[SX86_REG_BP].w.lo +
1939 ctx->state->general_reg[SX86_REG_DI].w.lo;
1940 else if (rm == 4)
1941 ofs = ctx->state->general_reg[SX86_REG_SI].w.lo;
1942 else if (rm == 5)
1943 ofs = ctx->state->general_reg[SX86_REG_DI].w.lo;
1944 else if (rm == 7)
1945 ofs = ctx->state->general_reg[SX86_REG_BX].w.lo;
1946 }
1947 else {
1948 sx86_uword xx;
1949
1950 if (rm == 0)
1951 ofs = ctx->state->general_reg[SX86_REG_BX].w.lo +
1952 ctx->state->general_reg[SX86_REG_SI].w.lo;
1953 else if (rm == 1)
1954 ofs = ctx->state->general_reg[SX86_REG_BX].w.lo +
1955 ctx->state->general_reg[SX86_REG_DI].w.lo;
1956 else if (rm == 2)
1957 ofs = ctx->state->general_reg[SX86_REG_BP].w.lo +
1958 ctx->state->general_reg[SX86_REG_SI].w.lo;
1959 else if (rm == 3)
1960 ofs = ctx->state->general_reg[SX86_REG_BP].w.lo +
1961 ctx->state->general_reg[SX86_REG_DI].w.lo;
1962 else if (rm == 4)
1963 ofs = ctx->state->general_reg[SX86_REG_SI].w.lo;
1964 else if (rm == 5)
1965 ofs = ctx->state->general_reg[SX86_REG_DI].w.lo;
1966 else if (rm == 6)
1967 ofs = ctx->state->general_reg[SX86_REG_BP].w.lo;
1968 else if (rm == 7)
1969 ofs = ctx->state->general_reg[SX86_REG_BX].w.lo;
1970
1971 if (mod == 1) {
1972 xx = softx86_fetch_exec_byte(ctx);
1973 if (xx & 0x80) xx |= 0xFF00;
1974 }
1975 else {
1976 xx = softx86_fetch_exec_byte(ctx);
1977 xx |= softx86_fetch_exec_byte(ctx)<<8;
1978 }
1979
1980 ofs = FORCE_WORD_SIZE(ofs + xx);
1981 }
1982
1983 // TODO: For 386+ 32-bit instructions... if (d32) {...}
1984 if (w16) {
1985 sx86_uword rmv;
1986
1987 lo = sx86_far_to_linear(ctx,seg,ofs);
1988 softx86_fetch(ctx,NULL,lo,&rmv,2);
1989 SWAP_WORD_FROM_LE(rmv);
1990
1991 rmv = op16(ctx,rmv);
1992 SWAP_WORD_TO_LE(rmv);
1993 softx86_write(ctx,NULL,lo,&rmv,2);
1994 }
1995 else {
1996 sx86_ubyte rmv;
1997
1998 lo = sx86_far_to_linear(ctx,seg,ofs);
1999 softx86_fetch(ctx,NULL,lo,&rmv,1);
2000
2001 rmv = op8(ctx,rmv);
2002 softx86_write(ctx,NULL,lo,&rmv,1);
2003 }
2004 }
2005 }
2006
2007 /* general purpose mod/rm executioneer helper for
2008 instructions that do not modify the destination operand
2009 and do not have an immediate operand of specified size.
2010
2011 this is provided to avoid copy and pasting this source code into the emulation
2012 code for *EVERY* instruction.
2013
2014 ctx = CPU context
2015 w16 = 16-bit operand flag
2016 d32 = 386+ 32-bit data size override (ignored if w16 == 0)
2017 mod/rm = mod/reg/rm unpacked byte
2018 op8 = function to call for emulation of instruction, given 8-bit operand "src"
2019 op16 = function to call for emulation of instruction, given 16-bit operand "src"
2020 op32 = function to call for emulation of instruction, given 32-bit operand "src"
2021
2022 CALL WORD PTR [2045h]
2023 */
2024 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))
2025 {
2026 if (mod == 3) { /* immediate <-> register */
2027 // TODO: For 386+ 32-bit instructions... if (d32) {...}
2028 if (w16) {
2029 op16(ctx,ctx->state->general_reg[rm].w.lo);
2030 }
2031 else {
2032 op8(ctx,*(ctx->__private->ptr_regs_8reg[rm]));
2033 }
2034 }
2035 else { /* immediate <-> memory */
2036 sx86_uword seg,ofs;
2037 sx86_udword lo;
2038
2039 if (!ctx->state->is_segment_override)
2040 /* apparently if BP is used (i.e. [BP+BX]) the stack segment is assumed. */
2041 if ((rm == 2 || rm == 3) || (rm == 6 && (mod == 1 || mod == 2)))
2042 seg = ctx->state->segment_reg[SX86_SREG_SS].val;
2043 else
2044 seg = ctx->state->segment_reg[SX86_SREG_DS].val;
2045 else
2046 seg = ctx->state->segment_override;
2047
2048 /* figure out the memory address */
2049 if (mod == 0) {
2050 if (rm == 6) {
2051 ofs = softx86_fetch_exec_byte(ctx);
2052 ofs |= softx86_fetch_exec_byte(ctx)<<8;
2053 }
2054 else if (rm == 0)
2055 ofs = ctx->state->general_reg[SX86_REG_BX].w.lo +
2056 ctx->state->general_reg[SX86_REG_SI].w.lo;
2057 else if (rm == 1)
2058 ofs = ctx->state->general_reg[SX86_REG_BX].w.lo +
2059 ctx->state->general_reg[SX86_REG_DI].w.lo;
2060 else if (rm == 2)
2061 ofs = ctx->state->general_reg[SX86_REG_BP].w.lo +
2062 ctx->state->general_reg[SX86_REG_SI].w.lo;
2063 else if (rm == 3)
2064 ofs = ctx->state->general_reg[SX86_REG_BP].w.lo +
2065 ctx->state->general_reg[SX86_REG_DI].w.lo;
2066 else if (rm == 4)
2067 ofs = ctx->state->general_reg[SX86_REG_SI].w.lo;
2068 else if (rm == 5)
2069 ofs = ctx->state->general_reg[SX86_REG_DI].w.lo;
2070 else if (rm == 7)
2071 ofs = ctx->state->general_reg[SX86_REG_BX].w.lo;
2072 }
2073 else {
2074 sx86_uword xx;
2075
2076 if (rm == 0)
2077 ofs = ctx->state->general_reg[SX86_REG_BX].w.lo +
2078 ctx->state->general_reg[SX86_REG_SI].w.lo;
2079 else if (rm == 1)
2080 ofs = ctx->state->general_reg[SX86_REG_BX].w.lo +
2081 ctx->state->general_reg[SX86_REG_DI].w.lo;
2082 else if (rm == 2)
2083 ofs = ctx->state->general_reg[SX86_REG_BP].w.lo +
2084 ctx->state->general_reg[SX86_REG_SI].w.lo;
2085 else if (rm == 3)
2086 ofs = ctx->state->general_reg[SX86_REG_BP].w.lo +
2087 ctx->state->general_reg[SX86_REG_DI].w.lo;
2088 else if (rm == 4)
2089 ofs = ctx->state->general_reg[SX86_REG_SI].w.lo;
2090 else if (rm == 5)
2091 ofs = ctx->state->general_reg[SX86_REG_DI].w.lo;
2092 else if (rm == 6)
2093 ofs = ctx->state->general_reg[SX86_REG_BP].w.lo;
2094 else if (rm == 7)
2095 ofs = ctx->state->general_reg[SX86_REG_BX].w.lo;
2096
2097 if (mod == 1) {
2098 xx = softx86_fetch_exec_byte(ctx);
2099 if (xx & 0x80) xx |= 0xFF00;
2100 }
2101 else {
2102 xx = softx86_fetch_exec_byte(ctx);
2103 xx |= softx86_fetch_exec_byte(ctx)<<8;
2104 }
2105
2106 ofs = FORCE_WORD_SIZE(ofs + xx);
2107 }
2108
2109 // TODO: For 386+ 32-bit instructions... if (d32) {...}
2110 if (w16) {
2111 sx86_uword rmv;
2112
2113 lo = sx86_far_to_linear(ctx,seg,ofs);
2114 softx86_fetch(ctx,NULL,lo,&rmv,2);
2115 SWAP_WORD_FROM_LE(rmv);
2116 op16(ctx,rmv);
2117 }
2118 else {
2119 sx86_ubyte rmv;
2120
2121 lo = sx86_far_to_linear(ctx,seg,ofs);
2122 softx86_fetch(ctx,NULL,lo,&rmv,1);
2123 op8(ctx,rmv);
2124 }
2125 }
2126 }
2127
2128 /* general purpose mod/rm executioneer helper for
2129 instructions that modify the destination operand
2130 and do not have an immediate operand of specified size.
2131 these functions do not consider the previous value.
2132
2133 this is provided to avoid copy and pasting this source code into the emulation
2134 code for *EVERY* instruction.
2135
2136 ctx = CPU context
2137 w16 = 16-bit operand flag
2138 d32 = 386+ 32-bit data size override (ignored if w16 == 0)
2139 mod/rm = mod/reg/rm unpacked byte
2140 op8 = function to call for emulation of instruction, given 8-bit operand "src"
2141 op16 = function to call for emulation of instruction, given 16-bit operand "src"
2142 op32 = function to call for emulation of instruction, given 32-bit operand "src"
2143
2144 POP WORD PTR [2045h]
2145 */
2146 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))
2147 {
2148 if (mod == 3) { /* immediate <-> register */
2149 // TODO: For 386+ 32-bit instructions... if (d32) {...}
2150 if (w16) {
2151 ctx->state->general_reg[rm].w.lo = op16(ctx);
2152 }
2153 else {
2154 *(ctx->__private->ptr_regs_8reg[rm]) = op8(ctx);
2155 }
2156 }
2157 else { /* immediate <-> memory */
2158 sx86_uword seg,ofs;
2159 sx86_udword lo;
2160
2161 if (!ctx->state->is_segment_override)
2162 /* apparently if BP is used (i.e. [BP+BX]) the stack segment is assumed. */
2163 if ((rm == 2 || rm == 3) || (rm == 6 && (mod == 1 || mod == 2)))
2164 seg = ctx->state->segment_reg[SX86_SREG_SS].val;
2165 else
2166 seg = ctx->state->segment_reg[SX86_SREG_DS].val;
2167 else
2168 seg = ctx->state->segment_override;
2169
2170 /* figure out the memory address */
2171 if (mod == 0) {
2172 if (rm == 6) {
2173 ofs = softx86_fetch_exec_byte(ctx);
2174 ofs |= softx86_fetch_exec_byte(ctx)<<8;
2175 }
2176 else if (rm == 0)
2177 ofs = ctx->state->general_reg[SX86_REG_BX].w.lo +
2178 ctx->state->general_reg[SX86_REG_SI].w.lo;
2179 else if (rm == 1)
2180 ofs = ctx->state->general_reg[SX86_REG_BX].w.lo +
2181 ctx->state->general_reg[SX86_REG_DI].w.lo;
2182 else if (rm == 2)
2183 ofs = ctx->state->general_reg[SX86_REG_BP].w.lo +
2184 ctx->state->general_reg[SX86_REG_SI].w.lo;
2185 else if (rm == 3)
2186 ofs = ctx->state->general_reg[SX86_REG_BP].w.lo +
2187 ctx->state->general_reg[SX86_REG_DI].w.lo;
2188 else if (rm == 4)
2189 ofs = ctx->state->general_reg[SX86_REG_SI].w.lo;
2190 else if (rm == 5)
2191 ofs = ctx->state->general_reg[SX86_REG_DI].w.lo;
2192 else if (rm == 7)
2193 ofs = ctx->state->general_reg[SX86_REG_BX].w.lo;
2194 }
2195 else {
2196 sx86_uword xx;
2197
2198 if (rm == 0)
2199 ofs = ctx->state->general_reg[SX86_REG_BX].w.lo +
2200 ctx->state->general_reg[SX86_REG_SI].w.lo;
2201 else if (rm == 1)
2202 ofs = ctx->state->general_reg[SX86_REG_BX].w.lo +
2203 ctx->state->general_reg[SX86_REG_DI].w.lo;
2204 else if (rm == 2)
2205 ofs = ctx->state->general_reg[SX86_REG_BP].w.lo +
2206 ctx->state->general_reg[SX86_REG_SI].w.lo;
2207 else if (rm == 3)
2208 ofs = ctx->state->general_reg[SX86_REG_BP].w.lo +
2209 ctx->state->general_reg[SX86_REG_DI].w.lo;
2210 else if (rm == 4)
2211 ofs = ctx->state->general_reg[SX86_REG_SI].w.lo;
2212 else if (rm == 5)
2213 ofs = ctx->state->general_reg[SX86_REG_DI].w.lo;
2214 else if (rm == 6)
2215 ofs = ctx->state->general_reg[SX86_REG_BP].w.lo;
2216 else if (rm == 7)
2217 ofs = ctx->state->general_reg[SX86_REG_BX].w.lo;
2218
2219 if (mod == 1) {
2220 xx = softx86_fetch_exec_byte(ctx);
2221 if (xx & 0x80) xx |= 0xFF00;
2222 }
2223 else {
2224 xx = softx86_fetch_exec_byte(ctx);
2225 xx |= softx86_fetch_exec_byte(ctx)<<8;
2226 }
2227
2228 ofs = FORCE_WORD_SIZE(ofs + xx);
2229 }
2230
2231 // TODO: For 386+ 32-bit instructions... if (d32) {...}
2232 if (w16) {
2233 sx86_uword rmv;
2234
2235 lo = sx86_far_to_linear(ctx,seg,ofs);
2236 rmv = op16(ctx);
2237 SWAP_WORD_TO_LE(rmv);
2238 softx86_write(ctx,NULL,lo,&rmv,2);
2239 }
2240 else {
2241 sx86_ubyte rmv;
2242
2243 lo = sx86_far_to_linear(ctx,seg,ofs);
2244 rmv = op8(ctx);
2245 softx86_write(ctx,NULL,lo,&rmv,1);
2246 }
2247 }
2248 }
2249
2250 /* general purpose mod/rm executioneer helper for
2251 instructions that need a segment:offset pair
2252 and do not have an immediate operand of specified size.
2253
2254 this is provided to avoid copy and pasting this source code into the emulation
2255 code for *EVERY* instruction.
2256
2257 ctx = CPU context
2258 d32 = 386+ 32-bit data size override (ignored if w16 == 0)
2259 mod/rm = mod/reg/rm unpacked byte
2260 op8 = function to call for emulation of instruction, given 8-bit operand "src"
2261 op16 = function to call for emulation of instruction, given 16-bit operand "src"
2262 op32 = function to call for emulation of instruction, given 32-bit operand "src"
2263
2264 CALL FAR WORD PTR [2045h]
2265 */
2266 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))
2267 {
2268 if (mod == 3) { /* immediate <-> register */
2269 // invalid, since a seg:off pair does not fit in a register
2270 }
2271 else { /* immediate <-> memory */
2272 sx86_uword seg,ofs;
2273 sx86_udword lo;
2274
2275 if (!ctx->state->is_segment_override)
2276 /* apparently if BP is used (i.e. [BP+BX]) the stack segment is assumed. */
2277 if ((rm == 2 || rm == 3) || (rm == 6 && (mod == 1 || mod == 2)))
2278 seg = ctx->state->segment_reg[SX86_SREG_SS].val;
2279 else
2280 seg = ctx->state->segment_reg[SX86_SREG_DS].val;
2281 else
2282 seg = ctx->state->segment_override;
2283
2284 /* figure out the memory address */
2285 if (mod == 0) {
2286 if (rm == 6) {
2287 ofs = softx86_fetch_exec_byte(ctx);
2288 ofs |= softx86_fetch_exec_byte(ctx)<<8;
2289 }
2290 else if (rm == 0)
2291 ofs = ctx->state->general_reg[SX86_REG_BX].w.lo +
2292 ctx->state->general_reg[SX86_REG_SI].w.lo;
2293 else if (rm == 1)
2294 ofs = ctx->state->general_reg[SX86_REG_BX].w.lo +
2295 ctx->state->general_reg[SX86_REG_DI].w.lo;
2296 else if (rm == 2)
2297 ofs = ctx->state->general_reg[SX86_REG_BP].w.lo +
2298 ctx->state->general_reg[SX86_REG_SI].w.lo;
2299 else if (rm == 3)
2300 ofs = ctx->state->general_reg[SX86_REG_BP].w.lo +
2301 ctx->state->general_reg[SX86_REG_DI].w.lo;
2302 else if (rm == 4)
2303 ofs = ctx->state->general_reg[SX86_REG_SI].w.lo;
2304 else if (rm == 5)
2305 ofs = ctx->state->general_reg[SX86_REG_DI].w.lo;
2306 else if (rm == 7)
2307 ofs = ctx->state->general_reg[SX86_REG_BX].w.lo;
2308 }
2309 else {
2310 sx86_uword xx;
2311
2312 if (rm == 0)
2313 ofs = ctx->state->general_reg[SX86_REG_BX].w.lo +
2314 ctx->state->general_reg[SX86_REG_SI].w.lo;
2315 else if (rm == 1)
2316 ofs = ctx->state->general_reg[SX86_REG_BX].w.lo +
2317 ctx->state->general_reg[SX86_REG_DI].w.lo;
2318 else if (rm == 2)
2319 ofs = ctx->state->general_reg[SX86_REG_BP].w.lo +
2320 ctx->state->general_reg[SX86_REG_SI].w.lo;
2321 else if (rm == 3)
2322 ofs = ctx->state->general_reg[SX86_REG_BP].w.lo +
2323 ctx->state->general_reg[SX86_REG_DI].w.lo;
2324 else if (rm == 4)
2325 ofs = ctx->state->general_reg[SX86_REG_SI].w.lo;
2326 else if (rm == 5)
2327 ofs = ctx->state->general_reg[SX86_REG_DI].w.lo;
2328 else if (rm == 6)
2329 ofs = ctx->state->general_reg[SX86_REG_BP].w.lo;
2330 else if (rm == 7)
2331 ofs = ctx->state->general_reg[SX86_REG_BX].w.lo;
2332
2333 if (mod == 1) {
2334 xx = softx86_fetch_exec_byte(ctx);
2335 if (xx & 0x80) xx |= 0xFF00;
2336 }
2337 else {
2338 xx = softx86_fetch_exec_byte(ctx);
2339 xx |= softx86_fetch_exec_byte(ctx)<<8;
2340 }
2341
2342 ofs = FORCE_WORD_SIZE(ofs + xx);
2343 }
2344
2345 // TODO: For 386+ 32-bit instructions... if (d32) {...}
2346 {
2347 sx86_uword rmv,rmv2;
2348
2349 lo = sx86_far_to_linear(ctx,seg,ofs);
2350 softx86_fetch(ctx,NULL,lo,&rmv,2); lo += 2;
2351 softx86_fetch(ctx,NULL,lo,&rmv2,2);
2352 SWAP_WORD_FROM_LE(rmv);
2353 SWAP_WORD_FROM_LE(rmv2);
2354 op16(ctx,rmv2,rmv);
2355 }
2356 }
2357 }
2358
2359 /* general purpose mod/reg/rm executioneer helper for
2360 the XCHG instruction.
2361
2362 this is provided to avoid copy and pasting this source code into the emulation
2363 code for *EVERY* instruction.
2364
2365 ctx = CPU context
2366 w16 = 16-bit operand flag
2367 d32 = 386+ 32-bit data size override (ignored if w16 == 0)
2368 mod/reg/rm = mod/reg/rm unpacked byte
2369 */
2370 void sx86_exec_full_modregrm_xchg(softx86_ctx* ctx,sx86_ubyte w16,sx86_ubyte d32,sx86_ubyte mod,sx86_ubyte reg,sx86_ubyte rm)
2371 {
2372 if (mod == 3) { /* register <-> register */
2373 // TODO: For 386+ 32-bit instructions... if (d32) {...}
2374 if (w16) {
2375 sx86_uword tmp;
2376
2377 tmp = ctx->state->general_reg[reg].w.lo;
2378 ctx->state->general_reg[reg].w.lo = ctx->state->general_reg[rm].w.lo;
2379 ctx->state->general_reg[rm].w.lo = tmp;
2380 }
2381 else {
2382 sx86_ubyte tmp;
2383
2384 tmp = *(ctx->__private->ptr_regs_8reg[reg]);
2385 *(ctx->__private->ptr_regs_8reg[reg]) = *(ctx->__private->ptr_regs_8reg[rm]);
2386 *(ctx->__private->ptr_regs_8reg[rm]) = tmp;
2387 }
2388 }
2389 else { /* register <-> memory */
2390 sx86_uword seg,ofs;
2391 sx86_udword lo;
2392
2393 if (!ctx->state->is_segment_override)
2394 /* apparently if BP is used (i.e. [BP+BX]) the stack segment is assumed. */
2395 if ((rm == 2 || rm == 3) || (rm == 6 && (mod == 1 || mod == 2)))
2396 seg = ctx->state->segment_reg[SX86_SREG_SS].val;
2397 else
2398 seg = ctx->state->segment_reg[SX86_SREG_DS].val;
2399 else
2400 seg = ctx->state->segment_override;
2401
2402 /* figure out the memory address */
2403 if (mod == 0) {
2404 if (rm == 6) {
2405 ofs = softx86_fetch_exec_byte(ctx);
2406 ofs |= softx86_fetch_exec_byte(ctx)<<8;
2407 }
2408 else if (rm == 0)
2409 ofs = ctx->state->general_reg[SX86_REG_BX].w.lo +
2410 ctx->state->general_reg[SX86_REG_SI].w.lo;
2411 else if (rm == 1)
2412 ofs = ctx->state->general_reg[SX86_REG_BX].w.lo +
2413 ctx->state->general_reg[SX86_REG_DI].w.lo;
2414 else if (rm == 2)
2415 ofs = ctx->state->general_reg[SX86_REG_BP].w.lo +
2416 ctx->state->general_reg[SX86_REG_SI].w.lo;
2417 else if (rm == 3)
2418 ofs = ctx->state->general_reg[SX86_REG_BP].w.lo +
2419 ctx->state->general_reg[SX86_REG_DI].w.lo;
2420 else if (rm == 4)
2421 ofs = ctx->state->general_reg[SX86_REG_SI].w.lo;
2422 else if (rm == 5)
2423 ofs = ctx->state->general_reg[SX86_REG_DI].w.lo;
2424 else if (rm == 7)
2425 ofs = ctx->state->general_reg[SX86_REG_BX].w.lo;
2426 }
2427 else {
2428 sx86_uword xx;
2429
2430 if (rm == 0)
2431 ofs = ctx->state->general_reg[SX86_REG_BX].w.lo +
2432 ctx->state->general_reg[SX86_REG_SI].w.lo;
2433 else if (rm == 1)
2434 ofs = ctx->state->general_reg[SX86_REG_BX].w.lo +
2435 ctx->state->general_reg[SX86_REG_DI].w.lo;
2436 else if (rm == 2)
2437 ofs = ctx->state->general_reg[SX86_REG_BP].w.lo +
2438 ctx->state->general_reg[SX86_REG_SI].w.lo;
2439 else if (rm == 3)
2440 ofs = ctx->state->general_reg[SX86_REG_BP].w.lo +
2441 ctx->state->general_reg[SX86_REG_DI].w.lo;
2442 else if (rm == 4)
2443 ofs = ctx->state->general_reg[SX86_REG_SI].w.lo;
2444 else if (rm == 5)
2445 ofs = ctx->state->general_reg[SX86_REG_DI].w.lo;
2446 else if (rm == 6)
2447 ofs = ctx->state->general_reg[SX86_REG_BP].w.lo;
2448 else if (rm == 7)
2449 ofs = ctx->state->general_reg[SX86_REG_BX].w.lo;
2450
2451 if (mod == 1) {
2452 xx = softx86_fetch_exec_byte(ctx);
2453 if (xx & 0x80) xx |= 0xFF00;
2454 }
2455 else {
2456 xx = softx86_fetch_exec_byte(ctx);
2457 xx |= softx86_fetch_exec_byte(ctx)<<8;
2458 }
2459
2460 ofs = FORCE_WORD_SIZE(ofs + xx);
2461 }
2462
2463 // TODO: For 386+ 32-bit instructions... if (d32) {...}
2464 if (w16) {
2465 sx86_uword tmp,mem;
2466
2467 lo = sx86_far_to_linear(ctx,seg,ofs);
2468 softx86_fetch(ctx,NULL,lo,&mem,2);
2469 SWAP_WORD_FROM_LE(mem);
2470 tmp = ctx->state->general_reg[reg].w.lo;
2471 SWAP_WORD_TO_LE(tmp);
2472 softx86_write(ctx,NULL,lo,&tmp,2);
2473 ctx->state->general_reg[reg].w.lo = mem;
2474 }
2475 else {
2476 sx86_ubyte tmp,mem;
2477
2478 lo = sx86_far_to_linear(ctx,seg,ofs);
2479 softx86_fetch(ctx,NULL,lo,&mem,1);
2480 tmp = *(ctx->__private->ptr_regs_8reg[reg]);
2481 softx86_write(ctx,NULL,lo,&tmp,1);
2482 *(ctx->__private->ptr_regs_8reg[reg]) = mem;
2483 }
2484 }
2485 }
2486
2487 int softx86_parity8(sx86_ubyte ret)
2488 {
2489 int b,p;
2490
2491 p=1;
2492 for (b=0;b < 8;b++) {
2493 p ^= (ret&1);
2494 ret >>= 1;
2495 }
2496
2497 return p;
2498 }
2499
2500 int softx86_parity16(sx86_uword ret)
2501 {
2502 int b,p;
2503
2504 p=1;
2505 for (b=0;b < 16;b++) {
2506 p ^= (ret&1);
2507 ret >>= 1;
2508 }
2509
2510 return p;
2511 }
2512
2513 int softx86_parity32(sx86_udword ret)
2514 {
2515 int b,p;
2516
2517 p=1;
2518 for (b=0;b < 32;b++) {
2519 p ^= (ret&1);
2520 ret >>= 1;
2521 }
2522
2523 return p;
2524 }
2525
2526 int softx86_parity64(sx86_uldword ret)
2527 {
2528 int b,p;
2529
2530 p=1;
2531 for (b=0;b < 64;b++) {
2532 p ^= (ret&1);
2533 ret >>= 1;
2534 }
2535
2536 return p;
2537 }
2538
2539 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))
2540 {
2541 if (sz > 16)
2542 return;
2543
2544 if (mod == 3) { /* immediate <-> register */
2545 // invalid
2546 }
2547 else { /* immediate <-> memory */
2548 sx86_uword seg,ofs;
2549 sx86_udword lo;
2550
2551 if (!ctx->state->is_segment_override)
2552 /* apparently if BP is used (i.e. [BP+BX]) the stack segment is assumed. */
2553 if ((rm == 2 || rm == 3) || (rm == 6 && (mod == 1 || mod == 2)))
2554 seg = ctx->state->segment_reg[SX86_SREG_SS].val;
2555 else
2556 seg = ctx->state->segment_reg[SX86_SREG_DS].val;
2557 else
2558 seg = ctx->state->segment_override;
2559
2560 /* figure out the memory address */
2561 if (mod == 0) {
2562 if (rm == 6) {
2563 ofs = softx86_fetch_exec_byte(ctx);
2564 ofs |= softx86_fetch_exec_byte(ctx)<<8;
2565 }
2566 else if (rm == 0)
2567 ofs = ctx->state->general_reg[SX86_REG_BX].w.lo +
2568 ctx->state->general_reg[SX86_REG_SI].w.lo;
2569 else if (rm == 1)
2570 ofs = ctx->state->general_reg[SX86_REG_BX].w.lo +
2571 ctx->state->general_reg[SX86_REG_DI].w.lo;
2572 else if (rm == 2)
2573 ofs = ctx->state->general_reg[SX86_REG_BP].w.lo +
2574 ctx->state->general_reg[SX86_REG_SI].w.lo;
2575 else if (rm == 3)
2576 ofs = ctx->state->general_reg[SX86_REG_BP].w.lo +
2577 ctx->state->general_reg[SX86_REG_DI].w.lo;
2578 else if (rm == 4)
2579 ofs = ctx->state->general_reg[SX86_REG_SI].w.lo;
2580 else if (rm == 5)
2581 ofs = ctx->state->general_reg[SX86_REG_DI].w.lo;
2582 else if (rm == 7)
2583 ofs = ctx->state->general_reg[SX86_REG_BX].w.lo;
2584 }
2585 else {
2586 sx86_uword xx;
2587
2588 if (rm == 0)
2589 ofs = ctx->state->general_reg[SX86_REG_BX].w.lo +
2590 ctx->state->general_reg[SX86_REG_SI].w.lo;
2591 else if (rm == 1)
2592 ofs = ctx->state->general_reg[SX86_REG_BX].w.lo +
2593 ctx->state->general_reg[SX86_REG_DI].w.lo;
2594 else if (rm == 2)
2595 ofs = ctx->state->general_reg[SX86_REG_BP].w.lo +
2596 ctx->state->general_reg[SX86_REG_SI].w.lo;
2597 else if (rm == 3)
2598 ofs = ctx->state->general_reg[SX86_REG_BP].w.lo +
2599 ctx->state->general_reg[SX86_REG_DI].w.lo;
2600 else if (rm == 4)
2601 ofs = ctx->state->general_reg[SX86_REG_SI].w.lo;
2602 else if (rm == 5)
2603 ofs = ctx->state->general_reg[SX86_REG_DI].w.lo;
2604 else if (rm == 6)
2605 ofs = ctx->state->general_reg[SX86_REG_BP].w.lo;
2606 else if (rm == 7)
2607 ofs = ctx->state->general_reg[SX86_REG_BX].w.lo;
2608
2609 if (mod == 1) {
2610 xx = softx86_fetch_exec_byte(ctx);
2611 if (xx & 0x80) xx |= 0xFF00;
2612 }
2613 else {
2614 xx = softx86_fetch_exec_byte(ctx);
2615 xx |= softx86_fetch_exec_byte(ctx)<<8;
2616 }
2617
2618 ofs = FORCE_WORD_SIZE(ofs + xx);
2619 }
2620
2621 // TODO: For 386+ 32-bit instructions... if (d32) {...}
2622 {
2623 sx86_ubyte tmp[16];
2624
2625 lo = sx86_far_to_linear(ctx,seg,ofs);
2626 softx86_fetch(ctx,NULL,lo,tmp,sz);
2627 op64(ctx,(char*)tmp,sz);
2628 }
2629 }
2630 }
2631
2632 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))
2633 {
2634 if (sz > 16)
2635 return;
2636
2637 if (mod == 3) { /* immediate <-> register */
2638 // invalid
2639 }
2640 else { /* immediate <-> memory */
2641 sx86_uword seg,ofs;
2642 sx86_udword lo;
2643
2644 if (!ctx->state->is_segment_override)
2645 /* apparently if BP is used (i.e. [BP+BX]) the stack segment is assumed. */
2646 if ((rm == 2 || rm == 3) || (rm == 6 && (mod == 1 || mod == 2)))
2647 seg = ctx->state->segment_reg[SX86_SREG_SS].val;
2648 else
2649 seg = ctx->state->segment_reg[SX86_SREG_DS].val;
2650 else
2651 seg = ctx->state->segment_override;
2652
2653 /* figure out the memory address */
2654 if (mod == 0) {
2655 if (rm == 6) {
2656 ofs = softx86_fetch_exec_byte(ctx);
2657 ofs |= softx86_fetch_exec_byte(ctx)<<8;
2658 }
2659 else if (rm == 0)
2660 ofs = ctx->state->general_reg[SX86_REG_BX].w.lo +
2661 ctx->state->general_reg[SX86_REG_SI].w.lo;
2662 else if (rm == 1)
2663 ofs = ctx->state->general_reg[SX86_REG_BX].w.lo +
2664 ctx->state->general_reg[SX86_REG_DI].w.lo;
2665 else if (rm == 2)
2666 ofs = ctx->state->general_reg[SX86_REG_BP].w.lo +
2667 ctx->state->general_reg[SX86_REG_SI].w.lo;
2668 else if (rm == 3)
2669 ofs = ctx->state->general_reg[SX86_REG_BP].w.lo +
2670 ctx->state->general_reg[SX86_REG_DI].w.lo;
2671 else if (rm == 4)
2672 ofs = ctx->state->general_reg[SX86_REG_SI].w.lo;
2673 else if (rm == 5)
2674 ofs = ctx->state->general_reg[SX86_REG_DI].w.lo;
2675 else if (rm == 7)
2676 ofs = ctx->state->general_reg[SX86_REG_BX].w.lo;
2677 }
2678 else {
2679 sx86_uword xx;
2680
2681 if (rm == 0)
2682 ofs = ctx->state->general_reg[SX86_REG_BX].w.lo +
2683 ctx->state->general_reg[SX86_REG_SI].w.lo;
2684 else if (rm == 1)
2685 ofs = ctx->state->general_reg[SX86_REG_BX].w.lo +
2686 ctx->state->general_reg[SX86_REG_DI].w.lo;
2687 else if (rm == 2)
2688 ofs = ctx->state->general_reg[SX86_REG_BP].w.lo +
2689 ctx->state->general_reg[SX86_REG_SI].w.lo;
2690 else if (rm == 3)
2691 ofs = ctx->state->general_reg[SX86_REG_BP].w.lo +
2692 ctx->state->general_reg[SX86_REG_DI].w.lo;
2693 else if (rm == 4)
2694 ofs = ctx->state->general_reg[SX86_REG_SI].w.lo;
2695 else if (rm == 5)
2696 ofs = ctx->state->general_reg[SX86_REG_DI].w.lo;
2697 else if (rm == 6)
2698 ofs = ctx->state->general_reg[SX86_REG_BP].w.lo;
2699 else if (rm == 7)
2700 ofs = ctx->state->general_reg[SX86_REG_BX].w.lo;
2701
2702 if (mod == 1) {
2703 xx = softx86_fetch_exec_byte(ctx);
2704 if (xx & 0x80) xx |= 0xFF00;
2705 }
2706 else {
2707 xx = softx86_fetch_exec_byte(ctx);
2708 xx |= softx86_fetch_exec_byte(ctx)<<8;
2709 }
2710
2711 ofs = FORCE_WORD_SIZE(ofs + xx);
2712 }
2713
2714 // TODO: For 386+ 32-bit instructions... if (d32) {...}
2715 {
2716 sx86_ubyte tmp[16];
2717
2718 lo = sx86_far_to_linear(ctx,seg,ofs);
2719 softx86_fetch(ctx,NULL,lo,tmp,sz);
2720 op64(ctx,(char*)tmp,sz);
2721 softx86_write(ctx,NULL,lo,tmp,sz);
2722 }
2723 }
2724 }
2725
2726 /* general purpose mod/segreg/rm executioneer helper for
2727 instructions that modify the destination operand.
2728
2729 this is provided to avoid copy and pasting this source code into the emulation
2730 of *EVERY* instruction.
2731
2732 ctx = CPU context
2733 mod/reg/rm = mod/reg/rm unpacked byte
2734 op16 = function to call for emulation of instruction, given 16-bit operands "src" and "dst"
2735
2736 MOV AX,ES
2737 MOV CS,BX
2738 MOV ES,WORD PTR [3939h]
2739 MOV WORD PTR [9393h],DS
2740 */
2741 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))
2742 {
2743 sx86_uword regv,rmv;
2744
2745 /* because not all segreg values are valid, check validity now! */
2746 if (reg >= 4) { /* the 8086 does not have FS and GS */
2747 /* TODO: Invalid opcode exception */
2748 return;
2749 }
2750
2751 if (mod == 3) { /* segment register <-> register */
2752 regv = ctx->state->segment_reg[reg].val;
2753 rmv = ctx->state->general_reg[rm].w.lo;
2754
2755 if (opswap) {
2756 /* REMEMBER: WE NEVER DIRECTLY MODIFY THE SEGMENT REGISTER VALUES! */
2757 /* *(ctx->ptr_segregs[reg]) =
2758 op16(ctx,rmv,regv); */
2759 softx86_setsegval(ctx,reg,rmv);
2760 }
2761 else {
2762 ctx->state->general_reg[rm].w.lo =
2763 op16(ctx,rmv,regv);
2764 }
2765 }
2766 else { /* segment register <-> memory */
2767 sx86_uword seg,ofs;
2768 sx86_udword lo;
2769
2770 if (!ctx->state->is_segment_override)
2771 /* apparently if BP is used (i.e. [BP+BX]) the stack segment is assumed. */
2772 if ((rm == 2 || rm == 3) || (rm == 6 && (mod == 1 || mod == 2)))
2773 seg = ctx->state->segment_reg[SX86_SREG_SS].val;
2774 else
2775 seg = ctx->state->segment_reg[SX86_SREG_DS].val;
2776 else
2777 seg = ctx->state->segment_override;
2778
2779 /* figure out the memory address */
2780 if (mod == 0) {
2781 if (rm == 6) {
2782 ofs = softx86_fetch_exec_byte(ctx);
2783 ofs |= softx86_fetch_exec_byte(ctx)<<8;
2784 }
2785 else if (rm == 0)
2786 ofs = ctx->state->general_reg[SX86_REG_BX].w.lo +
2787 ctx->state->general_reg[SX86_REG_SI].w.lo;
2788 else if (rm == 1)
2789 ofs = ctx->state->general_reg[SX86_REG_BX].w.lo +
2790 ctx->state->general_reg[SX86_REG_DI].w.lo;
2791 else if (rm == 2)
2792 ofs = ctx->state->general_reg[SX86_REG_BP].w.lo +
2793 ctx->state->general_reg[SX86_REG_SI].w.lo;
2794 else if (rm == 3)
2795 ofs = ctx->state->general_reg[SX86_REG_BP].w.lo +
2796 ctx->state->general_reg[SX86_REG_DI].w.lo;
2797 else if (rm == 4)
2798 ofs = ctx->state->general_reg[SX86_REG_SI].w.lo;
2799 else if (rm == 5)
2800 ofs = ctx->state->general_reg[SX86_REG_DI].w.lo;
2801 else if (rm == 7)
2802 ofs = ctx->state->general_reg[SX86_REG_BX].w.lo;
2803 }
2804 else {
2805 sx86_uword xx;
2806
2807 if (rm == 0)
2808 ofs = ctx->state->general_reg[SX86_REG_BX].w.lo +
2809 ctx->state->general_reg[SX86_REG_SI].w.lo;
2810 else if (rm == 1)
2811 ofs = ctx->state->general_reg[SX86_REG_BX].w.lo +
2812 ctx->state->general_reg[SX86_REG_DI].w.lo;
2813 else if (rm == 2)
2814 ofs = ctx->state->general_reg[SX86_REG_BP].w.lo +
2815 ctx->state->general_reg[SX86_REG_SI].w.lo;
2816 else if (rm == 3)
2817 ofs = ctx->state->general_reg[SX86_REG_BP].w.lo +
2818 ctx->state->general_reg[SX86_REG_DI].w.lo;
2819 else if (rm == 4)
2820 ofs = ctx->state->general_reg[SX86_REG_SI].w.lo