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 *******************************************************************/
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 HANDLE VgaSavedConsoleHandle
= NULL
;
175 static CONSOLE_SCREEN_BUFFER_INFO VgaSavedConsoleInfo
;
177 static BYTE VgaMemory
[VGA_NUM_BANKS
* VGA_BANK_SIZE
];
178 static LPVOID ConsoleFramebuffer
= NULL
;
179 static HANDLE TextConsoleBuffer
= NULL
;
180 static HANDLE GraphicsConsoleBuffer
= NULL
;
181 static HANDLE ConsoleMutex
= NULL
;
182 static HPALETTE PaletteHandle
= NULL
;
183 static BOOLEAN DoubleVision
= FALSE
;
185 static BYTE VgaLatchRegisters
[VGA_NUM_BANKS
] = {0, 0, 0, 0};
187 static BYTE VgaMiscRegister
;
188 static BYTE VgaFeatureRegister
;
190 static BYTE VgaSeqIndex
= VGA_SEQ_RESET_REG
;
191 static BYTE VgaSeqRegisters
[VGA_SEQ_MAX_REG
];
193 static BYTE VgaCrtcIndex
= VGA_CRTC_HORZ_TOTAL_REG
;
194 static BYTE VgaCrtcRegisters
[VGA_CRTC_MAX_REG
];
196 static BYTE VgaGcIndex
= VGA_GC_RESET_REG
;
197 static BYTE VgaGcRegisters
[VGA_GC_MAX_REG
];
199 static BOOLEAN VgaAcLatch
= FALSE
;
200 static BOOLEAN VgaAcPalDisable
= TRUE
;
201 static BYTE VgaAcIndex
= VGA_AC_PAL_0_REG
;
202 static BYTE VgaAcRegisters
[VGA_AC_MAX_REG
];
204 // static VGA_REGISTERS VgaRegisters;
206 static BYTE VgaDacMask
= 0xFF;
207 static WORD VgaDacIndex
= 0;
208 static BOOLEAN VgaDacReadWrite
= FALSE
;
209 static BYTE VgaDacRegisters
[VGA_PALETTE_SIZE
];
211 static BOOLEAN InVerticalRetrace
= FALSE
;
212 static BOOLEAN InHorizontalRetrace
= FALSE
;
214 static BOOLEAN NeedsUpdate
= FALSE
;
215 static BOOLEAN ModeChanged
= TRUE
;
216 static BOOLEAN CursorMoved
= FALSE
;
217 static BOOLEAN PaletteChanged
= FALSE
;
224 } ScreenMode
= TEXT_MODE
;
226 static SMALL_RECT UpdateRectangle
= { 0, 0, 0, 0 };
228 /* PRIVATE FUNCTIONS **********************************************************/
230 static inline DWORD
VgaGetAddressSize(VOID
)
232 if (VgaCrtcRegisters
[VGA_CRTC_UNDERLINE_REG
] & VGA_CRTC_UNDERLINE_DWORD
)
234 /* Double-word addressing */
235 return 4; // sizeof(DWORD)
238 if (VgaCrtcRegisters
[VGA_CRTC_MODE_CONTROL_REG
] & VGA_CRTC_MODE_CONTROL_BYTE
)
240 /* Byte addressing */
241 return 1; // sizeof(BYTE)
244 /* Word addressing */
245 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 buffer */
615 // SetConsoleActiveScreenBuffer(VgaSavedConsoleHandle);
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; // VgaSavedConsoleInfo.srWindow.Left;
634 ConRect
.Top
= VgaSavedConsoleInfo
.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
, &VgaSavedConsoleInfo
);
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 /* Reset the mode change flag */
694 // ModeChanged = FALSE;
696 if (ScreenMode
== GRAPHICS_MODE
)
698 /* Leave the current graphics mode */
699 VgaLeaveGraphicsMode();
703 /* Leave the current text mode */
707 /* Check if the new mode is alphanumeric */
708 if (!(VgaGcRegisters
[VGA_GC_MISC_REG
] & VGA_GC_MISC_NOALPHA
))
710 /* Enter new text mode */
711 if (!VgaEnterTextMode(&Resolution
))
713 DisplayMessage(L
"An unexpected VGA error occurred while switching into text mode.");
720 /* Enter graphics mode */
721 if (!VgaEnterGraphicsMode(&Resolution
))
723 DisplayMessage(L
"An unexpected VGA error occurred while switching into graphics mode.");
729 /* Trigger a full update of the screen */
731 UpdateRectangle
.Left
= 0;
732 UpdateRectangle
.Top
= 0;
733 UpdateRectangle
.Right
= Resolution
.X
;
734 UpdateRectangle
.Bottom
= Resolution
.Y
;
736 /* Reset the mode change flag */
740 static VOID
VgaUpdateFramebuffer(VOID
)
743 COORD Resolution
= VgaGetDisplayResolution();
744 DWORD AddressSize
= VgaGetAddressSize();
745 DWORD Address
= MAKEWORD(VgaCrtcRegisters
[VGA_CRTC_START_ADDR_LOW_REG
],
746 VgaCrtcRegisters
[VGA_CRTC_START_ADDR_HIGH_REG
]);
747 DWORD ScanlineSize
= (DWORD
)VgaCrtcRegisters
[VGA_CRTC_OFFSET_REG
] * 2;
750 * If console framebuffer is NULL, that means something went wrong
751 * earlier and this is the final display refresh.
753 if (ConsoleFramebuffer
== NULL
) return;
755 /* Check if this is text mode or graphics mode */
756 if (VgaGcRegisters
[VGA_GC_MISC_REG
] & VGA_GC_MISC_NOALPHA
)
759 PBYTE GraphicsBuffer
= (PBYTE
)ConsoleFramebuffer
;
762 * Synchronize access to the graphics framebuffer
763 * with the console framebuffer mutex.
765 WaitForSingleObject(ConsoleMutex
, INFINITE
);
767 /* Loop through the scanlines */
768 for (i
= 0; i
< Resolution
.Y
; i
++)
770 /* Loop through the pixels */
771 for (j
= 0; j
< Resolution
.X
; j
++)
775 /* Check the shifting mode */
776 if (VgaGcRegisters
[VGA_GC_MODE_REG
] & VGA_GC_MODE_SHIFT256
)
778 /* 4 bits shifted from each plane */
780 /* Check if this is 16 or 256 color mode */
781 if (VgaAcRegisters
[VGA_AC_CONTROL_REG
] & VGA_AC_CONTROL_8BIT
)
783 /* One byte per pixel */
784 PixelData
= VgaMemory
[(j
% VGA_NUM_BANKS
) * VGA_BANK_SIZE
785 + (Address
+ (j
/ VGA_NUM_BANKS
))
790 /* 4-bits per pixel */
792 PixelData
= VgaMemory
[(j
% VGA_NUM_BANKS
) * VGA_BANK_SIZE
793 + (Address
+ (j
/ (VGA_NUM_BANKS
* 2)))
796 /* Check if we should use the highest 4 bits or lowest 4 */
797 if (((j
/ VGA_NUM_BANKS
) % 2) == 0)
809 else if (VgaGcRegisters
[VGA_GC_MODE_REG
] & VGA_GC_MODE_SHIFTREG
)
811 /* Check if this is 16 or 256 color mode */
812 if (VgaAcRegisters
[VGA_AC_CONTROL_REG
] & VGA_AC_CONTROL_8BIT
)
814 // TODO: NOT IMPLEMENTED
815 DPRINT1("8-bit interleaved mode is not implemented!\n");
820 * 2 bits shifted from plane 0 and 2 for the first 4 pixels,
821 * then 2 bits shifted from plane 1 and 3 for the next 4
823 BYTE LowPlaneData
= VgaMemory
[((j
/ 4) % 2) * VGA_BANK_SIZE
824 + (Address
+ (j
/ 8)) * AddressSize
];
825 BYTE HighPlaneData
= VgaMemory
[(((j
/ 4) % 2) + 2) * VGA_BANK_SIZE
826 + (Address
+ (j
/ 8)) * AddressSize
];
828 /* Extract the two bits from each plane */
829 LowPlaneData
= (LowPlaneData
>> (6 - ((j
% 4) * 2))) & 3;
830 HighPlaneData
= (HighPlaneData
>> (6 - ((j
% 4) * 2))) & 3;
832 /* Combine them into the pixel */
833 PixelData
= LowPlaneData
| (HighPlaneData
<< 2);
838 /* 1 bit shifted from each plane */
840 /* Check if this is 16 or 256 color mode */
841 if (VgaAcRegisters
[VGA_AC_CONTROL_REG
] & VGA_AC_CONTROL_8BIT
)
843 /* 8 bits per pixel, 2 on each plane */
845 for (k
= 0; k
< VGA_NUM_BANKS
; k
++)
847 /* The data is on plane k, 4 pixels per byte */
848 BYTE PlaneData
= VgaMemory
[k
* VGA_BANK_SIZE
849 + (Address
+ (j
/ VGA_NUM_BANKS
))
852 /* The mask of the first bit in the pair */
853 BYTE BitMask
= 1 << (((3 - (j
% VGA_NUM_BANKS
)) * 2) + 1);
855 /* Bits 0, 1, 2 and 3 come from the first bit of the pair */
856 if (PlaneData
& BitMask
) PixelData
|= 1 << k
;
858 /* Bits 4, 5, 6 and 7 come from the second bit of the pair */
859 if (PlaneData
& (BitMask
>> 1)) PixelData
|= 1 << (k
+ 4);
864 /* 4 bits per pixel, 1 on each plane */
866 for (k
= 0; k
< VGA_NUM_BANKS
; k
++)
868 BYTE PlaneData
= VgaMemory
[k
* VGA_BANK_SIZE
869 + (Address
+ (j
/ (VGA_NUM_BANKS
* 2)))
872 /* If the bit on that plane is set, set it */
873 if (PlaneData
& (1 << (7 - (j
% 8)))) PixelData
|= 1 << k
;
878 if (!(VgaAcRegisters
[VGA_AC_CONTROL_REG
] & VGA_AC_CONTROL_8BIT
))
881 * In 16 color mode, the value is an index to the AC registers
882 * if external palette access is disabled, otherwise (in case
883 * of palette loading) it is a blank pixel.
885 PixelData
= (VgaAcPalDisable
? VgaAcRegisters
[PixelData
& 0x0F]
889 /* Take into account DoubleVision mode when checking for pixel updates */
892 /* Now check if the resulting pixel data has changed */
893 if (GraphicsBuffer
[(i
* Resolution
.X
* 4) + (j
* 2)] != PixelData
)
895 /* Yes, write the new value */
896 GraphicsBuffer
[(i
* Resolution
.X
* 4) + (j
* 2)] = PixelData
;
897 GraphicsBuffer
[(i
* Resolution
.X
* 4) + (j
* 2 + 1)] = PixelData
;
898 GraphicsBuffer
[((i
* 2 + 1) * Resolution
.X
* 2) + (j
* 2)] = PixelData
;
899 GraphicsBuffer
[((i
* 2 + 1) * Resolution
.X
* 2) + (j
* 2 + 1)] = PixelData
;
901 /* Mark the specified pixel as changed */
902 VgaMarkForUpdate(i
, j
);
907 /* Now check if the resulting pixel data has changed */
908 if (GraphicsBuffer
[i
* Resolution
.X
+ j
] != PixelData
)
910 /* Yes, write the new value */
911 GraphicsBuffer
[i
* Resolution
.X
+ j
] = PixelData
;
913 /* Mark the specified pixel as changed */
914 VgaMarkForUpdate(i
, j
);
919 /* Move to the next scanline */
920 Address
+= ScanlineSize
;
924 * Release the console framebuffer mutex
925 * so that we allow for repainting.
927 ReleaseMutex(ConsoleMutex
);
932 PCHAR_INFO CharBuffer
= (PCHAR_INFO
)ConsoleFramebuffer
;
934 /* Loop through the scanlines */
935 for (i
= 0; i
< Resolution
.Y
; i
++)
937 /* Loop through the characters */
938 for (j
= 0; j
< Resolution
.X
; j
++)
940 DWORD CurrentAddr
= LOWORD((Address
+ j
) * AddressSize
);
943 /* Plane 0 holds the character itself */
944 CharInfo
.Char
.AsciiChar
= VgaMemory
[CurrentAddr
];
946 /* Plane 1 holds the attribute */
947 CharInfo
.Attributes
= VgaMemory
[CurrentAddr
+ VGA_BANK_SIZE
];
949 /* Now check if the resulting character data has changed */
950 if ((CharBuffer
[i
* Resolution
.X
+ j
].Char
.AsciiChar
!= CharInfo
.Char
.AsciiChar
)
951 || (CharBuffer
[i
* Resolution
.X
+ j
].Attributes
!= CharInfo
.Attributes
))
953 /* Yes, write the new value */
954 CharBuffer
[i
* Resolution
.X
+ j
] = CharInfo
;
956 /* Mark the specified cell as changed */
957 VgaMarkForUpdate(i
, j
);
961 /* Move to the next scanline */
962 Address
+= ScanlineSize
;
967 static VOID
VgaUpdateTextCursor(VOID
)
970 CONSOLE_CURSOR_INFO CursorInfo
;
971 BYTE CursorStart
= VgaCrtcRegisters
[VGA_CRTC_CURSOR_START_REG
] & 0x3F;
972 BYTE CursorEnd
= VgaCrtcRegisters
[VGA_CRTC_CURSOR_END_REG
] & 0x1F;
973 DWORD ScanlineSize
= (DWORD
)VgaCrtcRegisters
[VGA_CRTC_OFFSET_REG
] * 2;
974 BYTE TextSize
= 1 + (VgaCrtcRegisters
[VGA_CRTC_MAX_SCAN_LINE_REG
] & 0x1F);
975 WORD Location
= MAKEWORD(VgaCrtcRegisters
[VGA_CRTC_CURSOR_LOC_LOW_REG
],
976 VgaCrtcRegisters
[VGA_CRTC_CURSOR_LOC_HIGH_REG
]);
978 /* Just return if we are not in text mode */
979 if ((VgaGcRegisters
[VGA_GC_MISC_REG
] & VGA_GC_MISC_NOALPHA
) != 0) return;
981 if (CursorStart
< CursorEnd
)
984 CursorInfo
.bVisible
= TRUE
;
985 CursorInfo
.dwSize
= (100 * (CursorEnd
- CursorStart
)) / TextSize
;
990 CursorInfo
.bVisible
= FALSE
;
991 CursorInfo
.dwSize
= 0;
994 /* Add the cursor skew to the location */
995 Location
+= (VgaCrtcRegisters
[VGA_CRTC_CURSOR_END_REG
] >> 5) & 3;
997 /* Find the coordinates of the new position */
998 Position
.X
= (WORD
)(Location
% ScanlineSize
);
999 Position
.Y
= (WORD
)(Location
/ ScanlineSize
);
1001 /* Update the physical cursor */
1002 SetConsoleCursorInfo(TextConsoleBuffer
, &CursorInfo
);
1003 SetConsoleCursorPosition(TextConsoleBuffer
, Position
);
1005 /* Reset the cursor move flag */
1006 CursorMoved
= FALSE
;
1009 /* PUBLIC FUNCTIONS ***********************************************************/
1011 DWORD
VgaGetVideoBaseAddress(VOID
)
1013 return MemoryBase
[(VgaGcRegisters
[VGA_GC_MISC_REG
] >> 2) & 0x03];
1016 DWORD
VgaGetVideoLimitAddress(VOID
)
1018 return MemoryLimit
[(VgaGcRegisters
[VGA_GC_MISC_REG
] >> 2) & 0x03];
1021 COORD
VgaGetDisplayResolution(VOID
)
1024 BYTE MaximumScanLine
= 1 + (VgaCrtcRegisters
[VGA_CRTC_MAX_SCAN_LINE_REG
] & 0x1F);
1026 /* The low 8 bits are in the display registers */
1027 Resolution
.X
= VgaCrtcRegisters
[VGA_CRTC_END_HORZ_DISP_REG
];
1028 Resolution
.Y
= VgaCrtcRegisters
[VGA_CRTC_VERT_DISP_END_REG
];
1030 /* Set the top bits from the overflow register */
1031 if (VgaCrtcRegisters
[VGA_CRTC_OVERFLOW_REG
] & VGA_CRTC_OVERFLOW_VDE8
)
1033 Resolution
.Y
|= 1 << 8;
1035 if (VgaCrtcRegisters
[VGA_CRTC_OVERFLOW_REG
] & VGA_CRTC_OVERFLOW_VDE9
)
1037 Resolution
.Y
|= 1 << 9;
1040 /* Increase the values by 1 */
1044 if (VgaGcRegisters
[VGA_GC_MISC_REG
] & VGA_GC_MISC_NOALPHA
)
1046 /* Multiply the horizontal resolution by the 9/8 dot mode */
1047 Resolution
.X
*= (VgaSeqRegisters
[VGA_SEQ_CLOCK_REG
] & VGA_SEQ_CLOCK_98DM
)
1050 /* The horizontal resolution is halved in 8-bit mode */
1051 if (VgaAcRegisters
[VGA_AC_CONTROL_REG
] & VGA_AC_CONTROL_8BIT
) Resolution
.X
/= 2;
1054 if (VgaCrtcRegisters
[VGA_CRTC_MAX_SCAN_LINE_REG
] & VGA_CRTC_MAXSCANLINE_DOUBLE
)
1056 /* Halve the vertical resolution */
1061 /* Divide the vertical resolution by the maximum scan line (== font size in text mode) */
1062 Resolution
.Y
/= MaximumScanLine
;
1065 /* Return the resolution */
1069 VOID
VgaRefreshDisplay(VOID
)
1071 HANDLE ConsoleBufferHandle
= NULL
;
1074 /* Set the vertical retrace flag */
1075 InVerticalRetrace
= TRUE
;
1077 /* If nothing has changed, just return */
1078 if (!ModeChanged
&& !CursorMoved
&& !PaletteChanged
&& !NeedsUpdate
)
1081 /* Retrieve the current resolution */
1082 Resolution
= VgaGetDisplayResolution();
1084 /* Change the display mode */
1085 if (ModeChanged
) VgaChangeMode();
1087 /* Change the text cursor location */
1088 if (CursorMoved
) VgaUpdateTextCursor();
1092 /* Trigger a full update of the screen */
1094 UpdateRectangle
.Left
= 0;
1095 UpdateRectangle
.Top
= 0;
1096 UpdateRectangle
.Right
= Resolution
.X
;
1097 UpdateRectangle
.Bottom
= Resolution
.Y
;
1099 PaletteChanged
= FALSE
;
1102 /* Update the contents of the framebuffer */
1103 VgaUpdateFramebuffer();
1105 /* Ignore if there's nothing to update */
1106 if (!NeedsUpdate
) return;
1108 DPRINT("Updating screen rectangle (%d, %d, %d, %d)\n",
1109 UpdateRectangle
.Left
,
1110 UpdateRectangle
.Top
,
1111 UpdateRectangle
.Right
,
1112 UpdateRectangle
.Bottom
);
1114 /* Check if this is text mode or graphics mode */
1115 if (VgaGcRegisters
[VGA_GC_MISC_REG
] & VGA_GC_MISC_NOALPHA
)
1118 ConsoleBufferHandle
= GraphicsConsoleBuffer
;
1123 COORD Origin
= { UpdateRectangle
.Left
, UpdateRectangle
.Top
};
1124 ConsoleBufferHandle
= TextConsoleBuffer
;
1126 /* Write the data to the console */
1127 WriteConsoleOutputA(TextConsoleBuffer
,
1128 (PCHAR_INFO
)ConsoleFramebuffer
,
1134 /* In DoubleVision mode, scale the update rectangle */
1137 UpdateRectangle
.Left
*= 2;
1138 UpdateRectangle
.Top
*= 2;
1139 UpdateRectangle
.Right
= UpdateRectangle
.Right
* 2 + 1;
1140 UpdateRectangle
.Bottom
= UpdateRectangle
.Bottom
* 2 + 1;
1143 /* Redraw the screen */
1144 InvalidateConsoleDIBits(ConsoleBufferHandle
, &UpdateRectangle
);
1146 /* Clear the update flag */
1147 NeedsUpdate
= FALSE
;
1150 VOID
VgaHorizontalRetrace(VOID
)
1153 InHorizontalRetrace
= TRUE
;
1156 VOID
VgaReadMemory(DWORD Address
, LPBYTE Buffer
, DWORD Size
)
1161 DPRINT("VgaReadMemory: Address 0x%08X, Size %lu\n", Address
, Size
);
1163 /* Ignore if video RAM access is disabled */
1164 if ((VgaMiscRegister
& VGA_MISC_RAM_ENABLED
) == 0) return;
1166 /* Loop through each byte */
1167 for (i
= 0; i
< Size
; i
++)
1169 VideoAddress
= VgaTranslateReadAddress(Address
+ i
);
1171 /* Load the latch registers */
1172 VgaLatchRegisters
[0] = VgaMemory
[LOWORD(VideoAddress
)];
1173 VgaLatchRegisters
[1] = VgaMemory
[VGA_BANK_SIZE
+ LOWORD(VideoAddress
)];
1174 VgaLatchRegisters
[2] = VgaMemory
[(2 * VGA_BANK_SIZE
) + LOWORD(VideoAddress
)];
1175 VgaLatchRegisters
[3] = VgaMemory
[(3 * VGA_BANK_SIZE
) + LOWORD(VideoAddress
)];
1177 /* Copy the value to the buffer */
1178 Buffer
[i
] = VgaMemory
[VideoAddress
];
1182 VOID
VgaWriteMemory(DWORD Address
, LPBYTE Buffer
, DWORD Size
)
1187 DPRINT("VgaWriteMemory: Address 0x%08X, Size %lu\n", Address
, Size
);
1189 /* Ignore if video RAM access is disabled */
1190 if ((VgaMiscRegister
& VGA_MISC_RAM_ENABLED
) == 0) return;
1192 /* Also ignore if write access to all planes is disabled */
1193 if ((VgaSeqRegisters
[VGA_SEQ_MASK_REG
] & 0x0F) == 0x00) return;
1195 /* Loop through each byte */
1196 for (i
= 0; i
< Size
; i
++)
1198 VideoAddress
= VgaTranslateWriteAddress(Address
+ i
);
1200 for (j
= 0; j
< VGA_NUM_BANKS
; j
++)
1202 /* Make sure the page is writeable */
1203 if (!(VgaSeqRegisters
[VGA_SEQ_MASK_REG
] & (1 << j
))) continue;
1205 /* Check if this is chain-4 mode */
1206 if (VgaSeqRegisters
[VGA_SEQ_MEM_REG
] & VGA_SEQ_MEM_C4
)
1208 if (((Address
+ i
) & 3) != j
)
1210 /* This plane will not be accessed */
1215 /* Check if this is odd-even mode */
1216 if (VgaGcRegisters
[VGA_GC_MODE_REG
] & VGA_GC_MODE_OE
)
1218 if (((Address
+ i
) & 1) != (j
& 1))
1220 /* This plane will not be accessed */
1225 /* Copy the value to the VGA memory */
1226 VgaMemory
[VideoAddress
+ j
* VGA_BANK_SIZE
] = VgaTranslateByteForWriting(Buffer
[i
], j
);
1231 BYTE WINAPI
VgaReadPort(ULONG Port
)
1233 DPRINT("VgaReadPort: Port 0x%X\n", Port
);
1238 return VgaMiscRegister
;
1240 case VGA_INSTAT0_READ
:
1241 return 0; // Not implemented
1243 case VGA_INSTAT1_READ_MONO
:
1244 case VGA_INSTAT1_READ_COLOR
:
1248 /* Reset the AC latch */
1251 /* Set a flag if there is a vertical or horizontal retrace */
1252 if (InVerticalRetrace
|| InHorizontalRetrace
) Result
|= VGA_STAT_DD
;
1254 /* Set an additional flag if there was a vertical retrace */
1255 if (InVerticalRetrace
) Result
|= VGA_STAT_VRETRACE
;
1257 /* Clear the flags */
1258 InHorizontalRetrace
= InVerticalRetrace
= FALSE
;
1263 case VGA_FEATURE_READ
:
1264 return VgaFeatureRegister
;
1270 return VgaAcRegisters
[VgaAcIndex
];
1276 return VgaSeqRegisters
[VgaSeqIndex
];
1281 case VGA_DAC_READ_INDEX
:
1282 /* This returns the read/write state */
1283 return (VgaDacReadWrite
? 0 : 3);
1285 case VGA_DAC_WRITE_INDEX
:
1286 return (VgaDacIndex
/ 3);
1290 /* Ignore reads in write mode */
1291 if (!VgaDacReadWrite
)
1293 BYTE Data
= VgaDacRegisters
[VgaDacIndex
++];
1294 VgaDacIndex
%= VGA_PALETTE_SIZE
;
1301 case VGA_CRTC_INDEX_MONO
:
1302 case VGA_CRTC_INDEX_COLOR
:
1303 return VgaCrtcIndex
;
1305 case VGA_CRTC_DATA_MONO
:
1306 case VGA_CRTC_DATA_COLOR
:
1307 return VgaCrtcRegisters
[VgaCrtcIndex
];
1313 return VgaGcRegisters
[VgaGcIndex
];
1316 DPRINT1("VgaReadPort: Unknown port 0x%X\n", Port
);
1323 VOID WINAPI
VgaWritePort(ULONG Port
, BYTE Data
)
1325 DPRINT("VgaWritePort: Port 0x%X, Data 0x%02X\n", Port
, Data
);
1329 case VGA_MISC_WRITE
:
1331 VgaMiscRegister
= Data
;
1333 if (VgaMiscRegister
& 0x01)
1335 /* Color emulation */
1336 DPRINT1("Color emulation\n");
1338 /* Register the new I/O Ports */
1339 RegisterIoPort(0x3D4, VgaReadPort
, VgaWritePort
); // VGA_CRTC_INDEX_COLOR
1340 RegisterIoPort(0x3D5, VgaReadPort
, VgaWritePort
); // VGA_CRTC_DATA_COLOR
1341 RegisterIoPort(0x3DA, VgaReadPort
, VgaWritePort
); // VGA_INSTAT1_READ_COLOR, VGA_FEATURE_WRITE_COLOR
1343 /* Unregister the old ones */
1344 UnregisterIoPort(0x3B4); // VGA_CRTC_INDEX_MONO
1345 UnregisterIoPort(0x3B5); // VGA_CRTC_DATA_MONO
1346 UnregisterIoPort(0x3BA); // VGA_INSTAT1_READ_MONO, VGA_FEATURE_WRITE_MONO
1350 /* Monochrome emulation */
1351 DPRINT1("Monochrome emulation\n");
1353 /* Register the new I/O Ports */
1354 RegisterIoPort(0x3B4, VgaReadPort
, VgaWritePort
); // VGA_CRTC_INDEX_MONO
1355 RegisterIoPort(0x3B5, VgaReadPort
, VgaWritePort
); // VGA_CRTC_DATA_MONO
1356 RegisterIoPort(0x3BA, VgaReadPort
, VgaWritePort
); // VGA_INSTAT1_READ_MONO, VGA_FEATURE_WRITE_MONO
1358 /* Unregister the old ones */
1359 UnregisterIoPort(0x3D4); // VGA_CRTC_INDEX_COLOR
1360 UnregisterIoPort(0x3D5); // VGA_CRTC_DATA_COLOR
1361 UnregisterIoPort(0x3DA); // VGA_INSTAT1_READ_COLOR, VGA_FEATURE_WRITE_COLOR
1364 // if (VgaMiscRegister & 0x02) { /* Enable RAM access */ } else { /* Disable RAM access */ }
1368 case VGA_FEATURE_WRITE_MONO
:
1369 case VGA_FEATURE_WRITE_COLOR
:
1371 VgaFeatureRegister
= Data
;
1376 // case VGA_AC_WRITE:
1380 /* Change the index */
1381 BYTE Index
= Data
& 0x1F;
1382 if (Index
< VGA_AC_MAX_REG
) VgaAcIndex
= Index
;
1385 * Change palette protection by checking for
1386 * the Palette Address Source bit.
1388 VgaAcPalDisable
= (Data
& 0x20) ? TRUE
: FALSE
;
1392 /* Write the data */
1396 /* Toggle the latch */
1397 VgaAcLatch
= !VgaAcLatch
;
1403 /* Set the sequencer index register */
1404 if (Data
< VGA_SEQ_MAX_REG
) VgaSeqIndex
= Data
;
1410 /* Call the sequencer function */
1411 VgaWriteSequencer(Data
);
1421 case VGA_DAC_READ_INDEX
:
1423 VgaDacReadWrite
= FALSE
;
1424 VgaDacIndex
= Data
* 3;
1428 case VGA_DAC_WRITE_INDEX
:
1430 VgaDacReadWrite
= TRUE
;
1431 VgaDacIndex
= Data
* 3;
1437 /* Ignore writes in read mode */
1438 if (VgaDacReadWrite
) VgaWriteDac(Data
& 0x3F);
1442 case VGA_CRTC_INDEX_MONO
:
1443 case VGA_CRTC_INDEX_COLOR
:
1445 /* Set the CRTC index register */
1446 if (Data
< VGA_CRTC_MAX_REG
) VgaCrtcIndex
= Data
;
1450 case VGA_CRTC_DATA_MONO
:
1451 case VGA_CRTC_DATA_COLOR
:
1453 /* Call the CRTC function */
1460 /* Set the GC index register */
1461 if (Data
< VGA_GC_MAX_REG
) VgaGcIndex
= Data
;
1467 /* Call the GC function */
1473 DPRINT1("VgaWritePort: Unknown port 0x%X\n", Port
);
1478 VOID
VgaClearMemory(VOID
)
1480 ZeroMemory(VgaMemory
, sizeof(VgaMemory
));
1483 VOID
VgaResetPalette(VOID
)
1485 PALETTEENTRY Entries
[VGA_MAX_COLORS
];
1487 /* Restore the default palette */
1488 VgaRestoreDefaultPalette(Entries
, VGA_MAX_COLORS
);
1489 SetPaletteEntries(PaletteHandle
, 0, VGA_MAX_COLORS
, Entries
);
1490 PaletteChanged
= TRUE
;
1493 BOOLEAN
VgaInitialize(HANDLE TextHandle
)
1499 COORD Origin
= { 0, 0 };
1500 SMALL_RECT ScreenRect
;
1501 PCHAR_INFO CharBuffer
;
1505 /* Save the console information */
1506 if (TextHandle
== INVALID_HANDLE_VALUE
) return FALSE
;
1507 VgaSavedConsoleHandle
= TextHandle
;
1508 if (!GetConsoleScreenBufferInfo(VgaSavedConsoleHandle
,
1509 &VgaSavedConsoleInfo
))
1514 /* Initialize the VGA palette and fail if it isn't successfully created */
1515 if (!VgaInitializePalette()) return FALSE
;
1516 /***/ VgaResetPalette(); /***/
1518 /* Save the default text-mode console output handle */
1519 TextConsoleBuffer
= TextHandle
;
1521 /* Clear the VGA memory */
1524 /* Register the I/O Ports */
1525 RegisterIoPort(0x3CC, VgaReadPort
, NULL
); // VGA_MISC_READ
1526 RegisterIoPort(0x3C2, VgaReadPort
, VgaWritePort
); // VGA_MISC_WRITE, VGA_INSTAT0_READ
1527 RegisterIoPort(0x3CA, VgaReadPort
, NULL
); // VGA_FEATURE_READ
1528 RegisterIoPort(0x3C0, VgaReadPort
, VgaWritePort
); // VGA_AC_INDEX, VGA_AC_WRITE
1529 RegisterIoPort(0x3C1, VgaReadPort
, NULL
); // VGA_AC_READ
1530 RegisterIoPort(0x3C4, VgaReadPort
, VgaWritePort
); // VGA_SEQ_INDEX
1531 RegisterIoPort(0x3C5, VgaReadPort
, VgaWritePort
); // VGA_SEQ_DATA
1532 RegisterIoPort(0x3C6, VgaReadPort
, VgaWritePort
); // VGA_DAC_MASK
1533 RegisterIoPort(0x3C7, VgaReadPort
, VgaWritePort
); // VGA_DAC_READ_INDEX
1534 RegisterIoPort(0x3C8, VgaReadPort
, VgaWritePort
); // VGA_DAC_WRITE_INDEX
1535 RegisterIoPort(0x3C9, VgaReadPort
, VgaWritePort
); // VGA_DAC_DATA
1536 RegisterIoPort(0x3CE, VgaReadPort
, VgaWritePort
); // VGA_GC_INDEX
1537 RegisterIoPort(0x3CF, VgaReadPort
, VgaWritePort
); // VGA_GC_DATA
1539 /* Set the default video mode */
1540 BiosSetVideoMode(BIOS_DEFAULT_VIDEO_MODE
);
1544 Resolution
= VgaGetDisplayResolution();
1545 CharBuffer
= (PCHAR_INFO
)ConsoleFramebuffer
;
1546 AddressSize
= VgaGetAddressSize();
1547 ScreenRect
.Left
= ScreenRect
.Top
= 0;
1548 ScreenRect
.Right
= Resolution
.X
;
1549 ScreenRect
.Bottom
= Resolution
.Y
;
1550 ScanlineSize
= (DWORD
)VgaCrtcRegisters
[VGA_CRTC_OFFSET_REG
] * 2;
1552 /* Read the data from the console into the framebuffer */
1553 ReadConsoleOutputA(TextConsoleBuffer
,
1559 /* Loop through the scanlines */
1560 for (i
= 0; i
< Resolution
.Y
; i
++)
1562 /* Loop through the characters */
1563 for (j
= 0; j
< Resolution
.X
; j
++)
1565 CurrentAddr
= LOWORD((Address
+ j
) * AddressSize
);
1567 /* Store the character in plane 0 */
1568 VgaMemory
[CurrentAddr
] = CharBuffer
[i
* Resolution
.X
+ j
].Char
.AsciiChar
;
1570 /* Store the attribute in plane 1 */
1571 VgaMemory
[CurrentAddr
+ VGA_BANK_SIZE
] = (BYTE
)CharBuffer
[i
* Resolution
.X
+ j
].Attributes
;
1574 /* Move to the next scanline */
1575 Address
+= ScanlineSize
;
1578 /* Return success */