e970e76d335c2ea9f6c2c2ae01341513f7a587bc
[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 // NEVER SET the ALWAYS-SET TextFramebuffer pointer to NULL!!
679 }
680
681 /* Reset the active framebuffer */
682 ActiveFramebuffer = NULL;
683 }
684
685 static VOID VgaChangeMode(VOID)
686 {
687 COORD NewResolution = VgaGetDisplayResolution();
688 SCREEN_MODE NewScreenMode =
689 !(VgaGcRegisters[VGA_GC_MISC_REG] & VGA_GC_MISC_NOALPHA) ? TEXT_MODE
690 : GRAPHICS_MODE;
691
692 /*
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.
695 */
696 if ((ScreenMode == NewScreenMode) && // CurrResolution == NewResolution
697 (CurrResolution.X == NewResolution.X && CurrResolution.Y == NewResolution.Y))
698 {
699 goto Quit;
700 }
701
702 // FIXME: Wouldn't it be preferrable to switch to the new console SB
703 // *ONLY* if we succeeded in setting the new mode??
704
705 /* Leave the current video mode */
706 VgaLeaveCurrentMode(); // ScreenMode
707
708 /* Update the current resolution */
709 CurrResolution = NewResolution;
710
711 /* Change the screen mode */
712 if (!VgaEnterNewMode(NewScreenMode, &CurrResolution))
713 return;
714
715 Quit:
716
717 /* Trigger a full update of the screen */
718 NeedsUpdate = TRUE;
719 UpdateRectangle.Left = 0;
720 UpdateRectangle.Top = 0;
721 UpdateRectangle.Right = CurrResolution.X;
722 UpdateRectangle.Bottom = CurrResolution.Y;
723
724 /* Reset the mode change flag */
725 ModeChanged = FALSE;
726 }
727
728 static inline VOID VgaMarkForUpdate(SHORT Row, SHORT Column)
729 {
730 /* Check if this is the first time the rectangle is updated */
731 if (!NeedsUpdate)
732 {
733 UpdateRectangle.Left = UpdateRectangle.Top = MAXSHORT;
734 UpdateRectangle.Right = UpdateRectangle.Bottom = MINSHORT;
735 }
736
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);
742
743 /* Set the update request flag */
744 NeedsUpdate = TRUE;
745 }
746
747 static VOID VgaUpdateFramebuffer(VOID)
748 {
749 SHORT i, j, k;
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
757 + BytePanning;
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;
761
762 /*
763 * If the console framebuffer is NULL, that means something
764 * went wrong earlier and this is the final display refresh.
765 */
766 if (ActiveFramebuffer == NULL) return;
767
768 /* Check if we are in text or graphics mode */
769 if (ScreenMode == GRAPHICS_MODE)
770 {
771 /* Graphics mode */
772 PBYTE GraphicsBuffer = (PBYTE)ActiveFramebuffer;
773 DWORD InterlaceHighBit = VGA_INTERLACE_HIGH_BIT;
774 SHORT X;
775
776 /*
777 * Synchronize access to the graphics framebuffer
778 * with the console framebuffer mutex.
779 */
780 WaitForSingleObject(ConsoleMutex, INFINITE);
781
782 /* Shift the high bit right by 1 in odd/even mode */
783 if (VgaGcRegisters[VGA_GC_MODE_REG] & VGA_GC_MODE_OE)
784 {
785 InterlaceHighBit >>= 1;
786 }
787
788 if (VgaCrtcRegisters[VGA_CRTC_MAX_SCAN_LINE_REG] & VGA_CRTC_MAXSCANLINE_DOUBLE)
789 {
790 /* Halve the line compare value */
791 LineCompare >>= 1;
792 }
793 else
794 {
795 /* Divide the line compare value by the maximum scan line */
796 LineCompare /= 1 + (VgaCrtcRegisters[VGA_CRTC_MAX_SCAN_LINE_REG] & 0x1F);
797 }
798
799 /* Loop through the scanlines */
800 for (i = 0; i < CurrResolution.Y; i++)
801 {
802 if (i == LineCompare)
803 {
804 if (VgaAcRegisters[VGA_AC_CONTROL_REG] & VGA_AC_CONTROL_PPM)
805 {
806 /*
807 * Disable the pixel shift count and byte panning
808 * for the rest of the display cycle
809 */
810 PixelShift = 0;
811 BytePanning = 0;
812 }
813
814 /* Reset the address, but assume the preset row scan is 0 */
815 Address = BytePanning;
816 }
817
818 if ((VgaGcRegisters[VGA_GC_MISC_REG] & VGA_GC_MISC_OE) && (i & 1))
819 {
820 /* Odd-numbered line in interlaced mode - set the high bit */
821 Address |= InterlaceHighBit;
822 }
823
824 /* Loop through the pixels */
825 for (j = 0; j < CurrResolution.X; j++)
826 {
827 BYTE PixelData = 0;
828
829 /* Apply horizontal pixel panning */
830 if (VgaAcRegisters[VGA_AC_CONTROL_REG] & VGA_AC_CONTROL_8BIT)
831 {
832 X = j + (PixelShift >> 1);
833 }
834 else
835 {
836 X = j + PixelShift;
837 }
838
839 /* Check the shifting mode */
840 if (VgaGcRegisters[VGA_GC_MODE_REG] & VGA_GC_MODE_SHIFT256)
841 {
842 /* 4 bits shifted from each plane */
843
844 /* Check if this is 16 or 256 color mode */
845 if (VgaAcRegisters[VGA_AC_CONTROL_REG] & VGA_AC_CONTROL_8BIT)
846 {
847 /* One byte per pixel */
848 PixelData = VgaMemory[(X % VGA_NUM_BANKS) * VGA_BANK_SIZE
849 + LOWORD((Address + (X / VGA_NUM_BANKS))
850 * AddressSize)];
851 }
852 else
853 {
854 /* 4-bits per pixel */
855
856 PixelData = VgaMemory[(X % VGA_NUM_BANKS) * VGA_BANK_SIZE
857 + LOWORD((Address + (X / (VGA_NUM_BANKS * 2)))
858 * AddressSize)];
859
860 /* Check if we should use the highest 4 bits or lowest 4 */
861 if (((X / VGA_NUM_BANKS) % 2) == 0)
862 {
863 /* Highest 4 */
864 PixelData >>= 4;
865 }
866 else
867 {
868 /* Lowest 4 */
869 PixelData &= 0x0F;
870 }
871 }
872 }
873 else if (VgaGcRegisters[VGA_GC_MODE_REG] & VGA_GC_MODE_SHIFTREG)
874 {
875 /* Check if this is 16 or 256 color mode */
876 if (VgaAcRegisters[VGA_AC_CONTROL_REG] & VGA_AC_CONTROL_8BIT)
877 {
878 // TODO: NOT IMPLEMENTED
879 DPRINT1("8-bit interleaved mode is not implemented!\n");
880 }
881 else
882 {
883 /*
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
886 */
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)];
891
892 /* Extract the two bits from each plane */
893 LowPlaneData = (LowPlaneData >> (6 - ((X % 4) * 2))) & 0x03;
894 HighPlaneData = (HighPlaneData >> (6 - ((X % 4) * 2))) & 0x03;
895
896 /* Combine them into the pixel */
897 PixelData = LowPlaneData | (HighPlaneData << 2);
898 }
899 }
900 else
901 {
902 /* 1 bit shifted from each plane */
903
904 /* Check if this is 16 or 256 color mode */
905 if (VgaAcRegisters[VGA_AC_CONTROL_REG] & VGA_AC_CONTROL_8BIT)
906 {
907 /* 8 bits per pixel, 2 on each plane */
908
909 for (k = 0; k < VGA_NUM_BANKS; k++)
910 {
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))
914 * AddressSize)];
915
916 /* The mask of the first bit in the pair */
917 BYTE BitMask = 1 << (((3 - (X % VGA_NUM_BANKS)) * 2) + 1);
918
919 /* Bits 0, 1, 2 and 3 come from the first bit of the pair */
920 if (PlaneData & BitMask) PixelData |= 1 << k;
921
922 /* Bits 4, 5, 6 and 7 come from the second bit of the pair */
923 if (PlaneData & (BitMask >> 1)) PixelData |= 1 << (k + 4);
924 }
925 }
926 else
927 {
928 /* 4 bits per pixel, 1 on each plane */
929
930 for (k = 0; k < VGA_NUM_BANKS; k++)
931 {
932 BYTE PlaneData = VgaMemory[k * VGA_BANK_SIZE
933 + LOWORD((Address + (X / (VGA_NUM_BANKS * 2)))
934 * AddressSize)];
935
936 /* If the bit on that plane is set, set it */
937 if (PlaneData & (1 << (7 - (X % 8)))) PixelData |= 1 << k;
938 }
939 }
940 }
941
942 if (!(VgaAcRegisters[VGA_AC_CONTROL_REG] & VGA_AC_CONTROL_8BIT))
943 {
944 /*
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.
948 */
949 PixelData = (VgaAcPalDisable ? VgaAcRegisters[PixelData & 0x0F]
950 : 0);
951 }
952
953 /* Take into account DoubleVision mode when checking for pixel updates */
954 if (DoubleWidth && DoubleHeight)
955 {
956 /* Now check if the resulting pixel data has changed */
957 if (GraphicsBuffer[(i * 2 * CurrResolution.X * 2) + (j * 2)] != PixelData)
958 {
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;
964
965 /* Mark the specified pixel as changed */
966 VgaMarkForUpdate(i, j);
967 }
968 }
969 else if (DoubleWidth && !DoubleHeight)
970 {
971 /* Now check if the resulting pixel data has changed */
972 if (GraphicsBuffer[(i * CurrResolution.X * 2) + (j * 2)] != PixelData)
973 {
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;
977
978 /* Mark the specified pixel as changed */
979 VgaMarkForUpdate(i, j);
980 }
981 }
982 else if (!DoubleWidth && DoubleHeight)
983 {
984 /* Now check if the resulting pixel data has changed */
985 if (GraphicsBuffer[(i * 2 * CurrResolution.X) + j] != PixelData)
986 {
987 /* Yes, write the new value */
988 GraphicsBuffer[(i * 2 * CurrResolution.X) + j] = PixelData;
989 GraphicsBuffer[((i * 2 + 1) * CurrResolution.X) + j] = PixelData;
990
991 /* Mark the specified pixel as changed */
992 VgaMarkForUpdate(i, j);
993 }
994 }
995 else // if (!DoubleWidth && !DoubleHeight)
996 {
997 /* Now check if the resulting pixel data has changed */
998 if (GraphicsBuffer[i * CurrResolution.X + j] != PixelData)
999 {
1000 /* Yes, write the new value */
1001 GraphicsBuffer[i * CurrResolution.X + j] = PixelData;
1002
1003 /* Mark the specified pixel as changed */
1004 VgaMarkForUpdate(i, j);
1005 }
1006 }
1007 }
1008
1009 if ((VgaGcRegisters[VGA_GC_MISC_REG] & VGA_GC_MISC_OE) && (i & 1))
1010 {
1011 /* Clear the high bit */
1012 Address &= ~InterlaceHighBit;
1013 }
1014
1015 if (!(VgaGcRegisters[VGA_GC_MISC_REG] & VGA_GC_MISC_OE) || (i & 1))
1016 {
1017 /* Move to the next scanline */
1018 Address += ScanlineSize;
1019 }
1020 }
1021
1022 /*
1023 * Release the console framebuffer mutex
1024 * so that we allow for repainting.
1025 */
1026 ReleaseMutex(ConsoleMutex);
1027 }
1028 else
1029 {
1030 /* Text mode */
1031 DWORD CurrentAddr;
1032 PCHAR_CELL CharBuffer = (PCHAR_CELL)ActiveFramebuffer;
1033 CHAR_CELL CharInfo;
1034
1035 /*
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.
1039 */
1040
1041 /* Loop through the scanlines */
1042 for (i = 0; i < CurrResolution.Y; i++)
1043 {
1044 /* Loop through the characters */
1045 for (j = 0; j < CurrResolution.X; j++)
1046 {
1047 CurrentAddr = LOWORD((Address + j) * AddressSize);
1048
1049 /* Plane 0 holds the character itself */
1050 CharInfo.Char = VgaMemory[CurrentAddr];
1051
1052 /* Plane 1 holds the attribute */
1053 CharInfo.Attributes = VgaMemory[CurrentAddr + VGA_BANK_SIZE];
1054
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))
1058 {
1059 /* Yes, write the new value */
1060 CharBuffer[i * CurrResolution.X + j] = CharInfo;
1061
1062 /* Mark the specified cell as changed */
1063 VgaMarkForUpdate(i, j);
1064 }
1065 }
1066
1067 /* Move to the next scanline */
1068 Address += ScanlineSize;
1069 }
1070 }
1071 }
1072
1073 static VOID VgaUpdateTextCursor(VOID)
1074 {
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;
1078
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]);
1083
1084 /* Just return if we are not in text mode */
1085 if (ScreenMode != TEXT_MODE) return;
1086
1087 /* Add the cursor skew to the location */
1088 Location += (VgaCrtcRegisters[VGA_CRTC_CURSOR_END_REG] >> 5) & 0x03;
1089
1090 VgaConsoleUpdateTextCursor(CursorVisible, CursorStart, CursorEnd,
1091 TextSize, ScanlineSize, Location);
1092
1093 /* Reset the cursor changed flag */
1094 CursorChanged = FALSE;
1095 }
1096
1097 static BYTE WINAPI VgaReadPort(USHORT Port)
1098 {
1099 DPRINT("VgaReadPort: Port 0x%X\n", Port);
1100
1101 if (Port != VGA_DAC_MASK) SvgaHdrCounter = 0;
1102
1103 switch (Port)
1104 {
1105 case VGA_MISC_READ:
1106 return VgaMiscRegister;
1107
1108 case VGA_INSTAT0_READ:
1109 return 0; // Not implemented
1110
1111 case VGA_INSTAT1_READ_MONO:
1112 case VGA_INSTAT1_READ_COLOR:
1113 {
1114 BYTE Result = 0;
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;
1123
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;
1130
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;
1137
1138 Vsync = (Cycles - VerticalRetraceCycle) < (ULONGLONG)VblankDuration;
1139 Hsync = (Cycles - HorizontalRetraceCycle) < (ULONGLONG)HblankDuration;
1140
1141 /* Reset the AC latch */
1142 VgaAcLatch = FALSE;
1143
1144 /* Reverse the polarity, if needed */
1145 if (VgaMiscRegister & VGA_MISC_VSYNCP) Vsync = !Vsync;
1146 if (VgaMiscRegister & VGA_MISC_HSYNCP) Hsync = !Hsync;
1147
1148 /* Set a flag if there is a vertical or horizontal retrace */
1149 if (Vsync || Hsync) Result |= VGA_STAT_DD;
1150
1151 /* Set an additional flag if there was a vertical retrace */
1152 if (Vsync) Result |= VGA_STAT_VRETRACE;
1153
1154 return Result;
1155 }
1156
1157 case VGA_FEATURE_READ:
1158 return VgaFeatureRegister;
1159
1160 case VGA_AC_INDEX:
1161 return VgaAcIndex;
1162
1163 case VGA_AC_READ:
1164 return VgaAcRegisters[VgaAcIndex];
1165
1166 case VGA_SEQ_INDEX:
1167 return VgaSeqIndex;
1168
1169 case VGA_SEQ_DATA:
1170 return VgaSeqRegisters[VgaSeqIndex];
1171
1172 case VGA_DAC_MASK:
1173 {
1174 if (SvgaHdrCounter == 4)
1175 {
1176 SvgaHdrCounter = 0;
1177 return SvgaHiddenRegister;
1178 }
1179 else
1180 {
1181 SvgaHdrCounter++;
1182 return VgaDacMask;
1183 }
1184 }
1185
1186 case VGA_DAC_READ_INDEX:
1187 /* This returns the read/write state */
1188 return (VgaDacReadWrite ? 0 : 3);
1189
1190 case VGA_DAC_WRITE_INDEX:
1191 return VgaDacIndex;
1192
1193 case VGA_DAC_DATA:
1194 {
1195 /* Ignore reads in write mode */
1196 if (!VgaDacReadWrite)
1197 {
1198 BYTE Data = VgaDacRegisters[VgaDacIndex * 3 + VgaDacLatchCounter];
1199 VgaDacLatchCounter++;
1200
1201 if (VgaDacLatchCounter == 3)
1202 {
1203 /* Reset the latch counter and increment the palette index */
1204 VgaDacLatchCounter = 0;
1205 VgaDacIndex++;
1206 VgaDacIndex %= VGA_MAX_COLORS;
1207 }
1208
1209 return Data;
1210 }
1211
1212 break;
1213 }
1214
1215 case VGA_CRTC_INDEX_MONO:
1216 case VGA_CRTC_INDEX_COLOR:
1217 return VgaCrtcIndex;
1218
1219 case VGA_CRTC_DATA_MONO:
1220 case VGA_CRTC_DATA_COLOR:
1221 return VgaCrtcRegisters[VgaCrtcIndex];
1222
1223 case VGA_GC_INDEX:
1224 return VgaGcIndex;
1225
1226 case VGA_GC_DATA:
1227 return VgaGcRegisters[VgaGcIndex];
1228
1229 default:
1230 DPRINT1("VgaReadPort: Unknown port 0x%X\n", Port);
1231 break;
1232 }
1233
1234 return 0;
1235 }
1236
1237 static inline VOID VgaWriteSequencer(BYTE Data)
1238 {
1239 /* Save the value */
1240 VgaSeqRegisters[VgaSeqIndex & VGA_SEQ_INDEX_MASK] = Data;
1241
1242 /* Check the index */
1243 switch (VgaSeqIndex & VGA_SEQ_INDEX_MASK)
1244 {
1245 case SVGA_SEQ_UNLOCK_REG:
1246 {
1247 if ((Data & SVGA_SEQ_UNLOCK_MASK) == SVGA_SEQ_UNLOCKED)
1248 {
1249 /* Unlock SVGA extensions */
1250 VgaSeqRegisters[SVGA_SEQ_UNLOCK_REG] = SVGA_SEQ_UNLOCKED;
1251 }
1252 else
1253 {
1254 /* Lock SVGA extensions */
1255 VgaSeqRegisters[SVGA_SEQ_UNLOCK_REG] = SVGA_SEQ_LOCKED;
1256 }
1257
1258 break;
1259 }
1260 }
1261 }
1262
1263 static inline VOID VgaWriteGc(BYTE Data)
1264 {
1265 /* Save the value */
1266 VgaGcRegisters[VgaGcIndex & VGA_GC_INDEX_MASK] = Data;
1267
1268 /* Check the index */
1269 switch (VgaGcIndex & VGA_GC_INDEX_MASK)
1270 {
1271 case VGA_GC_MISC_REG:
1272 {
1273 /* Remove any existing VGA memory hook */
1274 MemRemoveFastMemoryHook((PVOID)0xA0000, 0x20000);
1275
1276 if (VgaMiscRegister & VGA_MISC_RAM_ENABLED)
1277 {
1278 UCHAR MemoryMap = (VgaGcRegisters[VGA_GC_MISC_REG] >> 2) & 0x03;
1279
1280 /* Register a memory hook */
1281 MemInstallFastMemoryHook((PVOID)MemoryBase[MemoryMap],
1282 MemorySize[MemoryMap],
1283 VgaReadMemory,
1284 VgaWriteMemory);
1285 }
1286
1287 /* The GC misc register decides if it's text or graphics mode */
1288 ModeChanged = TRUE;
1289 break;
1290 }
1291 }
1292 }
1293
1294 static inline VOID VgaWriteCrtc(BYTE Data)
1295 {
1296 /* Save the value */
1297 VgaCrtcRegisters[VgaCrtcIndex & VGA_CRTC_INDEX_MASK] = Data;
1298
1299 /* Check the index */
1300 switch (VgaCrtcIndex & VGA_CRTC_INDEX_MASK)
1301 {
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:
1306 {
1307 /* The video mode has changed */
1308 ModeChanged = TRUE;
1309 break;
1310 }
1311
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:
1316 {
1317 /* Set the cursor changed flag */
1318 CursorChanged = TRUE;
1319 break;
1320 }
1321 }
1322 }
1323
1324 static inline VOID VgaWriteDac(BYTE Data)
1325 {
1326 UINT i;
1327 PALETTEENTRY Entry;
1328
1329 /* Store the value in the latch */
1330 VgaDacLatch[VgaDacLatchCounter++] = Data;
1331 if (VgaDacLatchCounter < 3) return;
1332
1333 /* Reset the latch counter */
1334 VgaDacLatchCounter = 0;
1335
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];
1340
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]);
1345 Entry.peFlags = 0;
1346
1347 /* Update the palette entry */
1348 SetPaletteEntries(PaletteHandle, VgaDacIndex, 1, &Entry);
1349
1350 /* Check which text palette entries are affected */
1351 for (i = 0; i <= VGA_AC_PAL_F_REG; i++)
1352 {
1353 if (VgaAcRegisters[i] == VgaDacIndex)
1354 {
1355 /* Update the text palette entry */
1356 SetPaletteEntries(TextPaletteHandle, i, 1, &Entry);
1357 }
1358 }
1359
1360 /* Set the palette changed flag */
1361 PaletteChanged = TRUE;
1362
1363 /* Update the index */
1364 VgaDacIndex++;
1365 VgaDacIndex %= VGA_MAX_COLORS;
1366 }
1367
1368 static inline VOID VgaWriteAc(BYTE Data)
1369 {
1370 PALETTEENTRY Entry;
1371
1372 ASSERT(VgaAcIndex < VGA_AC_MAX_REG);
1373
1374 /* Save the value */
1375 if (VgaAcIndex <= VGA_AC_PAL_F_REG)
1376 {
1377 if (VgaAcPalDisable) return;
1378
1379 // DbgPrint(" AC Palette Writing %d to index %d\n", Data, VgaAcIndex);
1380 if (VgaAcRegisters[VgaAcIndex] != Data)
1381 {
1382 /* Update the AC register */
1383 VgaAcRegisters[VgaAcIndex] = Data;
1384
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]);
1389 Entry.peFlags = 0;
1390
1391 /* Update the palette entry and set the palette change flag */
1392 SetPaletteEntries(TextPaletteHandle, VgaAcIndex, 1, &Entry);
1393 PaletteChanged = TRUE;
1394 }
1395 }
1396 else
1397 {
1398 VgaAcRegisters[VgaAcIndex] = Data;
1399 }
1400 }
1401
1402 static VOID WINAPI VgaWritePort(USHORT Port, BYTE Data)
1403 {
1404 DPRINT("VgaWritePort: Port 0x%X, Data 0x%02X\n", Port, Data);
1405
1406 switch (Port)
1407 {
1408 case VGA_MISC_WRITE:
1409 {
1410 VgaMiscRegister = Data;
1411
1412 if (VgaMiscRegister & 0x01)
1413 {
1414 /* Color emulation */
1415 DPRINT1("Color emulation\n");
1416
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
1421
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
1426 }
1427 else
1428 {
1429 /* Monochrome emulation */
1430 DPRINT1("Monochrome emulation\n");
1431
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
1436
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
1441 }
1442
1443 /* Remove any existing VGA memory hook */
1444 MemRemoveFastMemoryHook((PVOID)0xA0000, 0x20000);
1445
1446 if (VgaMiscRegister & VGA_MISC_RAM_ENABLED)
1447 {
1448 UCHAR MemoryMap = (VgaGcRegisters[VGA_GC_MISC_REG] >> 2) & 0x03;
1449
1450 /* Register a memory hook */
1451 MemInstallFastMemoryHook((PVOID)MemoryBase[MemoryMap],
1452 MemorySize[MemoryMap],
1453 VgaReadMemory,
1454 VgaWriteMemory);
1455 }
1456
1457 break;
1458 }
1459
1460 case VGA_FEATURE_WRITE_MONO:
1461 case VGA_FEATURE_WRITE_COLOR:
1462 {
1463 VgaFeatureRegister = Data;
1464 break;
1465 }
1466
1467 case VGA_AC_INDEX:
1468 // case VGA_AC_WRITE:
1469 {
1470 if (!VgaAcLatch)
1471 {
1472 /* Change the index */
1473 BYTE Index = Data & 0x1F;
1474 if (Index < VGA_AC_MAX_REG) VgaAcIndex = Index;
1475
1476 /*
1477 * Change palette protection by checking for
1478 * the Palette Address Source bit.
1479 */
1480 VgaAcPalDisable = (Data & 0x20) ? TRUE : FALSE;
1481 }
1482 else
1483 {
1484 /* Write the data */
1485 VgaWriteAc(Data);
1486 }
1487
1488 /* Toggle the latch */
1489 VgaAcLatch = !VgaAcLatch;
1490 break;
1491 }
1492
1493 case VGA_SEQ_INDEX:
1494 {
1495 /* Set the sequencer index register */
1496 if ((Data & 0x1F) < SVGA_SEQ_MAX_UNLOCKED_REG
1497 && (Data & 0x1F) != VGA_SEQ_MAX_REG)
1498 {
1499 VgaSeqIndex = Data;
1500 }
1501
1502 break;
1503 }
1504
1505 case VGA_SEQ_DATA:
1506 {
1507 /* Call the sequencer function */
1508 VgaWriteSequencer(Data);
1509 break;
1510 }
1511
1512 case VGA_DAC_MASK:
1513 {
1514 if (SvgaHdrCounter == 4) SvgaHiddenRegister = Data;
1515 else VgaDacMask = Data;
1516
1517 break;
1518 }
1519
1520 case VGA_DAC_READ_INDEX:
1521 {
1522 VgaDacReadWrite = FALSE;
1523 VgaDacIndex = Data;
1524 VgaDacLatchCounter = 0;
1525 break;
1526 }
1527
1528 case VGA_DAC_WRITE_INDEX:
1529 {
1530 VgaDacReadWrite = TRUE;
1531 VgaDacIndex = Data;
1532 VgaDacLatchCounter = 0;
1533 break;
1534 }
1535
1536 case VGA_DAC_DATA:
1537 {
1538 /* Ignore writes in read mode */
1539 if (VgaDacReadWrite) VgaWriteDac(Data & 0x3F);
1540 break;
1541 }
1542
1543 case VGA_CRTC_INDEX_MONO:
1544 case VGA_CRTC_INDEX_COLOR:
1545 {
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)
1551 {
1552 VgaCrtcIndex = Data;
1553 }
1554
1555 break;
1556 }
1557
1558 case VGA_CRTC_DATA_MONO:
1559 case VGA_CRTC_DATA_COLOR:
1560 {
1561 /* Call the CRTC function */
1562 VgaWriteCrtc(Data);
1563 break;
1564 }
1565
1566 case VGA_GC_INDEX:
1567 {
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))
1573 {
1574 VgaGcIndex = Data;
1575 }
1576
1577 break;
1578 }
1579
1580 case VGA_GC_DATA:
1581 {
1582 /* Call the GC function */
1583 VgaWriteGc(Data);
1584 break;
1585 }
1586
1587 default:
1588 DPRINT1("VgaWritePort: Unknown port 0x%X, Data 0x%02X\n", Port, Data);
1589 break;
1590 }
1591
1592 SvgaHdrCounter = 0;
1593 }
1594
1595 static VOID FASTCALL VgaVerticalRetrace(ULONGLONG ElapsedTime)
1596 {
1597 UNREFERENCED_PARAMETER(ElapsedTime);
1598
1599 /* Set the vertical retrace cycle */
1600 VerticalRetraceCycle = GetCycleCount();
1601
1602 /* If nothing has changed, just return */
1603 // if (!ModeChanged && !CursorChanged && !PaletteChanged && !NeedsUpdate)
1604 // return;
1605
1606 /* Change the display mode */
1607 if (ModeChanged) VgaChangeMode();
1608
1609 /* Change the text cursor appearance */
1610 if (CursorChanged) VgaUpdateTextCursor();
1611
1612 if (PaletteChanged)
1613 {
1614 /* Trigger a full update of the screen */
1615 NeedsUpdate = TRUE;
1616 UpdateRectangle.Left = 0;
1617 UpdateRectangle.Top = 0;
1618 UpdateRectangle.Right = CurrResolution.X;
1619 UpdateRectangle.Bottom = CurrResolution.Y;
1620
1621 PaletteChanged = FALSE;
1622 }
1623
1624 /* Update the contents of the framebuffer */
1625 VgaUpdateFramebuffer();
1626
1627 /* Ignore if there's nothing to update */
1628 if (!NeedsUpdate) return;
1629
1630 DPRINT("Updating screen rectangle (%d, %d, %d, %d)\n",
1631 UpdateRectangle.Left,
1632 UpdateRectangle.Top,
1633 UpdateRectangle.Right,
1634 UpdateRectangle.Bottom);
1635
1636 VgaConsoleRepaintScreen(&UpdateRectangle);
1637
1638 /* Clear the update flag */
1639 NeedsUpdate = FALSE;
1640 }
1641
1642 static VOID FASTCALL VgaHorizontalRetrace(ULONGLONG ElapsedTime)
1643 {
1644 UNREFERENCED_PARAMETER(ElapsedTime);
1645
1646 /* Set the cycle */
1647 HorizontalRetraceCycle = GetCycleCount();
1648 }
1649
1650 /* PUBLIC FUNCTIONS ***********************************************************/
1651
1652 COORD VgaGetDisplayResolution(VOID)
1653 {
1654 COORD Resolution;
1655 BYTE MaximumScanLine = 1 + (VgaCrtcRegisters[VGA_CRTC_MAX_SCAN_LINE_REG] & 0x1F);
1656
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];
1660
1661 /* Set the top bits from the overflow register */
1662 if (VgaCrtcRegisters[VGA_CRTC_OVERFLOW_REG] & VGA_CRTC_OVERFLOW_VDE8)
1663 {
1664 Resolution.Y |= 1 << 8;
1665 }
1666 if (VgaCrtcRegisters[VGA_CRTC_OVERFLOW_REG] & VGA_CRTC_OVERFLOW_VDE9)
1667 {
1668 Resolution.Y |= 1 << 9;
1669 }
1670
1671 /* Increase the values by 1 */
1672 Resolution.X++;
1673 Resolution.Y++;
1674
1675 if (VgaGcRegisters[VGA_GC_MISC_REG] & VGA_GC_MISC_NOALPHA)
1676 {
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)
1679 {
1680 Resolution.X *= 8;
1681 }
1682 else
1683 {
1684 /* Multiply the horizontal resolution by the 9/8 dot mode */
1685 Resolution.X *= (VgaSeqRegisters[VGA_SEQ_CLOCK_REG] & VGA_SEQ_CLOCK_98DM)
1686 ? 8 : 9;
1687
1688 /* The horizontal resolution is halved in 8-bit mode */
1689 if (VgaAcRegisters[VGA_AC_CONTROL_REG] & VGA_AC_CONTROL_8BIT) Resolution.X /= 2;
1690 }
1691 }
1692
1693 if (VgaCrtcRegisters[VGA_CRTC_MAX_SCAN_LINE_REG] & VGA_CRTC_MAXSCANLINE_DOUBLE)
1694 {
1695 /* Halve the vertical resolution */
1696 Resolution.Y >>= 1;
1697 }
1698 else
1699 {
1700 /* Divide the vertical resolution by the maximum scan line (== font size in text mode) */
1701 Resolution.Y /= MaximumScanLine;
1702 }
1703
1704 /* Return the resolution */
1705 return Resolution;
1706 }
1707
1708 VOID VgaRefreshDisplay(VOID)
1709 {
1710 VgaVerticalRetrace(0);
1711 }
1712
1713 VOID FASTCALL VgaReadMemory(ULONG Address, PVOID Buffer, ULONG Size)
1714 {
1715 DWORD i, j;
1716 DWORD VideoAddress;
1717 PUCHAR BufPtr = (PUCHAR)Buffer;
1718
1719 DPRINT("VgaReadMemory: Address 0x%08X, Size %lu\n", Address, Size);
1720
1721 /* Ignore if video RAM access is disabled */
1722 if ((VgaMiscRegister & VGA_MISC_RAM_ENABLED) == 0) return;
1723
1724 if (!(VgaGcRegisters[VGA_GC_MODE_REG] & VGA_GC_MODE_READ))
1725 {
1726 /* Loop through each byte */
1727 for (i = 0; i < Size; i++)
1728 {
1729 VideoAddress = VgaTranslateReadAddress(Address + i);
1730
1731 /* Copy the value to the buffer */
1732 BufPtr[i] = VgaMemory[VideoAddress];
1733 }
1734 }
1735 else
1736 {
1737 /* Loop through each byte */
1738 for (i = 0; i < Size; i++)
1739 {
1740 BYTE Result = 0xFF;
1741
1742 /* This should always return a plane 0 address for read mode 1 */
1743 VideoAddress = VgaTranslateReadAddress(Address + i);
1744
1745 for (j = 0; j < VGA_NUM_BANKS; j++)
1746 {
1747 /* Don't consider ignored banks */
1748 if (!(VgaGcRegisters[VGA_GC_COLOR_IGNORE_REG] & (1 << j))) continue;
1749
1750 if (VgaGcRegisters[VGA_GC_COLOR_COMPARE_REG] & (1 << j))
1751 {
1752 /* Comparing with 11111111 */
1753 Result &= VgaMemory[j * VGA_BANK_SIZE + LOWORD(VideoAddress)];
1754 }
1755 else
1756 {
1757 /* Comparing with 00000000 */
1758 Result &= ~(VgaMemory[j * VGA_BANK_SIZE + LOWORD(VideoAddress)]);
1759 }
1760 }
1761
1762 /* Copy the value to the buffer */
1763 BufPtr[i] = Result;
1764 }
1765 }
1766
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)];
1772 }
1773
1774 BOOLEAN FASTCALL VgaWriteMemory(ULONG Address, PVOID Buffer, ULONG Size)
1775 {
1776 DWORD i, j;
1777 DWORD VideoAddress;
1778 PUCHAR BufPtr = (PUCHAR)Buffer;
1779
1780 DPRINT("VgaWriteMemory: Address 0x%08X, Size %lu\n", Address, Size);
1781
1782 /* Ignore if video RAM access is disabled */
1783 if ((VgaMiscRegister & VGA_MISC_RAM_ENABLED) == 0) return TRUE;
1784
1785 /* Also ignore if write access to all planes is disabled */
1786 if ((VgaSeqRegisters[VGA_SEQ_MASK_REG] & 0x0F) == 0x00) return TRUE;
1787
1788 /* Loop through each byte */
1789 for (i = 0; i < Size; i++)
1790 {
1791 VideoAddress = VgaTranslateWriteAddress(Address + i);
1792
1793 for (j = 0; j < VGA_NUM_BANKS; j++)
1794 {
1795 /* Make sure the page is writeable */
1796 if (!(VgaSeqRegisters[VGA_SEQ_MASK_REG] & (1 << j))) continue;
1797
1798 /* Check if this is chain-4 mode */
1799 if (VgaSeqRegisters[VGA_SEQ_MEM_REG] & VGA_SEQ_MEM_C4)
1800 {
1801 if (((Address + i) & 0x03) != j)
1802 {
1803 /* This plane will not be accessed */
1804 continue;
1805 }
1806 }
1807
1808 /* Check if this is odd-even mode */
1809 if (VgaGcRegisters[VGA_GC_MODE_REG] & VGA_GC_MODE_OE)
1810 {
1811 if (((Address + i) & 0x01) != (j & 1))
1812 {
1813 /* This plane will not be accessed */
1814 continue;
1815 }
1816 }
1817
1818 /* Copy the value to the VGA memory */
1819 VgaMemory[VideoAddress + j * VGA_BANK_SIZE] = VgaTranslateByteForWriting(BufPtr[i], j);
1820 }
1821 }
1822
1823 return TRUE;
1824 }
1825
1826 VOID VgaClearMemory(VOID)
1827 {
1828 RtlZeroMemory(VgaMemory, sizeof(VgaMemory));
1829 }
1830
1831 VOID VgaWriteTextModeFont(UINT FontNumber, CONST UCHAR* FontData, UINT Height)
1832 {
1833 UINT i, j;
1834 PUCHAR FontMemory = (PUCHAR)&VgaMemory[VGA_BANK_SIZE * VGA_FONT_BANK + (FontNumber * VGA_FONT_SIZE)];
1835
1836 ASSERT(Height <= VGA_MAX_FONT_HEIGHT);
1837
1838 for (i = 0 ; i < VGA_FONT_CHARACTERS; i++)
1839 {
1840 /* Write the character */
1841 for (j = 0; j < Height; j++)
1842 {
1843 FontMemory[i * VGA_MAX_FONT_HEIGHT + j] = FontData[i * Height + j];
1844 }
1845
1846 /* Clear the unused part */
1847 for (j = Height; j < VGA_MAX_FONT_HEIGHT; j++)
1848 {
1849 FontMemory[i * VGA_MAX_FONT_HEIGHT + j] = 0;
1850 }
1851 }
1852 }
1853
1854 BOOLEAN VgaInitialize(HANDLE TextHandle)
1855 {
1856 if (!VgaConsoleInitialize(TextHandle)) return FALSE;
1857
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 ));
1863
1864 /* Initialize the VGA palette and fail if it isn't successfully created */
1865 if (!VgaInitializePalette()) return FALSE;
1866 /***/ VgaResetPalette(); /***/
1867
1868 /* Reset the sequencer */
1869 VgaResetSequencer();
1870
1871 /* Clear the VGA memory */
1872 VgaClearMemory();
1873
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
1888
1889 /* CGA ports for compatibility, unimplemented */
1890 RegisterIoPort(0x3D8, VgaReadPort, VgaWritePort); // CGA_MODE_CTRL_REG
1891 RegisterIoPort(0x3D9, VgaReadPort, VgaWritePort); // CGA_PAL_CTRL_REG
1892
1893 HSyncTimer = CreateHardwareTimer(HARDWARE_TIMER_ENABLED, HZ_TO_NS(31469), VgaHorizontalRetrace);
1894 VSyncTimer = CreateHardwareTimer(HARDWARE_TIMER_ENABLED, HZ_TO_NS(60), VgaVerticalRetrace);
1895
1896 /* Return success */
1897 return TRUE;
1898 }
1899
1900 VOID VgaCleanup(VOID)
1901 {
1902 /* Do a final display refresh */
1903 VgaRefreshDisplay();
1904
1905 DestroyHardwareTimer(VSyncTimer);
1906 DestroyHardwareTimer(HSyncTimer);
1907
1908 /* Leave the current video mode */
1909 VgaLeaveCurrentMode(); // ScreenMode
1910
1911 MemRemoveFastMemoryHook((PVOID)0xA0000, 0x20000);
1912
1913 VgaConsoleCleanup();
1914 }
1915
1916 /* EOF */