2cc5572ab907f492503c45fd2c4f1ca8f9caab12
[reactos.git] / reactos / subsystems / mvdm / ntvdm / hardware / video / svga.c
1 /*
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>
7 */
8
9 /* INCLUDES *******************************************************************/
10
11 #include "ntvdm.h"
12
13 #define NDEBUG
14 #include <debug.h>
15
16 #include "emulator.h"
17 #include "svga.h"
18 #include <bios/vidbios.h>
19
20 #include "memory.h"
21 #include "io.h"
22 #include "clock.h"
23
24 #include "../../console/video.h"
25
26 /* PRIVATE VARIABLES **********************************************************/
27
28 static CONST DWORD MemoryBase[] = { 0xA0000, 0xA0000, 0xB0000, 0xB8000 };
29 static CONST DWORD MemorySize[] = { 0x20000, 0x10000, 0x08000, 0x08000 };
30
31 #define USE_REACTOS_COLORS
32 // #define USE_DOSBOX_COLORS
33
34 #if defined(USE_REACTOS_COLORS)
35
36 // ReactOS colors
37 static CONST COLORREF VgaDefaultPalette[VGA_MAX_COLORS] =
38 {
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)
103 };
104
105 #elif defined(USE_DOSBOX_COLORS)
106
107 // DOSBox colors
108 static CONST COLORREF VgaDefaultPalette[VGA_MAX_COLORS] =
109 {
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),
126
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),
143
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),
160
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)
177 };
178
179 #endif
180
181 /*
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
185 */
186 static const COLORREF ConsoleColors[16] =
187 {
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
196
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
205 };
206
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;
213
214 /*
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.
220 */
221 static PCHAR_CELL TextFramebuffer = NULL;
222
223 /*
224 * Graphics mode
225 */
226 static PBYTE GraphicsFramebuffer = NULL;
227
228
229 // static HANDLE ConsoleMutex = NULL;
230 // /* DoubleVision support */
231 // static BOOLEAN DoubleWidth = FALSE;
232 // static BOOLEAN DoubleHeight = FALSE;
233
234
235
236
237
238 /*
239 * VGA Hardware
240 */
241 static BYTE VgaMemory[VGA_NUM_BANKS * SVGA_BANK_SIZE];
242
243 static BYTE VgaLatchRegisters[VGA_NUM_BANKS] = {0, 0, 0, 0};
244
245 static BYTE VgaMiscRegister;
246 static BYTE VgaFeatureRegister;
247
248 static BYTE VgaSeqIndex = VGA_SEQ_RESET_REG;
249 static BYTE VgaSeqRegisters[SVGA_SEQ_MAX_REG];
250
251 static BYTE VgaCrtcIndex = VGA_CRTC_HORZ_TOTAL_REG;
252 static BYTE VgaCrtcRegisters[SVGA_CRTC_MAX_REG];
253
254 static BYTE VgaGcIndex = VGA_GC_RESET_REG;
255 static BYTE VgaGcRegisters[SVGA_GC_MAX_REG];
256
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];
261
262 static BYTE VgaDacMask = 0xFF;
263 static BYTE VgaDacLatchCounter = 0;
264 static BYTE VgaDacLatch[3];
265
266 static BOOLEAN VgaDacReadWrite = FALSE;
267 static WORD VgaDacIndex = 0;
268 static BYTE VgaDacRegisters[VGA_PALETTE_SIZE];
269
270 // static VGA_REGISTERS VgaRegisters;
271
272 static ULONGLONG VerticalRetraceCycle = 0ULL;
273 static ULONGLONG HorizontalRetraceCycle = 0ULL;
274 static PHARDWARE_TIMER VSyncTimer;
275 static PHARDWARE_TIMER HSyncTimer;
276
277 static BOOLEAN NeedsUpdate = FALSE;
278 static BOOLEAN ModeChanged = FALSE;
279 static BOOLEAN CursorChanged = FALSE;
280 static BOOLEAN PaletteChanged = FALSE;
281
282 static UINT SvgaHdrCounter = 0;
283 static BYTE SvgaHiddenRegister = 0;
284
285 typedef enum _SCREEN_MODE
286 {
287 TEXT_MODE,
288 GRAPHICS_MODE
289 } SCREEN_MODE, *PSCREEN_MODE;
290
291 static SCREEN_MODE ScreenMode = TEXT_MODE;
292 static COORD CurrResolution = {0};
293
294 static SMALL_RECT UpdateRectangle = { 0, 0, 0, 0 };
295
296
297
298
299 /** HACK!! **/
300 #include "../../console/video.c"
301 /** HACK!! **/
302
303
304
305
306
307 /* PRIVATE FUNCTIONS **********************************************************/
308
309 static inline DWORD VgaGetVideoBaseAddress(VOID)
310 {
311 return MemoryBase[(VgaGcRegisters[VGA_GC_MISC_REG] >> 2) & 0x03];
312 }
313
314 static inline DWORD VgaGetAddressSize(VOID)
315 {
316 if (VgaCrtcRegisters[VGA_CRTC_UNDERLINE_REG] & VGA_CRTC_UNDERLINE_DWORD)
317 {
318 /* Double-word addressing */
319 return 4; // sizeof(DWORD)
320 }
321 else if (VgaCrtcRegisters[VGA_CRTC_MODE_CONTROL_REG] & VGA_CRTC_MODE_CONTROL_BYTE)
322 {
323 /* Byte addressing */
324 return 1; // sizeof(BYTE)
325 }
326 else
327 {
328 /* Word addressing */
329 return 2; // sizeof(WORD)
330 }
331 }
332
333 static inline DWORD VgaTranslateReadAddress(DWORD Address)
334 {
335 DWORD Offset = LOWORD(Address - VgaGetVideoBaseAddress());
336 BYTE Plane;
337
338 /* Check for chain-4 and odd-even mode */
339 if (VgaSeqRegisters[VGA_SEQ_MEM_REG] & VGA_SEQ_MEM_C4)
340 {
341 /* The lowest two bits are the plane number */
342 Plane = Offset & 0x03;
343 Offset &= ~3;
344 }
345 else if (VgaGcRegisters[VGA_GC_MODE_REG] & VGA_GC_MODE_OE)
346 {
347 /* The LSB is the plane number */
348 Plane = Offset & 0x01;
349 Offset &= ~1;
350 }
351 else
352 {
353 /* Use the read mode */
354 Plane = VgaGcRegisters[VGA_GC_READ_MAP_SEL_REG] & 0x03;
355 }
356
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;
360 }
361
362 static inline DWORD VgaTranslateWriteAddress(DWORD Address)
363 {
364 DWORD Offset = LOWORD(Address - VgaGetVideoBaseAddress());
365
366 /* Check for chain-4 and odd-even mode */
367 if (VgaSeqRegisters[VGA_SEQ_MEM_REG] & VGA_SEQ_MEM_C4)
368 {
369 /* Clear the lowest two bits since they're used to select the bank */
370 Offset &= ~3;
371 }
372 else if (VgaGcRegisters[VGA_GC_MODE_REG] & VGA_GC_MODE_OE)
373 {
374 /* Clear the lowest bit since it's used to select odd/even */
375 Offset &= ~1;
376 }
377
378 /* Return the offset on plane 0 */
379 return Offset;
380 }
381
382 static inline BYTE VgaTranslateByteForWriting(BYTE Data, BYTE Plane)
383 {
384 BYTE WriteMode = VgaGcRegisters[VGA_GC_MODE_REG] & 0x03;
385 BYTE BitMask = VgaGcRegisters[VGA_GC_BITMASK_REG];
386
387 if (WriteMode == 1)
388 {
389 /* In write mode 1 just return the latch register */
390 return VgaLatchRegisters[Plane];
391 }
392
393 if (WriteMode != 2)
394 {
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)));
398 }
399 else
400 {
401 /* Write mode 2 expands the appropriate bit to all 8 bits */
402 Data = (Data & (1 << Plane)) ? 0xFF : 0x00;
403 }
404
405 if (WriteMode == 0)
406 {
407 /*
408 * In write mode 0, the enable set/reset register decides if the
409 * set/reset bit should be expanded to all 8 bits.
410 */
411 if (VgaGcRegisters[VGA_GC_ENABLE_RESET_REG] & (1 << Plane))
412 {
413 /* Copy the bit from the set/reset register to all 8 bits */
414 Data = (VgaGcRegisters[VGA_GC_RESET_REG] & (1 << Plane)) ? 0xFF : 0x00;
415 }
416 }
417
418 if (WriteMode != 3)
419 {
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;
422
423 if (LogicalOperation == 1) Data &= VgaLatchRegisters[Plane];
424 else if (LogicalOperation == 2) Data |= VgaLatchRegisters[Plane];
425 else if (LogicalOperation == 3) Data ^= VgaLatchRegisters[Plane];
426 }
427 else
428 {
429 /* For write mode 3, we AND the bitmask with the data, which is used as the new bitmask */
430 BitMask &= Data;
431
432 /* Then we expand the bit in the set/reset field */
433 Data = (VgaGcRegisters[VGA_GC_RESET_REG] & (1 << Plane)) ? 0xFF : 0x00;
434 }
435
436 /* Bits cleared in the bitmask are replaced with latch register bits */
437 Data = (Data & BitMask) | (VgaLatchRegisters[Plane] & (~BitMask));
438
439 /* Return the byte */
440 return Data;
441 }
442
443 static inline ULONG VgaGetClockFrequency(VOID)
444 {
445 BYTE Numerator, Denominator;
446
447 if (VgaSeqRegisters[SVGA_SEQ_MCLK_REG] & SVGA_SEQ_MCLK_VCLK)
448 {
449 /* The VCLK is being generated using the MCLK */
450 ULONG Clock = (VGA_CLOCK_BASE * (VgaSeqRegisters[SVGA_SEQ_MCLK_REG] & 0x3F)) >> 3;
451
452 if (VgaSeqRegisters[SVGA_SEQ_VCLK3_DENOMINATOR_REG] & 1)
453 {
454 /* Use only half of the MCLK as the VCLK */
455 Clock >>= 1;
456 }
457
458 return Clock;
459 }
460
461 switch ((VgaMiscRegister >> 2) & 3)
462 {
463 case 0:
464 {
465 Numerator = VgaSeqRegisters[SVGA_SEQ_VCLK0_NUMERATOR_REG];
466 Denominator = VgaSeqRegisters[SVGA_SEQ_VCLK0_DENOMINATOR_REG];
467 break;
468 }
469
470 case 1:
471 {
472 Numerator = VgaSeqRegisters[SVGA_SEQ_VCLK1_NUMERATOR_REG];
473 Denominator = VgaSeqRegisters[SVGA_SEQ_VCLK1_DENOMINATOR_REG];
474 break;
475 }
476
477 case 2:
478 {
479 Numerator = VgaSeqRegisters[SVGA_SEQ_VCLK2_NUMERATOR_REG];
480 Denominator = VgaSeqRegisters[SVGA_SEQ_VCLK2_DENOMINATOR_REG];
481 break;
482 }
483
484 case 3:
485 {
486 Numerator = VgaSeqRegisters[SVGA_SEQ_VCLK3_NUMERATOR_REG];
487 Denominator = VgaSeqRegisters[SVGA_SEQ_VCLK3_DENOMINATOR_REG];
488 break;
489 }
490 }
491
492 /* The numerator is 7-bit */
493 Numerator &= ~(1 << 7);
494
495 /* If bit 7 is clear, the denominator is 5-bit */
496 if (!(Denominator & (1 << 7))) Denominator &= ~(1 << 6);
497
498 /* Bit 0 of the denominator is the post-scalar bit */
499 if (Denominator & 1) Denominator &= ~1;
500 else Denominator >>= 1;
501
502 /* Return the clock frequency in Hz */
503 return (VGA_CLOCK_BASE * Numerator) / Denominator;
504 }
505
506 static VOID VgaResetSequencer(VOID)
507 {
508 /* Lock extended SVGA registers */
509 VgaSeqRegisters[SVGA_SEQ_UNLOCK_REG] = SVGA_SEQ_LOCKED;
510
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;
520
521 /* 50 MHz MCLK, not being used as the VCLK */
522 VgaSeqRegisters[SVGA_SEQ_MCLK_REG] = 0x1C;
523 }
524
525 static VOID VgaRestoreDefaultPalette(PPALETTEENTRY Entries, USHORT NumOfEntries)
526 {
527 USHORT i;
528
529 /* Copy the colors of the default palette to the DAC and console palette */
530 for (i = 0; i < NumOfEntries; i++)
531 {
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;
537
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]));
542 }
543 }
544
545 static BOOLEAN VgaInitializePalette(VOID)
546 {
547 UINT i;
548 BOOLEAN Result = FALSE;
549 LPLOGPALETTE Palette, TextPalette;
550
551 /* Allocate storage space for the palettes */
552 Palette = RtlAllocateHeap(RtlGetProcessHeap(),
553 HEAP_ZERO_MEMORY,
554 sizeof(LOGPALETTE) +
555 VGA_MAX_COLORS * sizeof(PALETTEENTRY));
556 TextPalette = RtlAllocateHeap(RtlGetProcessHeap(),
557 HEAP_ZERO_MEMORY,
558 sizeof(LOGPALETTE) +
559 (VGA_AC_PAL_F_REG + 1) * sizeof(PALETTEENTRY));
560 if ((Palette == NULL) || (TextPalette == NULL)) goto Cleanup;
561
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;
566
567 /* Restore the default graphics palette */
568 VgaRestoreDefaultPalette(Palette->palPalEntry, Palette->palNumEntries);
569
570 /* Set the default text palette */
571 for (i = 0; i < TextPalette->palNumEntries; i++)
572 {
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;
578 }
579
580 /* Create the palettes */
581 PaletteHandle = CreatePalette(Palette);
582 TextPaletteHandle = CreatePalette(TextPalette);
583
584 if (PaletteHandle != NULL && TextPaletteHandle != NULL)
585 {
586 /* The palettes have been created successfully */
587 Result = TRUE;
588 }
589
590 Cleanup:
591 /* Free the palettes */
592 if (Palette) RtlFreeHeap(RtlGetProcessHeap(), 0, Palette);
593 if (TextPalette) RtlFreeHeap(RtlGetProcessHeap(), 0, TextPalette);
594
595 if (!Result)
596 {
597 /* Something failed, delete the palettes */
598 if (PaletteHandle) DeleteObject(PaletteHandle);
599 if (TextPaletteHandle) DeleteObject(TextPaletteHandle);
600 }
601
602 return Result;
603 }
604
605 static VOID VgaResetPalette(VOID)
606 {
607 PALETTEENTRY Entries[VGA_MAX_COLORS];
608
609 /* Restore the default palette */
610 VgaRestoreDefaultPalette(Entries, VGA_MAX_COLORS);
611 SetPaletteEntries(PaletteHandle, 0, VGA_MAX_COLORS, Entries);
612 PaletteChanged = TRUE;
613 }
614
615 static BOOL VgaEnterNewMode(SCREEN_MODE NewScreenMode, PCOORD Resolution)
616 {
617 /* Check if the new mode is alphanumeric */
618 if (NewScreenMode == TEXT_MODE)
619 {
620 /* Enter new text mode */
621
622 if (!VgaConsoleCreateTextScreen(// &TextFramebuffer,
623 Resolution,
624 TextPaletteHandle))
625 {
626 DisplayMessage(L"An unexpected VGA error occurred while switching into text mode. Error: %u", GetLastError());
627 EmulatorTerminate();
628 return FALSE;
629 }
630
631 /* The active framebuffer is now the text framebuffer */
632 ActiveFramebuffer = TextFramebuffer;
633
634 /* Set the screen mode flag */
635 ScreenMode = TEXT_MODE;
636
637 return TRUE;
638 }
639 else
640 {
641 /* Enter graphics mode */
642
643 if (!VgaConsoleCreateGraphicsScreen(// &GraphicsFramebuffer,
644 Resolution,
645 PaletteHandle))
646 {
647 DisplayMessage(L"An unexpected VGA error occurred while switching into graphics mode. Error: %u", GetLastError());
648 EmulatorTerminate();
649 return FALSE;
650 }
651
652 /* The active framebuffer is now the graphics framebuffer */
653 ActiveFramebuffer = GraphicsFramebuffer;
654
655 /* Set the screen mode flag */
656 ScreenMode = GRAPHICS_MODE;
657
658 return TRUE;
659 }
660 }
661
662 static VOID VgaLeaveCurrentMode(VOID)
663 {
664 /* Leave the current video mode */
665 if (ScreenMode == GRAPHICS_MODE)
666 {
667 VgaConsoleDestroyGraphicsScreen();
668
669 /* Cleanup the video data */
670 GraphicsFramebuffer = NULL;
671 }
672 else
673 {
674 VgaConsoleDestroyTextScreen();
675
676 /* Cleanup the video data */
677 TextFramebuffer = NULL;
678 }
679
680 /* Reset the active framebuffer */
681 ActiveFramebuffer = NULL;
682 }
683
684 static VOID VgaChangeMode(VOID)
685 {
686 COORD NewResolution = VgaGetDisplayResolution();
687 SCREEN_MODE NewScreenMode =
688 !(VgaGcRegisters[VGA_GC_MISC_REG] & VGA_GC_MISC_NOALPHA) ? TEXT_MODE
689 : GRAPHICS_MODE;
690
691 /*
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.
694 */
695 if ((ScreenMode == NewScreenMode) && // CurrResolution == NewResolution
696 (CurrResolution.X == NewResolution.X && CurrResolution.Y == NewResolution.Y))
697 {
698 goto Quit;
699 }
700
701 // FIXME: Wouldn't it be preferrable to switch to the new console SB
702 // *ONLY* if we succeeded in setting the new mode??
703
704 /* Leave the current video mode */
705 VgaLeaveCurrentMode(); // ScreenMode
706
707 /* Update the current resolution */
708 CurrResolution = NewResolution;
709
710 /* Change the screen mode */
711 if (!VgaEnterNewMode(NewScreenMode, &CurrResolution))
712 return;
713
714 Quit:
715
716 /* Trigger a full update of the screen */
717 NeedsUpdate = TRUE;
718 UpdateRectangle.Left = 0;
719 UpdateRectangle.Top = 0;
720 UpdateRectangle.Right = CurrResolution.X;
721 UpdateRectangle.Bottom = CurrResolution.Y;
722
723 /* Reset the mode change flag */
724 ModeChanged = FALSE;
725 }
726
727 static inline VOID VgaMarkForUpdate(SHORT Row, SHORT Column)
728 {
729 /* Check if this is the first time the rectangle is updated */
730 if (!NeedsUpdate)
731 {
732 UpdateRectangle.Left = UpdateRectangle.Top = MAXSHORT;
733 UpdateRectangle.Right = UpdateRectangle.Bottom = MINSHORT;
734 }
735
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);
741
742 /* Set the update request flag */
743 NeedsUpdate = TRUE;
744 }
745
746 static VOID VgaUpdateFramebuffer(VOID)
747 {
748 SHORT i, j, k;
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
756 + BytePanning;
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;
760
761 /*
762 * If the console framebuffer is NULL, that means something
763 * went wrong earlier and this is the final display refresh.
764 */
765 if (ActiveFramebuffer == NULL) return;
766
767 /* Check if we are in text or graphics mode */
768 if (ScreenMode == GRAPHICS_MODE)
769 {
770 /* Graphics mode */
771 PBYTE GraphicsBuffer = (PBYTE)ActiveFramebuffer;
772 DWORD InterlaceHighBit = VGA_INTERLACE_HIGH_BIT;
773 SHORT X;
774
775 /*
776 * Synchronize access to the graphics framebuffer
777 * with the console framebuffer mutex.
778 */
779 WaitForSingleObject(ConsoleMutex, INFINITE);
780
781 /* Shift the high bit right by 1 in odd/even mode */
782 if (VgaGcRegisters[VGA_GC_MODE_REG] & VGA_GC_MODE_OE)
783 {
784 InterlaceHighBit >>= 1;
785 }
786
787 if (VgaCrtcRegisters[VGA_CRTC_MAX_SCAN_LINE_REG] & VGA_CRTC_MAXSCANLINE_DOUBLE)
788 {
789 /* Halve the line compare value */
790 LineCompare >>= 1;
791 }
792 else
793 {
794 /* Divide the line compare value by the maximum scan line */
795 LineCompare /= 1 + (VgaCrtcRegisters[VGA_CRTC_MAX_SCAN_LINE_REG] & 0x1F);
796 }
797
798 /* Loop through the scanlines */
799 for (i = 0; i < CurrResolution.Y; i++)
800 {
801 if (i == LineCompare)
802 {
803 if (VgaAcRegisters[VGA_AC_CONTROL_REG] & VGA_AC_CONTROL_PPM)
804 {
805 /*
806 * Disable the pixel shift count and byte panning
807 * for the rest of the display cycle
808 */
809 PixelShift = 0;
810 BytePanning = 0;
811 }
812
813 /* Reset the address, but assume the preset row scan is 0 */
814 Address = BytePanning;
815 }
816
817 if ((VgaGcRegisters[VGA_GC_MISC_REG] & VGA_GC_MISC_OE) && (i & 1))
818 {
819 /* Odd-numbered line in interlaced mode - set the high bit */
820 Address |= InterlaceHighBit;
821 }
822
823 /* Loop through the pixels */
824 for (j = 0; j < CurrResolution.X; j++)
825 {
826 BYTE PixelData = 0;
827
828 /* Apply horizontal pixel panning */
829 if (VgaAcRegisters[VGA_AC_CONTROL_REG] & VGA_AC_CONTROL_8BIT)
830 {
831 X = j + (PixelShift >> 1);
832 }
833 else
834 {
835 X = j + PixelShift;
836 }
837
838 /* Check the shifting mode */
839 if (VgaGcRegisters[VGA_GC_MODE_REG] & VGA_GC_MODE_SHIFT256)
840 {
841 /* 4 bits shifted from each plane */
842
843 /* Check if this is 16 or 256 color mode */
844 if (VgaAcRegisters[VGA_AC_CONTROL_REG] & VGA_AC_CONTROL_8BIT)
845 {
846 /* One byte per pixel */
847 PixelData = VgaMemory[(X % VGA_NUM_BANKS) * VGA_BANK_SIZE
848 + LOWORD((Address + (X / VGA_NUM_BANKS))
849 * AddressSize)];
850 }
851 else
852 {
853 /* 4-bits per pixel */
854
855 PixelData = VgaMemory[(X % VGA_NUM_BANKS) * VGA_BANK_SIZE
856 + LOWORD((Address + (X / (VGA_NUM_BANKS * 2)))
857 * AddressSize)];
858
859 /* Check if we should use the highest 4 bits or lowest 4 */
860 if (((X / VGA_NUM_BANKS) % 2) == 0)
861 {
862 /* Highest 4 */
863 PixelData >>= 4;
864 }
865 else
866 {
867 /* Lowest 4 */
868 PixelData &= 0x0F;
869 }
870 }
871 }
872 else if (VgaGcRegisters[VGA_GC_MODE_REG] & VGA_GC_MODE_SHIFTREG)
873 {
874 /* Check if this is 16 or 256 color mode */
875 if (VgaAcRegisters[VGA_AC_CONTROL_REG] & VGA_AC_CONTROL_8BIT)
876 {
877 // TODO: NOT IMPLEMENTED
878 DPRINT1("8-bit interleaved mode is not implemented!\n");
879 }
880 else
881 {
882 /*
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
885 */
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)];
890
891 /* Extract the two bits from each plane */
892 LowPlaneData = (LowPlaneData >> (6 - ((X % 4) * 2))) & 0x03;
893 HighPlaneData = (HighPlaneData >> (6 - ((X % 4) * 2))) & 0x03;
894
895 /* Combine them into the pixel */
896 PixelData = LowPlaneData | (HighPlaneData << 2);
897 }
898 }
899 else
900 {
901 /* 1 bit shifted from each plane */
902
903 /* Check if this is 16 or 256 color mode */
904 if (VgaAcRegisters[VGA_AC_CONTROL_REG] & VGA_AC_CONTROL_8BIT)
905 {
906 /* 8 bits per pixel, 2 on each plane */
907
908 for (k = 0; k < VGA_NUM_BANKS; k++)
909 {
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))
913 * AddressSize)];
914
915 /* The mask of the first bit in the pair */
916 BYTE BitMask = 1 << (((3 - (X % VGA_NUM_BANKS)) * 2) + 1);
917
918 /* Bits 0, 1, 2 and 3 come from the first bit of the pair */
919 if (PlaneData & BitMask) PixelData |= 1 << k;
920
921 /* Bits 4, 5, 6 and 7 come from the second bit of the pair */
922 if (PlaneData & (BitMask >> 1)) PixelData |= 1 << (k + 4);
923 }
924 }
925 else
926 {
927 /* 4 bits per pixel, 1 on each plane */
928
929 for (k = 0; k < VGA_NUM_BANKS; k++)
930 {
931 BYTE PlaneData = VgaMemory[k * VGA_BANK_SIZE
932 + LOWORD((Address + (X / (VGA_NUM_BANKS * 2)))
933 * AddressSize)];
934
935 /* If the bit on that plane is set, set it */
936 if (PlaneData & (1 << (7 - (X % 8)))) PixelData |= 1 << k;
937 }
938 }
939 }
940
941 if (!(VgaAcRegisters[VGA_AC_CONTROL_REG] & VGA_AC_CONTROL_8BIT))
942 {
943 /*
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.
947 */
948 PixelData = (VgaAcPalDisable ? VgaAcRegisters[PixelData & 0x0F]
949 : 0);
950 }
951
952 /* Take into account DoubleVision mode when checking for pixel updates */
953 if (DoubleWidth && DoubleHeight)
954 {
955 /* Now check if the resulting pixel data has changed */
956 if (GraphicsBuffer[(i * 2 * CurrResolution.X * 2) + (j * 2)] != PixelData)
957 {
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;
963
964 /* Mark the specified pixel as changed */
965 VgaMarkForUpdate(i, j);
966 }
967 }
968 else if (DoubleWidth && !DoubleHeight)
969 {
970 /* Now check if the resulting pixel data has changed */
971 if (GraphicsBuffer[(i * CurrResolution.X * 2) + (j * 2)] != PixelData)
972 {
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;
976
977 /* Mark the specified pixel as changed */
978 VgaMarkForUpdate(i, j);
979 }
980 }
981 else if (!DoubleWidth && DoubleHeight)
982 {
983 /* Now check if the resulting pixel data has changed */
984 if (GraphicsBuffer[(i * 2 * CurrResolution.X) + j] != PixelData)
985 {
986 /* Yes, write the new value */
987 GraphicsBuffer[(i * 2 * CurrResolution.X) + j] = PixelData;
988 GraphicsBuffer[((i * 2 + 1) * CurrResolution.X) + j] = PixelData;
989
990 /* Mark the specified pixel as changed */
991 VgaMarkForUpdate(i, j);
992 }
993 }
994 else // if (!DoubleWidth && !DoubleHeight)
995 {
996 /* Now check if the resulting pixel data has changed */
997 if (GraphicsBuffer[i * CurrResolution.X + j] != PixelData)
998 {
999 /* Yes, write the new value */
1000 GraphicsBuffer[i * CurrResolution.X + j] = PixelData;
1001
1002 /* Mark the specified pixel as changed */
1003 VgaMarkForUpdate(i, j);
1004 }
1005 }
1006 }
1007
1008 if ((VgaGcRegisters[VGA_GC_MISC_REG] & VGA_GC_MISC_OE) && (i & 1))
1009 {
1010 /* Clear the high bit */
1011 Address &= ~InterlaceHighBit;
1012 }
1013
1014 if (!(VgaGcRegisters[VGA_GC_MISC_REG] & VGA_GC_MISC_OE) || (i & 1))
1015 {
1016 /* Move to the next scanline */
1017 Address += ScanlineSize;
1018 }
1019 }
1020
1021 /*
1022 * Release the console framebuffer mutex
1023 * so that we allow for repainting.
1024 */
1025 ReleaseMutex(ConsoleMutex);
1026 }
1027 else
1028 {
1029 /* Text mode */
1030 DWORD CurrentAddr;
1031 PCHAR_CELL CharBuffer = (PCHAR_CELL)ActiveFramebuffer;
1032 CHAR_CELL CharInfo;
1033
1034 /*
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.
1038 */
1039
1040 /* Loop through the scanlines */
1041 for (i = 0; i < CurrResolution.Y; i++)
1042 {
1043 /* Loop through the characters */
1044 for (j = 0; j < CurrResolution.X; j++)
1045 {
1046 CurrentAddr = LOWORD((Address + j) * AddressSize);
1047
1048 /* Plane 0 holds the character itself */
1049 CharInfo.Char = VgaMemory[CurrentAddr];
1050
1051 /* Plane 1 holds the attribute */
1052 CharInfo.Attributes = VgaMemory[CurrentAddr + VGA_BANK_SIZE];
1053
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))
1057 {
1058 /* Yes, write the new value */
1059 CharBuffer[i * CurrResolution.X + j] = CharInfo;
1060
1061 /* Mark the specified cell as changed */
1062 VgaMarkForUpdate(i, j);
1063 }
1064 }
1065
1066 /* Move to the next scanline */
1067 Address += ScanlineSize;
1068 }
1069 }
1070 }
1071
1072 static VOID VgaUpdateTextCursor(VOID)
1073 {
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;
1077
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]);
1082
1083 /* Just return if we are not in text mode */
1084 if (ScreenMode != TEXT_MODE) return;
1085
1086 /* Add the cursor skew to the location */
1087 Location += (VgaCrtcRegisters[VGA_CRTC_CURSOR_END_REG] >> 5) & 0x03;
1088
1089 VgaConsoleUpdateTextCursor(CursorVisible, CursorStart, CursorEnd,
1090 TextSize, ScanlineSize, Location);
1091
1092 /* Reset the cursor changed flag */
1093 CursorChanged = FALSE;
1094 }
1095
1096 static BYTE WINAPI VgaReadPort(USHORT Port)
1097 {
1098 DPRINT("VgaReadPort: Port 0x%X\n", Port);
1099
1100 if (Port != VGA_DAC_MASK) SvgaHdrCounter = 0;
1101
1102 switch (Port)
1103 {
1104 case VGA_MISC_READ:
1105 return VgaMiscRegister;
1106
1107 case VGA_INSTAT0_READ:
1108 return 0; // Not implemented
1109
1110 case VGA_INSTAT1_READ_MONO:
1111 case VGA_INSTAT1_READ_COLOR:
1112 {
1113 BYTE Result = 0;
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;
1122
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;
1129
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;
1136
1137 Vsync = (Cycles - VerticalRetraceCycle) < (ULONGLONG)VblankDuration;
1138 Hsync = (Cycles - HorizontalRetraceCycle) < (ULONGLONG)HblankDuration;
1139
1140 /* Reset the AC latch */
1141 VgaAcLatch = FALSE;
1142
1143 /* Reverse the polarity, if needed */
1144 if (VgaMiscRegister & VGA_MISC_VSYNCP) Vsync = !Vsync;
1145 if (VgaMiscRegister & VGA_MISC_HSYNCP) Hsync = !Hsync;
1146
1147 /* Set a flag if there is a vertical or horizontal retrace */
1148 if (Vsync || Hsync) Result |= VGA_STAT_DD;
1149
1150 /* Set an additional flag if there was a vertical retrace */
1151 if (Vsync) Result |= VGA_STAT_VRETRACE;
1152
1153 return Result;
1154 }
1155
1156 case VGA_FEATURE_READ:
1157 return VgaFeatureRegister;
1158
1159 case VGA_AC_INDEX:
1160 return VgaAcIndex;
1161
1162 case VGA_AC_READ:
1163 return VgaAcRegisters[VgaAcIndex];
1164
1165 case VGA_SEQ_INDEX:
1166 return VgaSeqIndex;
1167
1168 case VGA_SEQ_DATA:
1169 return VgaSeqRegisters[VgaSeqIndex];
1170
1171 case VGA_DAC_MASK:
1172 {
1173 if (SvgaHdrCounter == 4)
1174 {
1175 SvgaHdrCounter = 0;
1176 return SvgaHiddenRegister;
1177 }
1178 else
1179 {
1180 SvgaHdrCounter++;
1181 return VgaDacMask;
1182 }
1183 }
1184
1185 case VGA_DAC_READ_INDEX:
1186 /* This returns the read/write state */
1187 return (VgaDacReadWrite ? 0 : 3);
1188
1189 case VGA_DAC_WRITE_INDEX:
1190 return VgaDacIndex;
1191
1192 case VGA_DAC_DATA:
1193 {
1194 /* Ignore reads in write mode */
1195 if (!VgaDacReadWrite)
1196 {
1197 BYTE Data = VgaDacRegisters[VgaDacIndex * 3 + VgaDacLatchCounter];
1198 VgaDacLatchCounter++;
1199
1200 if (VgaDacLatchCounter == 3)
1201 {
1202 /* Reset the latch counter and increment the palette index */
1203 VgaDacLatchCounter = 0;
1204 VgaDacIndex++;
1205 VgaDacIndex %= VGA_MAX_COLORS;
1206 }
1207
1208 return Data;
1209 }
1210
1211 break;
1212 }
1213
1214 case VGA_CRTC_INDEX_MONO:
1215 case VGA_CRTC_INDEX_COLOR:
1216 return VgaCrtcIndex;
1217
1218 case VGA_CRTC_DATA_MONO:
1219 case VGA_CRTC_DATA_COLOR:
1220 return VgaCrtcRegisters[VgaCrtcIndex];
1221
1222 case VGA_GC_INDEX:
1223 return VgaGcIndex;
1224
1225 case VGA_GC_DATA:
1226 return VgaGcRegisters[VgaGcIndex];
1227
1228 default:
1229 DPRINT1("VgaReadPort: Unknown port 0x%X\n", Port);
1230 break;
1231 }
1232
1233 return 0;
1234 }
1235
1236 static inline VOID VgaWriteSequencer(BYTE Data)
1237 {
1238 /* Save the value */
1239 VgaSeqRegisters[VgaSeqIndex & VGA_SEQ_INDEX_MASK] = Data;
1240
1241 /* Check the index */
1242 switch (VgaSeqIndex & VGA_SEQ_INDEX_MASK)
1243 {
1244 case SVGA_SEQ_UNLOCK_REG:
1245 {
1246 if ((Data & SVGA_SEQ_UNLOCK_MASK) == SVGA_SEQ_UNLOCKED)
1247 {
1248 /* Unlock SVGA extensions */
1249 VgaSeqRegisters[SVGA_SEQ_UNLOCK_REG] = SVGA_SEQ_UNLOCKED;
1250 }
1251 else
1252 {
1253 /* Lock SVGA extensions */
1254 VgaSeqRegisters[SVGA_SEQ_UNLOCK_REG] = SVGA_SEQ_LOCKED;
1255 }
1256
1257 break;
1258 }
1259 }
1260 }
1261
1262 static inline VOID VgaWriteGc(BYTE Data)
1263 {
1264 /* Save the value */
1265 VgaGcRegisters[VgaGcIndex & VGA_GC_INDEX_MASK] = Data;
1266
1267 /* Check the index */
1268 switch (VgaGcIndex & VGA_GC_INDEX_MASK)
1269 {
1270 case VGA_GC_MISC_REG:
1271 {
1272 /* Remove any existing VGA memory hook */
1273 MemRemoveFastMemoryHook((PVOID)0xA0000, 0x20000);
1274
1275 if (VgaMiscRegister & VGA_MISC_RAM_ENABLED)
1276 {
1277 UCHAR MemoryMap = (VgaGcRegisters[VGA_GC_MISC_REG] >> 2) & 0x03;
1278
1279 /* Register a memory hook */
1280 MemInstallFastMemoryHook((PVOID)MemoryBase[MemoryMap],
1281 MemorySize[MemoryMap],
1282 VgaReadMemory,
1283 VgaWriteMemory);
1284 }
1285
1286 /* The GC misc register decides if it's text or graphics mode */
1287 ModeChanged = TRUE;
1288 break;
1289 }
1290 }
1291 }
1292
1293 static inline VOID VgaWriteCrtc(BYTE Data)
1294 {
1295 /* Save the value */
1296 VgaCrtcRegisters[VgaCrtcIndex & VGA_CRTC_INDEX_MASK] = Data;
1297
1298 /* Check the index */
1299 switch (VgaCrtcIndex & VGA_CRTC_INDEX_MASK)
1300 {
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:
1305 {
1306 /* The video mode has changed */
1307 ModeChanged = TRUE;
1308 break;
1309 }
1310
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:
1315 {
1316 /* Set the cursor changed flag */
1317 CursorChanged = TRUE;
1318 break;
1319 }
1320 }
1321 }
1322
1323 static inline VOID VgaWriteDac(BYTE Data)
1324 {
1325 UINT i;
1326 PALETTEENTRY Entry;
1327
1328 /* Store the value in the latch */
1329 VgaDacLatch[VgaDacLatchCounter++] = Data;
1330 if (VgaDacLatchCounter < 3) return;
1331
1332 /* Reset the latch counter */
1333 VgaDacLatchCounter = 0;
1334
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];
1339
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]);
1344 Entry.peFlags = 0;
1345
1346 /* Update the palette entry */
1347 SetPaletteEntries(PaletteHandle, VgaDacIndex, 1, &Entry);
1348
1349 /* Check which text palette entries are affected */
1350 for (i = 0; i <= VGA_AC_PAL_F_REG; i++)
1351 {
1352 if (VgaAcRegisters[i] == VgaDacIndex)
1353 {
1354 /* Update the text palette entry */
1355 SetPaletteEntries(TextPaletteHandle, i, 1, &Entry);
1356 }
1357 }
1358
1359 /* Set the palette changed flag */
1360 PaletteChanged = TRUE;
1361
1362 /* Update the index */
1363 VgaDacIndex++;
1364 VgaDacIndex %= VGA_MAX_COLORS;
1365 }
1366
1367 static inline VOID VgaWriteAc(BYTE Data)
1368 {
1369 PALETTEENTRY Entry;
1370
1371 ASSERT(VgaAcIndex < VGA_AC_MAX_REG);
1372
1373 /* Save the value */
1374 if (VgaAcIndex <= VGA_AC_PAL_F_REG)
1375 {
1376 if (VgaAcPalDisable) return;
1377
1378 // DbgPrint(" AC Palette Writing %d to index %d\n", Data, VgaAcIndex);
1379 if (VgaAcRegisters[VgaAcIndex] != Data)
1380 {
1381 /* Update the AC register */
1382 VgaAcRegisters[VgaAcIndex] = Data;
1383
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]);
1388 Entry.peFlags = 0;
1389
1390 /* Update the palette entry and set the palette change flag */
1391 SetPaletteEntries(TextPaletteHandle, VgaAcIndex, 1, &Entry);
1392 PaletteChanged = TRUE;
1393 }
1394 }
1395 else
1396 {
1397 VgaAcRegisters[VgaAcIndex] = Data;
1398 }
1399 }
1400
1401 static VOID WINAPI VgaWritePort(USHORT Port, BYTE Data)
1402 {
1403 DPRINT("VgaWritePort: Port 0x%X, Data 0x%02X\n", Port, Data);
1404
1405 switch (Port)
1406 {
1407 case VGA_MISC_WRITE:
1408 {
1409 VgaMiscRegister = Data;
1410
1411 if (VgaMiscRegister & 0x01)
1412 {
1413 /* Color emulation */
1414 DPRINT1("Color emulation\n");
1415
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
1420
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
1425 }
1426 else
1427 {
1428 /* Monochrome emulation */
1429 DPRINT1("Monochrome emulation\n");
1430
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
1435
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
1440 }
1441
1442 /* Remove any existing VGA memory hook */
1443 MemRemoveFastMemoryHook((PVOID)0xA0000, 0x20000);
1444
1445 if (VgaMiscRegister & VGA_MISC_RAM_ENABLED)
1446 {
1447 UCHAR MemoryMap = (VgaGcRegisters[VGA_GC_MISC_REG] >> 2) & 0x03;
1448
1449 /* Register a memory hook */
1450 MemInstallFastMemoryHook((PVOID)MemoryBase[MemoryMap],
1451 MemorySize[MemoryMap],
1452 VgaReadMemory,
1453 VgaWriteMemory);
1454 }
1455
1456 break;
1457 }
1458
1459 case VGA_FEATURE_WRITE_MONO:
1460 case VGA_FEATURE_WRITE_COLOR:
1461 {
1462 VgaFeatureRegister = Data;
1463 break;
1464 }
1465
1466 case VGA_AC_INDEX:
1467 // case VGA_AC_WRITE:
1468 {
1469 if (!VgaAcLatch)
1470 {
1471 /* Change the index */
1472 BYTE Index = Data & 0x1F;
1473 if (Index < VGA_AC_MAX_REG) VgaAcIndex = Index;
1474
1475 /*
1476 * Change palette protection by checking for
1477 * the Palette Address Source bit.
1478 */
1479 VgaAcPalDisable = (Data & 0x20) ? TRUE : FALSE;
1480 }
1481 else
1482 {
1483 /* Write the data */
1484 VgaWriteAc(Data);
1485 }
1486
1487 /* Toggle the latch */
1488 VgaAcLatch = !VgaAcLatch;
1489 break;
1490 }
1491
1492 case VGA_SEQ_INDEX:
1493 {
1494 /* Set the sequencer index register */
1495 if ((Data & 0x1F) < SVGA_SEQ_MAX_UNLOCKED_REG
1496 && (Data & 0x1F) != VGA_SEQ_MAX_REG)
1497 {
1498 VgaSeqIndex = Data;
1499 }
1500
1501 break;
1502 }
1503
1504 case VGA_SEQ_DATA:
1505 {
1506 /* Call the sequencer function */
1507 VgaWriteSequencer(Data);
1508 break;
1509 }
1510
1511 case VGA_DAC_MASK:
1512 {
1513 if (SvgaHdrCounter == 4) SvgaHiddenRegister = Data;
1514 else VgaDacMask = Data;
1515
1516 break;
1517 }
1518
1519 case VGA_DAC_READ_INDEX:
1520 {
1521 VgaDacReadWrite = FALSE;
1522 VgaDacIndex = Data;
1523 VgaDacLatchCounter = 0;
1524 break;
1525 }
1526
1527 case VGA_DAC_WRITE_INDEX:
1528 {
1529 VgaDacReadWrite = TRUE;
1530 VgaDacIndex = Data;
1531 VgaDacLatchCounter = 0;
1532 break;
1533 }
1534
1535 case VGA_DAC_DATA:
1536 {
1537 /* Ignore writes in read mode */
1538 if (VgaDacReadWrite) VgaWriteDac(Data & 0x3F);
1539 break;
1540 }
1541
1542 case VGA_CRTC_INDEX_MONO:
1543 case VGA_CRTC_INDEX_COLOR:
1544 {
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)
1550 {
1551 VgaCrtcIndex = Data;
1552 }
1553
1554 break;
1555 }
1556
1557 case VGA_CRTC_DATA_MONO:
1558 case VGA_CRTC_DATA_COLOR:
1559 {
1560 /* Call the CRTC function */
1561 VgaWriteCrtc(Data);
1562 break;
1563 }
1564
1565 case VGA_GC_INDEX:
1566 {
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))
1572 {
1573 VgaGcIndex = Data;
1574 }
1575
1576 break;
1577 }
1578
1579 case VGA_GC_DATA:
1580 {
1581 /* Call the GC function */
1582 VgaWriteGc(Data);
1583 break;
1584 }
1585
1586 default:
1587 DPRINT1("VgaWritePort: Unknown port 0x%X, Data 0x%02X\n", Port, Data);
1588 break;
1589 }
1590
1591 SvgaHdrCounter = 0;
1592 }
1593
1594 static VOID FASTCALL VgaVerticalRetrace(ULONGLONG ElapsedTime)
1595 {
1596 UNREFERENCED_PARAMETER(ElapsedTime);
1597
1598 /* Set the vertical retrace cycle */
1599 VerticalRetraceCycle = GetCycleCount();
1600
1601 /* If nothing has changed, just return */
1602 // if (!ModeChanged && !CursorChanged && !PaletteChanged && !NeedsUpdate)
1603 // return;
1604
1605 /* Change the display mode */
1606 if (ModeChanged) VgaChangeMode();
1607
1608 /* Change the text cursor appearance */
1609 if (CursorChanged) VgaUpdateTextCursor();
1610
1611 if (PaletteChanged)
1612 {
1613 /* Trigger a full update of the screen */
1614 NeedsUpdate = TRUE;
1615 UpdateRectangle.Left = 0;
1616 UpdateRectangle.Top = 0;
1617 UpdateRectangle.Right = CurrResolution.X;
1618 UpdateRectangle.Bottom = CurrResolution.Y;
1619
1620 PaletteChanged = FALSE;
1621 }
1622
1623 /* Update the contents of the framebuffer */
1624 VgaUpdateFramebuffer();
1625
1626 /* Ignore if there's nothing to update */
1627 if (!NeedsUpdate) return;
1628
1629 DPRINT("Updating screen rectangle (%d, %d, %d, %d)\n",
1630 UpdateRectangle.Left,
1631 UpdateRectangle.Top,
1632 UpdateRectangle.Right,
1633 UpdateRectangle.Bottom);
1634
1635 VgaConsoleRepaintScreen(&UpdateRectangle);
1636
1637 /* Clear the update flag */
1638 NeedsUpdate = FALSE;
1639 }
1640
1641 static VOID FASTCALL VgaHorizontalRetrace(ULONGLONG ElapsedTime)
1642 {
1643 UNREFERENCED_PARAMETER(ElapsedTime);
1644
1645 /* Set the cycle */
1646 HorizontalRetraceCycle = GetCycleCount();
1647 }
1648
1649 /* PUBLIC FUNCTIONS ***********************************************************/
1650
1651 COORD VgaGetDisplayResolution(VOID)
1652 {
1653 COORD Resolution;
1654 BYTE MaximumScanLine = 1 + (VgaCrtcRegisters[VGA_CRTC_MAX_SCAN_LINE_REG] & 0x1F);
1655
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];
1659
1660 /* Set the top bits from the overflow register */
1661 if (VgaCrtcRegisters[VGA_CRTC_OVERFLOW_REG] & VGA_CRTC_OVERFLOW_VDE8)
1662 {
1663 Resolution.Y |= 1 << 8;
1664 }
1665 if (VgaCrtcRegisters[VGA_CRTC_OVERFLOW_REG] & VGA_CRTC_OVERFLOW_VDE9)
1666 {
1667 Resolution.Y |= 1 << 9;
1668 }
1669
1670 /* Increase the values by 1 */
1671 Resolution.X++;
1672 Resolution.Y++;
1673
1674 if (VgaGcRegisters[VGA_GC_MISC_REG] & VGA_GC_MISC_NOALPHA)
1675 {
1676 /* Multiply the horizontal resolution by the 9/8 dot mode */
1677 Resolution.X *= (VgaSeqRegisters[VGA_SEQ_CLOCK_REG] & VGA_SEQ_CLOCK_98DM)
1678 ? 8 : 9;
1679
1680 /* The horizontal resolution is halved in 8-bit mode */
1681 if (VgaAcRegisters[VGA_AC_CONTROL_REG] & VGA_AC_CONTROL_8BIT) Resolution.X /= 2;
1682 }
1683
1684 if (VgaCrtcRegisters[VGA_CRTC_MAX_SCAN_LINE_REG] & VGA_CRTC_MAXSCANLINE_DOUBLE)
1685 {
1686 /* Halve the vertical resolution */
1687 Resolution.Y >>= 1;
1688 }
1689 else
1690 {
1691 /* Divide the vertical resolution by the maximum scan line (== font size in text mode) */
1692 Resolution.Y /= MaximumScanLine;
1693 }
1694
1695 /* Return the resolution */
1696 return Resolution;
1697 }
1698
1699 VOID VgaRefreshDisplay(VOID)
1700 {
1701 VgaVerticalRetrace(0);
1702 }
1703
1704 VOID FASTCALL VgaReadMemory(ULONG Address, PVOID Buffer, ULONG Size)
1705 {
1706 DWORD i, j;
1707 DWORD VideoAddress;
1708 PUCHAR BufPtr = (PUCHAR)Buffer;
1709
1710 DPRINT("VgaReadMemory: Address 0x%08X, Size %lu\n", Address, Size);
1711
1712 /* Ignore if video RAM access is disabled */
1713 if ((VgaMiscRegister & VGA_MISC_RAM_ENABLED) == 0) return;
1714
1715 if (!(VgaGcRegisters[VGA_GC_MODE_REG] & VGA_GC_MODE_READ))
1716 {
1717 /* Loop through each byte */
1718 for (i = 0; i < Size; i++)
1719 {
1720 VideoAddress = VgaTranslateReadAddress(Address + i);
1721
1722 /* Copy the value to the buffer */
1723 BufPtr[i] = VgaMemory[VideoAddress];
1724 }
1725 }
1726 else
1727 {
1728 /* Loop through each byte */
1729 for (i = 0; i < Size; i++)
1730 {
1731 BYTE Result = 0xFF;
1732
1733 /* This should always return a plane 0 address for read mode 1 */
1734 VideoAddress = VgaTranslateReadAddress(Address + i);
1735
1736 for (j = 0; j < VGA_NUM_BANKS; j++)
1737 {
1738 /* Don't consider ignored banks */
1739 if (!(VgaGcRegisters[VGA_GC_COLOR_IGNORE_REG] & (1 << j))) continue;
1740
1741 if (VgaGcRegisters[VGA_GC_COLOR_COMPARE_REG] & (1 << j))
1742 {
1743 /* Comparing with 11111111 */
1744 Result &= VgaMemory[j * VGA_BANK_SIZE + LOWORD(VideoAddress)];
1745 }
1746 else
1747 {
1748 /* Comparing with 00000000 */
1749 Result &= ~(VgaMemory[j * VGA_BANK_SIZE + LOWORD(VideoAddress)]);
1750 }
1751 }
1752
1753 /* Copy the value to the buffer */
1754 BufPtr[i] = Result;
1755 }
1756 }
1757
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)];
1763 }
1764
1765 BOOLEAN FASTCALL VgaWriteMemory(ULONG Address, PVOID Buffer, ULONG Size)
1766 {
1767 DWORD i, j;
1768 DWORD VideoAddress;
1769 PUCHAR BufPtr = (PUCHAR)Buffer;
1770
1771 DPRINT("VgaWriteMemory: Address 0x%08X, Size %lu\n", Address, Size);
1772
1773 /* Ignore if video RAM access is disabled */
1774 if ((VgaMiscRegister & VGA_MISC_RAM_ENABLED) == 0) return TRUE;
1775
1776 /* Also ignore if write access to all planes is disabled */
1777 if ((VgaSeqRegisters[VGA_SEQ_MASK_REG] & 0x0F) == 0x00) return TRUE;
1778
1779 /* Loop through each byte */
1780 for (i = 0; i < Size; i++)
1781 {
1782 VideoAddress = VgaTranslateWriteAddress(Address + i);
1783
1784 for (j = 0; j < VGA_NUM_BANKS; j++)
1785 {
1786 /* Make sure the page is writeable */
1787 if (!(VgaSeqRegisters[VGA_SEQ_MASK_REG] & (1 << j))) continue;
1788
1789 /* Check if this is chain-4 mode */
1790 if (VgaSeqRegisters[VGA_SEQ_MEM_REG] & VGA_SEQ_MEM_C4)
1791 {
1792 if (((Address + i) & 0x03) != j)
1793 {
1794 /* This plane will not be accessed */
1795 continue;
1796 }
1797 }
1798
1799 /* Check if this is odd-even mode */
1800 if (VgaGcRegisters[VGA_GC_MODE_REG] & VGA_GC_MODE_OE)
1801 {
1802 if (((Address + i) & 0x01) != (j & 1))
1803 {
1804 /* This plane will not be accessed */
1805 continue;
1806 }
1807 }
1808
1809 /* Copy the value to the VGA memory */
1810 VgaMemory[VideoAddress + j * VGA_BANK_SIZE] = VgaTranslateByteForWriting(BufPtr[i], j);
1811 }
1812 }
1813
1814 return TRUE;
1815 }
1816
1817 VOID VgaClearMemory(VOID)
1818 {
1819 RtlZeroMemory(VgaMemory, sizeof(VgaMemory));
1820 }
1821
1822 VOID VgaWriteTextModeFont(UINT FontNumber, CONST UCHAR* FontData, UINT Height)
1823 {
1824 UINT i, j;
1825 PUCHAR FontMemory = (PUCHAR)&VgaMemory[VGA_BANK_SIZE * VGA_FONT_BANK + (FontNumber * VGA_FONT_SIZE)];
1826
1827 ASSERT(Height <= VGA_MAX_FONT_HEIGHT);
1828
1829 for (i = 0 ; i < VGA_FONT_CHARACTERS; i++)
1830 {
1831 /* Write the character */
1832 for (j = 0; j < Height; j++)
1833 {
1834 FontMemory[i * VGA_MAX_FONT_HEIGHT + j] = FontData[i * Height + j];
1835 }
1836
1837 /* Clear the unused part */
1838 for (j = Height; j < VGA_MAX_FONT_HEIGHT; j++)
1839 {
1840 FontMemory[i * VGA_MAX_FONT_HEIGHT + j] = 0;
1841 }
1842 }
1843 }
1844
1845 BOOLEAN VgaInitialize(HANDLE TextHandle)
1846 {
1847 if (!VgaConsoleInitialize(TextHandle)) return FALSE;
1848
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 ));
1854
1855 /* Initialize the VGA palette and fail if it isn't successfully created */
1856 if (!VgaInitializePalette()) return FALSE;
1857 /***/ VgaResetPalette(); /***/
1858
1859 /* Reset the sequencer */
1860 VgaResetSequencer();
1861
1862 /* Clear the VGA memory */
1863 VgaClearMemory();
1864
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
1879
1880 /* CGA ports for compatibility, unimplemented */
1881 RegisterIoPort(0x3D8, VgaReadPort, VgaWritePort); // CGA_MODE_CTRL_REG
1882 RegisterIoPort(0x3D9, VgaReadPort, VgaWritePort); // CGA_PAL_CTRL_REG
1883
1884 HSyncTimer = CreateHardwareTimer(HARDWARE_TIMER_ENABLED, HZ_TO_NS(31469), VgaHorizontalRetrace);
1885 VSyncTimer = CreateHardwareTimer(HARDWARE_TIMER_ENABLED, HZ_TO_NS(60), VgaVerticalRetrace);
1886
1887 /* Return success */
1888 return TRUE;
1889 }
1890
1891 VOID VgaCleanup(VOID)
1892 {
1893 /* Do a final display refresh */
1894 VgaRefreshDisplay();
1895
1896 DestroyHardwareTimer(VSyncTimer);
1897 DestroyHardwareTimer(HSyncTimer);
1898
1899 /* Leave the current video mode */
1900 VgaLeaveCurrentMode(); // ScreenMode
1901
1902 MemRemoveFastMemoryHook((PVOID)0xA0000, 0x20000);
1903
1904 VgaConsoleCleanup();
1905 }
1906
1907 /* EOF */