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 BYTE VgaMemory
[VGA_NUM_BANKS
* VGA_BANK_SIZE
];
175 static LPVOID ConsoleFramebuffer
= NULL
;
176 static HANDLE TextConsoleBuffer
= NULL
;
177 static HANDLE GraphicsConsoleBuffer
= NULL
;
178 static HANDLE ConsoleMutex
= NULL
;
179 static HPALETTE PaletteHandle
= NULL
;
180 static BOOLEAN DoubleVision
= FALSE
;
182 static BYTE VgaLatchRegisters
[VGA_NUM_BANKS
] = {0, 0, 0, 0};
184 static BYTE VgaMiscRegister
;
185 static BYTE VgaFeatureRegister
;
187 static BYTE VgaSeqIndex
= VGA_SEQ_RESET_REG
;
188 static BYTE VgaSeqRegisters
[VGA_SEQ_MAX_REG
];
190 static BYTE VgaCrtcIndex
= VGA_CRTC_HORZ_TOTAL_REG
;
191 static BYTE VgaCrtcRegisters
[VGA_CRTC_MAX_REG
];
193 static BYTE VgaGcIndex
= VGA_GC_RESET_REG
;
194 static BYTE VgaGcRegisters
[VGA_GC_MAX_REG
];
196 static BOOLEAN VgaAcLatch
= FALSE
;
197 static BOOLEAN VgaAcPalDisable
= TRUE
;
198 static BYTE VgaAcIndex
= VGA_AC_PAL_0_REG
;
199 static BYTE VgaAcRegisters
[VGA_AC_MAX_REG
];
201 // static VGA_REGISTERS VgaRegisters;
203 static BYTE VgaDacMask
= 0xFF;
204 static WORD VgaDacIndex
= 0;
205 static BOOLEAN VgaDacReadWrite
= FALSE
;
206 static BYTE VgaDacRegisters
[VGA_PALETTE_SIZE
];
208 static BOOLEAN InVerticalRetrace
= FALSE
;
209 static BOOLEAN InHorizontalRetrace
= FALSE
;
211 static BOOLEAN NeedsUpdate
= FALSE
;
212 static BOOLEAN ModeChanged
= TRUE
;
213 static BOOLEAN CursorMoved
= FALSE
;
214 static BOOLEAN PaletteChanged
= FALSE
;
221 } ScreenMode
= TEXT_MODE
;
223 static SMALL_RECT UpdateRectangle
= { 0, 0, 0, 0 };
225 /* PRIVATE FUNCTIONS **********************************************************/
227 static inline INT
VgaGetAddressSize(VOID
)
229 if (VgaCrtcRegisters
[VGA_CRTC_UNDERLINE_REG
] & VGA_CRTC_UNDERLINE_DWORD
)
231 /* Double-word addressing */
232 return 4; // sizeof(DWORD)
235 if (VgaCrtcRegisters
[VGA_CRTC_MODE_CONTROL_REG
] & VGA_CRTC_MODE_CONTROL_BYTE
)
237 /* Byte addressing */
238 return 1; // sizeof(BYTE)
241 /* Word addressing */
242 return 2; // sizeof(WORD)
245 static inline DWORD
VgaTranslateReadAddress(DWORD Address
)
247 DWORD Offset
= Address
- VgaGetVideoBaseAddress();
250 /* Check for chain-4 and odd-even mode */
251 if (VgaSeqRegisters
[VGA_SEQ_MEM_REG
] & VGA_SEQ_MEM_C4
)
253 /* The lowest two bits are the plane number */
257 else if (VgaGcRegisters
[VGA_GC_MODE_REG
] & VGA_GC_MODE_OE
)
259 /* The LSB is the plane number */
265 /* Use the read mode */
266 Plane
= VgaGcRegisters
[VGA_GC_READ_MAP_SEL_REG
] & 0x03;
269 /* Multiply the offset by the address size */
270 Offset
*= VgaGetAddressSize();
272 return Offset
+ Plane
* VGA_BANK_SIZE
;
275 static inline DWORD
VgaTranslateWriteAddress(DWORD Address
)
277 DWORD Offset
= Address
- VgaGetVideoBaseAddress();
279 /* Check for chain-4 and odd-even mode */
280 if (VgaSeqRegisters
[VGA_SEQ_MEM_REG
] & VGA_SEQ_MEM_C4
)
282 /* Shift the offset to the right by 2 */
285 else if (VgaGcRegisters
[VGA_GC_MODE_REG
] & VGA_GC_MODE_OE
)
287 /* Shift the offset to the right by 1 */
291 /* Multiply the offset by the address size */
292 Offset
*= VgaGetAddressSize();
294 /* Return the offset on plane 0 */
298 static inline BYTE
VgaTranslateByteForWriting(BYTE Data
, BYTE Plane
)
300 BYTE WriteMode
= VgaGcRegisters
[VGA_GC_MODE_REG
] & 3;
301 BYTE BitMask
= VgaGcRegisters
[VGA_GC_BITMASK_REG
];
305 /* In write mode 1 just return the latch register */
306 return VgaLatchRegisters
[Plane
];
311 /* Write modes 0 and 3 rotate the data to the right first */
312 BYTE RotateCount
= VgaGcRegisters
[VGA_GC_ROTATE_REG
] & 7;
313 Data
= LOBYTE(((DWORD
)Data
>> RotateCount
) | ((DWORD
)Data
<< (8 - RotateCount
)));
317 /* Write mode 2 expands the appropriate bit to all 8 bits */
318 Data
= (Data
& (1 << Plane
)) ? 0xFF : 0x00;
324 * In write mode 0, the enable set/reset register decides if the
325 * set/reset bit should be expanded to all 8 bits.
327 if (VgaGcRegisters
[VGA_GC_ENABLE_RESET_REG
] & (1 << Plane
))
329 /* Copy the bit from the set/reset register to all 8 bits */
330 Data
= (VgaGcRegisters
[VGA_GC_RESET_REG
] & (1 << Plane
)) ? 0xFF : 0x00;
336 /* Write modes 0 and 2 then perform a logical operation on the data and latch */
337 BYTE LogicalOperation
= (VgaGcRegisters
[VGA_GC_ROTATE_REG
] >> 3) & 3;
339 if (LogicalOperation
== 1) Data
&= VgaLatchRegisters
[Plane
];
340 else if (LogicalOperation
== 2) Data
|= VgaLatchRegisters
[Plane
];
341 else if (LogicalOperation
== 3) Data
^= VgaLatchRegisters
[Plane
];
345 /* For write mode 3, we AND the bitmask with the data, which is used as the new bitmask */
348 /* Then we expand the bit in the set/reset field */
349 Data
= (VgaGcRegisters
[VGA_GC_RESET_REG
] & (1 << Plane
)) ? 0xFF : 0x00;
352 /* Bits cleared in the bitmask are replaced with latch register bits */
353 Data
= (Data
& BitMask
) | (VgaLatchRegisters
[Plane
] & (~BitMask
));
355 /* Return the byte */
359 static inline VOID
VgaMarkForUpdate(SHORT Row
, SHORT Column
)
361 /* Check if this is the first time the rectangle is updated */
364 UpdateRectangle
.Left
= UpdateRectangle
.Top
= MAXSHORT
;
365 UpdateRectangle
.Right
= UpdateRectangle
.Bottom
= MINSHORT
;
368 /* Expand the rectangle to include the point */
369 UpdateRectangle
.Left
= min(UpdateRectangle
.Left
, Column
);
370 UpdateRectangle
.Right
= max(UpdateRectangle
.Right
, Column
);
371 UpdateRectangle
.Top
= min(UpdateRectangle
.Top
, Row
);
372 UpdateRectangle
.Bottom
= max(UpdateRectangle
.Bottom
, Row
);
374 /* Set the update request flag */
378 static VOID
VgaWriteSequencer(BYTE Data
)
380 ASSERT(VgaSeqIndex
< VGA_SEQ_MAX_REG
);
383 VgaSeqRegisters
[VgaSeqIndex
] = Data
;
386 static VOID
VgaWriteGc(BYTE Data
)
388 ASSERT(VgaGcIndex
< VGA_GC_MAX_REG
);
391 VgaGcRegisters
[VgaGcIndex
] = Data
;
393 /* Check the index */
396 case VGA_GC_MISC_REG
:
398 /* The GC misc register decides if it's text or graphics mode */
405 static VOID
VgaWriteCrtc(BYTE Data
)
407 ASSERT(VgaGcIndex
< VGA_CRTC_MAX_REG
);
410 VgaCrtcRegisters
[VgaCrtcIndex
] = Data
;
412 /* Check the index */
413 switch (VgaCrtcIndex
)
415 case VGA_CRTC_END_HORZ_DISP_REG
:
416 case VGA_CRTC_VERT_DISP_END_REG
:
417 case VGA_CRTC_OVERFLOW_REG
:
419 /* The video mode has changed */
424 case VGA_CRTC_CURSOR_LOC_LOW_REG
:
425 case VGA_CRTC_CURSOR_LOC_HIGH_REG
:
426 case VGA_CRTC_CURSOR_START_REG
:
427 case VGA_CRTC_CURSOR_END_REG
:
429 /* Set the cursor moved flag */
436 static VOID
VgaWriteDac(BYTE Data
)
442 VgaDacRegisters
[VgaDacIndex
] = Data
;
444 /* Find the palette index */
445 PaletteIndex
= VgaDacIndex
/ 3;
447 /* Fill the entry structure */
448 Entry
.peRed
= VGA_DAC_TO_COLOR(VgaDacRegisters
[PaletteIndex
* 3]);
449 Entry
.peGreen
= VGA_DAC_TO_COLOR(VgaDacRegisters
[PaletteIndex
* 3 + 1]);
450 Entry
.peBlue
= VGA_DAC_TO_COLOR(VgaDacRegisters
[PaletteIndex
* 3 + 2]);
453 /* Update the palette entry and set the palette change flag */
454 SetPaletteEntries(PaletteHandle
, PaletteIndex
, 1, &Entry
);
455 PaletteChanged
= TRUE
;
457 /* Update the index */
459 VgaDacIndex
%= VGA_PALETTE_SIZE
;
462 static VOID
VgaWriteAc(BYTE Data
)
464 ASSERT(VgaAcIndex
< VGA_AC_MAX_REG
);
467 if (VgaAcIndex
<= VGA_AC_PAL_F_REG
)
469 if (VgaAcPalDisable
) return;
471 // DbgPrint(" AC Palette Writing %d to index %d\n", Data, VgaAcIndex);
472 if (VgaAcRegisters
[VgaAcIndex
] != Data
)
474 /* Update the AC register and set the palette change flag */
475 VgaAcRegisters
[VgaAcIndex
] = Data
;
476 PaletteChanged
= TRUE
;
481 VgaAcRegisters
[VgaAcIndex
] = Data
;
485 static VOID
VgaRestoreDefaultPalette(PPALETTEENTRY Entries
, USHORT NumOfEntries
)
489 /* Copy the colors of the default palette to the DAC and console palette */
490 for (i
= 0; i
< NumOfEntries
; i
++)
492 /* Set the palette entries */
493 Entries
[i
].peRed
= GetRValue(VgaDefaultPalette
[i
]);
494 Entries
[i
].peGreen
= GetGValue(VgaDefaultPalette
[i
]);
495 Entries
[i
].peBlue
= GetBValue(VgaDefaultPalette
[i
]);
496 Entries
[i
].peFlags
= 0;
498 /* Set the DAC registers */
499 VgaDacRegisters
[i
* 3] = VGA_COLOR_TO_DAC(GetRValue(VgaDefaultPalette
[i
]));
500 VgaDacRegisters
[i
* 3 + 1] = VGA_COLOR_TO_DAC(GetGValue(VgaDefaultPalette
[i
]));
501 VgaDacRegisters
[i
* 3 + 2] = VGA_COLOR_TO_DAC(GetBValue(VgaDefaultPalette
[i
]));
505 static BOOLEAN
VgaInitializePalette(VOID
)
507 LPLOGPALETTE Palette
;
509 /* Allocate storage space for the palette */
510 Palette
= (LPLOGPALETTE
)HeapAlloc(GetProcessHeap(),
513 VGA_MAX_COLORS
* sizeof(PALETTEENTRY
));
514 if (Palette
== NULL
) return FALSE
;
516 /* Initialize the palette */
517 Palette
->palVersion
= 0x0300;
518 Palette
->palNumEntries
= VGA_MAX_COLORS
;
520 /* Restore the default palette */
521 VgaRestoreDefaultPalette(Palette
->palPalEntry
, Palette
->palNumEntries
);
523 /* Create the palette */
524 PaletteHandle
= CreatePalette(Palette
);
526 /* Free the palette */
527 HeapFree(GetProcessHeap(), 0, Palette
);
529 /* Fail if the palette wasn't successfully created... */
530 if (PaletteHandle
== NULL
) return FALSE
;
532 /* ... otherwise return success */
536 static BOOL
VgaEnterGraphicsMode(PCOORD Resolution
)
539 CONSOLE_GRAPHICS_BUFFER_INFO GraphicsBufferInfo
;
540 BYTE BitmapInfoBuffer
[VGA_BITMAP_INFO_SIZE
];
541 LPBITMAPINFO BitmapInfo
= (LPBITMAPINFO
)BitmapInfoBuffer
;
542 LPWORD PaletteIndex
= (LPWORD
)(BitmapInfo
->bmiColors
);
544 LONG Width
= Resolution
->X
;
545 LONG Height
= Resolution
->Y
;
547 /* Use DoubleVision mode if the resolution is too small */
548 if (Width
< VGA_MINIMUM_WIDTH
&& Height
< VGA_MINIMUM_HEIGHT
)
555 /* Fill the bitmap info header */
556 ZeroMemory(&BitmapInfo
->bmiHeader
, sizeof(BITMAPINFOHEADER
));
557 BitmapInfo
->bmiHeader
.biSize
= sizeof(BITMAPINFOHEADER
);
558 BitmapInfo
->bmiHeader
.biWidth
= Width
;
559 BitmapInfo
->bmiHeader
.biHeight
= Height
;
560 BitmapInfo
->bmiHeader
.biBitCount
= 8;
561 BitmapInfo
->bmiHeader
.biPlanes
= 1;
562 BitmapInfo
->bmiHeader
.biCompression
= BI_RGB
;
563 BitmapInfo
->bmiHeader
.biSizeImage
= Width
* Height
/* * 1 == biBitCount / 8 */;
565 /* Fill the palette data */
566 for (i
= 0; i
< (VGA_PALETTE_SIZE
/ 3); i
++) PaletteIndex
[i
] = (WORD
)i
;
568 /* Fill the console graphics buffer info */
569 GraphicsBufferInfo
.dwBitMapInfoLength
= VGA_BITMAP_INFO_SIZE
;
570 GraphicsBufferInfo
.lpBitMapInfo
= BitmapInfo
;
571 GraphicsBufferInfo
.dwUsage
= DIB_PAL_COLORS
;
573 /* Create the buffer */
574 GraphicsConsoleBuffer
= CreateConsoleScreenBuffer(GENERIC_READ
| GENERIC_WRITE
,
575 FILE_SHARE_READ
| FILE_SHARE_WRITE
,
577 CONSOLE_GRAPHICS_BUFFER
,
578 &GraphicsBufferInfo
);
579 if (GraphicsConsoleBuffer
== INVALID_HANDLE_VALUE
) return FALSE
;
581 /* Save the framebuffer address and mutex */
582 ConsoleFramebuffer
= GraphicsBufferInfo
.lpBitMap
;
583 ConsoleMutex
= GraphicsBufferInfo
.hMutex
;
585 /* Clear the framebuffer */
586 ZeroMemory(ConsoleFramebuffer
, BitmapInfo
->bmiHeader
.biSizeImage
);
588 /* Set the active buffer */
589 SetConsoleActiveScreenBuffer(GraphicsConsoleBuffer
);
591 /* Set the graphics mode palette */
592 SetConsolePalette(GraphicsConsoleBuffer
,
596 /* Set the screen mode flag */
597 ScreenMode
= GRAPHICS_MODE
;
602 static VOID
VgaLeaveGraphicsMode(VOID
)
604 /* Release the console framebuffer mutex if needed */
605 ReleaseMutex(ConsoleMutex
);
607 /* Switch back to the text buffer */
608 SetConsoleActiveScreenBuffer(TextConsoleBuffer
);
610 /* Cleanup the video data */
611 CloseHandle(ConsoleMutex
);
613 CloseHandle(GraphicsConsoleBuffer
);
614 GraphicsConsoleBuffer
= NULL
;
615 DoubleVision
= FALSE
;
618 static BOOL
VgaEnterTextMode(PCOORD Resolution
)
620 /* Resize the console */
621 SetConsoleScreenBufferSize(TextConsoleBuffer
, *Resolution
);
623 /* Allocate a framebuffer */
624 ConsoleFramebuffer
= HeapAlloc(GetProcessHeap(),
626 Resolution
->X
* Resolution
->Y
627 * sizeof(CHAR_INFO
));
628 if (ConsoleFramebuffer
== NULL
)
630 DisplayMessage(L
"An unexpected error occurred!\n");
636 * Set the text mode palette.
638 * WARNING: This call should fail on Windows (and therefore
639 * we get the default palette and our external behaviour is
640 * just like Windows' one), but it should success on ReactOS
641 * (so that we get console palette changes even for text-mode
642 * screen-buffers, which is a new feature on ReactOS).
644 SetConsolePalette(TextConsoleBuffer
,
648 /* Set the screen mode flag */
649 ScreenMode
= TEXT_MODE
;
654 static VOID
VgaLeaveTextMode(VOID
)
656 /* Free the old framebuffer */
657 HeapFree(GetProcessHeap(), 0, ConsoleFramebuffer
);
658 ConsoleFramebuffer
= NULL
;
661 static VOID
VgaChangeMode(VOID
)
663 COORD Resolution
= VgaGetDisplayResolution();
665 /* Reset the mode change flag */
666 // ModeChanged = FALSE;
668 if (ScreenMode
== GRAPHICS_MODE
)
670 /* Leave the current graphics mode */
671 VgaLeaveGraphicsMode();
675 /* Leave the current text mode */
679 /* Check if the new mode is alphanumeric */
680 if (!(VgaGcRegisters
[VGA_GC_MISC_REG
] & VGA_GC_MISC_NOALPHA
))
682 /* Enter new text mode */
683 if (!VgaEnterTextMode(&Resolution
))
685 DisplayMessage(L
"An unexpected VGA error occurred while switching into text mode.");
692 /* Enter 8-bit graphics mode */
693 if (!VgaEnterGraphicsMode(&Resolution
))
695 DisplayMessage(L
"An unexpected VGA error occurred while switching into graphics mode.");
701 /* Trigger a full update of the screen */
703 UpdateRectangle
.Left
= 0;
704 UpdateRectangle
.Top
= 0;
705 UpdateRectangle
.Right
= Resolution
.X
;
706 UpdateRectangle
.Bottom
= Resolution
.Y
;
708 /* Reset the mode change flag */
712 static VOID
VgaUpdateFramebuffer(VOID
)
715 COORD Resolution
= VgaGetDisplayResolution();
716 INT AddressSize
= VgaGetAddressSize();
717 DWORD Address
= MAKEWORD(VgaCrtcRegisters
[VGA_CRTC_START_ADDR_LOW_REG
],
718 VgaCrtcRegisters
[VGA_CRTC_START_ADDR_HIGH_REG
]);
719 DWORD ScanlineSize
= (DWORD
)VgaCrtcRegisters
[VGA_CRTC_OFFSET_REG
] * 2;
722 * If console framebuffer is NULL, that means something went wrong
723 * earlier and this is the final display refresh.
725 if (ConsoleFramebuffer
== NULL
) return;
727 /* Check if this is text mode or graphics mode */
728 if (VgaGcRegisters
[VGA_GC_MISC_REG
] & VGA_GC_MISC_NOALPHA
)
731 PBYTE GraphicsBuffer
= (PBYTE
)ConsoleFramebuffer
;
734 * Synchronize access to the graphics framebuffer
735 * with the console framebuffer mutex.
737 WaitForSingleObject(ConsoleMutex
, INFINITE
);
739 /* Loop through the scanlines */
740 for (i
= 0; i
< Resolution
.Y
; i
++)
742 /* Loop through the pixels */
743 for (j
= 0; j
< Resolution
.X
; j
++)
747 /* Check the shifting mode */
748 if (VgaGcRegisters
[VGA_GC_MODE_REG
] & VGA_GC_MODE_SHIFT256
)
750 /* 4 bits shifted from each plane */
752 /* Check if this is 16 or 256 color mode */
753 if (VgaAcRegisters
[VGA_AC_CONTROL_REG
] & VGA_AC_CONTROL_8BIT
)
755 /* One byte per pixel */
756 PixelData
= VgaMemory
[(j
% VGA_NUM_BANKS
) * VGA_BANK_SIZE
757 + (Address
+ (j
/ VGA_NUM_BANKS
))
762 /* 4-bits per pixel */
764 PixelData
= VgaMemory
[(j
% VGA_NUM_BANKS
) * VGA_BANK_SIZE
765 + (Address
+ (j
/ (VGA_NUM_BANKS
* 2)))
768 /* Check if we should use the highest 4 bits or lowest 4 */
769 if (((j
/ VGA_NUM_BANKS
) % 2) == 0)
781 else if (VgaGcRegisters
[VGA_GC_MODE_REG
] & VGA_GC_MODE_SHIFTREG
)
783 /* Check if this is 16 or 256 color mode */
784 if (VgaAcRegisters
[VGA_AC_CONTROL_REG
] & VGA_AC_CONTROL_8BIT
)
786 // TODO: NOT IMPLEMENTED
787 DPRINT1("8-bit interleaved mode is not implemented!\n");
792 * 2 bits shifted from plane 0 and 2 for the first 4 pixels,
793 * then 2 bits shifted from plane 1 and 3 for the next 4
795 BYTE LowPlaneData
= VgaMemory
[((j
/ 4) % 2) * VGA_BANK_SIZE
796 + (Address
+ (j
/ 4)) * AddressSize
];
797 BYTE HighPlaneData
= VgaMemory
[(((j
/ 4) % 2) + 2) * VGA_BANK_SIZE
798 + (Address
+ (j
/ 4)) * AddressSize
];
800 /* Extract the two bits from each plane */
801 LowPlaneData
= (LowPlaneData
>> (6 - ((j
% 4) * 2))) & 3;
802 HighPlaneData
= (HighPlaneData
>> (6 - ((j
% 4) * 2))) & 3;
804 /* Combine them into the pixel */
805 PixelData
= LowPlaneData
| (HighPlaneData
<< 2);
810 /* 1 bit shifted from each plane */
812 /* Check if this is 16 or 256 color mode */
813 if (VgaAcRegisters
[VGA_AC_CONTROL_REG
] & VGA_AC_CONTROL_8BIT
)
815 /* 8 bits per pixel, 2 on each plane */
817 for (k
= 0; k
< VGA_NUM_BANKS
; k
++)
819 /* The data is on plane k, 4 pixels per byte */
820 BYTE PlaneData
= VgaMemory
[k
* VGA_BANK_SIZE
821 + (Address
+ (j
/ 4)) * AddressSize
];
823 /* The mask of the first bit in the pair */
824 BYTE BitMask
= 1 << (((3 - (j
% 4)) * 2) + 1);
826 /* Bits 0, 1, 2 and 3 come from the first bit of the pair */
827 if (PlaneData
& BitMask
) PixelData
|= 1 << k
;
829 /* Bits 4, 5, 6 and 7 come from the second bit of the pair */
830 if (PlaneData
& (BitMask
>> 1)) PixelData
|= 1 << (k
+ 4);
835 /* 4 bits per pixel, 1 on each plane */
837 for (k
= 0; k
< VGA_NUM_BANKS
; k
++)
839 BYTE PlaneData
= VgaMemory
[k
* VGA_BANK_SIZE
840 + (Address
+ (j
/ 8)) * AddressSize
];
842 /* If the bit on that plane is set, set it */
843 if (PlaneData
& (1 << (7 - (j
% 8)))) PixelData
|= 1 << k
;
848 if (!(VgaAcRegisters
[VGA_AC_CONTROL_REG
] & VGA_AC_CONTROL_8BIT
))
851 * In 16 color mode, the value is an index to the AC registers
852 * if external palette access is disabled, otherwise (in case
853 * of palette loading) it is a blank pixel.
855 PixelData
= (VgaAcPalDisable
? VgaAcRegisters
[PixelData
& 0x0F]
859 /* Take into account DoubleVision mode when checking for pixel updates */
862 /* Now check if the resulting pixel data has changed */
863 if (GraphicsBuffer
[(i
* Resolution
.X
* 4) + (j
* 2)] != PixelData
)
865 /* Yes, write the new value */
866 GraphicsBuffer
[(i
* Resolution
.X
* 4) + (j
* 2)] = PixelData
;
867 GraphicsBuffer
[(i
* Resolution
.X
* 4) + (j
* 2 + 1)] = PixelData
;
868 GraphicsBuffer
[((i
* 2 + 1) * Resolution
.X
* 2) + (j
* 2)] = PixelData
;
869 GraphicsBuffer
[((i
* 2 + 1) * Resolution
.X
* 2) + (j
* 2 + 1)] = PixelData
;
871 /* Mark the specified pixel as changed */
872 VgaMarkForUpdate(i
, j
);
877 /* Now check if the resulting pixel data has changed */
878 if (GraphicsBuffer
[i
* Resolution
.X
+ j
] != PixelData
)
880 /* Yes, write the new value */
881 GraphicsBuffer
[i
* Resolution
.X
+ j
] = PixelData
;
883 /* Mark the specified pixel as changed */
884 VgaMarkForUpdate(i
, j
);
889 /* Move to the next scanline */
890 Address
+= ScanlineSize
;
894 * Release the console framebuffer mutex
895 * so that we allow for repainting.
897 ReleaseMutex(ConsoleMutex
);
902 PCHAR_INFO CharBuffer
= (PCHAR_INFO
)ConsoleFramebuffer
;
904 /* Loop through the scanlines */
905 for (i
= 0; i
< Resolution
.Y
; i
++)
907 /* Loop through the characters */
908 for (j
= 0; j
< Resolution
.X
; j
++)
910 DWORD CurrentAddr
= LOWORD((Address
+ j
) * AddressSize
);
913 /* Plane 0 holds the character itself */
914 CharInfo
.Char
.AsciiChar
= VgaMemory
[CurrentAddr
];
916 /* Plane 1 holds the attribute */
917 CharInfo
.Attributes
= VgaMemory
[CurrentAddr
+ VGA_BANK_SIZE
];
919 /* Now check if the resulting character data has changed */
920 if ((CharBuffer
[i
* Resolution
.X
+ j
].Char
.AsciiChar
!= CharInfo
.Char
.AsciiChar
)
921 || (CharBuffer
[i
* Resolution
.X
+ j
].Attributes
!= CharInfo
.Attributes
))
923 /* Yes, write the new value */
924 CharBuffer
[i
* Resolution
.X
+ j
] = CharInfo
;
926 /* Mark the specified cell as changed */
927 VgaMarkForUpdate(i
, j
);
931 /* Move to the next scanline */
932 Address
+= ScanlineSize
;
937 static VOID
VgaUpdateTextCursor(VOID
)
940 CONSOLE_CURSOR_INFO CursorInfo
;
941 BYTE CursorStart
= VgaCrtcRegisters
[VGA_CRTC_CURSOR_START_REG
] & 0x3F;
942 BYTE CursorEnd
= VgaCrtcRegisters
[VGA_CRTC_CURSOR_END_REG
] & 0x1F;
943 DWORD ScanlineSize
= (DWORD
)VgaCrtcRegisters
[VGA_CRTC_OFFSET_REG
] * 2;
944 BYTE TextSize
= 1 + (VgaCrtcRegisters
[VGA_CRTC_MAX_SCAN_LINE_REG
] & 0x1F);
945 WORD Location
= MAKEWORD(VgaCrtcRegisters
[VGA_CRTC_CURSOR_LOC_LOW_REG
],
946 VgaCrtcRegisters
[VGA_CRTC_CURSOR_LOC_HIGH_REG
]);
948 /* Just return if we are not in text mode */
949 if ((VgaGcRegisters
[VGA_GC_MISC_REG
] & VGA_GC_MISC_NOALPHA
) != 0) return;
951 if (CursorStart
< CursorEnd
)
954 CursorInfo
.bVisible
= TRUE
;
955 CursorInfo
.dwSize
= (100 * (CursorEnd
- CursorStart
)) / TextSize
;
960 CursorInfo
.bVisible
= FALSE
;
961 CursorInfo
.dwSize
= 0;
964 /* Add the cursor skew to the location */
965 Location
+= (VgaCrtcRegisters
[VGA_CRTC_CURSOR_END_REG
] >> 5) & 3;
967 /* Find the coordinates of the new position */
968 Position
.X
= (WORD
)(Location
% ScanlineSize
);
969 Position
.Y
= (WORD
)(Location
/ ScanlineSize
);
971 /* Update the physical cursor */
972 SetConsoleCursorInfo(TextConsoleBuffer
, &CursorInfo
);
973 SetConsoleCursorPosition(TextConsoleBuffer
, Position
);
975 /* Reset the cursor move flag */
979 /* PUBLIC FUNCTIONS ***********************************************************/
981 DWORD
VgaGetVideoBaseAddress(VOID
)
983 return MemoryBase
[(VgaGcRegisters
[VGA_GC_MISC_REG
] >> 2) & 0x03];
986 DWORD
VgaGetVideoLimitAddress(VOID
)
988 return MemoryLimit
[(VgaGcRegisters
[VGA_GC_MISC_REG
] >> 2) & 0x03];
991 COORD
VgaGetDisplayResolution(VOID
)
994 BYTE MaximumScanLine
= 1 + (VgaCrtcRegisters
[VGA_CRTC_MAX_SCAN_LINE_REG
] & 0x1F);
996 /* The low 8 bits are in the display registers */
997 Resolution
.X
= VgaCrtcRegisters
[VGA_CRTC_END_HORZ_DISP_REG
];
998 Resolution
.Y
= VgaCrtcRegisters
[VGA_CRTC_VERT_DISP_END_REG
];
1000 /* Set the top bits from the overflow register */
1001 if (VgaCrtcRegisters
[VGA_CRTC_OVERFLOW_REG
] & VGA_CRTC_OVERFLOW_VDE8
)
1003 Resolution
.Y
|= 1 << 8;
1005 if (VgaCrtcRegisters
[VGA_CRTC_OVERFLOW_REG
] & VGA_CRTC_OVERFLOW_VDE9
)
1007 Resolution
.Y
|= 1 << 9;
1010 /* Increase the values by 1 */
1014 if (VgaGcRegisters
[VGA_GC_MISC_REG
] & VGA_GC_MISC_NOALPHA
)
1016 /* Multiply the horizontal resolution by the 9/8 dot mode */
1017 Resolution
.X
*= (VgaSeqRegisters
[VGA_SEQ_CLOCK_REG
] & VGA_SEQ_CLOCK_98DM
)
1020 /* The horizontal resolution is halved in 8-bit mode */
1021 if (VgaAcRegisters
[VGA_AC_CONTROL_REG
] & VGA_AC_CONTROL_8BIT
) Resolution
.X
/= 2;
1024 if (VgaCrtcRegisters
[VGA_CRTC_MAX_SCAN_LINE_REG
] & VGA_CRTC_MAXSCANLINE_DOUBLE
)
1026 /* Halve the vertical resolution */
1030 /* Divide the vertical resolution by the maximum scan line (== font size in text mode) */
1031 Resolution
.Y
/= MaximumScanLine
;
1033 /* Return the resolution */
1037 VOID
VgaRefreshDisplay(VOID
)
1039 HANDLE ConsoleBufferHandle
= NULL
;
1042 /* Set the vertical retrace flag */
1043 InVerticalRetrace
= TRUE
;
1045 /* If nothing has changed, just return */
1046 if (!ModeChanged
&& !CursorMoved
&& !PaletteChanged
&& !NeedsUpdate
)
1049 /* Retrieve the current resolution */
1050 Resolution
= VgaGetDisplayResolution();
1052 /* Change the display mode */
1053 if (ModeChanged
) VgaChangeMode();
1055 /* Change the text cursor location */
1056 if (CursorMoved
) VgaUpdateTextCursor();
1060 /* Trigger a full update of the screen */
1062 UpdateRectangle
.Left
= 0;
1063 UpdateRectangle
.Top
= 0;
1064 UpdateRectangle
.Right
= Resolution
.X
;
1065 UpdateRectangle
.Bottom
= Resolution
.Y
;
1067 PaletteChanged
= FALSE
;
1070 /* Update the contents of the framebuffer */
1071 VgaUpdateFramebuffer();
1073 /* Ignore if there's nothing to update */
1074 if (!NeedsUpdate
) return;
1076 DPRINT("Updating screen rectangle (%d, %d, %d, %d)\n",
1077 UpdateRectangle
.Left
,
1078 UpdateRectangle
.Top
,
1079 UpdateRectangle
.Right
,
1080 UpdateRectangle
.Bottom
);
1082 /* Check if this is text mode or graphics mode */
1083 if (VgaGcRegisters
[VGA_GC_MISC_REG
] & VGA_GC_MISC_NOALPHA
)
1086 ConsoleBufferHandle
= GraphicsConsoleBuffer
;
1091 COORD Origin
= { UpdateRectangle
.Left
, UpdateRectangle
.Top
};
1092 ConsoleBufferHandle
= TextConsoleBuffer
;
1094 /* Write the data to the console */
1095 WriteConsoleOutputA(TextConsoleBuffer
,
1096 (PCHAR_INFO
)ConsoleFramebuffer
,
1102 /* In DoubleVision mode, scale the update rectangle */
1105 UpdateRectangle
.Left
*= 2;
1106 UpdateRectangle
.Top
*= 2;
1107 UpdateRectangle
.Right
= UpdateRectangle
.Right
* 2 + 1;
1108 UpdateRectangle
.Bottom
= UpdateRectangle
.Bottom
* 2 + 1;
1111 /* Redraw the screen */
1112 InvalidateConsoleDIBits(ConsoleBufferHandle
, &UpdateRectangle
);
1114 /* Clear the update flag */
1115 NeedsUpdate
= FALSE
;
1118 VOID
VgaHorizontalRetrace(VOID
)
1121 InHorizontalRetrace
= TRUE
;
1124 VOID
VgaReadMemory(DWORD Address
, LPBYTE Buffer
, DWORD Size
)
1129 DPRINT("VgaReadMemory: Address 0x%08X, Size %lu\n", Address
, Size
);
1131 /* Ignore if video RAM access is disabled */
1132 if ((VgaMiscRegister
& VGA_MISC_RAM_ENABLED
) == 0) return;
1134 /* Loop through each byte */
1135 for (i
= 0; i
< Size
; i
++)
1137 VideoAddress
= VgaTranslateReadAddress(Address
+ i
);
1139 /* Load the latch registers */
1140 VgaLatchRegisters
[0] = VgaMemory
[LOWORD(VideoAddress
)];
1141 VgaLatchRegisters
[1] = VgaMemory
[VGA_BANK_SIZE
+ LOWORD(VideoAddress
)];
1142 VgaLatchRegisters
[2] = VgaMemory
[(2 * VGA_BANK_SIZE
) + LOWORD(VideoAddress
)];
1143 VgaLatchRegisters
[3] = VgaMemory
[(3 * VGA_BANK_SIZE
) + LOWORD(VideoAddress
)];
1145 /* Copy the value to the buffer */
1146 Buffer
[i
] = VgaMemory
[VideoAddress
];
1150 VOID
VgaWriteMemory(DWORD Address
, LPBYTE Buffer
, DWORD Size
)
1155 DPRINT("VgaWriteMemory: Address 0x%08X, Size %lu\n", Address
, Size
);
1157 /* Ignore if video RAM access is disabled */
1158 if ((VgaMiscRegister
& VGA_MISC_RAM_ENABLED
) == 0) return;
1160 /* Also ignore if write access to all planes is disabled */
1161 if ((VgaSeqRegisters
[VGA_SEQ_MASK_REG
] & 0x0F) == 0x00) return;
1163 /* Loop through each byte */
1164 for (i
= 0; i
< Size
; i
++)
1166 VideoAddress
= VgaTranslateWriteAddress(Address
+ i
);
1168 for (j
= 0; j
< VGA_NUM_BANKS
; j
++)
1170 /* Make sure the page is writeable */
1171 if (!(VgaSeqRegisters
[VGA_SEQ_MASK_REG
] & (1 << j
))) continue;
1173 /* Check if this is chain-4 mode */
1174 if (VgaSeqRegisters
[VGA_SEQ_MEM_REG
] & VGA_SEQ_MEM_C4
)
1176 if (((Address
+ i
) & 3) != j
)
1178 /* This plane will not be accessed */
1183 /* Check if this is odd-even mode */
1184 if (VgaGcRegisters
[VGA_GC_MODE_REG
] & VGA_GC_MODE_OE
)
1186 if (((Address
+ i
) & 1) != (j
& 1))
1188 /* This plane will not be accessed */
1193 /* Copy the value to the VGA memory */
1194 VgaMemory
[VideoAddress
+ j
* VGA_BANK_SIZE
] = VgaTranslateByteForWriting(Buffer
[i
], j
);
1199 BYTE WINAPI
VgaReadPort(ULONG Port
)
1201 DPRINT("VgaReadPort: Port 0x%X\n", Port
);
1206 return VgaMiscRegister
;
1208 case VGA_INSTAT0_READ
:
1209 return 0; // Not implemented
1211 case VGA_INSTAT1_READ_MONO
:
1212 case VGA_INSTAT1_READ_COLOR
:
1216 /* Reset the AC latch */
1219 /* Set a flag if there is a vertical or horizontal retrace */
1220 if (InVerticalRetrace
|| InHorizontalRetrace
) Result
|= VGA_STAT_DD
;
1222 /* Set an additional flag if there was a vertical retrace */
1223 if (InVerticalRetrace
) Result
|= VGA_STAT_VRETRACE
;
1225 /* Clear the flags */
1226 InHorizontalRetrace
= InVerticalRetrace
= FALSE
;
1231 case VGA_FEATURE_READ
:
1232 return VgaFeatureRegister
;
1238 return VgaAcRegisters
[VgaAcIndex
];
1244 return VgaSeqRegisters
[VgaSeqIndex
];
1249 case VGA_DAC_READ_INDEX
:
1250 /* This returns the read/write state */
1251 return (VgaDacReadWrite
? 0 : 3);
1253 case VGA_DAC_WRITE_INDEX
:
1254 return (VgaDacIndex
/ 3);
1258 /* Ignore reads in write mode */
1259 if (!VgaDacReadWrite
)
1261 BYTE Data
= VgaDacRegisters
[VgaDacIndex
++];
1262 VgaDacIndex
%= VGA_PALETTE_SIZE
;
1269 case VGA_CRTC_INDEX_MONO
:
1270 case VGA_CRTC_INDEX_COLOR
:
1271 return VgaCrtcIndex
;
1273 case VGA_CRTC_DATA_MONO
:
1274 case VGA_CRTC_DATA_COLOR
:
1275 return VgaCrtcRegisters
[VgaCrtcIndex
];
1281 return VgaGcRegisters
[VgaGcIndex
];
1284 DPRINT1("VgaReadPort: Unknown port 0x%X\n", Port
);
1291 VOID WINAPI
VgaWritePort(ULONG Port
, BYTE Data
)
1293 DPRINT("VgaWritePort: Port 0x%X, Data 0x%02X\n", Port
, Data
);
1297 case VGA_MISC_WRITE
:
1299 VgaMiscRegister
= Data
;
1301 if (VgaMiscRegister
& 0x01)
1303 /* Color emulation */
1304 DPRINT1("Color emulation\n");
1306 /* Register the new I/O Ports */
1307 RegisterIoPort(0x3D4, VgaReadPort
, VgaWritePort
); // VGA_CRTC_INDEX_COLOR
1308 RegisterIoPort(0x3D5, VgaReadPort
, VgaWritePort
); // VGA_CRTC_DATA_COLOR
1309 RegisterIoPort(0x3DA, VgaReadPort
, VgaWritePort
); // VGA_INSTAT1_READ_COLOR, VGA_FEATURE_WRITE_COLOR
1311 /* Unregister the old ones */
1312 UnregisterIoPort(0x3B4); // VGA_CRTC_INDEX_MONO
1313 UnregisterIoPort(0x3B5); // VGA_CRTC_DATA_MONO
1314 UnregisterIoPort(0x3BA); // VGA_INSTAT1_READ_MONO, VGA_FEATURE_WRITE_MONO
1318 /* Monochrome emulation */
1319 DPRINT1("Monochrome emulation\n");
1321 /* Register the new I/O Ports */
1322 RegisterIoPort(0x3B4, VgaReadPort
, VgaWritePort
); // VGA_CRTC_INDEX_MONO
1323 RegisterIoPort(0x3B5, VgaReadPort
, VgaWritePort
); // VGA_CRTC_DATA_MONO
1324 RegisterIoPort(0x3BA, VgaReadPort
, VgaWritePort
); // VGA_INSTAT1_READ_MONO, VGA_FEATURE_WRITE_MONO
1326 /* Unregister the old ones */
1327 UnregisterIoPort(0x3D4); // VGA_CRTC_INDEX_COLOR
1328 UnregisterIoPort(0x3D5); // VGA_CRTC_DATA_COLOR
1329 UnregisterIoPort(0x3DA); // VGA_INSTAT1_READ_COLOR, VGA_FEATURE_WRITE_COLOR
1332 // if (VgaMiscRegister & 0x02) { /* Enable RAM access */ } else { /* Disable RAM access */ }
1336 case VGA_FEATURE_WRITE_MONO
:
1337 case VGA_FEATURE_WRITE_COLOR
:
1339 VgaFeatureRegister
= Data
;
1344 // case VGA_AC_WRITE:
1348 /* Change the index */
1349 BYTE Index
= Data
& 0x1F;
1350 if (Index
< VGA_AC_MAX_REG
) VgaAcIndex
= Index
;
1353 * Change palette protection by checking for
1354 * the Palette Address Source bit.
1356 VgaAcPalDisable
= (Data
& 0x20) ? TRUE
: FALSE
;
1360 /* Write the data */
1364 /* Toggle the latch */
1365 VgaAcLatch
= !VgaAcLatch
;
1371 /* Set the sequencer index register */
1372 if (Data
< VGA_SEQ_MAX_REG
) VgaSeqIndex
= Data
;
1378 /* Call the sequencer function */
1379 VgaWriteSequencer(Data
);
1389 case VGA_DAC_READ_INDEX
:
1391 VgaDacReadWrite
= FALSE
;
1392 VgaDacIndex
= Data
* 3;
1396 case VGA_DAC_WRITE_INDEX
:
1398 VgaDacReadWrite
= TRUE
;
1399 VgaDacIndex
= Data
* 3;
1405 /* Ignore writes in read mode */
1406 if (VgaDacReadWrite
) VgaWriteDac(Data
& 0x3F);
1410 case VGA_CRTC_INDEX_MONO
:
1411 case VGA_CRTC_INDEX_COLOR
:
1413 /* Set the CRTC index register */
1414 if (Data
< VGA_CRTC_MAX_REG
) VgaCrtcIndex
= Data
;
1418 case VGA_CRTC_DATA_MONO
:
1419 case VGA_CRTC_DATA_COLOR
:
1421 /* Call the CRTC function */
1428 /* Set the GC index register */
1429 if (Data
< VGA_GC_MAX_REG
) VgaGcIndex
= Data
;
1435 /* Call the GC function */
1441 DPRINT1("VgaWritePort: Unknown port 0x%X\n", Port
);
1446 VOID
VgaClearMemory(VOID
)
1448 ZeroMemory(VgaMemory
, sizeof(VgaMemory
));
1451 VOID
VgaResetPalette(VOID
)
1453 PALETTEENTRY Entries
[VGA_MAX_COLORS
];
1455 /* Restore the default palette */
1456 VgaRestoreDefaultPalette(Entries
, VGA_MAX_COLORS
);
1457 SetPaletteEntries(PaletteHandle
, 0, VGA_MAX_COLORS
, Entries
);
1458 PaletteChanged
= TRUE
;
1461 BOOLEAN
VgaInitialize(HANDLE TextHandle
)
1467 COORD Origin
= { 0, 0 };
1468 SMALL_RECT ScreenRect
;
1469 PCHAR_INFO CharBuffer
;
1473 /* Initialize the VGA palette and fail if it isn't successfully created */
1474 if (!VgaInitializePalette()) return FALSE
;
1475 /***/ VgaResetPalette(); /***/
1477 /* Set the global handle */
1478 TextConsoleBuffer
= TextHandle
;
1480 /* Register the I/O Ports */
1481 RegisterIoPort(0x3CC, VgaReadPort
, NULL
); // VGA_MISC_READ
1482 RegisterIoPort(0x3C2, VgaReadPort
, VgaWritePort
); // VGA_MISC_WRITE, VGA_INSTAT0_READ
1483 RegisterIoPort(0x3CA, VgaReadPort
, NULL
); // VGA_FEATURE_READ
1484 RegisterIoPort(0x3C0, VgaReadPort
, VgaWritePort
); // VGA_AC_INDEX, VGA_AC_WRITE
1485 RegisterIoPort(0x3C1, VgaReadPort
, NULL
); // VGA_AC_READ
1486 RegisterIoPort(0x3C4, VgaReadPort
, VgaWritePort
); // VGA_SEQ_INDEX
1487 RegisterIoPort(0x3C5, VgaReadPort
, VgaWritePort
); // VGA_SEQ_DATA
1488 RegisterIoPort(0x3C6, VgaReadPort
, VgaWritePort
); // VGA_DAC_MASK
1489 RegisterIoPort(0x3C7, VgaReadPort
, VgaWritePort
); // VGA_DAC_READ_INDEX
1490 RegisterIoPort(0x3C8, VgaReadPort
, VgaWritePort
); // VGA_DAC_WRITE_INDEX
1491 RegisterIoPort(0x3C9, VgaReadPort
, VgaWritePort
); // VGA_DAC_DATA
1492 RegisterIoPort(0x3CE, VgaReadPort
, VgaWritePort
); // VGA_GC_INDEX
1493 RegisterIoPort(0x3CF, VgaReadPort
, VgaWritePort
); // VGA_GC_DATA
1495 /* Clear the VGA memory */
1498 /* Set the default video mode */
1499 BiosSetVideoMode(BIOS_DEFAULT_VIDEO_MODE
);
1503 Resolution
= VgaGetDisplayResolution();
1504 CharBuffer
= (PCHAR_INFO
)ConsoleFramebuffer
;
1505 AddressSize
= VgaGetAddressSize();
1506 ScreenRect
.Left
= ScreenRect
.Top
= 0;
1507 ScreenRect
.Right
= Resolution
.X
;
1508 ScreenRect
.Bottom
= Resolution
.Y
;
1509 ScanlineSize
= (DWORD
)VgaCrtcRegisters
[VGA_CRTC_OFFSET_REG
] * 2;
1511 /* Read the data from the console into the framebuffer */
1512 ReadConsoleOutputA(TextConsoleBuffer
,
1518 /* Loop through the scanlines */
1519 for (i
= 0; i
< Resolution
.Y
; i
++)
1521 /* Loop through the characters */
1522 for (j
= 0; j
< Resolution
.X
; j
++)
1524 CurrentAddr
= LOWORD((Address
+ j
) * AddressSize
);
1526 /* Store the character in plane 0 */
1527 VgaMemory
[CurrentAddr
] = CharBuffer
[i
* Resolution
.X
+ j
].Char
.AsciiChar
;
1529 /* Store the attribute in plane 1 */
1530 VgaMemory
[CurrentAddr
+ VGA_BANK_SIZE
] = (BYTE
)CharBuffer
[i
* Resolution
.X
+ j
].Attributes
;
1533 /* Move to the next scanline */
1534 Address
+= ScanlineSize
;
1537 /* Return success */