1 /* 2 * COPYRIGHT: GPL - See COPYING in the top level directory 3 * PROJECT: ReactOS Virtual DOS Machine 4 * FILE: subsystems/mvdm/ntvdm/hardware/video/svga.c 5 * PURPOSE: SuperVGA hardware emulation (Cirrus Logic CL-GD5434 compatible) 6 * PROGRAMMERS: Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org> 7 */ 8 9 /* INCLUDES *******************************************************************/ 10 11 #include "ntvdm.h" 12 13 #define NDEBUG 14 #include <debug.h> 15 16 #include "emulator.h" 17 #include "svga.h" 18 #include <bios/vidbios.h> 19 20 #include "memory.h" 21 #include "io.h" 22 #include "clock.h" 23 24 #include "../../console/video.h" 25 26 /* PRIVATE VARIABLES **********************************************************/ 27 28 #define WRAP_OFFSET(x) ((VgaCrtcRegisters[SVGA_CRTC_EXT_DISPLAY_REG] & SVGA_CRTC_EXT_ADDR_WRAP) \ 29 ? ((x) & 0xFFFFF) : LOWORD(x)) 30 31 static CONST DWORD MemoryBase[] = { 0xA0000, 0xA0000, 0xB0000, 0xB8000 }; 32 static CONST DWORD MemorySize[] = { 0x20000, 0x10000, 0x08000, 0x08000 }; 33 34 #define USE_REACTOS_COLORS 35 // #define USE_DOSBOX_COLORS 36 37 #if defined(USE_REACTOS_COLORS) 38 39 // ReactOS colors 40 static CONST COLORREF VgaDefaultPalette[VGA_MAX_COLORS] = 41 { 42 RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0xAA), RGB(0x00, 0xAA, 0x00), RGB(0x00, 0xAA, 0xAA), 43 RGB(0xAA, 0x00, 0x00), RGB(0xAA, 0x00, 0xAA), RGB(0xAA, 0x55, 0x00), RGB(0xAA, 0xAA, 0xAA), 44 RGB(0x55, 0x55, 0x55), RGB(0x55, 0x55, 0xFF), RGB(0x55, 0xFF, 0x55), RGB(0x55, 0xFF, 0xFF), 45 RGB(0xFF, 0x55, 0x55), RGB(0xFF, 0x55, 0xFF), RGB(0xFF, 0xFF, 0x55), RGB(0xFF, 0xFF, 0xFF), 46 RGB(0x00, 0x00, 0x00), RGB(0x10, 0x10, 0x10), RGB(0x20, 0x20, 0x20), RGB(0x35, 0x35, 0x35), 47 RGB(0x45, 0x45, 0x45), RGB(0x55, 0x55, 0x55), RGB(0x65, 0x65, 0x65), RGB(0x75, 0x75, 0x75), 48 RGB(0x8A, 0x8A, 0x8A), RGB(0x9A, 0x9A, 0x9A), RGB(0xAA, 0xAA, 0xAA), RGB(0xBA, 0xBA, 0xBA), 49 RGB(0xCA, 0xCA, 0xCA), RGB(0xDF, 0xDF, 0xDF), RGB(0xEF, 0xEF, 0xEF), RGB(0xFF, 0xFF, 0xFF), 50 RGB(0x00, 0x00, 0xFF), RGB(0x41, 0x00, 0xFF), RGB(0x82, 0x00, 0xFF), RGB(0xBE, 0x00, 0xFF), 51 RGB(0xFF, 0x00, 0xFF), RGB(0xFF, 0x00, 0xBE), RGB(0xFF, 0x00, 0x82), RGB(0xFF, 0x00, 0x41), 52 RGB(0xFF, 0x00, 0x00), RGB(0xFF, 0x41, 0x00), RGB(0xFF, 0x82, 0x00), RGB(0xFF, 0xBE, 0x00), 53 RGB(0xFF, 0xFF, 0x00), RGB(0xBE, 0xFF, 0x00), RGB(0x82, 0xFF, 0x00), RGB(0x41, 0xFF, 0x00), 54 RGB(0x00, 0xFF, 0x00), RGB(0x00, 0xFF, 0x41), RGB(0x00, 0xFF, 0x82), RGB(0x00, 0xFF, 0xBE), 55 RGB(0x00, 0xFF, 0xFF), RGB(0x00, 0xBE, 0xFF), RGB(0x00, 0x82, 0xFF), RGB(0x00, 0x41, 0xFF), 56 RGB(0x82, 0x82, 0xFF), RGB(0x9E, 0x82, 0xFF), RGB(0xBE, 0x82, 0xFF), RGB(0xDF, 0x82, 0xFF), 57 RGB(0xFF, 0x82, 0xFF), RGB(0xFF, 0x82, 0xDF), RGB(0xFF, 0x82, 0xBE), RGB(0xFF, 0x82, 0x9E), 58 RGB(0xFF, 0x82, 0x82), RGB(0xFF, 0x9E, 0x82), RGB(0xFF, 0xBE, 0x82), RGB(0xFF, 0xDF, 0x82), 59 RGB(0xFF, 0xFF, 0x82), RGB(0xDF, 0xFF, 0x82), RGB(0xBE, 0xFF, 0x82), RGB(0x9E, 0xFF, 0x82), 60 RGB(0x82, 0xFF, 0x82), RGB(0x82, 0xFF, 0x9E), RGB(0x82, 0xFF, 0xBE), RGB(0x82, 0xFF, 0xDF), 61 RGB(0x82, 0xFF, 0xFF), RGB(0x82, 0xDF, 0xFF), RGB(0x82, 0xBE, 0xFF), RGB(0x82, 0x9E, 0xFF), 62 RGB(0xBA, 0xBA, 0xFF), RGB(0xCA, 0xBA, 0xFF), RGB(0xDF, 0xBA, 0xFF), RGB(0xEF, 0xBA, 0xFF), 63 RGB(0xFF, 0xBA, 0xFF), RGB(0xFF, 0xBA, 0xEF), RGB(0xFF, 0xBA, 0xDF), RGB(0xFF, 0xBA, 0xCA), 64 RGB(0xFF, 0xBA, 0xBA), RGB(0xFF, 0xCA, 0xBA), RGB(0xFF, 0xDF, 0xBA), RGB(0xFF, 0xEF, 0xBA), 65 RGB(0xFF, 0xFF, 0xBA), RGB(0xEF, 0xFF, 0xBA), RGB(0xDF, 0xFF, 0xBA), RGB(0xCA, 0xFF, 0xBA), 66 RGB(0xBA, 0xFF, 0xBA), RGB(0xBA, 0xFF, 0xCA), RGB(0xBA, 0xFF, 0xDF), RGB(0xBA, 0xFF, 0xEF), 67 RGB(0xBA, 0xFF, 0xFF), RGB(0xBA, 0xEF, 0xFF), RGB(0xBA, 0xDF, 0xFF), RGB(0xBA, 0xCA, 0xFF), 68 RGB(0x00, 0x00, 0x71), RGB(0x1C, 0x00, 0x71), RGB(0x39, 0x00, 0x71), RGB(0x55, 0x00, 0x71), 69 RGB(0x71, 0x00, 0x71), RGB(0x71, 0x00, 0x55), RGB(0x71, 0x00, 0x39), RGB(0x71, 0x00, 0x1C), 70 RGB(0x71, 0x00, 0x00), RGB(0x71, 0x1C, 0x00), RGB(0x71, 0x39, 0x00), RGB(0x71, 0x55, 0x00), 71 RGB(0x71, 0x71, 0x00), RGB(0x55, 0x71, 0x00), RGB(0x39, 0x71, 0x00), RGB(0x1C, 0x71, 0x00), 72 RGB(0x00, 0x71, 0x00), RGB(0x00, 0x71, 0x1C), RGB(0x00, 0x71, 0x39), RGB(0x00, 0x71, 0x55), 73 RGB(0x00, 0x71, 0x71), RGB(0x00, 0x55, 0x71), RGB(0x00, 0x39, 0x71), RGB(0x00, 0x1C, 0x71), 74 RGB(0x39, 0x39, 0x71), RGB(0x45, 0x39, 0x71), RGB(0x55, 0x39, 0x71), RGB(0x61, 0x39, 0x71), 75 RGB(0x71, 0x39, 0x71), RGB(0x71, 0x39, 0x61), RGB(0x71, 0x39, 0x55), RGB(0x71, 0x39, 0x45), 76 RGB(0x71, 0x39, 0x39), RGB(0x71, 0x45, 0x39), RGB(0x71, 0x55, 0x39), RGB(0x71, 0x61, 0x39), 77 RGB(0x71, 0x71, 0x39), RGB(0x61, 0x71, 0x39), RGB(0x55, 0x71, 0x39), RGB(0x45, 0x71, 0x39), 78 RGB(0x39, 0x71, 0x39), RGB(0x39, 0x71, 0x45), RGB(0x39, 0x71, 0x55), RGB(0x39, 0x71, 0x61), 79 RGB(0x39, 0x71, 0x71), RGB(0x39, 0x61, 0x71), RGB(0x39, 0x55, 0x71), RGB(0x39, 0x45, 0x71), 80 RGB(0x51, 0x51, 0x71), RGB(0x59, 0x51, 0x71), RGB(0x61, 0x51, 0x71), RGB(0x69, 0x51, 0x71), 81 RGB(0x71, 0x51, 0x71), RGB(0x71, 0x51, 0x69), RGB(0x71, 0x51, 0x61), RGB(0x71, 0x51, 0x59), 82 RGB(0x71, 0x51, 0x51), RGB(0x71, 0x59, 0x51), RGB(0x71, 0x61, 0x51), RGB(0x71, 0x69, 0x51), 83 RGB(0x71, 0x71, 0x51), RGB(0x69, 0x71, 0x51), RGB(0x61, 0x71, 0x51), RGB(0x59, 0x71, 0x51), 84 RGB(0x51, 0x71, 0x51), RGB(0x51, 0x71, 0x59), RGB(0x51, 0x71, 0x61), RGB(0x51, 0x71, 0x69), 85 RGB(0x51, 0x71, 0x71), RGB(0x51, 0x69, 0x71), RGB(0x51, 0x61, 0x71), RGB(0x51, 0x59, 0x71), 86 RGB(0x00, 0x00, 0x41), RGB(0x10, 0x00, 0x41), RGB(0x20, 0x00, 0x41), RGB(0x31, 0x00, 0x41), 87 RGB(0x41, 0x00, 0x41), RGB(0x41, 0x00, 0x31), RGB(0x41, 0x00, 0x20), RGB(0x41, 0x00, 0x10), 88 RGB(0x41, 0x00, 0x00), RGB(0x41, 0x10, 0x00), RGB(0x41, 0x20, 0x00), RGB(0x41, 0x31, 0x00), 89 RGB(0x41, 0x41, 0x00), RGB(0x31, 0x41, 0x00), RGB(0x20, 0x41, 0x00), RGB(0x10, 0x41, 0x00), 90 RGB(0x00, 0x41, 0x00), RGB(0x00, 0x41, 0x10), RGB(0x00, 0x41, 0x20), RGB(0x00, 0x41, 0x31), 91 RGB(0x00, 0x41, 0x41), RGB(0x00, 0x31, 0x41), RGB(0x00, 0x20, 0x41), RGB(0x00, 0x10, 0x41), 92 RGB(0x20, 0x20, 0x41), RGB(0x28, 0x20, 0x41), RGB(0x31, 0x20, 0x41), RGB(0x39, 0x20, 0x41), 93 RGB(0x41, 0x20, 0x41), RGB(0x41, 0x20, 0x39), RGB(0x41, 0x20, 0x31), RGB(0x41, 0x20, 0x28), 94 RGB(0x41, 0x20, 0x20), RGB(0x41, 0x28, 0x20), RGB(0x41, 0x31, 0x20), RGB(0x41, 0x39, 0x20), 95 RGB(0x41, 0x41, 0x20), RGB(0x39, 0x41, 0x20), RGB(0x31, 0x41, 0x20), RGB(0x28, 0x41, 0x20), 96 RGB(0x20, 0x41, 0x20), RGB(0x20, 0x41, 0x28), RGB(0x20, 0x41, 0x31), RGB(0x20, 0x41, 0x39), 97 RGB(0x20, 0x41, 0x41), RGB(0x20, 0x39, 0x41), RGB(0x20, 0x31, 0x41), RGB(0x20, 0x28, 0x41), 98 RGB(0x2D, 0x2D, 0x41), RGB(0x31, 0x2D, 0x41), RGB(0x35, 0x2D, 0x41), RGB(0x3D, 0x2D, 0x41), 99 RGB(0x41, 0x2D, 0x41), RGB(0x41, 0x2D, 0x3D), RGB(0x41, 0x2D, 0x35), RGB(0x41, 0x2D, 0x31), 100 RGB(0x41, 0x2D, 0x2D), RGB(0x41, 0x31, 0x2D), RGB(0x41, 0x35, 0x2D), RGB(0x41, 0x3D, 0x2D), 101 RGB(0x41, 0x41, 0x2D), RGB(0x3D, 0x41, 0x2D), RGB(0x35, 0x41, 0x2D), RGB(0x31, 0x41, 0x2D), 102 RGB(0x2D, 0x41, 0x2D), RGB(0x2D, 0x41, 0x31), RGB(0x2D, 0x41, 0x35), RGB(0x2D, 0x41, 0x3D), 103 RGB(0x2D, 0x41, 0x41), RGB(0x2D, 0x3D, 0x41), RGB(0x2D, 0x35, 0x41), RGB(0x2D, 0x31, 0x41), 104 RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00), 105 RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00) 106 }; 107 108 #elif defined(USE_DOSBOX_COLORS) 109 110 // DOSBox colors 111 static CONST COLORREF VgaDefaultPalette[VGA_MAX_COLORS] = 112 { 113 RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0xAA), RGB(0x00, 0xAA, 0x00), RGB(0x00, 0xAA, 0xAA), 114 RGB(0xAA, 0x00, 0x00), RGB(0xAA, 0x00, 0xAA), RGB(0xAA, 0x55, 0x00), RGB(0xAA, 0xAA, 0xAA), 115 RGB(0x55, 0x55, 0x55), RGB(0x55, 0x55, 0xFF), RGB(0x55, 0xFF, 0x55), RGB(0x55, 0xFF, 0xFF), 116 RGB(0xFF, 0x55, 0x55), RGB(0xFF, 0x55, 0xFF), RGB(0xFF, 0xFF, 0x55), RGB(0xFF, 0xFF, 0xFF), 117 RGB(0x00, 0x00, 0x00), RGB(0x14, 0x14, 0x14), RGB(0x20, 0x20, 0x20), RGB(0x2C, 0x2C, 0x2C), 118 RGB(0x38, 0x38, 0x38), RGB(0x45, 0x45, 0x45), RGB(0x51, 0x51, 0x51), RGB(0x61, 0x61, 0x61), 119 RGB(0x71, 0x71, 0x71), RGB(0x82, 0x82, 0x82), RGB(0x92, 0x92, 0x92), RGB(0xA2, 0xA2, 0xA2), 120 RGB(0xB6, 0xB6, 0xB6), RGB(0xCB, 0xCB, 0xCB), RGB(0xE3, 0xE3, 0xE3), RGB(0xFF, 0xFF, 0xFF), 121 RGB(0x00, 0x00, 0xFF), RGB(0x41, 0x00, 0xFF), RGB(0x7D, 0x00, 0xFF), RGB(0xBE, 0x00, 0xFF), 122 RGB(0xFF, 0x00, 0xFF), RGB(0xFF, 0x00, 0xBE), RGB(0xFF, 0x00, 0x7D), RGB(0xFF, 0x00, 0x41), 123 RGB(0xFF, 0x00, 0x00), RGB(0xFF, 0x41, 0x00), RGB(0xFF, 0x7D, 0x00), RGB(0xFF, 0xBE, 0x00), 124 RGB(0xFF, 0xFF, 0x00), RGB(0xBE, 0xFF, 0x00), RGB(0x7D, 0xFF, 0x00), RGB(0x41, 0xFF, 0x00), 125 RGB(0x00, 0xFF, 0x00), RGB(0x00, 0xFF, 0x41), RGB(0x00, 0xFF, 0x7D), RGB(0x00, 0xFF, 0xBE), 126 RGB(0x00, 0xFF, 0xFF), RGB(0x00, 0xBE, 0xFF), RGB(0x00, 0x7D, 0xFF), RGB(0x00, 0x41, 0xFF), 127 RGB(0x7D, 0x7D, 0xFF), RGB(0x9E, 0x7D, 0xFF), RGB(0xBE, 0x7D, 0xFF), RGB(0xDF, 0x7D, 0xFF), 128 RGB(0xFF, 0x7D, 0xFF), RGB(0xFF, 0x7D, 0xDF), RGB(0xFF, 0x7D, 0xBE), RGB(0xFF, 0x7D, 0x9E), 129 130 RGB(0xFF, 0x7D, 0x7D), RGB(0xFF, 0x9E, 0x7D), RGB(0xFF, 0xBE, 0x7D), RGB(0xFF, 0xDF, 0x7D), 131 RGB(0xFF, 0xFF, 0x7D), RGB(0xDF, 0xFF, 0x7D), RGB(0xBE, 0xFF, 0x7D), RGB(0x9E, 0xFF, 0x7D), 132 RGB(0x7D, 0xFF, 0x7D), RGB(0x7D, 0xFF, 0x9E), RGB(0x7D, 0xFF, 0xBE), RGB(0x7D, 0xFF, 0xDF), 133 RGB(0x7D, 0xFF, 0xFF), RGB(0x7D, 0xDF, 0xFF), RGB(0x7D, 0xBE, 0xFF), RGB(0x7D, 0x9E, 0xFF), 134 RGB(0xB6, 0xB6, 0xFF), RGB(0xC7, 0xB6, 0xFF), RGB(0xDB, 0xB6, 0xFF), RGB(0xEB, 0xB6, 0xFF), 135 RGB(0xFF, 0xB6, 0xFF), RGB(0xFF, 0xB6, 0xEB), RGB(0xFF, 0xB6, 0xDB), RGB(0xFF, 0xB6, 0xC7), 136 RGB(0xFF, 0xB6, 0xB6), RGB(0xFF, 0xC7, 0xB6), RGB(0xFF, 0xDB, 0xB6), RGB(0xFF, 0xEB, 0xB6), 137 RGB(0xFF, 0xFF, 0xB6), RGB(0xEB, 0xFF, 0xB6), RGB(0xDB, 0xFF, 0xB6), RGB(0xC7, 0xFF, 0xB6), 138 RGB(0xB6, 0xFF, 0xB6), RGB(0xB6, 0xFF, 0xC7), RGB(0xB6, 0xFF, 0xDB), RGB(0xB6, 0xFF, 0xEB), 139 RGB(0xB6, 0xFF, 0xFF), RGB(0xB6, 0xEB, 0xFF), RGB(0xB6, 0xDB, 0xFF), RGB(0xB6, 0xC7, 0xFF), 140 RGB(0x00, 0x00, 0x71), RGB(0x1C, 0x00, 0x71), RGB(0x38, 0x00, 0x71), RGB(0x55, 0x00, 0x71), 141 RGB(0x71, 0x00, 0x71), RGB(0x71, 0x00, 0x55), RGB(0x71, 0x00, 0x38), RGB(0x71, 0x00, 0x1C), 142 RGB(0x71, 0x00, 0x00), RGB(0x71, 0x1C, 0x00), RGB(0x71, 0x38, 0x00), RGB(0x71, 0x55, 0x00), 143 RGB(0x71, 0x71, 0x00), RGB(0x55, 0x71, 0x00), RGB(0x38, 0x71, 0x00), RGB(0x1C, 0x71, 0x00), 144 RGB(0x00, 0x71, 0x00), RGB(0x00, 0x71, 0x1C), RGB(0x00, 0x71, 0x38), RGB(0x00, 0x71, 0x55), 145 RGB(0x00, 0x71, 0x71), RGB(0x00, 0x55, 0x71), RGB(0x00, 0x38, 0x71), RGB(0x00, 0x1C, 0x71), 146 147 RGB(0x38, 0x38, 0x71), RGB(0x45, 0x38, 0x71), RGB(0x55, 0x38, 0x71), RGB(0x61, 0x38, 0x71), 148 RGB(0x71, 0x38, 0x71), RGB(0x71, 0x38, 0x61), RGB(0x71, 0x38, 0x55), RGB(0x71, 0x38, 0x45), 149 RGB(0x71, 0x38, 0x38), RGB(0x71, 0x45, 0x38), RGB(0x71, 0x55, 0x38), RGB(0x71, 0x61, 0x38), 150 RGB(0x71, 0x71, 0x38), RGB(0x61, 0x71, 0x38), RGB(0x55, 0x71, 0x38), RGB(0x45, 0x71, 0x38), 151 RGB(0x38, 0x71, 0x38), RGB(0x38, 0x71, 0x45), RGB(0x38, 0x71, 0x55), RGB(0x38, 0x71, 0x61), 152 RGB(0x38, 0x71, 0x71), RGB(0x38, 0x61, 0x71), RGB(0x38, 0x55, 0x71), RGB(0x38, 0x45, 0x71), 153 RGB(0x51, 0x51, 0x71), RGB(0x59, 0x51, 0x71), RGB(0x61, 0x51, 0x71), RGB(0x69, 0x51, 0x71), 154 RGB(0x71, 0x51, 0x71), RGB(0x71, 0x51, 0x69), RGB(0x71, 0x51, 0x61), RGB(0x71, 0x51, 0x59), 155 RGB(0x71, 0x51, 0x51), RGB(0x71, 0x59, 0x51), RGB(0x71, 0x61, 0x51), RGB(0x71, 0x69, 0x51), 156 RGB(0x71, 0x71, 0x51), RGB(0x69, 0x71, 0x51), RGB(0x61, 0x71, 0x51), RGB(0x59, 0x71, 0x51), 157 RGB(0x51, 0x71, 0x51), RGB(0x51, 0x71, 0x59), RGB(0x51, 0x71, 0x61), RGB(0x51, 0x71, 0x69), 158 RGB(0x51, 0x71, 0x71), RGB(0x51, 0x69, 0x71), RGB(0x51, 0x61, 0x71), RGB(0x51, 0x59, 0x71), 159 RGB(0x00, 0x00, 0x41), RGB(0x10, 0x00, 0x41), RGB(0x20, 0x00, 0x41), RGB(0x30, 0x00, 0x41), 160 RGB(0x41, 0x00, 0x41), RGB(0x41, 0x00, 0x30), RGB(0x41, 0x00, 0x20), RGB(0x41, 0x00, 0x10), 161 RGB(0x41, 0x00, 0x00), RGB(0x41, 0x10, 0x00), RGB(0x41, 0x20, 0x00), RGB(0x41, 0x30, 0x00), 162 RGB(0x41, 0x41, 0x00), RGB(0x30, 0x41, 0x00), RGB(0x20, 0x41, 0x00), RGB(0x10, 0x41, 0x00), 163 164 RGB(0x00, 0x41, 0x00), RGB(0x00, 0x41, 0x10), RGB(0x00, 0x41, 0x20), RGB(0x00, 0x41, 0x30), 165 RGB(0x00, 0x41, 0x41), RGB(0x00, 0x30, 0x41), RGB(0x00, 0x20, 0x41), RGB(0x00, 0x10, 0x41), 166 RGB(0x20, 0x20, 0x41), RGB(0x28, 0x20, 0x41), RGB(0x30, 0x20, 0x41), RGB(0x38, 0x20, 0x41), 167 RGB(0x41, 0x20, 0x41), RGB(0x41, 0x20, 0x38), RGB(0x41, 0x20, 0x30), RGB(0x41, 0x20, 0x28), 168 RGB(0x41, 0x20, 0x20), RGB(0x41, 0x28, 0x20), RGB(0x41, 0x30, 0x20), RGB(0x41, 0x38, 0x20), 169 RGB(0x41, 0x41, 0x20), RGB(0x38, 0x41, 0x20), RGB(0x30, 0x41, 0x20), RGB(0x28, 0x41, 0x20), 170 RGB(0x20, 0x41, 0x20), RGB(0x20, 0x41, 0x28), RGB(0x20, 0x41, 0x30), RGB(0x20, 0x41, 0x38), 171 RGB(0x20, 0x41, 0x41), RGB(0x20, 0x38, 0x41), RGB(0x20, 0x30, 0x41), RGB(0x20, 0x28, 0x41), 172 RGB(0x2C, 0x2C, 0x41), RGB(0x30, 0x2C, 0x41), RGB(0x34, 0x2C, 0x41), RGB(0x3C, 0x2C, 0x41), 173 RGB(0x41, 0x2C, 0x41), RGB(0x41, 0x2C, 0x3C), RGB(0x41, 0x2C, 0x34), RGB(0x41, 0x2C, 0x30), 174 RGB(0x41, 0x2C, 0x2C), RGB(0x41, 0x30, 0x2C), RGB(0x41, 0x34, 0x2C), RGB(0x41, 0x3C, 0x2C), 175 RGB(0x41, 0x41, 0x2C), RGB(0x3C, 0x41, 0x2C), RGB(0x34, 0x41, 0x2C), RGB(0x30, 0x41, 0x2C), 176 RGB(0x2C, 0x41, 0x2C), RGB(0x2C, 0x41, 0x30), RGB(0x2C, 0x41, 0x34), RGB(0x2C, 0x41, 0x3C), 177 RGB(0x2C, 0x41, 0x41), RGB(0x2C, 0x3C, 0x41), RGB(0x2C, 0x34, 0x41), RGB(0x2C, 0x30, 0x41), 178 RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00), 179 RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00) 180 }; 181 182 #endif 183 184 /* 185 * Default 16-color palette for foreground and background 186 * (corresponding flags in comments). 187 * Taken from subsystems/win32/winsrv/consrv/frontends/gui/conwnd.c 188 */ 189 static const COLORREF ConsoleColors[16] = 190 { 191 RGB(0, 0, 0), // (Black) 192 RGB(0, 0, 128), // BLUE 193 RGB(0, 128, 0), // GREEN 194 RGB(0, 128, 128), // BLUE | GREEN 195 RGB(128, 0, 0), // RED 196 RGB(128, 0, 128), // BLUE | RED 197 RGB(128, 128, 0), // GREEN | RED 198 RGB(192, 192, 192), // BLUE | GREEN | RED 199 200 RGB(128, 128, 128), // (Grey) INTENSITY 201 RGB(0, 0, 255), // BLUE | INTENSITY 202 RGB(0, 255, 0), // GREEN | INTENSITY 203 RGB(0, 255, 255), // BLUE | GREEN | INTENSITY 204 RGB(255, 0, 0), // RED | INTENSITY 205 RGB(255, 0, 255), // BLUE | RED | INTENSITY 206 RGB(255, 255, 0), // GREEN | RED | INTENSITY 207 RGB(255, 255, 255) // BLUE | GREEN | RED | INTENSITY 208 }; 209 210 /// ConsoleFramebuffer 211 static PVOID ActiveFramebuffer = NULL; // Active framebuffer, points to 212 // either TextFramebuffer or a 213 // valid graphics framebuffer. 214 static HPALETTE TextPaletteHandle = NULL; 215 static HPALETTE PaletteHandle = NULL; 216 217 /* 218 * Text mode -- we always keep a valid text mode framebuffer 219 * even if we are in graphics mode. This is needed in order 220 * to keep a consistent VGA state. However, each time the VGA 221 * detaches from the console (and reattaches to it later on), 222 * this text mode framebuffer is recreated. 223 */ 224 static PCHAR_CELL TextFramebuffer = NULL; 225 226 /* 227 * Graphics mode 228 */ 229 static PBYTE GraphicsFramebuffer = NULL; 230 231 232 // static HANDLE ConsoleMutex = NULL; 233 // /* DoubleVision support */ 234 // static BOOLEAN DoubleWidth = FALSE; 235 // static BOOLEAN DoubleHeight = FALSE; 236 237 238 239 240 241 /* 242 * VGA Hardware 243 */ 244 static BYTE VgaMemory[VGA_NUM_BANKS * SVGA_BANK_SIZE]; 245 246 static BYTE VgaLatchRegisters[VGA_NUM_BANKS] = {0, 0, 0, 0}; 247 248 static BYTE VgaMiscRegister; 249 static BYTE VgaFeatureRegister; 250 251 static BYTE VgaSeqIndex = VGA_SEQ_RESET_REG; 252 static BYTE VgaSeqRegisters[SVGA_SEQ_MAX_REG]; 253 254 static BYTE VgaCrtcIndex = VGA_CRTC_HORZ_TOTAL_REG; 255 static BYTE VgaCrtcRegisters[SVGA_CRTC_MAX_REG]; 256 257 static BYTE VgaGcIndex = VGA_GC_RESET_REG; 258 static BYTE VgaGcRegisters[SVGA_GC_MAX_REG]; 259 260 static BOOLEAN VgaAcLatch = FALSE; 261 static BOOLEAN VgaAcPalDisable = TRUE; 262 static BYTE VgaAcIndex = VGA_AC_PAL_0_REG; 263 static BYTE VgaAcRegisters[VGA_AC_MAX_REG]; 264 265 static BYTE VgaDacMask = 0xFF; 266 static BYTE VgaDacLatchCounter = 0; 267 static BYTE VgaDacLatch[3]; 268 269 static BOOLEAN VgaDacReadWrite = FALSE; 270 static WORD VgaDacIndex = 0; 271 static BYTE VgaDacRegisters[VGA_PALETTE_SIZE]; 272 273 // static VGA_REGISTERS VgaRegisters; 274 275 static ULONGLONG HorizontalRetraceCycle = 0ULL; 276 static PHARDWARE_TIMER HSyncTimer; 277 static DWORD ScanlineCounter = 0; 278 static DWORD StartAddressLatch = 0; 279 static DWORD ScanlineSizeLatch = 0; 280 281 static BOOLEAN NeedsUpdate = FALSE; 282 static BOOLEAN ModeChanged = FALSE; 283 static BOOLEAN CursorChanged = FALSE; 284 static BOOLEAN PaletteChanged = FALSE; 285 286 static UINT SvgaHdrCounter = 0; 287 static BYTE SvgaHiddenRegister = 0; 288 289 typedef enum _SCREEN_MODE 290 { 291 TEXT_MODE, 292 GRAPHICS_MODE 293 } SCREEN_MODE, *PSCREEN_MODE; 294 295 static SCREEN_MODE ScreenMode = TEXT_MODE; 296 static COORD CurrResolution = {0}; 297 298 static SMALL_RECT UpdateRectangle = { 0, 0, 0, 0 }; 299 300 301 302 303 /** HACK!! **/ 304 #include "../../console/video.c" 305 /** HACK!! **/ 306 307 308 309 310 311 /* PRIVATE FUNCTIONS **********************************************************/ 312 313 static inline DWORD VgaGetVideoBaseAddress(VOID) 314 { 315 return MemoryBase[(VgaGcRegisters[VGA_GC_MISC_REG] >> 2) & 0x03]; 316 } 317 318 static inline DWORD VgaGetAddressSize(VOID) 319 { 320 if (VgaSeqRegisters[SVGA_SEQ_EXT_MODE_REG] & SVGA_SEQ_EXT_MODE_HIGH_RES) 321 { 322 /* Packed pixel addressing */ 323 return 1; 324 } 325 else if (VgaCrtcRegisters[VGA_CRTC_UNDERLINE_REG] & VGA_CRTC_UNDERLINE_DWORD) 326 { 327 /* Double-word addressing */ 328 return 4; // sizeof(DWORD) 329 } 330 else if (VgaCrtcRegisters[VGA_CRTC_MODE_CONTROL_REG] & VGA_CRTC_MODE_CONTROL_BYTE) 331 { 332 /* Byte addressing */ 333 return 1; // sizeof(BYTE) 334 } 335 else 336 { 337 /* Word addressing */ 338 return 2; // sizeof(WORD) 339 } 340 } 341 342 static inline DWORD VgaTranslateAddress(DWORD Address) 343 { 344 DWORD Offset = LOWORD(Address - VgaGetVideoBaseAddress()); 345 DWORD ExtOffset = ((VgaGcRegisters[SVGA_GC_EXT_MODE_REG] & SVGA_GC_EXT_MODE_WND_B) && (Offset & (1 << 15))) 346 ? VgaGcRegisters[SVGA_GC_OFFSET_1_REG] 347 : VgaGcRegisters[SVGA_GC_OFFSET_0_REG]; 348 349 /* Check for chain-4 and odd-even mode */ 350 if (VgaSeqRegisters[VGA_SEQ_MEM_REG] & VGA_SEQ_MEM_C4) 351 { 352 /* Clear the lowest two bits since they're used to select the bank */ 353 Offset &= ~3; 354 } 355 else if (VgaGcRegisters[VGA_GC_MODE_REG] & VGA_GC_MODE_OE) 356 { 357 /* Clear the lowest bit since it's used to select odd/even */ 358 Offset &= ~1; 359 } 360 361 if (ExtOffset) 362 { 363 /* Add the extended offset */ 364 Offset += ExtOffset << ((VgaGcRegisters[SVGA_GC_EXT_MODE_REG] & SVGA_GC_EXT_MODE_GRAN) ? 14 : 12); 365 } 366 367 /* Return the offset on plane 0 */ 368 return Offset; 369 } 370 371 static inline BYTE VgaTranslateByteForWriting(BYTE Data, BYTE Plane) 372 { 373 BYTE WriteMode = VgaGcRegisters[VGA_GC_MODE_REG] & 0x03; 374 BYTE BitMask = VgaGcRegisters[VGA_GC_BITMASK_REG]; 375 376 if (WriteMode == 1) 377 { 378 /* In write mode 1 just return the latch register */ 379 return VgaLatchRegisters[Plane]; 380 } 381 382 if (WriteMode != 2) 383 { 384 /* Write modes 0 and 3 rotate the data to the right first */ 385 BYTE RotateCount = VgaGcRegisters[VGA_GC_ROTATE_REG] & 0x07; 386 Data = LOBYTE(((DWORD)Data >> RotateCount) | ((DWORD)Data << (8 - RotateCount))); 387 } 388 else 389 { 390 /* Write mode 2 expands the appropriate bit to all 8 bits */ 391 Data = (Data & (1 << Plane)) ? 0xFF : 0x00; 392 } 393 394 if (WriteMode == 0) 395 { 396 /* 397 * In write mode 0, the enable set/reset register decides if the 398 * set/reset bit should be expanded to all 8 bits. 399 */ 400 if (VgaGcRegisters[VGA_GC_ENABLE_RESET_REG] & (1 << Plane)) 401 { 402 /* Copy the bit from the set/reset register to all 8 bits */ 403 Data = (VgaGcRegisters[VGA_GC_RESET_REG] & (1 << Plane)) ? 0xFF : 0x00; 404 } 405 } 406 407 if (WriteMode != 3) 408 { 409 /* Write modes 0 and 2 then perform a logical operation on the data and latch */ 410 BYTE LogicalOperation = (VgaGcRegisters[VGA_GC_ROTATE_REG] >> 3) & 0x03; 411 412 if (LogicalOperation == 1) Data &= VgaLatchRegisters[Plane]; 413 else if (LogicalOperation == 2) Data |= VgaLatchRegisters[Plane]; 414 else if (LogicalOperation == 3) Data ^= VgaLatchRegisters[Plane]; 415 } 416 else 417 { 418 /* For write mode 3, we AND the bitmask with the data, which is used as the new bitmask */ 419 BitMask &= Data; 420 421 /* Then we expand the bit in the set/reset field */ 422 Data = (VgaGcRegisters[VGA_GC_RESET_REG] & (1 << Plane)) ? 0xFF : 0x00; 423 } 424 425 /* Bits cleared in the bitmask are replaced with latch register bits */ 426 Data = (Data & BitMask) | (VgaLatchRegisters[Plane] & (~BitMask)); 427 428 /* Return the byte */ 429 return Data; 430 } 431 432 static inline ULONG VgaGetClockFrequency(VOID) 433 { 434 BYTE Numerator, Denominator; 435 436 if (VgaSeqRegisters[SVGA_SEQ_MCLK_REG] & SVGA_SEQ_MCLK_VCLK) 437 { 438 /* The VCLK is being generated using the MCLK */ 439 ULONG Clock = (VGA_CLOCK_BASE * (VgaSeqRegisters[SVGA_SEQ_MCLK_REG] & 0x3F)) >> 3; 440 441 if (VgaSeqRegisters[SVGA_SEQ_VCLK3_DENOMINATOR_REG] & 1) 442 { 443 /* Use only half of the MCLK as the VCLK */ 444 Clock >>= 1; 445 } 446 447 return Clock; 448 } 449 450 switch ((VgaMiscRegister >> 2) & 3) 451 { 452 case 0: 453 { 454 Numerator = VgaSeqRegisters[SVGA_SEQ_VCLK0_NUMERATOR_REG]; 455 Denominator = VgaSeqRegisters[SVGA_SEQ_VCLK0_DENOMINATOR_REG]; 456 break; 457 } 458 459 case 1: 460 { 461 Numerator = VgaSeqRegisters[SVGA_SEQ_VCLK1_NUMERATOR_REG]; 462 Denominator = VgaSeqRegisters[SVGA_SEQ_VCLK1_DENOMINATOR_REG]; 463 break; 464 } 465 466 case 2: 467 { 468 Numerator = VgaSeqRegisters[SVGA_SEQ_VCLK2_NUMERATOR_REG]; 469 Denominator = VgaSeqRegisters[SVGA_SEQ_VCLK2_DENOMINATOR_REG]; 470 break; 471 } 472 473 case 3: 474 { 475 Numerator = VgaSeqRegisters[SVGA_SEQ_VCLK3_NUMERATOR_REG]; 476 Denominator = VgaSeqRegisters[SVGA_SEQ_VCLK3_DENOMINATOR_REG]; 477 break; 478 } 479 } 480 481 /* The numerator is 7-bit */ 482 Numerator &= ~(1 << 7); 483 484 /* If bit 7 is clear, the denominator is 5-bit */ 485 if (!(Denominator & (1 << 7))) Denominator &= ~(1 << 6); 486 487 /* Bit 0 of the denominator is the post-scalar bit */ 488 if (Denominator & 1) Denominator &= ~1; 489 else Denominator >>= 1; 490 491 /* Return the clock frequency in Hz */ 492 return (VGA_CLOCK_BASE * Numerator) / Denominator; 493 } 494 495 static VOID VgaResetSequencer(VOID) 496 { 497 /* Lock extended SVGA registers */ 498 VgaSeqRegisters[SVGA_SEQ_UNLOCK_REG] = SVGA_SEQ_LOCKED; 499 500 /* Initialize the VCLKs */ 501 VgaSeqRegisters[SVGA_SEQ_VCLK0_NUMERATOR_REG] = 0x66; 502 VgaSeqRegisters[SVGA_SEQ_VCLK0_DENOMINATOR_REG] = 0x3B; 503 VgaSeqRegisters[SVGA_SEQ_VCLK1_NUMERATOR_REG] = 0x5B; 504 VgaSeqRegisters[SVGA_SEQ_VCLK1_DENOMINATOR_REG] = 0x2F; 505 VgaSeqRegisters[SVGA_SEQ_VCLK2_NUMERATOR_REG] = 0x45; 506 VgaSeqRegisters[SVGA_SEQ_VCLK2_DENOMINATOR_REG] = 0x30; 507 VgaSeqRegisters[SVGA_SEQ_VCLK3_NUMERATOR_REG] = 0x7E; 508 VgaSeqRegisters[SVGA_SEQ_VCLK3_DENOMINATOR_REG] = 0x33; 509 510 /* 50 MHz MCLK, not being used as the VCLK */ 511 VgaSeqRegisters[SVGA_SEQ_MCLK_REG] = 0x1C; 512 } 513 514 static VOID VgaRestoreDefaultPalette(PPALETTEENTRY Entries, USHORT NumOfEntries) 515 { 516 USHORT i; 517 518 /* Copy the colors of the default palette to the DAC and console palette */ 519 for (i = 0; i < NumOfEntries; i++) 520 { 521 /* Set the palette entries */ 522 Entries[i].peRed = GetRValue(VgaDefaultPalette[i]); 523 Entries[i].peGreen = GetGValue(VgaDefaultPalette[i]); 524 Entries[i].peBlue = GetBValue(VgaDefaultPalette[i]); 525 Entries[i].peFlags = 0; 526 527 /* Set the DAC registers */ 528 VgaDacRegisters[i * 3] = VGA_COLOR_TO_DAC(GetRValue(VgaDefaultPalette[i])); 529 VgaDacRegisters[i * 3 + 1] = VGA_COLOR_TO_DAC(GetGValue(VgaDefaultPalette[i])); 530 VgaDacRegisters[i * 3 + 2] = VGA_COLOR_TO_DAC(GetBValue(VgaDefaultPalette[i])); 531 } 532 } 533 534 static BOOLEAN VgaInitializePalette(VOID) 535 { 536 UINT i; 537 BOOLEAN Result = FALSE; 538 LPLOGPALETTE Palette, TextPalette; 539 540 /* Allocate storage space for the palettes */ 541 Palette = RtlAllocateHeap(RtlGetProcessHeap(), 542 HEAP_ZERO_MEMORY, 543 sizeof(LOGPALETTE) + 544 VGA_MAX_COLORS * sizeof(PALETTEENTRY)); 545 TextPalette = RtlAllocateHeap(RtlGetProcessHeap(), 546 HEAP_ZERO_MEMORY, 547 sizeof(LOGPALETTE) + 548 (VGA_AC_PAL_F_REG + 1) * sizeof(PALETTEENTRY)); 549 if ((Palette == NULL) || (TextPalette == NULL)) goto Cleanup; 550 551 /* Initialize the palettes */ 552 Palette->palVersion = TextPalette->palVersion = 0x0300; 553 Palette->palNumEntries = VGA_MAX_COLORS; 554 TextPalette->palNumEntries = VGA_AC_PAL_F_REG + 1; 555 556 /* Restore the default graphics palette */ 557 VgaRestoreDefaultPalette(Palette->palPalEntry, Palette->palNumEntries); 558 559 /* Set the default text palette */ 560 for (i = 0; i < TextPalette->palNumEntries; i++) 561 { 562 /* Set the palette entries */ 563 TextPalette->palPalEntry[i].peRed = GetRValue(ConsoleColors[i]); 564 TextPalette->palPalEntry[i].peGreen = GetGValue(ConsoleColors[i]); 565 TextPalette->palPalEntry[i].peBlue = GetBValue(ConsoleColors[i]); 566 TextPalette->palPalEntry[i].peFlags = 0; 567 } 568 569 /* Create the palettes */ 570 PaletteHandle = CreatePalette(Palette); 571 TextPaletteHandle = CreatePalette(TextPalette); 572 573 if (PaletteHandle != NULL && TextPaletteHandle != NULL) 574 { 575 /* The palettes have been created successfully */ 576 Result = TRUE; 577 } 578 579 Cleanup: 580 /* Free the palettes */ 581 if (Palette) RtlFreeHeap(RtlGetProcessHeap(), 0, Palette); 582 if (TextPalette) RtlFreeHeap(RtlGetProcessHeap(), 0, TextPalette); 583 584 if (!Result) 585 { 586 /* Something failed, delete the palettes */ 587 if (PaletteHandle) DeleteObject(PaletteHandle); 588 if (TextPaletteHandle) DeleteObject(TextPaletteHandle); 589 } 590 591 return Result; 592 } 593 594 static VOID VgaResetPalette(VOID) 595 { 596 PALETTEENTRY Entries[VGA_MAX_COLORS]; 597 598 /* Restore the default palette */ 599 VgaRestoreDefaultPalette(Entries, VGA_MAX_COLORS); 600 SetPaletteEntries(PaletteHandle, 0, VGA_MAX_COLORS, Entries); 601 PaletteChanged = TRUE; 602 } 603 604 static BOOL VgaEnterNewMode(SCREEN_MODE NewScreenMode, PCOORD Resolution) 605 { 606 /* Check if the new mode is alphanumeric */ 607 if (NewScreenMode == TEXT_MODE) 608 { 609 /* Enter new text mode */ 610 611 if (!VgaConsoleCreateTextScreen(// &TextFramebuffer, 612 Resolution, 613 TextPaletteHandle)) 614 { 615 DisplayMessage(L"An unexpected VGA error occurred while switching into text mode. Error: %u", GetLastError()); 616 EmulatorTerminate(); 617 return FALSE; 618 } 619 620 /* The active framebuffer is now the text framebuffer */ 621 ActiveFramebuffer = TextFramebuffer; 622 623 /* Set the screen mode flag */ 624 ScreenMode = TEXT_MODE; 625 626 return TRUE; 627 } 628 else 629 { 630 /* Enter graphics mode */ 631 632 if (!VgaConsoleCreateGraphicsScreen(// &GraphicsFramebuffer, 633 Resolution, 634 PaletteHandle)) 635 { 636 DisplayMessage(L"An unexpected VGA error occurred while switching into graphics mode. Error: %u", GetLastError()); 637 EmulatorTerminate(); 638 return FALSE; 639 } 640 641 /* The active framebuffer is now the graphics framebuffer */ 642 ActiveFramebuffer = GraphicsFramebuffer; 643 644 /* Set the screen mode flag */ 645 ScreenMode = GRAPHICS_MODE; 646 647 return TRUE; 648 } 649 } 650 651 static VOID VgaLeaveCurrentMode(VOID) 652 { 653 /* Leave the current video mode */ 654 if (ScreenMode == GRAPHICS_MODE) 655 { 656 VgaConsoleDestroyGraphicsScreen(); 657 658 /* Cleanup the video data */ 659 GraphicsFramebuffer = NULL; 660 } 661 else 662 { 663 VgaConsoleDestroyTextScreen(); 664 665 /* Cleanup the video data */ 666 // TextFramebuffer = NULL; 667 // NEVER SET the ALWAYS-SET TextFramebuffer pointer to NULL!! 668 } 669 670 /* Reset the active framebuffer */ 671 ActiveFramebuffer = NULL; 672 } 673 674 static VOID VgaChangeMode(VOID) 675 { 676 COORD NewResolution = VgaGetDisplayResolution(); 677 SCREEN_MODE NewScreenMode = 678 !(VgaGcRegisters[VGA_GC_MISC_REG] & VGA_GC_MISC_NOALPHA) ? TEXT_MODE 679 : GRAPHICS_MODE; 680 681 /* 682 * Do not switch to a different screen mode + resolution if the new settings 683 * are the same as the old ones. Just repaint the full screen. 684 */ 685 if ((ScreenMode == NewScreenMode) && // CurrResolution == NewResolution 686 (CurrResolution.X == NewResolution.X && CurrResolution.Y == NewResolution.Y)) 687 { 688 goto Quit; 689 } 690 691 // FIXME: Wouldn't it be preferrable to switch to the new console SB 692 // *ONLY* if we succeeded in setting the new mode?? 693 694 /* Leave the current video mode */ 695 VgaLeaveCurrentMode(); // ScreenMode 696 697 /* Update the current resolution */ 698 CurrResolution = NewResolution; 699 700 /* Change the screen mode */ 701 if (!VgaEnterNewMode(NewScreenMode, &CurrResolution)) 702 return; 703 704 Quit: 705 706 /* Trigger a full update of the screen */ 707 NeedsUpdate = TRUE; 708 UpdateRectangle.Left = 0; 709 UpdateRectangle.Top = 0; 710 UpdateRectangle.Right = CurrResolution.X; 711 UpdateRectangle.Bottom = CurrResolution.Y; 712 713 /* Reset the mode change flag */ 714 ModeChanged = FALSE; 715 } 716 717 static inline VOID VgaMarkForUpdate(SHORT Row, SHORT Column) 718 { 719 /* Check if this is the first time the rectangle is updated */ 720 if (!NeedsUpdate) 721 { 722 UpdateRectangle.Left = UpdateRectangle.Top = MAXSHORT; 723 UpdateRectangle.Right = UpdateRectangle.Bottom = MINSHORT; 724 } 725 726 /* Expand the rectangle to include the point */ 727 UpdateRectangle.Left = min(UpdateRectangle.Left, Column); 728 UpdateRectangle.Right = max(UpdateRectangle.Right, Column); 729 UpdateRectangle.Top = min(UpdateRectangle.Top, Row); 730 UpdateRectangle.Bottom = max(UpdateRectangle.Bottom, Row); 731 732 /* Set the update request flag */ 733 NeedsUpdate = TRUE; 734 } 735 736 static VOID VgaUpdateFramebuffer(VOID) 737 { 738 SHORT i, j, k; 739 DWORD AddressSize = VgaGetAddressSize(); 740 DWORD Address = StartAddressLatch; 741 BYTE BytePanning = (VgaCrtcRegisters[VGA_CRTC_PRESET_ROW_SCAN_REG] >> 5) & 3; 742 WORD LineCompare = VgaCrtcRegisters[VGA_CRTC_LINE_COMPARE_REG] 743 | ((VgaCrtcRegisters[VGA_CRTC_OVERFLOW_REG] & VGA_CRTC_OVERFLOW_LC8) << 4) 744 | ((VgaCrtcRegisters[VGA_CRTC_MAX_SCAN_LINE_REG] & VGA_CRTC_MAXSCANLINE_LC9) << 3); 745 BYTE PixelShift = VgaAcRegisters[VGA_AC_HORZ_PANNING_REG] & 0x0F; 746 747 /* 748 * If the console framebuffer is NULL, that means something 749 * went wrong earlier and this is the final display refresh. 750 */ 751 if (ActiveFramebuffer == NULL) return; 752 753 /* Check if we are in text or graphics mode */ 754 if (ScreenMode == GRAPHICS_MODE) 755 { 756 /* Graphics mode */ 757 PBYTE GraphicsBuffer = (PBYTE)ActiveFramebuffer; 758 DWORD InterlaceHighBit = VGA_INTERLACE_HIGH_BIT; 759 SHORT X; 760 761 /* 762 * Synchronize access to the graphics framebuffer 763 * with the console framebuffer mutex. 764 */ 765 WaitForSingleObject(ConsoleMutex, INFINITE); 766 767 /* Shift the high bit right by 1 in odd/even mode */ 768 if (VgaGcRegisters[VGA_GC_MODE_REG] & VGA_GC_MODE_OE) 769 { 770 InterlaceHighBit >>= 1; 771 } 772 773 if (VgaCrtcRegisters[VGA_CRTC_MAX_SCAN_LINE_REG] & VGA_CRTC_MAXSCANLINE_DOUBLE) 774 { 775 /* Halve the line compare value */ 776 LineCompare >>= 1; 777 } 778 else 779 { 780 /* Divide the line compare value by the maximum scan line */ 781 LineCompare /= 1 + (VgaCrtcRegisters[VGA_CRTC_MAX_SCAN_LINE_REG] & 0x1F); 782 } 783 784 /* Loop through the scanlines */ 785 for (i = 0; i < CurrResolution.Y; i++) 786 { 787 if (i == LineCompare) 788 { 789 if (VgaAcRegisters[VGA_AC_CONTROL_REG] & VGA_AC_CONTROL_PPM) 790 { 791 /* 792 * Disable the pixel shift count and byte panning 793 * for the rest of the display cycle 794 */ 795 PixelShift = 0; 796 BytePanning = 0; 797 } 798 799 /* Reset the address, but assume the preset row scan is 0 */ 800 Address = BytePanning; 801 } 802 803 if ((VgaGcRegisters[VGA_GC_MISC_REG] & VGA_GC_MISC_OE) && (i & 1)) 804 { 805 /* Odd-numbered line in interlaced mode - set the high bit */ 806 Address |= InterlaceHighBit; 807 } 808 809 /* Loop through the pixels */ 810 for (j = 0; j < CurrResolution.X; j++) 811 { 812 BYTE PixelData = 0; 813 814 /* Apply horizontal pixel panning */ 815 if (VgaAcRegisters[VGA_AC_CONTROL_REG] & VGA_AC_CONTROL_8BIT) 816 { 817 X = j + ((PixelShift >> 1) & 0x03); 818 } 819 else 820 { 821 X = j + ((PixelShift < 8) ? PixelShift : -1); 822 } 823 824 if (VgaSeqRegisters[SVGA_SEQ_EXT_MODE_REG] & SVGA_SEQ_EXT_MODE_HIGH_RES) 825 { 826 // TODO: Check for high color modes 827 828 /* 256 color mode */ 829 PixelData = VgaMemory[Address + X]; 830 } 831 else 832 { 833 /* Check the shifting mode */ 834 if (VgaGcRegisters[VGA_GC_MODE_REG] & VGA_GC_MODE_SHIFT256) 835 { 836 /* 4 bits shifted from each plane */ 837 838 /* Check if this is 16 or 256 color mode */ 839 if (VgaAcRegisters[VGA_AC_CONTROL_REG] & VGA_AC_CONTROL_8BIT) 840 { 841 /* One byte per pixel */ 842 PixelData = VgaMemory[WRAP_OFFSET((Address + (X / VGA_NUM_BANKS)) * AddressSize) 843 * VGA_NUM_BANKS + (X % VGA_NUM_BANKS)]; 844 } 845 else 846 { 847 /* 4-bits per pixel */ 848 849 PixelData = VgaMemory[WRAP_OFFSET((Address + (X / (VGA_NUM_BANKS * 2))) * AddressSize) 850 * VGA_NUM_BANKS + ((X / 2) % VGA_NUM_BANKS)]; 851 852 /* Check if we should use the highest 4 bits or lowest 4 */ 853 if ((X % 2) == 0) 854 { 855 /* Highest 4 */ 856 PixelData >>= 4; 857 } 858 else 859 { 860 /* Lowest 4 */ 861 PixelData &= 0x0F; 862 } 863 } 864 } 865 else if (VgaGcRegisters[VGA_GC_MODE_REG] & VGA_GC_MODE_SHIFTREG) 866 { 867 /* Check if this is 16 or 256 color mode */ 868 if (VgaAcRegisters[VGA_AC_CONTROL_REG] & VGA_AC_CONTROL_8BIT) 869 { 870 // TODO: NOT IMPLEMENTED 871 DPRINT1("8-bit interleaved mode is not implemented!\n"); 872 } 873 else 874 { 875 /* 876 * 2 bits shifted from plane 0 and 2 for the first 4 pixels, 877 * then 2 bits shifted from plane 1 and 3 for the next 4 878 */ 879 DWORD BankNumber = (X / 4) % 2; 880 DWORD Offset = Address + (X / 8); 881 BYTE LowPlaneData = VgaMemory[WRAP_OFFSET(Offset * AddressSize) * VGA_NUM_BANKS + BankNumber]; 882 BYTE HighPlaneData = VgaMemory[WRAP_OFFSET(Offset * AddressSize) * VGA_NUM_BANKS + (BankNumber + 2)]; 883 884 /* Extract the two bits from each plane */ 885 LowPlaneData = (LowPlaneData >> (6 - ((X % 4) * 2))) & 0x03; 886 HighPlaneData = (HighPlaneData >> (6 - ((X % 4) * 2))) & 0x03; 887 888 /* Combine them into the pixel */ 889 PixelData = LowPlaneData | (HighPlaneData << 2); 890 } 891 } 892 else 893 { 894 /* 1 bit shifted from each plane */ 895 896 /* Check if this is 16 or 256 color mode */ 897 if (VgaAcRegisters[VGA_AC_CONTROL_REG] & VGA_AC_CONTROL_8BIT) 898 { 899 /* 8 bits per pixel, 2 on each plane */ 900 901 for (k = 0; k < VGA_NUM_BANKS; k++) 902 { 903 /* The data is on plane k, 4 pixels per byte */ 904 BYTE PlaneData = VgaMemory[WRAP_OFFSET((Address + (X >> 2)) * AddressSize) * VGA_NUM_BANKS + k]; 905 906 /* The mask of the first bit in the pair */ 907 BYTE BitMask = 1 << (((3 - (X % VGA_NUM_BANKS)) * 2) + 1); 908 909 /* Bits 0, 1, 2 and 3 come from the first bit of the pair */ 910 if (PlaneData & BitMask) PixelData |= 1 << k; 911 912 /* Bits 4, 5, 6 and 7 come from the second bit of the pair */ 913 if (PlaneData & (BitMask >> 1)) PixelData |= 1 << (k + 4); 914 } 915 } 916 else 917 { 918 /* 4 bits per pixel, 1 on each plane */ 919 920 for (k = 0; k < VGA_NUM_BANKS; k++) 921 { 922 BYTE PlaneData = VgaMemory[WRAP_OFFSET((Address + (X >> 3)) * AddressSize) * VGA_NUM_BANKS + k]; 923 924 /* If the bit on that plane is set, set it */ 925 if (PlaneData & (1 << (7 - (X % 8)))) PixelData |= 1 << k; 926 } 927 } 928 } 929 } 930 931 if (!(VgaAcRegisters[VGA_AC_CONTROL_REG] & VGA_AC_CONTROL_8BIT)) 932 { 933 /* 934 * In 16 color mode, the value is an index to the AC registers 935 * if external palette access is disabled, otherwise (in case 936 * of palette loading) it is a blank pixel. 937 */ 938 939 if (VgaAcPalDisable) 940 { 941 if (!(VgaAcRegisters[VGA_AC_CONTROL_REG] & VGA_AC_CONTROL_P54S)) 942 { 943 /* Bits 4 and 5 are taken from the palette register */ 944 PixelData = ((VgaAcRegisters[VGA_AC_COLOR_SEL_REG] << 4) & 0xC0) 945 | (VgaAcRegisters[PixelData & 0x0F] & 0x3F); 946 } 947 else 948 { 949 /* Bits 4 and 5 are taken from the color select register */ 950 PixelData = (VgaAcRegisters[VGA_AC_COLOR_SEL_REG] << 4) 951 | (VgaAcRegisters[PixelData & 0x0F] & 0x0F); 952 } 953 } 954 else 955 { 956 PixelData = 0; 957 } 958 } 959 960 /* Take into account DoubleVision mode when checking for pixel updates */ 961 if (DoubleWidth && DoubleHeight) 962 { 963 /* Now check if the resulting pixel data has changed */ 964 if (GraphicsBuffer[(i * 2 * CurrResolution.X * 2) + (j * 2)] != PixelData) 965 { 966 /* Yes, write the new value */ 967 GraphicsBuffer[(i * 2 * CurrResolution.X * 2) + (j * 2)] = PixelData; 968 GraphicsBuffer[(i * 2 * CurrResolution.X * 2) + (j * 2 + 1)] = PixelData; 969 GraphicsBuffer[((i * 2 + 1) * CurrResolution.X * 2) + (j * 2)] = PixelData; 970 GraphicsBuffer[((i * 2 + 1) * CurrResolution.X * 2) + (j * 2 + 1)] = PixelData; 971 972 /* Mark the specified pixel as changed */ 973 VgaMarkForUpdate(i, j); 974 } 975 } 976 else if (DoubleWidth && !DoubleHeight) 977 { 978 /* Now check if the resulting pixel data has changed */ 979 if (GraphicsBuffer[(i * CurrResolution.X * 2) + (j * 2)] != PixelData) 980 { 981 /* Yes, write the new value */ 982 GraphicsBuffer[(i * CurrResolution.X * 2) + (j * 2)] = PixelData; 983 GraphicsBuffer[(i * CurrResolution.X * 2) + (j * 2 + 1)] = PixelData; 984 985 /* Mark the specified pixel as changed */ 986 VgaMarkForUpdate(i, j); 987 } 988 } 989 else if (!DoubleWidth && DoubleHeight) 990 { 991 /* Now check if the resulting pixel data has changed */ 992 if (GraphicsBuffer[(i * 2 * CurrResolution.X) + j] != PixelData) 993 { 994 /* Yes, write the new value */ 995 GraphicsBuffer[(i * 2 * CurrResolution.X) + j] = PixelData; 996 GraphicsBuffer[((i * 2 + 1) * CurrResolution.X) + j] = PixelData; 997 998 /* Mark the specified pixel as changed */ 999 VgaMarkForUpdate(i, j); 1000 } 1001 } 1002 else // if (!DoubleWidth && !DoubleHeight) 1003 { 1004 /* Now check if the resulting pixel data has changed */ 1005 if (GraphicsBuffer[i * CurrResolution.X + j] != PixelData) 1006 { 1007 /* Yes, write the new value */ 1008 GraphicsBuffer[i * CurrResolution.X + j] = PixelData; 1009 1010 /* Mark the specified pixel as changed */ 1011 VgaMarkForUpdate(i, j); 1012 } 1013 } 1014 } 1015 1016 if ((VgaGcRegisters[VGA_GC_MISC_REG] & VGA_GC_MISC_OE) && (i & 1)) 1017 { 1018 /* Clear the high bit */ 1019 Address &= ~InterlaceHighBit; 1020 } 1021 1022 if (!(VgaGcRegisters[VGA_GC_MISC_REG] & VGA_GC_MISC_OE) || (i & 1)) 1023 { 1024 /* Move to the next scanline */ 1025 Address += ScanlineSizeLatch; 1026 } 1027 } 1028 1029 /* 1030 * Release the console framebuffer mutex 1031 * so that we allow for repainting. 1032 */ 1033 ReleaseMutex(ConsoleMutex); 1034 } 1035 else 1036 { 1037 /* Text mode */ 1038 DWORD CurrentAddr; 1039 PCHAR_CELL CharBuffer = (PCHAR_CELL)ActiveFramebuffer; 1040 CHAR_CELL CharInfo; 1041 1042 /* 1043 * Technically, the horizontal panning and preset row count should 1044 * affect text mode too. However, it works on pixels and not characters, 1045 * so we can't support it currently. 1046 */ 1047 1048 /* Loop through the scanlines */ 1049 for (i = 0; i < CurrResolution.Y; i++) 1050 { 1051 /* Loop through the characters */ 1052 for (j = 0; j < CurrResolution.X; j++) 1053 { 1054 CurrentAddr = WRAP_OFFSET((Address + j) * AddressSize); 1055 1056 /* Plane 0 holds the character itself */ 1057 CharInfo.Char = VgaMemory[CurrentAddr * VGA_NUM_BANKS]; 1058 1059 /* Plane 1 holds the attribute */ 1060 CharInfo.Attributes = VgaMemory[CurrentAddr * VGA_NUM_BANKS + 1]; 1061 1062 /* Now check if the resulting character data has changed */ 1063 if ((CharBuffer[i * CurrResolution.X + j].Char != CharInfo.Char) || 1064 (CharBuffer[i * CurrResolution.X + j].Attributes != CharInfo.Attributes)) 1065 { 1066 /* Yes, write the new value */ 1067 CharBuffer[i * CurrResolution.X + j] = CharInfo; 1068 1069 /* Mark the specified cell as changed */ 1070 VgaMarkForUpdate(i, j); 1071 } 1072 } 1073 1074 /* Move to the next scanline */ 1075 Address += ScanlineSizeLatch; 1076 } 1077 } 1078 } 1079 1080 static VOID VgaUpdateTextCursor(VOID) 1081 { 1082 BOOL CursorVisible = !(VgaCrtcRegisters[VGA_CRTC_CURSOR_START_REG] & 0x20); 1083 BYTE CursorStart = VgaCrtcRegisters[VGA_CRTC_CURSOR_START_REG] & 0x1F; 1084 BYTE CursorEnd = VgaCrtcRegisters[VGA_CRTC_CURSOR_END_REG] & 0x1F; 1085 1086 DWORD ScanlineSize = (DWORD)VgaCrtcRegisters[VGA_CRTC_OFFSET_REG] * 2; 1087 BYTE TextSize = 1 + (VgaCrtcRegisters[VGA_CRTC_MAX_SCAN_LINE_REG] & 0x1F); 1088 WORD Location = MAKEWORD(VgaCrtcRegisters[VGA_CRTC_CURSOR_LOC_LOW_REG], 1089 VgaCrtcRegisters[VGA_CRTC_CURSOR_LOC_HIGH_REG]); 1090 1091 /* Just return if we are not in text mode */ 1092 if (ScreenMode != TEXT_MODE) return; 1093 1094 /* Add the cursor skew to the location */ 1095 Location += (VgaCrtcRegisters[VGA_CRTC_CURSOR_END_REG] >> 5) & 0x03; 1096 1097 VgaConsoleUpdateTextCursor(CursorVisible, CursorStart, CursorEnd, 1098 TextSize, ScanlineSize, Location); 1099 1100 /* Reset the cursor changed flag */ 1101 CursorChanged = FALSE; 1102 } 1103 1104 static BYTE WINAPI VgaReadPort(USHORT Port) 1105 { 1106 DPRINT("VgaReadPort: Port 0x%X\n", Port); 1107 1108 if (Port != VGA_DAC_MASK) SvgaHdrCounter = 0; 1109 1110 switch (Port) 1111 { 1112 case VGA_MISC_READ: 1113 return VgaMiscRegister; 1114 1115 case VGA_INSTAT0_READ: 1116 return 0; // Not implemented 1117 1118 case VGA_INSTAT1_READ_MONO: 1119 case VGA_INSTAT1_READ_COLOR: 1120 { 1121 BYTE Result = 0; 1122 BOOLEAN Vsync, Hsync; 1123 ULONGLONG Cycles = CurrentCycleCount; 1124 ULONG CyclesPerMicrosecond = (ULONG)((CurrentIps + 500000ULL) / 1000000ULL); 1125 ULONG Dots = (VgaSeqRegisters[VGA_SEQ_CLOCK_REG] & 1) ? 9 : 8; 1126 ULONG Clock = VgaGetClockFrequency() / 1000000; 1127 ULONG HblankStart, HblankEnd; 1128 ULONG HblankDuration; 1129 ULONG VerticalRetraceStart = VgaCrtcRegisters[VGA_CRTC_START_VERT_RETRACE_REG]; 1130 ULONG VerticalRetraceEnd; 1131 1132 VerticalRetraceStart |= (VgaCrtcRegisters[VGA_CRTC_OVERFLOW_REG] & VGA_CRTC_OVERFLOW_VRS8) << 6; 1133 VerticalRetraceStart |= (VgaCrtcRegisters[VGA_CRTC_OVERFLOW_REG] & VGA_CRTC_OVERFLOW_VRS9) << 2; 1134 1135 VerticalRetraceEnd = VerticalRetraceStart + (VgaCrtcRegisters[VGA_CRTC_END_VERT_RETRACE_REG] & 0x0F); 1136 1137 if (VgaGcRegisters[VGA_GC_MISC_REG] & VGA_GC_MISC_NOALPHA) 1138 { 1139 BYTE MaximumScanLine = 1 + (VgaCrtcRegisters[VGA_CRTC_MAX_SCAN_LINE_REG] & 0x1F); 1140 1141 if (VgaCrtcRegisters[VGA_CRTC_MAX_SCAN_LINE_REG] & VGA_CRTC_MAXSCANLINE_DOUBLE) 1142 { 1143 VerticalRetraceStart <<= 1; 1144 VerticalRetraceEnd <<= 1; 1145 } 1146 else 1147 { 1148 VerticalRetraceStart *= MaximumScanLine; 1149 VerticalRetraceEnd *= MaximumScanLine; 1150 } 1151 } 1152 1153 /* Calculate the horizontal blanking duration in cycles */ 1154 HblankStart = VgaCrtcRegisters[VGA_CRTC_START_HORZ_BLANKING_REG] & 0x1F; 1155 HblankEnd = VgaCrtcRegisters[VGA_CRTC_END_HORZ_BLANKING_REG] & 0x1F; 1156 if (HblankEnd < HblankStart) HblankEnd |= 0x20; 1157 HblankDuration = ((HblankEnd - HblankStart) * Dots 1158 * CyclesPerMicrosecond + (Clock >> 1)) / Clock; 1159 1160 Vsync = ScanlineCounter >= VerticalRetraceStart && ScanlineCounter <= VerticalRetraceEnd; 1161 Hsync = (Cycles - HorizontalRetraceCycle) < (ULONGLONG)HblankDuration; 1162 1163 /* Reset the AC latch */ 1164 VgaAcLatch = FALSE; 1165 1166 /* Set a flag if there is a vertical or horizontal retrace */ 1167 if (Vsync || Hsync) Result |= VGA_STAT_DD; 1168 1169 /* Set an additional flag if there was a vertical retrace */ 1170 if (Vsync) Result |= VGA_STAT_VRETRACE; 1171 1172 return Result; 1173 } 1174 1175 case VGA_FEATURE_READ: 1176 return VgaFeatureRegister; 1177 1178 case VGA_AC_INDEX: 1179 return VgaAcIndex | (VgaAcPalDisable ? 0x20 : 0x00); 1180 1181 case VGA_AC_READ: 1182 return VgaAcRegisters[VgaAcIndex]; 1183 1184 case VGA_SEQ_INDEX: 1185 return VgaSeqIndex; 1186 1187 case VGA_SEQ_DATA: 1188 return VgaSeqRegisters[VgaSeqIndex]; 1189 1190 case VGA_DAC_MASK: 1191 { 1192 if (SvgaHdrCounter == 4) 1193 { 1194 SvgaHdrCounter = 0; 1195 return SvgaHiddenRegister; 1196 } 1197 else 1198 { 1199 SvgaHdrCounter++; 1200 return VgaDacMask; 1201 } 1202 } 1203 1204 case VGA_DAC_READ_INDEX: 1205 /* This returns the read/write state */ 1206 return (VgaDacReadWrite ? 0 : 3); 1207 1208 case VGA_DAC_WRITE_INDEX: 1209 return VgaDacIndex; 1210 1211 case VGA_DAC_DATA: 1212 { 1213 /* Ignore reads in write mode */ 1214 if (!VgaDacReadWrite) 1215 { 1216 BYTE Data = VgaDacRegisters[VgaDacIndex * 3 + VgaDacLatchCounter]; 1217 VgaDacLatchCounter++; 1218 1219 if (VgaDacLatchCounter == 3) 1220 { 1221 /* Reset the latch counter and increment the palette index */ 1222 VgaDacLatchCounter = 0; 1223 VgaDacIndex++; 1224 VgaDacIndex %= VGA_MAX_COLORS; 1225 } 1226 1227 return Data; 1228 } 1229 1230 break; 1231 } 1232 1233 case VGA_CRTC_INDEX_MONO: 1234 case VGA_CRTC_INDEX_COLOR: 1235 return VgaCrtcIndex; 1236 1237 case VGA_CRTC_DATA_MONO: 1238 case VGA_CRTC_DATA_COLOR: 1239 return VgaCrtcRegisters[VgaCrtcIndex]; 1240 1241 case VGA_GC_INDEX: 1242 return VgaGcIndex; 1243 1244 case VGA_GC_DATA: 1245 return VgaGcRegisters[VgaGcIndex]; 1246 1247 default: 1248 DPRINT1("VgaReadPort: Unknown port 0x%X\n", Port); 1249 break; 1250 } 1251 1252 return 0; 1253 } 1254 1255 static inline VOID VgaWriteSequencer(BYTE Data) 1256 { 1257 /* Save the value */ 1258 VgaSeqRegisters[VgaSeqIndex & VGA_SEQ_INDEX_MASK] = Data; 1259 1260 /* Check the index */ 1261 switch (VgaSeqIndex & VGA_SEQ_INDEX_MASK) 1262 { 1263 case SVGA_SEQ_UNLOCK_REG: 1264 { 1265 if ((Data & SVGA_SEQ_UNLOCK_MASK) == SVGA_SEQ_UNLOCKED) 1266 { 1267 /* Unlock SVGA extensions */ 1268 VgaSeqRegisters[SVGA_SEQ_UNLOCK_REG] = SVGA_SEQ_UNLOCKED; 1269 } 1270 else 1271 { 1272 /* Lock SVGA extensions */ 1273 VgaSeqRegisters[SVGA_SEQ_UNLOCK_REG] = SVGA_SEQ_LOCKED; 1274 } 1275 1276 break; 1277 } 1278 } 1279 } 1280 1281 static inline VOID VgaWriteGc(BYTE Data) 1282 { 1283 /* Save the value */ 1284 VgaGcRegisters[VgaGcIndex & VGA_GC_INDEX_MASK] = Data; 1285 1286 /* Check the index */ 1287 switch (VgaGcIndex & VGA_GC_INDEX_MASK) 1288 { 1289 case VGA_GC_MISC_REG: 1290 { 1291 /* Remove any existing VGA memory hook */ 1292 MemRemoveFastMemoryHook((PVOID)0xA0000, 0x20000); 1293 1294 if (VgaMiscRegister & VGA_MISC_RAM_ENABLED) 1295 { 1296 UCHAR MemoryMap = (VgaGcRegisters[VGA_GC_MISC_REG] >> 2) & 0x03; 1297 1298 /* Register a memory hook */ 1299 MemInstallFastMemoryHook(UlongToPtr(MemoryBase[MemoryMap]), 1300 MemorySize[MemoryMap], 1301 VgaReadMemory, 1302 VgaWriteMemory); 1303 } 1304 1305 /* The GC misc register decides if it's text or graphics mode */ 1306 ModeChanged = TRUE; 1307 break; 1308 } 1309 } 1310 } 1311 1312 static inline VOID VgaWriteCrtc(BYTE Data) 1313 { 1314 /* Save the value */ 1315 VgaCrtcRegisters[VgaCrtcIndex & VGA_CRTC_INDEX_MASK] = Data; 1316 1317 /* Check the index */ 1318 switch (VgaCrtcIndex & VGA_CRTC_INDEX_MASK) 1319 { 1320 case VGA_CRTC_END_HORZ_DISP_REG: 1321 case VGA_CRTC_VERT_DISP_END_REG: 1322 case VGA_CRTC_OVERFLOW_REG: 1323 case VGA_CRTC_MAX_SCAN_LINE_REG: 1324 { 1325 /* The video mode has changed */ 1326 ModeChanged = TRUE; 1327 break; 1328 } 1329 1330 case VGA_CRTC_CURSOR_LOC_LOW_REG: 1331 case VGA_CRTC_CURSOR_LOC_HIGH_REG: 1332 case VGA_CRTC_CURSOR_START_REG: 1333 case VGA_CRTC_CURSOR_END_REG: 1334 { 1335 /* Set the cursor changed flag */ 1336 CursorChanged = TRUE; 1337 break; 1338 } 1339 } 1340 } 1341 1342 static inline VOID VgaWriteDac(BYTE Data) 1343 { 1344 UINT i; 1345 PALETTEENTRY Entry; 1346 1347 /* Store the value in the latch */ 1348 VgaDacLatch[VgaDacLatchCounter++] = Data; 1349 if (VgaDacLatchCounter < 3) return; 1350 1351 /* Reset the latch counter */ 1352 VgaDacLatchCounter = 0; 1353 1354 /* Set the DAC register values */ 1355 VgaDacRegisters[VgaDacIndex * 3] = VgaDacLatch[0]; 1356 VgaDacRegisters[VgaDacIndex * 3 + 1] = VgaDacLatch[1]; 1357 VgaDacRegisters[VgaDacIndex * 3 + 2] = VgaDacLatch[2]; 1358 1359 /* Fill the entry structure */ 1360 Entry.peRed = VGA_DAC_TO_COLOR(VgaDacLatch[0]); 1361 Entry.peGreen = VGA_DAC_TO_COLOR(VgaDacLatch[1]); 1362 Entry.peBlue = VGA_DAC_TO_COLOR(VgaDacLatch[2]); 1363 Entry.peFlags = 0; 1364 1365 /* Update the palette entry */ 1366 SetPaletteEntries(PaletteHandle, VgaDacIndex, 1, &Entry); 1367 1368 /* Check which text palette entries are affected */ 1369 for (i = 0; i <= VGA_AC_PAL_F_REG; i++) 1370 { 1371 if (VgaAcRegisters[i] == VgaDacIndex) 1372 { 1373 /* Update the text palette entry */ 1374 SetPaletteEntries(TextPaletteHandle, i, 1, &Entry); 1375 } 1376 } 1377 1378 /* Set the palette changed flag */ 1379 PaletteChanged = TRUE; 1380 1381 /* Update the index */ 1382 VgaDacIndex++; 1383 VgaDacIndex %= VGA_MAX_COLORS; 1384 } 1385 1386 static inline VOID VgaWriteAc(BYTE Data) 1387 { 1388 PALETTEENTRY Entry; 1389 1390 ASSERT(VgaAcIndex < VGA_AC_MAX_REG); 1391 1392 /* Save the value */ 1393 if (VgaAcIndex <= VGA_AC_PAL_F_REG) 1394 { 1395 if (VgaAcPalDisable) return; 1396 1397 // DbgPrint(" AC Palette Writing %d to index %d\n", Data, VgaAcIndex); 1398 if (VgaAcRegisters[VgaAcIndex] != Data) 1399 { 1400 /* Update the AC register */ 1401 VgaAcRegisters[VgaAcIndex] = Data; 1402 1403 /* Fill the entry structure */ 1404 Entry.peRed = VGA_DAC_TO_COLOR(VgaDacRegisters[Data * 3]); 1405 Entry.peGreen = VGA_DAC_TO_COLOR(VgaDacRegisters[Data * 3 + 1]); 1406 Entry.peBlue = VGA_DAC_TO_COLOR(VgaDacRegisters[Data * 3 + 2]); 1407 Entry.peFlags = 0; 1408 1409 /* Update the palette entry and set the palette change flag */ 1410 SetPaletteEntries(TextPaletteHandle, VgaAcIndex, 1, &Entry); 1411 PaletteChanged = TRUE; 1412 } 1413 } 1414 else 1415 { 1416 VgaAcRegisters[VgaAcIndex] = Data; 1417 } 1418 } 1419 1420 static VOID WINAPI VgaWritePort(USHORT Port, BYTE Data) 1421 { 1422 DPRINT("VgaWritePort: Port 0x%X, Data 0x%02X\n", Port, Data); 1423 1424 switch (Port) 1425 { 1426 case VGA_MISC_WRITE: 1427 { 1428 VgaMiscRegister = Data; 1429 1430 if (VgaMiscRegister & 0x01) 1431 { 1432 /* Color emulation */ 1433 DPRINT1("Color emulation\n"); 1434 1435 /* Register the new I/O Ports */ 1436 RegisterIoPort(0x3D4, VgaReadPort, VgaWritePort); // VGA_CRTC_INDEX_COLOR 1437 RegisterIoPort(0x3D5, VgaReadPort, VgaWritePort); // VGA_CRTC_DATA_COLOR 1438 RegisterIoPort(0x3DA, VgaReadPort, VgaWritePort); // VGA_INSTAT1_READ_COLOR, VGA_FEATURE_WRITE_COLOR 1439 1440 /* Unregister the old ones */ 1441 UnregisterIoPort(0x3B4); // VGA_CRTC_INDEX_MONO 1442 UnregisterIoPort(0x3B5); // VGA_CRTC_DATA_MONO 1443 UnregisterIoPort(0x3BA); // VGA_INSTAT1_READ_MONO, VGA_FEATURE_WRITE_MONO 1444 } 1445 else 1446 { 1447 /* Monochrome emulation */ 1448 DPRINT1("Monochrome emulation\n"); 1449 1450 /* Register the new I/O Ports */ 1451 RegisterIoPort(0x3B4, VgaReadPort, VgaWritePort); // VGA_CRTC_INDEX_MONO 1452 RegisterIoPort(0x3B5, VgaReadPort, VgaWritePort); // VGA_CRTC_DATA_MONO 1453 RegisterIoPort(0x3BA, VgaReadPort, VgaWritePort); // VGA_INSTAT1_READ_MONO, VGA_FEATURE_WRITE_MONO 1454 1455 /* Unregister the old ones */ 1456 UnregisterIoPort(0x3D4); // VGA_CRTC_INDEX_COLOR 1457 UnregisterIoPort(0x3D5); // VGA_CRTC_DATA_COLOR 1458 UnregisterIoPort(0x3DA); // VGA_INSTAT1_READ_COLOR, VGA_FEATURE_WRITE_COLOR 1459 } 1460 1461 /* Remove any existing VGA memory hook */ 1462 MemRemoveFastMemoryHook((PVOID)0xA0000, 0x20000); 1463 1464 if (VgaMiscRegister & VGA_MISC_RAM_ENABLED) 1465 { 1466 UCHAR MemoryMap = (VgaGcRegisters[VGA_GC_MISC_REG] >> 2) & 0x03; 1467 1468 /* Register a memory hook */ 1469 MemInstallFastMemoryHook(UlongToPtr(MemoryBase[MemoryMap]), 1470 MemorySize[MemoryMap], 1471 VgaReadMemory, 1472 VgaWriteMemory); 1473 } 1474 1475 break; 1476 } 1477 1478 case VGA_FEATURE_WRITE_MONO: 1479 case VGA_FEATURE_WRITE_COLOR: 1480 { 1481 VgaFeatureRegister = Data; 1482 break; 1483 } 1484 1485 case VGA_AC_INDEX: 1486 // case VGA_AC_WRITE: 1487 { 1488 if (!VgaAcLatch) 1489 { 1490 /* Change the index */ 1491 BYTE Index = Data & 0x1F; 1492 if (Index < VGA_AC_MAX_REG) VgaAcIndex = Index; 1493 1494 /* 1495 * Change palette protection by checking for 1496 * the Palette Address Source bit. 1497 */ 1498 VgaAcPalDisable = (Data & 0x20) ? TRUE : FALSE; 1499 } 1500 else 1501 { 1502 /* Write the data */ 1503 VgaWriteAc(Data); 1504 } 1505 1506 /* Toggle the latch */ 1507 VgaAcLatch = !VgaAcLatch; 1508 break; 1509 } 1510 1511 case VGA_SEQ_INDEX: 1512 { 1513 /* Set the sequencer index register */ 1514 if ((Data & 0x1F) < SVGA_SEQ_MAX_UNLOCKED_REG 1515 && (Data & 0x1F) != VGA_SEQ_MAX_REG) 1516 { 1517 VgaSeqIndex = Data; 1518 } 1519 1520 break; 1521 } 1522 1523 case VGA_SEQ_DATA: 1524 { 1525 /* Call the sequencer function */ 1526 VgaWriteSequencer(Data); 1527 break; 1528 } 1529 1530 case VGA_DAC_MASK: 1531 { 1532 if (SvgaHdrCounter == 4) SvgaHiddenRegister = Data; 1533 else VgaDacMask = Data; 1534 1535 break; 1536 } 1537 1538 case VGA_DAC_READ_INDEX: 1539 { 1540 VgaDacReadWrite = FALSE; 1541 VgaDacIndex = Data; 1542 VgaDacLatchCounter = 0; 1543 break; 1544 } 1545 1546 case VGA_DAC_WRITE_INDEX: 1547 { 1548 VgaDacReadWrite = TRUE; 1549 VgaDacIndex = Data; 1550 VgaDacLatchCounter = 0; 1551 break; 1552 } 1553 1554 case VGA_DAC_DATA: 1555 { 1556 /* Ignore writes in read mode */ 1557 if (VgaDacReadWrite) VgaWriteDac(Data & 0x3F); 1558 break; 1559 } 1560 1561 case VGA_CRTC_INDEX_MONO: 1562 case VGA_CRTC_INDEX_COLOR: 1563 { 1564 /* Set the CRTC index register */ 1565 if (((Data & VGA_CRTC_INDEX_MASK) < SVGA_CRTC_MAX_UNLOCKED_REG) 1566 && ((Data & VGA_CRTC_INDEX_MASK) < SVGA_CRTC_UNUSED0_REG 1567 || (Data & VGA_CRTC_INDEX_MASK) > SVGA_CRTC_UNUSED6_REG) 1568 && (Data & VGA_CRTC_INDEX_MASK) != SVGA_CRTC_UNUSED7_REG) 1569 { 1570 VgaCrtcIndex = Data; 1571 } 1572 1573 break; 1574 } 1575 1576 case VGA_CRTC_DATA_MONO: 1577 case VGA_CRTC_DATA_COLOR: 1578 { 1579 /* Call the CRTC function */ 1580 VgaWriteCrtc(Data); 1581 break; 1582 } 1583 1584 case VGA_GC_INDEX: 1585 { 1586 /* Set the GC index register */ 1587 if ((Data & VGA_GC_INDEX_MASK) < SVGA_GC_MAX_UNLOCKED_REG 1588 && (Data & VGA_GC_INDEX_MASK) != SVGA_GC_UNUSED0_REG 1589 && ((Data & VGA_GC_INDEX_MASK) < SVGA_GC_UNUSED1_REG 1590 || (Data & VGA_GC_INDEX_MASK) > SVGA_GC_UNUSED10_REG)) 1591 { 1592 VgaGcIndex = Data; 1593 } 1594 1595 break; 1596 } 1597 1598 case VGA_GC_DATA: 1599 { 1600 /* Call the GC function */ 1601 VgaWriteGc(Data); 1602 break; 1603 } 1604 1605 default: 1606 DPRINT1("VgaWritePort: Unknown port 0x%X, Data 0x%02X\n", Port, Data); 1607 break; 1608 } 1609 1610 SvgaHdrCounter = 0; 1611 } 1612 1613 static inline VOID VgaVerticalRetrace(VOID) 1614 { 1615 /* If nothing has changed, just return */ 1616 // if (!ModeChanged && !CursorChanged && !PaletteChanged && !NeedsUpdate) 1617 // return; 1618 1619 /* Change the display mode */ 1620 if (ModeChanged) VgaChangeMode(); 1621 1622 /* Change the text cursor appearance */ 1623 if (CursorChanged) VgaUpdateTextCursor(); 1624 1625 if (PaletteChanged) 1626 { 1627 /* Trigger a full update of the screen */ 1628 NeedsUpdate = TRUE; 1629 UpdateRectangle.Left = 0; 1630 UpdateRectangle.Top = 0; 1631 UpdateRectangle.Right = CurrResolution.X; 1632 UpdateRectangle.Bottom = CurrResolution.Y; 1633 1634 PaletteChanged = FALSE; 1635 } 1636 1637 /* Update the contents of the framebuffer */ 1638 VgaUpdateFramebuffer(); 1639 1640 /* Ignore if there's nothing to update */ 1641 if (!NeedsUpdate) return; 1642 1643 DPRINT("Updating screen rectangle (%d, %d, %d, %d)\n", 1644 UpdateRectangle.Left, 1645 UpdateRectangle.Top, 1646 UpdateRectangle.Right, 1647 UpdateRectangle.Bottom); 1648 1649 VgaConsoleRepaintScreen(&UpdateRectangle); 1650 1651 /* Clear the update flag */ 1652 NeedsUpdate = FALSE; 1653 } 1654 1655 static VOID FASTCALL VgaHorizontalRetrace(ULONGLONG ElapsedTime) 1656 { 1657 ULONG VerticalTotal = VgaCrtcRegisters[VGA_CRTC_VERT_TOTAL_REG]; 1658 ULONG VerticalRetraceStart = VgaCrtcRegisters[VGA_CRTC_START_VERT_RETRACE_REG]; 1659 BOOLEAN BeforeVSync; 1660 ULONG ElapsedCycles = CurrentCycleCount - HorizontalRetraceCycle; 1661 ULONG Dots = (VgaSeqRegisters[VGA_SEQ_CLOCK_REG] & 1) ? 9 : 8; 1662 ULONG HorizTotalDots = ((ULONG)VgaCrtcRegisters[VGA_CRTC_HORZ_TOTAL_REG] + 5) * Dots; 1663 BYTE MaximumScanLine = 1 + (VgaCrtcRegisters[VGA_CRTC_MAX_SCAN_LINE_REG] & 0x1F); 1664 ULONG HSyncsPerSecond, HSyncs; 1665 UNREFERENCED_PARAMETER(ElapsedTime); 1666 1667 if (VgaAcRegisters[VGA_AC_CONTROL_REG] & VGA_AC_CONTROL_8BIT) HorizTotalDots >>= 1; 1668 1669 HSyncsPerSecond = VgaGetClockFrequency() / HorizTotalDots; 1670 HSyncs = (ElapsedCycles * HSyncsPerSecond + (CurrentIps >> 1)) / CurrentIps; 1671 if (HSyncs == 0) HSyncs = 1; 1672 1673 VerticalTotal |= (VgaCrtcRegisters[VGA_CRTC_OVERFLOW_REG] & VGA_CRTC_OVERFLOW_VT8) << 8; 1674 VerticalTotal |= (VgaCrtcRegisters[VGA_CRTC_OVERFLOW_REG] & VGA_CRTC_OVERFLOW_VT9) << 4; 1675 1676 VerticalRetraceStart |= (VgaCrtcRegisters[VGA_CRTC_OVERFLOW_REG] & VGA_CRTC_OVERFLOW_VRS8) << 6; 1677 VerticalRetraceStart |= (VgaCrtcRegisters[VGA_CRTC_OVERFLOW_REG] & VGA_CRTC_OVERFLOW_VRS9) << 2; 1678 1679 if (VgaGcRegisters[VGA_GC_MISC_REG] & VGA_GC_MISC_NOALPHA) 1680 { 1681 if (VgaCrtcRegisters[VGA_CRTC_MAX_SCAN_LINE_REG] & VGA_CRTC_MAXSCANLINE_DOUBLE) 1682 { 1683 VerticalRetraceStart <<= 1; 1684 VerticalTotal <<= 1; 1685 } 1686 else 1687 { 1688 VerticalRetraceStart *= MaximumScanLine; 1689 VerticalTotal *= MaximumScanLine; 1690 } 1691 } 1692 1693 /* Set the cycle */ 1694 HorizontalRetraceCycle = CurrentCycleCount; 1695 1696 /* Increment the scanline counter, but make sure we don't skip any part of the vertical retrace */ 1697 BeforeVSync = (ScanlineCounter < VerticalRetraceStart); 1698 ScanlineCounter += HSyncs; 1699 if (BeforeVSync && ScanlineCounter >= VerticalRetraceStart) ScanlineCounter = VerticalRetraceStart; 1700 1701 if (ScanlineCounter == VerticalRetraceStart) 1702 { 1703 /* Save the scanline size */ 1704 ScanlineSizeLatch = ((DWORD)VgaCrtcRegisters[VGA_CRTC_OFFSET_REG] 1705 + (((DWORD)VgaCrtcRegisters[SVGA_CRTC_EXT_DISPLAY_REG] & SVGA_CRTC_EXT_OFFSET_BIT8) << 4)) * 2; 1706 if (VgaSeqRegisters[SVGA_SEQ_EXT_MODE_REG] & SVGA_SEQ_EXT_MODE_HIGH_RES) ScanlineSizeLatch <<= 2; 1707 1708 /* Save the starting address */ 1709 StartAddressLatch = MAKEWORD(VgaCrtcRegisters[VGA_CRTC_START_ADDR_LOW_REG], 1710 VgaCrtcRegisters[VGA_CRTC_START_ADDR_HIGH_REG]) 1711 + ((VgaCrtcRegisters[SVGA_CRTC_EXT_DISPLAY_REG] & SVGA_CRTC_EXT_ADDR_BIT16) << 16) 1712 + ((VgaCrtcRegisters[SVGA_CRTC_EXT_DISPLAY_REG] & SVGA_CRTC_EXT_ADDR_BITS1718) << 15) 1713 + ((VgaCrtcRegisters[SVGA_CRTC_OVERLAY_REG] & SVGA_CRTC_EXT_ADDR_BIT19) << 12) 1714 + (VgaCrtcRegisters[VGA_CRTC_PRESET_ROW_SCAN_REG] & 0x1F) * ScanlineSizeLatch 1715 + ((VgaCrtcRegisters[VGA_CRTC_PRESET_ROW_SCAN_REG] >> 5) & 3); 1716 } 1717 1718 if (ScanlineCounter > VerticalTotal) 1719 { 1720 ScanlineCounter = 0; 1721 VgaVerticalRetrace(); 1722 } 1723 } 1724 1725 /* PUBLIC FUNCTIONS ***********************************************************/ 1726 1727 COORD VgaGetDisplayResolution(VOID) 1728 { 1729 COORD Resolution; 1730 BYTE MaximumScanLine = 1 + (VgaCrtcRegisters[VGA_CRTC_MAX_SCAN_LINE_REG] & 0x1F); 1731 1732 /* The low 8 bits are in the display registers */ 1733 Resolution.X = VgaCrtcRegisters[VGA_CRTC_END_HORZ_DISP_REG]; 1734 Resolution.Y = VgaCrtcRegisters[VGA_CRTC_VERT_DISP_END_REG]; 1735 1736 /* Set the top bits from the overflow register */ 1737 if (VgaCrtcRegisters[VGA_CRTC_OVERFLOW_REG] & VGA_CRTC_OVERFLOW_VDE8) 1738 { 1739 Resolution.Y |= 1 << 8; 1740 } 1741 if (VgaCrtcRegisters[VGA_CRTC_OVERFLOW_REG] & VGA_CRTC_OVERFLOW_VDE9) 1742 { 1743 Resolution.Y |= 1 << 9; 1744 } 1745 1746 /* Increase the values by 1 */ 1747 Resolution.X++; 1748 Resolution.Y++; 1749 1750 if (VgaGcRegisters[VGA_GC_MISC_REG] & VGA_GC_MISC_NOALPHA) 1751 { 1752 /* In "High Resolution" mode, the width of a character is always 8 pixels */ 1753 if (VgaSeqRegisters[SVGA_SEQ_EXT_MODE_REG] & SVGA_SEQ_EXT_MODE_HIGH_RES) 1754 { 1755 Resolution.X *= 8; 1756 } 1757 else 1758 { 1759 /* Multiply the horizontal resolution by the 9/8 dot mode */ 1760 Resolution.X *= (VgaSeqRegisters[VGA_SEQ_CLOCK_REG] & VGA_SEQ_CLOCK_98DM) 1761 ? 8 : 9; 1762 1763 /* The horizontal resolution is halved in 8-bit mode */ 1764 if (VgaAcRegisters[VGA_AC_CONTROL_REG] & VGA_AC_CONTROL_8BIT) Resolution.X /= 2; 1765 } 1766 } 1767 1768 if (VgaCrtcRegisters[VGA_CRTC_MAX_SCAN_LINE_REG] & VGA_CRTC_MAXSCANLINE_DOUBLE) 1769 { 1770 /* Halve the vertical resolution */ 1771 Resolution.Y >>= 1; 1772 } 1773 else 1774 { 1775 /* Divide the vertical resolution by the maximum scan line (== font size in text mode) */ 1776 Resolution.Y /= MaximumScanLine; 1777 } 1778 1779 /* Return the resolution */ 1780 return Resolution; 1781 } 1782 1783 VOID VgaRefreshDisplay(VOID) 1784 { 1785 /* Save the scanline size */ 1786 ScanlineSizeLatch = ((DWORD)VgaCrtcRegisters[VGA_CRTC_OFFSET_REG] 1787 + (((DWORD)VgaCrtcRegisters[SVGA_CRTC_EXT_DISPLAY_REG] & SVGA_CRTC_EXT_OFFSET_BIT8) << 4)) * 2; 1788 if (VgaSeqRegisters[SVGA_SEQ_EXT_MODE_REG] & SVGA_SEQ_EXT_MODE_HIGH_RES) ScanlineSizeLatch <<= 2; 1789 1790 /* Save the starting address */ 1791 StartAddressLatch = MAKEWORD(VgaCrtcRegisters[VGA_CRTC_START_ADDR_LOW_REG], 1792 VgaCrtcRegisters[VGA_CRTC_START_ADDR_HIGH_REG]) 1793 + ((VgaCrtcRegisters[SVGA_CRTC_EXT_DISPLAY_REG] & SVGA_CRTC_EXT_ADDR_BIT16) << 16) 1794 + ((VgaCrtcRegisters[SVGA_CRTC_EXT_DISPLAY_REG] & SVGA_CRTC_EXT_ADDR_BITS1718) << 15) 1795 + ((VgaCrtcRegisters[SVGA_CRTC_OVERLAY_REG] & SVGA_CRTC_EXT_ADDR_BIT19) << 12) 1796 + (VgaCrtcRegisters[VGA_CRTC_PRESET_ROW_SCAN_REG] & 0x1F) * ScanlineSizeLatch 1797 + ((VgaCrtcRegisters[VGA_CRTC_PRESET_ROW_SCAN_REG] >> 5) & 3); 1798 1799 VgaVerticalRetrace(); 1800 } 1801 1802 VOID FASTCALL VgaReadMemory(ULONG Address, PVOID Buffer, ULONG Size) 1803 { 1804 DWORD i; 1805 DWORD VideoAddress; 1806 PUCHAR BufPtr = (PUCHAR)Buffer; 1807 1808 DPRINT("VgaReadMemory: Address 0x%08X, Size %lu\n", Address, Size); 1809 1810 /* Ignore if video RAM access is disabled */ 1811 if (!Size) return; 1812 if ((VgaMiscRegister & VGA_MISC_RAM_ENABLED) == 0) return; 1813 1814 if (!(VgaGcRegisters[VGA_GC_MODE_REG] & VGA_GC_MODE_READ)) 1815 { 1816 VideoAddress = VgaTranslateAddress(Address); 1817 1818 /* Check for packed pixel, chain-4, and odd-even mode */ 1819 if (VgaSeqRegisters[SVGA_SEQ_EXT_MODE_REG] & SVGA_SEQ_EXT_MODE_HIGH_RES) 1820 { 1821 /* Just copy from the video memory */ 1822 PVOID VideoMemory = &VgaMemory[VideoAddress + (Address & 3)]; 1823 1824 switch (Size) 1825 { 1826 case sizeof(UCHAR): 1827 *(PUCHAR)Buffer = *(PUCHAR)VideoMemory; 1828 return; 1829 1830 case sizeof(USHORT): 1831 *(PUSHORT)Buffer = *(PUSHORT)VideoMemory; 1832 return; 1833 1834 case sizeof(ULONG): 1835 *(PULONG)Buffer = *(PULONG)VideoMemory; 1836 return; 1837 1838 case sizeof(ULONGLONG): 1839 *(PULONGLONG)Buffer = *(PULONGLONG)VideoMemory; 1840 return; 1841 1842 default: 1843 #if defined(__GNUC__) 1844 __builtin_memcpy(Buffer, VideoMemory, Size); 1845 #else 1846 RtlCopyMemory(Buffer, VideoMemory, Size); 1847 #endif 1848 } 1849 } 1850 else if (VgaSeqRegisters[VGA_SEQ_MEM_REG] & VGA_SEQ_MEM_C4) 1851 { 1852 i = 0; 1853 1854 /* Write the unaligned part first */ 1855 if (Address & 3) 1856 { 1857 switch (Address & 3) 1858 { 1859 case 1: 1860 BufPtr[i++] = VgaMemory[VideoAddress * VGA_NUM_BANKS + 1]; 1861 case 2: 1862 BufPtr[i++] = VgaMemory[VideoAddress * VGA_NUM_BANKS + 2]; 1863 case 3: 1864 BufPtr[i++] = VgaMemory[VideoAddress * VGA_NUM_BANKS + 3]; 1865 } 1866 1867 VideoAddress += 4; 1868 } 1869 1870 /* Copy the aligned dwords */ 1871 while ((i + 3) < Size) 1872 { 1873 *(PULONG)&BufPtr[i] = *(PULONG)&VgaMemory[VideoAddress * VGA_NUM_BANKS]; 1874 1875 i += 4; 1876 VideoAddress += 4; 1877 } 1878 1879 /* Write the remaining part */ 1880 if (i < Size) 1881 { 1882 switch (Size - i - 3) 1883 { 1884 case 3: 1885 BufPtr[i] = VgaMemory[VideoAddress * VGA_NUM_BANKS + ((Address + i) & 3)]; 1886 i++; 1887 case 2: 1888 BufPtr[i] = VgaMemory[VideoAddress * VGA_NUM_BANKS + ((Address + i) & 3)]; 1889 i++; 1890 case 1: 1891 BufPtr[i] = VgaMemory[VideoAddress * VGA_NUM_BANKS + ((Address + i) & 3)]; 1892 i++; 1893 } 1894 } 1895 } 1896 else if (VgaGcRegisters[VGA_GC_MODE_REG] & VGA_GC_MODE_OE) 1897 { 1898 i = 0; 1899 1900 /* Check if the starting address is odd */ 1901 if (Address & 1) 1902 { 1903 BufPtr[i++] = VgaMemory[VideoAddress * VGA_NUM_BANKS + 1]; 1904 VideoAddress += 2; 1905 } 1906 1907 while (i < (Size - 1)) 1908 { 1909 *(PUSHORT)&BufPtr[i] = *(PUSHORT)&VgaMemory[VideoAddress * VGA_NUM_BANKS]; 1910 1911 i += 2; 1912 VideoAddress += 2; 1913 } 1914 1915 /* Check if there is one more byte to read */ 1916 if (i == Size - 1) BufPtr[i] = VgaMemory[VideoAddress * VGA_NUM_BANKS + ((Address + i) & 1)]; 1917 } 1918 else 1919 { 1920 /* Use the selected map */ 1921 BYTE Plane = VgaGcRegisters[VGA_GC_READ_MAP_SEL_REG] & 0x03; 1922 1923 for (i = 0; i < Size; i++) 1924 { 1925 /* Copy the value to the buffer */ 1926 BufPtr[i] = VgaMemory[(VideoAddress++) * VGA_NUM_BANKS + Plane]; 1927 } 1928 } 1929 } 1930 else 1931 { 1932 const ULONG BitExpandInvertTable[] = 1933 { 1934 0xFFFFFFFF, 0xFFFFFF00, 0xFFFF00FF, 0xFFFF0000, 1935 0xFF00FFFF, 0xFF00FF00, 0xFF0000FF, 0xFF000000, 1936 0x00FFFFFF, 0x00FFFF00, 0x00FF00FF, 0x00FF0000, 1937 0x0000FFFF, 0x0000FF00, 0x000000FF, 0x00000000 1938 }; 1939 1940 ULONG ColorCompareBytes = BitExpandInvertTable[VgaGcRegisters[VGA_GC_COLOR_COMPARE_REG] & 0x0F]; 1941 ULONG ColorIgnoreBytes = BitExpandInvertTable[VgaGcRegisters[VGA_GC_COLOR_IGNORE_REG] & 0x0F]; 1942 1943 /* 1944 * These values can also be computed in the following way, but using the table seems to be faster: 1945 * 1946 * ColorCompareBytes = VgaGcRegisters[VGA_GC_COLOR_COMPARE_REG] * 0x000204081; 1947 * ColorCompareBytes &= 0x01010101; 1948 * ColorCompareBytes = ~((ColorCompareBytes << 8) - ColorCompareBytes); 1949 * 1950 * ColorIgnoreBytes = VgaGcRegisters[VGA_GC_COLOR_IGNORE_REG] * 0x000204081; 1951 * ColorIgnoreBytes &= 0x01010101; 1952 * ColorIgnoreBytes = ~((ColorIgnoreBytes << 8) - ColorIgnoreBytes); 1953 */ 1954 1955 /* Loop through each byte */ 1956 for (i = 0; i < Size; i++) 1957 { 1958 ULONG PlaneData = 0; 1959 1960 /* This should always return a plane 0 address */ 1961 VideoAddress = VgaTranslateAddress(Address + i); 1962 1963 /* Read all 4 planes */ 1964 PlaneData = *(PULONG)&VgaMemory[VideoAddress * VGA_NUM_BANKS]; 1965 1966 /* Reverse the bytes for which the color compare register is zero */ 1967 PlaneData ^= ColorCompareBytes; 1968 1969 /* Apply the color ignore register */ 1970 PlaneData |= ColorIgnoreBytes; 1971 1972 /* Store the value in the buffer */ 1973 BufPtr[i] = (PlaneData & (PlaneData >> 8) & (PlaneData >> 16) & (PlaneData >> 24)) & 0xFF; 1974 } 1975 } 1976 1977 /* Load the latch registers */ 1978 VideoAddress = VgaTranslateAddress(Address + Size - 1); 1979 *(PULONG)VgaLatchRegisters = *(PULONG)&VgaMemory[WRAP_OFFSET(VideoAddress) * VGA_NUM_BANKS]; 1980 } 1981 1982 BOOLEAN FASTCALL VgaWriteMemory(ULONG Address, PVOID Buffer, ULONG Size) 1983 { 1984 DWORD i, j; 1985 DWORD VideoAddress; 1986 PUCHAR BufPtr = (PUCHAR)Buffer; 1987 1988 DPRINT("VgaWriteMemory: Address 0x%08X, Size %lu\n", Address, Size); 1989 1990 /* Ignore if video RAM access is disabled */ 1991 if ((VgaMiscRegister & VGA_MISC_RAM_ENABLED) == 0) return TRUE; 1992 1993 /* Also ignore if write access to all planes is disabled */ 1994 if ((VgaSeqRegisters[VGA_SEQ_MASK_REG] & 0x0F) == 0x00) return TRUE; 1995 1996 if (!(VgaSeqRegisters[SVGA_SEQ_EXT_MODE_REG] & SVGA_SEQ_EXT_MODE_HIGH_RES)) 1997 { 1998 /* Loop through each byte */ 1999 for (i = 0; i < Size; i++) 2000 { 2001 VideoAddress = VgaTranslateAddress(Address + i); 2002 2003 for (j = 0; j < VGA_NUM_BANKS; j++) 2004 { 2005 /* Make sure the page is writeable */ 2006 if (!(VgaSeqRegisters[VGA_SEQ_MASK_REG] & (1 << j))) continue; 2007 2008 /* Check if this is chain-4 mode */ 2009 if (VgaSeqRegisters[VGA_SEQ_MEM_REG] & VGA_SEQ_MEM_C4) 2010 { 2011 if (((Address + i) & 0x03) != j) 2012 { 2013 /* This plane will not be accessed */ 2014 continue; 2015 } 2016 } 2017 2018 /* Check if this is odd-even mode */ 2019 if (VgaGcRegisters[VGA_GC_MODE_REG] & VGA_GC_MODE_OE) 2020 { 2021 if (((Address + i) & 0x01) != (j & 1)) 2022 { 2023 /* This plane will not be accessed */ 2024 continue; 2025 } 2026 } 2027 2028 /* Copy the value to the VGA memory */ 2029 VgaMemory[VideoAddress * VGA_NUM_BANKS + j] = VgaTranslateByteForWriting(BufPtr[i], j); 2030 } 2031 } 2032 } 2033 else 2034 { 2035 PVOID VideoMemory; 2036 2037 // TODO: Apply the page write mask! 2038 // TODO: Check whether the write mode stuff applies to packed-pixel modes 2039 2040 /* Just copy to the video memory */ 2041 VideoAddress = VgaTranslateAddress(Address); 2042 VideoMemory = &VgaMemory[VideoAddress + (Address & 3)]; 2043 2044 switch (Size) 2045 { 2046 case sizeof(UCHAR): 2047 *(PUCHAR)VideoMemory = *(PUCHAR)Buffer; 2048 return TRUE; 2049 2050 case sizeof(USHORT): 2051 *(PUSHORT)VideoMemory = *(PUSHORT)Buffer; 2052 return TRUE; 2053 2054 case sizeof(ULONG): 2055 *(PULONG)VideoMemory = *(PULONG)Buffer; 2056 return TRUE; 2057 2058 case sizeof(ULONGLONG): 2059 *(PULONGLONG)VideoMemory = *(PULONGLONG)Buffer; 2060 return TRUE; 2061 2062 default: 2063 #if defined(__GNUC__) 2064 __builtin_memcpy(VideoMemory, Buffer, Size); 2065 #else 2066 RtlCopyMemory(VideoMemory, Buffer, Size); 2067 #endif 2068 } 2069 } 2070 2071 return TRUE; 2072 } 2073 2074 VOID VgaClearMemory(VOID) 2075 { 2076 RtlZeroMemory(VgaMemory, sizeof(VgaMemory)); 2077 } 2078 2079 VOID VgaWriteTextModeFont(UINT FontNumber, CONST UCHAR* FontData, UINT Height) 2080 { 2081 UINT i, j; 2082 ASSERT(Height <= VGA_MAX_FONT_HEIGHT); 2083 2084 for (i = 0; i < VGA_FONT_CHARACTERS; i++) 2085 { 2086 /* Write the character */ 2087 for (j = 0; j < Height; j++) 2088 { 2089 VgaMemory[(i * VGA_MAX_FONT_HEIGHT + j) * VGA_NUM_BANKS + VGA_FONT_BANK] = FontData[i * Height + j]; 2090 } 2091 2092 /* Clear the unused part */ 2093 for (j = Height; j < VGA_MAX_FONT_HEIGHT; j++) 2094 { 2095 VgaMemory[(i * VGA_MAX_FONT_HEIGHT + j) * VGA_NUM_BANKS + VGA_FONT_BANK] = 0; 2096 } 2097 } 2098 } 2099 2100 BOOLEAN VgaInitialize(HANDLE TextHandle) 2101 { 2102 if (!VgaConsoleInitialize(TextHandle)) return FALSE; 2103 2104 /* Clear the SEQ, GC, CRTC and AC registers */ 2105 RtlZeroMemory(VgaSeqRegisters , sizeof(VgaSeqRegisters )); 2106 RtlZeroMemory(VgaGcRegisters , sizeof(VgaGcRegisters )); 2107 RtlZeroMemory(VgaCrtcRegisters, sizeof(VgaCrtcRegisters)); 2108 RtlZeroMemory(VgaAcRegisters , sizeof(VgaAcRegisters )); 2109 2110 /* Initialize the VGA palette and fail if it isn't successfully created */ 2111 if (!VgaInitializePalette()) return FALSE; 2112 /***/ VgaResetPalette(); /***/ 2113 2114 /* Reset the sequencer */ 2115 VgaResetSequencer(); 2116 2117 /* Clear the VGA memory */ 2118 VgaClearMemory(); 2119 2120 /* Register the I/O Ports */ 2121 RegisterIoPort(0x3CC, VgaReadPort, NULL); // VGA_MISC_READ 2122 RegisterIoPort(0x3C2, VgaReadPort, VgaWritePort); // VGA_MISC_WRITE, VGA_INSTAT0_READ 2123 RegisterIoPort(0x3CA, VgaReadPort, NULL); // VGA_FEATURE_READ 2124 RegisterIoPort(0x3C0, VgaReadPort, VgaWritePort); // VGA_AC_INDEX, VGA_AC_WRITE 2125 RegisterIoPort(0x3C1, VgaReadPort, NULL); // VGA_AC_READ 2126 RegisterIoPort(0x3C4, VgaReadPort, VgaWritePort); // VGA_SEQ_INDEX 2127 RegisterIoPort(0x3C5, VgaReadPort, VgaWritePort); // VGA_SEQ_DATA 2128 RegisterIoPort(0x3C6, VgaReadPort, VgaWritePort); // VGA_DAC_MASK 2129 RegisterIoPort(0x3C7, VgaReadPort, VgaWritePort); // VGA_DAC_READ_INDEX 2130 RegisterIoPort(0x3C8, VgaReadPort, VgaWritePort); // VGA_DAC_WRITE_INDEX 2131 RegisterIoPort(0x3C9, VgaReadPort, VgaWritePort); // VGA_DAC_DATA 2132 RegisterIoPort(0x3CE, VgaReadPort, VgaWritePort); // VGA_GC_INDEX 2133 RegisterIoPort(0x3CF, VgaReadPort, VgaWritePort); // VGA_GC_DATA 2134 2135 /* CGA ports for compatibility, unimplemented */ 2136 RegisterIoPort(0x3D8, VgaReadPort, VgaWritePort); // CGA_MODE_CTRL_REG 2137 RegisterIoPort(0x3D9, VgaReadPort, VgaWritePort); // CGA_PAL_CTRL_REG 2138 2139 HSyncTimer = CreateHardwareTimer(HARDWARE_TIMER_ENABLED, HZ_TO_NS(31469), VgaHorizontalRetrace); 2140 2141 /* Return success */ 2142 return TRUE; 2143 } 2144 2145 VOID VgaCleanup(VOID) 2146 { 2147 /* Do a final display refresh */ 2148 VgaRefreshDisplay(); 2149 2150 DestroyHardwareTimer(HSyncTimer); 2151 2152 /* Leave the current video mode */ 2153 VgaLeaveCurrentMode(); // ScreenMode 2154 2155 MemRemoveFastMemoryHook((PVOID)0xA0000, 0x20000); 2156 2157 VgaConsoleCleanup(); 2158 } 2159 2160 /* EOF */ 2161