From 7395dd7c82263d3b74367af87a57cc33495fc6f3 Mon Sep 17 00:00:00 2001 From: Aleksandar Andrejevic Date: Tue, 9 Jun 2015 04:03:27 +0000 Subject: [PATCH] [NTVDM] Implement drawing characters for all supported video modes. svn path=/trunk/; revision=68086 --- reactos/subsystems/mvdm/ntvdm/bios/vidbios.c | 269 +++++++++++++++++-- reactos/subsystems/mvdm/ntvdm/bios/vidbios.h | 2 + 2 files changed, 247 insertions(+), 24 deletions(-) diff --git a/reactos/subsystems/mvdm/ntvdm/bios/vidbios.c b/reactos/subsystems/mvdm/ntvdm/bios/vidbios.c index 9543c17f933..7717e4c853b 100644 --- a/reactos/subsystems/mvdm/ntvdm/bios/vidbios.c +++ b/reactos/subsystems/mvdm/ntvdm/bios/vidbios.c @@ -2561,8 +2561,245 @@ static BOOLEAN VidBiosSetVideoPage(BYTE PageNumber) return TRUE; } -static VOID VidBiosPrintCharacter(CHAR Character, BYTE Attribute, BYTE Page) +static VOID VidBiosDrawGlyph(WORD CharData, BYTE Page, BYTE Row, BYTE Column) { + switch (Bda->VideoMode) + { + /* Alphanumeric mode */ + case 0x00: + case 0x01: + case 0x02: + case 0x03: + { + EmulatorWriteMemory(&EmulatorContext, + TO_LINEAR(TEXT_VIDEO_SEG, + Page * Bda->VideoPageSize + + (Row * Bda->ScreenColumns + Column) * sizeof(WORD)), + (LPVOID)&CharData, + sizeof(WORD)); + + 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 + i) & 1], + ((((Row + i) >> 1) * Bda->ScreenColumns) >> 2) + Column * 2), + (LPVOID)&Dummy, + sizeof(USHORT)); + } + + EmulatorWriteMemory(&EmulatorContext, + TO_LINEAR(CgaSegment[(Row + i) & 1], + ((((Row + i) >> 1) * Bda->ScreenColumns) >> 2) + 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 + i) & 1], + ((((Row + i) >> 1) * Bda->ScreenColumns) >> 3) + Column), + (LPVOID)&Dummy, + sizeof(UCHAR)); + } + + EmulatorWriteMemory(&EmulatorContext, + TO_LINEAR(CgaSegment[(Row + i) & 1], + ((((Row + i) >> 1) * Bda->ScreenColumns) >> 3) + 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 + i) * Bda->ScreenColumns) >> 3) + Column), + (LPVOID)&Dummy, + sizeof(UCHAR)); + } + + EmulatorWriteMemory(&EmulatorContext, + TO_LINEAR(GRAPHICS_VIDEO_SEG, + (((Row + i) * Bda->ScreenColumns) >> 3) + 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]; + + for (i = 0; i < Bda->CharacterHeight; i++) + { + for (j = 0; j < 8; j++) + { + PixelBuffer[j] = (Glyph[i] & (1 << (7 - j))) ? HIBYTE(CharData) : 0; + } + + EmulatorWriteMemory(&EmulatorContext, + TO_LINEAR(GRAPHICS_VIDEO_SEG, + (Row + 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, BYTE Page) + { WORD CharData = MAKEWORD(Character, Attribute); BYTE Row, Column; @@ -2594,12 +2831,7 @@ static VOID VidBiosPrintCharacter(CHAR Character, BYTE Attribute, BYTE Page) /* 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, Page, Row, Column); } else if (Character == '\t') { @@ -2626,12 +2858,7 @@ static VOID VidBiosPrintCharacter(CHAR Character, BYTE Attribute, BYTE Page) /* 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)); + VidBiosDrawGlyph(CharData, Page, Row, Column); /* Advance the cursor */ Column++; @@ -2761,24 +2988,18 @@ VOID WINAPI VidBiosVideoService(LPWORD Stack) { WORD CharacterData = MAKEWORD(getAL(), getBL()); BYTE Page = getBH(); - DWORD Offset, Counter = getCX(); + DWORD Counter = getCX(); /* Check if the page exists */ 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; - /* Write to video memory a certain number of times */ while (Counter > 0) { - EmulatorWriteMemory(&EmulatorContext, - TO_LINEAR(TEXT_VIDEO_SEG, Offset), - (LPVOID)&CharacterData, - (getAH() == 0x09) ? sizeof(WORD) : sizeof(BYTE)); - Offset += 2; + VidBiosDrawGlyph(CharacterData, + CharacterData, + HIBYTE(Bda->CursorPosition[Page]), + LOBYTE(Bda->CursorPosition[Page])); Counter--; } diff --git a/reactos/subsystems/mvdm/ntvdm/bios/vidbios.h b/reactos/subsystems/mvdm/ntvdm/bios/vidbios.h index 105874290aa..50dafcedf5b 100644 --- a/reactos/subsystems/mvdm/ntvdm/bios/vidbios.h +++ b/reactos/subsystems/mvdm/ntvdm/bios/vidbios.h @@ -22,6 +22,8 @@ #define GRAPHICS_VIDEO_SEG 0xA000 #define TEXT_VIDEO_SEG 0xB800 +#define CGA_EVEN_VIDEO_SEG 0xB800 +#define CGA_ODD_VIDEO_SEG 0xBA00 #define VIDEO_BIOS_DATA_SEG 0xC000 #define FONT_8x8_OFFSET 0x0000