2 * COPYRIGHT: GPL - See COPYING in the top level directory
3 * PROJECT: ReactOS Virtual DOS Machine
4 * FILE: subsystems/mvdm/ntvdm/hardware/video/svga.c
5 * PURPOSE: SuperVGA hardware emulation (Cirrus Logic CL-GD5434 compatible)
6 * PROGRAMMERS: Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
9 /* INCLUDES *******************************************************************/
18 #include <bios/vidbios.h>
24 #include "../../console/video.h"
26 /* PRIVATE VARIABLES **********************************************************/
28 static CONST DWORD MemoryBase
[] = { 0xA0000, 0xA0000, 0xB0000, 0xB8000 };
29 static CONST DWORD MemorySize
[] = { 0x20000, 0x10000, 0x08000, 0x08000 };
31 #define USE_REACTOS_COLORS
32 // #define USE_DOSBOX_COLORS
34 #if defined(USE_REACTOS_COLORS)
37 static CONST COLORREF VgaDefaultPalette
[VGA_MAX_COLORS
] =
39 RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0xAA), RGB(0x00, 0xAA, 0x00), RGB(0x00, 0xAA, 0xAA),
40 RGB(0xAA, 0x00, 0x00), RGB(0xAA, 0x00, 0xAA), RGB(0xAA, 0x55, 0x00), RGB(0xAA, 0xAA, 0xAA),
41 RGB(0x55, 0x55, 0x55), RGB(0x55, 0x55, 0xFF), RGB(0x55, 0xFF, 0x55), RGB(0x55, 0xFF, 0xFF),
42 RGB(0xFF, 0x55, 0x55), RGB(0xFF, 0x55, 0xFF), RGB(0xFF, 0xFF, 0x55), RGB(0xFF, 0xFF, 0xFF),
43 RGB(0x00, 0x00, 0x00), RGB(0x10, 0x10, 0x10), RGB(0x20, 0x20, 0x20), RGB(0x35, 0x35, 0x35),
44 RGB(0x45, 0x45, 0x45), RGB(0x55, 0x55, 0x55), RGB(0x65, 0x65, 0x65), RGB(0x75, 0x75, 0x75),
45 RGB(0x8A, 0x8A, 0x8A), RGB(0x9A, 0x9A, 0x9A), RGB(0xAA, 0xAA, 0xAA), RGB(0xBA, 0xBA, 0xBA),
46 RGB(0xCA, 0xCA, 0xCA), RGB(0xDF, 0xDF, 0xDF), RGB(0xEF, 0xEF, 0xEF), RGB(0xFF, 0xFF, 0xFF),
47 RGB(0x00, 0x00, 0xFF), RGB(0x41, 0x00, 0xFF), RGB(0x82, 0x00, 0xFF), RGB(0xBE, 0x00, 0xFF),
48 RGB(0xFF, 0x00, 0xFF), RGB(0xFF, 0x00, 0xBE), RGB(0xFF, 0x00, 0x82), RGB(0xFF, 0x00, 0x41),
49 RGB(0xFF, 0x00, 0x00), RGB(0xFF, 0x41, 0x00), RGB(0xFF, 0x82, 0x00), RGB(0xFF, 0xBE, 0x00),
50 RGB(0xFF, 0xFF, 0x00), RGB(0xBE, 0xFF, 0x00), RGB(0x82, 0xFF, 0x00), RGB(0x41, 0xFF, 0x00),
51 RGB(0x00, 0xFF, 0x00), RGB(0x00, 0xFF, 0x41), RGB(0x00, 0xFF, 0x82), RGB(0x00, 0xFF, 0xBE),
52 RGB(0x00, 0xFF, 0xFF), RGB(0x00, 0xBE, 0xFF), RGB(0x00, 0x82, 0xFF), RGB(0x00, 0x41, 0xFF),
53 RGB(0x82, 0x82, 0xFF), RGB(0x9E, 0x82, 0xFF), RGB(0xBE, 0x82, 0xFF), RGB(0xDF, 0x82, 0xFF),
54 RGB(0xFF, 0x82, 0xFF), RGB(0xFF, 0x82, 0xDF), RGB(0xFF, 0x82, 0xBE), RGB(0xFF, 0x82, 0x9E),
55 RGB(0xFF, 0x82, 0x82), RGB(0xFF, 0x9E, 0x82), RGB(0xFF, 0xBE, 0x82), RGB(0xFF, 0xDF, 0x82),
56 RGB(0xFF, 0xFF, 0x82), RGB(0xDF, 0xFF, 0x82), RGB(0xBE, 0xFF, 0x82), RGB(0x9E, 0xFF, 0x82),
57 RGB(0x82, 0xFF, 0x82), RGB(0x82, 0xFF, 0x9E), RGB(0x82, 0xFF, 0xBE), RGB(0x82, 0xFF, 0xDF),
58 RGB(0x82, 0xFF, 0xFF), RGB(0x82, 0xDF, 0xFF), RGB(0x82, 0xBE, 0xFF), RGB(0x82, 0x9E, 0xFF),
59 RGB(0xBA, 0xBA, 0xFF), RGB(0xCA, 0xBA, 0xFF), RGB(0xDF, 0xBA, 0xFF), RGB(0xEF, 0xBA, 0xFF),
60 RGB(0xFF, 0xBA, 0xFF), RGB(0xFF, 0xBA, 0xEF), RGB(0xFF, 0xBA, 0xDF), RGB(0xFF, 0xBA, 0xCA),
61 RGB(0xFF, 0xBA, 0xBA), RGB(0xFF, 0xCA, 0xBA), RGB(0xFF, 0xDF, 0xBA), RGB(0xFF, 0xEF, 0xBA),
62 RGB(0xFF, 0xFF, 0xBA), RGB(0xEF, 0xFF, 0xBA), RGB(0xDF, 0xFF, 0xBA), RGB(0xCA, 0xFF, 0xBA),
63 RGB(0xBA, 0xFF, 0xBA), RGB(0xBA, 0xFF, 0xCA), RGB(0xBA, 0xFF, 0xDF), RGB(0xBA, 0xFF, 0xEF),
64 RGB(0xBA, 0xFF, 0xFF), RGB(0xBA, 0xEF, 0xFF), RGB(0xBA, 0xDF, 0xFF), RGB(0xBA, 0xCA, 0xFF),
65 RGB(0x00, 0x00, 0x71), RGB(0x1C, 0x00, 0x71), RGB(0x39, 0x00, 0x71), RGB(0x55, 0x00, 0x71),
66 RGB(0x71, 0x00, 0x71), RGB(0x71, 0x00, 0x55), RGB(0x71, 0x00, 0x39), RGB(0x71, 0x00, 0x1C),
67 RGB(0x71, 0x00, 0x00), RGB(0x71, 0x1C, 0x00), RGB(0x71, 0x39, 0x00), RGB(0x71, 0x55, 0x00),
68 RGB(0x71, 0x71, 0x00), RGB(0x55, 0x71, 0x00), RGB(0x39, 0x71, 0x00), RGB(0x1C, 0x71, 0x00),
69 RGB(0x00, 0x71, 0x00), RGB(0x00, 0x71, 0x1C), RGB(0x00, 0x71, 0x39), RGB(0x00, 0x71, 0x55),
70 RGB(0x00, 0x71, 0x71), RGB(0x00, 0x55, 0x71), RGB(0x00, 0x39, 0x71), RGB(0x00, 0x1C, 0x71),
71 RGB(0x39, 0x39, 0x71), RGB(0x45, 0x39, 0x71), RGB(0x55, 0x39, 0x71), RGB(0x61, 0x39, 0x71),
72 RGB(0x71, 0x39, 0x71), RGB(0x71, 0x39, 0x61), RGB(0x71, 0x39, 0x55), RGB(0x71, 0x39, 0x45),
73 RGB(0x71, 0x39, 0x39), RGB(0x71, 0x45, 0x39), RGB(0x71, 0x55, 0x39), RGB(0x71, 0x61, 0x39),
74 RGB(0x71, 0x71, 0x39), RGB(0x61, 0x71, 0x39), RGB(0x55, 0x71, 0x39), RGB(0x45, 0x71, 0x39),
75 RGB(0x39, 0x71, 0x39), RGB(0x39, 0x71, 0x45), RGB(0x39, 0x71, 0x55), RGB(0x39, 0x71, 0x61),
76 RGB(0x39, 0x71, 0x71), RGB(0x39, 0x61, 0x71), RGB(0x39, 0x55, 0x71), RGB(0x39, 0x45, 0x71),
77 RGB(0x51, 0x51, 0x71), RGB(0x59, 0x51, 0x71), RGB(0x61, 0x51, 0x71), RGB(0x69, 0x51, 0x71),
78 RGB(0x71, 0x51, 0x71), RGB(0x71, 0x51, 0x69), RGB(0x71, 0x51, 0x61), RGB(0x71, 0x51, 0x59),
79 RGB(0x71, 0x51, 0x51), RGB(0x71, 0x59, 0x51), RGB(0x71, 0x61, 0x51), RGB(0x71, 0x69, 0x51),
80 RGB(0x71, 0x71, 0x51), RGB(0x69, 0x71, 0x51), RGB(0x61, 0x71, 0x51), RGB(0x59, 0x71, 0x51),
81 RGB(0x51, 0x71, 0x51), RGB(0x51, 0x71, 0x59), RGB(0x51, 0x71, 0x61), RGB(0x51, 0x71, 0x69),
82 RGB(0x51, 0x71, 0x71), RGB(0x51, 0x69, 0x71), RGB(0x51, 0x61, 0x71), RGB(0x51, 0x59, 0x71),
83 RGB(0x00, 0x00, 0x41), RGB(0x10, 0x00, 0x41), RGB(0x20, 0x00, 0x41), RGB(0x31, 0x00, 0x41),
84 RGB(0x41, 0x00, 0x41), RGB(0x41, 0x00, 0x31), RGB(0x41, 0x00, 0x20), RGB(0x41, 0x00, 0x10),
85 RGB(0x41, 0x00, 0x00), RGB(0x41, 0x10, 0x00), RGB(0x41, 0x20, 0x00), RGB(0x41, 0x31, 0x00),
86 RGB(0x41, 0x41, 0x00), RGB(0x31, 0x41, 0x00), RGB(0x20, 0x41, 0x00), RGB(0x10, 0x41, 0x00),
87 RGB(0x00, 0x41, 0x00), RGB(0x00, 0x41, 0x10), RGB(0x00, 0x41, 0x20), RGB(0x00, 0x41, 0x31),
88 RGB(0x00, 0x41, 0x41), RGB(0x00, 0x31, 0x41), RGB(0x00, 0x20, 0x41), RGB(0x00, 0x10, 0x41),
89 RGB(0x20, 0x20, 0x41), RGB(0x28, 0x20, 0x41), RGB(0x31, 0x20, 0x41), RGB(0x39, 0x20, 0x41),
90 RGB(0x41, 0x20, 0x41), RGB(0x41, 0x20, 0x39), RGB(0x41, 0x20, 0x31), RGB(0x41, 0x20, 0x28),
91 RGB(0x41, 0x20, 0x20), RGB(0x41, 0x28, 0x20), RGB(0x41, 0x31, 0x20), RGB(0x41, 0x39, 0x20),
92 RGB(0x41, 0x41, 0x20), RGB(0x39, 0x41, 0x20), RGB(0x31, 0x41, 0x20), RGB(0x28, 0x41, 0x20),
93 RGB(0x20, 0x41, 0x20), RGB(0x20, 0x41, 0x28), RGB(0x20, 0x41, 0x31), RGB(0x20, 0x41, 0x39),
94 RGB(0x20, 0x41, 0x41), RGB(0x20, 0x39, 0x41), RGB(0x20, 0x31, 0x41), RGB(0x20, 0x28, 0x41),
95 RGB(0x2D, 0x2D, 0x41), RGB(0x31, 0x2D, 0x41), RGB(0x35, 0x2D, 0x41), RGB(0x3D, 0x2D, 0x41),
96 RGB(0x41, 0x2D, 0x41), RGB(0x41, 0x2D, 0x3D), RGB(0x41, 0x2D, 0x35), RGB(0x41, 0x2D, 0x31),
97 RGB(0x41, 0x2D, 0x2D), RGB(0x41, 0x31, 0x2D), RGB(0x41, 0x35, 0x2D), RGB(0x41, 0x3D, 0x2D),
98 RGB(0x41, 0x41, 0x2D), RGB(0x3D, 0x41, 0x2D), RGB(0x35, 0x41, 0x2D), RGB(0x31, 0x41, 0x2D),
99 RGB(0x2D, 0x41, 0x2D), RGB(0x2D, 0x41, 0x31), RGB(0x2D, 0x41, 0x35), RGB(0x2D, 0x41, 0x3D),
100 RGB(0x2D, 0x41, 0x41), RGB(0x2D, 0x3D, 0x41), RGB(0x2D, 0x35, 0x41), RGB(0x2D, 0x31, 0x41),
101 RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00),
102 RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00)
105 #elif defined(USE_DOSBOX_COLORS)
108 static CONST COLORREF VgaDefaultPalette
[VGA_MAX_COLORS
] =
110 RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0xAA), RGB(0x00, 0xAA, 0x00), RGB(0x00, 0xAA, 0xAA),
111 RGB(0xAA, 0x00, 0x00), RGB(0xAA, 0x00, 0xAA), RGB(0xAA, 0x55, 0x00), RGB(0xAA, 0xAA, 0xAA),
112 RGB(0x55, 0x55, 0x55), RGB(0x55, 0x55, 0xFF), RGB(0x55, 0xFF, 0x55), RGB(0x55, 0xFF, 0xFF),
113 RGB(0xFF, 0x55, 0x55), RGB(0xFF, 0x55, 0xFF), RGB(0xFF, 0xFF, 0x55), RGB(0xFF, 0xFF, 0xFF),
114 RGB(0x00, 0x00, 0x00), RGB(0x14, 0x14, 0x14), RGB(0x20, 0x20, 0x20), RGB(0x2C, 0x2C, 0x2C),
115 RGB(0x38, 0x38, 0x38), RGB(0x45, 0x45, 0x45), RGB(0x51, 0x51, 0x51), RGB(0x61, 0x61, 0x61),
116 RGB(0x71, 0x71, 0x71), RGB(0x82, 0x82, 0x82), RGB(0x92, 0x92, 0x92), RGB(0xA2, 0xA2, 0xA2),
117 RGB(0xB6, 0xB6, 0xB6), RGB(0xCB, 0xCB, 0xCB), RGB(0xE3, 0xE3, 0xE3), RGB(0xFF, 0xFF, 0xFF),
118 RGB(0x00, 0x00, 0xFF), RGB(0x41, 0x00, 0xFF), RGB(0x7D, 0x00, 0xFF), RGB(0xBE, 0x00, 0xFF),
119 RGB(0xFF, 0x00, 0xFF), RGB(0xFF, 0x00, 0xBE), RGB(0xFF, 0x00, 0x7D), RGB(0xFF, 0x00, 0x41),
120 RGB(0xFF, 0x00, 0x00), RGB(0xFF, 0x41, 0x00), RGB(0xFF, 0x7D, 0x00), RGB(0xFF, 0xBE, 0x00),
121 RGB(0xFF, 0xFF, 0x00), RGB(0xBE, 0xFF, 0x00), RGB(0x7D, 0xFF, 0x00), RGB(0x41, 0xFF, 0x00),
122 RGB(0x00, 0xFF, 0x00), RGB(0x00, 0xFF, 0x41), RGB(0x00, 0xFF, 0x7D), RGB(0x00, 0xFF, 0xBE),
123 RGB(0x00, 0xFF, 0xFF), RGB(0x00, 0xBE, 0xFF), RGB(0x00, 0x7D, 0xFF), RGB(0x00, 0x41, 0xFF),
124 RGB(0x7D, 0x7D, 0xFF), RGB(0x9E, 0x7D, 0xFF), RGB(0xBE, 0x7D, 0xFF), RGB(0xDF, 0x7D, 0xFF),
125 RGB(0xFF, 0x7D, 0xFF), RGB(0xFF, 0x7D, 0xDF), RGB(0xFF, 0x7D, 0xBE), RGB(0xFF, 0x7D, 0x9E),
127 RGB(0xFF, 0x7D, 0x7D), RGB(0xFF, 0x9E, 0x7D), RGB(0xFF, 0xBE, 0x7D), RGB(0xFF, 0xDF, 0x7D),
128 RGB(0xFF, 0xFF, 0x7D), RGB(0xDF, 0xFF, 0x7D), RGB(0xBE, 0xFF, 0x7D), RGB(0x9E, 0xFF, 0x7D),
129 RGB(0x7D, 0xFF, 0x7D), RGB(0x7D, 0xFF, 0x9E), RGB(0x7D, 0xFF, 0xBE), RGB(0x7D, 0xFF, 0xDF),
130 RGB(0x7D, 0xFF, 0xFF), RGB(0x7D, 0xDF, 0xFF), RGB(0x7D, 0xBE, 0xFF), RGB(0x7D, 0x9E, 0xFF),
131 RGB(0xB6, 0xB6, 0xFF), RGB(0xC7, 0xB6, 0xFF), RGB(0xDB, 0xB6, 0xFF), RGB(0xEB, 0xB6, 0xFF),
132 RGB(0xFF, 0xB6, 0xFF), RGB(0xFF, 0xB6, 0xEB), RGB(0xFF, 0xB6, 0xDB), RGB(0xFF, 0xB6, 0xC7),
133 RGB(0xFF, 0xB6, 0xB6), RGB(0xFF, 0xC7, 0xB6), RGB(0xFF, 0xDB, 0xB6), RGB(0xFF, 0xEB, 0xB6),
134 RGB(0xFF, 0xFF, 0xB6), RGB(0xEB, 0xFF, 0xB6), RGB(0xDB, 0xFF, 0xB6), RGB(0xC7, 0xFF, 0xB6),
135 RGB(0xB6, 0xFF, 0xB6), RGB(0xB6, 0xFF, 0xC7), RGB(0xB6, 0xFF, 0xDB), RGB(0xB6, 0xFF, 0xEB),
136 RGB(0xB6, 0xFF, 0xFF), RGB(0xB6, 0xEB, 0xFF), RGB(0xB6, 0xDB, 0xFF), RGB(0xB6, 0xC7, 0xFF),
137 RGB(0x00, 0x00, 0x71), RGB(0x1C, 0x00, 0x71), RGB(0x38, 0x00, 0x71), RGB(0x55, 0x00, 0x71),
138 RGB(0x71, 0x00, 0x71), RGB(0x71, 0x00, 0x55), RGB(0x71, 0x00, 0x38), RGB(0x71, 0x00, 0x1C),
139 RGB(0x71, 0x00, 0x00), RGB(0x71, 0x1C, 0x00), RGB(0x71, 0x38, 0x00), RGB(0x71, 0x55, 0x00),
140 RGB(0x71, 0x71, 0x00), RGB(0x55, 0x71, 0x00), RGB(0x38, 0x71, 0x00), RGB(0x1C, 0x71, 0x00),
141 RGB(0x00, 0x71, 0x00), RGB(0x00, 0x71, 0x1C), RGB(0x00, 0x71, 0x38), RGB(0x00, 0x71, 0x55),
142 RGB(0x00, 0x71, 0x71), RGB(0x00, 0x55, 0x71), RGB(0x00, 0x38, 0x71), RGB(0x00, 0x1C, 0x71),
144 RGB(0x38, 0x38, 0x71), RGB(0x45, 0x38, 0x71), RGB(0x55, 0x38, 0x71), RGB(0x61, 0x38, 0x71),
145 RGB(0x71, 0x38, 0x71), RGB(0x71, 0x38, 0x61), RGB(0x71, 0x38, 0x55), RGB(0x71, 0x38, 0x45),
146 RGB(0x71, 0x38, 0x38), RGB(0x71, 0x45, 0x38), RGB(0x71, 0x55, 0x38), RGB(0x71, 0x61, 0x38),
147 RGB(0x71, 0x71, 0x38), RGB(0x61, 0x71, 0x38), RGB(0x55, 0x71, 0x38), RGB(0x45, 0x71, 0x38),
148 RGB(0x38, 0x71, 0x38), RGB(0x38, 0x71, 0x45), RGB(0x38, 0x71, 0x55), RGB(0x38, 0x71, 0x61),
149 RGB(0x38, 0x71, 0x71), RGB(0x38, 0x61, 0x71), RGB(0x38, 0x55, 0x71), RGB(0x38, 0x45, 0x71),
150 RGB(0x51, 0x51, 0x71), RGB(0x59, 0x51, 0x71), RGB(0x61, 0x51, 0x71), RGB(0x69, 0x51, 0x71),
151 RGB(0x71, 0x51, 0x71), RGB(0x71, 0x51, 0x69), RGB(0x71, 0x51, 0x61), RGB(0x71, 0x51, 0x59),
152 RGB(0x71, 0x51, 0x51), RGB(0x71, 0x59, 0x51), RGB(0x71, 0x61, 0x51), RGB(0x71, 0x69, 0x51),
153 RGB(0x71, 0x71, 0x51), RGB(0x69, 0x71, 0x51), RGB(0x61, 0x71, 0x51), RGB(0x59, 0x71, 0x51),
154 RGB(0x51, 0x71, 0x51), RGB(0x51, 0x71, 0x59), RGB(0x51, 0x71, 0x61), RGB(0x51, 0x71, 0x69),
155 RGB(0x51, 0x71, 0x71), RGB(0x51, 0x69, 0x71), RGB(0x51, 0x61, 0x71), RGB(0x51, 0x59, 0x71),
156 RGB(0x00, 0x00, 0x41), RGB(0x10, 0x00, 0x41), RGB(0x20, 0x00, 0x41), RGB(0x30, 0x00, 0x41),
157 RGB(0x41, 0x00, 0x41), RGB(0x41, 0x00, 0x30), RGB(0x41, 0x00, 0x20), RGB(0x41, 0x00, 0x10),
158 RGB(0x41, 0x00, 0x00), RGB(0x41, 0x10, 0x00), RGB(0x41, 0x20, 0x00), RGB(0x41, 0x30, 0x00),
159 RGB(0x41, 0x41, 0x00), RGB(0x30, 0x41, 0x00), RGB(0x20, 0x41, 0x00), RGB(0x10, 0x41, 0x00),
161 RGB(0x00, 0x41, 0x00), RGB(0x00, 0x41, 0x10), RGB(0x00, 0x41, 0x20), RGB(0x00, 0x41, 0x30),
162 RGB(0x00, 0x41, 0x41), RGB(0x00, 0x30, 0x41), RGB(0x00, 0x20, 0x41), RGB(0x00, 0x10, 0x41),
163 RGB(0x20, 0x20, 0x41), RGB(0x28, 0x20, 0x41), RGB(0x30, 0x20, 0x41), RGB(0x38, 0x20, 0x41),
164 RGB(0x41, 0x20, 0x41), RGB(0x41, 0x20, 0x38), RGB(0x41, 0x20, 0x30), RGB(0x41, 0x20, 0x28),
165 RGB(0x41, 0x20, 0x20), RGB(0x41, 0x28, 0x20), RGB(0x41, 0x30, 0x20), RGB(0x41, 0x38, 0x20),
166 RGB(0x41, 0x41, 0x20), RGB(0x38, 0x41, 0x20), RGB(0x30, 0x41, 0x20), RGB(0x28, 0x41, 0x20),
167 RGB(0x20, 0x41, 0x20), RGB(0x20, 0x41, 0x28), RGB(0x20, 0x41, 0x30), RGB(0x20, 0x41, 0x38),
168 RGB(0x20, 0x41, 0x41), RGB(0x20, 0x38, 0x41), RGB(0x20, 0x30, 0x41), RGB(0x20, 0x28, 0x41),
169 RGB(0x2C, 0x2C, 0x41), RGB(0x30, 0x2C, 0x41), RGB(0x34, 0x2C, 0x41), RGB(0x3C, 0x2C, 0x41),
170 RGB(0x41, 0x2C, 0x41), RGB(0x41, 0x2C, 0x3C), RGB(0x41, 0x2C, 0x34), RGB(0x41, 0x2C, 0x30),
171 RGB(0x41, 0x2C, 0x2C), RGB(0x41, 0x30, 0x2C), RGB(0x41, 0x34, 0x2C), RGB(0x41, 0x3C, 0x2C),
172 RGB(0x41, 0x41, 0x2C), RGB(0x3C, 0x41, 0x2C), RGB(0x34, 0x41, 0x2C), RGB(0x30, 0x41, 0x2C),
173 RGB(0x2C, 0x41, 0x2C), RGB(0x2C, 0x41, 0x30), RGB(0x2C, 0x41, 0x34), RGB(0x2C, 0x41, 0x3C),
174 RGB(0x2C, 0x41, 0x41), RGB(0x2C, 0x3C, 0x41), RGB(0x2C, 0x34, 0x41), RGB(0x2C, 0x30, 0x41),
175 RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00),
176 RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00)
182 * Default 16-color palette for foreground and background
183 * (corresponding flags in comments).
184 * Taken from subsystems/win32/winsrv/consrv/frontends/gui/conwnd.c
186 static const COLORREF ConsoleColors
[16] =
188 RGB(0, 0, 0), // (Black)
189 RGB(0, 0, 128), // BLUE
190 RGB(0, 128, 0), // GREEN
191 RGB(0, 128, 128), // BLUE | GREEN
192 RGB(128, 0, 0), // RED
193 RGB(128, 0, 128), // BLUE | RED
194 RGB(128, 128, 0), // GREEN | RED
195 RGB(192, 192, 192), // BLUE | GREEN | RED
197 RGB(128, 128, 128), // (Grey) INTENSITY
198 RGB(0, 0, 255), // BLUE | INTENSITY
199 RGB(0, 255, 0), // GREEN | INTENSITY
200 RGB(0, 255, 255), // BLUE | GREEN | INTENSITY
201 RGB(255, 0, 0), // RED | INTENSITY
202 RGB(255, 0, 255), // BLUE | RED | INTENSITY
203 RGB(255, 255, 0), // GREEN | RED | INTENSITY
204 RGB(255, 255, 255) // BLUE | GREEN | RED | INTENSITY
207 /// ConsoleFramebuffer
208 static PVOID ActiveFramebuffer
= NULL
; // Active framebuffer, points to
209 // either TextFramebuffer or a
210 // valid graphics framebuffer.
211 static HPALETTE TextPaletteHandle
= NULL
;
212 static HPALETTE PaletteHandle
= NULL
;
215 * Text mode -- we always keep a valid text mode framebuffer
216 * even if we are in graphics mode. This is needed in order
217 * to keep a consistent VGA state. However, each time the VGA
218 * detaches from the console (and reattaches to it later on),
219 * this text mode framebuffer is recreated.
221 static PCHAR_CELL TextFramebuffer
= NULL
;
226 static PBYTE GraphicsFramebuffer
= NULL
;
229 // static HANDLE ConsoleMutex = NULL;
230 // /* DoubleVision support */
231 // static BOOLEAN DoubleWidth = FALSE;
232 // static BOOLEAN DoubleHeight = FALSE;
241 static BYTE VgaMemory
[VGA_NUM_BANKS
* SVGA_BANK_SIZE
];
243 static BYTE VgaLatchRegisters
[VGA_NUM_BANKS
] = {0, 0, 0, 0};
245 static BYTE VgaMiscRegister
;
246 static BYTE VgaFeatureRegister
;
248 static BYTE VgaSeqIndex
= VGA_SEQ_RESET_REG
;
249 static BYTE VgaSeqRegisters
[SVGA_SEQ_MAX_REG
];
251 static BYTE VgaCrtcIndex
= VGA_CRTC_HORZ_TOTAL_REG
;
252 static BYTE VgaCrtcRegisters
[SVGA_CRTC_MAX_REG
];
254 static BYTE VgaGcIndex
= VGA_GC_RESET_REG
;
255 static BYTE VgaGcRegisters
[SVGA_GC_MAX_REG
];
257 static BOOLEAN VgaAcLatch
= FALSE
;
258 static BOOLEAN VgaAcPalDisable
= TRUE
;
259 static BYTE VgaAcIndex
= VGA_AC_PAL_0_REG
;
260 static BYTE VgaAcRegisters
[VGA_AC_MAX_REG
];
262 static BYTE VgaDacMask
= 0xFF;
263 static BYTE VgaDacLatchCounter
= 0;
264 static BYTE VgaDacLatch
[3];
266 static BOOLEAN VgaDacReadWrite
= FALSE
;
267 static WORD VgaDacIndex
= 0;
268 static BYTE VgaDacRegisters
[VGA_PALETTE_SIZE
];
270 // static VGA_REGISTERS VgaRegisters;
272 static ULONGLONG VerticalRetraceCycle
= 0ULL;
273 static ULONGLONG HorizontalRetraceCycle
= 0ULL;
274 static PHARDWARE_TIMER VSyncTimer
;
275 static PHARDWARE_TIMER HSyncTimer
;
277 static BOOLEAN NeedsUpdate
= FALSE
;
278 static BOOLEAN ModeChanged
= FALSE
;
279 static BOOLEAN CursorChanged
= FALSE
;
280 static BOOLEAN PaletteChanged
= FALSE
;
282 static UINT SvgaHdrCounter
= 0;
283 static BYTE SvgaHiddenRegister
= 0;
285 typedef enum _SCREEN_MODE
289 } SCREEN_MODE
, *PSCREEN_MODE
;
291 static SCREEN_MODE ScreenMode
= TEXT_MODE
;
292 static COORD CurrResolution
= {0};
294 static SMALL_RECT UpdateRectangle
= { 0, 0, 0, 0 };
300 #include "../../console/video.c"
307 /* PRIVATE FUNCTIONS **********************************************************/
309 static inline DWORD
VgaGetVideoBaseAddress(VOID
)
311 return MemoryBase
[(VgaGcRegisters
[VGA_GC_MISC_REG
] >> 2) & 0x03];
314 static inline DWORD
VgaGetAddressSize(VOID
)
316 if (VgaCrtcRegisters
[VGA_CRTC_UNDERLINE_REG
] & VGA_CRTC_UNDERLINE_DWORD
)
318 /* Double-word addressing */
319 return 4; // sizeof(DWORD)
321 else if (VgaCrtcRegisters
[VGA_CRTC_MODE_CONTROL_REG
] & VGA_CRTC_MODE_CONTROL_BYTE
)
323 /* Byte addressing */
324 return 1; // sizeof(BYTE)
328 /* Word addressing */
329 return 2; // sizeof(WORD)
333 static inline DWORD
VgaTranslateReadAddress(DWORD Address
)
335 DWORD Offset
= LOWORD(Address
- VgaGetVideoBaseAddress());
338 /* Check for chain-4 and odd-even mode */
339 if (VgaSeqRegisters
[VGA_SEQ_MEM_REG
] & VGA_SEQ_MEM_C4
)
341 /* The lowest two bits are the plane number */
342 Plane
= Offset
& 0x03;
345 else if (VgaGcRegisters
[VGA_GC_MODE_REG
] & VGA_GC_MODE_OE
)
347 /* The LSB is the plane number */
348 Plane
= Offset
& 0x01;
353 /* Use the read mode */
354 Plane
= VgaGcRegisters
[VGA_GC_READ_MAP_SEL_REG
] & 0x03;
357 /* Return the offset on plane 0 for read mode 1 */
358 if (VgaGcRegisters
[VGA_GC_MODE_REG
] & VGA_GC_MODE_READ
) return Offset
;
359 else return Offset
+ Plane
* VGA_BANK_SIZE
;
362 static inline DWORD
VgaTranslateWriteAddress(DWORD Address
)
364 DWORD Offset
= LOWORD(Address
- VgaGetVideoBaseAddress());
366 /* Check for chain-4 and odd-even mode */
367 if (VgaSeqRegisters
[VGA_SEQ_MEM_REG
] & VGA_SEQ_MEM_C4
)
369 /* Clear the lowest two bits since they're used to select the bank */
372 else if (VgaGcRegisters
[VGA_GC_MODE_REG
] & VGA_GC_MODE_OE
)
374 /* Clear the lowest bit since it's used to select odd/even */
378 /* Return the offset on plane 0 */
382 static inline BYTE
VgaTranslateByteForWriting(BYTE Data
, BYTE Plane
)
384 BYTE WriteMode
= VgaGcRegisters
[VGA_GC_MODE_REG
] & 0x03;
385 BYTE BitMask
= VgaGcRegisters
[VGA_GC_BITMASK_REG
];
389 /* In write mode 1 just return the latch register */
390 return VgaLatchRegisters
[Plane
];
395 /* Write modes 0 and 3 rotate the data to the right first */
396 BYTE RotateCount
= VgaGcRegisters
[VGA_GC_ROTATE_REG
] & 0x07;
397 Data
= LOBYTE(((DWORD
)Data
>> RotateCount
) | ((DWORD
)Data
<< (8 - RotateCount
)));
401 /* Write mode 2 expands the appropriate bit to all 8 bits */
402 Data
= (Data
& (1 << Plane
)) ? 0xFF : 0x00;
408 * In write mode 0, the enable set/reset register decides if the
409 * set/reset bit should be expanded to all 8 bits.
411 if (VgaGcRegisters
[VGA_GC_ENABLE_RESET_REG
] & (1 << Plane
))
413 /* Copy the bit from the set/reset register to all 8 bits */
414 Data
= (VgaGcRegisters
[VGA_GC_RESET_REG
] & (1 << Plane
)) ? 0xFF : 0x00;
420 /* Write modes 0 and 2 then perform a logical operation on the data and latch */
421 BYTE LogicalOperation
= (VgaGcRegisters
[VGA_GC_ROTATE_REG
] >> 3) & 0x03;
423 if (LogicalOperation
== 1) Data
&= VgaLatchRegisters
[Plane
];
424 else if (LogicalOperation
== 2) Data
|= VgaLatchRegisters
[Plane
];
425 else if (LogicalOperation
== 3) Data
^= VgaLatchRegisters
[Plane
];
429 /* For write mode 3, we AND the bitmask with the data, which is used as the new bitmask */
432 /* Then we expand the bit in the set/reset field */
433 Data
= (VgaGcRegisters
[VGA_GC_RESET_REG
] & (1 << Plane
)) ? 0xFF : 0x00;
436 /* Bits cleared in the bitmask are replaced with latch register bits */
437 Data
= (Data
& BitMask
) | (VgaLatchRegisters
[Plane
] & (~BitMask
));
439 /* Return the byte */
443 static inline ULONG
VgaGetClockFrequency(VOID
)
445 BYTE Numerator
, Denominator
;
447 if (VgaSeqRegisters
[SVGA_SEQ_MCLK_REG
] & SVGA_SEQ_MCLK_VCLK
)
449 /* The VCLK is being generated using the MCLK */
450 ULONG Clock
= (VGA_CLOCK_BASE
* (VgaSeqRegisters
[SVGA_SEQ_MCLK_REG
] & 0x3F)) >> 3;
452 if (VgaSeqRegisters
[SVGA_SEQ_VCLK3_DENOMINATOR_REG
] & 1)
454 /* Use only half of the MCLK as the VCLK */
461 switch ((VgaMiscRegister
>> 2) & 3)
465 Numerator
= VgaSeqRegisters
[SVGA_SEQ_VCLK0_NUMERATOR_REG
];
466 Denominator
= VgaSeqRegisters
[SVGA_SEQ_VCLK0_DENOMINATOR_REG
];
472 Numerator
= VgaSeqRegisters
[SVGA_SEQ_VCLK1_NUMERATOR_REG
];
473 Denominator
= VgaSeqRegisters
[SVGA_SEQ_VCLK1_DENOMINATOR_REG
];
479 Numerator
= VgaSeqRegisters
[SVGA_SEQ_VCLK2_NUMERATOR_REG
];
480 Denominator
= VgaSeqRegisters
[SVGA_SEQ_VCLK2_DENOMINATOR_REG
];
486 Numerator
= VgaSeqRegisters
[SVGA_SEQ_VCLK3_NUMERATOR_REG
];
487 Denominator
= VgaSeqRegisters
[SVGA_SEQ_VCLK3_DENOMINATOR_REG
];
492 /* The numerator is 7-bit */
493 Numerator
&= ~(1 << 7);
495 /* If bit 7 is clear, the denominator is 5-bit */
496 if (!(Denominator
& (1 << 7))) Denominator
&= ~(1 << 6);
498 /* Bit 0 of the denominator is the post-scalar bit */
499 if (Denominator
& 1) Denominator
&= ~1;
500 else Denominator
>>= 1;
502 /* Return the clock frequency in Hz */
503 return (VGA_CLOCK_BASE
* Numerator
) / Denominator
;
506 static VOID
VgaResetSequencer(VOID
)
508 /* Lock extended SVGA registers */
509 VgaSeqRegisters
[SVGA_SEQ_UNLOCK_REG
] = SVGA_SEQ_LOCKED
;
511 /* Initialize the VCLKs */
512 VgaSeqRegisters
[SVGA_SEQ_VCLK0_NUMERATOR_REG
] = 0x66;
513 VgaSeqRegisters
[SVGA_SEQ_VCLK0_DENOMINATOR_REG
] = 0x3B;
514 VgaSeqRegisters
[SVGA_SEQ_VCLK1_NUMERATOR_REG
] = 0x5B;
515 VgaSeqRegisters
[SVGA_SEQ_VCLK1_DENOMINATOR_REG
] = 0x2F;
516 VgaSeqRegisters
[SVGA_SEQ_VCLK2_NUMERATOR_REG
] = 0x45;
517 VgaSeqRegisters
[SVGA_SEQ_VCLK2_DENOMINATOR_REG
] = 0x30;
518 VgaSeqRegisters
[SVGA_SEQ_VCLK3_NUMERATOR_REG
] = 0x7E;
519 VgaSeqRegisters
[SVGA_SEQ_VCLK3_DENOMINATOR_REG
] = 0x33;
521 /* 50 MHz MCLK, not being used as the VCLK */
522 VgaSeqRegisters
[SVGA_SEQ_MCLK_REG
] = 0x1C;
525 static VOID
VgaRestoreDefaultPalette(PPALETTEENTRY Entries
, USHORT NumOfEntries
)
529 /* Copy the colors of the default palette to the DAC and console palette */
530 for (i
= 0; i
< NumOfEntries
; i
++)
532 /* Set the palette entries */
533 Entries
[i
].peRed
= GetRValue(VgaDefaultPalette
[i
]);
534 Entries
[i
].peGreen
= GetGValue(VgaDefaultPalette
[i
]);
535 Entries
[i
].peBlue
= GetBValue(VgaDefaultPalette
[i
]);
536 Entries
[i
].peFlags
= 0;
538 /* Set the DAC registers */
539 VgaDacRegisters
[i
* 3] = VGA_COLOR_TO_DAC(GetRValue(VgaDefaultPalette
[i
]));
540 VgaDacRegisters
[i
* 3 + 1] = VGA_COLOR_TO_DAC(GetGValue(VgaDefaultPalette
[i
]));
541 VgaDacRegisters
[i
* 3 + 2] = VGA_COLOR_TO_DAC(GetBValue(VgaDefaultPalette
[i
]));
545 static BOOLEAN
VgaInitializePalette(VOID
)
548 BOOLEAN Result
= FALSE
;
549 LPLOGPALETTE Palette
, TextPalette
;
551 /* Allocate storage space for the palettes */
552 Palette
= RtlAllocateHeap(RtlGetProcessHeap(),
555 VGA_MAX_COLORS
* sizeof(PALETTEENTRY
));
556 TextPalette
= RtlAllocateHeap(RtlGetProcessHeap(),
559 (VGA_AC_PAL_F_REG
+ 1) * sizeof(PALETTEENTRY
));
560 if ((Palette
== NULL
) || (TextPalette
== NULL
)) goto Cleanup
;
562 /* Initialize the palettes */
563 Palette
->palVersion
= TextPalette
->palVersion
= 0x0300;
564 Palette
->palNumEntries
= VGA_MAX_COLORS
;
565 TextPalette
->palNumEntries
= VGA_AC_PAL_F_REG
+ 1;
567 /* Restore the default graphics palette */
568 VgaRestoreDefaultPalette(Palette
->palPalEntry
, Palette
->palNumEntries
);
570 /* Set the default text palette */
571 for (i
= 0; i
< TextPalette
->palNumEntries
; i
++)
573 /* Set the palette entries */
574 TextPalette
->palPalEntry
[i
].peRed
= GetRValue(ConsoleColors
[i
]);
575 TextPalette
->palPalEntry
[i
].peGreen
= GetGValue(ConsoleColors
[i
]);
576 TextPalette
->palPalEntry
[i
].peBlue
= GetBValue(ConsoleColors
[i
]);
577 TextPalette
->palPalEntry
[i
].peFlags
= 0;
580 /* Create the palettes */
581 PaletteHandle
= CreatePalette(Palette
);
582 TextPaletteHandle
= CreatePalette(TextPalette
);
584 if (PaletteHandle
!= NULL
&& TextPaletteHandle
!= NULL
)
586 /* The palettes have been created successfully */
591 /* Free the palettes */
592 if (Palette
) RtlFreeHeap(RtlGetProcessHeap(), 0, Palette
);
593 if (TextPalette
) RtlFreeHeap(RtlGetProcessHeap(), 0, TextPalette
);
597 /* Something failed, delete the palettes */
598 if (PaletteHandle
) DeleteObject(PaletteHandle
);
599 if (TextPaletteHandle
) DeleteObject(TextPaletteHandle
);
605 static VOID
VgaResetPalette(VOID
)
607 PALETTEENTRY Entries
[VGA_MAX_COLORS
];
609 /* Restore the default palette */
610 VgaRestoreDefaultPalette(Entries
, VGA_MAX_COLORS
);
611 SetPaletteEntries(PaletteHandle
, 0, VGA_MAX_COLORS
, Entries
);
612 PaletteChanged
= TRUE
;
615 static BOOL
VgaEnterNewMode(SCREEN_MODE NewScreenMode
, PCOORD Resolution
)
617 /* Check if the new mode is alphanumeric */
618 if (NewScreenMode
== TEXT_MODE
)
620 /* Enter new text mode */
622 if (!VgaConsoleCreateTextScreen(// &TextFramebuffer,
626 DisplayMessage(L
"An unexpected VGA error occurred while switching into text mode. Error: %u", GetLastError());
631 /* The active framebuffer is now the text framebuffer */
632 ActiveFramebuffer
= TextFramebuffer
;
634 /* Set the screen mode flag */
635 ScreenMode
= TEXT_MODE
;
641 /* Enter graphics mode */
643 if (!VgaConsoleCreateGraphicsScreen(// &GraphicsFramebuffer,
647 DisplayMessage(L
"An unexpected VGA error occurred while switching into graphics mode. Error: %u", GetLastError());
652 /* The active framebuffer is now the graphics framebuffer */
653 ActiveFramebuffer
= GraphicsFramebuffer
;
655 /* Set the screen mode flag */
656 ScreenMode
= GRAPHICS_MODE
;
662 static VOID
VgaLeaveCurrentMode(VOID
)
664 /* Leave the current video mode */
665 if (ScreenMode
== GRAPHICS_MODE
)
667 VgaConsoleDestroyGraphicsScreen();
669 /* Cleanup the video data */
670 GraphicsFramebuffer
= NULL
;
674 VgaConsoleDestroyTextScreen();
676 /* Cleanup the video data */
677 TextFramebuffer
= NULL
;
680 /* Reset the active framebuffer */
681 ActiveFramebuffer
= NULL
;
684 static VOID
VgaChangeMode(VOID
)
686 COORD NewResolution
= VgaGetDisplayResolution();
687 SCREEN_MODE NewScreenMode
=
688 !(VgaGcRegisters
[VGA_GC_MISC_REG
] & VGA_GC_MISC_NOALPHA
) ? TEXT_MODE
692 * Do not switch to a different screen mode + resolution if the new settings
693 * are the same as the old ones. Just repaint the full screen.
695 if ((ScreenMode
== NewScreenMode
) && // CurrResolution == NewResolution
696 (CurrResolution
.X
== NewResolution
.X
&& CurrResolution
.Y
== NewResolution
.Y
))
701 // FIXME: Wouldn't it be preferrable to switch to the new console SB
702 // *ONLY* if we succeeded in setting the new mode??
704 /* Leave the current video mode */
705 VgaLeaveCurrentMode(); // ScreenMode
707 /* Update the current resolution */
708 CurrResolution
= NewResolution
;
710 /* Change the screen mode */
711 if (!VgaEnterNewMode(NewScreenMode
, &CurrResolution
))
716 /* Trigger a full update of the screen */
718 UpdateRectangle
.Left
= 0;
719 UpdateRectangle
.Top
= 0;
720 UpdateRectangle
.Right
= CurrResolution
.X
;
721 UpdateRectangle
.Bottom
= CurrResolution
.Y
;
723 /* Reset the mode change flag */
727 static inline VOID
VgaMarkForUpdate(SHORT Row
, SHORT Column
)
729 /* Check if this is the first time the rectangle is updated */
732 UpdateRectangle
.Left
= UpdateRectangle
.Top
= MAXSHORT
;
733 UpdateRectangle
.Right
= UpdateRectangle
.Bottom
= MINSHORT
;
736 /* Expand the rectangle to include the point */
737 UpdateRectangle
.Left
= min(UpdateRectangle
.Left
, Column
);
738 UpdateRectangle
.Right
= max(UpdateRectangle
.Right
, Column
);
739 UpdateRectangle
.Top
= min(UpdateRectangle
.Top
, Row
);
740 UpdateRectangle
.Bottom
= max(UpdateRectangle
.Bottom
, Row
);
742 /* Set the update request flag */
746 static VOID
VgaUpdateFramebuffer(VOID
)
749 DWORD AddressSize
= VgaGetAddressSize();
750 DWORD ScanlineSize
= (DWORD
)VgaCrtcRegisters
[VGA_CRTC_OFFSET_REG
] * 2;
751 BYTE PresetRowScan
= VgaCrtcRegisters
[VGA_CRTC_PRESET_ROW_SCAN_REG
] & 0x1F;
752 BYTE BytePanning
= (VgaCrtcRegisters
[VGA_CRTC_PRESET_ROW_SCAN_REG
] >> 5) & 3;
753 DWORD Address
= MAKEWORD(VgaCrtcRegisters
[VGA_CRTC_START_ADDR_LOW_REG
],
754 VgaCrtcRegisters
[VGA_CRTC_START_ADDR_HIGH_REG
])
755 + PresetRowScan
* ScanlineSize
757 WORD LineCompare
= VgaCrtcRegisters
[VGA_CRTC_LINE_COMPARE_REG
]
758 | ((VgaCrtcRegisters
[VGA_CRTC_OVERFLOW_REG
] & VGA_CRTC_OVERFLOW_LC8
) << 4);
759 BYTE PixelShift
= VgaAcRegisters
[VGA_AC_HORZ_PANNING_REG
] & 0x0F;
762 * If the console framebuffer is NULL, that means something
763 * went wrong earlier and this is the final display refresh.
765 if (ActiveFramebuffer
== NULL
) return;
767 /* Check if we are in text or graphics mode */
768 if (ScreenMode
== GRAPHICS_MODE
)
771 PBYTE GraphicsBuffer
= (PBYTE
)ActiveFramebuffer
;
772 DWORD InterlaceHighBit
= VGA_INTERLACE_HIGH_BIT
;
776 * Synchronize access to the graphics framebuffer
777 * with the console framebuffer mutex.
779 WaitForSingleObject(ConsoleMutex
, INFINITE
);
781 /* Shift the high bit right by 1 in odd/even mode */
782 if (VgaGcRegisters
[VGA_GC_MODE_REG
] & VGA_GC_MODE_OE
)
784 InterlaceHighBit
>>= 1;
787 if (VgaCrtcRegisters
[VGA_CRTC_MAX_SCAN_LINE_REG
] & VGA_CRTC_MAXSCANLINE_DOUBLE
)
789 /* Halve the line compare value */
794 /* Divide the line compare value by the maximum scan line */
795 LineCompare
/= 1 + (VgaCrtcRegisters
[VGA_CRTC_MAX_SCAN_LINE_REG
] & 0x1F);
798 /* Loop through the scanlines */
799 for (i
= 0; i
< CurrResolution
.Y
; i
++)
801 if (i
== LineCompare
)
803 if (VgaAcRegisters
[VGA_AC_CONTROL_REG
] & VGA_AC_CONTROL_PPM
)
806 * Disable the pixel shift count and byte panning
807 * for the rest of the display cycle
813 /* Reset the address, but assume the preset row scan is 0 */
814 Address
= BytePanning
;
817 if ((VgaGcRegisters
[VGA_GC_MISC_REG
] & VGA_GC_MISC_OE
) && (i
& 1))
819 /* Odd-numbered line in interlaced mode - set the high bit */
820 Address
|= InterlaceHighBit
;
823 /* Loop through the pixels */
824 for (j
= 0; j
< CurrResolution
.X
; j
++)
828 /* Apply horizontal pixel panning */
829 if (VgaAcRegisters
[VGA_AC_CONTROL_REG
] & VGA_AC_CONTROL_8BIT
)
831 X
= j
+ (PixelShift
>> 1);
838 /* Check the shifting mode */
839 if (VgaGcRegisters
[VGA_GC_MODE_REG
] & VGA_GC_MODE_SHIFT256
)
841 /* 4 bits shifted from each plane */
843 /* Check if this is 16 or 256 color mode */
844 if (VgaAcRegisters
[VGA_AC_CONTROL_REG
] & VGA_AC_CONTROL_8BIT
)
846 /* One byte per pixel */
847 PixelData
= VgaMemory
[(X
% VGA_NUM_BANKS
) * VGA_BANK_SIZE
848 + LOWORD((Address
+ (X
/ VGA_NUM_BANKS
))
853 /* 4-bits per pixel */
855 PixelData
= VgaMemory
[(X
% VGA_NUM_BANKS
) * VGA_BANK_SIZE
856 + LOWORD((Address
+ (X
/ (VGA_NUM_BANKS
* 2)))
859 /* Check if we should use the highest 4 bits or lowest 4 */
860 if (((X
/ VGA_NUM_BANKS
) % 2) == 0)
872 else if (VgaGcRegisters
[VGA_GC_MODE_REG
] & VGA_GC_MODE_SHIFTREG
)
874 /* Check if this is 16 or 256 color mode */
875 if (VgaAcRegisters
[VGA_AC_CONTROL_REG
] & VGA_AC_CONTROL_8BIT
)
877 // TODO: NOT IMPLEMENTED
878 DPRINT1("8-bit interleaved mode is not implemented!\n");
883 * 2 bits shifted from plane 0 and 2 for the first 4 pixels,
884 * then 2 bits shifted from plane 1 and 3 for the next 4
886 DWORD BankNumber
= (X
/ 4) % 2;
887 DWORD Offset
= Address
+ (X
/ 8);
888 BYTE LowPlaneData
= VgaMemory
[BankNumber
* VGA_BANK_SIZE
+ LOWORD(Offset
* AddressSize
)];
889 BYTE HighPlaneData
= VgaMemory
[(BankNumber
+ 2) * VGA_BANK_SIZE
+ LOWORD(Offset
* AddressSize
)];
891 /* Extract the two bits from each plane */
892 LowPlaneData
= (LowPlaneData
>> (6 - ((X
% 4) * 2))) & 0x03;
893 HighPlaneData
= (HighPlaneData
>> (6 - ((X
% 4) * 2))) & 0x03;
895 /* Combine them into the pixel */
896 PixelData
= LowPlaneData
| (HighPlaneData
<< 2);
901 /* 1 bit shifted from each plane */
903 /* Check if this is 16 or 256 color mode */
904 if (VgaAcRegisters
[VGA_AC_CONTROL_REG
] & VGA_AC_CONTROL_8BIT
)
906 /* 8 bits per pixel, 2 on each plane */
908 for (k
= 0; k
< VGA_NUM_BANKS
; k
++)
910 /* The data is on plane k, 4 pixels per byte */
911 BYTE PlaneData
= VgaMemory
[k
* VGA_BANK_SIZE
912 + LOWORD((Address
+ (X
/ VGA_NUM_BANKS
))
915 /* The mask of the first bit in the pair */
916 BYTE BitMask
= 1 << (((3 - (X
% VGA_NUM_BANKS
)) * 2) + 1);
918 /* Bits 0, 1, 2 and 3 come from the first bit of the pair */
919 if (PlaneData
& BitMask
) PixelData
|= 1 << k
;
921 /* Bits 4, 5, 6 and 7 come from the second bit of the pair */
922 if (PlaneData
& (BitMask
>> 1)) PixelData
|= 1 << (k
+ 4);
927 /* 4 bits per pixel, 1 on each plane */
929 for (k
= 0; k
< VGA_NUM_BANKS
; k
++)
931 BYTE PlaneData
= VgaMemory
[k
* VGA_BANK_SIZE
932 + LOWORD((Address
+ (X
/ (VGA_NUM_BANKS
* 2)))
935 /* If the bit on that plane is set, set it */
936 if (PlaneData
& (1 << (7 - (X
% 8)))) PixelData
|= 1 << k
;
941 if (!(VgaAcRegisters
[VGA_AC_CONTROL_REG
] & VGA_AC_CONTROL_8BIT
))
944 * In 16 color mode, the value is an index to the AC registers
945 * if external palette access is disabled, otherwise (in case
946 * of palette loading) it is a blank pixel.
948 PixelData
= (VgaAcPalDisable
? VgaAcRegisters
[PixelData
& 0x0F]
952 /* Take into account DoubleVision mode when checking for pixel updates */
953 if (DoubleWidth
&& DoubleHeight
)
955 /* Now check if the resulting pixel data has changed */
956 if (GraphicsBuffer
[(i
* 2 * CurrResolution
.X
* 2) + (j
* 2)] != PixelData
)
958 /* Yes, write the new value */
959 GraphicsBuffer
[(i
* 2 * CurrResolution
.X
* 2) + (j
* 2)] = PixelData
;
960 GraphicsBuffer
[(i
* 2 * CurrResolution
.X
* 2) + (j
* 2 + 1)] = PixelData
;
961 GraphicsBuffer
[((i
* 2 + 1) * CurrResolution
.X
* 2) + (j
* 2)] = PixelData
;
962 GraphicsBuffer
[((i
* 2 + 1) * CurrResolution
.X
* 2) + (j
* 2 + 1)] = PixelData
;
964 /* Mark the specified pixel as changed */
965 VgaMarkForUpdate(i
, j
);
968 else if (DoubleWidth
&& !DoubleHeight
)
970 /* Now check if the resulting pixel data has changed */
971 if (GraphicsBuffer
[(i
* CurrResolution
.X
* 2) + (j
* 2)] != PixelData
)
973 /* Yes, write the new value */
974 GraphicsBuffer
[(i
* CurrResolution
.X
* 2) + (j
* 2)] = PixelData
;
975 GraphicsBuffer
[(i
* CurrResolution
.X
* 2) + (j
* 2 + 1)] = PixelData
;
977 /* Mark the specified pixel as changed */
978 VgaMarkForUpdate(i
, j
);
981 else if (!DoubleWidth
&& DoubleHeight
)
983 /* Now check if the resulting pixel data has changed */
984 if (GraphicsBuffer
[(i
* 2 * CurrResolution
.X
) + j
] != PixelData
)
986 /* Yes, write the new value */
987 GraphicsBuffer
[(i
* 2 * CurrResolution
.X
) + j
] = PixelData
;
988 GraphicsBuffer
[((i
* 2 + 1) * CurrResolution
.X
) + j
] = PixelData
;
990 /* Mark the specified pixel as changed */
991 VgaMarkForUpdate(i
, j
);
994 else // if (!DoubleWidth && !DoubleHeight)
996 /* Now check if the resulting pixel data has changed */
997 if (GraphicsBuffer
[i
* CurrResolution
.X
+ j
] != PixelData
)
999 /* Yes, write the new value */
1000 GraphicsBuffer
[i
* CurrResolution
.X
+ j
] = PixelData
;
1002 /* Mark the specified pixel as changed */
1003 VgaMarkForUpdate(i
, j
);
1008 if ((VgaGcRegisters
[VGA_GC_MISC_REG
] & VGA_GC_MISC_OE
) && (i
& 1))
1010 /* Clear the high bit */
1011 Address
&= ~InterlaceHighBit
;
1014 if (!(VgaGcRegisters
[VGA_GC_MISC_REG
] & VGA_GC_MISC_OE
) || (i
& 1))
1016 /* Move to the next scanline */
1017 Address
+= ScanlineSize
;
1022 * Release the console framebuffer mutex
1023 * so that we allow for repainting.
1025 ReleaseMutex(ConsoleMutex
);
1031 PCHAR_CELL CharBuffer
= (PCHAR_CELL
)ActiveFramebuffer
;
1035 * Technically, the horizontal panning and preset row count should
1036 * affect text mode too. However, it works on pixels and not characters,
1037 * so we can't support it currently.
1040 /* Loop through the scanlines */
1041 for (i
= 0; i
< CurrResolution
.Y
; i
++)
1043 /* Loop through the characters */
1044 for (j
= 0; j
< CurrResolution
.X
; j
++)
1046 CurrentAddr
= LOWORD((Address
+ j
) * AddressSize
);
1048 /* Plane 0 holds the character itself */
1049 CharInfo
.Char
= VgaMemory
[CurrentAddr
];
1051 /* Plane 1 holds the attribute */
1052 CharInfo
.Attributes
= VgaMemory
[CurrentAddr
+ VGA_BANK_SIZE
];
1054 /* Now check if the resulting character data has changed */
1055 if ((CharBuffer
[i
* CurrResolution
.X
+ j
].Char
!= CharInfo
.Char
) ||
1056 (CharBuffer
[i
* CurrResolution
.X
+ j
].Attributes
!= CharInfo
.Attributes
))
1058 /* Yes, write the new value */
1059 CharBuffer
[i
* CurrResolution
.X
+ j
] = CharInfo
;
1061 /* Mark the specified cell as changed */
1062 VgaMarkForUpdate(i
, j
);
1066 /* Move to the next scanline */
1067 Address
+= ScanlineSize
;
1072 static VOID
VgaUpdateTextCursor(VOID
)
1074 BOOL CursorVisible
= !(VgaCrtcRegisters
[VGA_CRTC_CURSOR_START_REG
] & 0x20);
1075 BYTE CursorStart
= VgaCrtcRegisters
[VGA_CRTC_CURSOR_START_REG
] & 0x1F;
1076 BYTE CursorEnd
= VgaCrtcRegisters
[VGA_CRTC_CURSOR_END_REG
] & 0x1F;
1078 DWORD ScanlineSize
= (DWORD
)VgaCrtcRegisters
[VGA_CRTC_OFFSET_REG
] * 2;
1079 BYTE TextSize
= 1 + (VgaCrtcRegisters
[VGA_CRTC_MAX_SCAN_LINE_REG
] & 0x1F);
1080 WORD Location
= MAKEWORD(VgaCrtcRegisters
[VGA_CRTC_CURSOR_LOC_LOW_REG
],
1081 VgaCrtcRegisters
[VGA_CRTC_CURSOR_LOC_HIGH_REG
]);
1083 /* Just return if we are not in text mode */
1084 if (ScreenMode
!= TEXT_MODE
) return;
1086 /* Add the cursor skew to the location */
1087 Location
+= (VgaCrtcRegisters
[VGA_CRTC_CURSOR_END_REG
] >> 5) & 0x03;
1089 VgaConsoleUpdateTextCursor(CursorVisible
, CursorStart
, CursorEnd
,
1090 TextSize
, ScanlineSize
, Location
);
1092 /* Reset the cursor changed flag */
1093 CursorChanged
= FALSE
;
1096 static BYTE WINAPI
VgaReadPort(USHORT Port
)
1098 DPRINT("VgaReadPort: Port 0x%X\n", Port
);
1100 if (Port
!= VGA_DAC_MASK
) SvgaHdrCounter
= 0;
1105 return VgaMiscRegister
;
1107 case VGA_INSTAT0_READ
:
1108 return 0; // Not implemented
1110 case VGA_INSTAT1_READ_MONO
:
1111 case VGA_INSTAT1_READ_COLOR
:
1114 BOOLEAN Vsync
, Hsync
;
1115 ULONGLONG Cycles
= GetCycleCount();
1116 ULONG CyclesPerMicrosecond
= (ULONG
)((GetCycleSpeed() + 500000ULL) / 1000000ULL);
1117 ULONG Dots
= (VgaSeqRegisters
[VGA_SEQ_CLOCK_REG
] & 1) ? 9 : 8;
1118 ULONG Clock
= VgaGetClockFrequency() / 1000000;
1119 ULONG HorizTotalDots
= ((ULONG
)VgaCrtcRegisters
[VGA_CRTC_HORZ_TOTAL_REG
] + 5) * Dots
;
1120 ULONG VblankStart
, VblankEnd
, HblankStart
, HblankEnd
;
1121 ULONG HblankDuration
, VblankDuration
;
1123 /* Calculate the vertical blanking duration in cycles */
1124 VblankStart
= VgaCrtcRegisters
[VGA_CRTC_START_VERT_BLANKING_REG
] & 0x7F;
1125 VblankEnd
= VgaCrtcRegisters
[VGA_CRTC_END_VERT_BLANKING_REG
] & 0x7F;
1126 if (VblankEnd
< VblankStart
) VblankEnd
|= 0x80;
1127 VblankDuration
= ((VblankEnd
- VblankStart
) * HorizTotalDots
1128 * CyclesPerMicrosecond
+ (Clock
>> 1)) / Clock
;
1130 /* Calculate the horizontal blanking duration in cycles */
1131 HblankStart
= VgaCrtcRegisters
[VGA_CRTC_START_HORZ_BLANKING_REG
] & 0x1F;
1132 HblankEnd
= VgaCrtcRegisters
[VGA_CRTC_END_HORZ_BLANKING_REG
] & 0x1F;
1133 if (HblankEnd
< HblankStart
) HblankEnd
|= 0x20;
1134 HblankDuration
= ((HblankEnd
- HblankStart
) * Dots
1135 * CyclesPerMicrosecond
+ (Clock
>> 1)) / Clock
;
1137 Vsync
= (Cycles
- VerticalRetraceCycle
) < (ULONGLONG
)VblankDuration
;
1138 Hsync
= (Cycles
- HorizontalRetraceCycle
) < (ULONGLONG
)HblankDuration
;
1140 /* Reset the AC latch */
1143 /* Reverse the polarity, if needed */
1144 if (VgaMiscRegister
& VGA_MISC_VSYNCP
) Vsync
= !Vsync
;
1145 if (VgaMiscRegister
& VGA_MISC_HSYNCP
) Hsync
= !Hsync
;
1147 /* Set a flag if there is a vertical or horizontal retrace */
1148 if (Vsync
|| Hsync
) Result
|= VGA_STAT_DD
;
1150 /* Set an additional flag if there was a vertical retrace */
1151 if (Vsync
) Result
|= VGA_STAT_VRETRACE
;
1156 case VGA_FEATURE_READ
:
1157 return VgaFeatureRegister
;
1163 return VgaAcRegisters
[VgaAcIndex
];
1169 return VgaSeqRegisters
[VgaSeqIndex
];
1173 if (SvgaHdrCounter
== 4)
1176 return SvgaHiddenRegister
;
1185 case VGA_DAC_READ_INDEX
:
1186 /* This returns the read/write state */
1187 return (VgaDacReadWrite
? 0 : 3);
1189 case VGA_DAC_WRITE_INDEX
:
1194 /* Ignore reads in write mode */
1195 if (!VgaDacReadWrite
)
1197 BYTE Data
= VgaDacRegisters
[VgaDacIndex
* 3 + VgaDacLatchCounter
];
1198 VgaDacLatchCounter
++;
1200 if (VgaDacLatchCounter
== 3)
1202 /* Reset the latch counter and increment the palette index */
1203 VgaDacLatchCounter
= 0;
1205 VgaDacIndex
%= VGA_MAX_COLORS
;
1214 case VGA_CRTC_INDEX_MONO
:
1215 case VGA_CRTC_INDEX_COLOR
:
1216 return VgaCrtcIndex
;
1218 case VGA_CRTC_DATA_MONO
:
1219 case VGA_CRTC_DATA_COLOR
:
1220 return VgaCrtcRegisters
[VgaCrtcIndex
];
1226 return VgaGcRegisters
[VgaGcIndex
];
1229 DPRINT1("VgaReadPort: Unknown port 0x%X\n", Port
);
1236 static inline VOID
VgaWriteSequencer(BYTE Data
)
1238 /* Save the value */
1239 VgaSeqRegisters
[VgaSeqIndex
& VGA_SEQ_INDEX_MASK
] = Data
;
1241 /* Check the index */
1242 switch (VgaSeqIndex
& VGA_SEQ_INDEX_MASK
)
1244 case SVGA_SEQ_UNLOCK_REG
:
1246 if ((Data
& SVGA_SEQ_UNLOCK_MASK
) == SVGA_SEQ_UNLOCKED
)
1248 /* Unlock SVGA extensions */
1249 VgaSeqRegisters
[SVGA_SEQ_UNLOCK_REG
] = SVGA_SEQ_UNLOCKED
;
1253 /* Lock SVGA extensions */
1254 VgaSeqRegisters
[SVGA_SEQ_UNLOCK_REG
] = SVGA_SEQ_LOCKED
;
1262 static inline VOID
VgaWriteGc(BYTE Data
)
1264 /* Save the value */
1265 VgaGcRegisters
[VgaGcIndex
& VGA_GC_INDEX_MASK
] = Data
;
1267 /* Check the index */
1268 switch (VgaGcIndex
& VGA_GC_INDEX_MASK
)
1270 case VGA_GC_MISC_REG
:
1272 /* Remove any existing VGA memory hook */
1273 MemRemoveFastMemoryHook((PVOID
)0xA0000, 0x20000);
1275 if (VgaMiscRegister
& VGA_MISC_RAM_ENABLED
)
1277 UCHAR MemoryMap
= (VgaGcRegisters
[VGA_GC_MISC_REG
] >> 2) & 0x03;
1279 /* Register a memory hook */
1280 MemInstallFastMemoryHook((PVOID
)MemoryBase
[MemoryMap
],
1281 MemorySize
[MemoryMap
],
1286 /* The GC misc register decides if it's text or graphics mode */
1293 static inline VOID
VgaWriteCrtc(BYTE Data
)
1295 /* Save the value */
1296 VgaCrtcRegisters
[VgaCrtcIndex
& VGA_CRTC_INDEX_MASK
] = Data
;
1298 /* Check the index */
1299 switch (VgaCrtcIndex
& VGA_CRTC_INDEX_MASK
)
1301 case VGA_CRTC_END_HORZ_DISP_REG
:
1302 case VGA_CRTC_VERT_DISP_END_REG
:
1303 case VGA_CRTC_OVERFLOW_REG
:
1304 case VGA_CRTC_MAX_SCAN_LINE_REG
:
1306 /* The video mode has changed */
1311 case VGA_CRTC_CURSOR_LOC_LOW_REG
:
1312 case VGA_CRTC_CURSOR_LOC_HIGH_REG
:
1313 case VGA_CRTC_CURSOR_START_REG
:
1314 case VGA_CRTC_CURSOR_END_REG
:
1316 /* Set the cursor changed flag */
1317 CursorChanged
= TRUE
;
1323 static inline VOID
VgaWriteDac(BYTE Data
)
1328 /* Store the value in the latch */
1329 VgaDacLatch
[VgaDacLatchCounter
++] = Data
;
1330 if (VgaDacLatchCounter
< 3) return;
1332 /* Reset the latch counter */
1333 VgaDacLatchCounter
= 0;
1335 /* Set the DAC register values */
1336 VgaDacRegisters
[VgaDacIndex
* 3] = VgaDacLatch
[0];
1337 VgaDacRegisters
[VgaDacIndex
* 3 + 1] = VgaDacLatch
[1];
1338 VgaDacRegisters
[VgaDacIndex
* 3 + 2] = VgaDacLatch
[2];
1340 /* Fill the entry structure */
1341 Entry
.peRed
= VGA_DAC_TO_COLOR(VgaDacLatch
[0]);
1342 Entry
.peGreen
= VGA_DAC_TO_COLOR(VgaDacLatch
[1]);
1343 Entry
.peBlue
= VGA_DAC_TO_COLOR(VgaDacLatch
[2]);
1346 /* Update the palette entry */
1347 SetPaletteEntries(PaletteHandle
, VgaDacIndex
, 1, &Entry
);
1349 /* Check which text palette entries are affected */
1350 for (i
= 0; i
<= VGA_AC_PAL_F_REG
; i
++)
1352 if (VgaAcRegisters
[i
] == VgaDacIndex
)
1354 /* Update the text palette entry */
1355 SetPaletteEntries(TextPaletteHandle
, i
, 1, &Entry
);
1359 /* Set the palette changed flag */
1360 PaletteChanged
= TRUE
;
1362 /* Update the index */
1364 VgaDacIndex
%= VGA_MAX_COLORS
;
1367 static inline VOID
VgaWriteAc(BYTE Data
)
1371 ASSERT(VgaAcIndex
< VGA_AC_MAX_REG
);
1373 /* Save the value */
1374 if (VgaAcIndex
<= VGA_AC_PAL_F_REG
)
1376 if (VgaAcPalDisable
) return;
1378 // DbgPrint(" AC Palette Writing %d to index %d\n", Data, VgaAcIndex);
1379 if (VgaAcRegisters
[VgaAcIndex
] != Data
)
1381 /* Update the AC register */
1382 VgaAcRegisters
[VgaAcIndex
] = Data
;
1384 /* Fill the entry structure */
1385 Entry
.peRed
= VGA_DAC_TO_COLOR(VgaDacRegisters
[Data
* 3]);
1386 Entry
.peGreen
= VGA_DAC_TO_COLOR(VgaDacRegisters
[Data
* 3 + 1]);
1387 Entry
.peBlue
= VGA_DAC_TO_COLOR(VgaDacRegisters
[Data
* 3 + 2]);
1390 /* Update the palette entry and set the palette change flag */
1391 SetPaletteEntries(TextPaletteHandle
, VgaAcIndex
, 1, &Entry
);
1392 PaletteChanged
= TRUE
;
1397 VgaAcRegisters
[VgaAcIndex
] = Data
;
1401 static VOID WINAPI
VgaWritePort(USHORT Port
, BYTE Data
)
1403 DPRINT("VgaWritePort: Port 0x%X, Data 0x%02X\n", Port
, Data
);
1407 case VGA_MISC_WRITE
:
1409 VgaMiscRegister
= Data
;
1411 if (VgaMiscRegister
& 0x01)
1413 /* Color emulation */
1414 DPRINT1("Color emulation\n");
1416 /* Register the new I/O Ports */
1417 RegisterIoPort(0x3D4, VgaReadPort
, VgaWritePort
); // VGA_CRTC_INDEX_COLOR
1418 RegisterIoPort(0x3D5, VgaReadPort
, VgaWritePort
); // VGA_CRTC_DATA_COLOR
1419 RegisterIoPort(0x3DA, VgaReadPort
, VgaWritePort
); // VGA_INSTAT1_READ_COLOR, VGA_FEATURE_WRITE_COLOR
1421 /* Unregister the old ones */
1422 UnregisterIoPort(0x3B4); // VGA_CRTC_INDEX_MONO
1423 UnregisterIoPort(0x3B5); // VGA_CRTC_DATA_MONO
1424 UnregisterIoPort(0x3BA); // VGA_INSTAT1_READ_MONO, VGA_FEATURE_WRITE_MONO
1428 /* Monochrome emulation */
1429 DPRINT1("Monochrome emulation\n");
1431 /* Register the new I/O Ports */
1432 RegisterIoPort(0x3B4, VgaReadPort
, VgaWritePort
); // VGA_CRTC_INDEX_MONO
1433 RegisterIoPort(0x3B5, VgaReadPort
, VgaWritePort
); // VGA_CRTC_DATA_MONO
1434 RegisterIoPort(0x3BA, VgaReadPort
, VgaWritePort
); // VGA_INSTAT1_READ_MONO, VGA_FEATURE_WRITE_MONO
1436 /* Unregister the old ones */
1437 UnregisterIoPort(0x3D4); // VGA_CRTC_INDEX_COLOR
1438 UnregisterIoPort(0x3D5); // VGA_CRTC_DATA_COLOR
1439 UnregisterIoPort(0x3DA); // VGA_INSTAT1_READ_COLOR, VGA_FEATURE_WRITE_COLOR
1442 /* Remove any existing VGA memory hook */
1443 MemRemoveFastMemoryHook((PVOID
)0xA0000, 0x20000);
1445 if (VgaMiscRegister
& VGA_MISC_RAM_ENABLED
)
1447 UCHAR MemoryMap
= (VgaGcRegisters
[VGA_GC_MISC_REG
] >> 2) & 0x03;
1449 /* Register a memory hook */
1450 MemInstallFastMemoryHook((PVOID
)MemoryBase
[MemoryMap
],
1451 MemorySize
[MemoryMap
],
1459 case VGA_FEATURE_WRITE_MONO
:
1460 case VGA_FEATURE_WRITE_COLOR
:
1462 VgaFeatureRegister
= Data
;
1467 // case VGA_AC_WRITE:
1471 /* Change the index */
1472 BYTE Index
= Data
& 0x1F;
1473 if (Index
< VGA_AC_MAX_REG
) VgaAcIndex
= Index
;
1476 * Change palette protection by checking for
1477 * the Palette Address Source bit.
1479 VgaAcPalDisable
= (Data
& 0x20) ? TRUE
: FALSE
;
1483 /* Write the data */
1487 /* Toggle the latch */
1488 VgaAcLatch
= !VgaAcLatch
;
1494 /* Set the sequencer index register */
1495 if ((Data
& 0x1F) < SVGA_SEQ_MAX_UNLOCKED_REG
1496 && (Data
& 0x1F) != VGA_SEQ_MAX_REG
)
1506 /* Call the sequencer function */
1507 VgaWriteSequencer(Data
);
1513 if (SvgaHdrCounter
== 4) SvgaHiddenRegister
= Data
;
1514 else VgaDacMask
= Data
;
1519 case VGA_DAC_READ_INDEX
:
1521 VgaDacReadWrite
= FALSE
;
1523 VgaDacLatchCounter
= 0;
1527 case VGA_DAC_WRITE_INDEX
:
1529 VgaDacReadWrite
= TRUE
;
1531 VgaDacLatchCounter
= 0;
1537 /* Ignore writes in read mode */
1538 if (VgaDacReadWrite
) VgaWriteDac(Data
& 0x3F);
1542 case VGA_CRTC_INDEX_MONO
:
1543 case VGA_CRTC_INDEX_COLOR
:
1545 /* Set the CRTC index register */
1546 if (((Data
& VGA_CRTC_INDEX_MASK
) < SVGA_CRTC_MAX_UNLOCKED_REG
)
1547 && ((Data
& VGA_CRTC_INDEX_MASK
) < SVGA_CRTC_UNUSED0_REG
1548 || (Data
& VGA_CRTC_INDEX_MASK
) > SVGA_CRTC_UNUSED6_REG
)
1549 && (Data
& VGA_CRTC_INDEX_MASK
) != SVGA_CRTC_UNUSED7_REG
)
1551 VgaCrtcIndex
= Data
;
1557 case VGA_CRTC_DATA_MONO
:
1558 case VGA_CRTC_DATA_COLOR
:
1560 /* Call the CRTC function */
1567 /* Set the GC index register */
1568 if ((Data
& VGA_GC_INDEX_MASK
) < SVGA_GC_MAX_UNLOCKED_REG
1569 && (Data
& VGA_GC_INDEX_MASK
) != SVGA_GC_UNUSED0_REG
1570 && ((Data
& VGA_GC_INDEX_MASK
) < SVGA_GC_UNUSED1_REG
1571 || (Data
& VGA_GC_INDEX_MASK
) > SVGA_GC_UNUSED10_REG
))
1581 /* Call the GC function */
1587 DPRINT1("VgaWritePort: Unknown port 0x%X, Data 0x%02X\n", Port
, Data
);
1594 static VOID FASTCALL
VgaVerticalRetrace(ULONGLONG ElapsedTime
)
1596 UNREFERENCED_PARAMETER(ElapsedTime
);
1598 /* Set the vertical retrace cycle */
1599 VerticalRetraceCycle
= GetCycleCount();
1601 /* If nothing has changed, just return */
1602 // if (!ModeChanged && !CursorChanged && !PaletteChanged && !NeedsUpdate)
1605 /* Change the display mode */
1606 if (ModeChanged
) VgaChangeMode();
1608 /* Change the text cursor appearance */
1609 if (CursorChanged
) VgaUpdateTextCursor();
1613 /* Trigger a full update of the screen */
1615 UpdateRectangle
.Left
= 0;
1616 UpdateRectangle
.Top
= 0;
1617 UpdateRectangle
.Right
= CurrResolution
.X
;
1618 UpdateRectangle
.Bottom
= CurrResolution
.Y
;
1620 PaletteChanged
= FALSE
;
1623 /* Update the contents of the framebuffer */
1624 VgaUpdateFramebuffer();
1626 /* Ignore if there's nothing to update */
1627 if (!NeedsUpdate
) return;
1629 DPRINT("Updating screen rectangle (%d, %d, %d, %d)\n",
1630 UpdateRectangle
.Left
,
1631 UpdateRectangle
.Top
,
1632 UpdateRectangle
.Right
,
1633 UpdateRectangle
.Bottom
);
1635 VgaConsoleRepaintScreen(&UpdateRectangle
);
1637 /* Clear the update flag */
1638 NeedsUpdate
= FALSE
;
1641 static VOID FASTCALL
VgaHorizontalRetrace(ULONGLONG ElapsedTime
)
1643 UNREFERENCED_PARAMETER(ElapsedTime
);
1646 HorizontalRetraceCycle
= GetCycleCount();
1649 /* PUBLIC FUNCTIONS ***********************************************************/
1651 COORD
VgaGetDisplayResolution(VOID
)
1654 BYTE MaximumScanLine
= 1 + (VgaCrtcRegisters
[VGA_CRTC_MAX_SCAN_LINE_REG
] & 0x1F);
1656 /* The low 8 bits are in the display registers */
1657 Resolution
.X
= VgaCrtcRegisters
[VGA_CRTC_END_HORZ_DISP_REG
];
1658 Resolution
.Y
= VgaCrtcRegisters
[VGA_CRTC_VERT_DISP_END_REG
];
1660 /* Set the top bits from the overflow register */
1661 if (VgaCrtcRegisters
[VGA_CRTC_OVERFLOW_REG
] & VGA_CRTC_OVERFLOW_VDE8
)
1663 Resolution
.Y
|= 1 << 8;
1665 if (VgaCrtcRegisters
[VGA_CRTC_OVERFLOW_REG
] & VGA_CRTC_OVERFLOW_VDE9
)
1667 Resolution
.Y
|= 1 << 9;
1670 /* Increase the values by 1 */
1674 if (VgaGcRegisters
[VGA_GC_MISC_REG
] & VGA_GC_MISC_NOALPHA
)
1676 /* Multiply the horizontal resolution by the 9/8 dot mode */
1677 Resolution
.X
*= (VgaSeqRegisters
[VGA_SEQ_CLOCK_REG
] & VGA_SEQ_CLOCK_98DM
)
1680 /* The horizontal resolution is halved in 8-bit mode */
1681 if (VgaAcRegisters
[VGA_AC_CONTROL_REG
] & VGA_AC_CONTROL_8BIT
) Resolution
.X
/= 2;
1684 if (VgaCrtcRegisters
[VGA_CRTC_MAX_SCAN_LINE_REG
] & VGA_CRTC_MAXSCANLINE_DOUBLE
)
1686 /* Halve the vertical resolution */
1691 /* Divide the vertical resolution by the maximum scan line (== font size in text mode) */
1692 Resolution
.Y
/= MaximumScanLine
;
1695 /* Return the resolution */
1699 VOID
VgaRefreshDisplay(VOID
)
1701 VgaVerticalRetrace(0);
1704 VOID FASTCALL
VgaReadMemory(ULONG Address
, PVOID Buffer
, ULONG Size
)
1708 PUCHAR BufPtr
= (PUCHAR
)Buffer
;
1710 DPRINT("VgaReadMemory: Address 0x%08X, Size %lu\n", Address
, Size
);
1712 /* Ignore if video RAM access is disabled */
1713 if ((VgaMiscRegister
& VGA_MISC_RAM_ENABLED
) == 0) return;
1715 if (!(VgaGcRegisters
[VGA_GC_MODE_REG
] & VGA_GC_MODE_READ
))
1717 /* Loop through each byte */
1718 for (i
= 0; i
< Size
; i
++)
1720 VideoAddress
= VgaTranslateReadAddress(Address
+ i
);
1722 /* Copy the value to the buffer */
1723 BufPtr
[i
] = VgaMemory
[VideoAddress
];
1728 /* Loop through each byte */
1729 for (i
= 0; i
< Size
; i
++)
1733 /* This should always return a plane 0 address for read mode 1 */
1734 VideoAddress
= VgaTranslateReadAddress(Address
+ i
);
1736 for (j
= 0; j
< VGA_NUM_BANKS
; j
++)
1738 /* Don't consider ignored banks */
1739 if (!(VgaGcRegisters
[VGA_GC_COLOR_IGNORE_REG
] & (1 << j
))) continue;
1741 if (VgaGcRegisters
[VGA_GC_COLOR_COMPARE_REG
] & (1 << j
))
1743 /* Comparing with 11111111 */
1744 Result
&= VgaMemory
[j
* VGA_BANK_SIZE
+ LOWORD(VideoAddress
)];
1748 /* Comparing with 00000000 */
1749 Result
&= ~(VgaMemory
[j
* VGA_BANK_SIZE
+ LOWORD(VideoAddress
)]);
1753 /* Copy the value to the buffer */
1758 /* Load the latch registers */
1759 VgaLatchRegisters
[0] = VgaMemory
[LOWORD(VideoAddress
)];
1760 VgaLatchRegisters
[1] = VgaMemory
[VGA_BANK_SIZE
+ LOWORD(VideoAddress
)];
1761 VgaLatchRegisters
[2] = VgaMemory
[(2 * VGA_BANK_SIZE
) + LOWORD(VideoAddress
)];
1762 VgaLatchRegisters
[3] = VgaMemory
[(3 * VGA_BANK_SIZE
) + LOWORD(VideoAddress
)];
1765 BOOLEAN FASTCALL
VgaWriteMemory(ULONG Address
, PVOID Buffer
, ULONG Size
)
1769 PUCHAR BufPtr
= (PUCHAR
)Buffer
;
1771 DPRINT("VgaWriteMemory: Address 0x%08X, Size %lu\n", Address
, Size
);
1773 /* Ignore if video RAM access is disabled */
1774 if ((VgaMiscRegister
& VGA_MISC_RAM_ENABLED
) == 0) return TRUE
;
1776 /* Also ignore if write access to all planes is disabled */
1777 if ((VgaSeqRegisters
[VGA_SEQ_MASK_REG
] & 0x0F) == 0x00) return TRUE
;
1779 /* Loop through each byte */
1780 for (i
= 0; i
< Size
; i
++)
1782 VideoAddress
= VgaTranslateWriteAddress(Address
+ i
);
1784 for (j
= 0; j
< VGA_NUM_BANKS
; j
++)
1786 /* Make sure the page is writeable */
1787 if (!(VgaSeqRegisters
[VGA_SEQ_MASK_REG
] & (1 << j
))) continue;
1789 /* Check if this is chain-4 mode */
1790 if (VgaSeqRegisters
[VGA_SEQ_MEM_REG
] & VGA_SEQ_MEM_C4
)
1792 if (((Address
+ i
) & 0x03) != j
)
1794 /* This plane will not be accessed */
1799 /* Check if this is odd-even mode */
1800 if (VgaGcRegisters
[VGA_GC_MODE_REG
] & VGA_GC_MODE_OE
)
1802 if (((Address
+ i
) & 0x01) != (j
& 1))
1804 /* This plane will not be accessed */
1809 /* Copy the value to the VGA memory */
1810 VgaMemory
[VideoAddress
+ j
* VGA_BANK_SIZE
] = VgaTranslateByteForWriting(BufPtr
[i
], j
);
1817 VOID
VgaClearMemory(VOID
)
1819 RtlZeroMemory(VgaMemory
, sizeof(VgaMemory
));
1822 VOID
VgaWriteTextModeFont(UINT FontNumber
, CONST UCHAR
* FontData
, UINT Height
)
1825 PUCHAR FontMemory
= (PUCHAR
)&VgaMemory
[VGA_BANK_SIZE
* VGA_FONT_BANK
+ (FontNumber
* VGA_FONT_SIZE
)];
1827 ASSERT(Height
<= VGA_MAX_FONT_HEIGHT
);
1829 for (i
= 0 ; i
< VGA_FONT_CHARACTERS
; i
++)
1831 /* Write the character */
1832 for (j
= 0; j
< Height
; j
++)
1834 FontMemory
[i
* VGA_MAX_FONT_HEIGHT
+ j
] = FontData
[i
* Height
+ j
];
1837 /* Clear the unused part */
1838 for (j
= Height
; j
< VGA_MAX_FONT_HEIGHT
; j
++)
1840 FontMemory
[i
* VGA_MAX_FONT_HEIGHT
+ j
] = 0;
1845 BOOLEAN
VgaInitialize(HANDLE TextHandle
)
1847 if (!VgaConsoleInitialize(TextHandle
)) return FALSE
;
1849 /* Clear the SEQ, GC, CRTC and AC registers */
1850 RtlZeroMemory(VgaSeqRegisters
, sizeof(VgaSeqRegisters
));
1851 RtlZeroMemory(VgaGcRegisters
, sizeof(VgaGcRegisters
));
1852 RtlZeroMemory(VgaCrtcRegisters
, sizeof(VgaCrtcRegisters
));
1853 RtlZeroMemory(VgaAcRegisters
, sizeof(VgaAcRegisters
));
1855 /* Initialize the VGA palette and fail if it isn't successfully created */
1856 if (!VgaInitializePalette()) return FALSE
;
1857 /***/ VgaResetPalette(); /***/
1859 /* Reset the sequencer */
1860 VgaResetSequencer();
1862 /* Clear the VGA memory */
1865 /* Register the I/O Ports */
1866 RegisterIoPort(0x3CC, VgaReadPort
, NULL
); // VGA_MISC_READ
1867 RegisterIoPort(0x3C2, VgaReadPort
, VgaWritePort
); // VGA_MISC_WRITE, VGA_INSTAT0_READ
1868 RegisterIoPort(0x3CA, VgaReadPort
, NULL
); // VGA_FEATURE_READ
1869 RegisterIoPort(0x3C0, VgaReadPort
, VgaWritePort
); // VGA_AC_INDEX, VGA_AC_WRITE
1870 RegisterIoPort(0x3C1, VgaReadPort
, NULL
); // VGA_AC_READ
1871 RegisterIoPort(0x3C4, VgaReadPort
, VgaWritePort
); // VGA_SEQ_INDEX
1872 RegisterIoPort(0x3C5, VgaReadPort
, VgaWritePort
); // VGA_SEQ_DATA
1873 RegisterIoPort(0x3C6, VgaReadPort
, VgaWritePort
); // VGA_DAC_MASK
1874 RegisterIoPort(0x3C7, VgaReadPort
, VgaWritePort
); // VGA_DAC_READ_INDEX
1875 RegisterIoPort(0x3C8, VgaReadPort
, VgaWritePort
); // VGA_DAC_WRITE_INDEX
1876 RegisterIoPort(0x3C9, VgaReadPort
, VgaWritePort
); // VGA_DAC_DATA
1877 RegisterIoPort(0x3CE, VgaReadPort
, VgaWritePort
); // VGA_GC_INDEX
1878 RegisterIoPort(0x3CF, VgaReadPort
, VgaWritePort
); // VGA_GC_DATA
1880 /* CGA ports for compatibility, unimplemented */
1881 RegisterIoPort(0x3D8, VgaReadPort
, VgaWritePort
); // CGA_MODE_CTRL_REG
1882 RegisterIoPort(0x3D9, VgaReadPort
, VgaWritePort
); // CGA_PAL_CTRL_REG
1884 HSyncTimer
= CreateHardwareTimer(HARDWARE_TIMER_ENABLED
, HZ_TO_NS(31469), VgaHorizontalRetrace
);
1885 VSyncTimer
= CreateHardwareTimer(HARDWARE_TIMER_ENABLED
, HZ_TO_NS(60), VgaVerticalRetrace
);
1887 /* Return success */
1891 VOID
VgaCleanup(VOID
)
1893 /* Do a final display refresh */
1894 VgaRefreshDisplay();
1896 DestroyHardwareTimer(VSyncTimer
);
1897 DestroyHardwareTimer(HSyncTimer
);
1899 /* Leave the current video mode */
1900 VgaLeaveCurrentMode(); // ScreenMode
1902 MemRemoveFastMemoryHook((PVOID
)0xA0000, 0x20000);
1904 VgaConsoleCleanup();