Fix bugs in video memory access emulation.
Implement several missing INT 10h functions.
Resize the console screen buffer on startup.


svn path=/branches/ntvdm/; revision=59421
This commit is contained in:
Aleksandar Andrejevic 2013-07-03 23:38:51 +00:00
parent c4ef9b6f44
commit 988c4490a8
5 changed files with 109 additions and 49 deletions

View file

@ -16,8 +16,6 @@
/* PRIVATE VARIABLES **********************************************************/ /* PRIVATE VARIABLES **********************************************************/
static BYTE CursorRow, CursorCol;
static WORD ConsoleWidth, ConsoleHeight;
static BYTE BiosKeyboardMap[256]; static BYTE BiosKeyboardMap[256];
static WORD BiosKbdBuffer[BIOS_KBD_BUFFER_SIZE]; static WORD BiosKbdBuffer[BIOS_KBD_BUFFER_SIZE];
static UINT BiosKbdBufferStart = 0, BiosKbdBufferEnd = 0; static UINT BiosKbdBufferStart = 0, BiosKbdBufferEnd = 0;
@ -30,17 +28,9 @@ static BOOLEAN BiosPassedMidnight = FALSE;
static COORD BiosVideoAddressToCoord(ULONG Address) static COORD BiosVideoAddressToCoord(ULONG Address)
{ {
COORD Result = {0, 0}; COORD Result = {0, 0};
CONSOLE_SCREEN_BUFFER_INFO ConsoleInfo;
HANDLE ConsoleOutput = GetStdHandle(STD_OUTPUT_HANDLE);
if (!GetConsoleScreenBufferInfo(ConsoleOutput, &ConsoleInfo)) Result.X = ((Address - CONSOLE_VIDEO_MEM_START) >> 1) % CONSOLE_WIDTH;
{ Result.Y = ((Address - CONSOLE_VIDEO_MEM_START) >> 1) / CONSOLE_WIDTH;
ASSERT(FALSE);
return Result;
}
Result.X = ((Address - CONSOLE_VIDEO_MEM_START) >> 1) % ConsoleInfo.dwSize.X;
Result.Y = ((Address - CONSOLE_VIDEO_MEM_START) >> 1) / ConsoleInfo.dwSize.X;
return Result; return Result;
} }
@ -92,9 +82,9 @@ BOOLEAN BiosInitialize()
{ {
INT i; INT i;
WORD Offset = 0; WORD Offset = 0;
COORD Size = { CONSOLE_WIDTH, CONSOLE_HEIGHT};
HANDLE ConsoleInput = GetStdHandle(STD_INPUT_HANDLE); HANDLE ConsoleInput = GetStdHandle(STD_INPUT_HANDLE);
HANDLE ConsoleOutput = GetStdHandle(STD_OUTPUT_HANDLE); HANDLE ConsoleOutput = GetStdHandle(STD_OUTPUT_HANDLE);
CONSOLE_SCREEN_BUFFER_INFO ConsoleInfo;
LPWORD IntVecTable = (LPWORD)((ULONG_PTR)BaseAddress); LPWORD IntVecTable = (LPWORD)((ULONG_PTR)BaseAddress);
LPBYTE BiosCode = (LPBYTE)((ULONG_PTR)BaseAddress + TO_LINEAR(BIOS_SEGMENT, 0)); LPBYTE BiosCode = (LPBYTE)((ULONG_PTR)BaseAddress + TO_LINEAR(BIOS_SEGMENT, 0));
@ -122,17 +112,8 @@ BOOLEAN BiosInitialize()
BiosCode[Offset++] = 0xCF; // iret BiosCode[Offset++] = 0xCF; // iret
} }
/* Get the console buffer info */ /* Set the console buffer size */
if (!GetConsoleScreenBufferInfo(ConsoleOutput, &ConsoleInfo)) if (!SetConsoleScreenBufferSize(ConsoleOutput, Size)) return FALSE;
{
return FALSE;
}
/* Set the initial cursor position and console size */
CursorCol = ConsoleInfo.dwCursorPosition.X;
CursorRow = ConsoleInfo.dwCursorPosition.Y;
ConsoleWidth = ConsoleInfo.dwSize.X;
ConsoleHeight = ConsoleInfo.dwSize.Y;
/* Set the console input mode */ /* Set the console input mode */
SetConsoleMode(ConsoleInput, ENABLE_MOUSE_INPUT | ENABLE_PROCESSED_INPUT); SetConsoleMode(ConsoleInput, ENABLE_MOUSE_INPUT | ENABLE_PROCESSED_INPUT);
@ -168,34 +149,31 @@ VOID BiosUpdateConsole(ULONG StartAddress, ULONG EndAddress)
{ {
ULONG i; ULONG i;
COORD Coordinates; COORD Coordinates;
DWORD CharsWritten; COORD Origin = { 0, 0 };
COORD UnitSize = { 1, 1 };
CHAR_INFO Character;
SMALL_RECT Rect;
HANDLE ConsoleOutput = GetStdHandle(STD_OUTPUT_HANDLE); HANDLE ConsoleOutput = GetStdHandle(STD_OUTPUT_HANDLE);
/* Start from the character address */
StartAddress &= ~1;
/* Loop through all the addresses */ /* Loop through all the addresses */
for (i = StartAddress; i < EndAddress; i++) for (i = StartAddress; i < EndAddress; i += 2)
{ {
/* Get the coordinates */ /* Get the coordinates */
Coordinates = BiosVideoAddressToCoord(i); Coordinates = BiosVideoAddressToCoord(i);
/* Check if this is a character byte or an attribute byte */ /* Fill the rectangle structure */
if ((i - CONSOLE_VIDEO_MEM_START) % 2 == 0) Rect.Left = Coordinates.X;
{ Rect.Top = Coordinates.Y;
/* This is a regular character */
FillConsoleOutputCharacterA(ConsoleOutput, /* Fill the character data */
*(PCHAR)((ULONG_PTR)BaseAddress + i), Character.Char.AsciiChar = *((PCHAR)((ULONG_PTR)BaseAddress + i));
sizeof(CHAR), Character.Attributes = *((PBYTE)((ULONG_PTR)BaseAddress + i + 1));
Coordinates,
&CharsWritten); /* Write the character */
} WriteConsoleOutputA(ConsoleOutput, &Character, UnitSize, Origin, &Rect);
else
{
/* This is an attribute */
FillConsoleOutputAttribute(ConsoleOutput,
*(PCHAR)((ULONG_PTR)BaseAddress + i),
sizeof(CHAR),
Coordinates,
&CharsWritten);
}
} }
} }
@ -294,6 +272,7 @@ VOID BiosVideoService()
BOOLEAN Invisible = FALSE; BOOLEAN Invisible = FALSE;
COORD Position; COORD Position;
CONSOLE_CURSOR_INFO CursorInfo; CONSOLE_CURSOR_INFO CursorInfo;
CONSOLE_SCREEN_BUFFER_INFO ScreenBufferInfo;
CHAR_INFO Character; CHAR_INFO Character;
SMALL_RECT Rect; SMALL_RECT Rect;
DWORD Eax = EmulatorGetRegister(EMULATOR_REG_AX); DWORD Eax = EmulatorGetRegister(EMULATOR_REG_AX);
@ -330,6 +309,27 @@ VOID BiosVideoService()
break; break;
} }
/* Get Cursor Position */
case 0x03:
{
INT StartLine;
/* Retrieve the data */
GetConsoleCursorInfo(ConsoleOutput, &CursorInfo);
GetConsoleScreenBufferInfo(ConsoleOutput, &ScreenBufferInfo);
/* Find the first line */
StartLine = 32 - ((CursorInfo.dwSize * 32) / 100);
/* Return the result */
EmulatorSetRegister(EMULATOR_REG_AX, 0);
EmulatorSetRegister(EMULATOR_REG_CX, (StartLine << 8) | 0x1F);
EmulatorSetRegister(EMULATOR_REG_DX,
LOWORD(ScreenBufferInfo.dwCursorPosition.Y) << 8
|| LOWORD(ScreenBufferInfo.dwCursorPosition.X));
break;
}
/* Scroll Up/Down Window */ /* Scroll Up/Down Window */
case 0x06: case 0x06:
case 0x07: case 0x07:
@ -355,18 +355,75 @@ VOID BiosVideoService()
/* Read Character And Attribute At Cursor Position */ /* Read Character And Attribute At Cursor Position */
case 0x08: case 0x08:
{ {
COORD BufferSize = { 1, 1 }, Origin = { 0, 0 };
/* Get the cursor position */
GetConsoleScreenBufferInfo(ConsoleOutput, &ScreenBufferInfo);
/* Read at cursor position */
Rect.Left = ScreenBufferInfo.dwCursorPosition.X;
Rect.Top = ScreenBufferInfo.dwCursorPosition.Y;
/* Read the console output */
ReadConsoleOutput(ConsoleOutput, &Character, BufferSize, Origin, &Rect);
/* Return the result */
EmulatorSetRegister(EMULATOR_REG_AX,
(LOBYTE(Character.Attributes) << 8)
| Character.Char.AsciiChar);
break; break;
} }
/* Write Character And Attribute At Cursor Position */ /* Write Character And Attribute At Cursor Position */
case 0x09: case 0x09:
{ {
DWORD CharsWritten;
/* Get the cursor position */
GetConsoleScreenBufferInfo(ConsoleOutput, &ScreenBufferInfo);
/* Write the attribute to the output */
FillConsoleOutputAttribute(ConsoleOutput,
LOBYTE(Ebx),
LOWORD(Ecx),
ScreenBufferInfo.dwCursorPosition,
&CharsWritten);
/* Write the character to the output */
FillConsoleOutputCharacterA(ConsoleOutput,
LOBYTE(Eax),
LOWORD(Ecx),
ScreenBufferInfo.dwCursorPosition,
&CharsWritten);
break; break;
} }
/* Write Character Only At Cursor Position */ /* Write Character Only At Cursor Position */
case 0x0A: case 0x0A:
{ {
DWORD CharsWritten;
/* Get the cursor position */
GetConsoleScreenBufferInfo(ConsoleOutput, &ScreenBufferInfo);
/* Write the character to the output */
FillConsoleOutputCharacterA(ConsoleOutput,
LOBYTE(Eax),
LOWORD(Ecx),
ScreenBufferInfo.dwCursorPosition,
&CharsWritten);
break;
}
case 0x0F:
{
/* Return just text mode information, for now */
EmulatorSetRegister(EMULATOR_REG_AX, 0x5003);
EmulatorSetRegister(EMULATOR_REG_BX, 0x0000);
break; break;
} }

