/*
* COPYRIGHT: GPL - See COPYING in the top level directory
* PROJECT: ReactOS Virtual DOS Machine
- * FILE: vidbios.c
- * PURPOSE: VDM Video BIOS Support Library
+ * FILE: subsystems/mvdm/ntvdm/bios/vidbios.c
+ * PURPOSE: VDM 32-bit Video BIOS Support Library
* PROGRAMMERS: Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
* Hermes Belusca-Maito (hermes.belusca@sfr.fr)
*/
/* INCLUDES *******************************************************************/
+#include "ntvdm.h"
+
#define NDEBUG
+#include <debug.h>
+
+/* BIOS Version number and Copyright */
+#include <reactos/buildno.h>
+#include <reactos/version.h>
#include "emulator.h"
#include "cpu/cpu.h"
#include "cpu/bop.h"
+#include "memory.h"
#include "bios.h"
+#include "bios32/bios32p.h"
+#include "rom.h"
+#include "bios32/vbe.h"
// #include "vidbios.h"
+#include "bios32/vidbios32.h"
#include "io.h"
-#include "hardware/video/vga.h"
-
-/* DEFINES ********************************************************************/
-
-/* BOP Identifiers */
-#define BOP_VIDEO_INT 0x10
+#include "hardware/video/svga.h"
+/**/
+#include "../console/video.h"
+/**/
/* MACROS *********************************************************************/
/* PRIVATE VARIABLES **********************************************************/
+/*
+ * WARNING! For compatibility purposes the string "IBM" should be at C000:001E.
+ */
+static const CHAR BiosInfo[] =
+ "00000000000 Emulation of IBM VGA Compatible ROM\0"
+ "CL-GD5434 VGA BIOS Version 1.41 \r\n"
+ "Copyright (C) ReactOS Team 1996-"COPYRIGHT_YEAR"\r\n"
+ "The original CL-GD5434 card was created by Cirrus Logic, Inc.\r\n\0"
+ "BIOS Date: 06/17/13\0";
+
+C_ASSERT(sizeof(BiosInfo)-1 <= 0xFF-0x05); // Ensures that we won't overflow on the Video Code
+
+
/*
* VGA Register Configurations for BIOS Video Modes.
* The configurations were checked against SeaBIOS VGA BIOS.
*/
+
static VGA_REGISTERS VideoMode_40x25_text =
{
/* Miscellaneous Register */
0x0C, 0x0D, 0x0E, 0x0F, 0x41, 0x00, 0x0F, 0x00, 0x00}
};
-/* See http://wiki.osdev.org/Drawing_In_Protected_Mode#Locating_Video_Memory */
-static PVGA_REGISTERS VideoModes[BIOS_MAX_VIDEO_MODE + 1] =
-{
- &VideoMode_40x25_text, /* Mode 00h */ // 16 color (mono)
- &VideoMode_40x25_text, /* Mode 01h */ // 16 color
- &VideoMode_80x25_text, /* Mode 02h */ // 16 color (mono)
- &VideoMode_80x25_text, /* Mode 03h */ // 16 color
- &VideoMode_320x200_4color, /* Mode 04h */ // CGA 4 color
- &VideoMode_320x200_4color, /* Mode 05h */ // CGA same (m) (uses 3rd CGA palette)
- &VideoMode_640x200_2color, /* Mode 06h */ // CGA 640*200 2 color
- NULL, /* Mode 07h */ // MDA monochrome text 80*25
- NULL, /* Mode 08h */ // PCjr
- NULL, /* Mode 09h */ // PCjr
- NULL, /* Mode 0Ah */ // PCjr
- NULL, /* Mode 0Bh */ // Reserved
- NULL, /* Mode 0Ch */ // Reserved
- &VideoMode_320x200_16color, /* Mode 0Dh */ // EGA 320*200 16 color
- &VideoMode_640x200_16color, /* Mode 0Eh */ // EGA 640*200 16 color
- NULL, /* Mode 0Fh */ // EGA 640*350 mono
- &VideoMode_640x350_16color, /* Mode 10h */ // EGA 640*350 HiRes 16 color
- &VideoMode_640x480_2color, /* Mode 11h */ // VGA 640*480 mono
- &VideoMode_640x480_16color, /* Mode 12h */ // VGA
- &VideoMode_320x200_256color, /* Mode 13h */ // VGA
-};
-
-// FIXME: Are they computable with the previous data ??
-// Values taken from DOSBox.
-static WORD VideoModePageSize[BIOS_MAX_VIDEO_MODE + 1] =
-{
- 0x0800, 0x0800, 0x1000, 0x1000,
- 0x4000, 0x4000, 0x4000, 0x1000,
- 0x0000, 0x0000, 0x0000, 0x0000,
- 0x0000, 0x2000, 0x4000, 0x8000,
- 0x8000, 0xA000, 0xA000, 0x2000
-};
/*
* BIOS Mode Palettes
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};
+
+/*
+ * Table of supported Video Modes.
+ *
+ * See http://wiki.osdev.org/Drawing_In_Protected_Mode#Locating_Video_Memory
+ * Values of PageSize taken from DOSBox.
+ */
+
+typedef struct _VGA_MODE
+{
+ PVGA_REGISTERS VgaRegisters;
+ WORD PageSize;
+ WORD CharacterWidth;
+ WORD CharacterHeight;
+ // PCOLORREF Palette;
+} VGA_MODE, *PVGA_MODE;
+
+static CONST VGA_MODE VideoModes[BIOS_MAX_VIDEO_MODE + 1] =
+{
+ {&VideoMode_40x25_text, 0x0800, 9, 16}, /* Mode 00h - 16 color (mono) */
+ {&VideoMode_40x25_text, 0x0800, 9, 16}, /* Mode 01h - 16 color */
+ {&VideoMode_80x25_text, 0x1000, 9, 16}, /* Mode 02h - 16 color (mono) */
+ {&VideoMode_80x25_text, 0x1000, 9, 16}, /* Mode 03h - 16 color */
+ {&VideoMode_320x200_4color, 0x4000, 8, 8}, /* Mode 04h - CGA 4 color */
+ {&VideoMode_320x200_4color, 0x4000, 8, 8}, /* Mode 05h - CGA same (m) (uses 3rd CGA palette) */
+ {&VideoMode_640x200_2color, 0x4000, 8, 8}, /* Mode 06h - CGA 640*200 2 color */
+ {NULL, 0x1000, 1, 1}, /* Mode 07h - MDA monochrome text 80*25 */
+ {NULL, 0x0000, 1, 1}, /* Mode 08h - PCjr */
+ {NULL, 0x0000, 1, 1}, /* Mode 09h - PCjr */
+ {NULL, 0x0000, 1, 1}, /* Mode 0Ah - PCjr */
+ {NULL, 0x0000, 1, 1}, /* Mode 0Bh - Reserved */
+ {NULL, 0x0000, 1, 1}, /* Mode 0Ch - Reserved */
+ {&VideoMode_320x200_16color, 0x2000, 8, 8}, /* Mode 0Dh - EGA 320*200 16 color */
+ {&VideoMode_640x200_16color, 0x4000, 8, 8}, /* Mode 0Eh - EGA 640*200 16 color */
+ {NULL, 0x8000, 1, 1}, /* Mode 0Fh - EGA 640*350 mono */
+ {&VideoMode_640x350_16color, 0x8000, 8, 14}, /* Mode 10h - EGA 640*350 HiRes 16 color */
+ {&VideoMode_640x480_2color, 0xA000, 8, 16}, /* Mode 11h - VGA 640*480 mono */
+ {&VideoMode_640x480_16color, 0xA000, 8, 16}, /* Mode 12h - VGA */
+ {&VideoMode_320x200_256color, 0x2000, 8, 8}, /* Mode 13h - VGA */
+};
+
+#define IS_TEXT_MODE(ModeNumber) \
+ (((ModeNumber) >= 0x00 && (ModeNumber) <= 0x03) || ((ModeNumber) == 0x07))
+
+static PVGA_STATIC_FUNC_TABLE VgaStaticFuncTable;
+static BOOLEAN VbeInitialized = FALSE;
+
/* PRIVATE FUNCTIONS **********************************************************/
static BOOLEAN VidBiosScrollWindow(SCROLL_DIRECTION Direction,
WORD WindowWidth, WindowHeight;
+ /* TODO: This function doesn't work in non-alphanumeric modes yet */
+ if (Bda->VideoMode > 3)
+ {
+ DPRINT1("VidBiosScrollWindow: not implemented for mode 0%Xh\n", Bda->VideoMode);
+ return FALSE;
+ }
+
/* Fixup the rectangle if needed */
Rectangle.Left = min(max(Rectangle.Left , 0), Bda->ScreenColumns - 1);
Rectangle.Right = min(max(Rectangle.Right , 0), Bda->ScreenColumns - 1);
/* Move text lines up */
for (i = Rectangle.Top + Amount; i <= Rectangle.Bottom; i++)
{
- EmulatorWriteMemory(&EmulatorContext,
- VideoAddress + ((i - Amount) * Bda->ScreenColumns + Rectangle.Left) * sizeof(WORD),
- REAL_TO_PHYS(VideoAddress + ( i * Bda->ScreenColumns + Rectangle.Left) * sizeof(WORD)),
- (Rectangle.Right - Rectangle.Left + 1) * sizeof(WORD));
+ EmulatorCopyMemory(&EmulatorContext,
+ VideoAddress + ((i - Amount) * Bda->ScreenColumns + Rectangle.Left) * sizeof(WORD),
+ VideoAddress + ( i * Bda->ScreenColumns + Rectangle.Left) * sizeof(WORD),
+ (Rectangle.Right - Rectangle.Left + 1) * sizeof(WORD));
}
/* Fill the bottom of the rectangle */
/* Move text lines down */
for (i = Rectangle.Bottom - Amount; i >= Rectangle.Top; i--)
{
- EmulatorWriteMemory(&EmulatorContext,
- VideoAddress + ((i + Amount) * Bda->ScreenColumns + Rectangle.Left) * sizeof(WORD),
- REAL_TO_PHYS(VideoAddress + ( i * Bda->ScreenColumns + Rectangle.Left) * sizeof(WORD)),
- (Rectangle.Right - Rectangle.Left + 1) * sizeof(WORD));
+ EmulatorCopyMemory(&EmulatorContext,
+ VideoAddress + ((i + Amount) * Bda->ScreenColumns + Rectangle.Left) * sizeof(WORD),
+ VideoAddress + ( i * Bda->ScreenColumns + Rectangle.Left) * sizeof(WORD),
+ (Rectangle.Right - Rectangle.Left + 1) * sizeof(WORD));
}
/* Fill the top of the rectangle */
/* Move text lines left */
for (i = Rectangle.Top; i <= Rectangle.Bottom; i++)
{
- EmulatorWriteMemory(&EmulatorContext,
- VideoAddress + (i * Bda->ScreenColumns + Rectangle.Left ) * sizeof(WORD),
- REAL_TO_PHYS(VideoAddress + (i * Bda->ScreenColumns + Rectangle.Left + Amount) * sizeof(WORD)),
- (Rectangle.Right - Rectangle.Left - Amount + 1) * sizeof(WORD));
+ EmulatorCopyMemory(&EmulatorContext,
+ VideoAddress + (i * Bda->ScreenColumns + Rectangle.Left ) * sizeof(WORD),
+ VideoAddress + (i * Bda->ScreenColumns + Rectangle.Left + Amount) * sizeof(WORD),
+ (Rectangle.Right - Rectangle.Left - Amount + 1) * sizeof(WORD));
}
/* Fill the right of the rectangle */
case SCROLL_RIGHT:
{
+ INT Right;
+
/* Move text lines right */
for (i = Rectangle.Top; i <= Rectangle.Bottom; i++)
{
- EmulatorWriteMemory(&EmulatorContext,
- VideoAddress + (i * Bda->ScreenColumns + Rectangle.Left + Amount) * sizeof(WORD),
- REAL_TO_PHYS(VideoAddress + (i * Bda->ScreenColumns + Rectangle.Left ) * sizeof(WORD)),
- (Rectangle.Right - Rectangle.Left - Amount + 1) * sizeof(WORD));
+ EmulatorCopyMemory(&EmulatorContext,
+ VideoAddress + (i * Bda->ScreenColumns + Rectangle.Left + Amount) * sizeof(WORD),
+ VideoAddress + (i * Bda->ScreenColumns + Rectangle.Left ) * sizeof(WORD),
+ (Rectangle.Right - Rectangle.Left - Amount + 1) * sizeof(WORD));
}
/* Fill the left of the rectangle */
+ Right = Rectangle.Left + Amount - 1;
for (i = Rectangle.Top; i <= Rectangle.Bottom; i++)
{
- INT Right = Rectangle.Left + Amount - 1;
for (j = Rectangle.Left; j <= Right; j++)
{
EmulatorWriteMemory(&EmulatorContext,
static BOOLEAN VgaSetRegisters(PVGA_REGISTERS Registers)
{
- INT i;
+ UINT i;
if (Registers == NULL) return FALSE;
Bda->CrtBasePort = (Registers->Misc & 0x01) ? VGA_CRTC_INDEX_COLOR
: VGA_CRTC_INDEX_MONO;
/* Bit 1 indicates whether display is color (0) or monochrome (1) */
- Bda->VGAOptions = (Bda->VGAOptions & 0xFD) | (!(Registers->Misc & 0x01) << 1);
+ Bda->VGAOptions = (Bda->VGAOptions & 0xFD) | (!(Registers->Misc & 0x01) << 1);
+ Bda->CrtModeControl = (Bda->CrtModeControl & 0xFB) | (!(Registers->Misc & 0x01) << 1);
+
+ /* Update blink bit in BDA */
+ if (Registers->Attribute[VGA_AC_CONTROL_REG] & VGA_AC_CONTROL_BLINK)
+ Bda->CrtModeControl |= (1 << 5);
+ else
+ Bda->CrtModeControl &= ~(1 << 5);
/* Turn the video off */
IOWriteB(VGA_SEQ_INDEX, VGA_SEQ_CLOCK_REG);
{
/* VGA modes */
Palette = VgaPalette;
- Size = sizeof(VgaPalette)/sizeof(VgaPalette[0]);
+ Size = ARRAYSIZE(VgaPalette);
}
else if (ModeNumber == 0x10) // || (ModeNumber == 0x0D) || (ModeNumber == 0x0E)
{
/* EGA HiRes mode */
Palette = EgaPalette__HiRes;
- Size = sizeof(EgaPalette__HiRes)/sizeof(EgaPalette__HiRes[0]);
+ Size = ARRAYSIZE(EgaPalette__HiRes);
}
#if 0
else if ((ModeNumber == 0x04) || (ModeNumber == 0x05))
* bright versions of CGA palettes 0 and 1
*/
Palette = CgaPalette2;
- Size = sizeof(CgaPalette2)/sizeof(CgaPalette2[0]);
+ Size = ARRAYSIZE(CgaPalette2);
}
#endif
else // if ((ModeNumber == 0x0D) || (ModeNumber == 0x0E))
{
/* EGA modes */
Palette = EgaPalette__16Colors;
- Size = sizeof(EgaPalette__16Colors)/sizeof(EgaPalette__16Colors[0]);
+ Size = ARRAYSIZE(EgaPalette__16Colors);
}
VgaSetPalette(Palette, Size);
}
-static VOID VidBiosGetCursorPosition(PBYTE Row, PBYTE Column, BYTE Page)
+static __inline VOID VidBiosGetCursorPosition(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]);
}
static VOID VidBiosSetCursorPosition(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] = MAKEWORD(Column, Row);
static VOID VidBiosSetCursorShape(WORD CursorStartEnd)
{
/* Only valid in text-mode */
- if ((Bda->VideoMode > 0x03) && (Bda->VideoMode != 0x07)) return;
+ if (!IS_TEXT_MODE(Bda->VideoMode)) return;
/* Update the BDA */
Bda->CursorStartLine = HIBYTE(CursorStartEnd) & 0x1F;
IOWriteB(VGA_CRTC_DATA , LOBYTE(CursorStartEnd));
}
-VOID VidBiosSyncCursorPosition(VOID)
+static VOID VidBiosSyncCursorPosition(VOID)
{
BYTE Row, Column;
BYTE Low, High;
- SHORT ScreenColumns = VgaGetDisplayResolution().X;
+ SHORT ScreenColumns = Bda->ScreenColumns;
WORD Offset;
- /* Get the cursor location */
+ /* Get the cursor position */
IOWriteB(VGA_CRTC_INDEX, VGA_CRTC_CURSOR_LOC_LOW_REG);
Low = IOReadB(VGA_CRTC_DATA);
IOWriteB(VGA_CRTC_INDEX, VGA_CRTC_CURSOR_LOC_HIGH_REG);
return Bda->VideoMode | (Bda->VGAOptions & 0x80);
}
+static inline VOID VidBiosClearScreen(VOID)
+{
+ static const DWORD MemoryMaps[4] = { 0xA0000, 0xA0000, 0xB0000, 0xB8000 };
+ static const DWORD MemorySizes[4] = { 0x20000, 0x10000, 0x08000, 0x08000 };
+
+ DWORD VideoAddress;
+ DWORD BufferSize;
+ BYTE Misc;
+ BYTE Buffer[0x20000];
+
+ /* Read the misc register */
+ IOWriteB(VGA_GC_INDEX, VGA_GC_MISC_REG);
+ Misc = IOReadB(VGA_GC_DATA);
+
+ /* Get the video address and buffer size */
+ VideoAddress = MemoryMaps[(Misc >> 2) & 3];
+ BufferSize = MemorySizes[(Misc >> 2) & 3];
+
+ // !IS_TEXT_MODE(Bda->VideoMode)
+ if (Misc & 1)
+ {
+ /* Graphics mode */
+ RtlZeroMemory(Buffer, BufferSize);
+ }
+ else
+ {
+ /* Text mode */
+ UINT i;
+ for (i = 0; i < (BufferSize >> 1); i++)
+ {
+ ((PWORD)Buffer)[i] = MAKEWORD(' ', DEFAULT_ATTRIBUTE);
+ }
+ }
+
+ /* Write to video memory */
+ EmulatorWriteMemory(&EmulatorContext, VideoAddress, Buffer, BufferSize);
+}
+
static BOOLEAN VidBiosSetVideoMode(BYTE ModeNumber)
{
BYTE Page;
COORD Resolution;
- PVGA_REGISTERS VgaMode;
-
BYTE OrgModeNumber = ModeNumber;
/*
/* Retrieve the real mode number and check its validity */
ModeNumber &= 0x7F;
- // if (ModeNumber >= sizeof(VideoModes)/sizeof(VideoModes[0]))
+ // if (ModeNumber >= ARRAYSIZE(VideoModes))
if (ModeNumber > BIOS_MAX_VIDEO_MODE)
{
DPRINT1("VidBiosSetVideoMode -- Mode %02Xh invalid\n", ModeNumber);
return FALSE;
}
- VgaMode = VideoModes[ModeNumber];
-
- DPRINT1("Switching to mode %02Xh (%02Xh) %s clearing the screen; VgaMode = 0x%p\n",
- ModeNumber, OrgModeNumber, (DoNotClear ? "without" : "and"), VgaMode);
+ DPRINT1("Switching to mode %02Xh (%02Xh) %s clearing the screen; VgaRegisters = 0x%p\n",
+ ModeNumber, OrgModeNumber, (DoNotClear ? "without" : "and"), VideoModes[ModeNumber].VgaRegisters);
- if (!VgaSetRegisters(VgaMode)) return FALSE;
+ if (!VgaSetRegisters(VideoModes[ModeNumber].VgaRegisters)) return FALSE;
VgaChangePalette(ModeNumber);
/* Clear the VGA memory if needed */
if (!DoNotClear) VgaClearMemory();
- // Bda->CrtModeControl;
- // Bda->CrtColorPaletteMask;
- // Bda->EGAFlags;
- // Bda->VGAFlags;
-
/* Update the values in the BDA */
Bda->VideoMode = ModeNumber;
- Bda->VideoPageSize = VideoModePageSize[ModeNumber];
+ Bda->VideoPageSize = VideoModes[ModeNumber].PageSize;
Bda->VideoPage = 0;
Bda->VideoPageOffset = Bda->VideoPage * Bda->VideoPageSize;
Bda->VGAOptions = 0x60 | (Bda->VGAOptions & 0x7F) | (DoNotClear ? 0x80 : 0x00);
Bda->VGASwitches = 0xF9; /* High-resolution */
+ // Bda->VGAFlags;
+ // Bda->CrtModeControl;
+ // Bda->CrtColorPaletteMask;
+
/* Set the start address in the CRTC */
IOWriteB(VGA_CRTC_INDEX, VGA_CRTC_START_ADDR_LOW_REG);
IOWriteB(VGA_CRTC_DATA , LOBYTE(Bda->VideoPageOffset));
IOWriteB(VGA_CRTC_INDEX, VGA_CRTC_START_ADDR_HIGH_REG);
IOWriteB(VGA_CRTC_DATA , HIBYTE(Bda->VideoPageOffset));
- /* Update the character height */
- IOWriteB(VGA_CRTC_INDEX, VGA_CRTC_MAX_SCAN_LINE_REG);
- Bda->CharacterHeight = 1 + (IOReadB(VGA_CRTC_DATA) & 0x1F);
-
/* Update the screen size */
Resolution = VgaGetDisplayResolution();
+ // This could be simplified if the VGA helper always returned the resolution
+ // in number of pixels, instead of in number of cells for text-modes only...
+ if (!IS_TEXT_MODE(ModeNumber))
+ {
+ Resolution.X /= VideoModes[ModeNumber].CharacterWidth ;
+ Resolution.Y /= VideoModes[ModeNumber].CharacterHeight;
+ }
Bda->ScreenColumns = Resolution.X;
Bda->ScreenRows = Resolution.Y - 1;
+ /* Update the current font */
+ Bda->CharacterHeight = VideoModes[ModeNumber].CharacterHeight;
+ switch (Bda->CharacterHeight)
+ {
+ /*
+ * Write the default font to the VGA font plane for text-modes only.
+ * Update the BIOS INT 43h vector (far pointer to the character range 00h-...).
+ */
+ case 8:
+ {
+ if (IS_TEXT_MODE(ModeNumber))
+ VgaWriteTextModeFont(0, Font8x8, ARRAYSIZE(Font8x8) / VGA_FONT_CHARACTERS);
+
+ ((PULONG)BaseAddress)[0x43] = MAKELONG(FONT_8x8_OFFSET, VIDEO_BIOS_DATA_SEG);
+ break;
+ }
+ case 14:
+ {
+ if (IS_TEXT_MODE(ModeNumber))
+ VgaWriteTextModeFont(0, Font8x14, ARRAYSIZE(Font8x14) / VGA_FONT_CHARACTERS);
+
+ ((PULONG)BaseAddress)[0x43] = MAKELONG(FONT_8x14_OFFSET, VIDEO_BIOS_DATA_SEG);
+ break;
+ }
+ case 16:
+ {
+ if (IS_TEXT_MODE(ModeNumber))
+ VgaWriteTextModeFont(0, Font8x16, ARRAYSIZE(Font8x16) / VGA_FONT_CHARACTERS);
+
+ ((PULONG)BaseAddress)[0x43] = MAKELONG(FONT_8x16_OFFSET, VIDEO_BIOS_DATA_SEG);
+ break;
+ }
+ }
+
+#if 0 // Commented, because I need to think about how to change correctly the ScreenRows
+ // in the code that really use it (the Font generator functions of INT 10h, AH=11h)
+ // so that it also changes the screen resolution *in text mode only*.
+ switch (getBL())
+ {
+ case 0x00: Bda->ScreenRows = getDL()-1; break;
+ case 0x01: Bda->ScreenRows = 13; break;
+ case 0x03: Bda->ScreenRows = 42; break;
+ case 0x02:
+ default : Bda->ScreenRows = 24; break;
+ }
+#endif
+
/*
* Update the cursor shape (text-mode only).
* Use the default CGA cursor scanline values,
* see: http://vitaly_filatov.tripod.com/ng/asm/asm_023.2.html
*/
- if ((ModeNumber >= 0x00 && ModeNumber <= 0x03) || (ModeNumber == 0x07))
+ if (IS_TEXT_MODE(ModeNumber))
// FIXME: we might read the CRT registers and do the adjustment?
VidBiosSetCursorShape(MAKEWORD(0x07, 0x06));
for (Page = 0; Page < BIOS_MAX_PAGES; ++Page)
VidBiosSetCursorPosition(0, 0, Page);
- // FIXME: We need to reset the fonts and the font vectors. (INT 1Fh and 43h).
-
- // HACK: We clear here all the text memory. TODO: Do it better!
- if (!DoNotClear && ((ModeNumber >= 0x00 && ModeNumber <= 0x03) || (ModeNumber == 0x07)))
- {
- INT i, j;
- DWORD VideoAddress;
- WORD FillCharacter = MAKEWORD(' ', DEFAULT_ATTRIBUTE);
-
- for (Page = 0; Page < BIOS_MAX_PAGES; ++Page)
- {
- VideoAddress = TO_LINEAR(TEXT_VIDEO_SEG, Page * Bda->VideoPageSize);
-
- for (i = 0; i <= Bda->ScreenRows; i++)
- {
- for (j = 0; j <= Bda->ScreenColumns - 1; j++)
- {
- /* Write to video memory */
- EmulatorWriteMemory(&EmulatorContext,
- VideoAddress + (i * Bda->ScreenColumns + j) * sizeof(WORD),
- (LPVOID)&FillCharacter,
- sizeof(FillCharacter));
- }
- }
- }
- }
+ if (!DoNotClear) VidBiosClearScreen();
/* Refresh display */
VgaRefreshDisplay();
IOWriteB(VGA_CRTC_DATA , HIBYTE(Bda->VideoPageOffset));
/*
- * Get the cursor location (we don't update anything on the BIOS side
- * but we update the cursor location on the VGA side).
+ * Get the cursor position (we don't update anything on the BIOS side
+ * but we update the cursor position on the VGA side).
*/
VidBiosGetCursorPosition(&Row, &Column, PageNumber);
- VidBiosSetCursorPosition(Row, Column, PageNumber);
+ VidBiosSetCursorPosition( Row, Column, PageNumber);
return TRUE;
}
-static VOID VidBiosPrintCharacter(CHAR Character, BYTE Attribute, BYTE Page)
+static VOID VidBiosDrawGlyph(WORD CharData, BOOLEAN UseAttr, BYTE Page, BYTE Row, BYTE Column)
+{
+ switch (Bda->VideoMode)
+ {
+ /* Alphanumeric mode */
+ case 0x00:
+ case 0x01:
+ case 0x02:
+ case 0x03:
+ case 0x07:
+ {
+ EmulatorWriteMemory(&EmulatorContext,
+ TO_LINEAR(TEXT_VIDEO_SEG,
+ Page * Bda->VideoPageSize +
+ (Row * Bda->ScreenColumns + Column) * sizeof(WORD)),
+ (LPVOID)&CharData,
+ UseAttr ? sizeof(WORD) : sizeof(BYTE));
+ break;
+ }
+
+ /* 4-color CGA */
+ case 0x04:
+ case 0x05:
+ {
+ WORD i;
+ WORD CgaSegment[] = { CGA_EVEN_VIDEO_SEG, CGA_ODD_VIDEO_SEG };
+ PUCHAR Font = (PUCHAR)FAR_POINTER(((PULONG)BaseAddress)[0x43]);
+ PUCHAR Glyph = &Font[LOBYTE(CharData) * Bda->CharacterHeight];
+ BOOLEAN Xor = (HIBYTE(CharData) & 0x80) ? TRUE : FALSE;
+ BYTE OldRotate;
+ BYTE DoubledBits[] =
+ {
+ 0x00, 0x03, 0x0C, 0x0F, 0x30, 0x33, 0x3C, 0x3F,
+ 0xC0, 0xC3, 0xCC, 0xCF, 0xF0, 0xF3, 0xFC, 0xFF
+ };
+
+ if (Xor)
+ {
+ /* Set the logical operation to XOR */
+ IOWriteB(VGA_GC_INDEX, VGA_GC_ROTATE_REG);
+ OldRotate = IOReadB(VGA_GC_DATA);
+ IOWriteB(VGA_GC_DATA, OldRotate | 0x18);
+ }
+
+ for (i = 0; i < Bda->CharacterHeight; i++)
+ {
+ WORD Pixel = MAKEWORD(DoubledBits[Glyph[i] >> 4],
+ DoubledBits[Glyph[i] & 0x0F]);
+ if (Xor)
+ {
+ USHORT Dummy;
+
+ /* Read from VGA memory to load the latch register */
+ EmulatorReadMemory(&EmulatorContext,
+ TO_LINEAR(CgaSegment[(Row * Bda->CharacterHeight + i) & 1],
+ (((Row * Bda->CharacterHeight + i) >> 1)
+ * Bda->ScreenColumns + Column) * 2),
+ (LPVOID)&Dummy,
+ sizeof(USHORT));
+ }
+
+ EmulatorWriteMemory(&EmulatorContext,
+ TO_LINEAR(CgaSegment[(Row * Bda->CharacterHeight + i) & 1],
+ (((Row * Bda->CharacterHeight + i) >> 1)
+ * Bda->ScreenColumns + Column) * 2),
+ (LPVOID)&Pixel,
+ sizeof(USHORT));
+ }
+
+ if (Xor)
+ {
+ IOWriteB(VGA_GC_INDEX, VGA_GC_ROTATE_REG);
+ IOWriteB(VGA_GC_DATA, OldRotate);
+ }
+
+ break;
+ }
+
+ /* 2-color CGA */
+ case 0x06:
+ {
+ WORD i;
+ WORD CgaSegment[] = { CGA_EVEN_VIDEO_SEG, CGA_ODD_VIDEO_SEG };
+ PUCHAR Font = (PUCHAR)FAR_POINTER(((PULONG)BaseAddress)[0x43]);
+ PUCHAR Glyph = &Font[LOBYTE(CharData) * Bda->CharacterHeight];
+ BOOLEAN Xor = (HIBYTE(CharData) & 0x80) ? TRUE : FALSE;
+ BYTE OldRotate;
+
+ if (Xor)
+ {
+ /* Set the logical operation to XOR */
+ IOWriteB(VGA_GC_INDEX, VGA_GC_ROTATE_REG);
+ OldRotate = IOReadB(VGA_GC_DATA);
+ IOWriteB(VGA_GC_DATA, OldRotate | 0x18);
+ }
+
+ for (i = 0; i < Bda->CharacterHeight; i++)
+ {
+ if (Xor)
+ {
+ UCHAR Dummy;
+
+ /* Read from VGA memory to load the latch register */
+ EmulatorReadMemory(&EmulatorContext,
+ TO_LINEAR(CgaSegment[(Row * Bda->CharacterHeight + i) & 1],
+ (((Row * Bda->CharacterHeight + i) >> 1)
+ * Bda->ScreenColumns) + Column),
+ (LPVOID)&Dummy,
+ sizeof(UCHAR));
+ }
+
+ EmulatorWriteMemory(&EmulatorContext,
+ TO_LINEAR(CgaSegment[(Row * Bda->CharacterHeight + i) & 1],
+ (((Row * Bda->CharacterHeight + i) >> 1)
+ * Bda->ScreenColumns) + Column),
+ (LPVOID)&Glyph[i],
+ sizeof(UCHAR));
+ }
+
+ if (Xor)
+ {
+ IOWriteB(VGA_GC_INDEX, VGA_GC_ROTATE_REG);
+ IOWriteB(VGA_GC_DATA, OldRotate);
+ }
+
+ break;
+ }
+
+ /* 16-color modes */
+ case 0x0D:
+ case 0x0E:
+ case 0x10:
+ case 0x11:
+ case 0x12:
+ {
+ WORD i;
+ PUCHAR Font = (PUCHAR)FAR_POINTER(((PULONG)BaseAddress)[0x43]);
+ PUCHAR Glyph = &Font[LOBYTE(CharData) * Bda->CharacterHeight];
+ BOOLEAN Xor = (HIBYTE(CharData) & 0x80) ? TRUE : FALSE;
+ BYTE OldPlaneWrite, OldReset, OldEnableReset, OldRotate, OldMode;
+
+ /* Write to all planes */
+ IOWriteB(VGA_SEQ_INDEX, VGA_SEQ_MASK_REG);
+ OldPlaneWrite = IOReadB(VGA_SEQ_DATA);
+ IOWriteB(VGA_SEQ_DATA, 0x0F);
+
+ /* Zero the planes whose bits are set in the enable set/reset register */
+ IOWriteB(VGA_GC_INDEX, VGA_GC_RESET_REG);
+ OldReset = IOReadB(VGA_GC_DATA);
+ IOWriteB(VGA_GC_DATA, 0x00);
+
+ /* Set the enable set/reset register to the inverse of the color */
+ IOWriteB(VGA_GC_INDEX, VGA_GC_ENABLE_RESET_REG);
+ OldEnableReset = IOReadB(VGA_GC_DATA);
+ IOWriteB(VGA_GC_DATA, (~HIBYTE(CharData)) & 0x0F);
+
+ /* Make sure we're in write mode 0 */
+ IOWriteB(VGA_GC_INDEX, VGA_GC_MODE_REG);
+ OldMode = IOReadB(VGA_GC_DATA);
+ IOWriteB(VGA_GC_DATA, 0x00);
+
+ if (Xor)
+ {
+ /* Set the logical operation to XOR */
+ IOWriteB(VGA_GC_INDEX, VGA_GC_ROTATE_REG);
+ OldRotate = IOReadB(VGA_GC_DATA);
+ IOWriteB(VGA_GC_DATA, OldRotate | 0x18);
+ }
+
+ for (i = 0; i < Bda->CharacterHeight; i++)
+ {
+ if (Xor)
+ {
+ UCHAR Dummy;
+
+ /* Read from VGA memory to load the latch register */
+ EmulatorReadMemory(&EmulatorContext,
+ TO_LINEAR(GRAPHICS_VIDEO_SEG,
+ ((Row * Bda->CharacterHeight + i)
+ * Bda->ScreenColumns) + Column),
+ (LPVOID)&Dummy,
+ sizeof(UCHAR));
+ }
+
+ EmulatorWriteMemory(&EmulatorContext,
+ TO_LINEAR(GRAPHICS_VIDEO_SEG,
+ ((Row * Bda->CharacterHeight + i)
+ * Bda->ScreenColumns) + Column),
+ (LPVOID)&Glyph[i],
+ sizeof(UCHAR));
+ }
+
+ /* Restore the registers */
+ IOWriteB(VGA_SEQ_INDEX, VGA_SEQ_MASK_REG);
+ IOWriteB(VGA_SEQ_DATA, OldPlaneWrite);
+ IOWriteB(VGA_GC_INDEX, VGA_GC_RESET_REG);
+ IOWriteB(VGA_GC_DATA, OldReset);
+ IOWriteB(VGA_GC_INDEX, VGA_GC_ENABLE_RESET_REG);
+ IOWriteB(VGA_GC_DATA, OldEnableReset);
+ IOWriteB(VGA_GC_INDEX, VGA_GC_MODE_REG);
+ IOWriteB(VGA_GC_DATA, OldMode);
+
+ if (Xor)
+ {
+ IOWriteB(VGA_GC_INDEX, VGA_GC_ROTATE_REG);
+ IOWriteB(VGA_GC_DATA, OldRotate);
+ }
+
+ break;
+ }
+
+ /* 256-color mode */
+ case 0x13:
+ {
+ WORD i, j;
+ PUCHAR Font = (PUCHAR)FAR_POINTER(((PULONG)BaseAddress)[0x43]);
+ PUCHAR Glyph = &Font[LOBYTE(CharData) * Bda->CharacterHeight];
+ BYTE PixelBuffer[8]; // 8 == CharacterWidth
+
+ for (i = 0; i < Bda->CharacterHeight; i++)
+ {
+ for (j = 0; j < ARRAYSIZE(PixelBuffer); j++)
+ {
+ PixelBuffer[j] = (Glyph[i] & (1 << (7 - j))) ? HIBYTE(CharData) : 0;
+ }
+
+ EmulatorWriteMemory(&EmulatorContext,
+ TO_LINEAR(GRAPHICS_VIDEO_SEG,
+ ((Row * Bda->CharacterHeight + i)
+ * Bda->ScreenColumns + Column) * 8),
+ (LPVOID)PixelBuffer,
+ sizeof(PixelBuffer));
+ }
+
+ break;
+ }
+
+ default:
+ {
+ DPRINT1("Drawing glyphs in mode %02Xh is not supported.\n", Bda->VideoMode);
+ }
+ }
+}
+
+static VOID VidBiosPrintCharacter(CHAR Character, BYTE Attribute, BOOLEAN UseAttr, BYTE Page)
{
WORD CharData = MAKEWORD(Character, Attribute);
BYTE Row, Column;
- /* Make sure the page exists */
- if (Page >= BIOS_MAX_PAGES) return;
-
- /* Get the cursor location */
+ /* Get the cursor position */
VidBiosGetCursorPosition(&Row, &Column, Page);
if (Character == '\a')
/* Erase the existing character */
CharData = MAKEWORD(' ', Attribute);
- EmulatorWriteMemory(&EmulatorContext,
- TO_LINEAR(TEXT_VIDEO_SEG,
- Page * Bda->VideoPageSize +
- (Row * Bda->ScreenColumns + Column) * sizeof(WORD)),
- (LPVOID)&CharData,
- sizeof(WORD));
+ VidBiosDrawGlyph(CharData, UseAttr, Page, Row, Column);
}
else if (Character == '\t')
{
do
{
// Taken from DOSBox
- VidBiosPrintCharacter(' ', Attribute, Page);
+ VidBiosPrintCharacter(' ', Attribute, UseAttr, Page);
VidBiosGetCursorPosition(&Row, &Column, Page);
} while (Column % 8);
}
{
/* Default character */
- /* Write the character */
- EmulatorWriteMemory(&EmulatorContext,
- TO_LINEAR(TEXT_VIDEO_SEG,
- Page * Bda->VideoPageSize +
- (Row * Bda->ScreenColumns + Column) * sizeof(WORD)),
- (LPVOID)&CharData,
- sizeof(WORD));
-
- /* Advance the cursor */
+ /* Write the character and advance the cursor */
+ VidBiosDrawGlyph(CharData, UseAttr, Page, Row, Column);
Column++;
}
/* Set Cursor Position */
case 0x02:
{
- VidBiosSetCursorPosition(getDH(), getDL(), getBH());
+ BYTE Page = getBH();
+
+ /* Validate the selected video page */
+ if (Page >= BIOS_MAX_PAGES) break;
+
+ VidBiosSetCursorPosition(getDH(), getDL(), Page);
break;
}
/* Get Cursor Position and Shape */
case 0x03:
{
- /* Make sure the selected video page exists */
- if (getBH() >= BIOS_MAX_PAGES) break;
+ BYTE Page = getBH();
+
+ /* Validate the selected video page */
+ if (Page == 0xFF) // Special case: use the current video page
+ Page = Bda->VideoPage;
+ else if (Page >= BIOS_MAX_PAGES)
+ break;
/* Return the result */
setCX(MAKEWORD(Bda->CursorEndLine, Bda->CursorStartLine));
- setDX(Bda->CursorPosition[getBH()]);
+ setDX(Bda->CursorPosition[Page]);
break;
}
/* Read Character and Attribute at Cursor Position */
case 0x08:
{
- WORD CharacterData;
+ WORD CharData;
BYTE Page = getBH();
DWORD Offset;
- /* Check if the page exists */
- if (Page >= BIOS_MAX_PAGES) break;
+ /* Validate the selected video page */
+ if (Page == 0xFF) // Special case: use the current video page
+ Page = Bda->VideoPage;
+ else if (Page >= BIOS_MAX_PAGES)
+ break;
/* Find the offset of the character */
Offset = Page * Bda->VideoPageSize +
/* Read from the video memory */
EmulatorReadMemory(&EmulatorContext,
TO_LINEAR(TEXT_VIDEO_SEG, Offset),
- (LPVOID)&CharacterData,
+ (LPVOID)&CharData,
sizeof(WORD));
/* Return the character data in AX */
- setAX(CharacterData);
+ setAX(CharData);
break;
}
/* Write Character only (PCjr: + Attribute) at Cursor Position */
case 0x0A:
{
- WORD CharacterData = MAKEWORD(getAL(), getBL());
- BYTE Page = getBH();
- DWORD Offset, Counter = getCX();
-
- /* Check if the page exists */
- if (Page >= BIOS_MAX_PAGES) break;
+ WORD Counter = getCX();
+ WORD CharData = MAKEWORD(getAL(), getBL());
+ BOOLEAN UseAttr = (getAH() == 0x09);
+ BYTE Page = getBH();
+ BYTE Row, Column;
+
+ /* Validate the selected video page */
+ if (Page == 0xFF) // Special case: use the current video page
+ Page = Bda->VideoPage;
+ else if (Page >= BIOS_MAX_PAGES)
+ break;
- /* Find the offset of the character */
- Offset = Page * Bda->VideoPageSize +
- (HIBYTE(Bda->CursorPosition[Page]) * Bda->ScreenColumns +
- LOBYTE(Bda->CursorPosition[Page])) * 2;
+ /* Get the cursor position */
+ VidBiosGetCursorPosition(&Row, &Column, Page);
/* Write to video memory a certain number of times */
- while (Counter > 0)
+ while (Counter-- > 0)
{
- EmulatorWriteMemory(&EmulatorContext,
- TO_LINEAR(TEXT_VIDEO_SEG, Offset),
- (LPVOID)&CharacterData,
- (getAH() == 0x09) ? sizeof(WORD) : sizeof(BYTE));
- Offset += 2;
- Counter--;
+ /* Write the character and advance the position */
+ VidBiosDrawGlyph(CharData, UseAttr, Page, Row, Column);
+ Column++;
+
+ /* Check if it passed the end of the row */
+ if (Column >= Bda->ScreenColumns)
+ {
+ /* Return to the first column and go to the next line */
+ Column = 0;
+ Row++;
+ }
+
+ /* Contrary to the "Teletype Output" function, the screen is not scrolled */
+ if (Row > Bda->ScreenRows)
+ {
+ Row = Bda->ScreenRows;
+ }
}
break;
/* Teletype Output */
case 0x0E:
{
- VidBiosPrintCharacter(getAL(), getBL(), getBH());
+ BYTE Page = getBH();
+
+ /* Validate the selected video page */
+ if (Page == 0xFF) // Special case: use the current video page
+ Page = Bda->VideoPage;
+ else if (Page >= BIOS_MAX_PAGES)
+ break;
+
+ VidBiosPrintCharacter(getAL(), getBL(), !IS_TEXT_MODE(Bda->VideoMode), Page);
break;
}
/* Set All Palette Registers */
case 0x02:
{
- INT i;
+ UINT i;
LPBYTE Buffer = SEG_OFF_TO_PTR(getES(), getDX());
/* Set the palette registers */
break;
}
+ /* Toggle Intensity/Blinking Bit */
+ case 0x03:
+ {
+ /* Read the old AC mode control register value */
+ BYTE VgaAcControlReg;
+ IOWriteB(VGA_AC_INDEX, VGA_AC_CONTROL_REG);
+ VgaAcControlReg = IOReadB(VGA_AC_READ);
+
+ /* Toggle the blinking bit and write the new value */
+ if (getBL())
+ {
+ VgaAcControlReg |= VGA_AC_CONTROL_BLINK;
+ Bda->CrtModeControl |= (1 << 5);
+ }
+ else
+ {
+ VgaAcControlReg &= ~VGA_AC_CONTROL_BLINK;
+ Bda->CrtModeControl &= ~(1 << 5);
+ }
+
+ IOWriteB(VGA_AC_INDEX, VGA_AC_CONTROL_REG);
+ IOWriteB(VGA_AC_WRITE, VgaAcControlReg);
+
+ /* Enable screen and disable palette access */
+ IOReadB(VGA_INSTAT1_READ); // Put the AC register into index state
+ IOWriteB(VGA_AC_INDEX, 0x20);
+ break;
+ }
+
/* Get Single Palette Register */
case 0x07:
{
/* Get All Palette Registers */
case 0x09:
{
- INT i;
+ UINT i;
LPBYTE Buffer = SEG_OFF_TO_PTR(getES(), getDX());
/* Get the palette registers */
/* Set Block of DAC Registers */
case 0x12:
{
- INT i;
+ UINT i;
LPBYTE Buffer = SEG_OFF_TO_PTR(getES(), getDX());
/* Write the index */
/* Get Block of DAC Registers */
case 0x17:
{
- INT i;
+ UINT i;
LPBYTE Buffer = SEG_OFF_TO_PTR(getES(), getDX());
/* Write the index */
break;
}
+ /* Set PEL Mask */
+ case 0x18:
+ {
+ IOWriteB(VGA_DAC_MASK, getBL());
+ break;
+ }
+
+ /* Get PEL Mask */
+ case 0x19:
+ {
+ setBL(IOReadB(VGA_DAC_MASK));
+ break;
+ }
+
default:
{
DPRINT1("BIOS Palette Control Sub-command AL = 0x%02X NOT IMPLEMENTED\n",
{
switch (getAL())
{
+ // FIXME: At the moment we support only graphics-mode functions!
+
+ /* Load User-specified Patterns (Character Set) for Text Mode */
+ case 0x00:
+ case 0x10: // FIXME: 0x1x performs a full mode reset
+ {
+ // FIXME: BL == ??
+
+ /* Write the default font to the VGA font plane */
+ // VgaWriteTextModeFont(0, Font8x8, ARRAYSIZE(Font8x8) / VGA_FONT_CHARACTERS);
+
+ UNIMPLEMENTED;
+ break;
+ }
+
+ /* Load ROM Monochrome 8x14 Patterns (Character Set) for Text Mode */
+ case 0x01:
+ case 0x11: // FIXME: 0x1x performs a full mode reset
+ {
+ // FIXME: BL == ??
+
+ /* Write the default font to the VGA font plane */
+ VgaWriteTextModeFont(0, Font8x14, ARRAYSIZE(Font8x14) / VGA_FONT_CHARACTERS);
+
+ UNIMPLEMENTED;
+ break;
+ }
+
+ /* Load ROM 8x8 Double-dot Patterns (Character Set) for Text Mode */
+ case 0x02:
+ case 0x12: // FIXME: 0x1x performs a full mode reset
+ {
+ // FIXME: BL == ??
+
+ /* Write the default font to the VGA font plane */
+ VgaWriteTextModeFont(0, Font8x8, ARRAYSIZE(Font8x8) / VGA_FONT_CHARACTERS);
+
+ UNIMPLEMENTED;
+ break;
+ }
+
+ /* Load ROM 8x16 Character Set for Text Mode */
+ case 0x04:
+ case 0x14: // FIXME: 0x1x performs a full mode reset
+ {
+ // FIXME: BL == ??
+
+ /* Write the default font to the VGA font plane */
+ VgaWriteTextModeFont(0, Font8x16, ARRAYSIZE(Font8x16) / VGA_FONT_CHARACTERS);
+
+ UNIMPLEMENTED;
+ break;
+ }
+
/* Set User 8x8 Graphics Chars (Setup INT 1Fh Vector) */
case 0x20:
{
break;
}
- /* Setup ROM 8x8 Font for Graphics Mode */
- case 0x23:
+ /* Set User Graphics Characters */
+ case 0x21:
{
- // FIXME: Use BL and DL for the number of screen rows
+ /*
+ * Update the BIOS INT 43h vector (far pointer
+ * to the character range 00h-...)
+ */
+ ((PULONG)BaseAddress)[0x43] = MAKELONG(getBP(), getES());
- /* Write the default font to the VGA font plane */
- VgaWriteFont(0, Font8x8, sizeof(Font8x8)/sizeof(Font8x8[0]) / VGA_FONT_CHARACTERS);
+ /* Update BDA */
+ Bda->CharacterHeight = getCX();
+ switch (getBL())
+ {
+ case 0x00: Bda->ScreenRows = getDL()-1; break;
+ case 0x01: Bda->ScreenRows = 13; break;
+ case 0x03: Bda->ScreenRows = 42; break;
+ case 0x02:
+ default : Bda->ScreenRows = 24; break;
+ }
+
+ break;
+ }
- /* Update the BIOS INT 43h vector */
- // Far pointer to the 8x8 characters 00h-...
+ /* Setup ROM 8x14 Font for Graphics Mode */
+ case 0x22:
+ {
+ /*
+ * Update the BIOS INT 43h vector (far pointer
+ * to the character range 00h-...)
+ */
+ ((PULONG)BaseAddress)[0x43] = MAKELONG(FONT_8x14_OFFSET, VIDEO_BIOS_DATA_SEG);
+
+ /* Update BDA */
+ Bda->CharacterHeight = 14;
+ switch (getBL())
+ {
+ case 0x00: Bda->ScreenRows = getDL()-1; break;
+ case 0x01: Bda->ScreenRows = 13; break;
+ case 0x03: Bda->ScreenRows = 42; break;
+ case 0x02:
+ default : Bda->ScreenRows = 24; break;
+ }
+
+ break;
+ }
+
+ /* Setup ROM 8x8 Font for Graphics Mode */
+ case 0x23:
+ {
+ /*
+ * Update the BIOS INT 43h vector (far pointer
+ * to the character range 00h-...)
+ */
((PULONG)BaseAddress)[0x43] = MAKELONG(FONT_8x8_OFFSET, VIDEO_BIOS_DATA_SEG);
+ /* Update BDA */
+ Bda->CharacterHeight = 8;
+ switch (getBL())
+ {
+ case 0x00: Bda->ScreenRows = getDL()-1; break;
+ case 0x01: Bda->ScreenRows = 13; break;
+ case 0x03: Bda->ScreenRows = 42; break;
+ case 0x02:
+ default : Bda->ScreenRows = 24; break;
+ }
+
break;
}
/* Setup ROM 8x16 Font for Graphics Mode */
case 0x24:
{
- // FIXME: Use BL and DL for the number of screen rows
-
- /* Write the default font to the VGA font plane */
- VgaWriteFont(0, Font8x16, sizeof(Font8x16)/sizeof(Font8x16[0]) / VGA_FONT_CHARACTERS);
-
- /* Update the BIOS INT 43h vector */
- // Far pointer to the 8x16 characters 00h-...
+ /*
+ * Update the BIOS INT 43h vector (far pointer
+ * to the character range 00h-...).
+ */
((PULONG)BaseAddress)[0x43] = MAKELONG(FONT_8x16_OFFSET, VIDEO_BIOS_DATA_SEG);
+ /* Update BDA */
+ Bda->CharacterHeight = 16;
+ switch (getBL())
+ {
+ case 0x00: Bda->ScreenRows = getDL()-1; break;
+ case 0x01: Bda->ScreenRows = 13; break;
+ case 0x03: Bda->ScreenRows = 42; break;
+ case 0x02:
+ default : Bda->ScreenRows = 24; break;
+ }
+
break;
}
/* Write String */
case 0x13:
{
- DPRINT1("BIOS Function INT 13h (Write String) is UNIMPLEMENTED\n");
+ PCHAR String = (PCHAR)SEG_OFF_TO_PTR(getES(), getBP());
+ WORD Counter = getCX();
+ BYTE Row, Column;
+ BYTE OldRow, OldColumn;
+ CHAR Character;
+ BYTE Attribute = getBL(); // Default attribute in case the string contains only characters.
+ BYTE Page = getBH();
+ BYTE Flags = getAL();
+
+ /* Validate the selected video page */
+ if (Page == 0xFF) // Special case: use the current video page
+ Page = Bda->VideoPage;
+ else if (Page >= BIOS_MAX_PAGES)
+ break;
+
+ /* Get the original cursor position */
+ VidBiosGetCursorPosition(&OldRow, &OldColumn, Page);
+
+ /* Set the new cursor position */
+ Row = getDH();
+ Column = getDL();
+ if (Row == 0xFF) // Special case: use the current cursor position
+ {
+ Row = OldRow;
+ Column = OldColumn;
+ }
+ VidBiosSetCursorPosition(Row, Column, Page);
+
+ while (Counter-- > 0)
+ {
+ Character = *String++;
+ if (Flags & 0x02) Attribute = *String++;
+ VidBiosPrintCharacter(Character, Attribute, TRUE, Page);
+ }
+
+ /* Reset the cursor position to its original value if we don't want to update it */
+ if (!(Flags & 0x01)) VidBiosSetCursorPosition(OldRow, OldColumn, Page);
+
break;
}
switch (getAL())
{
case 0x00: /* Get Display combination code */
- setAX(MAKEWORD(0x1A, 0x1A));
- setBX(MAKEWORD(0x08, 0x00)); /* VGA w/ color analog display */
- break;
+ {
+ setBL(Bda->VGADccIDActive);
+ setBH(0x00); // No alternate display
+
+ /* Return success */
+ setAL(0x1A);
+ break;
+ }
case 0x01: /* Set Display combination code */
- DPRINT1("Set Display combination code - Unsupported\n");
- break;
+ {
+ DPRINT1("Set Display combination code - Unsupported\n");
+ break;
+ }
default:
- break;
+ break;
}
break;
}
+ /* Functionality/State Information (VGA) */
+ case 0x1B:
+ {
+ PVGA_DYNAMIC_FUNC_TABLE Table = SEG_OFF_TO_PTR(getES(), getDI());
+
+ /* Check for only supported subfunction */
+ if (getBX() != 0x0000)
+ {
+ DPRINT1("INT 10h, AH=1Bh, unsupported subfunction 0x%04x\n", getBX());
+ break;
+ }
+
+ /* Fill the VGA dynamic functionality table with our information */
+
+ Table->StaticFuncTablePtr = MAKELONG(VIDEO_STATE_INFO_OFFSET, VIDEO_BIOS_DATA_SEG);
+
+ Table->VideoMode = Bda->VideoMode;
+ Table->ScreenColumns = Bda->ScreenColumns;
+ Table->VideoPageSize = Bda->VideoPageSize;
+ Table->VideoPageOffset = Bda->VideoPageOffset;
+ RtlCopyMemory(Table->CursorPosition, Bda->CursorPosition, sizeof(Bda->CursorPosition));
+ Table->CursorEndLine = Bda->CursorEndLine;
+ Table->CursorStartLine = Bda->CursorStartLine;
+ Table->VideoPage = Bda->VideoPage;
+ Table->CrtBasePort = Bda->CrtBasePort;
+ Table->CrtModeControl = Bda->CrtModeControl;
+ Table->CrtColorPaletteMask = Bda->CrtColorPaletteMask;
+ Table->ScreenRows = Bda->ScreenRows;
+ Table->CharacterHeight = Bda->CharacterHeight;
+
+ Table->VGADccIDActive = Bda->VGADccIDActive;
+ Table->VGADccIDAlternate = 0x00; // No alternate display
+ // Table->CurrModeSupportedColorsNum;
+ // Table->CurrModeSupportedPagesNum;
+ // Table->Scanlines;
+ // Table->PrimaryCharTable;
+ // Table->SecondaryCharTable;
+ // Table->VGAFlags;
+ Table->VGAAvailMemory = (Bda->VGAOptions & 0x60) >> 5;
+ // Table->VGASavePtrStateFlags;
+ // Table->VGADispInfo;
+ UNIMPLEMENTED;
+
+ /* Return success */
+ setAL(0x1B);
+ break;
+ }
+
+ /* VESA BIOS Extensions */
+ case 0x4F:
+ {
+ if (VbeInitialized) VbeService(Stack);
+ break;
+ }
+
default:
{
DPRINT1("BIOS Function INT 10h, AH = 0x%02X, AL = 0x%02X, BH = 0x%02X NOT IMPLEMENTED\n",
VOID VidBiosAttachToConsole(VOID)
{
- // VgaRefreshDisplay();
if (!Attached)
{
VgaAttachToConsole();
Attached = TRUE;
}
+ /* Refresh display */
VgaRefreshDisplay();
VidBiosSyncCursorPosition();
}
VOID VidBiosDetachFromConsole(VOID)
{
- /* Perform another screen refresh */
+ if (!Attached) return;
+
+ /* Refresh display */
VgaRefreshDisplay();
/* Detach from the console */
- VgaDetachFromConsole(FALSE);
+ VgaDetachFromConsole();
Attached = FALSE;
}
-BOOLEAN VidBiosInitialize(VOID)
+VOID VidBiosPost(VOID)
{
- /* Some interrupts are in fact addresses to tables */
- ((PULONG)BaseAddress)[0x1D] = (ULONG)NULL;
- // Far pointer to the 8x8 characters 80h-FFh
+ /*
+ * Initialize VGA BIOS32 RAM dynamic data
+ */
+
+ /* Some vectors are in fact addresses to tables */
+ ((PULONG)BaseAddress)[0x1D] = (ULONG)NULL; // Video Parameter Tables
+ // Far pointer to the 8x8 graphics font for the 8x8 characters 80h-FFh
((PULONG)BaseAddress)[0x1F] = MAKELONG(FONT_8x8_HIGH_OFFSET, VIDEO_BIOS_DATA_SEG);
- // ((PULONG)BaseAddress)[0x42] = (ULONG)NULL;
- // Far pointer to the 8x16 characters 00h-...
+ // Far pointer to the character table (EGA, MCGA, VGA) for the 8x16 characters 00h-...
((PULONG)BaseAddress)[0x43] = MAKELONG(FONT_8x16_OFFSET, VIDEO_BIOS_DATA_SEG);
- ((PULONG)BaseAddress)[0x44] = (ULONG)NULL;
- // ((PULONG)BaseAddress)[0x6D] = (ULONG)NULL;
+ ((PULONG)BaseAddress)[0x44] = (ULONG)NULL; // ROM BIOS Character Font, Characters 00h-7Fh (PCjr)
- /* Fill the tables */
- RtlMoveMemory(SEG_OFF_TO_PTR(VIDEO_BIOS_DATA_SEG, FONT_8x8_OFFSET),
- Font8x8, sizeof(Font8x8));
- RtlMoveMemory(SEG_OFF_TO_PTR(VIDEO_BIOS_DATA_SEG, FONT_8x16_OFFSET),
- Font8x16, sizeof(Font8x16));
- RtlMoveMemory(SEG_OFF_TO_PTR(VIDEO_BIOS_DATA_SEG, FONT_8x14_OFFSET),
- Font8x14, sizeof(Font8x14));
-
- /* Write the default font to the VGA font plane */
- VgaWriteFont(0, Font8x16, sizeof(Font8x16)/sizeof(Font8x16[0]) / VGA_FONT_CHARACTERS);
+ /* Relocated services by the BIOS (when needed) */
+ ((PULONG)BaseAddress)[0x42] = (ULONG)NULL; // Relocated Default INT 10h Video Services
+ ((PULONG)BaseAddress)[0x6D] = (ULONG)NULL; // Video BIOS Entry Point
//
// FIXME: At the moment we always set a VGA mode. In the future,
// (that should be done here, or maybe in VGA ??)
//
+ Bda->CrtModeControl = 0x00;
+ Bda->CrtColorPaletteMask = 0x00;
+ Bda->VGADccIDActive = 0x08; // VGA w/ color analog active display
+
/* Set the default video mode */
VidBiosSetVideoMode(BIOS_DEFAULT_VIDEO_MODE);
/* Synchronize our cursor position with VGA */
VidBiosSyncCursorPosition();
- /* Register the BIOS support BOPs */
- RegisterBop(BOP_VIDEO_INT, VidBiosVideoService);
+ /* Register the BIOS 32-bit Interrupts */
+ RegisterBiosInt32(BIOS_VIDEO_INTERRUPT, VidBiosVideoService);
+
+ /* Vectors that should be implemented */
+ RegisterBiosInt32(0x42, NULL); // Relocated Default INT 10h Video Services
+ RegisterBiosInt32(0x6D, NULL); // Video BIOS Entry Point
+
+ /* Initialize VBE */
+ VbeInitialized = VbeInitialize();
+ if (!VbeInitialized) DPRINT1("Couldn't initialize VBE!\n");
+}
+
+BOOLEAN VidBiosInitialize(VOID)
+{
+ UCHAR Checksum;
+
+ /*
+ * Initialize VGA BIOS32 static data
+ */
+
+ /* This is a ROM of size 'VIDEO_BIOS_ROM_SIZE' */
+ *(PWORD)(SEG_OFF_TO_PTR(VIDEO_BIOS_DATA_SEG, 0x0000)) = 0xAA55;
+ *(PBYTE)(SEG_OFF_TO_PTR(VIDEO_BIOS_DATA_SEG, 0x0002)) = VIDEO_BIOS_ROM_SIZE / 512; // Size in blocks of 512 bytes
+
+ /* Bootstrap code */
+ *(PWORD)(SEG_OFF_TO_PTR(VIDEO_BIOS_DATA_SEG, 0x0003)) = 0x90CB; // retf, nop
+ // RtlCopyMemory(SEG_OFF_TO_PTR(VIDEO_BIOS_DATA_SEG, 0xFFF0), Bootstrap, sizeof(Bootstrap));
+
+ /* Video BIOS Information */
+ RtlCopyMemory(SEG_OFF_TO_PTR(VIDEO_BIOS_DATA_SEG, 0x0005), BiosInfo, sizeof(BiosInfo)-1);
+
+ /* Initialize the VGA static function table */
+ VgaStaticFuncTable = SEG_OFF_TO_PTR(VIDEO_BIOS_DATA_SEG, VIDEO_STATE_INFO_OFFSET);
+ RtlZeroMemory(VgaStaticFuncTable, sizeof(*VgaStaticFuncTable));
+ VgaStaticFuncTable->SupportedModes[0] = 0xFF; // Modes 0x00 to 0x07 supported
+ VgaStaticFuncTable->SupportedModes[1] = 0xFF; // Modes 0x08 to 0x0F supported
+ VgaStaticFuncTable->SupportedModes[2] = 0x0F; // Modes 0x10 to 0x13 supported
+ VgaStaticFuncTable->SupportedScanlines = 0x07; // Scanlines 200, 350 and 400 supported
+ VgaStaticFuncTable->TextCharBlocksNumber = 0;
+ VgaStaticFuncTable->MaxActiveTextCharBlocksNumber = 0;
+ VgaStaticFuncTable->VGAFuncSupportFlags = 0x0CFD; // See: http://www.ctyme.com/intr/rb-0221.htm#Table46
+ VgaStaticFuncTable->VGASavePtrFuncFlags = 0x18; // See: http://www.ctyme.com/intr/rb-0221.htm#Table47
+
+ /* Fill the font tables */
+ RtlMoveMemory(SEG_OFF_TO_PTR(VIDEO_BIOS_DATA_SEG, FONT_8x8_OFFSET),
+ Font8x8, sizeof(Font8x8));
+ RtlMoveMemory(SEG_OFF_TO_PTR(VIDEO_BIOS_DATA_SEG, FONT_8x16_OFFSET),
+ Font8x16, sizeof(Font8x16));
+ RtlMoveMemory(SEG_OFF_TO_PTR(VIDEO_BIOS_DATA_SEG, FONT_8x14_OFFSET),
+ Font8x14, sizeof(Font8x14));
+
+ VidBios32Initialize();
+
+ /* Compute the ROM checksum and store it */
+ *(PBYTE)(SEG_OFF_TO_PTR(VIDEO_BIOS_DATA_SEG, VIDEO_BIOS_ROM_SIZE - 1)) = 0x00;
+ Checksum = CalcRomChecksum(TO_LINEAR(VIDEO_BIOS_DATA_SEG, 0x0000), VIDEO_BIOS_ROM_SIZE);
+ *(PBYTE)(SEG_OFF_TO_PTR(VIDEO_BIOS_DATA_SEG, VIDEO_BIOS_ROM_SIZE - 1)) = (0xFF - Checksum + 1) & 0xFF;
+
+ WriteProtectRom((PVOID)TO_LINEAR(VIDEO_BIOS_DATA_SEG, 0x0000),
+ VIDEO_BIOS_ROM_SIZE);
return TRUE;
}