Skip to content

Commit e2863a8

Browse files
authored
fix: Put correct types for far pointers in structs (#2179)
1 parent ea06b62 commit e2863a8

8 files changed

Lines changed: 100 additions & 108 deletions

File tree

src/Spice86.Core/Emulator/Devices/Video/VideoFunctionalityInfo.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
using Spice86.Core.Emulator.Memory.ReaderWriter;
44
using Spice86.Core.Emulator.ReverseEngineer.DataStructure;
5+
using Spice86.Shared.Emulator.Memory;
56

67
using System.ComponentModel.DataAnnotations;
78

@@ -21,7 +22,7 @@ public VideoFunctionalityInfo(IByteReaderWriter byteReaderWriter, uint baseAddre
2122
/// <summary>
2223
/// Gets or sets the address of the Saved Functionality Table (SFT) in memory.
2324
/// </summary>
24-
public uint SftAddress { get => UInt32[0x00]; set => UInt32[0x00] = value; }
25+
public SegmentedAddress SftAddress { get => SegmentedAddress16[0x00]; set => SegmentedAddress16[0x00] = value; }
2526

2627
/// <summary>
2728
/// Gets or sets the current video mode.

src/Spice86.Core/Emulator/InterruptHandlers/VGA/VgaBios.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -670,7 +670,7 @@ public VideoFunctionalityInfo GetFunctionalityInfo() {
670670

671671
uint address = MemoryUtils.ToPhysicalAddress(segment, offset);
672672
var info = new VideoFunctionalityInfo(Memory, address) {
673-
SftAddress = MemoryMap.StaticFunctionalityTableSegment << 16,
673+
SftAddress = new SegmentedAddress(MemoryMap.StaticFunctionalityTableSegment, 0),
674674
VideoMode = _biosDataArea.VideoMode,
675675
ScreenColumns = _biosDataArea.ScreenColumns,
676676
VideoBufferLength = _biosDataArea.VideoPageSize,

src/Spice86.Core/Emulator/OperatingSystem/Dos.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -192,9 +192,10 @@ public Dos(Configuration configuration, IMemory memory,
192192
DosSysVars = new DosSysVars(configuration, (NullDevice)dosDevices[0], memory,
193193
MemoryUtils.ToPhysicalAddress(DosSysVars.Segment, 0x0));
194194

195-
DosSysVars.ConsoleDeviceHeaderPointer = ((IVirtualDevice)dosDevices[1]).Header.BaseAddress;
195+
// Item 1 of devices array
196+
DosSysVars.ConsoleDeviceHeaderPointer = new SegmentedAddress(MemoryMap.DeviceDriversSegment, (ushort)(1 * DosDeviceHeader.HeaderLength));
196197
SegmentedAddress cdsAddress = DosTables.CdsSegmentedAddress;
197-
DosSysVars.CurrentDirectoryStructureListPointer = (uint)(cdsAddress.Segment << 16 | cdsAddress.Offset);
198+
DosSysVars.CurrentDirectoryStructureListPointer = cdsAddress;
198199
DosSysVars.CurrentDirectoryStructureCount = 26;
199200

200201
DosSwappableDataArea = new(_memory,

src/Spice86.Core/Emulator/OperatingSystem/DosProcessManager.cs

Lines changed: 34 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -268,26 +268,26 @@ public DosProgramSegmentPrefix CreateRootCommandComPsp() {
268268

269269
// Root PSP: parent points to itself
270270
rootPsp.ParentProgramSegmentPrefix = CommandComSegment;
271-
rootPsp.PreviousPspAddress = MemoryUtils.To32BitAddress(SentinelSegment, SentinelOffset);
271+
rootPsp.PreviousPspAddress = new SegmentedAddress(SentinelSegment, SentinelOffset);
272272

273273
rootPsp.FarCall = FarCallOpcode;
274-
rootPsp.CpmServiceRequestAddress = MemoryUtils.To32BitAddress(CommandComSegment, Call5StubOffset);
274+
rootPsp.CpmServiceRequestAddress = new SegmentedAddress(CommandComSegment, Call5StubOffset);
275275
rootPsp.Service[0] = IntOpcode;
276276
rootPsp.Service[1] = Int21Number;
277277
rootPsp.Service[2] = RetfOpcode;
278278

279279
// Initialize interrupt vectors from IVT so child PSPs inherit proper addresses
280280
SegmentedAddress int22 = _interruptVectorTable[TerminateVectorNumber];
281-
rootPsp.TerminateAddress = MemoryUtils.To32BitAddress(int22.Segment, int22.Offset);
281+
rootPsp.TerminateAddress = int22;
282282

283283
SegmentedAddress int23 = _interruptVectorTable[CtrlBreakVectorNumber];
284-
rootPsp.BreakAddress = MemoryUtils.To32BitAddress(int23.Segment, int23.Offset);
284+
rootPsp.BreakAddress = int23;
285285

286286
SegmentedAddress int24 = _interruptVectorTable[CriticalErrorVectorNumber];
287-
rootPsp.CriticalErrorAddress = MemoryUtils.To32BitAddress(int24.Segment, int24.Offset);
287+
rootPsp.CriticalErrorAddress = int24;
288288

289289
rootPsp.MaximumOpenFiles = DosFileManager.MaxOpenFilesPerProcess;
290-
rootPsp.FileTableAddress = MemoryUtils.To32BitAddress(CommandComSegment, FileTableOffset);
290+
rootPsp.FileTableAddress = new SegmentedAddress(CommandComSegment, FileTableOffset);
291291

292292
rootPsp.DosVersionMajor = DefaultDosVersionMajor;
293293
rootPsp.DosVersionMinor = DefaultDosVersionMinor;
@@ -434,7 +434,7 @@ private DosExecResult HandleExeFileLoading(DosExecParameterBlock paramBlock,
434434
// FreeDOS: parent PSP's ps_stack field stores the parent's current iregs frame (only for LoadAndExecute).
435435
if (loadType == DosExecLoadType.LoadAndExecute) {
436436
DosProgramSegmentPrefix parentPsp = new(_memory, MemoryUtils.ToPhysicalAddress(parentPspSegment, 0));
437-
parentPsp.StackPointer = MemoryUtils.To32BitAddress(parentSS, parentReservedSP);
437+
parentPsp.StackPointer = new SegmentedAddress(parentSS, parentReservedSP);
438438
}
439439
CopyFcbFromPointer(paramBlock.FirstFcbPointer, exePsp.FirstFileControlBlock);
440440
CopyFcbFromPointer(paramBlock.SecondFcbPointer, exePsp.SecondFileControlBlock);
@@ -492,7 +492,7 @@ private DosExecResult HandleComFileLoading(DosExecParameterBlock paramBlock,
492492
// FreeDOS: parent PSP's ps_stack field stores the parent's current iregs frame (only for LoadAndExecute).
493493
if (loadType == DosExecLoadType.LoadAndExecute) {
494494
DosProgramSegmentPrefix parentPspForCom = new(_memory, MemoryUtils.ToPhysicalAddress(parentPspSegment, 0));
495-
parentPspForCom.StackPointer = MemoryUtils.To32BitAddress(parentSS, parentReservedSP);
495+
parentPspForCom.StackPointer = new SegmentedAddress(parentSS, parentReservedSP);
496496
}
497497
CopyFcbFromPointer(paramBlock.FirstFcbPointer, comPsp.FirstFileControlBlock);
498498
CopyFcbFromPointer(paramBlock.SecondFcbPointer, comPsp.SecondFileControlBlock);
@@ -647,9 +647,9 @@ public void TerminateProcess(byte exitCode, DosTerminationType terminationType)
647647
}
648648

649649
// Get interrupt vectors from current PSP before PopCurrentPspSegment call
650-
uint terminateAddr = currentPsp.TerminateAddress;
651-
uint breakAddr = currentPsp.BreakAddress;
652-
uint criticalErrorAddr = currentPsp.CriticalErrorAddress;
650+
SegmentedAddress terminateAddr = currentPsp.TerminateAddress;
651+
SegmentedAddress breakAddr = currentPsp.BreakAddress;
652+
SegmentedAddress criticalErrorAddr = currentPsp.CriticalErrorAddress;
653653
// Restore interrupt vectors from those values
654654
RestoreInterruptVector(TerminateVectorNumber, terminateAddr);
655655
RestoreInterruptVector(CtrlBreakVectorNumber, breakAddr);
@@ -666,12 +666,12 @@ public void TerminateProcess(byte exitCode, DosTerminationType terminationType)
666666
}
667667

668668
// FreeDOS return_user: restore SS:SP from parent's ps_stack, patch with child's ps_isv22.
669-
uint parentStackPtr = parentPsp.StackPointer;
670-
_state.SS = (ushort)(parentStackPtr >> 16);
671-
_state.SP = (ushort)(parentStackPtr & 0xFFFF);
669+
SegmentedAddress parentStackPtr = parentPsp.StackPointer;
670+
_state.SS = parentStackPtr.Segment;
671+
_state.SP = parentStackPtr.Offset;
672672
// Patch the iregs frame with child's TerminateAddress (INT 22h vector).
673-
_stack.Poke16(0, (ushort)(terminateAddr & 0xFFFF));
674-
_stack.Poke16(2, (ushort)(terminateAddr >> 16));
673+
_stack.Poke16(0, terminateAddr.Offset);
674+
_stack.Poke16(2, terminateAddr.Segment);
675675

676676
if (_loggerService.IsEnabled(LogEventLevel.Information)) {
677677
_loggerService.Information("TERMINATE: restored parent context SS:SP={0:X4}:{1:X4}, return CS:IP={2:X4}:{3:X4}",
@@ -748,14 +748,9 @@ public void CreateNewPsp(ushort newPspSegment) {
748748
newPsp.ParentProgramSegmentPrefix = currentPspSegment;
749749
newPsp.EnvironmentTableSegment = currentPsp.EnvironmentTableSegment;
750750

751-
SegmentedAddress int22 = _interruptVectorTable[TerminateVectorNumber];
752-
newPsp.TerminateAddress = MemoryUtils.To32BitAddress(int22.Segment, int22.Offset);
753-
754-
SegmentedAddress int23 = _interruptVectorTable[CtrlBreakVectorNumber];
755-
newPsp.BreakAddress = MemoryUtils.To32BitAddress(int23.Segment, int23.Offset);
756-
757-
SegmentedAddress int24 = _interruptVectorTable[CriticalErrorVectorNumber];
758-
newPsp.CriticalErrorAddress = MemoryUtils.To32BitAddress(int24.Segment, int24.Offset);
751+
newPsp.TerminateAddress = _interruptVectorTable[TerminateVectorNumber];
752+
newPsp.BreakAddress = _interruptVectorTable[CtrlBreakVectorNumber];
753+
newPsp.CriticalErrorAddress = _interruptVectorTable[CriticalErrorVectorNumber];
759754

760755
newPsp.DosVersionMajor = DefaultDosVersionMajor;
761756
newPsp.DosVersionMinor = DefaultDosVersionMinor;
@@ -780,14 +775,14 @@ public void CreateChildPsp(ushort childSegment, ushort sizeInParagraphs) {
780775

781776
// Parent/previous links.
782777
childPsp.ParentProgramSegmentPrefix = parentPspSegment;
783-
childPsp.PreviousPspAddress = MemoryUtils.To32BitAddress(parentPspSegment, 0);
778+
childPsp.PreviousPspAddress = new SegmentedAddress(parentPspSegment, 0);
784779

785780
// Size/next segment (ps_size in FreeDOS).
786781
childPsp.CurrentSize = sizeInParagraphs;
787782

788783
// File table layout and cloning (start unused then clone handles).
789784
childPsp.MaximumOpenFiles = DosFileManager.MaxOpenFilesPerProcess;
790-
childPsp.FileTableAddress = MemoryUtils.To32BitAddress(childSegment, FileTableOffset);
785+
childPsp.FileTableAddress = new SegmentedAddress(childSegment, FileTableOffset);
791786
for (int i = 0; i < JobFileTableLength; i++) {
792787
childPsp.Files[i] = UnusedFileHandle;
793788
}
@@ -806,29 +801,22 @@ public void CreateChildPsp(ushort childSegment, ushort sizeInParagraphs) {
806801

807802
// Keep INT 21h entry and CP/M far call consistent with FreeDOS child_psp.
808803
childPsp.FarCall = FarCallOpcode;
809-
childPsp.CpmServiceRequestAddress = MemoryUtils.To32BitAddress(childSegment, Call5StubOffset);
804+
childPsp.CpmServiceRequestAddress = new SegmentedAddress(childSegment, Call5StubOffset);
810805
childPsp.Service[0] = IntOpcode;
811806
childPsp.Service[1] = Int21Number;
812807
childPsp.Service[2] = RetfOpcode;
813808
}
814809

815-
private void RestoreInterruptVector(byte vectorNumber, uint storedFarPointer) {
816-
if (storedFarPointer != 0) {
817-
ushort offset = (ushort)(storedFarPointer & 0xFFFF);
818-
ushort segment = (ushort)(storedFarPointer >> 16);
819-
_interruptVectorTable[vectorNumber] = new SegmentedAddress(segment, offset);
810+
private void RestoreInterruptVector(byte vectorNumber, SegmentedAddress storedFarPointer) {
811+
if (storedFarPointer != SegmentedAddress.ZERO) {
812+
_interruptVectorTable[vectorNumber] = storedFarPointer;
820813
}
821814
}
822815

823816
private void SaveInterruptVectors(DosProgramSegmentPrefix psp) {
824-
SegmentedAddress int22 = _interruptVectorTable[TerminateVectorNumber];
825-
psp.TerminateAddress = MemoryUtils.To32BitAddress(int22.Segment, int22.Offset);
826-
827-
SegmentedAddress int23 = _interruptVectorTable[CtrlBreakVectorNumber];
828-
psp.BreakAddress = MemoryUtils.To32BitAddress(int23.Segment, int23.Offset);
829-
830-
SegmentedAddress int24 = _interruptVectorTable[CriticalErrorVectorNumber];
831-
psp.CriticalErrorAddress = MemoryUtils.To32BitAddress(int24.Segment, int24.Offset);
817+
psp.TerminateAddress = _interruptVectorTable[TerminateVectorNumber];
818+
psp.BreakAddress = _interruptVectorTable[CtrlBreakVectorNumber];
819+
psp.CriticalErrorAddress = _interruptVectorTable[CriticalErrorVectorNumber];
832820
}
833821

834822
private void CopyFileTableFromParent(DosProgramSegmentPrefix childPsp, DosProgramSegmentPrefix parentPsp) {
@@ -992,26 +980,24 @@ private void InitializePsp(ushort pspSegment, ushort blockSizeInParagraphs, stri
992980
psp.CurrentSize = (ushort)(pspSegment + blockSizeInParagraphs);
993981

994982
psp.FarCall = FarCallOpcode;
995-
psp.CpmServiceRequestAddress = MemoryUtils.To32BitAddress(pspSegment, Call5StubOffset);
983+
psp.CpmServiceRequestAddress = new SegmentedAddress(pspSegment, Call5StubOffset);
996984
psp.Service[0] = IntOpcode;
997985
psp.Service[1] = Int21Number;
998986
psp.Service[2] = RetfOpcode;
999987
psp.DosVersionMajor = DefaultDosVersionMajor;
1000988
psp.DosVersionMinor = DefaultDosVersionMinor;
1001989

1002990
// This sets INT 22h to point to the CALLER'S return address
1003-
psp.TerminateAddress = MemoryUtils.To32BitAddress(callerCS, callerIP);
991+
psp.TerminateAddress = new SegmentedAddress(callerCS, callerIP);
1004992

1005-
SegmentedAddress breakVector = _interruptVectorTable[CtrlBreakVectorNumber];
1006-
SegmentedAddress criticalErrorVector = _interruptVectorTable[CriticalErrorVectorNumber];
1007-
psp.BreakAddress = MemoryUtils.To32BitAddress(breakVector.Segment, breakVector.Offset);
1008-
psp.CriticalErrorAddress = MemoryUtils.To32BitAddress(criticalErrorVector.Segment, criticalErrorVector.Offset);
993+
psp.BreakAddress = _interruptVectorTable[CtrlBreakVectorNumber];
994+
psp.CriticalErrorAddress = _interruptVectorTable[CriticalErrorVectorNumber];
1009995

1010996
psp.ParentProgramSegmentPrefix = parentPspSegment;
1011997
psp.MaximumOpenFiles = DosFileManager.MaxOpenFilesPerProcess;
1012998
// file table address points to file table at offset FileTableOffset inside this PSP
1013-
psp.FileTableAddress = MemoryUtils.To32BitAddress(pspSegment, FileTableOffset);
1014-
psp.PreviousPspAddress = MemoryUtils.To32BitAddress(parentPspSegment, 0);
999+
psp.FileTableAddress = new SegmentedAddress(pspSegment, FileTableOffset);
1000+
psp.PreviousPspAddress = new SegmentedAddress(parentPspSegment, 0);
10151001

10161002
for (int i = 0; i < psp.Files.Count; i++) {
10171003
psp.Files[i] = (byte)Enums.DosPspFileTableEntry.Unused;

src/Spice86.Core/Emulator/OperatingSystem/Structures/DosProgramSegmentPrefix.cs

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
using Spice86.Core.Emulator.Memory.ReaderWriter;
44
using Spice86.Core.Emulator.ReverseEngineer.DataStructure;
55
using Spice86.Core.Emulator.ReverseEngineer.DataStructure.Array;
6+
using Spice86.Shared.Emulator.Memory;
67

78
using System.Diagnostics;
89

@@ -51,22 +52,22 @@ public DosProgramSegmentPrefix(IByteReaderWriter byteReaderWriter, uint baseAddr
5152
/// </summary>
5253
public byte FarCall { get => UInt8[0x5]; set => UInt8[0x5] = value; }
5354

54-
public uint CpmServiceRequestAddress { get => UInt32[0x6]; set => UInt32[0x6] = value; }
55+
public SegmentedAddress CpmServiceRequestAddress { get => SegmentedAddress16[0x6]; set => SegmentedAddress16[0x6] = value; }
5556

5657
/// <summary>
5758
/// On exit, DOS copies this to the INT 0x22 vector.
5859
/// </summary>
59-
public uint TerminateAddress { get => UInt32[0x0A]; set => UInt32[0x0A] = value; }
60+
public SegmentedAddress TerminateAddress { get => SegmentedAddress16[0x0A]; set => SegmentedAddress16[0x0A] = value; }
6061

6162
/// <summary>
6263
/// On exit, DOS copies this to the INT 0x23 vector.
6364
/// </summary>
64-
public uint BreakAddress { get => UInt32[0x0E]; set => UInt32[0x0E] = value; }
65+
public SegmentedAddress BreakAddress { get => SegmentedAddress16[0x0E]; set => SegmentedAddress16[0x0E] = value; }
6566

6667
/// <summary>
6768
/// On exit, DOS copies this to the INT 0x24 vector.
6869
/// </summary>
69-
public uint CriticalErrorAddress { get => UInt32[0x12]; set => UInt32[0x12] = value; }
70+
public SegmentedAddress CriticalErrorAddress { get => SegmentedAddress16[0x12]; set => SegmentedAddress16[0x12] = value; }
7071

7172
/// <summary>
7273
/// Segment of PSP of parent program.
@@ -77,13 +78,13 @@ public DosProgramSegmentPrefix(IByteReaderWriter byteReaderWriter, uint baseAddr
7778

7879
public ushort EnvironmentTableSegment { get => UInt16[0x2C]; set => UInt16[0x2C] = value; }
7980

80-
public uint StackPointer { get => UInt32[0x2E]; set => UInt32[0x2E] = value; }
81+
public SegmentedAddress StackPointer { get => SegmentedAddress16[0x2E]; set => SegmentedAddress16[0x2E] = value; }
8182

8283
public ushort MaximumOpenFiles { get => UInt16[0x32]; set => UInt16[0x32] = value; }
8384

84-
public uint FileTableAddress { get => UInt32[0x34]; set => UInt32[0x34] = value; }
85+
public SegmentedAddress FileTableAddress { get => SegmentedAddress16[0x34]; set => SegmentedAddress16[0x34] = value; }
8586

86-
public uint PreviousPspAddress { get => UInt32[0x38]; set => UInt32[0x38] = value; }
87+
public SegmentedAddress PreviousPspAddress { get => SegmentedAddress16[0x38]; set => SegmentedAddress16[0x38] = value; }
8788

8889
public byte InterimFlag { get => UInt8[0x3C]; set => UInt8[0x3C] = value; }
8990

src/Spice86.Core/Emulator/OperatingSystem/Structures/DosSwappableDataArea.cs

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
using Spice86.Core.Emulator.Memory.ReaderWriter;
44
using Spice86.Core.Emulator.ReverseEngineer.DataStructure;
5+
using Spice86.Shared.Emulator.Memory;
56

67
/// <summary>
78
/// Represents a DOS SDA (Swappable Data Area) in emulated memory.
@@ -71,17 +72,17 @@ public byte ErrorClass {
7172
/// <summary>
7273
/// Gets or sets the ES:DI pointer for the last error.
7374
/// </summary>
74-
public uint LastErrorPointer {
75-
get => UInt32[0x8];
76-
set => UInt32[0x8] = value;
75+
public SegmentedAddress LastErrorPointer {
76+
get => SegmentedAddress16[0x8];
77+
set => SegmentedAddress16[0x8] = value;
7778
}
7879

7980
/// <summary>
8081
/// Gets or sets the current DTA (Disk Transfer Area).
8182
/// </summary>
82-
public uint CurrentDiskTransferArea {
83-
get => UInt32[0xC];
84-
set => UInt32[0xC] = value;
83+
public SegmentedAddress CurrentDiskTransferArea {
84+
get => SegmentedAddress16[0xC];
85+
set => SegmentedAddress16[0xC] = value;
8586
}
8687

8788
/// <summary>

0 commit comments

Comments
 (0)