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;
678 // NEVER SET the ALWAYS-SET TextFramebuffer pointer to NULL!!
681 /* Reset the active framebuffer */
682 ActiveFramebuffer
= NULL
;
685 static VOID
VgaChangeMode(VOID
)
687 COORD NewResolution
= VgaGetDisplayResolution();
688 SCREEN_MODE NewScreenMode
=
689 !(VgaGcRegisters
[VGA_GC_MISC_REG
] & VGA_GC_MISC_NOALPHA
) ? TEXT_MODE
693 * Do not switch to a different screen mode + resolution if the new settings
694 * are the same as the old ones. Just repaint the full screen.
696 if ((ScreenMode
== NewScreenMode
) && // CurrResolution == NewResolution
697 (CurrResolution
.X
== NewResolution
.X
&& CurrResolution
.Y
== NewResolution
.Y
))
702 // FIXME: Wouldn't it be preferrable to switch to the new console SB
703 // *ONLY* if we succeeded in setting the new mode??
705 /* Leave the current video mode */
706 VgaLeaveCurrentMode(); // ScreenMode
708 /* Update the current resolution */
709 CurrResolution
= NewResolution
;
711 /* Change the screen mode */
712 if (!VgaEnterNewMode(NewScreenMode
, &CurrResolution
))
717 /* Trigger a full update of the screen */
719 UpdateRectangle
.Left
= 0;
720 UpdateRectangle
.Top
= 0;
721 UpdateRectangle
.Right
= CurrResolution
.X
;
722 UpdateRectangle
.Bottom
= CurrResolution
.Y
;
724 /* Reset the mode change flag */
728 static inline VOID
VgaMarkForUpdate(SHORT Row
, SHORT Column
)
730 /* Check if this is the first time the rectangle is updated */
733 UpdateRectangle
.Left
= UpdateRectangle
.Top
= MAXSHORT
;
734 UpdateRectangle
.Right
= UpdateRectangle
.Bottom
= MINSHORT
;
737 /* Expand the rectangle to include the point */
738 UpdateRectangle
.Left
= min(UpdateRectangle
.Left
, Column
);
739 UpdateRectangle
.Right
= max(UpdateRectangle
.Right
, Column
);
740 UpdateRectangle
.Top
= min(UpdateRectangle
.Top
, Row
);
741 UpdateRectangle
.Bottom
= max(UpdateRectangle
.Bottom
, Row
);
743 /* Set the update request flag */
747 static VOID
VgaUpdateFramebuffer(VOID
)
750 DWORD AddressSize
= VgaGetAddressSize();
751 DWORD ScanlineSize
= (DWORD
)VgaCrtcRegisters
[VGA_CRTC_OFFSET_REG
] * 2;
752 BYTE PresetRowScan
= VgaCrtcRegisters
[VGA_CRTC_PRESET_ROW_SCAN_REG
] & 0x1F;
753 BYTE BytePanning
= (VgaCrtcRegisters
[VGA_CRTC_PRESET_ROW_SCAN_REG
] >> 5) & 3;
754 DWORD Address
= MAKEWORD(VgaCrtcRegisters
[VGA_CRTC_START_ADDR_LOW_REG
],
755 VgaCrtcRegisters
[VGA_CRTC_START_ADDR_HIGH_REG
])
756 + PresetRowScan
* ScanlineSize
758 WORD LineCompare
= VgaCrtcRegisters
[VGA_CRTC_LINE_COMPARE_REG
]
759 | ((VgaCrtcRegisters
[VGA_CRTC_OVERFLOW_REG
] & VGA_CRTC_OVERFLOW_LC8
) << 4);
760 BYTE PixelShift
= VgaAcRegisters
[VGA_AC_HORZ_PANNING_REG
] & 0x0F;
763 * If the console framebuffer is NULL, that means something
764 * went wrong earlier and this is the final display refresh.
766 if (ActiveFramebuffer
== NULL
) return;
768 /* Check if we are in text or graphics mode */
769 if (ScreenMode
== GRAPHICS_MODE
)
772 PBYTE GraphicsBuffer
= (PBYTE
)ActiveFramebuffer
;
773 DWORD InterlaceHighBit
= VGA_INTERLACE_HIGH_BIT
;
777 * Synchronize access to the graphics framebuffer
778 * with the console framebuffer mutex.
780 WaitForSingleObject(ConsoleMutex
, INFINITE
);
782 /* Shift the high bit right by 1 in odd/even mode */
783 if (VgaGcRegisters
[VGA_GC_MODE_REG
] & VGA_GC_MODE_OE
)
785 InterlaceHighBit
>>= 1;
788 if (VgaCrtcRegisters
[VGA_CRTC_MAX_SCAN_LINE_REG
] & VGA_CRTC_MAXSCANLINE_DOUBLE
)
790 /* Halve the line compare value */
795 /* Divide the line compare value by the maximum scan line */
796 LineCompare
/= 1 + (VgaCrtcRegisters
[VGA_CRTC_MAX_SCAN_LINE_REG
] & 0x1F);
799 /* Loop through the scanlines */
800 for (i
= 0; i
< CurrResolution
.Y
; i
++)
802 if (i
== LineCompare
)
804 if (VgaAcRegisters
[VGA_AC_CONTROL_REG
] & VGA_AC_CONTROL_PPM
)
807 * Disable the pixel shift count and byte panning
808 * for the rest of the display cycle
814 /* Reset the address, but assume the preset row scan is 0 */
815 Address
= BytePanning
;
818 if ((VgaGcRegisters
[VGA_GC_MISC_REG
] & VGA_GC_MISC_OE
) && (i
& 1))
820 /* Odd-numbered line in interlaced mode - set the high bit */
821 Address
|= InterlaceHighBit
;
824 /* Loop through the pixels */
825 for (j
= 0; j
< CurrResolution
.X
; j
++)
829 /* Apply horizontal pixel panning */
830 if (VgaAcRegisters
[VGA_AC_CONTROL_REG
] & VGA_AC_CONTROL_8BIT
)
832 X
= j
+ (PixelShift
>> 1);
839 /* Check the shifting mode */
840 if (VgaGcRegisters
[VGA_GC_MODE_REG
] & VGA_GC_MODE_SHIFT256
)
842 /* 4 bits shifted from each plane */
844 /* Check if this is 16 or 256 color mode */
845 if (VgaAcRegisters
[VGA_AC_CONTROL_REG
] & VGA_AC_CONTROL_8BIT
)
847 /* One byte per pixel */
848 PixelData
= VgaMemory
[(X
% VGA_NUM_BANKS
) * VGA_BANK_SIZE
849 + LOWORD((Address
+ (X
/ VGA_NUM_BANKS
))
854 /* 4-bits per pixel */
856 PixelData
= VgaMemory
[(X
% VGA_NUM_BANKS
) * VGA_BANK_SIZE
857 + LOWORD((Address
+ (X
/ (VGA_NUM_BANKS
* 2)))
860 /* Check if we should use the highest 4 bits or lowest 4 */
861 if (((X
/ VGA_NUM_BANKS
) % 2) == 0)
873 else if (VgaGcRegisters
[VGA_GC_MODE_REG
] & VGA_GC_MODE_SHIFTREG
)
875 /* Check if this is 16 or 256 color mode */
876 if (VgaAcRegisters
[VGA_AC_CONTROL_REG
] & VGA_AC_CONTROL_8BIT
)
878 // TODO: NOT IMPLEMENTED
879 DPRINT1("8-bit interleaved mode is not implemented!\n");
884 * 2 bits shifted from plane 0 and 2 for the first 4 pixels,
885 * then 2 bits shifted from plane 1 and 3 for the next 4
887 DWORD BankNumber
= (X
/ 4) % 2;
888 DWORD Offset
= Address
+ (X
/ 8);
889 BYTE LowPlaneData
= VgaMemory
[BankNumber
* VGA_BANK_SIZE
+ LOWORD(Offset
* AddressSize
)];
890 BYTE HighPlaneData
= VgaMemory
[(BankNumber
+ 2) * VGA_BANK_SIZE
+ LOWORD(Offset
* AddressSize
)];
892 /* Extract the two bits from each plane */
893 LowPlaneData
= (LowPlaneData
>> (6 - ((X
% 4) * 2))) & 0x03;
894 HighPlaneData
= (HighPlaneData
>> (6 - ((X
% 4) * 2))) & 0x03;
896 /* Combine them into the pixel */
897 PixelData
= LowPlaneData
| (HighPlaneData
<< 2);
902 /* 1 bit shifted from each plane */
904 /* Check if this is 16 or 256 color mode */
905 if (VgaAcRegisters
[VGA_AC_CONTROL_REG
] & VGA_AC_CONTROL_8BIT
)
907 /* 8 bits per pixel, 2 on each plane */
909 for (k
= 0; k
< VGA_NUM_BANKS
; k
++)
911 /* The data is on plane k, 4 pixels per byte */
912 BYTE PlaneData
= VgaMemory
[k
* VGA_BANK_SIZE
913 + LOWORD((Address
+ (X
/ VGA_NUM_BANKS
))
916 /* The mask of the first bit in the pair */
917 BYTE BitMask
= 1 << (((3 - (X
% VGA_NUM_BANKS
)) * 2) + 1);
919 /* Bits 0, 1, 2 and 3 come from the first bit of the pair */
920 if (PlaneData
& BitMask
) PixelData
|= 1 << k
;
922 /* Bits 4, 5, 6 and 7 come from the second bit of the pair */
923 if (PlaneData
& (BitMask
>> 1)) PixelData
|= 1 << (k
+ 4);
928 /* 4 bits per pixel, 1 on each plane */
930 for (k
= 0; k
< VGA_NUM_BANKS
; k
++)
932 BYTE PlaneData
= VgaMemory
[k
* VGA_BANK_SIZE
933 + LOWORD((Address
+ (X
/ (VGA_NUM_BANKS
* 2)))
936 /* If the bit on that plane is set, set it */
937 if (PlaneData
& (1 << (7 - (X
% 8)))) PixelData
|= 1 << k
;
942 if (!(VgaAcRegisters
[VGA_AC_CONTROL_REG
] & VGA_AC_CONTROL_8BIT
))
945 * In 16 color mode, the value is an index to the AC registers
946 * if external palette access is disabled, otherwise (in case
947 * of palette loading) it is a blank pixel.
949 PixelData
= (VgaAcPalDisable
? VgaAcRegisters
[PixelData
& 0x0F]
953 /* Take into account DoubleVision mode when checking for pixel updates */
954 if (DoubleWidth
&& DoubleHeight
)
956 /* Now check if the resulting pixel data has changed */
957 if (GraphicsBuffer
[(i
* 2 * CurrResolution
.X
* 2) + (j
* 2)] != PixelData
)
959 /* Yes, write the new value */
960 GraphicsBuffer
[(i
* 2 * CurrResolution
.X
* 2) + (j
* 2)] = PixelData
;
961 GraphicsBuffer
[(i
* 2 * CurrResolution
.X
* 2) + (j
* 2 + 1)] = PixelData
;
962 GraphicsBuffer
[((i
* 2 + 1) * CurrResolution
.X
* 2) + (j
* 2)] = PixelData
;
963 GraphicsBuffer
[((i
* 2 + 1) * CurrResolution
.X
* 2) + (j
* 2 + 1)] = PixelData
;
965 /* Mark the specified pixel as changed */
966 VgaMarkForUpdate(i
, j
);
969 else if (DoubleWidth
&& !DoubleHeight
)
971 /* Now check if the resulting pixel data has changed */
972 if (GraphicsBuffer
[(i
* CurrResolution
.X
* 2) + (j
* 2)] != PixelData
)
974 /* Yes, write the new value */
975 GraphicsBuffer
[(i
* CurrResolution
.X
* 2) + (j
* 2)] = PixelData
;
976 GraphicsBuffer
[(i
* CurrResolution
.X
* 2) + (j
* 2 + 1)] = PixelData
;
978 /* Mark the specified pixel as changed */
979 VgaMarkForUpdate(i
, j
);
982 else if (!DoubleWidth
&& DoubleHeight
)
984 /* Now check if the resulting pixel data has changed */
985 if (GraphicsBuffer
[(i
* 2 * CurrResolution
.X
) + j
] != PixelData
)
987 /* Yes, write the new value */
988 GraphicsBuffer
[(i
* 2 * CurrResolution
.X
) + j
] = PixelData
;
989 GraphicsBuffer
[((i
* 2 + 1) * CurrResolution
.X
) + j
] = PixelData
;
991 /* Mark the specified pixel as changed */
992 VgaMarkForUpdate(i
, j
);
995 else // if (!DoubleWidth && !DoubleHeight)
997 /* Now check if the resulting pixel data has changed */
998 if (GraphicsBuffer
[i
* CurrResolution
.X
+ j
] != PixelData
)
1000 /* Yes, write the new value */
1001 GraphicsBuffer
[i
* CurrResolution
.X
+ j
] = PixelData
;
1003 /* Mark the specified pixel as changed */
1004 VgaMarkForUpdate(i
, j
);
1009 if ((VgaGcRegisters
[VGA_GC_MISC_REG
] & VGA_GC_MISC_OE
) && (i
& 1))
1011 /* Clear the high bit */
1012 Address
&= ~InterlaceHighBit
;
1015 if (!(VgaGcRegisters
[VGA_GC_MISC_REG
] & VGA_GC_MISC_OE
) || (i
& 1))
1017 /* Move to the next scanline */
1018 Address
+= ScanlineSize
;
1023 * Release the console framebuffer mutex
1024 * so that we allow for repainting.
1026 ReleaseMutex(ConsoleMutex
);
1032 PCHAR_CELL CharBuffer
= (PCHAR_CELL
)ActiveFramebuffer
;
1036 * Technically, the horizontal panning and preset row count should
1037 * affect text mode too. However, it works on pixels and not characters,
1038 * so we can't support it currently.
1041 /* Loop through the scanlines */
1042 for (i
= 0; i
< CurrResolution
.Y
; i
++)
1044 /* Loop through the characters */
1045 for (j
= 0; j
< CurrResolution
.X
; j
++)
1047 CurrentAddr
= LOWORD((Address
+ j
) * AddressSize
);
1049 /* Plane 0 holds the character itself */
1050 CharInfo
.Char
= VgaMemory
[CurrentAddr
];
1052 /* Plane 1 holds the attribute */
1053 CharInfo
.Attributes
= VgaMemory
[CurrentAddr
+ VGA_BANK_SIZE
];
1055 /* Now check if the resulting character data has changed */
1056 if ((CharBuffer
[i
* CurrResolution
.X
+ j
].Char
!= CharInfo
.Char
) ||
1057 (CharBuffer
[i
* CurrResolution
.X
+ j
].Attributes
!= CharInfo
.Attributes
))
1059 /* Yes, write the new value */
1060 CharBuffer
[i
* CurrResolution
.X
+ j
] = CharInfo
;
1062 /* Mark the specified cell as changed */
1063 VgaMarkForUpdate(i
, j
);
1067 /* Move to the next scanline */
1068 Address
+= ScanlineSize
;
1073 static VOID
VgaUpdateTextCursor(VOID
)
1075 BOOL CursorVisible
= !(VgaCrtcRegisters
[VGA_CRTC_CURSOR_START_REG
] & 0x20);
1076 BYTE CursorStart
= VgaCrtcRegisters
[VGA_CRTC_CURSOR_START_REG
] & 0x1F;
1077 BYTE CursorEnd
= VgaCrtcRegisters
[VGA_CRTC_CURSOR_END_REG
] & 0x1F;
1079 DWORD ScanlineSize
= (DWORD
)VgaCrtcRegisters
[VGA_CRTC_OFFSET_REG
] * 2;
1080 BYTE TextSize
= 1 + (VgaCrtcRegisters
[VGA_CRTC_MAX_SCAN_LINE_REG
] & 0x1F);
1081 WORD Location
= MAKEWORD(VgaCrtcRegisters
[VGA_CRTC_CURSOR_LOC_LOW_REG
],
1082 VgaCrtcRegisters
[VGA_CRTC_CURSOR_LOC_HIGH_REG
]);
1084 /* Just return if we are not in text mode */
1085 if (ScreenMode
!= TEXT_MODE
) return;
1087 /* Add the cursor skew to the location */
1088 Location
+= (VgaCrtcRegisters
[VGA_CRTC_CURSOR_END_REG
] >> 5) & 0x03;
1090 VgaConsoleUpdateTextCursor(CursorVisible
, CursorStart
, CursorEnd
,
1091 TextSize
, ScanlineSize
, Location
);
1093 /* Reset the cursor changed flag */
1094 CursorChanged
= FALSE
;
1097 static BYTE WINAPI
VgaReadPort(USHORT Port
)
1099 DPRINT("VgaReadPort: Port 0x%X\n", Port
);
1101 if (Port
!= VGA_DAC_MASK
) SvgaHdrCounter
= 0;
1106 return VgaMiscRegister
;
1108 case VGA_INSTAT0_READ
:
1109 return 0; // Not implemented
1111 case VGA_INSTAT1_READ_MONO
:
1112 case VGA_INSTAT1_READ_COLOR
:
1115 BOOLEAN Vsync
, Hsync
;
1116 ULONGLONG Cycles
= GetCycleCount();
1117 ULONG CyclesPerMicrosecond
= (ULONG
)((GetCycleSpeed() + 500000ULL) / 1000000ULL);
1118 ULONG Dots
= (VgaSeqRegisters
[VGA_SEQ_CLOCK_REG
] & 1) ? 9 : 8;
1119 ULONG Clock
= VgaGetClockFrequency() / 1000000;
1120 ULONG HorizTotalDots
= ((ULONG
)VgaCrtcRegisters
[VGA_CRTC_HORZ_TOTAL_REG
] + 5) * Dots
;
1121 ULONG VblankStart
, VblankEnd
, HblankStart
, HblankEnd
;
1122 ULONG HblankDuration
, VblankDuration
;
1124 /* Calculate the vertical blanking duration in cycles */
1125 VblankStart
= VgaCrtcRegisters
[VGA_CRTC_START_VERT_BLANKING_REG
] & 0x7F;
1126 VblankEnd
= VgaCrtcRegisters
[VGA_CRTC_END_VERT_BLANKING_REG
] & 0x7F;
1127 if (VblankEnd
< VblankStart
) VblankEnd
|= 0x80;
1128 VblankDuration
= ((VblankEnd
- VblankStart
) * HorizTotalDots
1129 * CyclesPerMicrosecond
+ (Clock
>> 1)) / Clock
;
1131 /* Calculate the horizontal blanking duration in cycles */
1132 HblankStart
= VgaCrtcRegisters
[VGA_CRTC_START_HORZ_BLANKING_REG
] & 0x1F;
1133 HblankEnd
= VgaCrtcRegisters
[VGA_CRTC_END_HORZ_BLANKING_REG
] & 0x1F;
1134 if (HblankEnd
< HblankStart
) HblankEnd
|= 0x20;
1135 HblankDuration
= ((HblankEnd
- HblankStart
) * Dots
1136 * CyclesPerMicrosecond
+ (Clock
>> 1)) / Clock
;
1138 Vsync
= (Cycles
- VerticalRetraceCycle
) < (ULONGLONG
)VblankDuration
;
1139 Hsync
= (Cycles
- HorizontalRetraceCycle
) < (ULONGLONG
)HblankDuration
;
1141 /* Reset the AC latch */
1144 /* Reverse the polarity, if needed */
1145 if (VgaMiscRegister
& VGA_MISC_VSYNCP
) Vsync
= !Vsync
;
1146 if (VgaMiscRegister
& VGA_MISC_HSYNCP
) Hsync
= !Hsync
;
1148 /* Set a flag if there is a vertical or horizontal retrace */
1149 if (Vsync
|| Hsync
) Result
|= VGA_STAT_DD
;
1151 /* Set an additional flag if there was a vertical retrace */
1152 if (Vsync
) Result
|= VGA_STAT_VRETRACE
;
1157 case VGA_FEATURE_READ
:
1158 return VgaFeatureRegister
;
1164 return VgaAcRegisters
[VgaAcIndex
];
1170 return VgaSeqRegisters
[VgaSeqIndex
];
1174 if (SvgaHdrCounter
== 4)
1177 return SvgaHiddenRegister
;
1186 case VGA_DAC_READ_INDEX
:
1187 /* This returns the read/write state */
1188 return (VgaDacReadWrite
? 0 : 3);
1190 case VGA_DAC_WRITE_INDEX
:
1195 /* Ignore reads in write mode */
1196 if (!VgaDacReadWrite
)
1198 BYTE Data
= VgaDacRegisters
[VgaDacIndex
* 3 + VgaDacLatchCounter
];
1199 VgaDacLatchCounter
++;
1201 if (VgaDacLatchCounter
== 3)
1203 /* Reset the latch counter and increment the palette index */
1204 VgaDacLatchCounter
= 0;
1206 VgaDacIndex
%= VGA_MAX_COLORS
;
1215 case VGA_CRTC_INDEX_MONO
:
1216 case VGA_CRTC_INDEX_COLOR
:
1217 return VgaCrtcIndex
;
1219 case VGA_CRTC_DATA_MONO
:
1220 case VGA_CRTC_DATA_COLOR
:
1221 return VgaCrtcRegisters
[VgaCrtcIndex
];
1227 return VgaGcRegisters
[VgaGcIndex
];
1230 DPRINT1("VgaReadPort: Unknown port 0x%X\n", Port
);
1237 static inline VOID
VgaWriteSequencer(BYTE Data
)
1239 /* Save the value */
1240 VgaSeqRegisters
[VgaSeqIndex
& VGA_SEQ_INDEX_MASK
] = Data
;
1242 /* Check the index */
1243 switch (VgaSeqIndex
& VGA_SEQ_INDEX_MASK
)
1245 case SVGA_SEQ_UNLOCK_REG
:
1247 if ((Data
& SVGA_SEQ_UNLOCK_MASK
) == SVGA_SEQ_UNLOCKED
)
1249 /* Unlock SVGA extensions */
1250 VgaSeqRegisters
[SVGA_SEQ_UNLOCK_REG
] = SVGA_SEQ_UNLOCKED
;
1254 /* Lock SVGA extensions */
1255 VgaSeqRegisters
[SVGA_SEQ_UNLOCK_REG
] = SVGA_SEQ_LOCKED
;
1263 static inline VOID
VgaWriteGc(BYTE Data
)
1265 /* Save the value */
1266 VgaGcRegisters
[VgaGcIndex
& VGA_GC_INDEX_MASK
] = Data
;
1268 /* Check the index */
1269 switch (VgaGcIndex
& VGA_GC_INDEX_MASK
)
1271 case VGA_GC_MISC_REG
:
1273 /* Remove any existing VGA memory hook */
1274 MemRemoveFastMemoryHook((PVOID
)0xA0000, 0x20000);
1276 if (VgaMiscRegister
& VGA_MISC_RAM_ENABLED
)
1278 UCHAR MemoryMap
= (VgaGcRegisters
[VGA_GC_MISC_REG
] >> 2) & 0x03;
1280 /* Register a memory hook */
1281 MemInstallFastMemoryHook((PVOID
)MemoryBase
[MemoryMap
],
1282 MemorySize
[MemoryMap
],
1287 /* The GC misc register decides if it's text or graphics mode */
1294 static inline VOID
VgaWriteCrtc(BYTE Data
)
1296 /* Save the value */
1297 VgaCrtcRegisters
[VgaCrtcIndex
& VGA_CRTC_INDEX_MASK
] = Data
;
1299 /* Check the index */
1300 switch (VgaCrtcIndex
& VGA_CRTC_INDEX_MASK
)
1302 case VGA_CRTC_END_HORZ_DISP_REG
:
1303 case VGA_CRTC_VERT_DISP_END_REG
:
1304 case VGA_CRTC_OVERFLOW_REG
:
1305 case VGA_CRTC_MAX_SCAN_LINE_REG
:
1307 /* The video mode has changed */
1312 case VGA_CRTC_CURSOR_LOC_LOW_REG
:
1313 case VGA_CRTC_CURSOR_LOC_HIGH_REG
:
1314 case VGA_CRTC_CURSOR_START_REG
:
1315 case VGA_CRTC_CURSOR_END_REG
:
1317 /* Set the cursor changed flag */
1318 CursorChanged
= TRUE
;
1324 static inline VOID
VgaWriteDac(BYTE Data
)
1329 /* Store the value in the latch */
1330 VgaDacLatch
[VgaDacLatchCounter
++] = Data
;
1331 if (VgaDacLatchCounter
< 3) return;
1333 /* Reset the latch counter */
1334 VgaDacLatchCounter
= 0;
1336 /* Set the DAC register values */
1337 VgaDacRegisters
[VgaDacIndex
* 3] = VgaDacLatch
[0];
1338 VgaDacRegisters
[VgaDacIndex
* 3 + 1] = VgaDacLatch
[1];
1339 VgaDacRegisters
[VgaDacIndex
* 3 + 2] = VgaDacLatch
[2];
1341 /* Fill the entry structure */
1342 Entry
.peRed
= VGA_DAC_TO_COLOR(VgaDacLatch
[0]);
1343 Entry
.peGreen
= VGA_DAC_TO_COLOR(VgaDacLatch
[1]);
1344 Entry
.peBlue
= VGA_DAC_TO_COLOR(VgaDacLatch
[2]);
1347 /* Update the palette entry */
1348 SetPaletteEntries(PaletteHandle
, VgaDacIndex
, 1, &Entry
);
1350 /* Check which text palette entries are affected */
1351 for (i
= 0; i
<= VGA_AC_PAL_F_REG
; i
++)
1353 if (VgaAcRegisters
[i
] == VgaDacIndex
)
1355 /* Update the text palette entry */
1356 SetPaletteEntries(TextPaletteHandle
, i
, 1, &Entry
);
1360 /* Set the palette changed flag */
1361 PaletteChanged
= TRUE
;
1363 /* Update the index */
1365 VgaDacIndex
%= VGA_MAX_COLORS
;
1368 static inline VOID
VgaWriteAc(BYTE Data
)
1372 ASSERT(VgaAcIndex
< VGA_AC_MAX_REG
);
1374 /* Save the value */
1375 if (VgaAcIndex
<= VGA_AC_PAL_F_REG
)
1377 if (VgaAcPalDisable
) return;
1379 // DbgPrint(" AC Palette Writing %d to index %d\n", Data, VgaAcIndex);
1380 if (VgaAcRegisters
[VgaAcIndex
] != Data
)
1382 /* Update the AC register */
1383 VgaAcRegisters
[VgaAcIndex
] = Data
;
1385 /* Fill the entry structure */
1386 Entry
.peRed
= VGA_DAC_TO_COLOR(VgaDacRegisters
[Data
* 3]);
1387 Entry
.peGreen
= VGA_DAC_TO_COLOR(VgaDacRegisters
[Data
* 3 + 1]);
1388 Entry
.peBlue
= VGA_DAC_TO_COLOR(VgaDacRegisters
[Data
* 3 + 2]);
1391 /* Update the palette entry and set the palette change flag */
1392 SetPaletteEntries(TextPaletteHandle
, VgaAcIndex
, 1, &Entry
);
1393 PaletteChanged
= TRUE
;
1398 VgaAcRegisters
[VgaAcIndex
] = Data
;
1402 static VOID WINAPI
VgaWritePort(USHORT Port
, BYTE Data
)
1404 DPRINT("VgaWritePort: Port 0x%X, Data 0x%02X\n", Port
, Data
);
1408 case VGA_MISC_WRITE
:
1410 VgaMiscRegister
= Data
;
1412 if (VgaMiscRegister
& 0x01)
1414 /* Color emulation */
1415 DPRINT1("Color emulation\n");
1417 /* Register the new I/O Ports */
1418 RegisterIoPort(0x3D4, VgaReadPort
, VgaWritePort
); // VGA_CRTC_INDEX_COLOR
1419 RegisterIoPort(0x3D5, VgaReadPort
, VgaWritePort
); // VGA_CRTC_DATA_COLOR
1420 RegisterIoPort(0x3DA, VgaReadPort
, VgaWritePort
); // VGA_INSTAT1_READ_COLOR, VGA_FEATURE_WRITE_COLOR
1422 /* Unregister the old ones */
1423 UnregisterIoPort(0x3B4); // VGA_CRTC_INDEX_MONO
1424 UnregisterIoPort(0x3B5); // VGA_CRTC_DATA_MONO
1425 UnregisterIoPort(0x3BA); // VGA_INSTAT1_READ_MONO, VGA_FEATURE_WRITE_MONO
1429 /* Monochrome emulation */
1430 DPRINT1("Monochrome emulation\n");
1432 /* Register the new I/O Ports */
1433 RegisterIoPort(0x3B4, VgaReadPort
, VgaWritePort
); // VGA_CRTC_INDEX_MONO
1434 RegisterIoPort(0x3B5, VgaReadPort
, VgaWritePort
); // VGA_CRTC_DATA_MONO
1435 RegisterIoPort(0x3BA, VgaReadPort
, VgaWritePort
); // VGA_INSTAT1_READ_MONO, VGA_FEATURE_WRITE_MONO
1437 /* Unregister the old ones */
1438 UnregisterIoPort(0x3D4); // VGA_CRTC_INDEX_COLOR
1439 UnregisterIoPort(0x3D5); // VGA_CRTC_DATA_COLOR
1440 UnregisterIoPort(0x3DA); // VGA_INSTAT1_READ_COLOR, VGA_FEATURE_WRITE_COLOR
1443 /* Remove any existing VGA memory hook */
1444 MemRemoveFastMemoryHook((PVOID
)0xA0000, 0x20000);
1446 if (VgaMiscRegister
& VGA_MISC_RAM_ENABLED
)
1448 UCHAR MemoryMap
= (VgaGcRegisters
[VGA_GC_MISC_REG
] >> 2) & 0x03;
1450 /* Register a memory hook */
1451 MemInstallFastMemoryHook((PVOID
)MemoryBase
[MemoryMap
],
1452 MemorySize
[MemoryMap
],
1460 case VGA_FEATURE_WRITE_MONO
:
1461 case VGA_FEATURE_WRITE_COLOR
:
1463 VgaFeatureRegister
= Data
;
1468 // case VGA_AC_WRITE:
1472 /* Change the index */
1473 BYTE Index
= Data
& 0x1F;
1474 if (Index
< VGA_AC_MAX_REG
) VgaAcIndex
= Index
;
1477 * Change palette protection by checking for
1478 * the Palette Address Source bit.
1480 VgaAcPalDisable
= (Data
& 0x20) ? TRUE
: FALSE
;
1484 /* Write the data */
1488 /* Toggle the latch */
1489 VgaAcLatch
= !VgaAcLatch
;
1495 /* Set the sequencer index register */
1496 if ((Data
& 0x1F) < SVGA_SEQ_MAX_UNLOCKED_REG
1497 && (Data
& 0x1F) != VGA_SEQ_MAX_REG
)
1507 /* Call the sequencer function */
1508 VgaWriteSequencer(Data
);
1514 if (SvgaHdrCounter
== 4) SvgaHiddenRegister
= Data
;
1515 else VgaDacMask
= Data
;
1520 case VGA_DAC_READ_INDEX
:
1522 VgaDacReadWrite
= FALSE
;
1524 VgaDacLatchCounter
= 0;
1528 case VGA_DAC_WRITE_INDEX
:
1530 VgaDacReadWrite
= TRUE
;
1532 VgaDacLatchCounter
= 0;
1538 /* Ignore writes in read mode */
1539 if (VgaDacReadWrite
) VgaWriteDac(Data
& 0x3F);
1543 case VGA_CRTC_INDEX_MONO
:
1544 case VGA_CRTC_INDEX_COLOR
:
1546 /* Set the CRTC index register */
1547 if (((Data
& VGA_CRTC_INDEX_MASK
) < SVGA_CRTC_MAX_UNLOCKED_REG
)
1548 && ((Data
& VGA_CRTC_INDEX_MASK
) < SVGA_CRTC_UNUSED0_REG
1549 || (Data
& VGA_CRTC_INDEX_MASK
) > SVGA_CRTC_UNUSED6_REG
)
1550 && (Data
& VGA_CRTC_INDEX_MASK
) != SVGA_CRTC_UNUSED7_REG
)
1552 VgaCrtcIndex
= Data
;
1558 case VGA_CRTC_DATA_MONO
:
1559 case VGA_CRTC_DATA_COLOR
:
1561 /* Call the CRTC function */
1568 /* Set the GC index register */
1569 if ((Data
& VGA_GC_INDEX_MASK
) < SVGA_GC_MAX_UNLOCKED_REG
1570 && (Data
& VGA_GC_INDEX_MASK
) != SVGA_GC_UNUSED0_REG
1571 && ((Data
& VGA_GC_INDEX_MASK
) < SVGA_GC_UNUSED1_REG
1572 || (Data
& VGA_GC_INDEX_MASK
) > SVGA_GC_UNUSED10_REG
))
1582 /* Call the GC function */
1588 DPRINT1("VgaWritePort: Unknown port 0x%X, Data 0x%02X\n", Port
, Data
);
1595 static VOID FASTCALL
VgaVerticalRetrace(ULONGLONG ElapsedTime
)
1597 UNREFERENCED_PARAMETER(ElapsedTime
);
1599 /* Set the vertical retrace cycle */
1600 VerticalRetraceCycle
= GetCycleCount();
1602 /* If nothing has changed, just return */
1603 // if (!ModeChanged && !CursorChanged && !PaletteChanged && !NeedsUpdate)
1606 /* Change the display mode */
1607 if (ModeChanged
) VgaChangeMode();
1609 /* Change the text cursor appearance */
1610 if (CursorChanged
) VgaUpdateTextCursor();
1614 /* Trigger a full update of the screen */
1616 UpdateRectangle
.Left
= 0;
1617 UpdateRectangle
.Top
= 0;
1618 UpdateRectangle
.Right
= CurrResolution
.X
;
1619 UpdateRectangle
.Bottom
= CurrResolution
.Y
;
1621 PaletteChanged
= FALSE
;
1624 /* Update the contents of the framebuffer */
1625 VgaUpdateFramebuffer();
1627 /* Ignore if there's nothing to update */
1628 if (!NeedsUpdate
) return;
1630 DPRINT("Updating screen rectangle (%d, %d, %d, %d)\n",
1631 UpdateRectangle
.Left
,
1632 UpdateRectangle
.Top
,
1633 UpdateRectangle
.Right
,
1634 UpdateRectangle
.Bottom
);
1636 VgaConsoleRepaintScreen(&UpdateRectangle
);
1638 /* Clear the update flag */
1639 NeedsUpdate
= FALSE
;
1642 static VOID FASTCALL
VgaHorizontalRetrace(ULONGLONG ElapsedTime
)
1644 UNREFERENCED_PARAMETER(ElapsedTime
);
1647 HorizontalRetraceCycle
= GetCycleCount();
1650 /* PUBLIC FUNCTIONS ***********************************************************/
1652 COORD
VgaGetDisplayResolution(VOID
)
1655 BYTE MaximumScanLine
= 1 + (VgaCrtcRegisters
[VGA_CRTC_MAX_SCAN_LINE_REG
] & 0x1F);
1657 /* The low 8 bits are in the display registers */
1658 Resolution
.X
= VgaCrtcRegisters
[VGA_CRTC_END_HORZ_DISP_REG
];
1659 Resolution
.Y
= VgaCrtcRegisters
[VGA_CRTC_VERT_DISP_END_REG
];
1661 /* Set the top bits from the overflow register */
1662 if (VgaCrtcRegisters
[VGA_CRTC_OVERFLOW_REG
] & VGA_CRTC_OVERFLOW_VDE8
)
1664 Resolution
.Y
|= 1 << 8;
1666 if (VgaCrtcRegisters
[VGA_CRTC_OVERFLOW_REG
] & VGA_CRTC_OVERFLOW_VDE9
)
1668 Resolution
.Y
|= 1 << 9;
1671 /* Increase the values by 1 */
1675 if (VgaGcRegisters
[VGA_GC_MISC_REG
] & VGA_GC_MISC_NOALPHA
)
1677 /* In "High Resolution" mode, the width of a character is always 8 pixels */
1678 if (VgaSeqRegisters
[SVGA_SEQ_EXT_MODE_REG
] & SVGA_SEQ_EXT_MODE_HIGH_RES
)
1684 /* Multiply the horizontal resolution by the 9/8 dot mode */
1685 Resolution
.X
*= (VgaSeqRegisters
[VGA_SEQ_CLOCK_REG
] & VGA_SEQ_CLOCK_98DM
)
1688 /* The horizontal resolution is halved in 8-bit mode */
1689 if (VgaAcRegisters
[VGA_AC_CONTROL_REG
] & VGA_AC_CONTROL_8BIT
) Resolution
.X
/= 2;
1693 if (VgaCrtcRegisters
[VGA_CRTC_MAX_SCAN_LINE_REG
] & VGA_CRTC_MAXSCANLINE_DOUBLE
)
1695 /* Halve the vertical resolution */
1700 /* Divide the vertical resolution by the maximum scan line (== font size in text mode) */
1701 Resolution
.Y
/= MaximumScanLine
;
1704 /* Return the resolution */
1708 VOID
VgaRefreshDisplay(VOID
)
1710 VgaVerticalRetrace(0);
1713 VOID FASTCALL
VgaReadMemory(ULONG Address
, PVOID Buffer
, ULONG Size
)
1717 PUCHAR BufPtr
= (PUCHAR
)Buffer
;
1719 DPRINT("VgaReadMemory: Address 0x%08X, Size %lu\n", Address
, Size
);
1721 /* Ignore if video RAM access is disabled */
1722 if ((VgaMiscRegister
& VGA_MISC_RAM_ENABLED
) == 0) return;
1724 if (!(VgaGcRegisters
[VGA_GC_MODE_REG
] & VGA_GC_MODE_READ
))
1726 /* Loop through each byte */
1727 for (i
= 0; i
< Size
; i
++)
1729 VideoAddress
= VgaTranslateReadAddress(Address
+ i
);
1731 /* Copy the value to the buffer */
1732 BufPtr
[i
] = VgaMemory
[VideoAddress
];
1737 /* Loop through each byte */
1738 for (i
= 0; i
< Size
; i
++)
1742 /* This should always return a plane 0 address for read mode 1 */
1743 VideoAddress
= VgaTranslateReadAddress(Address
+ i
);
1745 for (j
= 0; j
< VGA_NUM_BANKS
; j
++)
1747 /* Don't consider ignored banks */
1748 if (!(VgaGcRegisters
[VGA_GC_COLOR_IGNORE_REG
] & (1 << j
))) continue;
1750 if (VgaGcRegisters
[VGA_GC_COLOR_COMPARE_REG
] & (1 << j
))
1752 /* Comparing with 11111111 */
1753 Result
&= VgaMemory
[j
* VGA_BANK_SIZE
+ LOWORD(VideoAddress
)];
1757 /* Comparing with 00000000 */
1758 Result
&= ~(VgaMemory
[j
* VGA_BANK_SIZE
+ LOWORD(VideoAddress
)]);
1762 /* Copy the value to the buffer */
1767 /* Load the latch registers */
1768 VgaLatchRegisters
[0] = VgaMemory
[LOWORD(VideoAddress
)];
1769 VgaLatchRegisters
[1] = VgaMemory
[VGA_BANK_SIZE
+ LOWORD(VideoAddress
)];
1770 VgaLatchRegisters
[2] = VgaMemory
[(2 * VGA_BANK_SIZE
) + LOWORD(VideoAddress
)];
1771 VgaLatchRegisters
[3] = VgaMemory
[(3 * VGA_BANK_SIZE
) + LOWORD(VideoAddress
)];
1774 BOOLEAN FASTCALL
VgaWriteMemory(ULONG Address
, PVOID Buffer
, ULONG Size
)
1778 PUCHAR BufPtr
= (PUCHAR
)Buffer
;
1780 DPRINT("VgaWriteMemory: Address 0x%08X, Size %lu\n", Address
, Size
);
1782 /* Ignore if video RAM access is disabled */
1783 if ((VgaMiscRegister
& VGA_MISC_RAM_ENABLED
) == 0) return TRUE
;
1785 /* Also ignore if write access to all planes is disabled */
1786 if ((VgaSeqRegisters
[VGA_SEQ_MASK_REG
] & 0x0F) == 0x00) return TRUE
;
1788 /* Loop through each byte */
1789 for (i
= 0; i
< Size
; i
++)
1791 VideoAddress
= VgaTranslateWriteAddress(Address
+ i
);
1793 for (j
= 0; j
< VGA_NUM_BANKS
; j
++)
1795 /* Make sure the page is writeable */
1796 if (!(VgaSeqRegisters
[VGA_SEQ_MASK_REG
] & (1 << j
))) continue;
1798 /* Check if this is chain-4 mode */
1799 if (VgaSeqRegisters
[VGA_SEQ_MEM_REG
] & VGA_SEQ_MEM_C4
)
1801 if (((Address
+ i
) & 0x03) != j
)
1803 /* This plane will not be accessed */
1808 /* Check if this is odd-even mode */
1809 if (VgaGcRegisters
[VGA_GC_MODE_REG
] & VGA_GC_MODE_OE
)
1811 if (((Address
+ i
) & 0x01) != (j
& 1))
1813 /* This plane will not be accessed */
1818 /* Copy the value to the VGA memory */
1819 VgaMemory
[VideoAddress
+ j
* VGA_BANK_SIZE
] = VgaTranslateByteForWriting(BufPtr
[i
], j
);
1826 VOID
VgaClearMemory(VOID
)
1828 RtlZeroMemory(VgaMemory
, sizeof(VgaMemory
));
1831 VOID
VgaWriteTextModeFont(UINT FontNumber
, CONST UCHAR
* FontData
, UINT Height
)
1834 PUCHAR FontMemory
= (PUCHAR
)&VgaMemory
[VGA_BANK_SIZE
* VGA_FONT_BANK
+ (FontNumber
* VGA_FONT_SIZE
)];
1836 ASSERT(Height
<= VGA_MAX_FONT_HEIGHT
);
1838 for (i
= 0 ; i
< VGA_FONT_CHARACTERS
; i
++)
1840 /* Write the character */
1841 for (j
= 0; j
< Height
; j
++)
1843 FontMemory
[i
* VGA_MAX_FONT_HEIGHT
+ j
] = FontData
[i
* Height
+ j
];
1846 /* Clear the unused part */
1847 for (j
= Height
; j
< VGA_MAX_FONT_HEIGHT
; j
++)
1849 FontMemory
[i
* VGA_MAX_FONT_HEIGHT
+ j
] = 0;
1854 BOOLEAN
VgaInitialize(HANDLE TextHandle
)
1856 if (!VgaConsoleInitialize(TextHandle
)) return FALSE
;
1858 /* Clear the SEQ, GC, CRTC and AC registers */
1859 RtlZeroMemory(VgaSeqRegisters
, sizeof(VgaSeqRegisters
));
1860 RtlZeroMemory(VgaGcRegisters
, sizeof(VgaGcRegisters
));
1861 RtlZeroMemory(VgaCrtcRegisters
, sizeof(VgaCrtcRegisters
));
1862 RtlZeroMemory(VgaAcRegisters
, sizeof(VgaAcRegisters
));
1864 /* Initialize the VGA palette and fail if it isn't successfully created */
1865 if (!VgaInitializePalette()) return FALSE
;
1866 /***/ VgaResetPalette(); /***/
1868 /* Reset the sequencer */
1869 VgaResetSequencer();
1871 /* Clear the VGA memory */
1874 /* Register the I/O Ports */
1875 RegisterIoPort(0x3CC, VgaReadPort
, NULL
); // VGA_MISC_READ
1876 RegisterIoPort(0x3C2, VgaReadPort
, VgaWritePort
); // VGA_MISC_WRITE, VGA_INSTAT0_READ
1877 RegisterIoPort(0x3CA, VgaReadPort
, NULL
); // VGA_FEATURE_READ
1878 RegisterIoPort(0x3C0, VgaReadPort
, VgaWritePort
); // VGA_AC_INDEX, VGA_AC_WRITE
1879 RegisterIoPort(0x3C1, VgaReadPort
, NULL
); // VGA_AC_READ
1880 RegisterIoPort(0x3C4, VgaReadPort
, VgaWritePort
); // VGA_SEQ_INDEX
1881 RegisterIoPort(0x3C5, VgaReadPort
, VgaWritePort
); // VGA_SEQ_DATA
1882 RegisterIoPort(0x3C6, VgaReadPort
, VgaWritePort
); // VGA_DAC_MASK
1883 RegisterIoPort(0x3C7, VgaReadPort
, VgaWritePort
); // VGA_DAC_READ_INDEX
1884 RegisterIoPort(0x3C8, VgaReadPort
, VgaWritePort
); // VGA_DAC_WRITE_INDEX
1885 RegisterIoPort(0x3C9, VgaReadPort
, VgaWritePort
); // VGA_DAC_DATA
1886 RegisterIoPort(0x3CE, VgaReadPort
, VgaWritePort
); // VGA_GC_INDEX
1887 RegisterIoPort(0x3CF, VgaReadPort
, VgaWritePort
); // VGA_GC_DATA
1889 /* CGA ports for compatibility, unimplemented */
1890 RegisterIoPort(0x3D8, VgaReadPort
, VgaWritePort
); // CGA_MODE_CTRL_REG
1891 RegisterIoPort(0x3D9, VgaReadPort
, VgaWritePort
); // CGA_PAL_CTRL_REG
1893 HSyncTimer
= CreateHardwareTimer(HARDWARE_TIMER_ENABLED
, HZ_TO_NS(31469), VgaHorizontalRetrace
);
1894 VSyncTimer
= CreateHardwareTimer(HARDWARE_TIMER_ENABLED
, HZ_TO_NS(60), VgaVerticalRetrace
);
1896 /* Return success */
1900 VOID
VgaCleanup(VOID
)
1902 /* Do a final display refresh */
1903 VgaRefreshDisplay();
1905 DestroyHardwareTimer(VSyncTimer
);
1906 DestroyHardwareTimer(HSyncTimer
);
1908 /* Leave the current video mode */
1909 VgaLeaveCurrentMode(); // ScreenMode
1911 MemRemoveFastMemoryHook((PVOID
)0xA0000, 0x20000);
1913 VgaConsoleCleanup();