View file

@ -26,6 +26,8 @@
#define BIOS_EQUIPMENT_INTERRUPT 0x11 #define BIOS_EQUIPMENT_INTERRUPT 0x11
#define BIOS_KBD_INTERRUPT 0x16 #define BIOS_KBD_INTERRUPT 0x16
#define BIOS_TIME_INTERRUPT 0x1A #define BIOS_TIME_INTERRUPT 0x1A
#define CONSOLE_WIDTH 80
#define CONSOLE_HEIGHT 25
#define CONSOLE_FONT_HEIGHT 8 #define CONSOLE_FONT_HEIGHT 8
#define BIOS_KBD_BUFFER_SIZE 256 #define BIOS_KBD_BUFFER_SIZE 256
#define BIOS_EQUIPMENT_LIST 0x3C // HACK: Disable FPU for now #define BIOS_EQUIPMENT_LIST 0x3C // HACK: Disable FPU for now

View file

@ -943,6 +943,7 @@ VOID DosInt21h(WORD CodeSegment)
} }
/* Read Character Without Echo */ /* Read Character Without Echo */
case 0x07:
case 0x08: case 0x08:
{ {
EmulatorSetRegister(EMULATOR_REG_AX, EmulatorSetRegister(EMULATOR_REG_AX,

View file

@ -36,8 +36,8 @@ static VOID EmulatorReadMemory(PVOID Context, UINT Address, LPBYTE Buffer, INT S
&& (Address < CONSOLE_VIDEO_MEM_END)) && (Address < CONSOLE_VIDEO_MEM_END))
{ {
/* Call the VDM BIOS to update the video memory */ /* Call the VDM BIOS to update the video memory */
BiosUpdateConsole(max(Address, CONSOLE_VIDEO_MEM_START), BiosUpdateVideoMemory(max(Address, CONSOLE_VIDEO_MEM_START),
min(Address + Size, CONSOLE_VIDEO_MEM_END)); min(Address + Size, CONSOLE_VIDEO_MEM_END));
} }
/* Read the data from the virtual address space and store it in the buffer */ /* Read the data from the virtual address space and store it in the buffer */

View file

@ -47,7 +47,7 @@ enum
EMULATOR_EXCEPTION_NO_FPU EMULATOR_EXCEPTION_NO_FPU
}; };
typedef enum enum
{ {
EMULATOR_REG_AX, EMULATOR_REG_AX,
EMULATOR_REG_CX, EMULATOR_REG_CX,
@ -61,7 +61,7 @@ typedef enum
EMULATOR_REG_CS, EMULATOR_REG_CS,
EMULATOR_REG_SS, EMULATOR_REG_SS,
EMULATOR_REG_DS, EMULATOR_REG_DS,
} EMULATOR_REGISTER; };
/* FUNCTIONS ******************************************************************/ /* FUNCTIONS ******************************************************************/