mirror of
https://github.com/reactos/reactos.git
synced 2024-09-06 02:37:06 +00:00
[NTVDM]
Implement BIOS video mode setting. Fix bugs in video memory access emulation. svn path=/branches/ntvdm/; revision=59424
This commit is contained in:
parent
988c4490a8
commit
01fd2f9aa3
|
@ -22,6 +22,35 @@ static UINT BiosKbdBufferStart = 0, BiosKbdBufferEnd = 0;
|
||||||
static BOOLEAN BiosKbdBufferEmpty = TRUE;
|
static BOOLEAN BiosKbdBufferEmpty = TRUE;
|
||||||
static DWORD BiosTickCount = 0;
|
static DWORD BiosTickCount = 0;
|
||||||
static BOOLEAN BiosPassedMidnight = FALSE;
|
static BOOLEAN BiosPassedMidnight = FALSE;
|
||||||
|
static HANDLE BiosConsoleInput, BiosConsoleOutput;
|
||||||
|
static BYTE CurrentVideoMode = BIOS_DEFAULT_VIDEO_MODE;
|
||||||
|
static BYTE CurrentVideoPage = 0;
|
||||||
|
static HANDLE ConsoleBuffers[BIOS_MAX_PAGES] = { NULL };
|
||||||
|
static LPVOID ConsoleFramebuffers[BIOS_MAX_PAGES] = { NULL };
|
||||||
|
static VIDEO_MODE VideoModes[] =
|
||||||
|
{
|
||||||
|
/* Width | Height | Text | Colors | Gray | Pages | Segment */
|
||||||
|
{ 40, 25, TRUE, 16, TRUE, 8, 0xB800}, /* Mode 00h */
|
||||||
|
{ 40, 25, TRUE, 16, FALSE, 8, 0xB800}, /* Mode 01h */
|
||||||
|
{ 80, 25, TRUE, 16, TRUE, 8, 0xB800}, /* Mode 02h */
|
||||||
|
{ 80, 25, TRUE, 16, FALSE, 8, 0xB800}, /* Mode 03h */
|
||||||
|
{ 320, 200, FALSE, 4, FALSE, 4, 0xB800}, /* Mode 04h */
|
||||||
|
{ 320, 200, FALSE, 4, TRUE, 4, 0xB800}, /* Mode 05h */
|
||||||
|
{ 640, 200, FALSE, 2, FALSE, 2, 0xB800}, /* Mode 06h */
|
||||||
|
{ 80, 25, TRUE, 3, FALSE, 1, 0xB000}, /* Mode 07h */
|
||||||
|
{ 0, 0, FALSE, 0, FALSE, 0, 0x0000}, /* Mode 08h - not used */
|
||||||
|
{ 0, 0, FALSE, 0, FALSE, 0, 0x0000}, /* Mode 09h - not used */
|
||||||
|
{ 0, 0, FALSE, 0, FALSE, 0, 0x0000}, /* Mode 0Ah - not used */
|
||||||
|
{ 0, 0, FALSE, 0, FALSE, 0, 0x0000}, /* Mode 0Bh - not used */
|
||||||
|
{ 0, 0, FALSE, 0, FALSE, 0, 0x0000}, /* Mode 0Ch - not used */
|
||||||
|
{ 320, 200, FALSE, 16, FALSE, 8, 0xA000}, /* Mode 0Dh */
|
||||||
|
{ 640, 200, FALSE, 16, FALSE, 4, 0xA000}, /* Mode 0Eh */
|
||||||
|
{ 640, 350, FALSE, 3, FALSE, 2, 0xA000}, /* Mode 0Fh */
|
||||||
|
{ 640, 350, FALSE, 4, FALSE, 2, 0xA000}, /* Mode 10h */
|
||||||
|
{ 640, 480, FALSE, 2, FALSE, 1, 0xA000}, /* Mode 11h */
|
||||||
|
{ 640, 480, FALSE, 16, FALSE, 1, 0xA000}, /* Mode 12h */
|
||||||
|
{ 640, 480, FALSE, 256, FALSE, 1, 0xA000} /* Mode 13h */
|
||||||
|
};
|
||||||
|
|
||||||
/* PRIVATE FUNCTIONS **********************************************************/
|
/* PRIVATE FUNCTIONS **********************************************************/
|
||||||
|
|
||||||
|
@ -29,8 +58,10 @@ static COORD BiosVideoAddressToCoord(ULONG Address)
|
||||||
{
|
{
|
||||||
COORD Result = {0, 0};
|
COORD Result = {0, 0};
|
||||||
|
|
||||||
Result.X = ((Address - CONSOLE_VIDEO_MEM_START) >> 1) % CONSOLE_WIDTH;
|
Result.X = ((Address - (VideoModes[CurrentVideoMode].Segment << 4)) >> 1)
|
||||||
Result.Y = ((Address - CONSOLE_VIDEO_MEM_START) >> 1) / CONSOLE_WIDTH;
|
% VideoModes[CurrentVideoMode].Width;
|
||||||
|
Result.Y = ((Address - (VideoModes[CurrentVideoMode].Segment << 4)) >> 1)
|
||||||
|
/ VideoModes[CurrentVideoMode].Width;
|
||||||
|
|
||||||
return Result;
|
return Result;
|
||||||
}
|
}
|
||||||
|
@ -78,13 +109,160 @@ static BOOLEAN BiosKbdBufferPop()
|
||||||
|
|
||||||
/* PUBLIC FUNCTIONS ***********************************************************/
|
/* PUBLIC FUNCTIONS ***********************************************************/
|
||||||
|
|
||||||
BOOLEAN BiosInitialize()
|
BYTE BiosGetVideoMode()
|
||||||
|
{
|
||||||
|
return CurrentVideoMode;
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOLEAN BiosSetVideoMode(BYTE ModeNumber)
|
||||||
|
{
|
||||||
|
INT i;
|
||||||
|
COORD Coord;
|
||||||
|
CONSOLE_GRAPHICS_BUFFER_INFO GraphicsBufferInfo;
|
||||||
|
LPBITMAPINFO BitmapInfo;
|
||||||
|
LPWORD PaletteIndex;
|
||||||
|
|
||||||
|
/* Make sure this is a valid video mode */
|
||||||
|
if (ModeNumber > BIOS_MAX_VIDEO_MODE) return FALSE;
|
||||||
|
if (VideoModes[ModeNumber].Pages == 0) return FALSE;
|
||||||
|
|
||||||
|
/* Free the current buffers */
|
||||||
|
for (i = 0; i < VideoModes[CurrentVideoMode].Pages; i++)
|
||||||
|
{
|
||||||
|
if (ConsoleBuffers[i] != NULL) CloseHandle(ConsoleBuffers[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (VideoModes[ModeNumber].Text)
|
||||||
|
{
|
||||||
|
/* Page 0 is CONOUT$ */
|
||||||
|
ConsoleBuffers[0] = CreateFile(TEXT("CONOUT$"),
|
||||||
|
GENERIC_READ | GENERIC_WRITE,
|
||||||
|
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
||||||
|
NULL,
|
||||||
|
OPEN_EXISTING,
|
||||||
|
0,
|
||||||
|
NULL);
|
||||||
|
|
||||||
|
/* Set the current page to page 0 */
|
||||||
|
CurrentVideoPage = 0;
|
||||||
|
|
||||||
|
/* Create console buffers for other pages */
|
||||||
|
for (i = 1; i < VideoModes[ModeNumber].Pages; i++)
|
||||||
|
{
|
||||||
|
ConsoleBuffers[i] = CreateConsoleScreenBuffer(GENERIC_READ | GENERIC_WRITE,
|
||||||
|
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
||||||
|
NULL,
|
||||||
|
CONSOLE_TEXTMODE_BUFFER,
|
||||||
|
NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set the size for the buffers */
|
||||||
|
for (i = 0; i < VideoModes[ModeNumber].Pages; i++)
|
||||||
|
{
|
||||||
|
Coord.X = VideoModes[ModeNumber].Width;
|
||||||
|
Coord.Y = VideoModes[ModeNumber].Height;
|
||||||
|
|
||||||
|
SetConsoleScreenBufferSize(ConsoleBuffers[i], Coord);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Allocate a bitmap info structure */
|
||||||
|
BitmapInfo = (LPBITMAPINFO)HeapAlloc(GetProcessHeap(),
|
||||||
|
HEAP_ZERO_MEMORY,
|
||||||
|
sizeof(BITMAPINFOHEADER)
|
||||||
|
+ VideoModes[ModeNumber].Colors
|
||||||
|
* sizeof(WORD));
|
||||||
|
if (BitmapInfo == NULL) return FALSE;
|
||||||
|
|
||||||
|
/* Fill the bitmap info header */
|
||||||
|
ZeroMemory(&BitmapInfo->bmiHeader, sizeof(BITMAPINFOHEADER));
|
||||||
|
BitmapInfo->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
|
||||||
|
BitmapInfo->bmiHeader.biWidth = VideoModes[ModeNumber].Width;
|
||||||
|
BitmapInfo->bmiHeader.biHeight = VideoModes[ModeNumber].Height;
|
||||||
|
BitmapInfo->bmiHeader.biPlanes = 1;
|
||||||
|
BitmapInfo->bmiHeader.biCompression = BI_RGB;
|
||||||
|
|
||||||
|
/* Calculate the number of color bits */
|
||||||
|
for (i = 31; i >= 0; i--)
|
||||||
|
{
|
||||||
|
if (VideoModes[ModeNumber].Colors & (1 << i)) break;
|
||||||
|
}
|
||||||
|
if (i == 0) i = 32;
|
||||||
|
BitmapInfo->bmiHeader.biBitCount = i;
|
||||||
|
|
||||||
|
/* Calculate the image size */
|
||||||
|
BitmapInfo->bmiHeader.biSizeImage = BitmapInfo->bmiHeader.biWidth
|
||||||
|
* BitmapInfo->bmiHeader.biHeight
|
||||||
|
* (BitmapInfo->bmiHeader.biBitCount >> 3);
|
||||||
|
|
||||||
|
/* Fill the palette data */
|
||||||
|
PaletteIndex = (LPWORD)((ULONG_PTR)BitmapInfo + sizeof(BITMAPINFOHEADER));
|
||||||
|
for (i = 0; i < VideoModes[ModeNumber].Colors; i++)
|
||||||
|
{
|
||||||
|
PaletteIndex[i] = i;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Create a console buffer for each page */
|
||||||
|
for (i = 0; i < VideoModes[ModeNumber].Pages; i++)
|
||||||
|
{
|
||||||
|
/* Fill the console graphics buffer info */
|
||||||
|
GraphicsBufferInfo.dwBitMapInfoLength = sizeof(BITMAPINFOHEADER)
|
||||||
|
+ VideoModes[ModeNumber].Colors
|
||||||
|
* sizeof(WORD);
|
||||||
|
GraphicsBufferInfo.lpBitMapInfo = BitmapInfo;
|
||||||
|
GraphicsBufferInfo.dwUsage = DIB_PAL_COLORS;
|
||||||
|
|
||||||
|
/* Create the buffer */
|
||||||
|
ConsoleBuffers[i] = CreateConsoleScreenBuffer(GENERIC_READ | GENERIC_WRITE,
|
||||||
|
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
||||||
|
NULL,
|
||||||
|
CONSOLE_GRAPHICS_BUFFER,
|
||||||
|
&GraphicsBufferInfo);
|
||||||
|
|
||||||
|
/* Save the framebuffer address */
|
||||||
|
ConsoleFramebuffers[i] = GraphicsBufferInfo.lpBitMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Free the bitmap information */
|
||||||
|
HeapFree(GetProcessHeap(), 0, BitmapInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set the active page console buffer */
|
||||||
|
SetConsoleActiveScreenBuffer(ConsoleBuffers[CurrentVideoPage]);
|
||||||
|
|
||||||
|
/* Update the mode number */
|
||||||
|
CurrentVideoMode = ModeNumber;
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline DWORD BiosGetVideoMemoryStart()
|
||||||
|
{
|
||||||
|
return (VideoModes[CurrentVideoMode].Segment << 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline VOID BiosVerticalRefresh()
|
||||||
|
{
|
||||||
|
SMALL_RECT Region;
|
||||||
|
|
||||||
|
/* Ignore if we're in text mode */
|
||||||
|
if (VideoModes[CurrentVideoMode].Text) return;
|
||||||
|
|
||||||
|
/* Fill the rectangle structure */
|
||||||
|
Region.Left = Region.Top = 0;
|
||||||
|
Region.Right = VideoModes[CurrentVideoMode].Width;
|
||||||
|
Region.Bottom = VideoModes[CurrentVideoMode].Height;
|
||||||
|
|
||||||
|
/* Redraw the screen */
|
||||||
|
InvalidateConsoleDIBits(ConsoleBuffers[CurrentVideoPage],
|
||||||
|
&Region);
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOLEAN BiosInitialize(HANDLE ConsoleInput, HANDLE ConsoleOutput)
|
||||||
{
|
{
|
||||||
INT i;
|
INT i;
|
||||||
WORD Offset = 0;
|
WORD Offset = 0;
|
||||||
COORD Size = { CONSOLE_WIDTH, CONSOLE_HEIGHT};
|
|
||||||
HANDLE ConsoleInput = GetStdHandle(STD_INPUT_HANDLE);
|
|
||||||
HANDLE ConsoleOutput = GetStdHandle(STD_OUTPUT_HANDLE);
|
|
||||||
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));
|
||||||
|
|
||||||
|
@ -112,8 +290,12 @@ BOOLEAN BiosInitialize()
|
||||||
BiosCode[Offset++] = 0xCF; // iret
|
BiosCode[Offset++] = 0xCF; // iret
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Set the console buffer size */
|
/* Set global console I/O handles */
|
||||||
if (!SetConsoleScreenBufferSize(ConsoleOutput, Size)) return FALSE;
|
BiosConsoleInput = ConsoleInput;
|
||||||
|
BiosConsoleOutput = ConsoleOutput;
|
||||||
|
|
||||||
|
/* Set the default video mode */
|
||||||
|
BiosSetVideoMode(BIOS_DEFAULT_VIDEO_MODE);
|
||||||
|
|
||||||
/* 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);
|
||||||
|
@ -153,11 +335,12 @@ VOID BiosUpdateConsole(ULONG StartAddress, ULONG EndAddress)
|
||||||
COORD UnitSize = { 1, 1 };
|
COORD UnitSize = { 1, 1 };
|
||||||
CHAR_INFO Character;
|
CHAR_INFO Character;
|
||||||
SMALL_RECT Rect;
|
SMALL_RECT Rect;
|
||||||
HANDLE ConsoleOutput = GetStdHandle(STD_OUTPUT_HANDLE);
|
|
||||||
|
|
||||||
/* Start from the character address */
|
/* Start from the character address */
|
||||||
StartAddress &= ~1;
|
StartAddress &= ~1;
|
||||||
|
|
||||||
|
if (VideoModes[CurrentVideoMode].Text)
|
||||||
|
{
|
||||||
/* Loop through all the addresses */
|
/* Loop through all the addresses */
|
||||||
for (i = StartAddress; i < EndAddress; i += 2)
|
for (i = StartAddress; i < EndAddress; i += 2)
|
||||||
{
|
{
|
||||||
|
@ -167,13 +350,28 @@ VOID BiosUpdateConsole(ULONG StartAddress, ULONG EndAddress)
|
||||||
/* Fill the rectangle structure */
|
/* Fill the rectangle structure */
|
||||||
Rect.Left = Coordinates.X;
|
Rect.Left = Coordinates.X;
|
||||||
Rect.Top = Coordinates.Y;
|
Rect.Top = Coordinates.Y;
|
||||||
|
Rect.Right = Rect.Left;
|
||||||
|
Rect.Bottom = Rect.Top;
|
||||||
|
|
||||||
/* Fill the character data */
|
/* Fill the character data */
|
||||||
Character.Char.AsciiChar = *((PCHAR)((ULONG_PTR)BaseAddress + i));
|
Character.Char.AsciiChar = *((PCHAR)((ULONG_PTR)BaseAddress + i));
|
||||||
Character.Attributes = *((PBYTE)((ULONG_PTR)BaseAddress + i + 1));
|
Character.Attributes = *((PBYTE)((ULONG_PTR)BaseAddress + i + 1));
|
||||||
|
|
||||||
/* Write the character */
|
/* Write the character */
|
||||||
WriteConsoleOutputA(ConsoleOutput, &Character, UnitSize, Origin, &Rect);
|
WriteConsoleOutputA(BiosConsoleOutput,
|
||||||
|
&Character,
|
||||||
|
UnitSize,
|
||||||
|
Origin,
|
||||||
|
&Rect);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Copy the data to the framebuffer */
|
||||||
|
RtlCopyMemory((LPVOID)((ULONG_PTR)ConsoleFramebuffers[CurrentVideoPage]
|
||||||
|
+ StartAddress - BiosGetVideoMemoryStart()),
|
||||||
|
(LPVOID)((ULONG_PTR)BaseAddress + StartAddress),
|
||||||
|
EndAddress - StartAddress);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -183,8 +381,9 @@ VOID BiosUpdateVideoMemory(ULONG StartAddress, ULONG EndAddress)
|
||||||
COORD Coordinates;
|
COORD Coordinates;
|
||||||
WORD Attribute;
|
WORD Attribute;
|
||||||
DWORD CharsWritten;
|
DWORD CharsWritten;
|
||||||
HANDLE ConsoleOutput = GetStdHandle(STD_OUTPUT_HANDLE);
|
|
||||||
|
|
||||||
|
if (VideoModes[CurrentVideoMode].Text)
|
||||||
|
{
|
||||||
/* Loop through all the addresses */
|
/* Loop through all the addresses */
|
||||||
for (i = StartAddress; i < EndAddress; i++)
|
for (i = StartAddress; i < EndAddress; i++)
|
||||||
{
|
{
|
||||||
|
@ -192,10 +391,10 @@ VOID BiosUpdateVideoMemory(ULONG StartAddress, ULONG EndAddress)
|
||||||
Coordinates = BiosVideoAddressToCoord(i);
|
Coordinates = BiosVideoAddressToCoord(i);
|
||||||
|
|
||||||
/* Check if this is a character byte or an attribute byte */
|
/* Check if this is a character byte or an attribute byte */
|
||||||
if ((i - CONSOLE_VIDEO_MEM_START) % 2 == 0)
|
if ((i - (VideoModes[CurrentVideoMode].Segment << 4)) % 2 == 0)
|
||||||
{
|
{
|
||||||
/* This is a regular character */
|
/* This is a regular character */
|
||||||
ReadConsoleOutputCharacterA(ConsoleOutput,
|
ReadConsoleOutputCharacterA(BiosConsoleOutput,
|
||||||
(LPSTR)((ULONG_PTR)BaseAddress + i),
|
(LPSTR)((ULONG_PTR)BaseAddress + i),
|
||||||
sizeof(CHAR),
|
sizeof(CHAR),
|
||||||
Coordinates,
|
Coordinates,
|
||||||
|
@ -204,7 +403,7 @@ VOID BiosUpdateVideoMemory(ULONG StartAddress, ULONG EndAddress)
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* This is an attribute */
|
/* This is an attribute */
|
||||||
ReadConsoleOutputAttribute(ConsoleOutput,
|
ReadConsoleOutputAttribute(BiosConsoleOutput,
|
||||||
&Attribute,
|
&Attribute,
|
||||||
sizeof(CHAR),
|
sizeof(CHAR),
|
||||||
Coordinates,
|
Coordinates,
|
||||||
|
@ -213,6 +412,15 @@ VOID BiosUpdateVideoMemory(ULONG StartAddress, ULONG EndAddress)
|
||||||
*(PCHAR)((ULONG_PTR)BaseAddress + i) = LOBYTE(Attribute);
|
*(PCHAR)((ULONG_PTR)BaseAddress + i) = LOBYTE(Attribute);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Copy the data to the emulator memory */
|
||||||
|
RtlCopyMemory((LPVOID)((ULONG_PTR)BaseAddress + StartAddress),
|
||||||
|
(LPVOID)((ULONG_PTR)ConsoleFramebuffers[CurrentVideoPage]
|
||||||
|
+ StartAddress - BiosGetVideoMemoryStart()),
|
||||||
|
EndAddress - StartAddress);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
WORD BiosPeekCharacter()
|
WORD BiosPeekCharacter()
|
||||||
|
@ -231,7 +439,6 @@ WORD BiosPeekCharacter()
|
||||||
WORD BiosGetCharacter()
|
WORD BiosGetCharacter()
|
||||||
{
|
{
|
||||||
WORD CharacterData;
|
WORD CharacterData;
|
||||||
HANDLE ConsoleInput = GetStdHandle(STD_INPUT_HANDLE);
|
|
||||||
INPUT_RECORD InputRecord;
|
INPUT_RECORD InputRecord;
|
||||||
DWORD Count;
|
DWORD Count;
|
||||||
|
|
||||||
|
@ -247,10 +454,10 @@ WORD BiosGetCharacter()
|
||||||
while (TRUE)
|
while (TRUE)
|
||||||
{
|
{
|
||||||
/* Wait for a console event */
|
/* Wait for a console event */
|
||||||
WaitForSingleObject(ConsoleInput, INFINITE);
|
WaitForSingleObject(BiosConsoleInput, INFINITE);
|
||||||
|
|
||||||
/* Read the event, and make sure it's a keypress */
|
/* Read the event, and make sure it's a keypress */
|
||||||
if (!ReadConsoleInput(ConsoleInput, &InputRecord, 1, &Count)) continue;
|
if (!ReadConsoleInput(BiosConsoleInput, &InputRecord, 1, &Count)) continue;
|
||||||
if (InputRecord.EventType != KEY_EVENT) continue;
|
if (InputRecord.EventType != KEY_EVENT) continue;
|
||||||
if (!InputRecord.Event.KeyEvent.bKeyDown) continue;
|
if (!InputRecord.Event.KeyEvent.bKeyDown) continue;
|
||||||
|
|
||||||
|
@ -267,7 +474,6 @@ WORD BiosGetCharacter()
|
||||||
|
|
||||||
VOID BiosVideoService()
|
VOID BiosVideoService()
|
||||||
{
|
{
|
||||||
HANDLE ConsoleOutput = GetStdHandle(STD_OUTPUT_HANDLE);
|
|
||||||
INT CursorHeight;
|
INT CursorHeight;
|
||||||
BOOLEAN Invisible = FALSE;
|
BOOLEAN Invisible = FALSE;
|
||||||
COORD Position;
|
COORD Position;
|
||||||
|
@ -282,6 +488,13 @@ VOID BiosVideoService()
|
||||||
|
|
||||||
switch (HIBYTE(Eax))
|
switch (HIBYTE(Eax))
|
||||||
{
|
{
|
||||||
|
/* Set Video Mode */
|
||||||
|
case 0x00:
|
||||||
|
{
|
||||||
|
BiosSetVideoMode(LOBYTE(Eax));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
/* Set Text-Mode Cursor Shape */
|
/* Set Text-Mode Cursor Shape */
|
||||||
case 0x01:
|
case 0x01:
|
||||||
{
|
{
|
||||||
|
@ -294,7 +507,7 @@ VOID BiosVideoService()
|
||||||
/* Set the cursor */
|
/* Set the cursor */
|
||||||
CursorInfo.dwSize = (CursorHeight * 100) / CONSOLE_FONT_HEIGHT;
|
CursorInfo.dwSize = (CursorHeight * 100) / CONSOLE_FONT_HEIGHT;
|
||||||
CursorInfo.bVisible = !Invisible;
|
CursorInfo.bVisible = !Invisible;
|
||||||
SetConsoleCursorInfo(ConsoleOutput, &CursorInfo);
|
SetConsoleCursorInfo(BiosConsoleOutput, &CursorInfo);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -305,7 +518,7 @@ VOID BiosVideoService()
|
||||||
Position.X = LOBYTE(Edx);
|
Position.X = LOBYTE(Edx);
|
||||||
Position.Y = HIBYTE(Edx);
|
Position.Y = HIBYTE(Edx);
|
||||||
|
|
||||||
SetConsoleCursorPosition(ConsoleOutput, Position);
|
SetConsoleCursorPosition(BiosConsoleOutput, Position);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -315,8 +528,8 @@ VOID BiosVideoService()
|
||||||
INT StartLine;
|
INT StartLine;
|
||||||
|
|
||||||
/* Retrieve the data */
|
/* Retrieve the data */
|
||||||
GetConsoleCursorInfo(ConsoleOutput, &CursorInfo);
|
GetConsoleCursorInfo(BiosConsoleOutput, &CursorInfo);
|
||||||
GetConsoleScreenBufferInfo(ConsoleOutput, &ScreenBufferInfo);
|
GetConsoleScreenBufferInfo(BiosConsoleOutput, &ScreenBufferInfo);
|
||||||
|
|
||||||
/* Find the first line */
|
/* Find the first line */
|
||||||
StartLine = 32 - ((CursorInfo.dwSize * 32) / 100);
|
StartLine = 32 - ((CursorInfo.dwSize * 32) / 100);
|
||||||
|
@ -344,7 +557,7 @@ VOID BiosVideoService()
|
||||||
if (HIBYTE(Eax) == 0x06) Position.Y = Rect.Top - LOBYTE(Eax);
|
if (HIBYTE(Eax) == 0x06) Position.Y = Rect.Top - LOBYTE(Eax);
|
||||||
else Position.Y = Rect.Top + LOBYTE(Eax);
|
else Position.Y = Rect.Top + LOBYTE(Eax);
|
||||||
|
|
||||||
ScrollConsoleScreenBuffer(ConsoleOutput,
|
ScrollConsoleScreenBuffer(BiosConsoleOutput,
|
||||||
&Rect,
|
&Rect,
|
||||||
&Rect,
|
&Rect,
|
||||||
Position,
|
Position,
|
||||||
|
@ -358,14 +571,14 @@ VOID BiosVideoService()
|
||||||
COORD BufferSize = { 1, 1 }, Origin = { 0, 0 };
|
COORD BufferSize = { 1, 1 }, Origin = { 0, 0 };
|
||||||
|
|
||||||
/* Get the cursor position */
|
/* Get the cursor position */
|
||||||
GetConsoleScreenBufferInfo(ConsoleOutput, &ScreenBufferInfo);
|
GetConsoleScreenBufferInfo(BiosConsoleOutput, &ScreenBufferInfo);
|
||||||
|
|
||||||
/* Read at cursor position */
|
/* Read at cursor position */
|
||||||
Rect.Left = ScreenBufferInfo.dwCursorPosition.X;
|
Rect.Left = ScreenBufferInfo.dwCursorPosition.X;
|
||||||
Rect.Top = ScreenBufferInfo.dwCursorPosition.Y;
|
Rect.Top = ScreenBufferInfo.dwCursorPosition.Y;
|
||||||
|
|
||||||
/* Read the console output */
|
/* Read the console output */
|
||||||
ReadConsoleOutput(ConsoleOutput, &Character, BufferSize, Origin, &Rect);
|
ReadConsoleOutput(BiosConsoleOutput, &Character, BufferSize, Origin, &Rect);
|
||||||
|
|
||||||
/* Return the result */
|
/* Return the result */
|
||||||
EmulatorSetRegister(EMULATOR_REG_AX,
|
EmulatorSetRegister(EMULATOR_REG_AX,
|
||||||
|
@ -381,17 +594,17 @@ VOID BiosVideoService()
|
||||||
DWORD CharsWritten;
|
DWORD CharsWritten;
|
||||||
|
|
||||||
/* Get the cursor position */
|
/* Get the cursor position */
|
||||||
GetConsoleScreenBufferInfo(ConsoleOutput, &ScreenBufferInfo);
|
GetConsoleScreenBufferInfo(BiosConsoleOutput, &ScreenBufferInfo);
|
||||||
|
|
||||||
/* Write the attribute to the output */
|
/* Write the attribute to the output */
|
||||||
FillConsoleOutputAttribute(ConsoleOutput,
|
FillConsoleOutputAttribute(BiosConsoleOutput,
|
||||||
LOBYTE(Ebx),
|
LOBYTE(Ebx),
|
||||||
LOWORD(Ecx),
|
LOWORD(Ecx),
|
||||||
ScreenBufferInfo.dwCursorPosition,
|
ScreenBufferInfo.dwCursorPosition,
|
||||||
&CharsWritten);
|
&CharsWritten);
|
||||||
|
|
||||||
/* Write the character to the output */
|
/* Write the character to the output */
|
||||||
FillConsoleOutputCharacterA(ConsoleOutput,
|
FillConsoleOutputCharacterA(BiosConsoleOutput,
|
||||||
LOBYTE(Eax),
|
LOBYTE(Eax),
|
||||||
LOWORD(Ecx),
|
LOWORD(Ecx),
|
||||||
ScreenBufferInfo.dwCursorPosition,
|
ScreenBufferInfo.dwCursorPosition,
|
||||||
|
@ -406,10 +619,10 @@ VOID BiosVideoService()
|
||||||
DWORD CharsWritten;
|
DWORD CharsWritten;
|
||||||
|
|
||||||
/* Get the cursor position */
|
/* Get the cursor position */
|
||||||
GetConsoleScreenBufferInfo(ConsoleOutput, &ScreenBufferInfo);
|
GetConsoleScreenBufferInfo(BiosConsoleOutput, &ScreenBufferInfo);
|
||||||
|
|
||||||
/* Write the character to the output */
|
/* Write the character to the output */
|
||||||
FillConsoleOutputCharacterA(ConsoleOutput,
|
FillConsoleOutputCharacterA(BiosConsoleOutput,
|
||||||
LOBYTE(Eax),
|
LOBYTE(Eax),
|
||||||
LOWORD(Ecx),
|
LOWORD(Ecx),
|
||||||
ScreenBufferInfo.dwCursorPosition,
|
ScreenBufferInfo.dwCursorPosition,
|
||||||
|
@ -418,11 +631,14 @@ VOID BiosVideoService()
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Get Current Video Mode */
|
||||||
case 0x0F:
|
case 0x0F:
|
||||||
{
|
{
|
||||||
/* Return just text mode information, for now */
|
EmulatorSetRegister(EMULATOR_REG_AX,
|
||||||
EmulatorSetRegister(EMULATOR_REG_AX, 0x5003);
|
(VideoModes[CurrentVideoMode].Width << 8)
|
||||||
EmulatorSetRegister(EMULATOR_REG_BX, 0x0000);
|
| CurrentVideoMode);
|
||||||
|
EmulatorSetRegister(EMULATOR_REG_BX,
|
||||||
|
(CurrentVideoPage << 8) | LOBYTE(Ebx));
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,7 +15,6 @@
|
||||||
|
|
||||||
/* DEFINES ********************************************************************/
|
/* DEFINES ********************************************************************/
|
||||||
|
|
||||||
#define CONSOLE_VIDEO_MEM_START 0xB8000
|
|
||||||
#define CONSOLE_VIDEO_MEM_END 0xBFFFF
|
#define CONSOLE_VIDEO_MEM_END 0xBFFFF
|
||||||
#define ROM_AREA_START 0xC0000
|
#define ROM_AREA_START 0xC0000
|
||||||
#define ROM_AREA_END 0xFFFFF
|
#define ROM_AREA_END 0xFFFFF
|
||||||
|
@ -26,17 +25,31 @@
|
||||||
#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
|
||||||
|
#define BIOS_DEFAULT_VIDEO_MODE 0x03
|
||||||
|
#define BIOS_MAX_PAGES 8
|
||||||
|
#define BIOS_MAX_VIDEO_MODE 0x13
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
DWORD Width;
|
||||||
|
DWORD Height;
|
||||||
|
BOOLEAN Text;
|
||||||
|
DWORD Colors;
|
||||||
|
BOOLEAN Gray;
|
||||||
|
BYTE Pages;
|
||||||
|
WORD Segment;
|
||||||
|
} VIDEO_MODE;
|
||||||
|
|
||||||
/* FUNCTIONS ******************************************************************/
|
/* FUNCTIONS ******************************************************************/
|
||||||
|
|
||||||
BOOLEAN BiosInitialize();
|
BOOLEAN BiosInitialize();
|
||||||
VOID BiosUpdateConsole(ULONG StartAddress, ULONG EndAddress);
|
VOID BiosUpdateConsole(ULONG StartAddress, ULONG EndAddress);
|
||||||
VOID BiosUpdateVideoMemory(ULONG StartAddress, ULONG EndAddress);
|
VOID BiosUpdateVideoMemory(ULONG StartAddress, ULONG EndAddress);
|
||||||
|
inline DWORD BiosGetVideoMemoryStart();
|
||||||
|
inline VOID BiosVerticalRefresh();
|
||||||
WORD BiosPeekCharacter();
|
WORD BiosPeekCharacter();
|
||||||
WORD BiosGetCharacter();
|
WORD BiosGetCharacter();
|
||||||
VOID BiosVideoService();
|
VOID BiosVideoService();
|
||||||
|
|
|
@ -32,11 +32,11 @@ static VOID EmulatorReadMemory(PVOID Context, UINT Address, LPBYTE Buffer, INT S
|
||||||
if ((Address + Size) >= MAX_ADDRESS) return;
|
if ((Address + Size) >= MAX_ADDRESS) return;
|
||||||
|
|
||||||
/* Are we reading some of the console video memory? */
|
/* Are we reading some of the console video memory? */
|
||||||
if (((Address + Size) >= CONSOLE_VIDEO_MEM_START)
|
if (((Address + Size) >= BiosGetVideoMemoryStart())
|
||||||
&& (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 */
|
||||||
BiosUpdateVideoMemory(max(Address, CONSOLE_VIDEO_MEM_START),
|
BiosUpdateVideoMemory(max(Address, BiosGetVideoMemoryStart()),
|
||||||
min(Address + Size, CONSOLE_VIDEO_MEM_END));
|
min(Address + Size, CONSOLE_VIDEO_MEM_END));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -59,11 +59,11 @@ static VOID EmulatorWriteMemory(PVOID Context, UINT Address, LPBYTE Buffer, INT
|
||||||
RtlCopyMemory((LPVOID)((ULONG_PTR)BaseAddress + Address), Buffer, Size);
|
RtlCopyMemory((LPVOID)((ULONG_PTR)BaseAddress + Address), Buffer, Size);
|
||||||
|
|
||||||
/* Check if we modified the console video memory */
|
/* Check if we modified the console video memory */
|
||||||
if (((Address + Size) >= CONSOLE_VIDEO_MEM_START)
|
if (((Address + Size) >= BiosGetVideoMemoryStart())
|
||||||
&& (Address < CONSOLE_VIDEO_MEM_END))
|
&& (Address < CONSOLE_VIDEO_MEM_END))
|
||||||
{
|
{
|
||||||
/* Call the VDM BIOS to update the screen */
|
/* Call the VDM BIOS to update the screen */
|
||||||
BiosUpdateConsole(max(Address, CONSOLE_VIDEO_MEM_START),
|
BiosUpdateConsole(max(Address, BiosGetVideoMemoryStart()),
|
||||||
min(Address + Size, CONSOLE_VIDEO_MEM_END));
|
min(Address + Size, CONSOLE_VIDEO_MEM_END));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -73,19 +73,54 @@ INT wmain(INT argc, WCHAR *argv[])
|
||||||
DWORD LastTickCount = GetTickCount();
|
DWORD LastTickCount = GetTickCount();
|
||||||
DWORD Cycles = 0;
|
DWORD Cycles = 0;
|
||||||
DWORD LastCyclePrintout = GetTickCount();
|
DWORD LastCyclePrintout = GetTickCount();
|
||||||
|
DWORD LastVerticalRefresh = GetTickCount();
|
||||||
LARGE_INTEGER Frequency, LastTimerTick, Counter;
|
LARGE_INTEGER Frequency, LastTimerTick, Counter;
|
||||||
LONGLONG TimerTicks;
|
LONGLONG TimerTicks;
|
||||||
|
HANDLE ConsoleInput = INVALID_HANDLE_VALUE;
|
||||||
|
HANDLE ConsoleOutput = INVALID_HANDLE_VALUE;
|
||||||
|
CONSOLE_SCREEN_BUFFER_INFO SavedBufferInfo;
|
||||||
|
|
||||||
/* Set the handler routine */
|
/* Set the handler routine */
|
||||||
SetConsoleCtrlHandler(ConsoleCtrlHandler, TRUE);
|
SetConsoleCtrlHandler(ConsoleCtrlHandler, TRUE);
|
||||||
|
|
||||||
|
/* Get the input and output handles to the real console */
|
||||||
|
ConsoleInput = CreateFile(TEXT("CONIN$"),
|
||||||
|
GENERIC_READ | GENERIC_WRITE,
|
||||||
|
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
||||||
|
NULL,
|
||||||
|
OPEN_EXISTING,
|
||||||
|
0,
|
||||||
|
NULL);
|
||||||
|
|
||||||
|
ConsoleOutput = CreateFile(TEXT("CONOUT$"),
|
||||||
|
GENERIC_READ | GENERIC_WRITE,
|
||||||
|
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
||||||
|
NULL,
|
||||||
|
OPEN_EXISTING,
|
||||||
|
0,
|
||||||
|
NULL);
|
||||||
|
|
||||||
|
if ((ConsoleInput == INVALID_HANDLE_VALUE)
|
||||||
|
|| (ConsoleOutput == INVALID_HANDLE_VALUE))
|
||||||
|
{
|
||||||
|
wprintf(L"FATAL: Could not get handles to the console\n");
|
||||||
|
goto Cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Save the console screen buffer information */
|
||||||
|
if (!GetConsoleScreenBufferInfo(ConsoleOutput, &SavedBufferInfo))
|
||||||
|
{
|
||||||
|
wprintf(L"FATAL: Could not save the console screen buffer information\n");
|
||||||
|
goto Cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
/* The DOS command line must be ASCII */
|
/* The DOS command line must be ASCII */
|
||||||
WideCharToMultiByte(CP_ACP, 0, GetCommandLine(), -1, CommandLine, 128, NULL, NULL);
|
WideCharToMultiByte(CP_ACP, 0, GetCommandLine(), -1, CommandLine, 128, NULL, NULL);
|
||||||
|
|
||||||
if (!EmulatorInitialize())
|
if (!EmulatorInitialize())
|
||||||
{
|
{
|
||||||
wprintf(L"FATAL: Failed to initialize the CPU emulator\n");
|
wprintf(L"FATAL: Failed to initialize the CPU emulator\n");
|
||||||
return 1;
|
goto Cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Initialize the performance counter (needed for hardware timers) */
|
/* Initialize the performance counter (needed for hardware timers) */
|
||||||
|
@ -96,7 +131,7 @@ INT wmain(INT argc, WCHAR *argv[])
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Initialize the system BIOS */
|
/* Initialize the system BIOS */
|
||||||
if (!BiosInitialize())
|
if (!BiosInitialize(ConsoleInput, ConsoleOutput))
|
||||||
{
|
{
|
||||||
wprintf(L"FATAL: Failed to initialize the VDM BIOS.\n");
|
wprintf(L"FATAL: Failed to initialize the VDM BIOS.\n");
|
||||||
goto Cleanup;
|
goto Cleanup;
|
||||||
|
@ -143,6 +178,13 @@ INT wmain(INT argc, WCHAR *argv[])
|
||||||
LastTickCount = CurrentTickCount;
|
LastTickCount = CurrentTickCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Check for vertical refresh */
|
||||||
|
if ((CurrentTickCount - LastVerticalRefresh) >= 16)
|
||||||
|
{
|
||||||
|
BiosVerticalRefresh();
|
||||||
|
LastVerticalRefresh = CurrentTickCount;
|
||||||
|
}
|
||||||
|
|
||||||
/* Continue CPU emulation */
|
/* Continue CPU emulation */
|
||||||
for (i = 0; (i < STEPS_PER_CYCLE) && VdmRunning; i++)
|
for (i = 0; (i < STEPS_PER_CYCLE) && VdmRunning; i++)
|
||||||
{
|
{
|
||||||
|
@ -159,8 +201,18 @@ INT wmain(INT argc, WCHAR *argv[])
|
||||||
}
|
}
|
||||||
|
|
||||||
Cleanup:
|
Cleanup:
|
||||||
|
/* Restore the old screen buffer */
|
||||||
|
SetConsoleActiveScreenBuffer(ConsoleOutput);
|
||||||
|
|
||||||
|
/* Restore the screen buffer size */
|
||||||
|
SetConsoleScreenBufferSize(ConsoleOutput, SavedBufferInfo.dwSize);
|
||||||
|
|
||||||
EmulatorCleanup();
|
EmulatorCleanup();
|
||||||
|
|
||||||
|
/* Close the console handles */
|
||||||
|
if (ConsoleInput != INVALID_HANDLE_VALUE) CloseHandle(ConsoleInput);
|
||||||
|
if (ConsoleOutput != INVALID_HANDLE_VALUE) CloseHandle(ConsoleOutput);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue