[SOFT386]
[reactos.git] / lib / soft386 / common.inl
1 /*
2 * COPYRIGHT: GPL - See COPYING in the top level directory
3 * PROJECT: 386/486 CPU Emulation Library
4 * FILE: common.inl
5 * PURPOSE: Common functions used internally by Soft386 (inlined funtions).
6 * PROGRAMMERS: Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
7 */
8
9 /* PUBLIC FUNCTIONS ***********************************************************/
10
11 FORCEINLINE
12 VOID
13 Soft386Exception(PSOFT386_STATE State,
14 SOFT386_EXCEPTIONS ExceptionCode)
15 {
16 /* Call the internal function */
17 Soft386ExceptionWithErrorCode(State, ExceptionCode, 0);
18 }
19
20 FORCEINLINE
21 BOOLEAN
22 Soft386StackPush(PSOFT386_STATE State,
23 ULONG Value)
24 {
25 BOOLEAN Size = State->SegmentRegs[SOFT386_REG_SS].Size;
26
27 /* The OPSIZE prefix toggles the size */
28 if (State->PrefixFlags & SOFT386_PREFIX_OPSIZE) Size = !Size;
29
30 if (Size)
31 {
32 /* 32-bit size */
33
34 /* Check if ESP is between 1 and 3 */
35 if (State->GeneralRegs[SOFT386_REG_ESP].Long >= 1
36 && State->GeneralRegs[SOFT386_REG_ESP].Long <= 3)
37 {
38 Soft386Exception(State, SOFT386_EXCEPTION_SS);
39 return FALSE;
40 }
41
42 /* Subtract ESP by 4 */
43 State->GeneralRegs[SOFT386_REG_ESP].Long -= 4;
44
45 /* Store the value in SS:ESP */
46 return Soft386WriteMemory(State,
47 SOFT386_REG_SS,
48 State->GeneralRegs[SOFT386_REG_ESP].Long,
49 &Value,
50 sizeof(ULONG));
51 }
52 else
53 {
54 /* 16-bit size */
55 USHORT ShortValue = LOWORD(Value);
56
57 /* Check if SP is 1 */
58 if (State->GeneralRegs[SOFT386_REG_ESP].Long == 1)
59 {
60 Soft386Exception(State, SOFT386_EXCEPTION_SS);
61 return FALSE;
62 }
63
64 /* Subtract SP by 2 */
65 State->GeneralRegs[SOFT386_REG_ESP].LowWord -= 2;
66
67 /* Store the value in SS:SP */
68 return Soft386WriteMemory(State,
69 SOFT386_REG_SS,
70 State->GeneralRegs[SOFT386_REG_ESP].LowWord,
71 &ShortValue,
72 sizeof(USHORT));
73 }
74 }
75
76 FORCEINLINE
77 BOOLEAN
78 Soft386StackPop(PSOFT386_STATE State,
79 PULONG Value)
80 {
81 ULONG LongValue;
82 USHORT ShortValue;
83 BOOLEAN Size = State->SegmentRegs[SOFT386_REG_SS].Size;
84
85 /* The OPSIZE prefix toggles the size */
86 if (State->PrefixFlags & SOFT386_PREFIX_OPSIZE) Size = !Size;
87
88 if (Size)
89 {
90 /* 32-bit size */
91
92 /* Check if ESP is 0xFFFFFFFF */
93 if (State->GeneralRegs[SOFT386_REG_ESP].Long == 0xFFFFFFFF)
94 {
95 Soft386Exception(State, SOFT386_EXCEPTION_SS);
96 return FALSE;
97 }
98
99 /* Read the value from SS:ESP */
100 if (!Soft386ReadMemory(State,
101 SOFT386_REG_SS,
102 State->GeneralRegs[SOFT386_REG_ESP].Long,
103 FALSE,
104 &LongValue,
105 sizeof(LongValue)))
106 {
107 /* An exception occurred */
108 return FALSE;
109 }
110
111 /* Increment ESP by 4 */
112 State->GeneralRegs[SOFT386_REG_ESP].Long += 4;
113
114 /* Store the value in the result */
115 *Value = LongValue;
116 }
117 else
118 {
119 /* 16-bit size */
120
121 /* Check if SP is 0xFFFF */
122 if (State->GeneralRegs[SOFT386_REG_ESP].LowWord == 0xFFFF)
123 {
124 Soft386Exception(State, SOFT386_EXCEPTION_SS);
125 return FALSE;
126 }
127
128 /* Read the value from SS:SP */
129 if (!Soft386ReadMemory(State,
130 SOFT386_REG_SS,
131 State->GeneralRegs[SOFT386_REG_ESP].LowWord,
132 FALSE,
133 &ShortValue,
134 sizeof(ShortValue)))
135 {
136 /* An exception occurred */
137 return FALSE;
138 }
139
140 /* Increment SP by 2 */
141 State->GeneralRegs[SOFT386_REG_ESP].Long += 2;
142
143 /* Store the value in the result */
144 *Value = ShortValue;
145 }
146
147 return TRUE;
148 }
149
150 FORCEINLINE
151 BOOLEAN
152 Soft386LoadSegment(PSOFT386_STATE State,
153 INT Segment,
154 USHORT Selector)
155 {
156 PSOFT386_SEG_REG CachedDescriptor;
157 SOFT386_GDT_ENTRY GdtEntry;
158
159 ASSERT(Segment < SOFT386_NUM_SEG_REGS);
160
161 /* Get the cached descriptor */
162 CachedDescriptor = &State->SegmentRegs[Segment];
163
164 /* Check for protected mode */
165 if (State->ControlRegisters[SOFT386_REG_CR0] & SOFT386_CR0_PE)
166 {
167 /* Make sure the GDT contains the entry */
168 if (GET_SEGMENT_INDEX(Selector) >= (State->Gdtr.Size + 1))
169 {
170 Soft386Exception(State, SOFT386_EXCEPTION_GP);
171 return FALSE;
172 }
173
174 /* Read the GDT */
175 // FIXME: This code is only correct when paging is disabled!!!
176 if (State->MemReadCallback)
177 {
178 State->MemReadCallback(State,
179 State->Gdtr.Address
180 + GET_SEGMENT_INDEX(Selector),
181 &GdtEntry,
182 sizeof(GdtEntry));
183 }
184 else
185 {
186 RtlMoveMemory(&GdtEntry,
187 (PVOID)(State->Gdtr.Address
188 + GET_SEGMENT_INDEX(Selector)),
189 sizeof(GdtEntry));
190 }
191
192 /* Check if we are loading SS */
193 if (Segment == SOFT386_REG_SS)
194 {
195 if (GET_SEGMENT_INDEX(Selector) == 0)
196 {
197 Soft386Exception(State, SOFT386_EXCEPTION_GP);
198 return FALSE;
199 }
200
201 if (GdtEntry.Executable || !GdtEntry.ReadWrite)
202 {
203 Soft386Exception(State, SOFT386_EXCEPTION_GP);
204 return FALSE;
205 }
206
207 if ((GET_SEGMENT_RPL(Selector) != Soft386GetCurrentPrivLevel(State))
208 || (GET_SEGMENT_RPL(Selector) != GdtEntry.Dpl))
209 {
210 Soft386Exception(State, SOFT386_EXCEPTION_GP);
211 return FALSE;
212 }
213
214 if (!GdtEntry.Present)
215 {
216 Soft386Exception(State, SOFT386_EXCEPTION_SS);
217 return FALSE;
218 }
219 }
220 else
221 {
222 if ((GET_SEGMENT_RPL(Selector) > GdtEntry.Dpl)
223 && (Soft386GetCurrentPrivLevel(State) > GdtEntry.Dpl))
224 {
225 Soft386Exception(State, SOFT386_EXCEPTION_GP);
226 return FALSE;
227 }
228
229 if (!GdtEntry.Present)
230 {
231 Soft386Exception(State, SOFT386_EXCEPTION_NP);
232 return FALSE;
233 }
234 }
235
236 /* Update the cache entry */
237 CachedDescriptor->Selector = Selector;
238 CachedDescriptor->Base = GdtEntry.Base | (GdtEntry.BaseHigh << 24);
239 CachedDescriptor->Limit = GdtEntry.Limit | (GdtEntry.LimitHigh << 16);
240 CachedDescriptor->Accessed = GdtEntry.Accessed;
241 CachedDescriptor->ReadWrite = GdtEntry.ReadWrite;
242 CachedDescriptor->DirConf = GdtEntry.DirConf;
243 CachedDescriptor->Executable = GdtEntry.Executable;
244 CachedDescriptor->SystemType = GdtEntry.SystemType;
245 CachedDescriptor->Dpl = GdtEntry.Dpl;
246 CachedDescriptor->Present = GdtEntry.Present;
247 CachedDescriptor->Size = GdtEntry.Size;
248
249 /* Check for page granularity */
250 if (GdtEntry.Granularity) CachedDescriptor->Limit <<= 12;
251 }
252 else
253 {
254 /* Update the selector and base */
255 CachedDescriptor->Selector = Selector;
256 CachedDescriptor->Base = Selector << 4;
257 }
258
259 return TRUE;
260 }
261
262 FORCEINLINE
263 BOOLEAN
264 Soft386FetchByte(PSOFT386_STATE State,
265 PUCHAR Data)
266 {
267 PSOFT386_SEG_REG CachedDescriptor;
268
269 /* Get the cached descriptor of CS */
270 CachedDescriptor = &State->SegmentRegs[SOFT386_REG_CS];
271
272 /* Read from memory */
273 if (!Soft386ReadMemory(State,
274 SOFT386_REG_CS,
275 (CachedDescriptor->Size) ? State->InstPtr.Long
276 : State->InstPtr.LowWord,
277 TRUE,
278 Data,
279 sizeof(UCHAR)))
280 {
281 /* Exception occurred during instruction fetch */
282 return FALSE;
283 }
284
285 /* Advance the instruction pointer */
286 if (CachedDescriptor->Size) State->InstPtr.Long++;
287 else State->InstPtr.LowWord++;
288
289 return TRUE;
290 }
291
292 FORCEINLINE
293 BOOLEAN
294 Soft386FetchWord(PSOFT386_STATE State,
295 PUSHORT Data)
296 {
297 PSOFT386_SEG_REG CachedDescriptor;
298
299 /* Get the cached descriptor of CS */
300 CachedDescriptor = &State->SegmentRegs[SOFT386_REG_CS];
301
302 /* Read from memory */
303 // FIXME: Fix byte order on big-endian machines
304 if (!Soft386ReadMemory(State,
305 SOFT386_REG_CS,
306 (CachedDescriptor->Size) ? State->InstPtr.Long
307 : State->InstPtr.LowWord,
308 TRUE,
309 Data,
310 sizeof(USHORT)))
311 {
312 /* Exception occurred during instruction fetch */
313 return FALSE;
314 }
315
316 /* Advance the instruction pointer */
317 if (CachedDescriptor->Size) State->InstPtr.Long += sizeof(USHORT);
318 else State->InstPtr.LowWord += sizeof(USHORT);
319
320 return TRUE;
321 }
322
323 FORCEINLINE
324 BOOLEAN
325 Soft386FetchDword(PSOFT386_STATE State,
326 PULONG Data)
327 {
328 PSOFT386_SEG_REG CachedDescriptor;
329
330 /* Get the cached descriptor of CS */
331 CachedDescriptor = &State->SegmentRegs[SOFT386_REG_CS];
332
333 /* Read from memory */
334 // FIXME: Fix byte order on big-endian machines
335 if (!Soft386ReadMemory(State,
336 SOFT386_REG_CS,
337 (CachedDescriptor->Size) ? State->InstPtr.Long
338 : State->InstPtr.LowWord,
339 TRUE,
340 Data,
341 sizeof(ULONG)))
342 {
343 /* Exception occurred during instruction fetch */
344 return FALSE;
345 }
346
347 /* Advance the instruction pointer */
348 if (CachedDescriptor->Size) State->InstPtr.Long += sizeof(ULONG);
349 else State->InstPtr.LowWord += sizeof(ULONG);
350
351 return TRUE;
352 }
353
354 FORCEINLINE
355 BOOLEAN
356 Soft386GetIntVector(PSOFT386_STATE State,
357 UCHAR Number,
358 PSOFT386_IDT_ENTRY IdtEntry)
359 {
360 ULONG FarPointer;
361
362 /* Check for protected mode */
363 if (State->ControlRegisters[SOFT386_REG_CR0] & SOFT386_CR0_PE)
364 {
365 /* Read from the IDT */
366 // FIXME: This code is only correct when paging is disabled!!!
367 if (State->MemReadCallback)
368 {
369 State->MemReadCallback(State,
370 State->Idtr.Address
371 + Number * sizeof(*IdtEntry),
372 IdtEntry,
373 sizeof(*IdtEntry));
374 }
375 else
376 {
377 RtlMoveMemory(IdtEntry,
378 (PVOID)(State->Idtr.Address
379 + Number * sizeof(*IdtEntry)),
380 sizeof(*IdtEntry));
381 }
382 }
383 else
384 {
385 /* Read from the real-mode IVT */
386
387 /* Paging is always disabled in real mode */
388 if (State->MemReadCallback)
389 {
390 State->MemReadCallback(State,
391 State->Idtr.Address
392 + Number * sizeof(FarPointer),
393 &FarPointer,
394 sizeof(FarPointer));
395 }
396 else
397 {
398 RtlMoveMemory(IdtEntry,
399 (PVOID)(State->Idtr.Address
400 + Number * sizeof(FarPointer)),
401 sizeof(FarPointer));
402 }
403
404 /* Fill a fake IDT entry */
405 IdtEntry->Offset = LOWORD(FarPointer);
406 IdtEntry->Selector = HIWORD(FarPointer);
407 IdtEntry->Zero = 0;
408 IdtEntry->Type = SOFT386_IDT_INT_GATE;
409 IdtEntry->Storage = FALSE;
410 IdtEntry->Dpl = 0;
411 IdtEntry->Present = TRUE;
412 IdtEntry->OffsetHigh = 0;
413 }
414
415 /*
416 * Once paging support is implemented this function
417 * will not always return true
418 */
419 return TRUE;
420 }
421
422 FORCEINLINE
423 BOOLEAN
424 Soft386CalculateParity(UCHAR Number)
425 {
426 Number ^= Number >> 1;
427 Number ^= Number >> 2;
428 Number ^= Number >> 4;
429 return !(Number & 1);
430 }
431
432 FORCEINLINE
433 BOOLEAN
434 Soft386ParseModRegRm(PSOFT386_STATE State,
435 BOOLEAN AddressSize,
436 PSOFT386_MOD_REG_RM ModRegRm)
437 {
438 UCHAR ModRmByte, Mode, RegMem;
439
440 /* Fetch the MOD REG R/M byte */
441 if (!Soft386FetchByte(State, &ModRmByte))
442 {
443 /* Exception occurred */
444 return FALSE;
445 }
446
447 /* Unpack the mode and R/M */
448 Mode = ModRmByte >> 6;
449 RegMem = ModRmByte & 0x07;
450
451 /* Set the register operand */
452 ModRegRm->Register = (ModRmByte >> 3) & 0x07;
453
454 /* Check the mode */
455 if ((ModRmByte >> 6) == 3)
456 {
457 /* The second operand is also a register */
458 ModRegRm->Memory = FALSE;
459 ModRegRm->SecondRegister = RegMem;
460
461 /* Done parsing */
462 return TRUE;
463 }
464
465 /* The second operand is memory */
466 ModRegRm->Memory = TRUE;
467
468 if (AddressSize)
469 {
470 if (RegMem == SOFT386_REG_ESP)
471 {
472 UCHAR SibByte;
473 ULONG Scale, Index, Base;
474
475 /* Fetch the SIB byte */
476 if (!Soft386FetchByte(State, &SibByte))
477 {
478 /* Exception occurred */
479 return FALSE;
480 }
481
482 /* Unpack the scale, index and base */
483 Scale = 1 << (SibByte >> 6);
484 Index = (SibByte >> 3) & 0x07;
485 if (Index != SOFT386_REG_ESP) Index = State->GeneralRegs[Index].Long;
486 else Index = 0;
487 Base = State->GeneralRegs[SibByte & 0x07].Long;
488
489 /* Calculate the address */
490 ModRegRm->MemoryAddress = Base + Index * Scale;
491 }
492 else if (RegMem == SOFT386_REG_EBP)
493 {
494 if (Mode) ModRegRm->MemoryAddress = State->GeneralRegs[SOFT386_REG_EBP].Long;
495 else ModRegRm->MemoryAddress = 0;
496 }
497 else
498 {
499 /* Get the base from the register */
500 ModRegRm->MemoryAddress = State->GeneralRegs[RegMem].Long;
501 }
502
503 /* Check if there is no segment override */
504 if (!(State->PrefixFlags & SOFT386_PREFIX_SEG))
505 {
506 /* Check if the default segment should be SS */
507 if ((RegMem == SOFT386_REG_EBP) && Mode)
508 {
509 /* Add a SS: prefix */
510 State->PrefixFlags |= SOFT386_PREFIX_SEG;
511 State->SegmentOverride = SOFT386_REG_SS;
512 }
513 }
514
515 if (Mode == 1)
516 {
517 CHAR Offset;
518
519 /* Fetch the byte */
520 if (!Soft386FetchByte(State, (PUCHAR)&Offset))
521 {
522 /* Exception occurred */
523 return FALSE;
524 }
525
526 /* Add the signed offset to the address */
527 ModRegRm->MemoryAddress += (LONG)Offset;
528 }
529 else if ((Mode == 2) || ((Mode == 0) && (RegMem == SOFT386_REG_EBP)))
530 {
531 LONG Offset;
532
533 /* Fetch the dword */
534 if (!Soft386FetchDword(State, (PULONG)&Offset))
535 {
536 /* Exception occurred */
537 return FALSE;
538 }
539
540 /* Add the signed offset to the address */
541 ModRegRm->MemoryAddress += Offset;
542 }
543 }
544 else
545 {
546 /* Check the operand */
547 switch (RegMem)
548 {
549 case 0:
550 case 2:
551 {
552 /* (SS:)[BX + SI] */
553 ModRegRm->MemoryAddress = State->GeneralRegs[SOFT386_REG_EBX].LowWord
554 + State->GeneralRegs[SOFT386_REG_ESI].LowWord;
555
556 break;
557 }
558
559 case 1:
560 case 3:
561 {
562 /* (SS:)[BX + DI] */
563 ModRegRm->MemoryAddress = State->GeneralRegs[SOFT386_REG_EBX].LowWord
564 + State->GeneralRegs[SOFT386_REG_EDI].LowWord;
565
566 break;
567 }
568
569 case 4:
570 {
571 /* [SI] */
572 ModRegRm->MemoryAddress = State->GeneralRegs[SOFT386_REG_ESI].LowWord;
573
574 break;
575 }
576
577 case 5:
578 {
579 /* [DI] */
580 ModRegRm->MemoryAddress = State->GeneralRegs[SOFT386_REG_EDI].LowWord;
581
582 break;
583 }
584
585 case 6:
586 {
587 if (Mode)
588 {
589 /* [BP] */
590 ModRegRm->MemoryAddress = State->GeneralRegs[SOFT386_REG_EBP].LowWord;
591 }
592 else
593 {
594 /* [constant] (added later) */
595 ModRegRm->MemoryAddress = 0;
596 }
597
598 break;
599 }
600
601 case 7:
602 {
603 /* [BX] */
604 ModRegRm->MemoryAddress = State->GeneralRegs[SOFT386_REG_EBX].LowWord;
605
606 break;
607 }
608 }
609
610 /* Check if there is no segment override */
611 if (!(State->PrefixFlags & SOFT386_PREFIX_SEG))
612 {
613 /* Check if the default segment should be SS */
614 if ((RegMem == 2) || (RegMem == 3) || ((RegMem == 6) && Mode))
615 {
616 /* Add a SS: prefix */
617 State->PrefixFlags |= SOFT386_PREFIX_SEG;
618 State->SegmentOverride = SOFT386_REG_SS;
619 }
620 }
621
622 if (Mode == 1)
623 {
624 CHAR Offset;
625
626 /* Fetch the byte */
627 if (!Soft386FetchByte(State, (PUCHAR)&Offset))
628 {
629 /* Exception occurred */
630 return FALSE;
631 }
632
633 /* Add the signed offset to the address */
634 ModRegRm->MemoryAddress += (LONG)Offset;
635 }
636 else if ((Mode == 2) || ((Mode == 0) && (RegMem == 6)))
637 {
638 SHORT Offset;
639
640 /* Fetch the word */
641 if (!Soft386FetchWord(State, (PUSHORT)&Offset))
642 {
643 /* Exception occurred */
644 return FALSE;
645 }
646
647 /* Add the signed offset to the address */
648 ModRegRm->MemoryAddress += (LONG)Offset;
649 }
650 }
651
652 return TRUE;
653 }
654
655 FORCEINLINE
656 BOOLEAN
657 Soft386ReadModrmByteOperands(PSOFT386_STATE State,
658 PSOFT386_MOD_REG_RM ModRegRm,
659 PUCHAR RegValue,
660 PUCHAR RmValue)
661 {
662 SOFT386_SEG_REGS Segment = SOFT386_REG_DS;
663
664 /* Get the register value */
665 if (ModRegRm->Register & 0x04)
666 {
667 /* AH, CH, DH, BH */
668 *RegValue = State->GeneralRegs[ModRegRm->Register & 0x03].HighByte;
669 }
670 else
671 {
672 /* AL, CL, DL, BL */
673 *RegValue = State->GeneralRegs[ModRegRm->Register & 0x03].LowByte;
674 }
675
676 if (!ModRegRm->Memory)
677 {
678 /* Get the second register value */
679 if (ModRegRm->SecondRegister & 0x04)
680 {
681 /* AH, CH, DH, BH */
682 *RmValue = State->GeneralRegs[ModRegRm->SecondRegister & 0x03].HighByte;
683 }
684 else
685 {
686 /* AL, CL, DL, BL */
687 *RmValue = State->GeneralRegs[ModRegRm->SecondRegister & 0x03].LowByte;
688 }
689 }
690 else
691 {
692 /* Check for the segment override */
693 if (State->PrefixFlags & SOFT386_PREFIX_SEG)
694 {
695 /* Use the override segment instead */
696 Segment = State->SegmentOverride;
697 }
698
699 /* Read memory */
700 if (!Soft386ReadMemory(State,
701 Segment,
702 ModRegRm->MemoryAddress,
703 FALSE,
704 RmValue,
705 sizeof(UCHAR)))
706 {
707 /* Exception occurred */
708 return FALSE;
709 }
710 }
711
712 return TRUE;
713 }
714
715 FORCEINLINE
716 BOOLEAN
717 Soft386ReadModrmWordOperands(PSOFT386_STATE State,
718 PSOFT386_MOD_REG_RM ModRegRm,
719 PUSHORT RegValue,
720 PUSHORT RmValue)
721 {
722 SOFT386_SEG_REGS Segment = SOFT386_REG_DS;
723
724 /* Get the register value */
725 *RegValue = State->GeneralRegs[ModRegRm->Register].LowWord;
726
727 if (!ModRegRm->Memory)
728 {
729 /* Get the second register value */
730 *RmValue = State->GeneralRegs[ModRegRm->SecondRegister].LowWord;
731 }
732 else
733 {
734 /* Check for the segment override */
735 if (State->PrefixFlags & SOFT386_PREFIX_SEG)
736 {
737 /* Use the override segment instead */
738 Segment = State->SegmentOverride;
739 }
740
741 /* Read memory */
742 if (!Soft386ReadMemory(State,
743 Segment,
744 ModRegRm->MemoryAddress,
745 FALSE,
746 RmValue,
747 sizeof(USHORT)))
748 {
749 /* Exception occurred */
750 return FALSE;
751 }
752 }
753
754 return TRUE;
755 }
756
757 FORCEINLINE
758 BOOLEAN
759 Soft386ReadModrmDwordOperands(PSOFT386_STATE State,
760 PSOFT386_MOD_REG_RM ModRegRm,
761 PULONG RegValue,
762 PULONG RmValue)
763 {
764 SOFT386_SEG_REGS Segment = SOFT386_REG_DS;
765
766 /* Get the register value */
767 *RegValue = State->GeneralRegs[ModRegRm->Register].Long;
768
769 if (!ModRegRm->Memory)
770 {
771 /* Get the second register value */
772 *RmValue = State->GeneralRegs[ModRegRm->SecondRegister].Long;
773 }
774 else
775 {
776 /* Check for the segment override */
777 if (State->PrefixFlags & SOFT386_PREFIX_SEG)
778 {
779 /* Use the override segment instead */
780 Segment = State->SegmentOverride;
781 }
782
783 /* Read memory */
784 if (!Soft386ReadMemory(State,
785 Segment,
786 ModRegRm->MemoryAddress,
787 FALSE,
788 RmValue,
789 sizeof(ULONG)))
790 {
791 /* Exception occurred */
792 return FALSE;
793 }
794 }
795
796 return TRUE;
797 }
798
799 FORCEINLINE
800 BOOLEAN
801 Soft386WriteModrmByteOperands(PSOFT386_STATE State,
802 PSOFT386_MOD_REG_RM ModRegRm,
803 BOOLEAN WriteRegister,
804 UCHAR Value)
805 {
806 SOFT386_SEG_REGS Segment = SOFT386_REG_DS;
807
808 if (WriteRegister)
809 {
810 /* Store the value in the register */
811 if (ModRegRm->Register & 0x04)
812 {
813 /* AH, CH, DH, BH */
814 State->GeneralRegs[ModRegRm->Register & 0x03].HighByte = Value;
815 }
816 else
817 {
818 /* AL, CL, DL, BL */
819 State->GeneralRegs[ModRegRm->Register & 0x03].LowByte = Value;
820 }
821 }
822 else
823 {
824 if (!ModRegRm->Memory)
825 {
826 /* Store the value in the second register */
827 if (ModRegRm->SecondRegister & 0x04)
828 {
829 /* AH, CH, DH, BH */
830 State->GeneralRegs[ModRegRm->SecondRegister & 0x03].HighByte = Value;
831 }
832 else
833 {
834 /* AL, CL, DL, BL */
835 State->GeneralRegs[ModRegRm->SecondRegister & 0x03].LowByte = Value;
836 }
837 }
838 else
839 {
840 /* Check for the segment override */
841 if (State->PrefixFlags & SOFT386_PREFIX_SEG)
842 {
843 /* Use the override segment instead */
844 Segment = State->SegmentOverride;
845 }
846
847 /* Write memory */
848 if (!Soft386WriteMemory(State,
849 Segment,
850 ModRegRm->MemoryAddress,
851 &Value,
852 sizeof(UCHAR)))
853 {
854 /* Exception occurred */
855 return FALSE;
856 }
857 }
858 }
859
860 return TRUE;
861 }
862
863 FORCEINLINE
864 BOOLEAN
865 Soft386WriteModrmWordOperands(PSOFT386_STATE State,
866 PSOFT386_MOD_REG_RM ModRegRm,
867 BOOLEAN WriteRegister,
868 USHORT Value)
869 {
870 SOFT386_SEG_REGS Segment = SOFT386_REG_DS;
871
872 if (WriteRegister)
873 {
874 /* Store the value in the register */
875 State->GeneralRegs[ModRegRm->Register].LowWord = Value;
876 }
877 else
878 {
879 if (!ModRegRm->Memory)
880 {
881 /* Store the value in the second register */
882 State->GeneralRegs[ModRegRm->SecondRegister].LowWord = Value;
883 }
884 else
885 {
886 /* Check for the segment override */
887 if (State->PrefixFlags & SOFT386_PREFIX_SEG)
888 {
889 /* Use the override segment instead */
890 Segment = State->SegmentOverride;
891 }
892
893 /* Write memory */
894 if (!Soft386WriteMemory(State,
895 Segment,
896 ModRegRm->MemoryAddress,
897 &Value,
898 sizeof(USHORT)))
899 {
900 /* Exception occurred */
901 return FALSE;
902 }
903 }
904 }
905
906 return TRUE;
907 }
908
909 FORCEINLINE
910 BOOLEAN
911 Soft386WriteModrmDwordOperands(PSOFT386_STATE State,
912 PSOFT386_MOD_REG_RM ModRegRm,
913 BOOLEAN WriteRegister,
914 ULONG Value)
915 {
916 SOFT386_SEG_REGS Segment = SOFT386_REG_DS;
917
918 if (WriteRegister)
919 {
920 /* Store the value in the register */
921 State->GeneralRegs[ModRegRm->Register].Long = Value;
922 }
923 else
924 {
925 if (!ModRegRm->Memory)
926 {
927 /* Store the value in the second register */
928 State->GeneralRegs[ModRegRm->SecondRegister].Long = Value;
929 }
930 else
931 {
932 /* Check for the segment override */
933 if (State->PrefixFlags & SOFT386_PREFIX_SEG)
934 {
935 /* Use the override segment instead */
936 Segment = State->SegmentOverride;
937 }
938
939 /* Write memory */
940 if (!Soft386WriteMemory(State,
941 Segment,
942 ModRegRm->MemoryAddress,
943 &Value,
944 sizeof(ULONG)))
945 {
946 /* Exception occurred */
947 return FALSE;
948 }
949 }
950 }
951
952 return TRUE;
953 }
954
955 /* EOF */