Merge with git://www.denx.de/git/u-boot.git
[platform/kernel/u-boot.git] / drivers / bios_emulator / x86emu / decode.c
1 /****************************************************************************
2 *
3 *                       Realmode X86 Emulator Library
4 *
5 *               Copyright (C) 1991-2004 SciTech Software, Inc.
6 *                    Copyright (C) David Mosberger-Tang
7 *                      Copyright (C) 1999 Egbert Eich
8 *
9 *  ========================================================================
10 *
11 *  Permission to use, copy, modify, distribute, and sell this software and
12 *  its documentation for any purpose is hereby granted without fee,
13 *  provided that the above copyright notice appear in all copies and that
14 *  both that copyright notice and this permission notice appear in
15 *  supporting documentation, and that the name of the authors not be used
16 *  in advertising or publicity pertaining to distribution of the software
17 *  without specific, written prior permission.  The authors makes no
18 *  representations about the suitability of this software for any purpose.
19 *  It is provided "as is" without express or implied warranty.
20 *
21 *  THE AUTHORS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
22 *  INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
23 *  EVENT SHALL THE AUTHORS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
24 *  CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
25 *  USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
26 *  OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
27 *  PERFORMANCE OF THIS SOFTWARE.
28 *
29 *  ========================================================================
30 *
31 * Language:     ANSI C
32 * Environment:  Any
33 * Developer:    Kendall Bennett
34 *
35 * Description:  This file includes subroutines which are related to
36 *               instruction decoding and accessess of immediate data via IP.  etc.
37 *
38 ****************************************************************************/
39
40 #include "x86emu/x86emui.h"
41
42 #if defined(CONFIG_BIOSEMU)
43
44 /*----------------------------- Implementation ----------------------------*/
45
46 /****************************************************************************
47 REMARKS:
48 Handles any pending asychronous interrupts.
49 ****************************************************************************/
50 static void x86emu_intr_handle(void)
51 {
52     u8  intno;
53
54     if (M.x86.intr & INTR_SYNCH) {
55         intno = M.x86.intno;
56         if (_X86EMU_intrTab[intno]) {
57             (*_X86EMU_intrTab[intno])(intno);
58         } else {
59             push_word((u16)M.x86.R_FLG);
60             CLEAR_FLAG(F_IF);
61             CLEAR_FLAG(F_TF);
62             push_word(M.x86.R_CS);
63             M.x86.R_CS = mem_access_word(intno * 4 + 2);
64             push_word(M.x86.R_IP);
65             M.x86.R_IP = mem_access_word(intno * 4);
66             M.x86.intr = 0;
67         }
68     }
69 }
70
71 /****************************************************************************
72 PARAMETERS:
73 intrnum - Interrupt number to raise
74
75 REMARKS:
76 Raise the specified interrupt to be handled before the execution of the
77 next instruction.
78 ****************************************************************************/
79 void x86emu_intr_raise(
80     u8 intrnum)
81 {
82     M.x86.intno = intrnum;
83     M.x86.intr |= INTR_SYNCH;
84 }
85
86 /****************************************************************************
87 REMARKS:
88 Main execution loop for the emulator. We return from here when the system
89 halts, which is normally caused by a stack fault when we return from the
90 original real mode call.
91 ****************************************************************************/
92 void X86EMU_exec(void)
93 {
94     u8 op1;
95
96     M.x86.intr = 0;
97     DB(x86emu_end_instr();)
98
99     for (;;) {
100 DB(     if (CHECK_IP_FETCH())
101             x86emu_check_ip_access();)
102         /* If debugging, save the IP and CS values. */
103         SAVE_IP_CS(M.x86.R_CS, M.x86.R_IP);
104         INC_DECODED_INST_LEN(1);
105         if (M.x86.intr) {
106             if (M.x86.intr & INTR_HALTED) {
107 DB(             if (M.x86.R_SP != 0) {
108                     printk("halted\n");
109                     X86EMU_trace_regs();
110                     }
111                 else {
112                     if (M.x86.debug)
113                         printk("Service completed successfully\n");
114                     })
115                 return;
116             }
117             if (((M.x86.intr & INTR_SYNCH) && (M.x86.intno == 0 || M.x86.intno == 2)) ||
118                 !ACCESS_FLAG(F_IF)) {
119                 x86emu_intr_handle();
120             }
121         }
122         op1 = (*sys_rdb)(((u32)M.x86.R_CS << 4) + (M.x86.R_IP++));
123         (*x86emu_optab[op1])(op1);
124         if (M.x86.debug & DEBUG_EXIT) {
125             M.x86.debug &= ~DEBUG_EXIT;
126             return;
127         }
128     }
129 }
130
131 /****************************************************************************
132 REMARKS:
133 Halts the system by setting the halted system flag.
134 ****************************************************************************/
135 void X86EMU_halt_sys(void)
136 {
137     M.x86.intr |= INTR_HALTED;
138 }
139
140 /****************************************************************************
141 PARAMETERS:
142 mod     - Mod value from decoded byte
143 regh    - Reg h value from decoded byte
144 regl    - Reg l value from decoded byte
145
146 REMARKS:
147 Raise the specified interrupt to be handled before the execution of the
148 next instruction.
149
150 NOTE: Do not inline this function, as (*sys_rdb) is already inline!
151 ****************************************************************************/
152 void fetch_decode_modrm(
153     int *mod,
154     int *regh,
155     int *regl)
156 {
157     int fetched;
158
159 DB( if (CHECK_IP_FETCH())
160         x86emu_check_ip_access();)
161     fetched = (*sys_rdb)(((u32)M.x86.R_CS << 4) + (M.x86.R_IP++));
162     INC_DECODED_INST_LEN(1);
163     *mod  = (fetched >> 6) & 0x03;
164     *regh = (fetched >> 3) & 0x07;
165     *regl = (fetched >> 0) & 0x07;
166 }
167
168 /****************************************************************************
169 RETURNS:
170 Immediate byte value read from instruction queue
171
172 REMARKS:
173 This function returns the immediate byte from the instruction queue, and
174 moves the instruction pointer to the next value.
175
176 NOTE: Do not inline this function, as (*sys_rdb) is already inline!
177 ****************************************************************************/
178 u8 fetch_byte_imm(void)
179 {
180     u8 fetched;
181
182 DB( if (CHECK_IP_FETCH())
183         x86emu_check_ip_access();)
184     fetched = (*sys_rdb)(((u32)M.x86.R_CS << 4) + (M.x86.R_IP++));
185     INC_DECODED_INST_LEN(1);
186     return fetched;
187 }
188
189 /****************************************************************************
190 RETURNS:
191 Immediate word value read from instruction queue
192
193 REMARKS:
194 This function returns the immediate byte from the instruction queue, and
195 moves the instruction pointer to the next value.
196
197 NOTE: Do not inline this function, as (*sys_rdw) is already inline!
198 ****************************************************************************/
199 u16 fetch_word_imm(void)
200 {
201     u16 fetched;
202
203 DB( if (CHECK_IP_FETCH())
204         x86emu_check_ip_access();)
205     fetched = (*sys_rdw)(((u32)M.x86.R_CS << 4) + (M.x86.R_IP));
206     M.x86.R_IP += 2;
207     INC_DECODED_INST_LEN(2);
208     return fetched;
209 }
210
211 /****************************************************************************
212 RETURNS:
213 Immediate lone value read from instruction queue
214
215 REMARKS:
216 This function returns the immediate byte from the instruction queue, and
217 moves the instruction pointer to the next value.
218
219 NOTE: Do not inline this function, as (*sys_rdw) is already inline!
220 ****************************************************************************/
221 u32 fetch_long_imm(void)
222 {
223     u32 fetched;
224
225 DB( if (CHECK_IP_FETCH())
226         x86emu_check_ip_access();)
227     fetched = (*sys_rdl)(((u32)M.x86.R_CS << 4) + (M.x86.R_IP));
228     M.x86.R_IP += 4;
229     INC_DECODED_INST_LEN(4);
230     return fetched;
231 }
232
233 /****************************************************************************
234 RETURNS:
235 Value of the default data segment
236
237 REMARKS:
238 Inline function that returns the default data segment for the current
239 instruction.
240
241 On the x86 processor, the default segment is not always DS if there is
242 no segment override. Address modes such as -3[BP] or 10[BP+SI] all refer to
243 addresses relative to SS (ie: on the stack). So, at the minimum, all
244 decodings of addressing modes would have to set/clear a bit describing
245 whether the access is relative to DS or SS.  That is the function of the
246 cpu-state-varible M.x86.mode. There are several potential states:
247
248     repe prefix seen  (handled elsewhere)
249     repne prefix seen  (ditto)
250
251     cs segment override
252     ds segment override
253     es segment override
254     fs segment override
255     gs segment override
256     ss segment override
257
258     ds/ss select (in absense of override)
259
260 Each of the above 7 items are handled with a bit in the mode field.
261 ****************************************************************************/
262 _INLINE u32 get_data_segment(void)
263 {
264 #define GET_SEGMENT(segment)
265     switch (M.x86.mode & SYSMODE_SEGMASK) {
266       case 0:                   /* default case: use ds register */
267       case SYSMODE_SEGOVR_DS:
268       case SYSMODE_SEGOVR_DS | SYSMODE_SEG_DS_SS:
269         return  M.x86.R_DS;
270       case SYSMODE_SEG_DS_SS:   /* non-overridden, use ss register */
271         return  M.x86.R_SS;
272       case SYSMODE_SEGOVR_CS:
273       case SYSMODE_SEGOVR_CS | SYSMODE_SEG_DS_SS:
274         return  M.x86.R_CS;
275       case SYSMODE_SEGOVR_ES:
276       case SYSMODE_SEGOVR_ES | SYSMODE_SEG_DS_SS:
277         return  M.x86.R_ES;
278       case SYSMODE_SEGOVR_FS:
279       case SYSMODE_SEGOVR_FS | SYSMODE_SEG_DS_SS:
280         return  M.x86.R_FS;
281       case SYSMODE_SEGOVR_GS:
282       case SYSMODE_SEGOVR_GS | SYSMODE_SEG_DS_SS:
283         return  M.x86.R_GS;
284       case SYSMODE_SEGOVR_SS:
285       case SYSMODE_SEGOVR_SS | SYSMODE_SEG_DS_SS:
286         return  M.x86.R_SS;
287       default:
288 #ifdef  DEBUG
289         printk("error: should not happen:  multiple overrides.\n");
290 #endif
291         HALT_SYS();
292         return 0;
293     }
294 }
295
296 /****************************************************************************
297 PARAMETERS:
298 offset  - Offset to load data from
299
300 RETURNS:
301 Byte value read from the absolute memory location.
302
303 NOTE: Do not inline this function as (*sys_rdX) is already inline!
304 ****************************************************************************/
305 u8 fetch_data_byte(
306     uint offset)
307 {
308 #ifdef DEBUG
309     if (CHECK_DATA_ACCESS())
310         x86emu_check_data_access((u16)get_data_segment(), offset);
311 #endif
312     return (*sys_rdb)((get_data_segment() << 4) + offset);
313 }
314
315 /****************************************************************************
316 PARAMETERS:
317 offset  - Offset to load data from
318
319 RETURNS:
320 Word value read from the absolute memory location.
321
322 NOTE: Do not inline this function as (*sys_rdX) is already inline!
323 ****************************************************************************/
324 u16 fetch_data_word(
325     uint offset)
326 {
327 #ifdef DEBUG
328     if (CHECK_DATA_ACCESS())
329         x86emu_check_data_access((u16)get_data_segment(), offset);
330 #endif
331     return (*sys_rdw)((get_data_segment() << 4) + offset);
332 }
333
334 /****************************************************************************
335 PARAMETERS:
336 offset  - Offset to load data from
337
338 RETURNS:
339 Long value read from the absolute memory location.
340
341 NOTE: Do not inline this function as (*sys_rdX) is already inline!
342 ****************************************************************************/
343 u32 fetch_data_long(
344     uint offset)
345 {
346 #ifdef DEBUG
347     if (CHECK_DATA_ACCESS())
348         x86emu_check_data_access((u16)get_data_segment(), offset);
349 #endif
350     return (*sys_rdl)((get_data_segment() << 4) + offset);
351 }
352
353 /****************************************************************************
354 PARAMETERS:
355 segment - Segment to load data from
356 offset  - Offset to load data from
357
358 RETURNS:
359 Byte value read from the absolute memory location.
360
361 NOTE: Do not inline this function as (*sys_rdX) is already inline!
362 ****************************************************************************/
363 u8 fetch_data_byte_abs(
364     uint segment,
365     uint offset)
366 {
367 #ifdef DEBUG
368     if (CHECK_DATA_ACCESS())
369         x86emu_check_data_access(segment, offset);
370 #endif
371     return (*sys_rdb)(((u32)segment << 4) + offset);
372 }
373
374 /****************************************************************************
375 PARAMETERS:
376 segment - Segment to load data from
377 offset  - Offset to load data from
378
379 RETURNS:
380 Word value read from the absolute memory location.
381
382 NOTE: Do not inline this function as (*sys_rdX) is already inline!
383 ****************************************************************************/
384 u16 fetch_data_word_abs(
385     uint segment,
386     uint offset)
387 {
388 #ifdef DEBUG
389     if (CHECK_DATA_ACCESS())
390         x86emu_check_data_access(segment, offset);
391 #endif
392     return (*sys_rdw)(((u32)segment << 4) + offset);
393 }
394
395 /****************************************************************************
396 PARAMETERS:
397 segment - Segment to load data from
398 offset  - Offset to load data from
399
400 RETURNS:
401 Long value read from the absolute memory location.
402
403 NOTE: Do not inline this function as (*sys_rdX) is already inline!
404 ****************************************************************************/
405 u32 fetch_data_long_abs(
406     uint segment,
407     uint offset)
408 {
409 #ifdef DEBUG
410     if (CHECK_DATA_ACCESS())
411         x86emu_check_data_access(segment, offset);
412 #endif
413     return (*sys_rdl)(((u32)segment << 4) + offset);
414 }
415
416 /****************************************************************************
417 PARAMETERS:
418 offset  - Offset to store data at
419 val     - Value to store
420
421 REMARKS:
422 Writes a word value to an segmented memory location. The segment used is
423 the current 'default' segment, which may have been overridden.
424
425 NOTE: Do not inline this function as (*sys_wrX) is already inline!
426 ****************************************************************************/
427 void store_data_byte(
428     uint offset,
429     u8 val)
430 {
431 #ifdef DEBUG
432     if (CHECK_DATA_ACCESS())
433         x86emu_check_data_access((u16)get_data_segment(), offset);
434 #endif
435     (*sys_wrb)((get_data_segment() << 4) + offset, val);
436 }
437
438 /****************************************************************************
439 PARAMETERS:
440 offset  - Offset to store data at
441 val     - Value to store
442
443 REMARKS:
444 Writes a word value to an segmented memory location. The segment used is
445 the current 'default' segment, which may have been overridden.
446
447 NOTE: Do not inline this function as (*sys_wrX) is already inline!
448 ****************************************************************************/
449 void store_data_word(
450     uint offset,
451     u16 val)
452 {
453 #ifdef DEBUG
454     if (CHECK_DATA_ACCESS())
455         x86emu_check_data_access((u16)get_data_segment(), offset);
456 #endif
457     (*sys_wrw)((get_data_segment() << 4) + offset, val);
458 }
459
460 /****************************************************************************
461 PARAMETERS:
462 offset  - Offset to store data at
463 val     - Value to store
464
465 REMARKS:
466 Writes a long value to an segmented memory location. The segment used is
467 the current 'default' segment, which may have been overridden.
468
469 NOTE: Do not inline this function as (*sys_wrX) is already inline!
470 ****************************************************************************/
471 void store_data_long(
472     uint offset,
473     u32 val)
474 {
475 #ifdef DEBUG
476     if (CHECK_DATA_ACCESS())
477         x86emu_check_data_access((u16)get_data_segment(), offset);
478 #endif
479     (*sys_wrl)((get_data_segment() << 4) + offset, val);
480 }
481
482 /****************************************************************************
483 PARAMETERS:
484 segment - Segment to store data at
485 offset  - Offset to store data at
486 val     - Value to store
487
488 REMARKS:
489 Writes a byte value to an absolute memory location.
490
491 NOTE: Do not inline this function as (*sys_wrX) is already inline!
492 ****************************************************************************/
493 void store_data_byte_abs(
494     uint segment,
495     uint offset,
496     u8 val)
497 {
498 #ifdef DEBUG
499     if (CHECK_DATA_ACCESS())
500         x86emu_check_data_access(segment, offset);
501 #endif
502     (*sys_wrb)(((u32)segment << 4) + offset, val);
503 }
504
505 /****************************************************************************
506 PARAMETERS:
507 segment - Segment to store data at
508 offset  - Offset to store data at
509 val     - Value to store
510
511 REMARKS:
512 Writes a word value to an absolute memory location.
513
514 NOTE: Do not inline this function as (*sys_wrX) is already inline!
515 ****************************************************************************/
516 void store_data_word_abs(
517     uint segment,
518     uint offset,
519     u16 val)
520 {
521 #ifdef DEBUG
522     if (CHECK_DATA_ACCESS())
523         x86emu_check_data_access(segment, offset);
524 #endif
525     (*sys_wrw)(((u32)segment << 4) + offset, val);
526 }
527
528 /****************************************************************************
529 PARAMETERS:
530 segment - Segment to store data at
531 offset  - Offset to store data at
532 val     - Value to store
533
534 REMARKS:
535 Writes a long value to an absolute memory location.
536
537 NOTE: Do not inline this function as (*sys_wrX) is already inline!
538 ****************************************************************************/
539 void store_data_long_abs(
540     uint segment,
541     uint offset,
542     u32 val)
543 {
544 #ifdef DEBUG
545     if (CHECK_DATA_ACCESS())
546         x86emu_check_data_access(segment, offset);
547 #endif
548     (*sys_wrl)(((u32)segment << 4) + offset, val);
549 }
550
551 /****************************************************************************
552 PARAMETERS:
553 reg - Register to decode
554
555 RETURNS:
556 Pointer to the appropriate register
557
558 REMARKS:
559 Return a pointer to the register given by the R/RM field of the
560 modrm byte, for byte operands. Also enables the decoding of instructions.
561 ****************************************************************************/
562 u8* decode_rm_byte_register(
563     int reg)
564 {
565     switch (reg) {
566       case 0:
567         DECODE_PRINTF("AL");
568         return &M.x86.R_AL;
569       case 1:
570         DECODE_PRINTF("CL");
571         return &M.x86.R_CL;
572       case 2:
573         DECODE_PRINTF("DL");
574         return &M.x86.R_DL;
575       case 3:
576         DECODE_PRINTF("BL");
577         return &M.x86.R_BL;
578       case 4:
579         DECODE_PRINTF("AH");
580         return &M.x86.R_AH;
581       case 5:
582         DECODE_PRINTF("CH");
583         return &M.x86.R_CH;
584       case 6:
585         DECODE_PRINTF("DH");
586         return &M.x86.R_DH;
587       case 7:
588         DECODE_PRINTF("BH");
589         return &M.x86.R_BH;
590     }
591     HALT_SYS();
592     return NULL;                /* NOT REACHED OR REACHED ON ERROR */
593 }
594
595 /****************************************************************************
596 PARAMETERS:
597 reg - Register to decode
598
599 RETURNS:
600 Pointer to the appropriate register
601
602 REMARKS:
603 Return a pointer to the register given by the R/RM field of the
604 modrm byte, for word operands.  Also enables the decoding of instructions.
605 ****************************************************************************/
606 u16* decode_rm_word_register(
607     int reg)
608 {
609     switch (reg) {
610       case 0:
611         DECODE_PRINTF("AX");
612         return &M.x86.R_AX;
613       case 1:
614         DECODE_PRINTF("CX");
615         return &M.x86.R_CX;
616       case 2:
617         DECODE_PRINTF("DX");
618         return &M.x86.R_DX;
619       case 3:
620         DECODE_PRINTF("BX");
621         return &M.x86.R_BX;
622       case 4:
623         DECODE_PRINTF("SP");
624         return &M.x86.R_SP;
625       case 5:
626         DECODE_PRINTF("BP");
627         return &M.x86.R_BP;
628       case 6:
629         DECODE_PRINTF("SI");
630         return &M.x86.R_SI;
631       case 7:
632         DECODE_PRINTF("DI");
633         return &M.x86.R_DI;
634     }
635     HALT_SYS();
636     return NULL;                /* NOTREACHED OR REACHED ON ERROR */
637 }
638
639 /****************************************************************************
640 PARAMETERS:
641 reg - Register to decode
642
643 RETURNS:
644 Pointer to the appropriate register
645
646 REMARKS:
647 Return a pointer to the register given by the R/RM field of the
648 modrm byte, for dword operands.  Also enables the decoding of instructions.
649 ****************************************************************************/
650 u32* decode_rm_long_register(
651     int reg)
652 {
653     switch (reg) {
654       case 0:
655         DECODE_PRINTF("EAX");
656         return &M.x86.R_EAX;
657       case 1:
658         DECODE_PRINTF("ECX");
659         return &M.x86.R_ECX;
660       case 2:
661         DECODE_PRINTF("EDX");
662         return &M.x86.R_EDX;
663       case 3:
664         DECODE_PRINTF("EBX");
665         return &M.x86.R_EBX;
666       case 4:
667         DECODE_PRINTF("ESP");
668         return &M.x86.R_ESP;
669       case 5:
670         DECODE_PRINTF("EBP");
671         return &M.x86.R_EBP;
672       case 6:
673         DECODE_PRINTF("ESI");
674         return &M.x86.R_ESI;
675       case 7:
676         DECODE_PRINTF("EDI");
677         return &M.x86.R_EDI;
678     }
679     HALT_SYS();
680     return NULL;                /* NOTREACHED OR REACHED ON ERROR */
681 }
682
683 /****************************************************************************
684 PARAMETERS:
685 reg - Register to decode
686
687 RETURNS:
688 Pointer to the appropriate register
689
690 REMARKS:
691 Return a pointer to the register given by the R/RM field of the
692 modrm byte, for word operands, modified from above for the weirdo
693 special case of segreg operands.  Also enables the decoding of instructions.
694 ****************************************************************************/
695 u16* decode_rm_seg_register(
696     int reg)
697 {
698     switch (reg) {
699       case 0:
700         DECODE_PRINTF("ES");
701         return &M.x86.R_ES;
702       case 1:
703         DECODE_PRINTF("CS");
704         return &M.x86.R_CS;
705       case 2:
706         DECODE_PRINTF("SS");
707         return &M.x86.R_SS;
708       case 3:
709         DECODE_PRINTF("DS");
710         return &M.x86.R_DS;
711       case 4:
712         DECODE_PRINTF("FS");
713         return &M.x86.R_FS;
714       case 5:
715         DECODE_PRINTF("GS");
716         return &M.x86.R_GS;
717       case 6:
718       case 7:
719         DECODE_PRINTF("ILLEGAL SEGREG");
720         break;
721     }
722     HALT_SYS();
723     return NULL;                /* NOT REACHED OR REACHED ON ERROR */
724 }
725
726 /****************************************************************************
727 PARAMETERS:
728 scale - scale value of SIB byte
729 index - index value of SIB byte
730
731 RETURNS:
732 Value of scale * index
733
734 REMARKS:
735 Decodes scale/index of SIB byte and returns relevant offset part of
736 effective address.
737 ****************************************************************************/
738 unsigned decode_sib_si(
739     int scale,
740     int index)
741 {
742     scale = 1 << scale;
743     if (scale > 1) {
744         DECODE_PRINTF2("[%d*", scale);
745     } else {
746         DECODE_PRINTF("[");
747     }
748     switch (index) {
749       case 0:
750         DECODE_PRINTF("EAX]");
751         return M.x86.R_EAX * index;
752       case 1:
753         DECODE_PRINTF("ECX]");
754         return M.x86.R_ECX * index;
755       case 2:
756         DECODE_PRINTF("EDX]");
757         return M.x86.R_EDX * index;
758       case 3:
759         DECODE_PRINTF("EBX]");
760         return M.x86.R_EBX * index;
761       case 4:
762         DECODE_PRINTF("0]");
763         return 0;
764       case 5:
765         DECODE_PRINTF("EBP]");
766         return M.x86.R_EBP * index;
767       case 6:
768         DECODE_PRINTF("ESI]");
769         return M.x86.R_ESI * index;
770       case 7:
771         DECODE_PRINTF("EDI]");
772         return M.x86.R_EDI * index;
773     }
774     HALT_SYS();
775     return 0;                   /* NOT REACHED OR REACHED ON ERROR */
776 }
777
778 /****************************************************************************
779 PARAMETERS:
780 mod - MOD value of preceding ModR/M byte
781
782 RETURNS:
783 Offset in memory for the address decoding
784
785 REMARKS:
786 Decodes SIB addressing byte and returns calculated effective address.
787 ****************************************************************************/
788 unsigned decode_sib_address(
789     int mod)
790 {
791     int sib   = fetch_byte_imm();
792     int ss    = (sib >> 6) & 0x03;
793     int index = (sib >> 3) & 0x07;
794     int base  = sib & 0x07;
795     int offset = 0;
796     int displacement;
797
798     switch (base) {
799       case 0:
800         DECODE_PRINTF("[EAX]");
801         offset = M.x86.R_EAX;
802         break;
803       case 1:
804         DECODE_PRINTF("[ECX]");
805         offset = M.x86.R_ECX;
806         break;
807       case 2:
808         DECODE_PRINTF("[EDX]");
809         offset = M.x86.R_EDX;
810         break;
811       case 3:
812         DECODE_PRINTF("[EBX]");
813         offset = M.x86.R_EBX;
814         break;
815       case 4:
816         DECODE_PRINTF("[ESP]");
817         offset = M.x86.R_ESP;
818         break;
819       case 5:
820         switch (mod) {
821           case 0:
822             displacement = (s32)fetch_long_imm();
823             DECODE_PRINTF2("[%d]", displacement);
824             offset = displacement;
825             break;
826           case 1:
827             displacement = (s8)fetch_byte_imm();
828             DECODE_PRINTF2("[%d][EBP]", displacement);
829             offset = M.x86.R_EBP + displacement;
830             break;
831           case 2:
832             displacement = (s32)fetch_long_imm();
833             DECODE_PRINTF2("[%d][EBP]", displacement);
834             offset = M.x86.R_EBP + displacement;
835             break;
836           default:
837             HALT_SYS();
838         }
839         DECODE_PRINTF("[EAX]");
840         offset = M.x86.R_EAX;
841         break;
842       case 6:
843         DECODE_PRINTF("[ESI]");
844         offset = M.x86.R_ESI;
845         break;
846       case 7:
847         DECODE_PRINTF("[EDI]");
848         offset = M.x86.R_EDI;
849         break;
850       default:
851         HALT_SYS();
852     }
853     offset += decode_sib_si(ss, index);
854     return offset;
855
856 }
857
858 /****************************************************************************
859 PARAMETERS:
860 rm  - RM value to decode
861
862 RETURNS:
863 Offset in memory for the address decoding
864
865 REMARKS:
866 Return the offset given by mod=00 addressing.  Also enables the
867 decoding of instructions.
868
869 NOTE:   The code which specifies the corresponding segment (ds vs ss)
870         below in the case of [BP+..].  The assumption here is that at the
871         point that this subroutine is called, the bit corresponding to
872         SYSMODE_SEG_DS_SS will be zero.  After every instruction
873         except the segment override instructions, this bit (as well
874         as any bits indicating segment overrides) will be clear.  So
875         if a SS access is needed, set this bit.  Otherwise, DS access
876         occurs (unless any of the segment override bits are set).
877 ****************************************************************************/
878 unsigned decode_rm00_address(
879     int rm)
880 {
881     unsigned offset;
882
883     if (M.x86.mode & SYSMODE_PREFIX_ADDR) {
884         /* 32-bit addressing */
885         switch (rm) {
886           case 0:
887             DECODE_PRINTF("[EAX]");
888             return M.x86.R_EAX;
889           case 1:
890             DECODE_PRINTF("[ECX]");
891             return M.x86.R_ECX;
892           case 2:
893             DECODE_PRINTF("[EDX]");
894             return M.x86.R_EDX;
895           case 3:
896             DECODE_PRINTF("[EBX]");
897             return M.x86.R_EBX;
898           case 4:
899             return decode_sib_address(0);
900           case 5:
901             offset = fetch_long_imm();
902             DECODE_PRINTF2("[%08x]", offset);
903             return offset;
904           case 6:
905             DECODE_PRINTF("[ESI]");
906             return M.x86.R_ESI;
907           case 7:
908             DECODE_PRINTF("[EDI]");
909             return M.x86.R_EDI;
910         }
911     } else {
912         /* 16-bit addressing */
913         switch (rm) {
914           case 0:
915             DECODE_PRINTF("[BX+SI]");
916             return (M.x86.R_BX + M.x86.R_SI) & 0xffff;
917           case 1:
918             DECODE_PRINTF("[BX+DI]");
919             return (M.x86.R_BX + M.x86.R_DI) & 0xffff;
920           case 2:
921             DECODE_PRINTF("[BP+SI]");
922             M.x86.mode |= SYSMODE_SEG_DS_SS;
923             return (M.x86.R_BP + M.x86.R_SI) & 0xffff;
924           case 3:
925             DECODE_PRINTF("[BP+DI]");
926             M.x86.mode |= SYSMODE_SEG_DS_SS;
927             return (M.x86.R_BP + M.x86.R_DI) & 0xffff;
928           case 4:
929             DECODE_PRINTF("[SI]");
930             return M.x86.R_SI;
931           case 5:
932             DECODE_PRINTF("[DI]");
933             return M.x86.R_DI;
934           case 6:
935             offset = fetch_word_imm();
936             DECODE_PRINTF2("[%04x]", offset);
937             return offset;
938           case 7:
939             DECODE_PRINTF("[BX]");
940             return M.x86.R_BX;
941         }
942     }
943     HALT_SYS();
944     return 0;
945 }
946
947 /****************************************************************************
948 PARAMETERS:
949 rm  - RM value to decode
950
951 RETURNS:
952 Offset in memory for the address decoding
953
954 REMARKS:
955 Return the offset given by mod=01 addressing.  Also enables the
956 decoding of instructions.
957 ****************************************************************************/
958 unsigned decode_rm01_address(
959     int rm)
960 {
961     int displacement;
962
963     if (M.x86.mode & SYSMODE_PREFIX_ADDR) {
964         /* 32-bit addressing */
965         if (rm != 4)
966             displacement = (s8)fetch_byte_imm();
967         else
968             displacement = 0;
969
970         switch (rm) {
971           case 0:
972             DECODE_PRINTF2("%d[EAX]", displacement);
973             return M.x86.R_EAX + displacement;
974           case 1:
975             DECODE_PRINTF2("%d[ECX]", displacement);
976             return M.x86.R_ECX + displacement;
977           case 2:
978             DECODE_PRINTF2("%d[EDX]", displacement);
979             return M.x86.R_EDX + displacement;
980           case 3:
981             DECODE_PRINTF2("%d[EBX]", displacement);
982             return M.x86.R_EBX + displacement;
983           case 4: {
984             int offset = decode_sib_address(1);
985             displacement = (s8)fetch_byte_imm();
986             DECODE_PRINTF2("[%d]", displacement);
987             return offset + displacement;
988           }
989           case 5:
990             DECODE_PRINTF2("%d[EBP]", displacement);
991             return M.x86.R_EBP + displacement;
992           case 6:
993             DECODE_PRINTF2("%d[ESI]", displacement);
994             return M.x86.R_ESI + displacement;
995           case 7:
996             DECODE_PRINTF2("%d[EDI]", displacement);
997             return M.x86.R_EDI + displacement;
998         }
999     } else {
1000         /* 16-bit addressing */
1001         displacement = (s8)fetch_byte_imm();
1002         switch (rm) {
1003           case 0:
1004             DECODE_PRINTF2("%d[BX+SI]", displacement);
1005             return (M.x86.R_BX + M.x86.R_SI + displacement) & 0xffff;
1006           case 1:
1007             DECODE_PRINTF2("%d[BX+DI]", displacement);
1008             return (M.x86.R_BX + M.x86.R_DI + displacement) & 0xffff;
1009           case 2:
1010             DECODE_PRINTF2("%d[BP+SI]", displacement);
1011             M.x86.mode |= SYSMODE_SEG_DS_SS;
1012             return (M.x86.R_BP + M.x86.R_SI + displacement) & 0xffff;
1013           case 3:
1014             DECODE_PRINTF2("%d[BP+DI]", displacement);
1015             M.x86.mode |= SYSMODE_SEG_DS_SS;
1016             return (M.x86.R_BP + M.x86.R_DI + displacement) & 0xffff;
1017           case 4:
1018             DECODE_PRINTF2("%d[SI]", displacement);
1019             return (M.x86.R_SI + displacement) & 0xffff;
1020           case 5:
1021             DECODE_PRINTF2("%d[DI]", displacement);
1022             return (M.x86.R_DI + displacement) & 0xffff;
1023           case 6:
1024             DECODE_PRINTF2("%d[BP]", displacement);
1025             M.x86.mode |= SYSMODE_SEG_DS_SS;
1026             return (M.x86.R_BP + displacement) & 0xffff;
1027           case 7:
1028             DECODE_PRINTF2("%d[BX]", displacement);
1029             return (M.x86.R_BX + displacement) & 0xffff;
1030         }
1031     }
1032     HALT_SYS();
1033     return 0;                   /* SHOULD NOT HAPPEN */
1034 }
1035
1036 /****************************************************************************
1037 PARAMETERS:
1038 rm  - RM value to decode
1039
1040 RETURNS:
1041 Offset in memory for the address decoding
1042
1043 REMARKS:
1044 Return the offset given by mod=10 addressing.  Also enables the
1045 decoding of instructions.
1046 ****************************************************************************/
1047 unsigned decode_rm10_address(
1048     int rm)
1049 {
1050     if (M.x86.mode & SYSMODE_PREFIX_ADDR) {
1051         int displacement;
1052
1053         /* 32-bit addressing */
1054         if (rm != 4)
1055             displacement = (s32)fetch_long_imm();
1056         else
1057             displacement = 0;
1058
1059         switch (rm) {
1060           case 0:
1061             DECODE_PRINTF2("%d[EAX]", displacement);
1062             return M.x86.R_EAX + displacement;
1063           case 1:
1064             DECODE_PRINTF2("%d[ECX]", displacement);
1065             return M.x86.R_ECX + displacement;
1066           case 2:
1067             DECODE_PRINTF2("%d[EDX]", displacement);
1068             return M.x86.R_EDX + displacement;
1069           case 3:
1070             DECODE_PRINTF2("%d[EBX]", displacement);
1071             return M.x86.R_EBX + displacement;
1072           case 4: {
1073             int offset = decode_sib_address(2);
1074             displacement = (s32)fetch_long_imm();
1075             DECODE_PRINTF2("[%d]", displacement);
1076             return offset + displacement;
1077           }
1078           case 5:
1079             DECODE_PRINTF2("%d[EBP]", displacement);
1080             return M.x86.R_EBP + displacement;
1081           case 6:
1082             DECODE_PRINTF2("%d[ESI]", displacement);
1083             return M.x86.R_ESI + displacement;
1084           case 7:
1085             DECODE_PRINTF2("%d[EDI]", displacement);
1086             return M.x86.R_EDI + displacement;
1087         }
1088     } else {
1089         int displacement = (s16)fetch_word_imm();
1090
1091         /* 16-bit addressing */
1092         switch (rm) {
1093           case 0:
1094             DECODE_PRINTF2("%d[BX+SI]", displacement);
1095             return (M.x86.R_BX + M.x86.R_SI + displacement) & 0xffff;
1096           case 1:
1097             DECODE_PRINTF2("%d[BX+DI]", displacement);
1098             return (M.x86.R_BX + M.x86.R_DI + displacement) & 0xffff;
1099           case 2:
1100             DECODE_PRINTF2("%d[BP+SI]", displacement);
1101             M.x86.mode |= SYSMODE_SEG_DS_SS;
1102             return (M.x86.R_BP + M.x86.R_SI + displacement) & 0xffff;
1103           case 3:
1104             DECODE_PRINTF2("%d[BP+DI]", displacement);
1105             M.x86.mode |= SYSMODE_SEG_DS_SS;
1106             return (M.x86.R_BP + M.x86.R_DI + displacement) & 0xffff;
1107           case 4:
1108             DECODE_PRINTF2("%d[SI]", displacement);
1109             return (M.x86.R_SI + displacement) & 0xffff;
1110           case 5:
1111             DECODE_PRINTF2("%d[DI]", displacement);
1112             return (M.x86.R_DI + displacement) & 0xffff;
1113           case 6:
1114             DECODE_PRINTF2("%d[BP]", displacement);
1115             M.x86.mode |= SYSMODE_SEG_DS_SS;
1116             return (M.x86.R_BP + displacement) & 0xffff;
1117           case 7:
1118             DECODE_PRINTF2("%d[BX]", displacement);
1119             return (M.x86.R_BX + displacement) & 0xffff;
1120         }
1121     }
1122     HALT_SYS();
1123     return 0;                   /* SHOULD NOT HAPPEN */
1124 }
1125
1126 /****************************************************************************
1127 PARAMETERS:
1128 mod - modifier
1129 rm  - RM value to decode
1130
1131 RETURNS:
1132 Offset in memory for the address decoding, multiplexing calls to
1133 the decode_rmXX_address functions
1134
1135 REMARKS:
1136 Return the offset given by "mod" addressing.
1137 ****************************************************************************/
1138
1139 unsigned decode_rmXX_address(int mod, int rm)
1140 {
1141   if(mod == 0)
1142     return decode_rm00_address(rm);
1143   if(mod == 1)
1144     return decode_rm01_address(rm);
1145   return decode_rm10_address(rm);
1146 }
1147
1148 #endif