fixes to make adl855pc compile.
[coreboot.git] / util / vgabios / x86emu / src / x86emu / decode.c
1 /****************************************************************************
2 *
3 *                                               Realmode X86 Emulator Library
4 *
5 *               Copyright (C) 1996-1999 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 /* $XFree86: xc/extras/x86emu/src/x86emu/decode.c,v 1.9 2001/01/06 20:19:03 tsi Exp $ */
41
42 #include "x86emu/x86emui.h"
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(u8 intrnum)
80 {
81         M.x86.intno = intrnum;
82         M.x86.intr |= INTR_SYNCH;
83 }
84
85 /****************************************************************************
86 REMARKS:
87 Main execution loop for the emulator. We return from here when the system
88 halts, which is normally caused by a stack fault when we return from the
89 original real mode call.
90 ****************************************************************************/
91 void X86EMU_exec(void)
92 {
93         u8 op1;
94
95         M.x86.intr = 0;
96         DB(x86emu_end_instr();
97             )
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(printk("halted\n"); X86EMU_trace_regs();
108                                     )
109                                     return;
110                         }
111                         if (((M.x86.intr & INTR_SYNCH)
112                              && (M.x86.intno == 0 || M.x86.intno == 2))
113                             || !ACCESS_FLAG(F_IF)) {
114                                 x86emu_intr_handle();
115                         }
116                 }
117                 op1 = (*sys_rdb) (((u32) M.x86.R_CS << 4) + (M.x86.R_IP++));
118                 (*x86emu_optab[op1]) (op1);
119         }
120 }
121
122 /****************************************************************************
123 REMARKS:
124 Halts the system by setting the halted system flag.
125 ****************************************************************************/
126 void X86EMU_halt_sys(void)
127 {
128         M.x86.intr |= INTR_HALTED;
129 }
130
131 /****************************************************************************
132 PARAMETERS:
133 mod             - Mod value from decoded byte
134 regh    - Reg h value from decoded byte
135 regl    - Reg l value from decoded byte
136
137 REMARKS:
138 Raise the specified interrupt to be handled before the execution of the
139 next instruction.
140
141 NOTE: Do not inline this function, as (*sys_rdb) is already inline!
142 ****************************************************************************/
143 void fetch_decode_modrm(int *mod, int *regh, int *regl)
144 {
145         int fetched;
146
147         DB(if (CHECK_IP_FETCH())
148            x86emu_check_ip_access();)
149                 fetched = (*sys_rdb) (((u32) M.x86.R_CS << 4) + (M.x86.R_IP++));
150         INC_DECODED_INST_LEN(1);
151         *mod = (fetched >> 6) & 0x03;
152         *regh = (fetched >> 3) & 0x07;
153         *regl = (fetched >> 0) & 0x07;
154 }
155
156 /****************************************************************************
157 RETURNS:
158 Immediate byte value read from instruction queue
159
160 REMARKS:
161 This function returns the immediate byte from the instruction queue, and
162 moves the instruction pointer to the next value.
163
164 NOTE: Do not inline this function, as (*sys_rdb) is already inline!
165 ****************************************************************************/
166 u8 fetch_byte_imm(void)
167 {
168         u8 fetched;
169
170         DB(if (CHECK_IP_FETCH())
171            x86emu_check_ip_access();)
172                 fetched = (*sys_rdb) (((u32) M.x86.R_CS << 4) + (M.x86.R_IP++));
173         INC_DECODED_INST_LEN(1);
174         return fetched;
175 }
176
177 /****************************************************************************
178 RETURNS:
179 Immediate word value read from instruction queue
180
181 REMARKS:
182 This function returns the immediate byte from the instruction queue, and
183 moves the instruction pointer to the next value.
184
185 NOTE: Do not inline this function, as (*sys_rdw) is already inline!
186 ****************************************************************************/
187 u16 fetch_word_imm(void)
188 {
189         u16 fetched;
190
191         DB(if (CHECK_IP_FETCH())
192            x86emu_check_ip_access();)
193                 fetched = (*sys_rdw) (((u32) M.x86.R_CS << 4) + (M.x86.R_IP));
194         M.x86.R_IP += 2;
195         INC_DECODED_INST_LEN(2);
196         return fetched;
197 }
198
199 /****************************************************************************
200 RETURNS:
201 Immediate lone value read from instruction queue
202
203 REMARKS:
204 This function returns the immediate byte from the instruction queue, and
205 moves the instruction pointer to the next value.
206
207 NOTE: Do not inline this function, as (*sys_rdw) is already inline!
208 ****************************************************************************/
209 u32 fetch_long_imm(void)
210 {
211         u32 fetched;
212
213         DB(if (CHECK_IP_FETCH())
214            x86emu_check_ip_access();)
215                 fetched = (*sys_rdl) (((u32) M.x86.R_CS << 4) + (M.x86.R_IP));
216         M.x86.R_IP += 4;
217         INC_DECODED_INST_LEN(4);
218         return fetched;
219 }
220
221 /****************************************************************************
222 RETURNS:
223 Value of the default data segment
224
225 REMARKS:
226 Inline function that returns the default data segment for the current
227 instruction.
228
229 On the x86 processor, the default segment is not always DS if there is
230 no segment override. Address modes such as -3[BP] or 10[BP+SI] all refer to
231 addresses relative to SS (ie: on the stack). So, at the minimum, all
232 decodings of addressing modes would have to set/clear a bit describing
233 whether the access is relative to DS or SS.  That is the function of the
234 cpu-state-varible M.x86.mode. There are several potential states:
235
236         repe prefix seen  (handled elsewhere)
237         repne prefix seen  (ditto)
238
239         cs segment override
240         ds segment override
241         es segment override
242         fs segment override
243         gs segment override
244         ss segment override
245
246         ds/ss select (in absense of override)
247
248 Each of the above 7 items are handled with a bit in the mode field.
249 ****************************************************************************/
250 _INLINE u32 get_data_segment(void)
251 {
252 #define GET_SEGMENT(segment)
253         switch (M.x86.mode & SYSMODE_SEGMASK) {
254         case 0:         /* default case: use ds register */
255         case SYSMODE_SEGOVR_DS:
256         case SYSMODE_SEGOVR_DS | SYSMODE_SEG_DS_SS:
257                 return M.x86.R_DS;
258         case SYSMODE_SEG_DS_SS: /* non-overridden, use ss register */
259                 return M.x86.R_SS;
260         case SYSMODE_SEGOVR_CS:
261         case SYSMODE_SEGOVR_CS | SYSMODE_SEG_DS_SS:
262                 return M.x86.R_CS;
263         case SYSMODE_SEGOVR_ES:
264         case SYSMODE_SEGOVR_ES | SYSMODE_SEG_DS_SS:
265                 return M.x86.R_ES;
266         case SYSMODE_SEGOVR_FS:
267         case SYSMODE_SEGOVR_FS | SYSMODE_SEG_DS_SS:
268                 return M.x86.R_FS;
269         case SYSMODE_SEGOVR_GS:
270         case SYSMODE_SEGOVR_GS | SYSMODE_SEG_DS_SS:
271                 return M.x86.R_GS;
272         case SYSMODE_SEGOVR_SS:
273         case SYSMODE_SEGOVR_SS | SYSMODE_SEG_DS_SS:
274                 return M.x86.R_SS;
275         default:
276 #ifdef  DEBUG
277                 printk("error: should not happen:  multiple overrides.\n");
278 #endif
279                 HALT_SYS();
280                 return 0;
281         }
282 }
283
284 /****************************************************************************
285 PARAMETERS:
286 offset  - Offset to load data from
287
288 RETURNS:
289 Byte value read from the absolute memory location.
290
291 NOTE: Do not inline this function as (*sys_rdX) is already inline!
292 ****************************************************************************/
293 u8 fetch_data_byte(uint offset)
294 {
295 #ifdef DEBUG
296         if (CHECK_DATA_ACCESS())
297                 x86emu_check_data_access((u16) get_data_segment(), offset);
298 #endif
299         return (*sys_rdb) ((get_data_segment() << 4) + offset);
300 }
301
302 /****************************************************************************
303 PARAMETERS:
304 offset  - Offset to load data from
305
306 RETURNS:
307 Word value read from the absolute memory location.
308
309 NOTE: Do not inline this function as (*sys_rdX) is already inline!
310 ****************************************************************************/
311 u16 fetch_data_word(uint offset)
312 {
313 #ifdef DEBUG
314         if (CHECK_DATA_ACCESS())
315                 x86emu_check_data_access((u16) get_data_segment(), offset);
316 #endif
317         return (*sys_rdw) ((get_data_segment() << 4) + offset);
318 }
319
320 /****************************************************************************
321 PARAMETERS:
322 offset  - Offset to load data from
323
324 RETURNS:
325 Long value read from the absolute memory location.
326
327 NOTE: Do not inline this function as (*sys_rdX) is already inline!
328 ****************************************************************************/
329 u32 fetch_data_long(uint offset)
330 {
331 #ifdef DEBUG
332         if (CHECK_DATA_ACCESS())
333                 x86emu_check_data_access((u16) get_data_segment(), offset);
334 #endif
335         return (*sys_rdl) ((get_data_segment() << 4) + offset);
336 }
337
338 /****************************************************************************
339 PARAMETERS:
340 segment - Segment to load data from
341 offset  - Offset to load data from
342
343 RETURNS:
344 Byte value read from the absolute memory location.
345
346 NOTE: Do not inline this function as (*sys_rdX) is already inline!
347 ****************************************************************************/
348 u8 fetch_data_byte_abs(uint segment, uint offset)
349 {
350 #ifdef DEBUG
351         if (CHECK_DATA_ACCESS())
352                 x86emu_check_data_access(segment, offset);
353 #endif
354         return (*sys_rdb) (((u32) segment << 4) + offset);
355 }
356
357 /****************************************************************************
358 PARAMETERS:
359 segment - Segment to load data from
360 offset  - Offset to load data from
361
362 RETURNS:
363 Word value read from the absolute memory location.
364
365 NOTE: Do not inline this function as (*sys_rdX) is already inline!
366 ****************************************************************************/
367 u16 fetch_data_word_abs(uint segment, uint offset)
368 {
369 #ifdef DEBUG
370         if (CHECK_DATA_ACCESS())
371                 x86emu_check_data_access(segment, offset);
372 #endif
373         return (*sys_rdw) (((u32) segment << 4) + offset);
374 }
375
376 /****************************************************************************
377 PARAMETERS:
378 segment - Segment to load data from
379 offset  - Offset to load data from
380
381 RETURNS:
382 Long value read from the absolute memory location.
383
384 NOTE: Do not inline this function as (*sys_rdX) is already inline!
385 ****************************************************************************/
386 u32 fetch_data_long_abs(uint segment, uint offset)
387 {
388 #ifdef DEBUG
389         if (CHECK_DATA_ACCESS())
390                 x86emu_check_data_access(segment, offset);
391 #endif
392         return (*sys_rdl) (((u32) segment << 4) + offset);
393 }
394
395 /****************************************************************************
396 PARAMETERS:
397 offset  - Offset to store data at
398 val             - Value to store
399
400 REMARKS:
401 Writes a word value to an segmented memory location. The segment used is
402 the current 'default' segment, which may have been overridden.
403
404 NOTE: Do not inline this function as (*sys_wrX) is already inline!
405 ****************************************************************************/
406 void store_data_byte(uint offset, u8 val)
407 {
408 #ifdef DEBUG
409         if (CHECK_DATA_ACCESS())
410                 x86emu_check_data_access((u16) get_data_segment(), offset);
411 #endif
412         (*sys_wrb) ((get_data_segment() << 4) + offset, val);
413 }
414
415 /****************************************************************************
416 PARAMETERS:
417 offset  - Offset to store data at
418 val             - Value to store
419
420 REMARKS:
421 Writes a word value to an segmented memory location. The segment used is
422 the current 'default' segment, which may have been overridden.
423
424 NOTE: Do not inline this function as (*sys_wrX) is already inline!
425 ****************************************************************************/
426 void store_data_word(uint offset, u16 val)
427 {
428 #ifdef DEBUG
429         if (CHECK_DATA_ACCESS())
430                 x86emu_check_data_access((u16) get_data_segment(), offset);
431 #endif
432         (*sys_wrw) ((get_data_segment() << 4) + offset, val);
433 }
434
435 /****************************************************************************
436 PARAMETERS:
437 offset  - Offset to store data at
438 val             - Value to store
439
440 REMARKS:
441 Writes a long value to an segmented memory location. The segment used is
442 the current 'default' segment, which may have been overridden.
443
444 NOTE: Do not inline this function as (*sys_wrX) is already inline!
445 ****************************************************************************/
446 void store_data_long(uint offset, u32 val)
447 {
448 #ifdef DEBUG
449         if (CHECK_DATA_ACCESS())
450                 x86emu_check_data_access((u16) get_data_segment(), offset);
451 #endif
452         (*sys_wrl) ((get_data_segment() << 4) + offset, val);
453 }
454
455 /****************************************************************************
456 PARAMETERS:
457 segment - Segment to store data at
458 offset  - Offset to store data at
459 val             - Value to store
460
461 REMARKS:
462 Writes a byte value to an absolute memory location.
463
464 NOTE: Do not inline this function as (*sys_wrX) is already inline!
465 ****************************************************************************/
466 void store_data_byte_abs(uint segment, uint offset, u8 val)
467 {
468 #ifdef DEBUG
469         if (CHECK_DATA_ACCESS())
470                 x86emu_check_data_access(segment, offset);
471 #endif
472         (*sys_wrb) (((u32) segment << 4) + offset, val);
473 }
474
475 /****************************************************************************
476 PARAMETERS:
477 segment - Segment to store data at
478 offset  - Offset to store data at
479 val             - Value to store
480
481 REMARKS:
482 Writes a word value to an absolute memory location.
483
484 NOTE: Do not inline this function as (*sys_wrX) is already inline!
485 ****************************************************************************/
486 void store_data_word_abs(uint segment, uint offset, u16 val)
487 {
488 #ifdef DEBUG
489         if (CHECK_DATA_ACCESS())
490                 x86emu_check_data_access(segment, offset);
491 #endif
492         (*sys_wrw) (((u32) segment << 4) + offset, val);
493 }
494
495 /****************************************************************************
496 PARAMETERS:
497 segment - Segment to store data at
498 offset  - Offset to store data at
499 val             - Value to store
500
501 REMARKS:
502 Writes a long value to an absolute memory location.
503
504 NOTE: Do not inline this function as (*sys_wrX) is already inline!
505 ****************************************************************************/
506 void store_data_long_abs(uint segment, uint offset, u32 val)
507 {
508 #ifdef DEBUG
509         if (CHECK_DATA_ACCESS())
510                 x86emu_check_data_access(segment, offset);
511 #endif
512         (*sys_wrl) (((u32) segment << 4) + offset, val);
513 }
514
515 /****************************************************************************
516 PARAMETERS:
517 reg     - Register to decode
518
519 RETURNS:
520 Pointer to the appropriate register
521
522 REMARKS:
523 Return a pointer to the register given by the R/RM field of the
524 modrm byte, for byte operands. Also enables the decoding of instructions.
525 ****************************************************************************/
526 u8 *decode_rm_byte_register(int reg)
527 {
528         switch (reg) {
529         case 0:
530                 DECODE_PRINTF("AL");
531                 return &M.x86.R_AL;
532         case 1:
533                 DECODE_PRINTF("CL");
534                 return &M.x86.R_CL;
535         case 2:
536                 DECODE_PRINTF("DL");
537                 return &M.x86.R_DL;
538         case 3:
539                 DECODE_PRINTF("BL");
540                 return &M.x86.R_BL;
541         case 4:
542                 DECODE_PRINTF("AH");
543                 return &M.x86.R_AH;
544         case 5:
545                 DECODE_PRINTF("CH");
546                 return &M.x86.R_CH;
547         case 6:
548                 DECODE_PRINTF("DH");
549                 return &M.x86.R_DH;
550         case 7:
551                 DECODE_PRINTF("BH");
552                 return &M.x86.R_BH;
553         }
554         HALT_SYS();
555         return NULL;            /* NOT REACHED OR REACHED ON ERROR */
556 }
557
558 /****************************************************************************
559 PARAMETERS:
560 reg     - Register to decode
561
562 RETURNS:
563 Pointer to the appropriate register
564
565 REMARKS:
566 Return a pointer to the register given by the R/RM field of the
567 modrm byte, for word operands.  Also enables the decoding of instructions.
568 ****************************************************************************/
569 u16 *decode_rm_word_register(int reg)
570 {
571         switch (reg) {
572         case 0:
573                 DECODE_PRINTF("AX");
574                 return &M.x86.R_AX;
575         case 1:
576                 DECODE_PRINTF("CX");
577                 return &M.x86.R_CX;
578         case 2:
579                 DECODE_PRINTF("DX");
580                 return &M.x86.R_DX;
581         case 3:
582                 DECODE_PRINTF("BX");
583                 return &M.x86.R_BX;
584         case 4:
585                 DECODE_PRINTF("SP");
586                 return &M.x86.R_SP;
587         case 5:
588                 DECODE_PRINTF("BP");
589                 return &M.x86.R_BP;
590         case 6:
591                 DECODE_PRINTF("SI");
592                 return &M.x86.R_SI;
593         case 7:
594                 DECODE_PRINTF("DI");
595                 return &M.x86.R_DI;
596         }
597         HALT_SYS();
598         return NULL;            /* NOTREACHED OR REACHED ON ERROR */
599 }
600
601 /****************************************************************************
602 PARAMETERS:
603 reg     - Register to decode
604
605 RETURNS:
606 Pointer to the appropriate register
607
608 REMARKS:
609 Return a pointer to the register given by the R/RM field of the
610 modrm byte, for dword operands.  Also enables the decoding of instructions.
611 ****************************************************************************/
612 u32 *decode_rm_long_register(int reg)
613 {
614         switch (reg) {
615         case 0:
616                 DECODE_PRINTF("EAX");
617                 return &M.x86.R_EAX;
618         case 1:
619                 DECODE_PRINTF("ECX");
620                 return &M.x86.R_ECX;
621         case 2:
622                 DECODE_PRINTF("EDX");
623                 return &M.x86.R_EDX;
624         case 3:
625                 DECODE_PRINTF("EBX");
626                 return &M.x86.R_EBX;
627         case 4:
628                 DECODE_PRINTF("ESP");
629                 return &M.x86.R_ESP;
630         case 5:
631                 DECODE_PRINTF("EBP");
632                 return &M.x86.R_EBP;
633         case 6:
634                 DECODE_PRINTF("ESI");
635                 return &M.x86.R_ESI;
636         case 7:
637                 DECODE_PRINTF("EDI");
638                 return &M.x86.R_EDI;
639         }
640         HALT_SYS();
641         return NULL;            /* NOTREACHED OR REACHED ON ERROR */
642 }
643
644 /****************************************************************************
645 PARAMETERS:
646 reg     - Register to decode
647
648 RETURNS:
649 Pointer to the appropriate register
650
651 REMARKS:
652 Return a pointer to the register given by the R/RM field of the
653 modrm byte, for word operands, modified from above for the weirdo
654 special case of segreg operands.  Also enables the decoding of instructions.
655 ****************************************************************************/
656 u16 *decode_rm_seg_register(int reg)
657 {
658         switch (reg) {
659         case 0:
660                 DECODE_PRINTF("ES");
661                 return &M.x86.R_ES;
662         case 1:
663                 DECODE_PRINTF("CS");
664                 return &M.x86.R_CS;
665         case 2:
666                 DECODE_PRINTF("SS");
667                 return &M.x86.R_SS;
668         case 3:
669                 DECODE_PRINTF("DS");
670                 return &M.x86.R_DS;
671         case 4:
672                 DECODE_PRINTF("FS");
673                 return &M.x86.R_FS;
674          case 5:
675                 DECODE_PRINTF("GS");
676                 return &M.x86.R_GS;
677
678         case 6:
679         case 7:
680                 DECODE_PRINTF("ILLEGAL SEGREG");
681                 break;
682         }
683         HALT_SYS();
684         return NULL;            /* NOT REACHED OR REACHED ON ERROR */
685 }
686
687 /****************************************************************************
688 PARAMETERS:
689 rm      - RM value to decode
690
691 RETURNS:
692 Offset in memory for the address decoding
693
694 REMARKS:
695 Return the offset given by mod=00 addressing.  Also enables the
696 decoding of instructions.
697
698 NOTE:   The code which specifies the corresponding segment (ds vs ss)
699                 below in the case of [BP+..].  The assumption here is that at the
700                 point that this subroutine is called, the bit corresponding to
701                 SYSMODE_SEG_DS_SS will be zero.  After every instruction
702                 except the segment override instructions, this bit (as well
703                 as any bits indicating segment overrides) will be clear.  So
704                 if a SS access is needed, set this bit.  Otherwise, DS access
705                 occurs (unless any of the segment override bits are set).
706 ****************************************************************************/
707 unsigned decode_rm00_address(int rm)
708 {
709         unsigned offset;
710
711         switch (rm) {
712         case 0:
713                 DECODE_PRINTF("[BX+SI]");
714                 return M.x86.R_BX + M.x86.R_SI;
715         case 1:
716                 DECODE_PRINTF("[BX+DI]");
717                 return M.x86.R_BX + M.x86.R_DI;
718         case 2:
719                 DECODE_PRINTF("[BP+SI]");
720                 M.x86.mode |= SYSMODE_SEG_DS_SS;
721                 return M.x86.R_BP + M.x86.R_SI;
722         case 3:
723                 DECODE_PRINTF("[BP+DI]");
724                 M.x86.mode |= SYSMODE_SEG_DS_SS;
725                 return M.x86.R_BP + M.x86.R_DI;
726         case 4:
727                 DECODE_PRINTF("[SI]");
728                 return M.x86.R_SI;
729         case 5:
730                 DECODE_PRINTF("[DI]");
731                 return M.x86.R_DI;
732         case 6:
733                 offset = fetch_word_imm();
734                 DECODE_PRINTF2("[%04x]", offset);
735                 return offset;
736         case 7:
737                 DECODE_PRINTF("[BX]");
738                 return M.x86.R_BX;
739         }
740         HALT_SYS();
741         return 0;
742 }
743
744 /****************************************************************************
745 PARAMETERS:
746 rm      - RM value to decode
747
748 RETURNS:
749 Offset in memory for the address decoding
750
751 REMARKS:
752 Return the offset given by mod=01 addressing.  Also enables the
753 decoding of instructions.
754 ****************************************************************************/
755 unsigned decode_rm01_address(int rm)
756 {
757         int displacement = (s8) fetch_byte_imm();
758         switch (rm) {
759         case 0:
760                 DECODE_PRINTF2("%d[BX+SI]", displacement);
761                 return M.x86.R_BX + M.x86.R_SI + displacement;
762         case 1:
763                 DECODE_PRINTF2("%d[BX+DI]", displacement);
764                 return M.x86.R_BX + M.x86.R_DI + displacement;
765         case 2:
766                 DECODE_PRINTF2("%d[BP+SI]", displacement);
767                 M.x86.mode |= SYSMODE_SEG_DS_SS;
768                 return M.x86.R_BP + M.x86.R_SI + displacement;
769         case 3:
770                 DECODE_PRINTF2("%d[BP+DI]", displacement);
771                 M.x86.mode |= SYSMODE_SEG_DS_SS;
772                 return M.x86.R_BP + M.x86.R_DI + displacement;
773         case 4:
774                 DECODE_PRINTF2("%d[SI]", displacement);
775                 return M.x86.R_SI + displacement;
776         case 5:
777                 DECODE_PRINTF2("%d[DI]", displacement);
778                 return M.x86.R_DI + displacement;
779         case 6:
780                 DECODE_PRINTF2("%d[BP]", displacement);
781                 M.x86.mode |= SYSMODE_SEG_DS_SS;
782                 return M.x86.R_BP + displacement;
783         case 7:
784                 DECODE_PRINTF2("%d[BX]", displacement);
785                 return M.x86.R_BX + displacement;
786         }
787         HALT_SYS();
788         return 0;               /* SHOULD NOT HAPPEN */
789 }
790
791 /****************************************************************************
792 PARAMETERS:
793 rm      - RM value to decode
794
795 RETURNS:
796 Offset in memory for the address decoding
797
798 REMARKS:
799 Return the offset given by mod=10 addressing.  Also enables the
800 decoding of instructions.
801 ****************************************************************************/
802 unsigned decode_rm10_address(int rm)
803 {
804         unsigned displacement = (u16) fetch_word_imm();
805         switch (rm) {
806         case 0:
807                 DECODE_PRINTF2("%04x[BX+SI]", displacement);
808                 return M.x86.R_BX + M.x86.R_SI + displacement;
809         case 1:
810                 DECODE_PRINTF2("%04x[BX+DI]", displacement);
811                 return M.x86.R_BX + M.x86.R_DI + displacement;
812         case 2:
813                 DECODE_PRINTF2("%04x[BP+SI]", displacement);
814                 M.x86.mode |= SYSMODE_SEG_DS_SS;
815                 return M.x86.R_BP + M.x86.R_SI + displacement;
816         case 3:
817                 DECODE_PRINTF2("%04x[BP+DI]", displacement);
818                 M.x86.mode |= SYSMODE_SEG_DS_SS;
819                 return M.x86.R_BP + M.x86.R_DI + displacement;
820         case 4:
821                 DECODE_PRINTF2("%04x[SI]", displacement);
822                 return M.x86.R_SI + displacement;
823         case 5:
824                 DECODE_PRINTF2("%04x[DI]", displacement);
825                 return M.x86.R_DI + displacement;
826         case 6:
827                 DECODE_PRINTF2("%04x[BP]", displacement);
828                 M.x86.mode |= SYSMODE_SEG_DS_SS;
829                 return M.x86.R_BP + displacement;
830         case 7:
831                 DECODE_PRINTF2("%04x[BX]", displacement);
832                 return M.x86.R_BX + displacement;
833         }
834         HALT_SYS();
835         return 0;
836         /*NOTREACHED */
837 }