#define NDEBUG
-#include "bios.h"
#include "emulator.h"
+#include "bios.h"
+
#include "vga.h"
#include "pic.h"
#include "ps2.h"
#include "timer.h"
+#include "int32.h"
#include "registers.h"
/* PRIVATE VARIABLES **********************************************************/
static HANDLE BiosConsoleInput = INVALID_HANDLE_VALUE;
static HANDLE BiosConsoleOutput = INVALID_HANDLE_VALUE;
static CONSOLE_SCREEN_BUFFER_INFO BiosSavedBufferInfo;
+static HANDLE InputThread = NULL;
/*
* VGA Register Configurations for BIOS Video Modes
COORD Resolution;
LPBYTE Values = VideoModes[ModeNumber];
+ DPRINT1("Switching to mode %Xh; Values = 0x%p\n", ModeNumber, Values);
+
if (Values == NULL) return FALSE;
/* Write the misc register */
VgaWritePort(VGA_AC_WRITE, *(Values++));
}
+ /* Reset the palette */
+ VgaResetPalette();
+
/* Update the values in the BDA */
Bda->VideoMode = ModeNumber;
Bda->VideoPage = 0;
Resolution = VgaGetDisplayResolution();
Bda->ScreenColumns = Resolution.X;
- Bda->ScreenRows = Resolution.Y - 1;
+ Bda->ScreenRows = Resolution.Y - 1;
return TRUE;
}
BOOLEAN BiosInitialize(VOID)
{
- INT i;
- WORD Offset = 0;
- LPWORD IntVecTable = (LPWORD)BaseAddress;
- LPBYTE BiosCode = (LPBYTE)SEG_OFF_TO_PTR(BIOS_SEGMENT, 0);
-
/* Initialize the BDA */
Bda = (PBIOS_DATA_AREA)SEG_OFF_TO_PTR(BDA_SEGMENT, 0);
Bda->EquipmentList = BIOS_EQUIPMENT_LIST;
+ /*
+ * Conventional memory size is 640 kB,
+ * see: http://webpages.charter.net/danrollins/techhelp/0184.HTM
+ * and see Ralf Brown: http://www.ctyme.com/intr/rb-0598.htm
+ * for more information.
+ */
+ Bda->MemorySize = 0x0280;
Bda->KeybdBufferStart = FIELD_OFFSET(BIOS_DATA_AREA, KeybdBuffer);
Bda->KeybdBufferEnd = Bda->KeybdBufferStart + BIOS_KBD_BUFFER_SIZE * sizeof(WORD);
- /* Generate ISR stubs and fill the IVT */
- for (i = 0; i < 256; i++)
- {
- IntVecTable[i * 2] = Offset;
- IntVecTable[i * 2 + 1] = BIOS_SEGMENT;
-
- BiosCode[Offset++] = 0xFB; // sti
+ /* Initialize the 32-bit Interrupt system */
+ InitializeInt32(BIOS_SEGMENT);
- BiosCode[Offset++] = 0x6A; // push i
- BiosCode[Offset++] = (BYTE)i;
-
- BiosCode[Offset++] = 0x6A; // push 0
- BiosCode[Offset++] = 0x00;
-
- BiosCode[Offset++] = 0xF8; // clc
-
- BiosCode[Offset++] = LOBYTE(EMULATOR_BOP); // BOP sequence
- BiosCode[Offset++] = HIBYTE(EMULATOR_BOP);
- BiosCode[Offset++] = LOBYTE(EMULATOR_INT_BOP);
- BiosCode[Offset++] = HIBYTE(EMULATOR_INT_BOP);
-
- BiosCode[Offset++] = 0x73; // jnc +3
- BiosCode[Offset++] = 0x03;
-
- // HACK: The following instruction should be HLT!
- BiosCode[Offset++] = 0x90; // nop
-
- BiosCode[Offset++] = 0xEB; // jmp -10
- BiosCode[Offset++] = 0xF6;
-
- BiosCode[Offset++] = 0x83; // add sp, 4
- BiosCode[Offset++] = 0xC4;
- BiosCode[Offset++] = 0x04;
-
- BiosCode[Offset++] = 0xCF; // iret
- }
+ /* Register the BIOS 32-bit Interrupts */
+ RegisterInt32(BIOS_VIDEO_INTERRUPT , BiosVideoService );
+ RegisterInt32(BIOS_EQUIPMENT_INTERRUPT, BiosEquipmentService );
+ RegisterInt32(BIOS_MEMORY_SIZE , BiosGetMemorySize );
+ RegisterInt32(BIOS_MISC_INTERRUPT , BiosMiscService );
+ RegisterInt32(BIOS_KBD_INTERRUPT , BiosKeyboardService );
+ RegisterInt32(BIOS_TIME_INTERRUPT , BiosTimeService );
+ RegisterInt32(BIOS_SYS_TIMER_INTERRUPT, BiosSystemTimerInterrupt);
/* Get the input handle to the real console, and check for success */
BiosConsoleInput = CreateFileW(L"CONIN$",
/* Set the console input mode */
SetConsoleMode(BiosConsoleInput, ENABLE_MOUSE_INPUT | ENABLE_PROCESSED_INPUT);
+ /* Start the input thread */
+ InputThread = CreateThread(NULL, 0, &InputThreadProc, BiosConsoleInput, 0, NULL);
+
/* Initialize the PIC */
PicWriteCommand(PIC_MASTER_CMD, PIC_ICW1 | PIC_ICW1_ICW4);
PicWriteCommand(PIC_SLAVE_CMD , PIC_ICW1 | PIC_ICW1_ICW4);
VOID BiosCleanup(VOID)
{
+ /* Close the input thread handle */
+ if (InputThread != NULL) CloseHandle(InputThread);
+
/* Restore the old screen buffer */
SetConsoleActiveScreenBuffer(BiosConsoleOutput);
return CharacterData;
}
+VOID BiosGetCursorPosition(PBYTE Row, PBYTE Column, BYTE Page)
+{
+ /* Make sure the selected video page is valid */
+ if (Page >= BIOS_MAX_PAGES) return;
+
+ /* Get the cursor location */
+ *Row = HIBYTE(Bda->CursorPosition[Page]);
+ *Column = LOBYTE(Bda->CursorPosition[Page]);
+}
+
VOID BiosSetCursorPosition(BYTE Row, BYTE Column, BYTE Page)
{
/* Make sure the selected video page is valid */
if (Page >= BIOS_MAX_PAGES) return;
/* Update the position in the BDA */
- Bda->CursorPosition[Page] = (Row << 8) | Column;
+ Bda->CursorPosition[Page] = MAKEWORD(Column, Row);
/* Check if this is the current video page */
if (Page == Bda->VideoPage)
/* Fill the window */
for (i = 0; i < WindowSize; i++)
{
- WindowData[i] = ' ' | (FillAttribute << 8);
+ WindowData[i] = MAKEWORD(' ', FillAttribute);
}
goto Done;
VOID BiosPrintCharacter(CHAR Character, BYTE Attribute, BYTE Page)
{
- WORD CharData = (Attribute << 8) | Character;
+ WORD CharData = MAKEWORD(Character, Attribute);
BYTE Row, Column;
/* Make sure the page exists */
if (Page >= BIOS_MAX_PAGES) return;
/* Get the cursor location */
- Row = HIBYTE(Bda->CursorPosition[Page]);
- Column = LOBYTE(Bda->CursorPosition[Page]);
+ BiosGetCursorPosition(&Row, &Column, Page);
if (Character == '\a')
{
}
/* Erase the existing character */
- CharData = (Attribute << 8) | ' ';
- VgaWriteMemory(TO_LINEAR(TEXT_VIDEO_SEG,
- Page * Bda->VideoPageSize
- + (Row * Bda->ScreenColumns + Column) * sizeof(WORD)),
- (LPVOID)&CharData,
- sizeof(WORD));
+ CharData = MAKEWORD(' ', Attribute);
+ EmulatorWriteMemory(&EmulatorContext,
+ TO_LINEAR(TEXT_VIDEO_SEG,
+ Page * Bda->VideoPageSize +
+ (Row * Bda->ScreenColumns + Column) * sizeof(WORD)),
+ (LPVOID)&CharData,
+ sizeof(WORD));
+ }
+ else if (Character == '\t')
+ {
+ /* Horizontal Tabulation control character */
+ do
+ {
+ // Taken from DosBox
+ BiosPrintCharacter(' ', Attribute, Page);
+ BiosGetCursorPosition(&Row, &Column, Page);
+ } while (Column % 8);
}
else if (Character == '\n')
{
/* Default character */
/* Write the character */
- VgaWriteMemory(TO_LINEAR(TEXT_VIDEO_SEG,
- Page * Bda->VideoPageSize
- + (Row * Bda->ScreenColumns + Column) * sizeof(WORD)),
- (LPVOID)&CharData,
- sizeof(WORD));
+ EmulatorWriteMemory(&EmulatorContext,
+ TO_LINEAR(TEXT_VIDEO_SEG,
+ Page * Bda->VideoPageSize +
+ (Row * Bda->ScreenColumns + Column) * sizeof(WORD)),
+ (LPVOID)&CharData,
+ sizeof(WORD));
/* Advance the cursor */
Column++;
Rectangle,
Page,
DEFAULT_ATTRIBUTE);
+
+ Row--;
}
/* Set the cursor position */
BiosSetCursorPosition(Row, Column, Page);
}
-VOID BiosVideoService(LPWORD Stack)
+VOID WINAPI BiosVideoService(LPWORD Stack)
{
switch (getAH())
{
break;
}
+ /* Palette Control */
+ case 0x10:
+ {
+ switch (getAL())
+ {
+ /* Set Single Palette Register */
+ case 0x00:
+ {
+ /* Reset the flip-flop */
+ VgaReadPort(VGA_STAT_COLOR);
+
+ /* Write the index */
+ VgaWritePort(VGA_AC_INDEX, getBL());
+
+ /* Write the data */
+ VgaWritePort(VGA_AC_WRITE, getBH());
+
+ break;
+ }
+
+ /* Set Overscan Color */
+ case 0x01:
+ {
+ /* Reset the flip-flop */
+ VgaReadPort(VGA_STAT_COLOR);
+
+ /* Write the index */
+ VgaWritePort(VGA_AC_INDEX, VGA_AC_OVERSCAN_REG);
+
+ /* Write the data */
+ VgaWritePort(VGA_AC_WRITE, getBH());
+
+ break;
+ }
+
+ /* Set All Palette Registers */
+ case 0x02:
+ {
+ INT i;
+ LPBYTE Buffer = SEG_OFF_TO_PTR(getES(), getDX());
+
+ /* Set the palette registers */
+ for (i = 0; i <= VGA_AC_PAL_F_REG; i++)
+ {
+ /* Reset the flip-flop */
+ VgaReadPort(VGA_STAT_COLOR);
+
+ /* Write the index */
+ VgaWritePort(VGA_AC_INDEX, i);
+
+ /* Write the data */
+ VgaWritePort(VGA_AC_WRITE, Buffer[i]);
+ }
+
+ /* Set the overscan register */
+ VgaWritePort(VGA_AC_INDEX, VGA_AC_OVERSCAN_REG);
+ VgaWritePort(VGA_AC_WRITE, Buffer[VGA_AC_PAL_F_REG + 1]);
+
+ break;
+ }
+
+ /* Get Single Palette Register */
+ case 0x07:
+ {
+ /* Reset the flip-flop */
+ VgaReadPort(VGA_STAT_COLOR);
+
+ /* Write the index */
+ VgaWritePort(VGA_AC_INDEX, getBL());
+
+ /* Read the data */
+ setBH(VgaReadPort(VGA_AC_READ));
+
+ break;
+ }
+
+ /* Get Overscan Color */
+ case 0x08:
+ {
+ /* Reset the flip-flop */
+ VgaReadPort(VGA_STAT_COLOR);
+
+ /* Write the index */
+ VgaWritePort(VGA_AC_INDEX, VGA_AC_OVERSCAN_REG);
+
+ /* Read the data */
+ setBH(VgaReadPort(VGA_AC_READ));
+
+ break;
+ }
+
+ /* Get All Palette Registers */
+ case 0x09:
+ {
+ INT i;
+ LPBYTE Buffer = SEG_OFF_TO_PTR(getES(), getDX());
+
+ /* Get the palette registers */
+ for (i = 0; i <= VGA_AC_PAL_F_REG; i++)
+ {
+ /* Reset the flip-flop */
+ VgaReadPort(VGA_STAT_COLOR);
+
+ /* Write the index */
+ VgaWritePort(VGA_AC_INDEX, i);
+
+ /* Read the data */
+ Buffer[i] = VgaReadPort(VGA_AC_READ);
+ }
+
+ /* Get the overscan register */
+ VgaWritePort(VGA_AC_INDEX, VGA_AC_OVERSCAN_REG);
+ Buffer[VGA_AC_PAL_F_REG + 1] = VgaReadPort(VGA_AC_READ);
+
+ break;
+ }
+
+ /* Set Individual DAC Register */
+ case 0x10:
+ {
+ /* Write the index */
+ // Certainly in BL and not in BX as said by Ralf Brown...
+ VgaWritePort(VGA_DAC_WRITE_INDEX, getBL());
+
+ /* Write the data in this order: Red, Green, Blue */
+ VgaWritePort(VGA_DAC_DATA, getDH());
+ VgaWritePort(VGA_DAC_DATA, getCH());
+ VgaWritePort(VGA_DAC_DATA, getCL());
+
+ break;
+ }
+
+ /* Set Block of DAC Registers */
+ case 0x12:
+ {
+ INT i;
+ LPBYTE Buffer = SEG_OFF_TO_PTR(getES(), getDX());
+
+ /* Write the index */
+ // Certainly in BL and not in BX as said by Ralf Brown...
+ VgaWritePort(VGA_DAC_WRITE_INDEX, getBL());
+
+ for (i = 0; i < getCX(); i++)
+ {
+ /* Write the data in this order: Red, Green, Blue */
+ VgaWritePort(VGA_DAC_DATA, *Buffer++);
+ VgaWritePort(VGA_DAC_DATA, *Buffer++);
+ VgaWritePort(VGA_DAC_DATA, *Buffer++);
+ }
+
+ break;
+ }
+
+ /* Get Individual DAC Register */
+ case 0x15:
+ {
+ /* Write the index */
+ VgaWritePort(VGA_DAC_READ_INDEX, getBL());
+
+ /* Read the data in this order: Red, Green, Blue */
+ setDH(VgaReadPort(VGA_DAC_DATA));
+ setCH(VgaReadPort(VGA_DAC_DATA));
+ setCL(VgaReadPort(VGA_DAC_DATA));
+
+ break;
+ }
+
+ /* Get Block of DAC Registers */
+ case 0x17:
+ {
+ INT i;
+ LPBYTE Buffer = SEG_OFF_TO_PTR(getES(), getDX());
+
+ /* Write the index */
+ // Certainly in BL and not in BX as said by Ralf Brown...
+ VgaWritePort(VGA_DAC_READ_INDEX, getBL());
+
+ for (i = 0; i < getCX(); i++)
+ {
+ /* Write the data in this order: Red, Green, Blue */
+ *Buffer++ = VgaReadPort(VGA_DAC_DATA);
+ *Buffer++ = VgaReadPort(VGA_DAC_DATA);
+ *Buffer++ = VgaReadPort(VGA_DAC_DATA);
+ }
+
+ break;
+ }
+
+ default:
+ {
+ DPRINT1("BIOS Palette Control Sub-command AL = 0x%02X NOT IMPLEMENTED\n",
+ getAL());
+ break;
+ }
+ }
+
+ break;
+ }
+
/* Scroll Window */
case 0x12:
{
}
}
-VOID BiosKeyboardService(LPWORD Stack)
+VOID WINAPI BiosEquipmentService(LPWORD Stack)
+{
+ /* Return the equipment list */
+ setAX(Bda->EquipmentList);
+}
+
+VOID WINAPI BiosGetMemorySize(LPWORD Stack)
+{
+ /* Return the conventional memory size in kB, typically 640 kB */
+ setAX(Bda->MemorySize);
+}
+
+VOID WINAPI BiosMiscService(LPWORD Stack)
+{
+ switch (getAH())
+ {
+ /* Get Extended Memory Size */
+ case 0x88:
+ {
+ /* Return the number of KB of RAM after 1 MB */
+ setAX((MAX_ADDRESS - 0x100000) / 1024);
+
+ /* Clear CF */
+ Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
+
+ break;
+ }
+
+ default:
+ {
+ DPRINT1("BIOS Function INT 15h, AH = 0x%02X NOT IMPLEMENTED\n",
+ getAH());
+ }
+ }
+}
+
+VOID WINAPI BiosKeyboardService(LPWORD Stack)
{
switch (getAH())
{
}
}
-VOID BiosTimeService(LPWORD Stack)
+VOID WINAPI BiosTimeService(LPWORD Stack)
{
switch (getAH())
{
}
}
-VOID BiosSystemTimerInterrupt(LPWORD Stack)
+VOID WINAPI BiosSystemTimerInterrupt(LPWORD Stack)
{
/* Increase the system tick count */
Bda->TickCounter++;
}
-VOID BiosEquipmentService(LPWORD Stack)
-{
- /* Return the equipment list */
- setAX(Bda->EquipmentList);
-}
-
VOID BiosHandleIrq(BYTE IrqNumber, LPWORD Stack)
{
switch (IrqNumber)
}
/* Send End-of-Interrupt to the PIC */
- if (IrqNumber > 8) PicWriteCommand(PIC_SLAVE_CMD, PIC_OCW2_EOI);
+ if (IrqNumber >= 8) PicWriteCommand(PIC_SLAVE_CMD, PIC_OCW2_EOI);
PicWriteCommand(PIC_MASTER_CMD, PIC_OCW2_EOI);
}