2 * COPYRIGHT: GPL - See COPYING in the top level directory
3 * PROJECT: ReactOS Virtual DOS Machine
5 * PURPOSE: VGA hardware emulation
6 * PROGRAMMERS: Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
9 /* INCLUDES *******************************************************************/
17 #include "bios/bios.h"
19 /* PRIVATE VARIABLES **********************************************************/
21 static CONST DWORD MemoryBase
[] = { 0xA0000, 0xA0000, 0xB0000, 0xB8000 };
22 static CONST DWORD MemoryLimit
[] = { 0xAFFFF, 0xAFFFF, 0xB7FFF, 0xBFFFF };
24 #define USE_REACTOS_COLORS
25 // #define USE_DOSBOX_COLORS
27 #if defined(USE_REACTOS_COLORS)
30 static CONST COLORREF VgaDefaultPalette
[VGA_MAX_COLORS
] =
32 RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0xAA), RGB(0x00, 0xAA, 0x00), RGB(0x00, 0xAA, 0xAA),
33 RGB(0xAA, 0x00, 0x00), RGB(0xAA, 0x00, 0xAA), RGB(0xAA, 0x55, 0x00), RGB(0xAA, 0xAA, 0xAA),
34 RGB(0x55, 0x55, 0x55), RGB(0x55, 0x55, 0xFF), RGB(0x55, 0xFF, 0x55), RGB(0x55, 0xFF, 0xFF),
35 RGB(0xFF, 0x55, 0x55), RGB(0xFF, 0x55, 0xFF), RGB(0xFF, 0xFF, 0x55), RGB(0xFF, 0xFF, 0xFF),
36 RGB(0x00, 0x00, 0x00), RGB(0x10, 0x10, 0x10), RGB(0x20, 0x20, 0x20), RGB(0x35, 0x35, 0x35),
37 RGB(0x45, 0x45, 0x45), RGB(0x55, 0x55, 0x55), RGB(0x65, 0x65, 0x65), RGB(0x75, 0x75, 0x75),
38 RGB(0x8A, 0x8A, 0x8A), RGB(0x9A, 0x9A, 0x9A), RGB(0xAA, 0xAA, 0xAA), RGB(0xBA, 0xBA, 0xBA),
39 RGB(0xCA, 0xCA, 0xCA), RGB(0xDF, 0xDF, 0xDF), RGB(0xEF, 0xEF, 0xEF), RGB(0xFF, 0xFF, 0xFF),
40 RGB(0x00, 0x00, 0xFF), RGB(0x41, 0x00, 0xFF), RGB(0x82, 0x00, 0xFF), RGB(0xBE, 0x00, 0xFF),
41 RGB(0xFF, 0x00, 0xFF), RGB(0xFF, 0x00, 0xBE), RGB(0xFF, 0x00, 0x82), RGB(0xFF, 0x00, 0x41),
42 RGB(0xFF, 0x00, 0x00), RGB(0xFF, 0x41, 0x00), RGB(0xFF, 0x82, 0x00), RGB(0xFF, 0xBE, 0x00),
43 RGB(0xFF, 0xFF, 0x00), RGB(0xBE, 0xFF, 0x00), RGB(0x82, 0xFF, 0x00), RGB(0x41, 0xFF, 0x00),
44 RGB(0x00, 0xFF, 0x00), RGB(0x00, 0xFF, 0x41), RGB(0x00, 0xFF, 0x82), RGB(0x00, 0xFF, 0xBE),
45 RGB(0x00, 0xFF, 0xFF), RGB(0x00, 0xBE, 0xFF), RGB(0x00, 0x82, 0xFF), RGB(0x00, 0x41, 0xFF),
46 RGB(0x82, 0x82, 0xFF), RGB(0x9E, 0x82, 0xFF), RGB(0xBE, 0x82, 0xFF), RGB(0xDF, 0x82, 0xFF),
47 RGB(0xFF, 0x82, 0xFF), RGB(0xFF, 0x82, 0xDF), RGB(0xFF, 0x82, 0xBE), RGB(0xFF, 0x82, 0x9E),
48 RGB(0xFF, 0x82, 0x82), RGB(0xFF, 0x9E, 0x82), RGB(0xFF, 0xBE, 0x82), RGB(0xFF, 0xDF, 0x82),
49 RGB(0xFF, 0xFF, 0x82), RGB(0xDF, 0xFF, 0x82), RGB(0xBE, 0xFF, 0x82), RGB(0x9E, 0xFF, 0x82),
50 RGB(0x82, 0xFF, 0x82), RGB(0x82, 0xFF, 0x9E), RGB(0x82, 0xFF, 0xBE), RGB(0x82, 0xFF, 0xDF),
51 RGB(0x82, 0xFF, 0xFF), RGB(0x82, 0xDF, 0xFF), RGB(0x82, 0xBE, 0xFF), RGB(0x82, 0x9E, 0xFF),
52 RGB(0xBA, 0xBA, 0xFF), RGB(0xCA, 0xBA, 0xFF), RGB(0xDF, 0xBA, 0xFF), RGB(0xEF, 0xBA, 0xFF),
53 RGB(0xFF, 0xBA, 0xFF), RGB(0xFF, 0xBA, 0xEF), RGB(0xFF, 0xBA, 0xDF), RGB(0xFF, 0xBA, 0xCA),
54 RGB(0xFF, 0xBA, 0xBA), RGB(0xFF, 0xCA, 0xBA), RGB(0xFF, 0xDF, 0xBA), RGB(0xFF, 0xEF, 0xBA),
55 RGB(0xFF, 0xFF, 0xBA), RGB(0xEF, 0xFF, 0xBA), RGB(0xDF, 0xFF, 0xBA), RGB(0xCA, 0xFF, 0xBA),
56 RGB(0xBA, 0xFF, 0xBA), RGB(0xBA, 0xFF, 0xCA), RGB(0xBA, 0xFF, 0xDF), RGB(0xBA, 0xFF, 0xEF),
57 RGB(0xBA, 0xFF, 0xFF), RGB(0xBA, 0xEF, 0xFF), RGB(0xBA, 0xDF, 0xFF), RGB(0xBA, 0xCA, 0xFF),
58 RGB(0x00, 0x00, 0x71), RGB(0x1C, 0x00, 0x71), RGB(0x39, 0x00, 0x71), RGB(0x55, 0x00, 0x71),
59 RGB(0x71, 0x00, 0x71), RGB(0x71, 0x00, 0x55), RGB(0x71, 0x00, 0x39), RGB(0x71, 0x00, 0x1C),
60 RGB(0x71, 0x00, 0x00), RGB(0x71, 0x1C, 0x00), RGB(0x71, 0x39, 0x00), RGB(0x71, 0x55, 0x00),
61 RGB(0x71, 0x71, 0x00), RGB(0x55, 0x71, 0x00), RGB(0x39, 0x71, 0x00), RGB(0x1C, 0x71, 0x00),
62 RGB(0x00, 0x71, 0x00), RGB(0x00, 0x71, 0x1C), RGB(0x00, 0x71, 0x39), RGB(0x00, 0x71, 0x55),
63 RGB(0x00, 0x71, 0x71), RGB(0x00, 0x55, 0x71), RGB(0x00, 0x39, 0x71), RGB(0x00, 0x1C, 0x71),
64 RGB(0x39, 0x39, 0x71), RGB(0x45, 0x39, 0x71), RGB(0x55, 0x39, 0x71), RGB(0x61, 0x39, 0x71),
65 RGB(0x71, 0x39, 0x71), RGB(0x71, 0x39, 0x61), RGB(0x71, 0x39, 0x55), RGB(0x71, 0x39, 0x45),
66 RGB(0x71, 0x39, 0x39), RGB(0x71, 0x45, 0x39), RGB(0x71, 0x55, 0x39), RGB(0x71, 0x61, 0x39),
67 RGB(0x71, 0x71, 0x39), RGB(0x61, 0x71, 0x39), RGB(0x55, 0x71, 0x39), RGB(0x45, 0x71, 0x39),
68 RGB(0x39, 0x71, 0x39), RGB(0x39, 0x71, 0x45), RGB(0x39, 0x71, 0x55), RGB(0x39, 0x71, 0x61),
69 RGB(0x39, 0x71, 0x71), RGB(0x39, 0x61, 0x71), RGB(0x39, 0x55, 0x71), RGB(0x39, 0x45, 0x71),
70 RGB(0x51, 0x51, 0x71), RGB(0x59, 0x51, 0x71), RGB(0x61, 0x51, 0x71), RGB(0x69, 0x51, 0x71),
71 RGB(0x71, 0x51, 0x71), RGB(0x71, 0x51, 0x69), RGB(0x71, 0x51, 0x61), RGB(0x71, 0x51, 0x59),
72 RGB(0x71, 0x51, 0x51), RGB(0x71, 0x59, 0x51), RGB(0x71, 0x61, 0x51), RGB(0x71, 0x69, 0x51),
73 RGB(0x71, 0x71, 0x51), RGB(0x69, 0x71, 0x51), RGB(0x61, 0x71, 0x51), RGB(0x59, 0x71, 0x51),
74 RGB(0x51, 0x71, 0x51), RGB(0x51, 0x71, 0x59), RGB(0x51, 0x71, 0x61), RGB(0x51, 0x71, 0x69),
75 RGB(0x51, 0x71, 0x71), RGB(0x51, 0x69, 0x71), RGB(0x51, 0x61, 0x71), RGB(0x51, 0x59, 0x71),
76 RGB(0x00, 0x00, 0x41), RGB(0x10, 0x00, 0x41), RGB(0x20, 0x00, 0x41), RGB(0x31, 0x00, 0x41),
77 RGB(0x41, 0x00, 0x41), RGB(0x41, 0x00, 0x31), RGB(0x41, 0x00, 0x20), RGB(0x41, 0x00, 0x10),
78 RGB(0x41, 0x00, 0x00), RGB(0x41, 0x10, 0x00), RGB(0x41, 0x20, 0x00), RGB(0x41, 0x31, 0x00),
79 RGB(0x41, 0x41, 0x00), RGB(0x31, 0x41, 0x00), RGB(0x20, 0x41, 0x00), RGB(0x10, 0x41, 0x00),
80 RGB(0x00, 0x41, 0x00), RGB(0x00, 0x41, 0x10), RGB(0x00, 0x41, 0x20), RGB(0x00, 0x41, 0x31),
81 RGB(0x00, 0x41, 0x41), RGB(0x00, 0x31, 0x41), RGB(0x00, 0x20, 0x41), RGB(0x00, 0x10, 0x41),
82 RGB(0x20, 0x20, 0x41), RGB(0x28, 0x20, 0x41), RGB(0x31, 0x20, 0x41), RGB(0x39, 0x20, 0x41),
83 RGB(0x41, 0x20, 0x41), RGB(0x41, 0x20, 0x39), RGB(0x41, 0x20, 0x31), RGB(0x41, 0x20, 0x28),
84 RGB(0x41, 0x20, 0x20), RGB(0x41, 0x28, 0x20), RGB(0x41, 0x31, 0x20), RGB(0x41, 0x39, 0x20),
85 RGB(0x41, 0x41, 0x20), RGB(0x39, 0x41, 0x20), RGB(0x31, 0x41, 0x20), RGB(0x28, 0x41, 0x20),
86 RGB(0x20, 0x41, 0x20), RGB(0x20, 0x41, 0x28), RGB(0x20, 0x41, 0x31), RGB(0x20, 0x41, 0x39),
87 RGB(0x20, 0x41, 0x41), RGB(0x20, 0x39, 0x41), RGB(0x20, 0x31, 0x41), RGB(0x20, 0x28, 0x41),
88 RGB(0x2D, 0x2D, 0x41), RGB(0x31, 0x2D, 0x41), RGB(0x35, 0x2D, 0x41), RGB(0x3D, 0x2D, 0x41),
89 RGB(0x41, 0x2D, 0x41), RGB(0x41, 0x2D, 0x3D), RGB(0x41, 0x2D, 0x35), RGB(0x41, 0x2D, 0x31),
90 RGB(0x41, 0x2D, 0x2D), RGB(0x41, 0x31, 0x2D), RGB(0x41, 0x35, 0x2D), RGB(0x41, 0x3D, 0x2D),
91 RGB(0x41, 0x41, 0x2D), RGB(0x3D, 0x41, 0x2D), RGB(0x35, 0x41, 0x2D), RGB(0x31, 0x41, 0x2D),
92 RGB(0x2D, 0x41, 0x2D), RGB(0x2D, 0x41, 0x31), RGB(0x2D, 0x41, 0x35), RGB(0x2D, 0x41, 0x3D),
93 RGB(0x2D, 0x41, 0x41), RGB(0x2D, 0x3D, 0x41), RGB(0x2D, 0x35, 0x41), RGB(0x2D, 0x31, 0x41),
94 RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00),
95 RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00)
98 #elif defined(USE_DOSBOX_COLORS)
101 static CONST COLORREF VgaDefaultPalette
[VGA_MAX_COLORS
] =
103 RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0xAA), RGB(0x00, 0xAA, 0x00), RGB(0x00, 0xAA, 0xAA),
104 RGB(0xAA, 0x00, 0x00), RGB(0xAA, 0x00, 0xAA), RGB(0xAA, 0x55, 0x00), RGB(0xAA, 0xAA, 0xAA),
105 RGB(0x55, 0x55, 0x55), RGB(0x55, 0x55, 0xFF), RGB(0x55, 0xFF, 0x55), RGB(0x55, 0xFF, 0xFF),
106 RGB(0xFF, 0x55, 0x55), RGB(0xFF, 0x55, 0xFF), RGB(0xFF, 0xFF, 0x55), RGB(0xFF, 0xFF, 0xFF),
107 RGB(0x00, 0x00, 0x00), RGB(0x14, 0x14, 0x14), RGB(0x20, 0x20, 0x20), RGB(0x2C, 0x2C, 0x2C),
108 RGB(0x38, 0x38, 0x38), RGB(0x45, 0x45, 0x45), RGB(0x51, 0x51, 0x51), RGB(0x61, 0x61, 0x61),
109 RGB(0x71, 0x71, 0x71), RGB(0x82, 0x82, 0x82), RGB(0x92, 0x92, 0x92), RGB(0xA2, 0xA2, 0xA2),
110 RGB(0xB6, 0xB6, 0xB6), RGB(0xCB, 0xCB, 0xCB), RGB(0xE3, 0xE3, 0xE3), RGB(0xFF, 0xFF, 0xFF),
111 RGB(0x00, 0x00, 0xFF), RGB(0x41, 0x00, 0xFF), RGB(0x7D, 0x00, 0xFF), RGB(0xBE, 0x00, 0xFF),
112 RGB(0xFF, 0x00, 0xFF), RGB(0xFF, 0x00, 0xBE), RGB(0xFF, 0x00, 0x7D), RGB(0xFF, 0x00, 0x41),
113 RGB(0xFF, 0x00, 0x00), RGB(0xFF, 0x41, 0x00), RGB(0xFF, 0x7D, 0x00), RGB(0xFF, 0xBE, 0x00),
114 RGB(0xFF, 0xFF, 0x00), RGB(0xBE, 0xFF, 0x00), RGB(0x7D, 0xFF, 0x00), RGB(0x41, 0xFF, 0x00),
115 RGB(0x00, 0xFF, 0x00), RGB(0x00, 0xFF, 0x41), RGB(0x00, 0xFF, 0x7D), RGB(0x00, 0xFF, 0xBE),
116 RGB(0x00, 0xFF, 0xFF), RGB(0x00, 0xBE, 0xFF), RGB(0x00, 0x7D, 0xFF), RGB(0x00, 0x41, 0xFF),
117 RGB(0x7D, 0x7D, 0xFF), RGB(0x9E, 0x7D, 0xFF), RGB(0xBE, 0x7D, 0xFF), RGB(0xDF, 0x7D, 0xFF),
118 RGB(0xFF, 0x7D, 0xFF), RGB(0xFF, 0x7D, 0xDF), RGB(0xFF, 0x7D, 0xBE), RGB(0xFF, 0x7D, 0x9E),
120 RGB(0xFF, 0x7D, 0x7D), RGB(0xFF, 0x9E, 0x7D), RGB(0xFF, 0xBE, 0x7D), RGB(0xFF, 0xDF, 0x7D),
121 RGB(0xFF, 0xFF, 0x7D), RGB(0xDF, 0xFF, 0x7D), RGB(0xBE, 0xFF, 0x7D), RGB(0x9E, 0xFF, 0x7D),
122 RGB(0x7D, 0xFF, 0x7D), RGB(0x7D, 0xFF, 0x9E), RGB(0x7D, 0xFF, 0xBE), RGB(0x7D, 0xFF, 0xDF),
123 RGB(0x7D, 0xFF, 0xFF), RGB(0x7D, 0xDF, 0xFF), RGB(0x7D, 0xBE, 0xFF), RGB(0x7D, 0x9E, 0xFF),
124 RGB(0xB6, 0xB6, 0xFF), RGB(0xC7, 0xB6, 0xFF), RGB(0xDB, 0xB6, 0xFF), RGB(0xEB, 0xB6, 0xFF),
125 RGB(0xFF, 0xB6, 0xFF), RGB(0xFF, 0xB6, 0xEB), RGB(0xFF, 0xB6, 0xDB), RGB(0xFF, 0xB6, 0xC7),
126 RGB(0xFF, 0xB6, 0xB6), RGB(0xFF, 0xC7, 0xB6), RGB(0xFF, 0xDB, 0xB6), RGB(0xFF, 0xEB, 0xB6),
127 RGB(0xFF, 0xFF, 0xB6), RGB(0xEB, 0xFF, 0xB6), RGB(0xDB, 0xFF, 0xB6), RGB(0xC7, 0xFF, 0xB6),
128 RGB(0xB6, 0xFF, 0xB6), RGB(0xB6, 0xFF, 0xC7), RGB(0xB6, 0xFF, 0xDB), RGB(0xB6, 0xFF, 0xEB),
129 RGB(0xB6, 0xFF, 0xFF), RGB(0xB6, 0xEB, 0xFF), RGB(0xB6, 0xDB, 0xFF), RGB(0xB6, 0xC7, 0xFF),
130 RGB(0x00, 0x00, 0x71), RGB(0x1C, 0x00, 0x71), RGB(0x38, 0x00, 0x71), RGB(0x55, 0x00, 0x71),
131 RGB(0x71, 0x00, 0x71), RGB(0x71, 0x00, 0x55), RGB(0x71, 0x00, 0x38), RGB(0x71, 0x00, 0x1C),
132 RGB(0x71, 0x00, 0x00), RGB(0x71, 0x1C, 0x00), RGB(0x71, 0x38, 0x00), RGB(0x71, 0x55, 0x00),
133 RGB(0x71, 0x71, 0x00), RGB(0x55, 0x71, 0x00), RGB(0x38, 0x71, 0x00), RGB(0x1C, 0x71, 0x00),
134 RGB(0x00, 0x71, 0x00), RGB(0x00, 0x71, 0x1C), RGB(0x00, 0x71, 0x38), RGB(0x00, 0x71, 0x55),
135 RGB(0x00, 0x71, 0x71), RGB(0x00, 0x55, 0x71), RGB(0x00, 0x38, 0x71), RGB(0x00, 0x1C, 0x71),
137 RGB(0x38, 0x38, 0x71), RGB(0x45, 0x38, 0x71), RGB(0x55, 0x38, 0x71), RGB(0x61, 0x38, 0x71),
138 RGB(0x71, 0x38, 0x71), RGB(0x71, 0x38, 0x61), RGB(0x71, 0x38, 0x55), RGB(0x71, 0x38, 0x45),
139 RGB(0x71, 0x38, 0x38), RGB(0x71, 0x45, 0x38), RGB(0x71, 0x55, 0x38), RGB(0x71, 0x61, 0x38),
140 RGB(0x71, 0x71, 0x38), RGB(0x61, 0x71, 0x38), RGB(0x55, 0x71, 0x38), RGB(0x45, 0x71, 0x38),
141 RGB(0x38, 0x71, 0x38), RGB(0x38, 0x71, 0x45), RGB(0x38, 0x71, 0x55), RGB(0x38, 0x71, 0x61),
142 RGB(0x38, 0x71, 0x71), RGB(0x38, 0x61, 0x71), RGB(0x38, 0x55, 0x71), RGB(0x38, 0x45, 0x71),
143 RGB(0x51, 0x51, 0x71), RGB(0x59, 0x51, 0x71), RGB(0x61, 0x51, 0x71), RGB(0x69, 0x51, 0x71),
144 RGB(0x71, 0x51, 0x71), RGB(0x71, 0x51, 0x69), RGB(0x71, 0x51, 0x61), RGB(0x71, 0x51, 0x59),
145 RGB(0x71, 0x51, 0x51), RGB(0x71, 0x59, 0x51), RGB(0x71, 0x61, 0x51), RGB(0x71, 0x69, 0x51),
146 RGB(0x71, 0x71, 0x51), RGB(0x69, 0x71, 0x51), RGB(0x61, 0x71, 0x51), RGB(0x59, 0x71, 0x51),
147 RGB(0x51, 0x71, 0x51), RGB(0x51, 0x71, 0x59), RGB(0x51, 0x71, 0x61), RGB(0x51, 0x71, 0x69),
148 RGB(0x51, 0x71, 0x71), RGB(0x51, 0x69, 0x71), RGB(0x51, 0x61, 0x71), RGB(0x51, 0x59, 0x71),
149 RGB(0x00, 0x00, 0x41), RGB(0x10, 0x00, 0x41), RGB(0x20, 0x00, 0x41), RGB(0x30, 0x00, 0x41),
150 RGB(0x41, 0x00, 0x41), RGB(0x41, 0x00, 0x30), RGB(0x41, 0x00, 0x20), RGB(0x41, 0x00, 0x10),
151 RGB(0x41, 0x00, 0x00), RGB(0x41, 0x10, 0x00), RGB(0x41, 0x20, 0x00), RGB(0x41, 0x30, 0x00),
152 RGB(0x41, 0x41, 0x00), RGB(0x30, 0x41, 0x00), RGB(0x20, 0x41, 0x00), RGB(0x10, 0x41, 0x00),
154 RGB(0x00, 0x41, 0x00), RGB(0x00, 0x41, 0x10), RGB(0x00, 0x41, 0x20), RGB(0x00, 0x41, 0x30),
155 RGB(0x00, 0x41, 0x41), RGB(0x00, 0x30, 0x41), RGB(0x00, 0x20, 0x41), RGB(0x00, 0x10, 0x41),
156 RGB(0x20, 0x20, 0x41), RGB(0x28, 0x20, 0x41), RGB(0x30, 0x20, 0x41), RGB(0x38, 0x20, 0x41),
157 RGB(0x41, 0x20, 0x41), RGB(0x41, 0x20, 0x38), RGB(0x41, 0x20, 0x30), RGB(0x41, 0x20, 0x28),
158 RGB(0x41, 0x20, 0x20), RGB(0x41, 0x28, 0x20), RGB(0x41, 0x30, 0x20), RGB(0x41, 0x38, 0x20),
159 RGB(0x41, 0x41, 0x20), RGB(0x38, 0x41, 0x20), RGB(0x30, 0x41, 0x20), RGB(0x28, 0x41, 0x20),
160 RGB(0x20, 0x41, 0x20), RGB(0x20, 0x41, 0x28), RGB(0x20, 0x41, 0x30), RGB(0x20, 0x41, 0x38),
161 RGB(0x20, 0x41, 0x41), RGB(0x20, 0x38, 0x41), RGB(0x20, 0x30, 0x41), RGB(0x20, 0x28, 0x41),
162 RGB(0x2C, 0x2C, 0x41), RGB(0x30, 0x2C, 0x41), RGB(0x34, 0x2C, 0x41), RGB(0x3C, 0x2C, 0x41),
163 RGB(0x41, 0x2C, 0x41), RGB(0x41, 0x2C, 0x3C), RGB(0x41, 0x2C, 0x34), RGB(0x41, 0x2C, 0x30),
164 RGB(0x41, 0x2C, 0x2C), RGB(0x41, 0x30, 0x2C), RGB(0x41, 0x34, 0x2C), RGB(0x41, 0x3C, 0x2C),
165 RGB(0x41, 0x41, 0x2C), RGB(0x3C, 0x41, 0x2C), RGB(0x34, 0x41, 0x2C), RGB(0x30, 0x41, 0x2C),
166 RGB(0x2C, 0x41, 0x2C), RGB(0x2C, 0x41, 0x30), RGB(0x2C, 0x41, 0x34), RGB(0x2C, 0x41, 0x3C),
167 RGB(0x2C, 0x41, 0x41), RGB(0x2C, 0x3C, 0x41), RGB(0x2C, 0x34, 0x41), RGB(0x2C, 0x30, 0x41),
168 RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00),
169 RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00)
174 static CONSOLE_SCREEN_BUFFER_INFO ConsoleInfo
;
176 static BYTE VgaMemory
[VGA_NUM_BANKS
* VGA_BANK_SIZE
];
177 static LPVOID ConsoleFramebuffer
= NULL
;
178 static HANDLE TextConsoleBuffer
= NULL
;
179 static HANDLE GraphicsConsoleBuffer
= NULL
;
180 static HANDLE ConsoleMutex
= NULL
;
181 static HPALETTE PaletteHandle
= NULL
;
182 static BOOLEAN DoubleVision
= FALSE
;
184 static BYTE VgaLatchRegisters
[VGA_NUM_BANKS
] = {0, 0, 0, 0};
186 static BYTE VgaMiscRegister
;
187 static BYTE VgaFeatureRegister
;
189 static BYTE VgaSeqIndex
= VGA_SEQ_RESET_REG
;
190 static BYTE VgaSeqRegisters
[VGA_SEQ_MAX_REG
];
192 static BYTE VgaCrtcIndex
= VGA_CRTC_HORZ_TOTAL_REG
;
193 static BYTE VgaCrtcRegisters
[VGA_CRTC_MAX_REG
];
195 static BYTE VgaGcIndex
= VGA_GC_RESET_REG
;
196 static BYTE VgaGcRegisters
[VGA_GC_MAX_REG
];
198 static BOOLEAN VgaAcLatch
= FALSE
;
199 static BOOLEAN VgaAcPalDisable
= TRUE
;
200 static BYTE VgaAcIndex
= VGA_AC_PAL_0_REG
;
201 static BYTE VgaAcRegisters
[VGA_AC_MAX_REG
];
203 // static VGA_REGISTERS VgaRegisters;
205 static BYTE VgaDacMask
= 0xFF;
206 static WORD VgaDacIndex
= 0;
207 static BOOLEAN VgaDacReadWrite
= FALSE
;
208 static BYTE VgaDacRegisters
[VGA_PALETTE_SIZE
];
210 static BOOLEAN InVerticalRetrace
= FALSE
;
211 static BOOLEAN InHorizontalRetrace
= FALSE
;
213 static BOOLEAN NeedsUpdate
= FALSE
;
214 static BOOLEAN ModeChanged
= TRUE
;
215 static BOOLEAN CursorMoved
= FALSE
;
216 static BOOLEAN PaletteChanged
= FALSE
;
223 } ScreenMode
= TEXT_MODE
;
225 static SMALL_RECT UpdateRectangle
= { 0, 0, 0, 0 };
227 /* PRIVATE FUNCTIONS **********************************************************/
229 static inline DWORD
VgaGetAddressSize(VOID
)
231 if (VgaCrtcRegisters
[VGA_CRTC_UNDERLINE_REG
] & VGA_CRTC_UNDERLINE_DWORD
)
233 /* Double-word addressing */
234 return 4; // sizeof(DWORD)
236 else if (VgaCrtcRegisters
[VGA_CRTC_MODE_CONTROL_REG
] & VGA_CRTC_MODE_CONTROL_BYTE
)
238 /* Byte addressing */
239 return 1; // sizeof(BYTE)
243 /* Word addressing */
244 return 2; // sizeof(WORD)
248 static inline DWORD
VgaTranslateReadAddress(DWORD Address
)
250 DWORD Offset
= Address
- VgaGetVideoBaseAddress();
253 /* Check for chain-4 and odd-even mode */
254 if (VgaSeqRegisters
[VGA_SEQ_MEM_REG
] & VGA_SEQ_MEM_C4
)
256 /* The lowest two bits are the plane number */
260 else if (VgaGcRegisters
[VGA_GC_MODE_REG
] & VGA_GC_MODE_OE
)
262 /* The LSB is the plane number */
268 /* Use the read mode */
269 Plane
= VgaGcRegisters
[VGA_GC_READ_MAP_SEL_REG
] & 0x03;
272 /* Multiply the offset by the address size */
273 Offset
*= VgaGetAddressSize();
275 return Offset
+ Plane
* VGA_BANK_SIZE
;
278 static inline DWORD
VgaTranslateWriteAddress(DWORD Address
)
280 DWORD Offset
= Address
- VgaGetVideoBaseAddress();
282 /* Check for chain-4 and odd-even mode */
283 if (VgaSeqRegisters
[VGA_SEQ_MEM_REG
] & VGA_SEQ_MEM_C4
)
285 /* Shift the offset to the right by 2 */
288 else if (VgaGcRegisters
[VGA_GC_MODE_REG
] & VGA_GC_MODE_OE
)
290 /* Shift the offset to the right by 1 */
294 /* Multiply the offset by the address size */
295 Offset
*= VgaGetAddressSize();
297 /* Return the offset on plane 0 */
301 static inline BYTE
VgaTranslateByteForWriting(BYTE Data
, BYTE Plane
)
303 BYTE WriteMode
= VgaGcRegisters
[VGA_GC_MODE_REG
] & 3;
304 BYTE BitMask
= VgaGcRegisters
[VGA_GC_BITMASK_REG
];
308 /* In write mode 1 just return the latch register */
309 return VgaLatchRegisters
[Plane
];
314 /* Write modes 0 and 3 rotate the data to the right first */
315 BYTE RotateCount
= VgaGcRegisters
[VGA_GC_ROTATE_REG
] & 7;
316 Data
= LOBYTE(((DWORD
)Data
>> RotateCount
) | ((DWORD
)Data
<< (8 - RotateCount
)));
320 /* Write mode 2 expands the appropriate bit to all 8 bits */
321 Data
= (Data
& (1 << Plane
)) ? 0xFF : 0x00;
327 * In write mode 0, the enable set/reset register decides if the
328 * set/reset bit should be expanded to all 8 bits.
330 if (VgaGcRegisters
[VGA_GC_ENABLE_RESET_REG
] & (1 << Plane
))
332 /* Copy the bit from the set/reset register to all 8 bits */
333 Data
= (VgaGcRegisters
[VGA_GC_RESET_REG
] & (1 << Plane
)) ? 0xFF : 0x00;
339 /* Write modes 0 and 2 then perform a logical operation on the data and latch */
340 BYTE LogicalOperation
= (VgaGcRegisters
[VGA_GC_ROTATE_REG
] >> 3) & 3;
342 if (LogicalOperation
== 1) Data
&= VgaLatchRegisters
[Plane
];
343 else if (LogicalOperation
== 2) Data
|= VgaLatchRegisters
[Plane
];
344 else if (LogicalOperation
== 3) Data
^= VgaLatchRegisters
[Plane
];
348 /* For write mode 3, we AND the bitmask with the data, which is used as the new bitmask */
351 /* Then we expand the bit in the set/reset field */
352 Data
= (VgaGcRegisters
[VGA_GC_RESET_REG
] & (1 << Plane
)) ? 0xFF : 0x00;
355 /* Bits cleared in the bitmask are replaced with latch register bits */
356 Data
= (Data
& BitMask
) | (VgaLatchRegisters
[Plane
] & (~BitMask
));
358 /* Return the byte */
362 static inline VOID
VgaMarkForUpdate(SHORT Row
, SHORT Column
)
364 /* Check if this is the first time the rectangle is updated */
367 UpdateRectangle
.Left
= UpdateRectangle
.Top
= MAXSHORT
;
368 UpdateRectangle
.Right
= UpdateRectangle
.Bottom
= MINSHORT
;
371 /* Expand the rectangle to include the point */
372 UpdateRectangle
.Left
= min(UpdateRectangle
.Left
, Column
);
373 UpdateRectangle
.Right
= max(UpdateRectangle
.Right
, Column
);
374 UpdateRectangle
.Top
= min(UpdateRectangle
.Top
, Row
);
375 UpdateRectangle
.Bottom
= max(UpdateRectangle
.Bottom
, Row
);
377 /* Set the update request flag */
381 static VOID
VgaWriteSequencer(BYTE Data
)
383 ASSERT(VgaSeqIndex
< VGA_SEQ_MAX_REG
);
386 VgaSeqRegisters
[VgaSeqIndex
] = Data
;
389 static VOID
VgaWriteGc(BYTE Data
)
391 ASSERT(VgaGcIndex
< VGA_GC_MAX_REG
);
394 VgaGcRegisters
[VgaGcIndex
] = Data
;
396 /* Check the index */
399 case VGA_GC_MISC_REG
:
401 /* The GC misc register decides if it's text or graphics mode */
408 static VOID
VgaWriteCrtc(BYTE Data
)
410 ASSERT(VgaGcIndex
< VGA_CRTC_MAX_REG
);
413 VgaCrtcRegisters
[VgaCrtcIndex
] = Data
;
415 /* Check the index */
416 switch (VgaCrtcIndex
)
418 case VGA_CRTC_END_HORZ_DISP_REG
:
419 case VGA_CRTC_VERT_DISP_END_REG
:
420 case VGA_CRTC_OVERFLOW_REG
:
422 /* The video mode has changed */
427 case VGA_CRTC_CURSOR_LOC_LOW_REG
:
428 case VGA_CRTC_CURSOR_LOC_HIGH_REG
:
429 case VGA_CRTC_CURSOR_START_REG
:
430 case VGA_CRTC_CURSOR_END_REG
:
432 /* Set the cursor moved flag */
439 static VOID
VgaWriteDac(BYTE Data
)
445 VgaDacRegisters
[VgaDacIndex
] = Data
;
447 /* Find the palette index */
448 PaletteIndex
= VgaDacIndex
/ 3;
450 /* Fill the entry structure */
451 Entry
.peRed
= VGA_DAC_TO_COLOR(VgaDacRegisters
[PaletteIndex
* 3]);
452 Entry
.peGreen
= VGA_DAC_TO_COLOR(VgaDacRegisters
[PaletteIndex
* 3 + 1]);
453 Entry
.peBlue
= VGA_DAC_TO_COLOR(VgaDacRegisters
[PaletteIndex
* 3 + 2]);
456 /* Update the palette entry and set the palette change flag */
457 SetPaletteEntries(PaletteHandle
, PaletteIndex
, 1, &Entry
);
458 PaletteChanged
= TRUE
;
460 /* Update the index */
462 VgaDacIndex
%= VGA_PALETTE_SIZE
;
465 static VOID
VgaWriteAc(BYTE Data
)
467 ASSERT(VgaAcIndex
< VGA_AC_MAX_REG
);
470 if (VgaAcIndex
<= VGA_AC_PAL_F_REG
)
472 if (VgaAcPalDisable
) return;
474 // DbgPrint(" AC Palette Writing %d to index %d\n", Data, VgaAcIndex);
475 if (VgaAcRegisters
[VgaAcIndex
] != Data
)
477 /* Update the AC register and set the palette change flag */
478 VgaAcRegisters
[VgaAcIndex
] = Data
;
479 PaletteChanged
= TRUE
;
484 VgaAcRegisters
[VgaAcIndex
] = Data
;
488 static VOID
VgaRestoreDefaultPalette(PPALETTEENTRY Entries
, USHORT NumOfEntries
)
492 /* Copy the colors of the default palette to the DAC and console palette */
493 for (i
= 0; i
< NumOfEntries
; i
++)
495 /* Set the palette entries */
496 Entries
[i
].peRed
= GetRValue(VgaDefaultPalette
[i
]);
497 Entries
[i
].peGreen
= GetGValue(VgaDefaultPalette
[i
]);
498 Entries
[i
].peBlue
= GetBValue(VgaDefaultPalette
[i
]);
499 Entries
[i
].peFlags
= 0;
501 /* Set the DAC registers */
502 VgaDacRegisters
[i
* 3] = VGA_COLOR_TO_DAC(GetRValue(VgaDefaultPalette
[i
]));
503 VgaDacRegisters
[i
* 3 + 1] = VGA_COLOR_TO_DAC(GetGValue(VgaDefaultPalette
[i
]));
504 VgaDacRegisters
[i
* 3 + 2] = VGA_COLOR_TO_DAC(GetBValue(VgaDefaultPalette
[i
]));
508 static BOOLEAN
VgaInitializePalette(VOID
)
510 LPLOGPALETTE Palette
;
512 /* Allocate storage space for the palette */
513 Palette
= (LPLOGPALETTE
)HeapAlloc(GetProcessHeap(),
516 VGA_MAX_COLORS
* sizeof(PALETTEENTRY
));
517 if (Palette
== NULL
) return FALSE
;
519 /* Initialize the palette */
520 Palette
->palVersion
= 0x0300;
521 Palette
->palNumEntries
= VGA_MAX_COLORS
;
523 /* Restore the default palette */
524 VgaRestoreDefaultPalette(Palette
->palPalEntry
, Palette
->palNumEntries
);
526 /* Create the palette */
527 PaletteHandle
= CreatePalette(Palette
);
529 /* Free the palette */
530 HeapFree(GetProcessHeap(), 0, Palette
);
532 /* Fail if the palette wasn't successfully created... */
533 if (PaletteHandle
== NULL
) return FALSE
;
535 /* ... otherwise return success */
539 static BOOL
VgaEnterGraphicsMode(PCOORD Resolution
)
542 CONSOLE_GRAPHICS_BUFFER_INFO GraphicsBufferInfo
;
543 BYTE BitmapInfoBuffer
[VGA_BITMAP_INFO_SIZE
];
544 LPBITMAPINFO BitmapInfo
= (LPBITMAPINFO
)BitmapInfoBuffer
;
545 LPWORD PaletteIndex
= (LPWORD
)(BitmapInfo
->bmiColors
);
547 LONG Width
= Resolution
->X
;
548 LONG Height
= Resolution
->Y
;
550 /* Use DoubleVision mode if the resolution is too small */
551 if (Width
< VGA_MINIMUM_WIDTH
&& Height
< VGA_MINIMUM_HEIGHT
)
559 DoubleVision
= FALSE
;
562 /* Fill the bitmap info header */
563 ZeroMemory(&BitmapInfo
->bmiHeader
, sizeof(BITMAPINFOHEADER
));
564 BitmapInfo
->bmiHeader
.biSize
= sizeof(BITMAPINFOHEADER
);
565 BitmapInfo
->bmiHeader
.biWidth
= Width
;
566 BitmapInfo
->bmiHeader
.biHeight
= Height
;
567 BitmapInfo
->bmiHeader
.biBitCount
= 8;
568 BitmapInfo
->bmiHeader
.biPlanes
= 1;
569 BitmapInfo
->bmiHeader
.biCompression
= BI_RGB
;
570 BitmapInfo
->bmiHeader
.biSizeImage
= Width
* Height
/* * 1 == biBitCount / 8 */;
572 /* Fill the palette data */
573 for (i
= 0; i
< (VGA_PALETTE_SIZE
/ 3); i
++) PaletteIndex
[i
] = (WORD
)i
;
575 /* Fill the console graphics buffer info */
576 GraphicsBufferInfo
.dwBitMapInfoLength
= VGA_BITMAP_INFO_SIZE
;
577 GraphicsBufferInfo
.lpBitMapInfo
= BitmapInfo
;
578 GraphicsBufferInfo
.dwUsage
= DIB_PAL_COLORS
;
580 /* Create the buffer */
581 GraphicsConsoleBuffer
= CreateConsoleScreenBuffer(GENERIC_READ
| GENERIC_WRITE
,
582 FILE_SHARE_READ
| FILE_SHARE_WRITE
,
584 CONSOLE_GRAPHICS_BUFFER
,
585 &GraphicsBufferInfo
);
586 if (GraphicsConsoleBuffer
== INVALID_HANDLE_VALUE
) return FALSE
;
588 /* Save the framebuffer address and mutex */
589 ConsoleFramebuffer
= GraphicsBufferInfo
.lpBitMap
;
590 ConsoleMutex
= GraphicsBufferInfo
.hMutex
;
592 /* Clear the framebuffer */
593 ZeroMemory(ConsoleFramebuffer
, BitmapInfo
->bmiHeader
.biSizeImage
);
595 /* Set the active buffer */
596 SetConsoleActiveScreenBuffer(GraphicsConsoleBuffer
);
598 /* Set the graphics mode palette */
599 SetConsolePalette(GraphicsConsoleBuffer
,
603 /* Set the screen mode flag */
604 ScreenMode
= GRAPHICS_MODE
;
609 static VOID
VgaLeaveGraphicsMode(VOID
)
611 /* Release the console framebuffer mutex */
612 ReleaseMutex(ConsoleMutex
);
614 /* Switch back to the default console text buffer */
615 // SetConsoleActiveScreenBuffer(TextConsoleBuffer);
617 /* Cleanup the video data */
618 CloseHandle(ConsoleMutex
);
620 CloseHandle(GraphicsConsoleBuffer
);
621 GraphicsConsoleBuffer
= NULL
;
622 DoubleVision
= FALSE
;
625 static BOOL
VgaEnterTextMode(PCOORD Resolution
)
629 /* Switch to the text buffer */
630 SetConsoleActiveScreenBuffer(TextConsoleBuffer
);
632 /* Resize the console */
633 ConRect
.Left
= 0; // ConsoleInfo.srWindow.Left;
634 ConRect
.Top
= ConsoleInfo
.srWindow
.Top
;
635 ConRect
.Right
= ConRect
.Left
+ Resolution
->X
- 1;
636 ConRect
.Bottom
= ConRect
.Top
+ Resolution
->Y
- 1;
638 * Use this trick to effectively resize the console buffer and window,
640 * - SetConsoleScreenBufferSize fails if the new console screen buffer size
641 * is smaller than the current console window size, and:
642 * - SetConsoleWindowInfo fails if the new console window size is larger
643 * than the current console screen buffer size.
645 SetConsoleScreenBufferSize(TextConsoleBuffer
, *Resolution
);
646 SetConsoleWindowInfo(TextConsoleBuffer
, TRUE
, &ConRect
);
647 SetConsoleScreenBufferSize(TextConsoleBuffer
, *Resolution
);
648 /* Update the saved console information */
649 GetConsoleScreenBufferInfo(TextConsoleBuffer
, &ConsoleInfo
);
651 /* Allocate a framebuffer */
652 ConsoleFramebuffer
= HeapAlloc(GetProcessHeap(),
654 Resolution
->X
* Resolution
->Y
655 * sizeof(CHAR_INFO
));
656 if (ConsoleFramebuffer
== NULL
)
658 DisplayMessage(L
"An unexpected error occurred!\n");
664 * Set the text mode palette.
666 * WARNING: This call should fail on Windows (and therefore
667 * we get the default palette and our external behaviour is
668 * just like Windows' one), but it should success on ReactOS
669 * (so that we get console palette changes even for text-mode
670 * screen-buffers, which is a new feature on ReactOS).
672 SetConsolePalette(TextConsoleBuffer
,
676 /* Set the screen mode flag */
677 ScreenMode
= TEXT_MODE
;
682 static VOID
VgaLeaveTextMode(VOID
)
684 /* Free the old framebuffer */
685 HeapFree(GetProcessHeap(), 0, ConsoleFramebuffer
);
686 ConsoleFramebuffer
= NULL
;
689 static VOID
VgaChangeMode(VOID
)
691 COORD Resolution
= VgaGetDisplayResolution();
693 if (ScreenMode
== GRAPHICS_MODE
)
695 /* Leave the current graphics mode */
696 VgaLeaveGraphicsMode();
700 /* Leave the current text mode */
704 /* Check if the new mode is alphanumeric */
705 if (!(VgaGcRegisters
[VGA_GC_MISC_REG
] & VGA_GC_MISC_NOALPHA
))
707 /* Enter new text mode */
708 if (!VgaEnterTextMode(&Resolution
))
710 DisplayMessage(L
"An unexpected VGA error occurred while switching into text mode.");
717 /* Enter graphics mode */
718 if (!VgaEnterGraphicsMode(&Resolution
))
720 DisplayMessage(L
"An unexpected VGA error occurred while switching into graphics mode.");
726 /* Trigger a full update of the screen */
728 UpdateRectangle
.Left
= 0;
729 UpdateRectangle
.Top
= 0;
730 UpdateRectangle
.Right
= Resolution
.X
;
731 UpdateRectangle
.Bottom
= Resolution
.Y
;
733 /* Reset the mode change flag */
737 static VOID
VgaUpdateFramebuffer(VOID
)
740 COORD Resolution
= VgaGetDisplayResolution();
741 DWORD AddressSize
= VgaGetAddressSize();
742 DWORD Address
= MAKEWORD(VgaCrtcRegisters
[VGA_CRTC_START_ADDR_LOW_REG
],
743 VgaCrtcRegisters
[VGA_CRTC_START_ADDR_HIGH_REG
]);
744 DWORD ScanlineSize
= (DWORD
)VgaCrtcRegisters
[VGA_CRTC_OFFSET_REG
] * 2;
747 * If console framebuffer is NULL, that means something went wrong
748 * earlier and this is the final display refresh.
750 if (ConsoleFramebuffer
== NULL
) return;
752 /* Check if this is text mode or graphics mode */
753 if (VgaGcRegisters
[VGA_GC_MISC_REG
] & VGA_GC_MISC_NOALPHA
)
756 PBYTE GraphicsBuffer
= (PBYTE
)ConsoleFramebuffer
;
759 * Synchronize access to the graphics framebuffer
760 * with the console framebuffer mutex.
762 WaitForSingleObject(ConsoleMutex
, INFINITE
);
764 /* Loop through the scanlines */
765 for (i
= 0; i
< Resolution
.Y
; i
++)
767 /* Loop through the pixels */
768 for (j
= 0; j
< Resolution
.X
; j
++)
772 /* Check the shifting mode */
773 if (VgaGcRegisters
[VGA_GC_MODE_REG
] & VGA_GC_MODE_SHIFT256
)
775 /* 4 bits shifted from each plane */
777 /* Check if this is 16 or 256 color mode */
778 if (VgaAcRegisters
[VGA_AC_CONTROL_REG
] & VGA_AC_CONTROL_8BIT
)
780 /* One byte per pixel */
781 PixelData
= VgaMemory
[(j
% VGA_NUM_BANKS
) * VGA_BANK_SIZE
782 + (Address
+ (j
/ VGA_NUM_BANKS
))
787 /* 4-bits per pixel */
789 PixelData
= VgaMemory
[(j
% VGA_NUM_BANKS
) * VGA_BANK_SIZE
790 + (Address
+ (j
/ (VGA_NUM_BANKS
* 2)))
793 /* Check if we should use the highest 4 bits or lowest 4 */
794 if (((j
/ VGA_NUM_BANKS
) % 2) == 0)
806 else if (VgaGcRegisters
[VGA_GC_MODE_REG
] & VGA_GC_MODE_SHIFTREG
)
808 /* Check if this is 16 or 256 color mode */
809 if (VgaAcRegisters
[VGA_AC_CONTROL_REG
] & VGA_AC_CONTROL_8BIT
)
811 // TODO: NOT IMPLEMENTED
812 DPRINT1("8-bit interleaved mode is not implemented!\n");
817 * 2 bits shifted from plane 0 and 2 for the first 4 pixels,
818 * then 2 bits shifted from plane 1 and 3 for the next 4
820 BYTE LowPlaneData
= VgaMemory
[((j
/ 4) % 2) * VGA_BANK_SIZE
821 + (Address
+ (j
/ 8)) * AddressSize
];
822 BYTE HighPlaneData
= VgaMemory
[(((j
/ 4) % 2) + 2) * VGA_BANK_SIZE
823 + (Address
+ (j
/ 8)) * AddressSize
];
825 /* Extract the two bits from each plane */
826 LowPlaneData
= (LowPlaneData
>> (6 - ((j
% 4) * 2))) & 3;
827 HighPlaneData
= (HighPlaneData
>> (6 - ((j
% 4) * 2))) & 3;
829 /* Combine them into the pixel */
830 PixelData
= LowPlaneData
| (HighPlaneData
<< 2);
835 /* 1 bit shifted from each plane */
837 /* Check if this is 16 or 256 color mode */
838 if (VgaAcRegisters
[VGA_AC_CONTROL_REG
] & VGA_AC_CONTROL_8BIT
)
840 /* 8 bits per pixel, 2 on each plane */
842 for (k
= 0; k
< VGA_NUM_BANKS
; k
++)
844 /* The data is on plane k, 4 pixels per byte */
845 BYTE PlaneData
= VgaMemory
[k
* VGA_BANK_SIZE
846 + (Address
+ (j
/ VGA_NUM_BANKS
))
849 /* The mask of the first bit in the pair */
850 BYTE BitMask
= 1 << (((3 - (j
% VGA_NUM_BANKS
)) * 2) + 1);
852 /* Bits 0, 1, 2 and 3 come from the first bit of the pair */
853 if (PlaneData
& BitMask
) PixelData
|= 1 << k
;
855 /* Bits 4, 5, 6 and 7 come from the second bit of the pair */
856 if (PlaneData
& (BitMask
>> 1)) PixelData
|= 1 << (k
+ 4);
861 /* 4 bits per pixel, 1 on each plane */
863 for (k
= 0; k
< VGA_NUM_BANKS
; k
++)
865 BYTE PlaneData
= VgaMemory
[k
* VGA_BANK_SIZE
866 + (Address
+ (j
/ (VGA_NUM_BANKS
* 2)))
869 /* If the bit on that plane is set, set it */
870 if (PlaneData
& (1 << (7 - (j
% 8)))) PixelData
|= 1 << k
;
875 if (!(VgaAcRegisters
[VGA_AC_CONTROL_REG
] & VGA_AC_CONTROL_8BIT
))
878 * In 16 color mode, the value is an index to the AC registers
879 * if external palette access is disabled, otherwise (in case
880 * of palette loading) it is a blank pixel.
882 PixelData
= (VgaAcPalDisable
? VgaAcRegisters
[PixelData
& 0x0F]
886 /* Take into account DoubleVision mode when checking for pixel updates */
889 /* Now check if the resulting pixel data has changed */
890 if (GraphicsBuffer
[(i
* Resolution
.X
* 4) + (j
* 2)] != PixelData
)
892 /* Yes, write the new value */
893 GraphicsBuffer
[(i
* Resolution
.X
* 4) + (j
* 2)] = PixelData
;
894 GraphicsBuffer
[(i
* Resolution
.X
* 4) + (j
* 2 + 1)] = PixelData
;
895 GraphicsBuffer
[((i
* 2 + 1) * Resolution
.X
* 2) + (j
* 2)] = PixelData
;
896 GraphicsBuffer
[((i
* 2 + 1) * Resolution
.X
* 2) + (j
* 2 + 1)] = PixelData
;
898 /* Mark the specified pixel as changed */
899 VgaMarkForUpdate(i
, j
);
904 /* Now check if the resulting pixel data has changed */
905 if (GraphicsBuffer
[i
* Resolution
.X
+ j
] != PixelData
)
907 /* Yes, write the new value */
908 GraphicsBuffer
[i
* Resolution
.X
+ j
] = PixelData
;
910 /* Mark the specified pixel as changed */
911 VgaMarkForUpdate(i
, j
);
916 /* Move to the next scanline */
917 Address
+= ScanlineSize
;
921 * Release the console framebuffer mutex
922 * so that we allow for repainting.
924 ReleaseMutex(ConsoleMutex
);
930 PCHAR_INFO CharBuffer
= (PCHAR_INFO
)ConsoleFramebuffer
;
933 /* Loop through the scanlines */
934 for (i
= 0; i
< Resolution
.Y
; i
++)
936 /* Loop through the characters */
937 for (j
= 0; j
< Resolution
.X
; j
++)
939 CurrentAddr
= LOWORD((Address
+ j
) * AddressSize
);
941 /* Plane 0 holds the character itself */
942 CharInfo
.Char
.AsciiChar
= VgaMemory
[CurrentAddr
];
944 /* Plane 1 holds the attribute */
945 CharInfo
.Attributes
= VgaMemory
[CurrentAddr
+ VGA_BANK_SIZE
];
947 /* Now check if the resulting character data has changed */
948 if ((CharBuffer
[i
* Resolution
.X
+ j
].Char
.AsciiChar
!= CharInfo
.Char
.AsciiChar
)
949 || (CharBuffer
[i
* Resolution
.X
+ j
].Attributes
!= CharInfo
.Attributes
))
951 /* Yes, write the new value */
952 CharBuffer
[i
* Resolution
.X
+ j
] = CharInfo
;
954 /* Mark the specified cell as changed */
955 VgaMarkForUpdate(i
, j
);
959 /* Move to the next scanline */
960 Address
+= ScanlineSize
;
965 static VOID
VgaUpdateTextCursor(VOID
)
968 CONSOLE_CURSOR_INFO CursorInfo
;
969 BYTE CursorStart
= VgaCrtcRegisters
[VGA_CRTC_CURSOR_START_REG
] & 0x3F;
970 BYTE CursorEnd
= VgaCrtcRegisters
[VGA_CRTC_CURSOR_END_REG
] & 0x1F;
971 DWORD ScanlineSize
= (DWORD
)VgaCrtcRegisters
[VGA_CRTC_OFFSET_REG
] * 2;
972 BYTE TextSize
= 1 + (VgaCrtcRegisters
[VGA_CRTC_MAX_SCAN_LINE_REG
] & 0x1F);
973 WORD Location
= MAKEWORD(VgaCrtcRegisters
[VGA_CRTC_CURSOR_LOC_LOW_REG
],
974 VgaCrtcRegisters
[VGA_CRTC_CURSOR_LOC_HIGH_REG
]);
976 /* Just return if we are not in text mode */
977 if (VgaGcRegisters
[VGA_GC_MISC_REG
] & VGA_GC_MISC_NOALPHA
) return;
979 if (CursorStart
< CursorEnd
)
982 CursorInfo
.bVisible
= TRUE
;
983 CursorInfo
.dwSize
= (100 * (CursorEnd
- CursorStart
)) / TextSize
;
988 CursorInfo
.bVisible
= FALSE
;
989 CursorInfo
.dwSize
= 0;
992 /* Add the cursor skew to the location */
993 Location
+= (VgaCrtcRegisters
[VGA_CRTC_CURSOR_END_REG
] >> 5) & 3;
995 /* Find the coordinates of the new position */
996 Position
.X
= (WORD
)(Location
% ScanlineSize
);
997 Position
.Y
= (WORD
)(Location
/ ScanlineSize
);
999 /* Update the physical cursor */
1000 SetConsoleCursorInfo(TextConsoleBuffer
, &CursorInfo
);
1001 SetConsoleCursorPosition(TextConsoleBuffer
, Position
);
1003 /* Reset the cursor move flag */
1004 CursorMoved
= FALSE
;
1007 static BYTE WINAPI
VgaReadPort(ULONG Port
)
1009 DPRINT("VgaReadPort: Port 0x%X\n", Port
);
1014 return VgaMiscRegister
;
1016 case VGA_INSTAT0_READ
:
1017 return 0; // Not implemented
1019 case VGA_INSTAT1_READ_MONO
:
1020 case VGA_INSTAT1_READ_COLOR
:
1024 /* Reset the AC latch */
1027 /* Set a flag if there is a vertical or horizontal retrace */
1028 if (InVerticalRetrace
|| InHorizontalRetrace
) Result
|= VGA_STAT_DD
;
1030 /* Set an additional flag if there was a vertical retrace */
1031 if (InVerticalRetrace
) Result
|= VGA_STAT_VRETRACE
;
1033 /* Clear the flags */
1034 InHorizontalRetrace
= InVerticalRetrace
= FALSE
;
1039 case VGA_FEATURE_READ
:
1040 return VgaFeatureRegister
;
1046 return VgaAcRegisters
[VgaAcIndex
];
1052 return VgaSeqRegisters
[VgaSeqIndex
];
1057 case VGA_DAC_READ_INDEX
:
1058 /* This returns the read/write state */
1059 return (VgaDacReadWrite
? 0 : 3);
1061 case VGA_DAC_WRITE_INDEX
:
1062 return (VgaDacIndex
/ 3);
1066 /* Ignore reads in write mode */
1067 if (!VgaDacReadWrite
)
1069 BYTE Data
= VgaDacRegisters
[VgaDacIndex
++];
1070 VgaDacIndex
%= VGA_PALETTE_SIZE
;
1077 case VGA_CRTC_INDEX_MONO
:
1078 case VGA_CRTC_INDEX_COLOR
:
1079 return VgaCrtcIndex
;
1081 case VGA_CRTC_DATA_MONO
:
1082 case VGA_CRTC_DATA_COLOR
:
1083 return VgaCrtcRegisters
[VgaCrtcIndex
];
1089 return VgaGcRegisters
[VgaGcIndex
];
1092 DPRINT1("VgaReadPort: Unknown port 0x%X\n", Port
);
1099 static VOID WINAPI
VgaWritePort(ULONG Port
, BYTE Data
)
1101 DPRINT("VgaWritePort: Port 0x%X, Data 0x%02X\n", Port
, Data
);
1105 case VGA_MISC_WRITE
:
1107 VgaMiscRegister
= Data
;
1109 if (VgaMiscRegister
& 0x01)
1111 /* Color emulation */
1112 DPRINT1("Color emulation\n");
1114 /* Register the new I/O Ports */
1115 RegisterIoPort(0x3D4, VgaReadPort
, VgaWritePort
); // VGA_CRTC_INDEX_COLOR
1116 RegisterIoPort(0x3D5, VgaReadPort
, VgaWritePort
); // VGA_CRTC_DATA_COLOR
1117 RegisterIoPort(0x3DA, VgaReadPort
, VgaWritePort
); // VGA_INSTAT1_READ_COLOR, VGA_FEATURE_WRITE_COLOR
1119 /* Unregister the old ones */
1120 UnregisterIoPort(0x3B4); // VGA_CRTC_INDEX_MONO
1121 UnregisterIoPort(0x3B5); // VGA_CRTC_DATA_MONO
1122 UnregisterIoPort(0x3BA); // VGA_INSTAT1_READ_MONO, VGA_FEATURE_WRITE_MONO
1126 /* Monochrome emulation */
1127 DPRINT1("Monochrome emulation\n");
1129 /* Register the new I/O Ports */
1130 RegisterIoPort(0x3B4, VgaReadPort
, VgaWritePort
); // VGA_CRTC_INDEX_MONO
1131 RegisterIoPort(0x3B5, VgaReadPort
, VgaWritePort
); // VGA_CRTC_DATA_MONO
1132 RegisterIoPort(0x3BA, VgaReadPort
, VgaWritePort
); // VGA_INSTAT1_READ_MONO, VGA_FEATURE_WRITE_MONO
1134 /* Unregister the old ones */
1135 UnregisterIoPort(0x3D4); // VGA_CRTC_INDEX_COLOR
1136 UnregisterIoPort(0x3D5); // VGA_CRTC_DATA_COLOR
1137 UnregisterIoPort(0x3DA); // VGA_INSTAT1_READ_COLOR, VGA_FEATURE_WRITE_COLOR
1140 // if (VgaMiscRegister & 0x02) { /* Enable RAM access */ } else { /* Disable RAM access */ }
1144 case VGA_FEATURE_WRITE_MONO
:
1145 case VGA_FEATURE_WRITE_COLOR
:
1147 VgaFeatureRegister
= Data
;
1152 // case VGA_AC_WRITE:
1156 /* Change the index */
1157 BYTE Index
= Data
& 0x1F;
1158 if (Index
< VGA_AC_MAX_REG
) VgaAcIndex
= Index
;
1161 * Change palette protection by checking for
1162 * the Palette Address Source bit.
1164 VgaAcPalDisable
= (Data
& 0x20) ? TRUE
: FALSE
;
1168 /* Write the data */
1172 /* Toggle the latch */
1173 VgaAcLatch
= !VgaAcLatch
;
1179 /* Set the sequencer index register */
1180 if (Data
< VGA_SEQ_MAX_REG
) VgaSeqIndex
= Data
;
1186 /* Call the sequencer function */
1187 VgaWriteSequencer(Data
);
1197 case VGA_DAC_READ_INDEX
:
1199 VgaDacReadWrite
= FALSE
;
1200 VgaDacIndex
= Data
* 3;
1204 case VGA_DAC_WRITE_INDEX
:
1206 VgaDacReadWrite
= TRUE
;
1207 VgaDacIndex
= Data
* 3;
1213 /* Ignore writes in read mode */
1214 if (VgaDacReadWrite
) VgaWriteDac(Data
& 0x3F);
1218 case VGA_CRTC_INDEX_MONO
:
1219 case VGA_CRTC_INDEX_COLOR
:
1221 /* Set the CRTC index register */
1222 if (Data
< VGA_CRTC_MAX_REG
) VgaCrtcIndex
= Data
;
1226 case VGA_CRTC_DATA_MONO
:
1227 case VGA_CRTC_DATA_COLOR
:
1229 /* Call the CRTC function */
1236 /* Set the GC index register */
1237 if (Data
< VGA_GC_MAX_REG
) VgaGcIndex
= Data
;
1243 /* Call the GC function */
1249 DPRINT1("VgaWritePort: Unknown port 0x%X\n", Port
);
1254 /* PUBLIC FUNCTIONS ***********************************************************/
1256 DWORD
VgaGetVideoBaseAddress(VOID
)
1258 return MemoryBase
[(VgaGcRegisters
[VGA_GC_MISC_REG
] >> 2) & 0x03];
1261 DWORD
VgaGetVideoLimitAddress(VOID
)
1263 return MemoryLimit
[(VgaGcRegisters
[VGA_GC_MISC_REG
] >> 2) & 0x03];
1266 COORD
VgaGetDisplayResolution(VOID
)
1269 BYTE MaximumScanLine
= 1 + (VgaCrtcRegisters
[VGA_CRTC_MAX_SCAN_LINE_REG
] & 0x1F);
1271 /* The low 8 bits are in the display registers */
1272 Resolution
.X
= VgaCrtcRegisters
[VGA_CRTC_END_HORZ_DISP_REG
];
1273 Resolution
.Y
= VgaCrtcRegisters
[VGA_CRTC_VERT_DISP_END_REG
];
1275 /* Set the top bits from the overflow register */
1276 if (VgaCrtcRegisters
[VGA_CRTC_OVERFLOW_REG
] & VGA_CRTC_OVERFLOW_VDE8
)
1278 Resolution
.Y
|= 1 << 8;
1280 if (VgaCrtcRegisters
[VGA_CRTC_OVERFLOW_REG
] & VGA_CRTC_OVERFLOW_VDE9
)
1282 Resolution
.Y
|= 1 << 9;
1285 /* Increase the values by 1 */
1289 if (VgaGcRegisters
[VGA_GC_MISC_REG
] & VGA_GC_MISC_NOALPHA
)
1291 /* Multiply the horizontal resolution by the 9/8 dot mode */
1292 Resolution
.X
*= (VgaSeqRegisters
[VGA_SEQ_CLOCK_REG
] & VGA_SEQ_CLOCK_98DM
)
1295 /* The horizontal resolution is halved in 8-bit mode */
1296 if (VgaAcRegisters
[VGA_AC_CONTROL_REG
] & VGA_AC_CONTROL_8BIT
) Resolution
.X
/= 2;
1299 if (VgaCrtcRegisters
[VGA_CRTC_MAX_SCAN_LINE_REG
] & VGA_CRTC_MAXSCANLINE_DOUBLE
)
1301 /* Halve the vertical resolution */
1306 /* Divide the vertical resolution by the maximum scan line (== font size in text mode) */
1307 Resolution
.Y
/= MaximumScanLine
;
1310 /* Return the resolution */
1314 VOID
VgaRefreshDisplay(VOID
)
1316 HANDLE ConsoleBufferHandle
= NULL
;
1319 /* Set the vertical retrace flag */
1320 InVerticalRetrace
= TRUE
;
1322 /* If nothing has changed, just return */
1323 if (!ModeChanged
&& !CursorMoved
&& !PaletteChanged
&& !NeedsUpdate
)
1326 /* Change the display mode */
1327 if (ModeChanged
) VgaChangeMode();
1329 /* Change the text cursor location */
1330 if (CursorMoved
) VgaUpdateTextCursor();
1332 /* Retrieve the current resolution */
1333 Resolution
= VgaGetDisplayResolution();
1337 /* Trigger a full update of the screen */
1339 UpdateRectangle
.Left
= 0;
1340 UpdateRectangle
.Top
= 0;
1341 UpdateRectangle
.Right
= Resolution
.X
;
1342 UpdateRectangle
.Bottom
= Resolution
.Y
;
1344 PaletteChanged
= FALSE
;
1347 /* Update the contents of the framebuffer */
1348 VgaUpdateFramebuffer();
1350 /* Ignore if there's nothing to update */
1351 if (!NeedsUpdate
) return;
1353 DPRINT("Updating screen rectangle (%d, %d, %d, %d)\n",
1354 UpdateRectangle
.Left
,
1355 UpdateRectangle
.Top
,
1356 UpdateRectangle
.Right
,
1357 UpdateRectangle
.Bottom
);
1359 /* Check if this is text mode or graphics mode */
1360 if (VgaGcRegisters
[VGA_GC_MISC_REG
] & VGA_GC_MISC_NOALPHA
)
1363 ConsoleBufferHandle
= GraphicsConsoleBuffer
;
1368 COORD Origin
= { UpdateRectangle
.Left
, UpdateRectangle
.Top
};
1369 ConsoleBufferHandle
= TextConsoleBuffer
;
1371 /* Write the data to the console */
1372 WriteConsoleOutputA(TextConsoleBuffer
,
1373 (PCHAR_INFO
)ConsoleFramebuffer
,
1379 /* In DoubleVision mode, scale the update rectangle */
1382 UpdateRectangle
.Left
*= 2;
1383 UpdateRectangle
.Top
*= 2;
1384 UpdateRectangle
.Right
= UpdateRectangle
.Right
* 2 + 1;
1385 UpdateRectangle
.Bottom
= UpdateRectangle
.Bottom
* 2 + 1;
1388 /* Redraw the screen */
1389 InvalidateConsoleDIBits(ConsoleBufferHandle
, &UpdateRectangle
);
1391 /* Clear the update flag */
1392 NeedsUpdate
= FALSE
;
1395 VOID
VgaHorizontalRetrace(VOID
)
1398 InHorizontalRetrace
= TRUE
;
1401 VOID
VgaReadMemory(DWORD Address
, LPBYTE Buffer
, DWORD Size
)
1406 DPRINT("VgaReadMemory: Address 0x%08X, Size %lu\n", Address
, Size
);
1408 /* Ignore if video RAM access is disabled */
1409 if ((VgaMiscRegister
& VGA_MISC_RAM_ENABLED
) == 0) return;
1411 /* Loop through each byte */
1412 for (i
= 0; i
< Size
; i
++)
1414 VideoAddress
= VgaTranslateReadAddress(Address
+ i
);
1416 /* Load the latch registers */
1417 VgaLatchRegisters
[0] = VgaMemory
[LOWORD(VideoAddress
)];
1418 VgaLatchRegisters
[1] = VgaMemory
[VGA_BANK_SIZE
+ LOWORD(VideoAddress
)];
1419 VgaLatchRegisters
[2] = VgaMemory
[(2 * VGA_BANK_SIZE
) + LOWORD(VideoAddress
)];
1420 VgaLatchRegisters
[3] = VgaMemory
[(3 * VGA_BANK_SIZE
) + LOWORD(VideoAddress
)];
1422 /* Copy the value to the buffer */
1423 Buffer
[i
] = VgaMemory
[VideoAddress
];
1427 VOID
VgaWriteMemory(DWORD Address
, LPBYTE Buffer
, DWORD Size
)
1432 DPRINT("VgaWriteMemory: Address 0x%08X, Size %lu\n", Address
, Size
);
1434 /* Ignore if video RAM access is disabled */
1435 if ((VgaMiscRegister
& VGA_MISC_RAM_ENABLED
) == 0) return;
1437 /* Also ignore if write access to all planes is disabled */
1438 if ((VgaSeqRegisters
[VGA_SEQ_MASK_REG
] & 0x0F) == 0x00) return;
1440 /* Loop through each byte */
1441 for (i
= 0; i
< Size
; i
++)
1443 VideoAddress
= VgaTranslateWriteAddress(Address
+ i
);
1445 for (j
= 0; j
< VGA_NUM_BANKS
; j
++)
1447 /* Make sure the page is writeable */
1448 if (!(VgaSeqRegisters
[VGA_SEQ_MASK_REG
] & (1 << j
))) continue;
1450 /* Check if this is chain-4 mode */
1451 if (VgaSeqRegisters
[VGA_SEQ_MEM_REG
] & VGA_SEQ_MEM_C4
)
1453 if (((Address
+ i
) & 3) != j
)
1455 /* This plane will not be accessed */
1460 /* Check if this is odd-even mode */
1461 if (VgaGcRegisters
[VGA_GC_MODE_REG
] & VGA_GC_MODE_OE
)
1463 if (((Address
+ i
) & 1) != (j
& 1))
1465 /* This plane will not be accessed */
1470 /* Copy the value to the VGA memory */
1471 VgaMemory
[VideoAddress
+ j
* VGA_BANK_SIZE
] = VgaTranslateByteForWriting(Buffer
[i
], j
);
1476 VOID
VgaClearMemory(VOID
)
1478 ZeroMemory(VgaMemory
, sizeof(VgaMemory
));
1481 VOID
VgaResetPalette(VOID
)
1483 PALETTEENTRY Entries
[VGA_MAX_COLORS
];
1485 /* Restore the default palette */
1486 VgaRestoreDefaultPalette(Entries
, VGA_MAX_COLORS
);
1487 SetPaletteEntries(PaletteHandle
, 0, VGA_MAX_COLORS
, Entries
);
1488 PaletteChanged
= TRUE
;
1491 BOOLEAN
VgaInitialize(HANDLE TextHandle
)
1493 /* Save the default text-mode console output handle */
1494 if (TextHandle
== INVALID_HANDLE_VALUE
) return FALSE
;
1495 TextConsoleBuffer
= TextHandle
;
1497 /* Save the console information */
1498 if (!GetConsoleScreenBufferInfo(TextConsoleBuffer
, &ConsoleInfo
))
1503 /* Initialize the VGA palette and fail if it isn't successfully created */
1504 if (!VgaInitializePalette()) return FALSE
;
1505 /***/ VgaResetPalette(); /***/
1507 /* Switch to the text buffer */
1508 SetConsoleActiveScreenBuffer(TextConsoleBuffer
);
1510 /* Clear the VGA memory */
1513 /* Register the I/O Ports */
1514 RegisterIoPort(0x3CC, VgaReadPort
, NULL
); // VGA_MISC_READ
1515 RegisterIoPort(0x3C2, VgaReadPort
, VgaWritePort
); // VGA_MISC_WRITE, VGA_INSTAT0_READ
1516 RegisterIoPort(0x3CA, VgaReadPort
, NULL
); // VGA_FEATURE_READ
1517 RegisterIoPort(0x3C0, VgaReadPort
, VgaWritePort
); // VGA_AC_INDEX, VGA_AC_WRITE
1518 RegisterIoPort(0x3C1, VgaReadPort
, NULL
); // VGA_AC_READ
1519 RegisterIoPort(0x3C4, VgaReadPort
, VgaWritePort
); // VGA_SEQ_INDEX
1520 RegisterIoPort(0x3C5, VgaReadPort
, VgaWritePort
); // VGA_SEQ_DATA
1521 RegisterIoPort(0x3C6, VgaReadPort
, VgaWritePort
); // VGA_DAC_MASK
1522 RegisterIoPort(0x3C7, VgaReadPort
, VgaWritePort
); // VGA_DAC_READ_INDEX
1523 RegisterIoPort(0x3C8, VgaReadPort
, VgaWritePort
); // VGA_DAC_WRITE_INDEX
1524 RegisterIoPort(0x3C9, VgaReadPort
, VgaWritePort
); // VGA_DAC_DATA
1525 RegisterIoPort(0x3CE, VgaReadPort
, VgaWritePort
); // VGA_GC_INDEX
1526 RegisterIoPort(0x3CF, VgaReadPort
, VgaWritePort
); // VGA_GC_DATA
1528 /* Return success */