ab4423d32f3a029345d86fed3077e5585893ca63
[reactos.git] / subsystems / ntvdm / hardware / vga.c
1 /*
2 * COPYRIGHT: GPL - See COPYING in the top level directory
3 * PROJECT: ReactOS Virtual DOS Machine
4 * FILE: vga.c
5 * PURPOSE: VGA hardware emulation
6 * PROGRAMMERS: Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
7 */
8
9 /* INCLUDES *******************************************************************/
10
11 #define NDEBUG
12
13 #include "emulator.h"
14 #include "vga.h"
15
16 #include "io.h"
17
18 /* PRIVATE VARIABLES **********************************************************/
19
20 static CONST DWORD MemoryBase[] = { 0xA0000, 0xA0000, 0xB0000, 0xB8000 };
21 static CONST DWORD MemoryLimit[] = { 0xAFFFF, 0xAFFFF, 0xB7FFF, 0xBFFFF };
22
23 #define USE_REACTOS_COLORS
24 // #define USE_DOSBOX_COLORS
25
26 #if defined(USE_REACTOS_COLORS)
27
28 // ReactOS colors
29 static CONST COLORREF VgaDefaultPalette[VGA_MAX_COLORS] =
30 {
31 RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0xAA), RGB(0x00, 0xAA, 0x00), RGB(0x00, 0xAA, 0xAA),
32 RGB(0xAA, 0x00, 0x00), RGB(0xAA, 0x00, 0xAA), RGB(0xAA, 0x55, 0x00), RGB(0xAA, 0xAA, 0xAA),
33 RGB(0x55, 0x55, 0x55), RGB(0x55, 0x55, 0xFF), RGB(0x55, 0xFF, 0x55), RGB(0x55, 0xFF, 0xFF),
34 RGB(0xFF, 0x55, 0x55), RGB(0xFF, 0x55, 0xFF), RGB(0xFF, 0xFF, 0x55), RGB(0xFF, 0xFF, 0xFF),
35 RGB(0x00, 0x00, 0x00), RGB(0x10, 0x10, 0x10), RGB(0x20, 0x20, 0x20), RGB(0x35, 0x35, 0x35),
36 RGB(0x45, 0x45, 0x45), RGB(0x55, 0x55, 0x55), RGB(0x65, 0x65, 0x65), RGB(0x75, 0x75, 0x75),
37 RGB(0x8A, 0x8A, 0x8A), RGB(0x9A, 0x9A, 0x9A), RGB(0xAA, 0xAA, 0xAA), RGB(0xBA, 0xBA, 0xBA),
38 RGB(0xCA, 0xCA, 0xCA), RGB(0xDF, 0xDF, 0xDF), RGB(0xEF, 0xEF, 0xEF), RGB(0xFF, 0xFF, 0xFF),
39 RGB(0x00, 0x00, 0xFF), RGB(0x41, 0x00, 0xFF), RGB(0x82, 0x00, 0xFF), RGB(0xBE, 0x00, 0xFF),
40 RGB(0xFF, 0x00, 0xFF), RGB(0xFF, 0x00, 0xBE), RGB(0xFF, 0x00, 0x82), RGB(0xFF, 0x00, 0x41),
41 RGB(0xFF, 0x00, 0x00), RGB(0xFF, 0x41, 0x00), RGB(0xFF, 0x82, 0x00), RGB(0xFF, 0xBE, 0x00),
42 RGB(0xFF, 0xFF, 0x00), RGB(0xBE, 0xFF, 0x00), RGB(0x82, 0xFF, 0x00), RGB(0x41, 0xFF, 0x00),
43 RGB(0x00, 0xFF, 0x00), RGB(0x00, 0xFF, 0x41), RGB(0x00, 0xFF, 0x82), RGB(0x00, 0xFF, 0xBE),
44 RGB(0x00, 0xFF, 0xFF), RGB(0x00, 0xBE, 0xFF), RGB(0x00, 0x82, 0xFF), RGB(0x00, 0x41, 0xFF),
45 RGB(0x82, 0x82, 0xFF), RGB(0x9E, 0x82, 0xFF), RGB(0xBE, 0x82, 0xFF), RGB(0xDF, 0x82, 0xFF),
46 RGB(0xFF, 0x82, 0xFF), RGB(0xFF, 0x82, 0xDF), RGB(0xFF, 0x82, 0xBE), RGB(0xFF, 0x82, 0x9E),
47 RGB(0xFF, 0x82, 0x82), RGB(0xFF, 0x9E, 0x82), RGB(0xFF, 0xBE, 0x82), RGB(0xFF, 0xDF, 0x82),
48 RGB(0xFF, 0xFF, 0x82), RGB(0xDF, 0xFF, 0x82), RGB(0xBE, 0xFF, 0x82), RGB(0x9E, 0xFF, 0x82),
49 RGB(0x82, 0xFF, 0x82), RGB(0x82, 0xFF, 0x9E), RGB(0x82, 0xFF, 0xBE), RGB(0x82, 0xFF, 0xDF),
50 RGB(0x82, 0xFF, 0xFF), RGB(0x82, 0xDF, 0xFF), RGB(0x82, 0xBE, 0xFF), RGB(0x82, 0x9E, 0xFF),
51 RGB(0xBA, 0xBA, 0xFF), RGB(0xCA, 0xBA, 0xFF), RGB(0xDF, 0xBA, 0xFF), RGB(0xEF, 0xBA, 0xFF),
52 RGB(0xFF, 0xBA, 0xFF), RGB(0xFF, 0xBA, 0xEF), RGB(0xFF, 0xBA, 0xDF), RGB(0xFF, 0xBA, 0xCA),
53 RGB(0xFF, 0xBA, 0xBA), RGB(0xFF, 0xCA, 0xBA), RGB(0xFF, 0xDF, 0xBA), RGB(0xFF, 0xEF, 0xBA),
54 RGB(0xFF, 0xFF, 0xBA), RGB(0xEF, 0xFF, 0xBA), RGB(0xDF, 0xFF, 0xBA), RGB(0xCA, 0xFF, 0xBA),
55 RGB(0xBA, 0xFF, 0xBA), RGB(0xBA, 0xFF, 0xCA), RGB(0xBA, 0xFF, 0xDF), RGB(0xBA, 0xFF, 0xEF),
56 RGB(0xBA, 0xFF, 0xFF), RGB(0xBA, 0xEF, 0xFF), RGB(0xBA, 0xDF, 0xFF), RGB(0xBA, 0xCA, 0xFF),
57 RGB(0x00, 0x00, 0x71), RGB(0x1C, 0x00, 0x71), RGB(0x39, 0x00, 0x71), RGB(0x55, 0x00, 0x71),
58 RGB(0x71, 0x00, 0x71), RGB(0x71, 0x00, 0x55), RGB(0x71, 0x00, 0x39), RGB(0x71, 0x00, 0x1C),
59 RGB(0x71, 0x00, 0x00), RGB(0x71, 0x1C, 0x00), RGB(0x71, 0x39, 0x00), RGB(0x71, 0x55, 0x00),
60 RGB(0x71, 0x71, 0x00), RGB(0x55, 0x71, 0x00), RGB(0x39, 0x71, 0x00), RGB(0x1C, 0x71, 0x00),
61 RGB(0x00, 0x71, 0x00), RGB(0x00, 0x71, 0x1C), RGB(0x00, 0x71, 0x39), RGB(0x00, 0x71, 0x55),
62 RGB(0x00, 0x71, 0x71), RGB(0x00, 0x55, 0x71), RGB(0x00, 0x39, 0x71), RGB(0x00, 0x1C, 0x71),
63 RGB(0x39, 0x39, 0x71), RGB(0x45, 0x39, 0x71), RGB(0x55, 0x39, 0x71), RGB(0x61, 0x39, 0x71),
64 RGB(0x71, 0x39, 0x71), RGB(0x71, 0x39, 0x61), RGB(0x71, 0x39, 0x55), RGB(0x71, 0x39, 0x45),
65 RGB(0x71, 0x39, 0x39), RGB(0x71, 0x45, 0x39), RGB(0x71, 0x55, 0x39), RGB(0x71, 0x61, 0x39),
66 RGB(0x71, 0x71, 0x39), RGB(0x61, 0x71, 0x39), RGB(0x55, 0x71, 0x39), RGB(0x45, 0x71, 0x39),
67 RGB(0x39, 0x71, 0x39), RGB(0x39, 0x71, 0x45), RGB(0x39, 0x71, 0x55), RGB(0x39, 0x71, 0x61),
68 RGB(0x39, 0x71, 0x71), RGB(0x39, 0x61, 0x71), RGB(0x39, 0x55, 0x71), RGB(0x39, 0x45, 0x71),
69 RGB(0x51, 0x51, 0x71), RGB(0x59, 0x51, 0x71), RGB(0x61, 0x51, 0x71), RGB(0x69, 0x51, 0x71),
70 RGB(0x71, 0x51, 0x71), RGB(0x71, 0x51, 0x69), RGB(0x71, 0x51, 0x61), RGB(0x71, 0x51, 0x59),
71 RGB(0x71, 0x51, 0x51), RGB(0x71, 0x59, 0x51), RGB(0x71, 0x61, 0x51), RGB(0x71, 0x69, 0x51),
72 RGB(0x71, 0x71, 0x51), RGB(0x69, 0x71, 0x51), RGB(0x61, 0x71, 0x51), RGB(0x59, 0x71, 0x51),
73 RGB(0x51, 0x71, 0x51), RGB(0x51, 0x71, 0x59), RGB(0x51, 0x71, 0x61), RGB(0x51, 0x71, 0x69),
74 RGB(0x51, 0x71, 0x71), RGB(0x51, 0x69, 0x71), RGB(0x51, 0x61, 0x71), RGB(0x51, 0x59, 0x71),
75 RGB(0x00, 0x00, 0x41), RGB(0x10, 0x00, 0x41), RGB(0x20, 0x00, 0x41), RGB(0x31, 0x00, 0x41),
76 RGB(0x41, 0x00, 0x41), RGB(0x41, 0x00, 0x31), RGB(0x41, 0x00, 0x20), RGB(0x41, 0x00, 0x10),
77 RGB(0x41, 0x00, 0x00), RGB(0x41, 0x10, 0x00), RGB(0x41, 0x20, 0x00), RGB(0x41, 0x31, 0x00),
78 RGB(0x41, 0x41, 0x00), RGB(0x31, 0x41, 0x00), RGB(0x20, 0x41, 0x00), RGB(0x10, 0x41, 0x00),
79 RGB(0x00, 0x41, 0x00), RGB(0x00, 0x41, 0x10), RGB(0x00, 0x41, 0x20), RGB(0x00, 0x41, 0x31),
80 RGB(0x00, 0x41, 0x41), RGB(0x00, 0x31, 0x41), RGB(0x00, 0x20, 0x41), RGB(0x00, 0x10, 0x41),
81 RGB(0x20, 0x20, 0x41), RGB(0x28, 0x20, 0x41), RGB(0x31, 0x20, 0x41), RGB(0x39, 0x20, 0x41),
82 RGB(0x41, 0x20, 0x41), RGB(0x41, 0x20, 0x39), RGB(0x41, 0x20, 0x31), RGB(0x41, 0x20, 0x28),
83 RGB(0x41, 0x20, 0x20), RGB(0x41, 0x28, 0x20), RGB(0x41, 0x31, 0x20), RGB(0x41, 0x39, 0x20),
84 RGB(0x41, 0x41, 0x20), RGB(0x39, 0x41, 0x20), RGB(0x31, 0x41, 0x20), RGB(0x28, 0x41, 0x20),
85 RGB(0x20, 0x41, 0x20), RGB(0x20, 0x41, 0x28), RGB(0x20, 0x41, 0x31), RGB(0x20, 0x41, 0x39),
86 RGB(0x20, 0x41, 0x41), RGB(0x20, 0x39, 0x41), RGB(0x20, 0x31, 0x41), RGB(0x20, 0x28, 0x41),
87 RGB(0x2D, 0x2D, 0x41), RGB(0x31, 0x2D, 0x41), RGB(0x35, 0x2D, 0x41), RGB(0x3D, 0x2D, 0x41),
88 RGB(0x41, 0x2D, 0x41), RGB(0x41, 0x2D, 0x3D), RGB(0x41, 0x2D, 0x35), RGB(0x41, 0x2D, 0x31),
89 RGB(0x41, 0x2D, 0x2D), RGB(0x41, 0x31, 0x2D), RGB(0x41, 0x35, 0x2D), RGB(0x41, 0x3D, 0x2D),
90 RGB(0x41, 0x41, 0x2D), RGB(0x3D, 0x41, 0x2D), RGB(0x35, 0x41, 0x2D), RGB(0x31, 0x41, 0x2D),
91 RGB(0x2D, 0x41, 0x2D), RGB(0x2D, 0x41, 0x31), RGB(0x2D, 0x41, 0x35), RGB(0x2D, 0x41, 0x3D),
92 RGB(0x2D, 0x41, 0x41), RGB(0x2D, 0x3D, 0x41), RGB(0x2D, 0x35, 0x41), RGB(0x2D, 0x31, 0x41),
93 RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00),
94 RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00)
95 };
96
97 #elif defined(USE_DOSBOX_COLORS)
98
99 // DOSBox colors
100 static CONST COLORREF VgaDefaultPalette[VGA_MAX_COLORS] =
101 {
102 RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0xAA), RGB(0x00, 0xAA, 0x00), RGB(0x00, 0xAA, 0xAA),
103 RGB(0xAA, 0x00, 0x00), RGB(0xAA, 0x00, 0xAA), RGB(0xAA, 0x55, 0x00), RGB(0xAA, 0xAA, 0xAA),
104 RGB(0x55, 0x55, 0x55), RGB(0x55, 0x55, 0xFF), RGB(0x55, 0xFF, 0x55), RGB(0x55, 0xFF, 0xFF),
105 RGB(0xFF, 0x55, 0x55), RGB(0xFF, 0x55, 0xFF), RGB(0xFF, 0xFF, 0x55), RGB(0xFF, 0xFF, 0xFF),
106 RGB(0x00, 0x00, 0x00), RGB(0x14, 0x14, 0x14), RGB(0x20, 0x20, 0x20), RGB(0x2C, 0x2C, 0x2C),
107 RGB(0x38, 0x38, 0x38), RGB(0x45, 0x45, 0x45), RGB(0x51, 0x51, 0x51), RGB(0x61, 0x61, 0x61),
108 RGB(0x71, 0x71, 0x71), RGB(0x82, 0x82, 0x82), RGB(0x92, 0x92, 0x92), RGB(0xA2, 0xA2, 0xA2),
109 RGB(0xB6, 0xB6, 0xB6), RGB(0xCB, 0xCB, 0xCB), RGB(0xE3, 0xE3, 0xE3), RGB(0xFF, 0xFF, 0xFF),
110 RGB(0x00, 0x00, 0xFF), RGB(0x41, 0x00, 0xFF), RGB(0x7D, 0x00, 0xFF), RGB(0xBE, 0x00, 0xFF),
111 RGB(0xFF, 0x00, 0xFF), RGB(0xFF, 0x00, 0xBE), RGB(0xFF, 0x00, 0x7D), RGB(0xFF, 0x00, 0x41),
112 RGB(0xFF, 0x00, 0x00), RGB(0xFF, 0x41, 0x00), RGB(0xFF, 0x7D, 0x00), RGB(0xFF, 0xBE, 0x00),
113 RGB(0xFF, 0xFF, 0x00), RGB(0xBE, 0xFF, 0x00), RGB(0x7D, 0xFF, 0x00), RGB(0x41, 0xFF, 0x00),
114 RGB(0x00, 0xFF, 0x00), RGB(0x00, 0xFF, 0x41), RGB(0x00, 0xFF, 0x7D), RGB(0x00, 0xFF, 0xBE),
115 RGB(0x00, 0xFF, 0xFF), RGB(0x00, 0xBE, 0xFF), RGB(0x00, 0x7D, 0xFF), RGB(0x00, 0x41, 0xFF),
116 RGB(0x7D, 0x7D, 0xFF), RGB(0x9E, 0x7D, 0xFF), RGB(0xBE, 0x7D, 0xFF), RGB(0xDF, 0x7D, 0xFF),
117 RGB(0xFF, 0x7D, 0xFF), RGB(0xFF, 0x7D, 0xDF), RGB(0xFF, 0x7D, 0xBE), RGB(0xFF, 0x7D, 0x9E),
118
119 RGB(0xFF, 0x7D, 0x7D), RGB(0xFF, 0x9E, 0x7D), RGB(0xFF, 0xBE, 0x7D), RGB(0xFF, 0xDF, 0x7D),
120 RGB(0xFF, 0xFF, 0x7D), RGB(0xDF, 0xFF, 0x7D), RGB(0xBE, 0xFF, 0x7D), RGB(0x9E, 0xFF, 0x7D),
121 RGB(0x7D, 0xFF, 0x7D), RGB(0x7D, 0xFF, 0x9E), RGB(0x7D, 0xFF, 0xBE), RGB(0x7D, 0xFF, 0xDF),
122 RGB(0x7D, 0xFF, 0xFF), RGB(0x7D, 0xDF, 0xFF), RGB(0x7D, 0xBE, 0xFF), RGB(0x7D, 0x9E, 0xFF),
123 RGB(0xB6, 0xB6, 0xFF), RGB(0xC7, 0xB6, 0xFF), RGB(0xDB, 0xB6, 0xFF), RGB(0xEB, 0xB6, 0xFF),
124 RGB(0xFF, 0xB6, 0xFF), RGB(0xFF, 0xB6, 0xEB), RGB(0xFF, 0xB6, 0xDB), RGB(0xFF, 0xB6, 0xC7),
125 RGB(0xFF, 0xB6, 0xB6), RGB(0xFF, 0xC7, 0xB6), RGB(0xFF, 0xDB, 0xB6), RGB(0xFF, 0xEB, 0xB6),
126 RGB(0xFF, 0xFF, 0xB6), RGB(0xEB, 0xFF, 0xB6), RGB(0xDB, 0xFF, 0xB6), RGB(0xC7, 0xFF, 0xB6),
127 RGB(0xB6, 0xFF, 0xB6), RGB(0xB6, 0xFF, 0xC7), RGB(0xB6, 0xFF, 0xDB), RGB(0xB6, 0xFF, 0xEB),
128 RGB(0xB6, 0xFF, 0xFF), RGB(0xB6, 0xEB, 0xFF), RGB(0xB6, 0xDB, 0xFF), RGB(0xB6, 0xC7, 0xFF),
129 RGB(0x00, 0x00, 0x71), RGB(0x1C, 0x00, 0x71), RGB(0x38, 0x00, 0x71), RGB(0x55, 0x00, 0x71),
130 RGB(0x71, 0x00, 0x71), RGB(0x71, 0x00, 0x55), RGB(0x71, 0x00, 0x38), RGB(0x71, 0x00, 0x1C),
131 RGB(0x71, 0x00, 0x00), RGB(0x71, 0x1C, 0x00), RGB(0x71, 0x38, 0x00), RGB(0x71, 0x55, 0x00),
132 RGB(0x71, 0x71, 0x00), RGB(0x55, 0x71, 0x00), RGB(0x38, 0x71, 0x00), RGB(0x1C, 0x71, 0x00),
133 RGB(0x00, 0x71, 0x00), RGB(0x00, 0x71, 0x1C), RGB(0x00, 0x71, 0x38), RGB(0x00, 0x71, 0x55),
134 RGB(0x00, 0x71, 0x71), RGB(0x00, 0x55, 0x71), RGB(0x00, 0x38, 0x71), RGB(0x00, 0x1C, 0x71),
135
136 RGB(0x38, 0x38, 0x71), RGB(0x45, 0x38, 0x71), RGB(0x55, 0x38, 0x71), RGB(0x61, 0x38, 0x71),
137 RGB(0x71, 0x38, 0x71), RGB(0x71, 0x38, 0x61), RGB(0x71, 0x38, 0x55), RGB(0x71, 0x38, 0x45),
138 RGB(0x71, 0x38, 0x38), RGB(0x71, 0x45, 0x38), RGB(0x71, 0x55, 0x38), RGB(0x71, 0x61, 0x38),
139 RGB(0x71, 0x71, 0x38), RGB(0x61, 0x71, 0x38), RGB(0x55, 0x71, 0x38), RGB(0x45, 0x71, 0x38),
140 RGB(0x38, 0x71, 0x38), RGB(0x38, 0x71, 0x45), RGB(0x38, 0x71, 0x55), RGB(0x38, 0x71, 0x61),
141 RGB(0x38, 0x71, 0x71), RGB(0x38, 0x61, 0x71), RGB(0x38, 0x55, 0x71), RGB(0x38, 0x45, 0x71),
142 RGB(0x51, 0x51, 0x71), RGB(0x59, 0x51, 0x71), RGB(0x61, 0x51, 0x71), RGB(0x69, 0x51, 0x71),
143 RGB(0x71, 0x51, 0x71), RGB(0x71, 0x51, 0x69), RGB(0x71, 0x51, 0x61), RGB(0x71, 0x51, 0x59),
144 RGB(0x71, 0x51, 0x51), RGB(0x71, 0x59, 0x51), RGB(0x71, 0x61, 0x51), RGB(0x71, 0x69, 0x51),
145 RGB(0x71, 0x71, 0x51), RGB(0x69, 0x71, 0x51), RGB(0x61, 0x71, 0x51), RGB(0x59, 0x71, 0x51),
146 RGB(0x51, 0x71, 0x51), RGB(0x51, 0x71, 0x59), RGB(0x51, 0x71, 0x61), RGB(0x51, 0x71, 0x69),
147 RGB(0x51, 0x71, 0x71), RGB(0x51, 0x69, 0x71), RGB(0x51, 0x61, 0x71), RGB(0x51, 0x59, 0x71),
148 RGB(0x00, 0x00, 0x41), RGB(0x10, 0x00, 0x41), RGB(0x20, 0x00, 0x41), RGB(0x30, 0x00, 0x41),
149 RGB(0x41, 0x00, 0x41), RGB(0x41, 0x00, 0x30), RGB(0x41, 0x00, 0x20), RGB(0x41, 0x00, 0x10),
150 RGB(0x41, 0x00, 0x00), RGB(0x41, 0x10, 0x00), RGB(0x41, 0x20, 0x00), RGB(0x41, 0x30, 0x00),
151 RGB(0x41, 0x41, 0x00), RGB(0x30, 0x41, 0x00), RGB(0x20, 0x41, 0x00), RGB(0x10, 0x41, 0x00),
152
153 RGB(0x00, 0x41, 0x00), RGB(0x00, 0x41, 0x10), RGB(0x00, 0x41, 0x20), RGB(0x00, 0x41, 0x30),
154 RGB(0x00, 0x41, 0x41), RGB(0x00, 0x30, 0x41), RGB(0x00, 0x20, 0x41), RGB(0x00, 0x10, 0x41),
155 RGB(0x20, 0x20, 0x41), RGB(0x28, 0x20, 0x41), RGB(0x30, 0x20, 0x41), RGB(0x38, 0x20, 0x41),
156 RGB(0x41, 0x20, 0x41), RGB(0x41, 0x20, 0x38), RGB(0x41, 0x20, 0x30), RGB(0x41, 0x20, 0x28),
157 RGB(0x41, 0x20, 0x20), RGB(0x41, 0x28, 0x20), RGB(0x41, 0x30, 0x20), RGB(0x41, 0x38, 0x20),
158 RGB(0x41, 0x41, 0x20), RGB(0x38, 0x41, 0x20), RGB(0x30, 0x41, 0x20), RGB(0x28, 0x41, 0x20),
159 RGB(0x20, 0x41, 0x20), RGB(0x20, 0x41, 0x28), RGB(0x20, 0x41, 0x30), RGB(0x20, 0x41, 0x38),
160 RGB(0x20, 0x41, 0x41), RGB(0x20, 0x38, 0x41), RGB(0x20, 0x30, 0x41), RGB(0x20, 0x28, 0x41),
161 RGB(0x2C, 0x2C, 0x41), RGB(0x30, 0x2C, 0x41), RGB(0x34, 0x2C, 0x41), RGB(0x3C, 0x2C, 0x41),
162 RGB(0x41, 0x2C, 0x41), RGB(0x41, 0x2C, 0x3C), RGB(0x41, 0x2C, 0x34), RGB(0x41, 0x2C, 0x30),
163 RGB(0x41, 0x2C, 0x2C), RGB(0x41, 0x30, 0x2C), RGB(0x41, 0x34, 0x2C), RGB(0x41, 0x3C, 0x2C),
164 RGB(0x41, 0x41, 0x2C), RGB(0x3C, 0x41, 0x2C), RGB(0x34, 0x41, 0x2C), RGB(0x30, 0x41, 0x2C),
165 RGB(0x2C, 0x41, 0x2C), RGB(0x2C, 0x41, 0x30), RGB(0x2C, 0x41, 0x34), RGB(0x2C, 0x41, 0x3C),
166 RGB(0x2C, 0x41, 0x41), RGB(0x2C, 0x3C, 0x41), RGB(0x2C, 0x34, 0x41), RGB(0x2C, 0x30, 0x41),
167 RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00),
168 RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00)
169 };
170
171 #endif
172
173 static CONSOLE_SCREEN_BUFFER_INFO ConsoleInfo;
174
175 static BYTE VgaMemory[VGA_NUM_BANKS * VGA_BANK_SIZE];
176 static LPVOID ConsoleFramebuffer = NULL;
177 static HANDLE TextConsoleBuffer = NULL;
178 static HANDLE GraphicsConsoleBuffer = NULL;
179 static HANDLE ConsoleMutex = NULL;
180 static HPALETTE PaletteHandle = NULL;
181 static BOOLEAN DoubleVision = FALSE;
182
183 static BYTE VgaLatchRegisters[VGA_NUM_BANKS] = {0, 0, 0, 0};
184
185 static BYTE VgaMiscRegister;
186 static BYTE VgaFeatureRegister;
187
188 static BYTE VgaSeqIndex = VGA_SEQ_RESET_REG;
189 static BYTE VgaSeqRegisters[VGA_SEQ_MAX_REG];
190
191 static BYTE VgaCrtcIndex = VGA_CRTC_HORZ_TOTAL_REG;
192 static BYTE VgaCrtcRegisters[VGA_CRTC_MAX_REG];
193
194 static BYTE VgaGcIndex = VGA_GC_RESET_REG;
195 static BYTE VgaGcRegisters[VGA_GC_MAX_REG];
196
197 static BOOLEAN VgaAcLatch = FALSE;
198 static BOOLEAN VgaAcPalDisable = TRUE;
199 static BYTE VgaAcIndex = VGA_AC_PAL_0_REG;
200 static BYTE VgaAcRegisters[VGA_AC_MAX_REG];
201
202 // static VGA_REGISTERS VgaRegisters;
203
204 static BYTE VgaDacMask = 0xFF;
205 static WORD VgaDacIndex = 0;
206 static BOOLEAN VgaDacReadWrite = FALSE;
207 static BYTE VgaDacRegisters[VGA_PALETTE_SIZE];
208
209 static BOOLEAN InVerticalRetrace = FALSE;
210 static BOOLEAN InHorizontalRetrace = FALSE;
211
212 static BOOLEAN NeedsUpdate = FALSE;
213 static BOOLEAN ModeChanged = TRUE;
214 static BOOLEAN CursorMoved = FALSE;
215 static BOOLEAN PaletteChanged = FALSE;
216
217 static
218 enum SCREEN_MODE
219 {
220 TEXT_MODE,
221 GRAPHICS_MODE
222 } ScreenMode = TEXT_MODE;
223
224 static SMALL_RECT UpdateRectangle = { 0, 0, 0, 0 };
225
226 /* PRIVATE FUNCTIONS **********************************************************/
227
228 static inline DWORD VgaGetAddressSize(VOID)
229 {
230 if (VgaCrtcRegisters[VGA_CRTC_UNDERLINE_REG] & VGA_CRTC_UNDERLINE_DWORD)
231 {
232 /* Double-word addressing */
233 return 4; // sizeof(DWORD)
234 }
235 else if (VgaCrtcRegisters[VGA_CRTC_MODE_CONTROL_REG] & VGA_CRTC_MODE_CONTROL_BYTE)
236 {
237 /* Byte addressing */
238 return 1; // sizeof(BYTE)
239 }
240 else
241 {
242 /* Word addressing */
243 return 2; // sizeof(WORD)
244 }
245 }
246
247 static inline DWORD VgaTranslateReadAddress(DWORD Address)
248 {
249 DWORD Offset = Address - VgaGetVideoBaseAddress();
250 BYTE Plane;
251
252 /* Check for chain-4 and odd-even mode */
253 if (VgaSeqRegisters[VGA_SEQ_MEM_REG] & VGA_SEQ_MEM_C4)
254 {
255 /* The lowest two bits are the plane number */
256 Plane = Offset & 3;
257 Offset >>= 2;
258 }
259 else if (VgaGcRegisters[VGA_GC_MODE_REG] & VGA_GC_MODE_OE)
260 {
261 /* The LSB is the plane number */
262 Plane = Offset & 1;
263 Offset >>= 1;
264 }
265 else
266 {
267 /* Use the read mode */
268 Plane = VgaGcRegisters[VGA_GC_READ_MAP_SEL_REG] & 0x03;
269 }
270
271 /* Multiply the offset by the address size */
272 Offset *= VgaGetAddressSize();
273
274 return Offset + Plane * VGA_BANK_SIZE;
275 }
276
277 static inline DWORD VgaTranslateWriteAddress(DWORD Address)
278 {
279 DWORD Offset = Address - VgaGetVideoBaseAddress();
280
281 /* Check for chain-4 and odd-even mode */
282 if (VgaSeqRegisters[VGA_SEQ_MEM_REG] & VGA_SEQ_MEM_C4)
283 {
284 /* Shift the offset to the right by 2 */
285 Offset >>= 2;
286 }
287 else if (VgaGcRegisters[VGA_GC_MODE_REG] & VGA_GC_MODE_OE)
288 {
289 /* Shift the offset to the right by 1 */
290 Offset >>= 1;
291 }
292
293 /* Multiply the offset by the address size */
294 Offset *= VgaGetAddressSize();
295
296 /* Return the offset on plane 0 */
297 return Offset;
298 }
299
300 static inline BYTE VgaTranslateByteForWriting(BYTE Data, BYTE Plane)
301 {
302 BYTE WriteMode = VgaGcRegisters[VGA_GC_MODE_REG] & 3;
303 BYTE BitMask = VgaGcRegisters[VGA_GC_BITMASK_REG];
304
305 if (WriteMode == 1)
306 {
307 /* In write mode 1 just return the latch register */
308 return VgaLatchRegisters[Plane];
309 }
310
311 if (WriteMode != 2)
312 {
313 /* Write modes 0 and 3 rotate the data to the right first */
314 BYTE RotateCount = VgaGcRegisters[VGA_GC_ROTATE_REG] & 7;
315 Data = LOBYTE(((DWORD)Data >> RotateCount) | ((DWORD)Data << (8 - RotateCount)));
316 }
317 else
318 {
319 /* Write mode 2 expands the appropriate bit to all 8 bits */
320 Data = (Data & (1 << Plane)) ? 0xFF : 0x00;
321 }
322
323 if (WriteMode == 0)
324 {
325 /*
326 * In write mode 0, the enable set/reset register decides if the
327 * set/reset bit should be expanded to all 8 bits.
328 */
329 if (VgaGcRegisters[VGA_GC_ENABLE_RESET_REG] & (1 << Plane))
330 {
331 /* Copy the bit from the set/reset register to all 8 bits */
332 Data = (VgaGcRegisters[VGA_GC_RESET_REG] & (1 << Plane)) ? 0xFF : 0x00;
333 }
334 }
335
336 if (WriteMode != 3)
337 {
338 /* Write modes 0 and 2 then perform a logical operation on the data and latch */
339 BYTE LogicalOperation = (VgaGcRegisters[VGA_GC_ROTATE_REG] >> 3) & 3;
340
341 if (LogicalOperation == 1) Data &= VgaLatchRegisters[Plane];
342 else if (LogicalOperation == 2) Data |= VgaLatchRegisters[Plane];
343 else if (LogicalOperation == 3) Data ^= VgaLatchRegisters[Plane];
344 }
345 else
346 {
347 /* For write mode 3, we AND the bitmask with the data, which is used as the new bitmask */
348 BitMask &= Data;
349
350 /* Then we expand the bit in the set/reset field */
351 Data = (VgaGcRegisters[VGA_GC_RESET_REG] & (1 << Plane)) ? 0xFF : 0x00;
352 }
353
354 /* Bits cleared in the bitmask are replaced with latch register bits */
355 Data = (Data & BitMask) | (VgaLatchRegisters[Plane] & (~BitMask));
356
357 /* Return the byte */
358 return Data;
359 }
360
361 static inline VOID VgaMarkForUpdate(SHORT Row, SHORT Column)
362 {
363 /* Check if this is the first time the rectangle is updated */
364 if (!NeedsUpdate)
365 {
366 UpdateRectangle.Left = UpdateRectangle.Top = MAXSHORT;
367 UpdateRectangle.Right = UpdateRectangle.Bottom = MINSHORT;
368 }
369
370 /* Expand the rectangle to include the point */
371 UpdateRectangle.Left = min(UpdateRectangle.Left, Column);
372 UpdateRectangle.Right = max(UpdateRectangle.Right, Column);
373 UpdateRectangle.Top = min(UpdateRectangle.Top, Row);
374 UpdateRectangle.Bottom = max(UpdateRectangle.Bottom, Row);
375
376 /* Set the update request flag */
377 NeedsUpdate = TRUE;
378 }
379
380 static VOID VgaWriteSequencer(BYTE Data)
381 {
382 ASSERT(VgaSeqIndex < VGA_SEQ_MAX_REG);
383
384 /* Save the value */
385 VgaSeqRegisters[VgaSeqIndex] = Data;
386 }
387
388 static VOID VgaWriteGc(BYTE Data)
389 {
390 ASSERT(VgaGcIndex < VGA_GC_MAX_REG);
391
392 /* Save the value */
393 VgaGcRegisters[VgaGcIndex] = Data;
394
395 /* Check the index */
396 switch (VgaGcIndex)
397 {
398 case VGA_GC_MISC_REG:
399 {
400 /* The GC misc register decides if it's text or graphics mode */
401 ModeChanged = TRUE;
402 break;
403 }
404 }
405 }
406
407 static VOID VgaWriteCrtc(BYTE Data)
408 {
409 ASSERT(VgaGcIndex < VGA_CRTC_MAX_REG);
410
411 /* Save the value */
412 VgaCrtcRegisters[VgaCrtcIndex] = Data;
413
414 /* Check the index */
415 switch (VgaCrtcIndex)
416 {
417 case VGA_CRTC_END_HORZ_DISP_REG:
418 case VGA_CRTC_VERT_DISP_END_REG:
419 case VGA_CRTC_OVERFLOW_REG:
420 {
421 /* The video mode has changed */
422 ModeChanged = TRUE;
423 break;
424 }
425
426 case VGA_CRTC_CURSOR_LOC_LOW_REG:
427 case VGA_CRTC_CURSOR_LOC_HIGH_REG:
428 case VGA_CRTC_CURSOR_START_REG:
429 case VGA_CRTC_CURSOR_END_REG:
430 {
431 /* Set the cursor moved flag */
432 CursorMoved = TRUE;
433 break;
434 }
435 }
436 }
437
438 static VOID VgaWriteDac(BYTE Data)
439 {
440 INT PaletteIndex;
441 PALETTEENTRY Entry;
442
443 /* Set the value */
444 VgaDacRegisters[VgaDacIndex] = Data;
445
446 /* Find the palette index */
447 PaletteIndex = VgaDacIndex / 3;
448
449 /* Fill the entry structure */
450 Entry.peRed = VGA_DAC_TO_COLOR(VgaDacRegisters[PaletteIndex * 3]);
451 Entry.peGreen = VGA_DAC_TO_COLOR(VgaDacRegisters[PaletteIndex * 3 + 1]);
452 Entry.peBlue = VGA_DAC_TO_COLOR(VgaDacRegisters[PaletteIndex * 3 + 2]);
453 Entry.peFlags = 0;
454
455 /* Update the palette entry and set the palette change flag */
456 SetPaletteEntries(PaletteHandle, PaletteIndex, 1, &Entry);
457 PaletteChanged = TRUE;
458
459 /* Update the index */
460 VgaDacIndex++;
461 VgaDacIndex %= VGA_PALETTE_SIZE;
462 }
463
464 static VOID VgaWriteAc(BYTE Data)
465 {
466 ASSERT(VgaAcIndex < VGA_AC_MAX_REG);
467
468 /* Save the value */
469 if (VgaAcIndex <= VGA_AC_PAL_F_REG)
470 {
471 if (VgaAcPalDisable) return;
472
473 // DbgPrint(" AC Palette Writing %d to index %d\n", Data, VgaAcIndex);
474 if (VgaAcRegisters[VgaAcIndex] != Data)
475 {
476 /* Update the AC register and set the palette change flag */
477 VgaAcRegisters[VgaAcIndex] = Data;
478 PaletteChanged = TRUE;
479 }
480 }
481 else
482 {
483 VgaAcRegisters[VgaAcIndex] = Data;
484 }
485 }
486
487 static VOID VgaRestoreDefaultPalette(PPALETTEENTRY Entries, USHORT NumOfEntries)
488 {
489 USHORT i;
490
491 /* Copy the colors of the default palette to the DAC and console palette */
492 for (i = 0; i < NumOfEntries; i++)
493 {
494 /* Set the palette entries */
495 Entries[i].peRed = GetRValue(VgaDefaultPalette[i]);
496 Entries[i].peGreen = GetGValue(VgaDefaultPalette[i]);
497 Entries[i].peBlue = GetBValue(VgaDefaultPalette[i]);
498 Entries[i].peFlags = 0;
499
500 /* Set the DAC registers */
501 VgaDacRegisters[i * 3] = VGA_COLOR_TO_DAC(GetRValue(VgaDefaultPalette[i]));
502 VgaDacRegisters[i * 3 + 1] = VGA_COLOR_TO_DAC(GetGValue(VgaDefaultPalette[i]));
503 VgaDacRegisters[i * 3 + 2] = VGA_COLOR_TO_DAC(GetBValue(VgaDefaultPalette[i]));
504 }
505 }
506
507 static BOOLEAN VgaInitializePalette(VOID)
508 {
509 LPLOGPALETTE Palette;
510
511 /* Allocate storage space for the palette */
512 Palette = (LPLOGPALETTE)HeapAlloc(GetProcessHeap(),
513 HEAP_ZERO_MEMORY,
514 sizeof(LOGPALETTE) +
515 VGA_MAX_COLORS * sizeof(PALETTEENTRY));
516 if (Palette == NULL) return FALSE;
517
518 /* Initialize the palette */
519 Palette->palVersion = 0x0300;
520 Palette->palNumEntries = VGA_MAX_COLORS;
521
522 /* Restore the default palette */
523 VgaRestoreDefaultPalette(Palette->palPalEntry, Palette->palNumEntries);
524
525 /* Create the palette */
526 PaletteHandle = CreatePalette(Palette);
527
528 /* Free the palette */
529 HeapFree(GetProcessHeap(), 0, Palette);
530
531 /* Fail if the palette wasn't successfully created... */
532 if (PaletteHandle == NULL) return FALSE;
533
534 /* ... otherwise return success */
535 return TRUE;
536 }
537
538 static BOOL VgaEnterGraphicsMode(PCOORD Resolution)
539 {
540 DWORD i;
541 CONSOLE_GRAPHICS_BUFFER_INFO GraphicsBufferInfo;
542 BYTE BitmapInfoBuffer[VGA_BITMAP_INFO_SIZE];
543 LPBITMAPINFO BitmapInfo = (LPBITMAPINFO)BitmapInfoBuffer;
544 LPWORD PaletteIndex = (LPWORD)(BitmapInfo->bmiColors);
545
546 LONG Width = Resolution->X;
547 LONG Height = Resolution->Y;
548
549 /* Use DoubleVision mode if the resolution is too small */
550 if (Width < VGA_MINIMUM_WIDTH && Height < VGA_MINIMUM_HEIGHT)
551 {
552 DoubleVision = TRUE;
553 Width *= 2;
554 Height *= 2;
555 }
556 else
557 {
558 DoubleVision = FALSE;
559 }
560
561 /* Fill the bitmap info header */
562 ZeroMemory(&BitmapInfo->bmiHeader, sizeof(BITMAPINFOHEADER));
563 BitmapInfo->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
564 BitmapInfo->bmiHeader.biWidth = Width;
565 BitmapInfo->bmiHeader.biHeight = Height;
566 BitmapInfo->bmiHeader.biBitCount = 8;
567 BitmapInfo->bmiHeader.biPlanes = 1;
568 BitmapInfo->bmiHeader.biCompression = BI_RGB;
569 BitmapInfo->bmiHeader.biSizeImage = Width * Height /* * 1 == biBitCount / 8 */;
570
571 /* Fill the palette data */
572 for (i = 0; i < (VGA_PALETTE_SIZE / 3); i++) PaletteIndex[i] = (WORD)i;
573
574 /* Fill the console graphics buffer info */
575 GraphicsBufferInfo.dwBitMapInfoLength = VGA_BITMAP_INFO_SIZE;
576 GraphicsBufferInfo.lpBitMapInfo = BitmapInfo;
577 GraphicsBufferInfo.dwUsage = DIB_PAL_COLORS;
578
579 /* Create the buffer */
580 GraphicsConsoleBuffer = CreateConsoleScreenBuffer(GENERIC_READ | GENERIC_WRITE,
581 FILE_SHARE_READ | FILE_SHARE_WRITE,
582 NULL,
583 CONSOLE_GRAPHICS_BUFFER,
584 &GraphicsBufferInfo);
585 if (GraphicsConsoleBuffer == INVALID_HANDLE_VALUE) return FALSE;
586
587 /* Save the framebuffer address and mutex */
588 ConsoleFramebuffer = GraphicsBufferInfo.lpBitMap;
589 ConsoleMutex = GraphicsBufferInfo.hMutex;
590
591 /* Clear the framebuffer */
592 ZeroMemory(ConsoleFramebuffer, BitmapInfo->bmiHeader.biSizeImage);
593
594 /* Set the active buffer */
595 SetConsoleActiveScreenBuffer(GraphicsConsoleBuffer);
596
597 /* Set the graphics mode palette */
598 SetConsolePalette(GraphicsConsoleBuffer,
599 PaletteHandle,
600 SYSPAL_NOSTATIC256);
601
602 /* Set the screen mode flag */
603 ScreenMode = GRAPHICS_MODE;
604
605 return TRUE;
606 }
607
608 static VOID VgaLeaveGraphicsMode(VOID)
609 {
610 /* Release the console framebuffer mutex */
611 ReleaseMutex(ConsoleMutex);
612
613 /* Switch back to the default console text buffer */
614 // SetConsoleActiveScreenBuffer(TextConsoleBuffer);
615
616 /* Cleanup the video data */
617 CloseHandle(ConsoleMutex);
618 ConsoleMutex = NULL;
619 ConsoleFramebuffer = NULL;
620 CloseHandle(GraphicsConsoleBuffer);
621 GraphicsConsoleBuffer = NULL;
622 DoubleVision = FALSE;
623 }
624
625 static BOOL VgaEnterTextMode(PCOORD Resolution)
626 {
627 SMALL_RECT ConRect;
628
629 /* Switch to the text buffer */
630 SetConsoleActiveScreenBuffer(TextConsoleBuffer);
631
632 /* Resize the console */
633 ConRect.Left = 0; // ConsoleInfo.srWindow.Left;
634 ConRect.Top = ConsoleInfo.srWindow.Top;
635 ConRect.Right = ConRect.Left + Resolution->X - 1;
636 ConRect.Bottom = ConRect.Top + Resolution->Y - 1;
637 /*
638 * Use this trick to effectively resize the console buffer and window,
639 * because:
640 * - SetConsoleScreenBufferSize fails if the new console screen buffer size
641 * is smaller than the current console window size, and:
642 * - SetConsoleWindowInfo fails if the new console window size is larger
643 * than the current console screen buffer size.
644 */
645 SetConsoleScreenBufferSize(TextConsoleBuffer, *Resolution);
646 SetConsoleWindowInfo(TextConsoleBuffer, TRUE, &ConRect);
647 SetConsoleScreenBufferSize(TextConsoleBuffer, *Resolution);
648 /* Update the saved console information */
649 GetConsoleScreenBufferInfo(TextConsoleBuffer, &ConsoleInfo);
650
651 /* Allocate a framebuffer */
652 ConsoleFramebuffer = HeapAlloc(GetProcessHeap(),
653 HEAP_ZERO_MEMORY,
654 Resolution->X * Resolution->Y
655 * sizeof(CHAR_INFO));
656 if (ConsoleFramebuffer == NULL)
657 {
658 DisplayMessage(L"An unexpected error occurred!\n");
659 VdmRunning = FALSE;
660 return FALSE;
661 }
662
663 /*
664 * Set the text mode palette.
665 *
666 * WARNING: This call should fail on Windows (and therefore
667 * we get the default palette and our external behaviour is
668 * just like Windows' one), but it should success on ReactOS
669 * (so that we get console palette changes even for text-mode
670 * screen-buffers, which is a new feature on ReactOS).
671 */
672 SetConsolePalette(TextConsoleBuffer,
673 PaletteHandle,
674 SYSPAL_NOSTATIC256);
675
676 /* Set the screen mode flag */
677 ScreenMode = TEXT_MODE;
678
679 return TRUE;
680 }
681
682 static VOID VgaLeaveTextMode(VOID)
683 {
684 /* Free the old framebuffer */
685 HeapFree(GetProcessHeap(), 0, ConsoleFramebuffer);
686 ConsoleFramebuffer = NULL;
687 }
688
689 static VOID VgaChangeMode(VOID)
690 {
691 COORD Resolution = VgaGetDisplayResolution();
692
693 if (ScreenMode == GRAPHICS_MODE)
694 {
695 /* Leave the current graphics mode */
696 VgaLeaveGraphicsMode();
697 }
698 else
699 {
700 /* Leave the current text mode */
701 VgaLeaveTextMode();
702 }
703
704 /* Check if the new mode is alphanumeric */
705 if (!(VgaGcRegisters[VGA_GC_MISC_REG] & VGA_GC_MISC_NOALPHA))
706 {
707 /* Enter new text mode */
708 if (!VgaEnterTextMode(&Resolution))
709 {
710 DisplayMessage(L"An unexpected VGA error occurred while switching into text mode.");
711 VdmRunning = FALSE;
712 return;
713 }
714 }
715 else
716 {
717 /* Enter graphics mode */
718 if (!VgaEnterGraphicsMode(&Resolution))
719 {
720 DisplayMessage(L"An unexpected VGA error occurred while switching into graphics mode.");
721 VdmRunning = FALSE;
722 return;
723 }
724 }
725
726 /* Trigger a full update of the screen */
727 NeedsUpdate = TRUE;
728 UpdateRectangle.Left = 0;
729 UpdateRectangle.Top = 0;
730 UpdateRectangle.Right = Resolution.X;
731 UpdateRectangle.Bottom = Resolution.Y;
732
733 /* Reset the mode change flag */
734 ModeChanged = FALSE;
735 }
736
737 static VOID VgaUpdateFramebuffer(VOID)
738 {
739 INT i, j, k;
740 COORD Resolution = VgaGetDisplayResolution();
741 DWORD AddressSize = VgaGetAddressSize();
742 DWORD Address = MAKEWORD(VgaCrtcRegisters[VGA_CRTC_START_ADDR_LOW_REG],
743 VgaCrtcRegisters[VGA_CRTC_START_ADDR_HIGH_REG]);
744 DWORD ScanlineSize = (DWORD)VgaCrtcRegisters[VGA_CRTC_OFFSET_REG] * 2;
745
746 /*
747 * If console framebuffer is NULL, that means something went wrong
748 * earlier and this is the final display refresh.
749 */
750 if (ConsoleFramebuffer == NULL) return;
751
752 /* Check if this is text mode or graphics mode */
753 if (VgaGcRegisters[VGA_GC_MISC_REG] & VGA_GC_MISC_NOALPHA)
754 {
755 /* Graphics mode */
756 PBYTE GraphicsBuffer = (PBYTE)ConsoleFramebuffer;
757
758 /*
759 * Synchronize access to the graphics framebuffer
760 * with the console framebuffer mutex.
761 */
762 WaitForSingleObject(ConsoleMutex, INFINITE);
763
764 /* Loop through the scanlines */
765 for (i = 0; i < Resolution.Y; i++)
766 {
767 /* Loop through the pixels */
768 for (j = 0; j < Resolution.X; j++)
769 {
770 BYTE PixelData = 0;
771
772 /* Check the shifting mode */
773 if (VgaGcRegisters[VGA_GC_MODE_REG] & VGA_GC_MODE_SHIFT256)
774 {
775 /* 4 bits shifted from each plane */
776
777 /* Check if this is 16 or 256 color mode */
778 if (VgaAcRegisters[VGA_AC_CONTROL_REG] & VGA_AC_CONTROL_8BIT)
779 {
780 /* One byte per pixel */
781 PixelData = VgaMemory[(j % VGA_NUM_BANKS) * VGA_BANK_SIZE
782 + (Address + (j / VGA_NUM_BANKS))
783 * AddressSize];
784 }
785 else
786 {
787 /* 4-bits per pixel */
788
789 PixelData = VgaMemory[(j % VGA_NUM_BANKS) * VGA_BANK_SIZE
790 + (Address + (j / (VGA_NUM_BANKS * 2)))
791 * AddressSize];
792
793 /* Check if we should use the highest 4 bits or lowest 4 */
794 if (((j / VGA_NUM_BANKS) % 2) == 0)
795 {
796 /* Highest 4 */
797 PixelData >>= 4;
798 }
799 else
800 {
801 /* Lowest 4 */
802 PixelData &= 0x0F;
803 }
804 }
805 }
806 else if (VgaGcRegisters[VGA_GC_MODE_REG] & VGA_GC_MODE_SHIFTREG)
807 {
808 /* Check if this is 16 or 256 color mode */
809 if (VgaAcRegisters[VGA_AC_CONTROL_REG] & VGA_AC_CONTROL_8BIT)
810 {
811 // TODO: NOT IMPLEMENTED
812 DPRINT1("8-bit interleaved mode is not implemented!\n");
813 }
814 else
815 {
816 /*
817 * 2 bits shifted from plane 0 and 2 for the first 4 pixels,
818 * then 2 bits shifted from plane 1 and 3 for the next 4
819 */
820 BYTE LowPlaneData = VgaMemory[((j / 4) % 2) * VGA_BANK_SIZE
821 + (Address + (j / 8)) * AddressSize];
822 BYTE HighPlaneData = VgaMemory[(((j / 4) % 2) + 2) * VGA_BANK_SIZE
823 + (Address + (j / 8)) * AddressSize];
824
825 /* Extract the two bits from each plane */
826 LowPlaneData = (LowPlaneData >> (6 - ((j % 4) * 2))) & 3;
827 HighPlaneData = (HighPlaneData >> (6 - ((j % 4) * 2))) & 3;
828
829 /* Combine them into the pixel */
830 PixelData = LowPlaneData | (HighPlaneData << 2);
831 }
832 }
833 else
834 {
835 /* 1 bit shifted from each plane */
836
837 /* Check if this is 16 or 256 color mode */
838 if (VgaAcRegisters[VGA_AC_CONTROL_REG] & VGA_AC_CONTROL_8BIT)
839 {
840 /* 8 bits per pixel, 2 on each plane */
841
842 for (k = 0; k < VGA_NUM_BANKS; k++)
843 {
844 /* The data is on plane k, 4 pixels per byte */
845 BYTE PlaneData = VgaMemory[k * VGA_BANK_SIZE
846 + (Address + (j / VGA_NUM_BANKS))
847 * AddressSize];
848
849 /* The mask of the first bit in the pair */
850 BYTE BitMask = 1 << (((3 - (j % VGA_NUM_BANKS)) * 2) + 1);
851
852 /* Bits 0, 1, 2 and 3 come from the first bit of the pair */
853 if (PlaneData & BitMask) PixelData |= 1 << k;
854
855 /* Bits 4, 5, 6 and 7 come from the second bit of the pair */
856 if (PlaneData & (BitMask >> 1)) PixelData |= 1 << (k + 4);
857 }
858 }
859 else
860 {
861 /* 4 bits per pixel, 1 on each plane */
862
863 for (k = 0; k < VGA_NUM_BANKS; k++)
864 {
865 BYTE PlaneData = VgaMemory[k * VGA_BANK_SIZE
866 + (Address + (j / (VGA_NUM_BANKS * 2)))
867 * AddressSize];
868
869 /* If the bit on that plane is set, set it */
870 if (PlaneData & (1 << (7 - (j % 8)))) PixelData |= 1 << k;
871 }
872 }
873 }
874
875 if (!(VgaAcRegisters[VGA_AC_CONTROL_REG] & VGA_AC_CONTROL_8BIT))
876 {
877 /*
878 * In 16 color mode, the value is an index to the AC registers
879 * if external palette access is disabled, otherwise (in case
880 * of palette loading) it is a blank pixel.
881 */
882 PixelData = (VgaAcPalDisable ? VgaAcRegisters[PixelData & 0x0F]
883 : 0);
884 }
885
886 /* Take into account DoubleVision mode when checking for pixel updates */
887 if (DoubleVision)
888 {
889 /* Now check if the resulting pixel data has changed */
890 if (GraphicsBuffer[(i * Resolution.X * 4) + (j * 2)] != PixelData)
891 {
892 /* Yes, write the new value */
893 GraphicsBuffer[(i * Resolution.X * 4) + (j * 2)] = PixelData;
894 GraphicsBuffer[(i * Resolution.X * 4) + (j * 2 + 1)] = PixelData;
895 GraphicsBuffer[((i * 2 + 1) * Resolution.X * 2) + (j * 2)] = PixelData;
896 GraphicsBuffer[((i * 2 + 1) * Resolution.X * 2) + (j * 2 + 1)] = PixelData;
897
898 /* Mark the specified pixel as changed */
899 VgaMarkForUpdate(i, j);
900 }
901 }
902 else
903 {
904 /* Now check if the resulting pixel data has changed */
905 if (GraphicsBuffer[i * Resolution.X + j] != PixelData)
906 {
907 /* Yes, write the new value */
908 GraphicsBuffer[i * Resolution.X + j] = PixelData;
909
910 /* Mark the specified pixel as changed */
911 VgaMarkForUpdate(i, j);
912 }
913 }
914 }
915
916 /* Move to the next scanline */
917 Address += ScanlineSize;
918 }
919
920 /*
921 * Release the console framebuffer mutex
922 * so that we allow for repainting.
923 */
924 ReleaseMutex(ConsoleMutex);
925 }
926 else
927 {
928 /* Text mode */
929 DWORD CurrentAddr;
930 PCHAR_INFO CharBuffer = (PCHAR_INFO)ConsoleFramebuffer;
931 CHAR_INFO CharInfo;
932
933 /* Loop through the scanlines */
934 for (i = 0; i < Resolution.Y; i++)
935 {
936 /* Loop through the characters */
937 for (j = 0; j < Resolution.X; j++)
938 {
939 CurrentAddr = LOWORD((Address + j) * AddressSize);
940
941 /* Plane 0 holds the character itself */
942 CharInfo.Char.AsciiChar = VgaMemory[CurrentAddr];
943
944 /* Plane 1 holds the attribute */
945 CharInfo.Attributes = VgaMemory[CurrentAddr + VGA_BANK_SIZE];
946
947 /* Now check if the resulting character data has changed */
948 if ((CharBuffer[i * Resolution.X + j].Char.AsciiChar != CharInfo.Char.AsciiChar)
949 || (CharBuffer[i * Resolution.X + j].Attributes != CharInfo.Attributes))
950 {
951 /* Yes, write the new value */
952 CharBuffer[i * Resolution.X + j] = CharInfo;
953
954 /* Mark the specified cell as changed */
955 VgaMarkForUpdate(i, j);
956 }
957 }
958
959 /* Move to the next scanline */
960 Address += ScanlineSize;
961 }
962 }
963 }
964
965 static VOID VgaUpdateTextCursor(VOID)
966 {
967 COORD Position;
968 CONSOLE_CURSOR_INFO CursorInfo;
969 BYTE CursorStart = VgaCrtcRegisters[VGA_CRTC_CURSOR_START_REG] & 0x3F;
970 BYTE CursorEnd = VgaCrtcRegisters[VGA_CRTC_CURSOR_END_REG] & 0x1F;
971 DWORD ScanlineSize = (DWORD)VgaCrtcRegisters[VGA_CRTC_OFFSET_REG] * 2;
972 BYTE TextSize = 1 + (VgaCrtcRegisters[VGA_CRTC_MAX_SCAN_LINE_REG] & 0x1F);
973 WORD Location = MAKEWORD(VgaCrtcRegisters[VGA_CRTC_CURSOR_LOC_LOW_REG],
974 VgaCrtcRegisters[VGA_CRTC_CURSOR_LOC_HIGH_REG]);
975
976 /* Just return if we are not in text mode */
977 if (VgaGcRegisters[VGA_GC_MISC_REG] & VGA_GC_MISC_NOALPHA) return;
978
979 if (CursorStart < CursorEnd)
980 {
981 /* Visible cursor */
982 CursorInfo.bVisible = TRUE;
983 CursorInfo.dwSize = (100 * (CursorEnd - CursorStart)) / TextSize;
984 }
985 else
986 {
987 /* No cursor */
988 CursorInfo.bVisible = FALSE;
989 CursorInfo.dwSize = 0;
990 }
991
992 /* Add the cursor skew to the location */
993 Location += (VgaCrtcRegisters[VGA_CRTC_CURSOR_END_REG] >> 5) & 3;
994
995 /* Find the coordinates of the new position */
996 Position.X = (WORD)(Location % ScanlineSize);
997 Position.Y = (WORD)(Location / ScanlineSize);
998
999 /* Update the physical cursor */
1000 SetConsoleCursorInfo(TextConsoleBuffer, &CursorInfo);
1001 SetConsoleCursorPosition(TextConsoleBuffer, Position);
1002
1003 /* Reset the cursor move flag */
1004 CursorMoved = FALSE;
1005 }
1006
1007 static BYTE WINAPI VgaReadPort(ULONG Port)
1008 {
1009 DPRINT("VgaReadPort: Port 0x%X\n", Port);
1010
1011 switch (Port)
1012 {
1013 case VGA_MISC_READ:
1014 return VgaMiscRegister;
1015
1016 case VGA_INSTAT0_READ:
1017 return 0; // Not implemented
1018
1019 case VGA_INSTAT1_READ_MONO:
1020 case VGA_INSTAT1_READ_COLOR:
1021 {
1022 BYTE Result = 0;
1023
1024 /* Reset the AC latch */
1025 VgaAcLatch = FALSE;
1026
1027 /* Set a flag if there is a vertical or horizontal retrace */
1028 if (InVerticalRetrace || InHorizontalRetrace) Result |= VGA_STAT_DD;
1029
1030 /* Set an additional flag if there was a vertical retrace */
1031 if (InVerticalRetrace) Result |= VGA_STAT_VRETRACE;
1032
1033 /* Clear the flags */
1034 InHorizontalRetrace = InVerticalRetrace = FALSE;
1035
1036 return Result;
1037 }
1038
1039 case VGA_FEATURE_READ:
1040 return VgaFeatureRegister;
1041
1042 case VGA_AC_INDEX:
1043 return VgaAcIndex;
1044
1045 case VGA_AC_READ:
1046 return VgaAcRegisters[VgaAcIndex];
1047
1048 case VGA_SEQ_INDEX:
1049 return VgaSeqIndex;
1050
1051 case VGA_SEQ_DATA:
1052 return VgaSeqRegisters[VgaSeqIndex];
1053
1054 case VGA_DAC_MASK:
1055 return VgaDacMask;
1056
1057 case VGA_DAC_READ_INDEX:
1058 /* This returns the read/write state */
1059 return (VgaDacReadWrite ? 0 : 3);
1060
1061 case VGA_DAC_WRITE_INDEX:
1062 return (VgaDacIndex / 3);
1063
1064 case VGA_DAC_DATA:
1065 {
1066 /* Ignore reads in write mode */
1067 if (!VgaDacReadWrite)
1068 {
1069 BYTE Data = VgaDacRegisters[VgaDacIndex++];
1070 VgaDacIndex %= VGA_PALETTE_SIZE;
1071 return Data;
1072 }
1073
1074 break;
1075 }
1076
1077 case VGA_CRTC_INDEX_MONO:
1078 case VGA_CRTC_INDEX_COLOR:
1079 return VgaCrtcIndex;
1080
1081 case VGA_CRTC_DATA_MONO:
1082 case VGA_CRTC_DATA_COLOR:
1083 return VgaCrtcRegisters[VgaCrtcIndex];
1084
1085 case VGA_GC_INDEX:
1086 return VgaGcIndex;
1087
1088 case VGA_GC_DATA:
1089 return VgaGcRegisters[VgaGcIndex];
1090
1091 default:
1092 DPRINT1("VgaReadPort: Unknown port 0x%X\n", Port);
1093 break;
1094 }
1095
1096 return 0;
1097 }
1098
1099 static VOID WINAPI VgaWritePort(ULONG Port, BYTE Data)
1100 {
1101 DPRINT("VgaWritePort: Port 0x%X, Data 0x%02X\n", Port, Data);
1102
1103 switch (Port)
1104 {
1105 case VGA_MISC_WRITE:
1106 {
1107 VgaMiscRegister = Data;
1108
1109 if (VgaMiscRegister & 0x01)
1110 {
1111 /* Color emulation */
1112 DPRINT1("Color emulation\n");
1113
1114 /* Register the new I/O Ports */
1115 RegisterIoPort(0x3D4, VgaReadPort, VgaWritePort); // VGA_CRTC_INDEX_COLOR
1116 RegisterIoPort(0x3D5, VgaReadPort, VgaWritePort); // VGA_CRTC_DATA_COLOR
1117 RegisterIoPort(0x3DA, VgaReadPort, VgaWritePort); // VGA_INSTAT1_READ_COLOR, VGA_FEATURE_WRITE_COLOR
1118
1119 /* Unregister the old ones */
1120 UnregisterIoPort(0x3B4); // VGA_CRTC_INDEX_MONO
1121 UnregisterIoPort(0x3B5); // VGA_CRTC_DATA_MONO
1122 UnregisterIoPort(0x3BA); // VGA_INSTAT1_READ_MONO, VGA_FEATURE_WRITE_MONO
1123 }
1124 else
1125 {
1126 /* Monochrome emulation */
1127 DPRINT1("Monochrome emulation\n");
1128
1129 /* Register the new I/O Ports */
1130 RegisterIoPort(0x3B4, VgaReadPort, VgaWritePort); // VGA_CRTC_INDEX_MONO
1131 RegisterIoPort(0x3B5, VgaReadPort, VgaWritePort); // VGA_CRTC_DATA_MONO
1132 RegisterIoPort(0x3BA, VgaReadPort, VgaWritePort); // VGA_INSTAT1_READ_MONO, VGA_FEATURE_WRITE_MONO
1133
1134 /* Unregister the old ones */
1135 UnregisterIoPort(0x3D4); // VGA_CRTC_INDEX_COLOR
1136 UnregisterIoPort(0x3D5); // VGA_CRTC_DATA_COLOR
1137 UnregisterIoPort(0x3DA); // VGA_INSTAT1_READ_COLOR, VGA_FEATURE_WRITE_COLOR
1138 }
1139
1140 // if (VgaMiscRegister & 0x02) { /* Enable RAM access */ } else { /* Disable RAM access */ }
1141 break;
1142 }
1143
1144 case VGA_FEATURE_WRITE_MONO:
1145 case VGA_FEATURE_WRITE_COLOR:
1146 {
1147 VgaFeatureRegister = Data;
1148 break;
1149 }
1150
1151 case VGA_AC_INDEX:
1152 // case VGA_AC_WRITE:
1153 {
1154 if (!VgaAcLatch)
1155 {
1156 /* Change the index */
1157 BYTE Index = Data & 0x1F;
1158 if (Index < VGA_AC_MAX_REG) VgaAcIndex = Index;
1159
1160 /*
1161 * Change palette protection by checking for
1162 * the Palette Address Source bit.
1163 */
1164 VgaAcPalDisable = (Data & 0x20) ? TRUE : FALSE;
1165 }
1166 else
1167 {
1168 /* Write the data */
1169 VgaWriteAc(Data);
1170 }
1171
1172 /* Toggle the latch */
1173 VgaAcLatch = !VgaAcLatch;
1174 break;
1175 }
1176
1177 case VGA_SEQ_INDEX:
1178 {
1179 /* Set the sequencer index register */
1180 if (Data < VGA_SEQ_MAX_REG) VgaSeqIndex = Data;
1181 break;
1182 }
1183
1184 case VGA_SEQ_DATA:
1185 {
1186 /* Call the sequencer function */
1187 VgaWriteSequencer(Data);
1188 break;
1189 }
1190
1191 case VGA_DAC_MASK:
1192 {
1193 VgaDacMask = Data;
1194 break;
1195 }
1196
1197 case VGA_DAC_READ_INDEX:
1198 {
1199 VgaDacReadWrite = FALSE;
1200 VgaDacIndex = Data * 3;
1201 break;
1202 }
1203
1204 case VGA_DAC_WRITE_INDEX:
1205 {
1206 VgaDacReadWrite = TRUE;
1207 VgaDacIndex = Data * 3;
1208 break;
1209 }
1210
1211 case VGA_DAC_DATA:
1212 {
1213 /* Ignore writes in read mode */
1214 if (VgaDacReadWrite) VgaWriteDac(Data & 0x3F);
1215 break;
1216 }
1217
1218 case VGA_CRTC_INDEX_MONO:
1219 case VGA_CRTC_INDEX_COLOR:
1220 {
1221 /* Set the CRTC index register */
1222 if (Data < VGA_CRTC_MAX_REG) VgaCrtcIndex = Data;
1223 break;
1224 }
1225
1226 case VGA_CRTC_DATA_MONO:
1227 case VGA_CRTC_DATA_COLOR:
1228 {
1229 /* Call the CRTC function */
1230 VgaWriteCrtc(Data);
1231 break;
1232 }
1233
1234 case VGA_GC_INDEX:
1235 {
1236 /* Set the GC index register */
1237 if (Data < VGA_GC_MAX_REG) VgaGcIndex = Data;
1238 break;
1239 }
1240
1241 case VGA_GC_DATA:
1242 {
1243 /* Call the GC function */
1244 VgaWriteGc(Data);
1245 break;
1246 }
1247
1248 default:
1249 DPRINT1("VgaWritePort: Unknown port 0x%X\n", Port);
1250 break;
1251 }
1252 }
1253
1254 /* PUBLIC FUNCTIONS ***********************************************************/
1255
1256 DWORD VgaGetVideoBaseAddress(VOID)
1257 {
1258 return MemoryBase[(VgaGcRegisters[VGA_GC_MISC_REG] >> 2) & 0x03];
1259 }
1260
1261 DWORD VgaGetVideoLimitAddress(VOID)
1262 {
1263 return MemoryLimit[(VgaGcRegisters[VGA_GC_MISC_REG] >> 2) & 0x03];
1264 }
1265
1266 COORD VgaGetDisplayResolution(VOID)
1267 {
1268 COORD Resolution;
1269 BYTE MaximumScanLine = 1 + (VgaCrtcRegisters[VGA_CRTC_MAX_SCAN_LINE_REG] & 0x1F);
1270
1271 /* The low 8 bits are in the display registers */
1272 Resolution.X = VgaCrtcRegisters[VGA_CRTC_END_HORZ_DISP_REG];
1273 Resolution.Y = VgaCrtcRegisters[VGA_CRTC_VERT_DISP_END_REG];
1274
1275 /* Set the top bits from the overflow register */
1276 if (VgaCrtcRegisters[VGA_CRTC_OVERFLOW_REG] & VGA_CRTC_OVERFLOW_VDE8)
1277 {
1278 Resolution.Y |= 1 << 8;
1279 }
1280 if (VgaCrtcRegisters[VGA_CRTC_OVERFLOW_REG] & VGA_CRTC_OVERFLOW_VDE9)
1281 {
1282 Resolution.Y |= 1 << 9;
1283 }
1284
1285 /* Increase the values by 1 */
1286 Resolution.X++;
1287 Resolution.Y++;
1288
1289 if (VgaGcRegisters[VGA_GC_MISC_REG] & VGA_GC_MISC_NOALPHA)
1290 {
1291 /* Multiply the horizontal resolution by the 9/8 dot mode */
1292 Resolution.X *= (VgaSeqRegisters[VGA_SEQ_CLOCK_REG] & VGA_SEQ_CLOCK_98DM)
1293 ? 8 : 9;
1294
1295 /* The horizontal resolution is halved in 8-bit mode */
1296 if (VgaAcRegisters[VGA_AC_CONTROL_REG] & VGA_AC_CONTROL_8BIT) Resolution.X /= 2;
1297 }
1298
1299 if (VgaCrtcRegisters[VGA_CRTC_MAX_SCAN_LINE_REG] & VGA_CRTC_MAXSCANLINE_DOUBLE)
1300 {
1301 /* Halve the vertical resolution */
1302 Resolution.Y >>= 1;
1303 }
1304 else
1305 {
1306 /* Divide the vertical resolution by the maximum scan line (== font size in text mode) */
1307 Resolution.Y /= MaximumScanLine;
1308 }
1309
1310 /* Return the resolution */
1311 return Resolution;
1312 }
1313
1314 VOID VgaRefreshDisplay(VOID)
1315 {
1316 HANDLE ConsoleBufferHandle = NULL;
1317 COORD Resolution;
1318
1319 /* Set the vertical retrace flag */
1320 InVerticalRetrace = TRUE;
1321
1322 /* If nothing has changed, just return */
1323 // if (!ModeChanged && !CursorMoved && !PaletteChanged && !NeedsUpdate)
1324 // return;
1325
1326 /* Change the display mode */
1327 if (ModeChanged) VgaChangeMode();
1328
1329 /* Change the text cursor location */
1330 if (CursorMoved) VgaUpdateTextCursor();
1331
1332 /* Retrieve the current resolution */
1333 Resolution = VgaGetDisplayResolution();
1334
1335 if (PaletteChanged)
1336 {
1337 /* Trigger a full update of the screen */
1338 NeedsUpdate = TRUE;
1339 UpdateRectangle.Left = 0;
1340 UpdateRectangle.Top = 0;
1341 UpdateRectangle.Right = Resolution.X;
1342 UpdateRectangle.Bottom = Resolution.Y;
1343
1344 PaletteChanged = FALSE;
1345 }
1346
1347 /* Update the contents of the framebuffer */
1348 VgaUpdateFramebuffer();
1349
1350 /* Ignore if there's nothing to update */
1351 if (!NeedsUpdate) return;
1352
1353 DPRINT("Updating screen rectangle (%d, %d, %d, %d)\n",
1354 UpdateRectangle.Left,
1355 UpdateRectangle.Top,
1356 UpdateRectangle.Right,
1357 UpdateRectangle.Bottom);
1358
1359 /* Check if this is text mode or graphics mode */
1360 if (VgaGcRegisters[VGA_GC_MISC_REG] & VGA_GC_MISC_NOALPHA)
1361 {
1362 /* Graphics mode */
1363 ConsoleBufferHandle = GraphicsConsoleBuffer;
1364 }
1365 else
1366 {
1367 /* Text mode */
1368 COORD Origin = { UpdateRectangle.Left, UpdateRectangle.Top };
1369 ConsoleBufferHandle = TextConsoleBuffer;
1370
1371 /* Write the data to the console */
1372 WriteConsoleOutputA(TextConsoleBuffer,
1373 (PCHAR_INFO)ConsoleFramebuffer,
1374 Resolution,
1375 Origin,
1376 &UpdateRectangle);
1377 }
1378
1379 /* In DoubleVision mode, scale the update rectangle */
1380 if (DoubleVision)
1381 {
1382 UpdateRectangle.Left *= 2;
1383 UpdateRectangle.Top *= 2;
1384 UpdateRectangle.Right = UpdateRectangle.Right * 2 + 1;
1385 UpdateRectangle.Bottom = UpdateRectangle.Bottom * 2 + 1;
1386 }
1387
1388 /* Redraw the screen */
1389 InvalidateConsoleDIBits(ConsoleBufferHandle, &UpdateRectangle);
1390
1391 /* Clear the update flag */
1392 NeedsUpdate = FALSE;
1393 }
1394
1395 VOID VgaHorizontalRetrace(VOID)
1396 {
1397 /* Set the flag */
1398 InHorizontalRetrace = TRUE;
1399 }
1400
1401 VOID VgaReadMemory(DWORD Address, LPBYTE Buffer, DWORD Size)
1402 {
1403 DWORD i;
1404 DWORD VideoAddress;
1405
1406 DPRINT("VgaReadMemory: Address 0x%08X, Size %lu\n", Address, Size);
1407
1408 /* Ignore if video RAM access is disabled */
1409 if ((VgaMiscRegister & VGA_MISC_RAM_ENABLED) == 0) return;
1410
1411 /* Loop through each byte */
1412 for (i = 0; i < Size; i++)
1413 {
1414 VideoAddress = VgaTranslateReadAddress(Address + i);
1415
1416 /* Load the latch registers */
1417 VgaLatchRegisters[0] = VgaMemory[LOWORD(VideoAddress)];
1418 VgaLatchRegisters[1] = VgaMemory[VGA_BANK_SIZE + LOWORD(VideoAddress)];
1419 VgaLatchRegisters[2] = VgaMemory[(2 * VGA_BANK_SIZE) + LOWORD(VideoAddress)];
1420 VgaLatchRegisters[3] = VgaMemory[(3 * VGA_BANK_SIZE) + LOWORD(VideoAddress)];
1421
1422 /* Copy the value to the buffer */
1423 Buffer[i] = VgaMemory[VideoAddress];
1424 }
1425 }
1426
1427 VOID VgaWriteMemory(DWORD Address, LPBYTE Buffer, DWORD Size)
1428 {
1429 DWORD i, j;
1430 DWORD VideoAddress;
1431
1432 DPRINT("VgaWriteMemory: Address 0x%08X, Size %lu\n", Address, Size);
1433
1434 /* Ignore if video RAM access is disabled */
1435 if ((VgaMiscRegister & VGA_MISC_RAM_ENABLED) == 0) return;
1436
1437 /* Also ignore if write access to all planes is disabled */
1438 if ((VgaSeqRegisters[VGA_SEQ_MASK_REG] & 0x0F) == 0x00) return;
1439
1440 /* Loop through each byte */
1441 for (i = 0; i < Size; i++)
1442 {
1443 VideoAddress = VgaTranslateWriteAddress(Address + i);
1444
1445 for (j = 0; j < VGA_NUM_BANKS; j++)
1446 {
1447 /* Make sure the page is writeable */
1448 if (!(VgaSeqRegisters[VGA_SEQ_MASK_REG] & (1 << j))) continue;
1449
1450 /* Check if this is chain-4 mode */
1451 if (VgaSeqRegisters[VGA_SEQ_MEM_REG] & VGA_SEQ_MEM_C4)
1452 {
1453 if (((Address + i) & 3) != j)
1454 {
1455 /* This plane will not be accessed */
1456 continue;
1457 }
1458 }
1459
1460 /* Check if this is odd-even mode */
1461 if (VgaGcRegisters[VGA_GC_MODE_REG] & VGA_GC_MODE_OE)
1462 {
1463 if (((Address + i) & 1) != (j & 1))
1464 {
1465 /* This plane will not be accessed */
1466 continue;
1467 }
1468 }
1469
1470 /* Copy the value to the VGA memory */
1471 VgaMemory[VideoAddress + j * VGA_BANK_SIZE] = VgaTranslateByteForWriting(Buffer[i], j);
1472 }
1473 }
1474 }
1475
1476 VOID VgaClearMemory(VOID)
1477 {
1478 ZeroMemory(VgaMemory, sizeof(VgaMemory));
1479 }
1480
1481 VOID VgaResetPalette(VOID)
1482 {
1483 PALETTEENTRY Entries[VGA_MAX_COLORS];
1484
1485 /* Restore the default palette */
1486 VgaRestoreDefaultPalette(Entries, VGA_MAX_COLORS);
1487 SetPaletteEntries(PaletteHandle, 0, VGA_MAX_COLORS, Entries);
1488 PaletteChanged = TRUE;
1489 }
1490
1491 BOOLEAN VgaInitialize(HANDLE TextHandle)
1492 {
1493 /* Save the default text-mode console output handle */
1494 if (TextHandle == INVALID_HANDLE_VALUE) return FALSE;
1495 TextConsoleBuffer = TextHandle;
1496
1497 /* Save the console information */
1498 if (!GetConsoleScreenBufferInfo(TextConsoleBuffer, &ConsoleInfo))
1499 {
1500 return FALSE;
1501 }
1502
1503 /* Initialize the VGA palette and fail if it isn't successfully created */
1504 if (!VgaInitializePalette()) return FALSE;
1505 /***/ VgaResetPalette(); /***/
1506
1507 /* Switch to the text buffer */
1508 SetConsoleActiveScreenBuffer(TextConsoleBuffer);
1509
1510 /* Clear the VGA memory */
1511 VgaClearMemory();
1512
1513 /* Register the I/O Ports */
1514 RegisterIoPort(0x3CC, VgaReadPort, NULL); // VGA_MISC_READ
1515 RegisterIoPort(0x3C2, VgaReadPort, VgaWritePort); // VGA_MISC_WRITE, VGA_INSTAT0_READ
1516 RegisterIoPort(0x3CA, VgaReadPort, NULL); // VGA_FEATURE_READ
1517 RegisterIoPort(0x3C0, VgaReadPort, VgaWritePort); // VGA_AC_INDEX, VGA_AC_WRITE
1518 RegisterIoPort(0x3C1, VgaReadPort, NULL); // VGA_AC_READ
1519 RegisterIoPort(0x3C4, VgaReadPort, VgaWritePort); // VGA_SEQ_INDEX
1520 RegisterIoPort(0x3C5, VgaReadPort, VgaWritePort); // VGA_SEQ_DATA
1521 RegisterIoPort(0x3C6, VgaReadPort, VgaWritePort); // VGA_DAC_MASK
1522 RegisterIoPort(0x3C7, VgaReadPort, VgaWritePort); // VGA_DAC_READ_INDEX
1523 RegisterIoPort(0x3C8, VgaReadPort, VgaWritePort); // VGA_DAC_WRITE_INDEX
1524 RegisterIoPort(0x3C9, VgaReadPort, VgaWritePort); // VGA_DAC_DATA
1525 RegisterIoPort(0x3CE, VgaReadPort, VgaWritePort); // VGA_GC_INDEX
1526 RegisterIoPort(0x3CF, VgaReadPort, VgaWritePort); // VGA_GC_DATA
1527
1528 /* Return success */
1529 return TRUE;
1530 }
1531
1532 /* EOF */