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 #define WRAP_OFFSET(x) ((VgaCrtcRegisters[SVGA_CRTC_EXT_DISPLAY_REG] & SVGA_CRTC_EXT_ADDR_WRAP) \
29                        ? ((x) & 0xFFFFF) : LOWORD(x))
30 
31 static CONST DWORD MemoryBase[] = { 0xA0000, 0xA0000, 0xB0000, 0xB8000 };
32 static CONST DWORD MemorySize[] = { 0x20000, 0x10000, 0x08000, 0x08000 };
33 
34 #define USE_REACTOS_COLORS
35 // #define USE_DOSBOX_COLORS
36 
37 #if defined(USE_REACTOS_COLORS)
38 
39 // ReactOS colors
40 static CONST COLORREF VgaDefaultPalette[VGA_MAX_COLORS] =
41 {
42     RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0xAA), RGB(0x00, 0xAA, 0x00), RGB(0x00, 0xAA, 0xAA),
43     RGB(0xAA, 0x00, 0x00), RGB(0xAA, 0x00, 0xAA), RGB(0xAA, 0x55, 0x00), RGB(0xAA, 0xAA, 0xAA),
44     RGB(0x55, 0x55, 0x55), RGB(0x55, 0x55, 0xFF), RGB(0x55, 0xFF, 0x55), RGB(0x55, 0xFF, 0xFF),
45     RGB(0xFF, 0x55, 0x55), RGB(0xFF, 0x55, 0xFF), RGB(0xFF, 0xFF, 0x55), RGB(0xFF, 0xFF, 0xFF),
46     RGB(0x00, 0x00, 0x00), RGB(0x10, 0x10, 0x10), RGB(0x20, 0x20, 0x20), RGB(0x35, 0x35, 0x35),
47     RGB(0x45, 0x45, 0x45), RGB(0x55, 0x55, 0x55), RGB(0x65, 0x65, 0x65), RGB(0x75, 0x75, 0x75),
48     RGB(0x8A, 0x8A, 0x8A), RGB(0x9A, 0x9A, 0x9A), RGB(0xAA, 0xAA, 0xAA), RGB(0xBA, 0xBA, 0xBA),
49     RGB(0xCA, 0xCA, 0xCA), RGB(0xDF, 0xDF, 0xDF), RGB(0xEF, 0xEF, 0xEF), RGB(0xFF, 0xFF, 0xFF),
50     RGB(0x00, 0x00, 0xFF), RGB(0x41, 0x00, 0xFF), RGB(0x82, 0x00, 0xFF), RGB(0xBE, 0x00, 0xFF),
51     RGB(0xFF, 0x00, 0xFF), RGB(0xFF, 0x00, 0xBE), RGB(0xFF, 0x00, 0x82), RGB(0xFF, 0x00, 0x41),
52     RGB(0xFF, 0x00, 0x00), RGB(0xFF, 0x41, 0x00), RGB(0xFF, 0x82, 0x00), RGB(0xFF, 0xBE, 0x00),
53     RGB(0xFF, 0xFF, 0x00), RGB(0xBE, 0xFF, 0x00), RGB(0x82, 0xFF, 0x00), RGB(0x41, 0xFF, 0x00),
54     RGB(0x00, 0xFF, 0x00), RGB(0x00, 0xFF, 0x41), RGB(0x00, 0xFF, 0x82), RGB(0x00, 0xFF, 0xBE),
55     RGB(0x00, 0xFF, 0xFF), RGB(0x00, 0xBE, 0xFF), RGB(0x00, 0x82, 0xFF), RGB(0x00, 0x41, 0xFF),
56     RGB(0x82, 0x82, 0xFF), RGB(0x9E, 0x82, 0xFF), RGB(0xBE, 0x82, 0xFF), RGB(0xDF, 0x82, 0xFF),
57     RGB(0xFF, 0x82, 0xFF), RGB(0xFF, 0x82, 0xDF), RGB(0xFF, 0x82, 0xBE), RGB(0xFF, 0x82, 0x9E),
58     RGB(0xFF, 0x82, 0x82), RGB(0xFF, 0x9E, 0x82), RGB(0xFF, 0xBE, 0x82), RGB(0xFF, 0xDF, 0x82),
59     RGB(0xFF, 0xFF, 0x82), RGB(0xDF, 0xFF, 0x82), RGB(0xBE, 0xFF, 0x82), RGB(0x9E, 0xFF, 0x82),
60     RGB(0x82, 0xFF, 0x82), RGB(0x82, 0xFF, 0x9E), RGB(0x82, 0xFF, 0xBE), RGB(0x82, 0xFF, 0xDF),
61     RGB(0x82, 0xFF, 0xFF), RGB(0x82, 0xDF, 0xFF), RGB(0x82, 0xBE, 0xFF), RGB(0x82, 0x9E, 0xFF),
62     RGB(0xBA, 0xBA, 0xFF), RGB(0xCA, 0xBA, 0xFF), RGB(0xDF, 0xBA, 0xFF), RGB(0xEF, 0xBA, 0xFF),
63     RGB(0xFF, 0xBA, 0xFF), RGB(0xFF, 0xBA, 0xEF), RGB(0xFF, 0xBA, 0xDF), RGB(0xFF, 0xBA, 0xCA),
64     RGB(0xFF, 0xBA, 0xBA), RGB(0xFF, 0xCA, 0xBA), RGB(0xFF, 0xDF, 0xBA), RGB(0xFF, 0xEF, 0xBA),
65     RGB(0xFF, 0xFF, 0xBA), RGB(0xEF, 0xFF, 0xBA), RGB(0xDF, 0xFF, 0xBA), RGB(0xCA, 0xFF, 0xBA),
66     RGB(0xBA, 0xFF, 0xBA), RGB(0xBA, 0xFF, 0xCA), RGB(0xBA, 0xFF, 0xDF), RGB(0xBA, 0xFF, 0xEF),
67     RGB(0xBA, 0xFF, 0xFF), RGB(0xBA, 0xEF, 0xFF), RGB(0xBA, 0xDF, 0xFF), RGB(0xBA, 0xCA, 0xFF),
68     RGB(0x00, 0x00, 0x71), RGB(0x1C, 0x00, 0x71), RGB(0x39, 0x00, 0x71), RGB(0x55, 0x00, 0x71),
69     RGB(0x71, 0x00, 0x71), RGB(0x71, 0x00, 0x55), RGB(0x71, 0x00, 0x39), RGB(0x71, 0x00, 0x1C),
70     RGB(0x71, 0x00, 0x00), RGB(0x71, 0x1C, 0x00), RGB(0x71, 0x39, 0x00), RGB(0x71, 0x55, 0x00),
71     RGB(0x71, 0x71, 0x00), RGB(0x55, 0x71, 0x00), RGB(0x39, 0x71, 0x00), RGB(0x1C, 0x71, 0x00),
72     RGB(0x00, 0x71, 0x00), RGB(0x00, 0x71, 0x1C), RGB(0x00, 0x71, 0x39), RGB(0x00, 0x71, 0x55),
73     RGB(0x00, 0x71, 0x71), RGB(0x00, 0x55, 0x71), RGB(0x00, 0x39, 0x71), RGB(0x00, 0x1C, 0x71),
74     RGB(0x39, 0x39, 0x71), RGB(0x45, 0x39, 0x71), RGB(0x55, 0x39, 0x71), RGB(0x61, 0x39, 0x71),
75     RGB(0x71, 0x39, 0x71), RGB(0x71, 0x39, 0x61), RGB(0x71, 0x39, 0x55), RGB(0x71, 0x39, 0x45),
76     RGB(0x71, 0x39, 0x39), RGB(0x71, 0x45, 0x39), RGB(0x71, 0x55, 0x39), RGB(0x71, 0x61, 0x39),
77     RGB(0x71, 0x71, 0x39), RGB(0x61, 0x71, 0x39), RGB(0x55, 0x71, 0x39), RGB(0x45, 0x71, 0x39),
78     RGB(0x39, 0x71, 0x39), RGB(0x39, 0x71, 0x45), RGB(0x39, 0x71, 0x55), RGB(0x39, 0x71, 0x61),
79     RGB(0x39, 0x71, 0x71), RGB(0x39, 0x61, 0x71), RGB(0x39, 0x55, 0x71), RGB(0x39, 0x45, 0x71),
80     RGB(0x51, 0x51, 0x71), RGB(0x59, 0x51, 0x71), RGB(0x61, 0x51, 0x71), RGB(0x69, 0x51, 0x71),
81     RGB(0x71, 0x51, 0x71), RGB(0x71, 0x51, 0x69), RGB(0x71, 0x51, 0x61), RGB(0x71, 0x51, 0x59),
82     RGB(0x71, 0x51, 0x51), RGB(0x71, 0x59, 0x51), RGB(0x71, 0x61, 0x51), RGB(0x71, 0x69, 0x51),
83     RGB(0x71, 0x71, 0x51), RGB(0x69, 0x71, 0x51), RGB(0x61, 0x71, 0x51), RGB(0x59, 0x71, 0x51),
84     RGB(0x51, 0x71, 0x51), RGB(0x51, 0x71, 0x59), RGB(0x51, 0x71, 0x61), RGB(0x51, 0x71, 0x69),
85     RGB(0x51, 0x71, 0x71), RGB(0x51, 0x69, 0x71), RGB(0x51, 0x61, 0x71), RGB(0x51, 0x59, 0x71),
86     RGB(0x00, 0x00, 0x41), RGB(0x10, 0x00, 0x41), RGB(0x20, 0x00, 0x41), RGB(0x31, 0x00, 0x41),
87     RGB(0x41, 0x00, 0x41), RGB(0x41, 0x00, 0x31), RGB(0x41, 0x00, 0x20), RGB(0x41, 0x00, 0x10),
88     RGB(0x41, 0x00, 0x00), RGB(0x41, 0x10, 0x00), RGB(0x41, 0x20, 0x00), RGB(0x41, 0x31, 0x00),
89     RGB(0x41, 0x41, 0x00), RGB(0x31, 0x41, 0x00), RGB(0x20, 0x41, 0x00), RGB(0x10, 0x41, 0x00),
90     RGB(0x00, 0x41, 0x00), RGB(0x00, 0x41, 0x10), RGB(0x00, 0x41, 0x20), RGB(0x00, 0x41, 0x31),
91     RGB(0x00, 0x41, 0x41), RGB(0x00, 0x31, 0x41), RGB(0x00, 0x20, 0x41), RGB(0x00, 0x10, 0x41),
92     RGB(0x20, 0x20, 0x41), RGB(0x28, 0x20, 0x41), RGB(0x31, 0x20, 0x41), RGB(0x39, 0x20, 0x41),
93     RGB(0x41, 0x20, 0x41), RGB(0x41, 0x20, 0x39), RGB(0x41, 0x20, 0x31), RGB(0x41, 0x20, 0x28),
94     RGB(0x41, 0x20, 0x20), RGB(0x41, 0x28, 0x20), RGB(0x41, 0x31, 0x20), RGB(0x41, 0x39, 0x20),
95     RGB(0x41, 0x41, 0x20), RGB(0x39, 0x41, 0x20), RGB(0x31, 0x41, 0x20), RGB(0x28, 0x41, 0x20),
96     RGB(0x20, 0x41, 0x20), RGB(0x20, 0x41, 0x28), RGB(0x20, 0x41, 0x31), RGB(0x20, 0x41, 0x39),
97     RGB(0x20, 0x41, 0x41), RGB(0x20, 0x39, 0x41), RGB(0x20, 0x31, 0x41), RGB(0x20, 0x28, 0x41),
98     RGB(0x2D, 0x2D, 0x41), RGB(0x31, 0x2D, 0x41), RGB(0x35, 0x2D, 0x41), RGB(0x3D, 0x2D, 0x41),
99     RGB(0x41, 0x2D, 0x41), RGB(0x41, 0x2D, 0x3D), RGB(0x41, 0x2D, 0x35), RGB(0x41, 0x2D, 0x31),
100     RGB(0x41, 0x2D, 0x2D), RGB(0x41, 0x31, 0x2D), RGB(0x41, 0x35, 0x2D), RGB(0x41, 0x3D, 0x2D),
101     RGB(0x41, 0x41, 0x2D), RGB(0x3D, 0x41, 0x2D), RGB(0x35, 0x41, 0x2D), RGB(0x31, 0x41, 0x2D),
102     RGB(0x2D, 0x41, 0x2D), RGB(0x2D, 0x41, 0x31), RGB(0x2D, 0x41, 0x35), RGB(0x2D, 0x41, 0x3D),
103     RGB(0x2D, 0x41, 0x41), RGB(0x2D, 0x3D, 0x41), RGB(0x2D, 0x35, 0x41), RGB(0x2D, 0x31, 0x41),
104     RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00),
105     RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00)
106 };
107 
108 #elif defined(USE_DOSBOX_COLORS)
109 
110 // DOSBox colors
111 static CONST COLORREF VgaDefaultPalette[VGA_MAX_COLORS] =
112 {
113     RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0xAA), RGB(0x00, 0xAA, 0x00), RGB(0x00, 0xAA, 0xAA),
114     RGB(0xAA, 0x00, 0x00), RGB(0xAA, 0x00, 0xAA), RGB(0xAA, 0x55, 0x00), RGB(0xAA, 0xAA, 0xAA),
115     RGB(0x55, 0x55, 0x55), RGB(0x55, 0x55, 0xFF), RGB(0x55, 0xFF, 0x55), RGB(0x55, 0xFF, 0xFF),
116     RGB(0xFF, 0x55, 0x55), RGB(0xFF, 0x55, 0xFF), RGB(0xFF, 0xFF, 0x55), RGB(0xFF, 0xFF, 0xFF),
117     RGB(0x00, 0x00, 0x00), RGB(0x14, 0x14, 0x14), RGB(0x20, 0x20, 0x20), RGB(0x2C, 0x2C, 0x2C),
118     RGB(0x38, 0x38, 0x38), RGB(0x45, 0x45, 0x45), RGB(0x51, 0x51, 0x51), RGB(0x61, 0x61, 0x61),
119     RGB(0x71, 0x71, 0x71), RGB(0x82, 0x82, 0x82), RGB(0x92, 0x92, 0x92), RGB(0xA2, 0xA2, 0xA2),
120     RGB(0xB6, 0xB6, 0xB6), RGB(0xCB, 0xCB, 0xCB), RGB(0xE3, 0xE3, 0xE3), RGB(0xFF, 0xFF, 0xFF),
121     RGB(0x00, 0x00, 0xFF), RGB(0x41, 0x00, 0xFF), RGB(0x7D, 0x00, 0xFF), RGB(0xBE, 0x00, 0xFF),
122     RGB(0xFF, 0x00, 0xFF), RGB(0xFF, 0x00, 0xBE), RGB(0xFF, 0x00, 0x7D), RGB(0xFF, 0x00, 0x41),
123     RGB(0xFF, 0x00, 0x00), RGB(0xFF, 0x41, 0x00), RGB(0xFF, 0x7D, 0x00), RGB(0xFF, 0xBE, 0x00),
124     RGB(0xFF, 0xFF, 0x00), RGB(0xBE, 0xFF, 0x00), RGB(0x7D, 0xFF, 0x00), RGB(0x41, 0xFF, 0x00),
125     RGB(0x00, 0xFF, 0x00), RGB(0x00, 0xFF, 0x41), RGB(0x00, 0xFF, 0x7D), RGB(0x00, 0xFF, 0xBE),
126     RGB(0x00, 0xFF, 0xFF), RGB(0x00, 0xBE, 0xFF), RGB(0x00, 0x7D, 0xFF), RGB(0x00, 0x41, 0xFF),
127     RGB(0x7D, 0x7D, 0xFF), RGB(0x9E, 0x7D, 0xFF), RGB(0xBE, 0x7D, 0xFF), RGB(0xDF, 0x7D, 0xFF),
128     RGB(0xFF, 0x7D, 0xFF), RGB(0xFF, 0x7D, 0xDF), RGB(0xFF, 0x7D, 0xBE), RGB(0xFF, 0x7D, 0x9E),
129 
130     RGB(0xFF, 0x7D, 0x7D), RGB(0xFF, 0x9E, 0x7D), RGB(0xFF, 0xBE, 0x7D), RGB(0xFF, 0xDF, 0x7D),
131     RGB(0xFF, 0xFF, 0x7D), RGB(0xDF, 0xFF, 0x7D), RGB(0xBE, 0xFF, 0x7D), RGB(0x9E, 0xFF, 0x7D),
132     RGB(0x7D, 0xFF, 0x7D), RGB(0x7D, 0xFF, 0x9E), RGB(0x7D, 0xFF, 0xBE), RGB(0x7D, 0xFF, 0xDF),
133     RGB(0x7D, 0xFF, 0xFF), RGB(0x7D, 0xDF, 0xFF), RGB(0x7D, 0xBE, 0xFF), RGB(0x7D, 0x9E, 0xFF),
134     RGB(0xB6, 0xB6, 0xFF), RGB(0xC7, 0xB6, 0xFF), RGB(0xDB, 0xB6, 0xFF), RGB(0xEB, 0xB6, 0xFF),
135     RGB(0xFF, 0xB6, 0xFF), RGB(0xFF, 0xB6, 0xEB), RGB(0xFF, 0xB6, 0xDB), RGB(0xFF, 0xB6, 0xC7),
136     RGB(0xFF, 0xB6, 0xB6), RGB(0xFF, 0xC7, 0xB6), RGB(0xFF, 0xDB, 0xB6), RGB(0xFF, 0xEB, 0xB6),
137     RGB(0xFF, 0xFF, 0xB6), RGB(0xEB, 0xFF, 0xB6), RGB(0xDB, 0xFF, 0xB6), RGB(0xC7, 0xFF, 0xB6),
138     RGB(0xB6, 0xFF, 0xB6), RGB(0xB6, 0xFF, 0xC7), RGB(0xB6, 0xFF, 0xDB), RGB(0xB6, 0xFF, 0xEB),
139     RGB(0xB6, 0xFF, 0xFF), RGB(0xB6, 0xEB, 0xFF), RGB(0xB6, 0xDB, 0xFF), RGB(0xB6, 0xC7, 0xFF),
140     RGB(0x00, 0x00, 0x71), RGB(0x1C, 0x00, 0x71), RGB(0x38, 0x00, 0x71), RGB(0x55, 0x00, 0x71),
141     RGB(0x71, 0x00, 0x71), RGB(0x71, 0x00, 0x55), RGB(0x71, 0x00, 0x38), RGB(0x71, 0x00, 0x1C),
142     RGB(0x71, 0x00, 0x00), RGB(0x71, 0x1C, 0x00), RGB(0x71, 0x38, 0x00), RGB(0x71, 0x55, 0x00),
143     RGB(0x71, 0x71, 0x00), RGB(0x55, 0x71, 0x00), RGB(0x38, 0x71, 0x00), RGB(0x1C, 0x71, 0x00),
144     RGB(0x00, 0x71, 0x00), RGB(0x00, 0x71, 0x1C), RGB(0x00, 0x71, 0x38), RGB(0x00, 0x71, 0x55),
145     RGB(0x00, 0x71, 0x71), RGB(0x00, 0x55, 0x71), RGB(0x00, 0x38, 0x71), RGB(0x00, 0x1C, 0x71),
146 
147     RGB(0x38, 0x38, 0x71), RGB(0x45, 0x38, 0x71), RGB(0x55, 0x38, 0x71), RGB(0x61, 0x38, 0x71),
148     RGB(0x71, 0x38, 0x71), RGB(0x71, 0x38, 0x61), RGB(0x71, 0x38, 0x55), RGB(0x71, 0x38, 0x45),
149     RGB(0x71, 0x38, 0x38), RGB(0x71, 0x45, 0x38), RGB(0x71, 0x55, 0x38), RGB(0x71, 0x61, 0x38),
150     RGB(0x71, 0x71, 0x38), RGB(0x61, 0x71, 0x38), RGB(0x55, 0x71, 0x38), RGB(0x45, 0x71, 0x38),
151     RGB(0x38, 0x71, 0x38), RGB(0x38, 0x71, 0x45), RGB(0x38, 0x71, 0x55), RGB(0x38, 0x71, 0x61),
152     RGB(0x38, 0x71, 0x71), RGB(0x38, 0x61, 0x71), RGB(0x38, 0x55, 0x71), RGB(0x38, 0x45, 0x71),
153     RGB(0x51, 0x51, 0x71), RGB(0x59, 0x51, 0x71), RGB(0x61, 0x51, 0x71), RGB(0x69, 0x51, 0x71),
154     RGB(0x71, 0x51, 0x71), RGB(0x71, 0x51, 0x69), RGB(0x71, 0x51, 0x61), RGB(0x71, 0x51, 0x59),
155     RGB(0x71, 0x51, 0x51), RGB(0x71, 0x59, 0x51), RGB(0x71, 0x61, 0x51), RGB(0x71, 0x69, 0x51),
156     RGB(0x71, 0x71, 0x51), RGB(0x69, 0x71, 0x51), RGB(0x61, 0x71, 0x51), RGB(0x59, 0x71, 0x51),
157     RGB(0x51, 0x71, 0x51), RGB(0x51, 0x71, 0x59), RGB(0x51, 0x71, 0x61), RGB(0x51, 0x71, 0x69),
158     RGB(0x51, 0x71, 0x71), RGB(0x51, 0x69, 0x71), RGB(0x51, 0x61, 0x71), RGB(0x51, 0x59, 0x71),
159     RGB(0x00, 0x00, 0x41), RGB(0x10, 0x00, 0x41), RGB(0x20, 0x00, 0x41), RGB(0x30, 0x00, 0x41),
160     RGB(0x41, 0x00, 0x41), RGB(0x41, 0x00, 0x30), RGB(0x41, 0x00, 0x20), RGB(0x41, 0x00, 0x10),
161     RGB(0x41, 0x00, 0x00), RGB(0x41, 0x10, 0x00), RGB(0x41, 0x20, 0x00), RGB(0x41, 0x30, 0x00),
162     RGB(0x41, 0x41, 0x00), RGB(0x30, 0x41, 0x00), RGB(0x20, 0x41, 0x00), RGB(0x10, 0x41, 0x00),
163 
164     RGB(0x00, 0x41, 0x00), RGB(0x00, 0x41, 0x10), RGB(0x00, 0x41, 0x20), RGB(0x00, 0x41, 0x30),
165     RGB(0x00, 0x41, 0x41), RGB(0x00, 0x30, 0x41), RGB(0x00, 0x20, 0x41), RGB(0x00, 0x10, 0x41),
166     RGB(0x20, 0x20, 0x41), RGB(0x28, 0x20, 0x41), RGB(0x30, 0x20, 0x41), RGB(0x38, 0x20, 0x41),
167     RGB(0x41, 0x20, 0x41), RGB(0x41, 0x20, 0x38), RGB(0x41, 0x20, 0x30), RGB(0x41, 0x20, 0x28),
168     RGB(0x41, 0x20, 0x20), RGB(0x41, 0x28, 0x20), RGB(0x41, 0x30, 0x20), RGB(0x41, 0x38, 0x20),
169     RGB(0x41, 0x41, 0x20), RGB(0x38, 0x41, 0x20), RGB(0x30, 0x41, 0x20), RGB(0x28, 0x41, 0x20),
170     RGB(0x20, 0x41, 0x20), RGB(0x20, 0x41, 0x28), RGB(0x20, 0x41, 0x30), RGB(0x20, 0x41, 0x38),
171     RGB(0x20, 0x41, 0x41), RGB(0x20, 0x38, 0x41), RGB(0x20, 0x30, 0x41), RGB(0x20, 0x28, 0x41),
172     RGB(0x2C, 0x2C, 0x41), RGB(0x30, 0x2C, 0x41), RGB(0x34, 0x2C, 0x41), RGB(0x3C, 0x2C, 0x41),
173     RGB(0x41, 0x2C, 0x41), RGB(0x41, 0x2C, 0x3C), RGB(0x41, 0x2C, 0x34), RGB(0x41, 0x2C, 0x30),
174     RGB(0x41, 0x2C, 0x2C), RGB(0x41, 0x30, 0x2C), RGB(0x41, 0x34, 0x2C), RGB(0x41, 0x3C, 0x2C),
175     RGB(0x41, 0x41, 0x2C), RGB(0x3C, 0x41, 0x2C), RGB(0x34, 0x41, 0x2C), RGB(0x30, 0x41, 0x2C),
176     RGB(0x2C, 0x41, 0x2C), RGB(0x2C, 0x41, 0x30), RGB(0x2C, 0x41, 0x34), RGB(0x2C, 0x41, 0x3C),
177     RGB(0x2C, 0x41, 0x41), RGB(0x2C, 0x3C, 0x41), RGB(0x2C, 0x34, 0x41), RGB(0x2C, 0x30, 0x41),
178     RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00),
179     RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00)
180 };
181 
182 #endif
183 
184 /*
185  * Default 16-color palette for foreground and background
186  * (corresponding flags in comments).
187  * Taken from subsystems/win32/winsrv/consrv/frontends/gui/conwnd.c
188  */
189 static const COLORREF ConsoleColors[16] =
190 {
191     RGB(0, 0, 0),       // (Black)
192     RGB(0, 0, 128),     // BLUE
193     RGB(0, 128, 0),     // GREEN
194     RGB(0, 128, 128),   // BLUE  | GREEN
195     RGB(128, 0, 0),     // RED
196     RGB(128, 0, 128),   // BLUE  | RED
197     RGB(128, 128, 0),   // GREEN | RED
198     RGB(192, 192, 192), // BLUE  | GREEN | RED
199 
200     RGB(128, 128, 128), // (Grey)  INTENSITY
201     RGB(0, 0, 255),     // BLUE  | INTENSITY
202     RGB(0, 255, 0),     // GREEN | INTENSITY
203     RGB(0, 255, 255),   // BLUE  | GREEN | INTENSITY
204     RGB(255, 0, 0),     // RED   | INTENSITY
205     RGB(255, 0, 255),   // BLUE  | RED   | INTENSITY
206     RGB(255, 255, 0),   // GREEN | RED   | INTENSITY
207     RGB(255, 255, 255)  // BLUE  | GREEN | RED | INTENSITY
208 };
209 
210 /// ConsoleFramebuffer
211 static PVOID ActiveFramebuffer = NULL; // Active framebuffer, points to
212                                        // either TextFramebuffer or a
213                                        // valid graphics framebuffer.
214 static HPALETTE TextPaletteHandle = NULL;
215 static HPALETTE PaletteHandle = NULL;
216 
217 /*
218  * Text mode -- we always keep a valid text mode framebuffer
219  * even if we are in graphics mode. This is needed in order
220  * to keep a consistent VGA state. However, each time the VGA
221  * detaches from the console (and reattaches to it later on),
222  * this text mode framebuffer is recreated.
223  */
224 static PCHAR_CELL TextFramebuffer = NULL;
225 
226 /*
227  * Graphics mode
228  */
229 static PBYTE GraphicsFramebuffer = NULL;
230 
231 
232 // static HANDLE ConsoleMutex = NULL;
233 // /* DoubleVision support */
234 // static BOOLEAN DoubleWidth  = FALSE;
235 // static BOOLEAN DoubleHeight = FALSE;
236 
237 
238 
239 
240 
241 /*
242  * VGA Hardware
243  */
244 static BYTE VgaMemory[VGA_NUM_BANKS * SVGA_BANK_SIZE];
245 
246 static BYTE VgaLatchRegisters[VGA_NUM_BANKS] = {0, 0, 0, 0};
247 
248 static BYTE VgaMiscRegister;
249 static BYTE VgaFeatureRegister;
250 
251 static BYTE VgaSeqIndex = VGA_SEQ_RESET_REG;
252 static BYTE VgaSeqRegisters[SVGA_SEQ_MAX_REG];
253 
254 static BYTE VgaCrtcIndex = VGA_CRTC_HORZ_TOTAL_REG;
255 static BYTE VgaCrtcRegisters[SVGA_CRTC_MAX_REG];
256 
257 static BYTE VgaGcIndex = VGA_GC_RESET_REG;
258 static BYTE VgaGcRegisters[SVGA_GC_MAX_REG];
259 
260 static BOOLEAN VgaAcLatch = FALSE;
261 static BOOLEAN VgaAcPalDisable = TRUE;
262 static BYTE VgaAcIndex = VGA_AC_PAL_0_REG;
263 static BYTE VgaAcRegisters[VGA_AC_MAX_REG];
264 
265 static BYTE VgaDacMask  = 0xFF;
266 static BYTE VgaDacLatchCounter = 0;
267 static BYTE VgaDacLatch[3];
268 
269 static BOOLEAN VgaDacReadWrite = FALSE;
270 static WORD VgaDacIndex = 0;
271 static BYTE VgaDacRegisters[VGA_PALETTE_SIZE];
272 
273 // static VGA_REGISTERS VgaRegisters;
274 
275 static ULONGLONG HorizontalRetraceCycle = 0ULL;
276 static PHARDWARE_TIMER HSyncTimer;
277 static DWORD ScanlineCounter = 0;
278 static DWORD StartAddressLatch = 0;
279 static DWORD ScanlineSizeLatch = 0;
280 
281 static BOOLEAN NeedsUpdate = FALSE;
282 static BOOLEAN ModeChanged = FALSE;
283 static BOOLEAN CursorChanged  = FALSE;
284 static BOOLEAN PaletteChanged = FALSE;
285 
286 static UINT SvgaHdrCounter = 0;
287 static BYTE SvgaHiddenRegister = 0;
288 
289 typedef enum _SCREEN_MODE
290 {
291     TEXT_MODE,
292     GRAPHICS_MODE
293 } SCREEN_MODE, *PSCREEN_MODE;
294 
295 static SCREEN_MODE ScreenMode = TEXT_MODE;
296 static COORD CurrResolution   = {0};
297 
298 static SMALL_RECT UpdateRectangle = { 0, 0, 0, 0 };
299 
300 
301 
302 
303 /** HACK!! **/
304 #include "../../console/video.c"
305 /** HACK!! **/
306 
307 
308 
309 
310 
311 /* PRIVATE FUNCTIONS **********************************************************/
312 
VgaGetVideoBaseAddress(VOID)313 static inline DWORD VgaGetVideoBaseAddress(VOID)
314 {
315     return MemoryBase[(VgaGcRegisters[VGA_GC_MISC_REG] >> 2) & 0x03];
316 }
317 
VgaGetAddressSize(VOID)318 static inline DWORD VgaGetAddressSize(VOID)
319 {
320     if (VgaSeqRegisters[SVGA_SEQ_EXT_MODE_REG] & SVGA_SEQ_EXT_MODE_HIGH_RES)
321     {
322         /* Packed pixel addressing */
323         return 1;
324     }
325     else if (VgaCrtcRegisters[VGA_CRTC_UNDERLINE_REG] & VGA_CRTC_UNDERLINE_DWORD)
326     {
327         /* Double-word addressing */
328         return 4; // sizeof(DWORD)
329     }
330     else if (VgaCrtcRegisters[VGA_CRTC_MODE_CONTROL_REG] & VGA_CRTC_MODE_CONTROL_BYTE)
331     {
332         /* Byte addressing */
333         return 1; // sizeof(BYTE)
334     }
335     else
336     {
337         /* Word addressing */
338         return 2; // sizeof(WORD)
339     }
340 }
341 
VgaTranslateAddress(DWORD Address)342 static inline DWORD VgaTranslateAddress(DWORD Address)
343 {
344     DWORD Offset = LOWORD(Address - VgaGetVideoBaseAddress());
345     DWORD ExtOffset = ((VgaGcRegisters[SVGA_GC_EXT_MODE_REG] & SVGA_GC_EXT_MODE_WND_B) && (Offset & (1 << 15)))
346                       ? VgaGcRegisters[SVGA_GC_OFFSET_1_REG]
347                       : VgaGcRegisters[SVGA_GC_OFFSET_0_REG];
348 
349     /* Check for chain-4 and odd-even mode */
350     if (VgaSeqRegisters[VGA_SEQ_MEM_REG] & VGA_SEQ_MEM_C4)
351     {
352         /* Clear the lowest two bits since they're used to select the bank */
353         Offset &= ~3;
354     }
355     else if (VgaGcRegisters[VGA_GC_MODE_REG] & VGA_GC_MODE_OE)
356     {
357         /* Clear the lowest bit since it's used to select odd/even */
358         Offset &= ~1;
359     }
360 
361     if (ExtOffset)
362     {
363         /* Add the extended offset */
364         Offset += ExtOffset << ((VgaGcRegisters[SVGA_GC_EXT_MODE_REG] & SVGA_GC_EXT_MODE_GRAN) ? 14 : 12);
365     }
366 
367     /* Return the offset on plane 0 */
368     return Offset;
369 }
370 
VgaTranslateByteForWriting(BYTE Data,BYTE Plane)371 static inline BYTE VgaTranslateByteForWriting(BYTE Data, BYTE Plane)
372 {
373     BYTE WriteMode = VgaGcRegisters[VGA_GC_MODE_REG] & 0x03;
374     BYTE BitMask = VgaGcRegisters[VGA_GC_BITMASK_REG];
375 
376     if (WriteMode == 1)
377     {
378         /* In write mode 1 just return the latch register */
379         return VgaLatchRegisters[Plane];
380     }
381 
382     if (WriteMode != 2)
383     {
384         /* Write modes 0 and 3 rotate the data to the right first */
385         BYTE RotateCount = VgaGcRegisters[VGA_GC_ROTATE_REG] & 0x07;
386         Data = LOBYTE(((DWORD)Data >> RotateCount) | ((DWORD)Data << (8 - RotateCount)));
387     }
388     else
389     {
390         /* Write mode 2 expands the appropriate bit to all 8 bits */
391         Data = (Data & (1 << Plane)) ? 0xFF : 0x00;
392     }
393 
394     if (WriteMode == 0)
395     {
396         /*
397          * In write mode 0, the enable set/reset register decides if the
398          * set/reset bit should be expanded to all 8 bits.
399          */
400         if (VgaGcRegisters[VGA_GC_ENABLE_RESET_REG] & (1 << Plane))
401         {
402             /* Copy the bit from the set/reset register to all 8 bits */
403             Data = (VgaGcRegisters[VGA_GC_RESET_REG] & (1 << Plane)) ? 0xFF : 0x00;
404         }
405     }
406 
407     if (WriteMode != 3)
408     {
409         /* Write modes 0 and 2 then perform a logical operation on the data and latch */
410         BYTE LogicalOperation = (VgaGcRegisters[VGA_GC_ROTATE_REG] >> 3) & 0x03;
411 
412         if (LogicalOperation == 1) Data &= VgaLatchRegisters[Plane];
413         else if (LogicalOperation == 2) Data |= VgaLatchRegisters[Plane];
414         else if (LogicalOperation == 3) Data ^= VgaLatchRegisters[Plane];
415     }
416     else
417     {
418         /* For write mode 3, we AND the bitmask with the data, which is used as the new bitmask */
419         BitMask &= Data;
420 
421         /* Then we expand the bit in the set/reset field */
422         Data = (VgaGcRegisters[VGA_GC_RESET_REG] & (1 << Plane)) ? 0xFF : 0x00;
423     }
424 
425     /* Bits cleared in the bitmask are replaced with latch register bits */
426     Data = (Data & BitMask) | (VgaLatchRegisters[Plane] & (~BitMask));
427 
428     /* Return the byte */
429     return Data;
430 }
431 
VgaGetClockFrequency(VOID)432 static inline ULONG VgaGetClockFrequency(VOID)
433 {
434     BYTE Numerator, Denominator;
435 
436     if (VgaSeqRegisters[SVGA_SEQ_MCLK_REG] & SVGA_SEQ_MCLK_VCLK)
437     {
438         /* The VCLK is being generated using the MCLK */
439         ULONG Clock = (VGA_CLOCK_BASE * (VgaSeqRegisters[SVGA_SEQ_MCLK_REG] & 0x3F)) >> 3;
440 
441         if (VgaSeqRegisters[SVGA_SEQ_VCLK3_DENOMINATOR_REG] & 1)
442         {
443             /* Use only half of the MCLK as the VCLK */
444             Clock >>= 1;
445         }
446 
447         return Clock;
448     }
449 
450     switch ((VgaMiscRegister >> 2) & 3)
451     {
452         case 0:
453         {
454             Numerator = VgaSeqRegisters[SVGA_SEQ_VCLK0_NUMERATOR_REG];
455             Denominator = VgaSeqRegisters[SVGA_SEQ_VCLK0_DENOMINATOR_REG];
456             break;
457         }
458 
459         case 1:
460         {
461             Numerator = VgaSeqRegisters[SVGA_SEQ_VCLK1_NUMERATOR_REG];
462             Denominator = VgaSeqRegisters[SVGA_SEQ_VCLK1_DENOMINATOR_REG];
463             break;
464         }
465 
466         case 2:
467         {
468             Numerator = VgaSeqRegisters[SVGA_SEQ_VCLK2_NUMERATOR_REG];
469             Denominator = VgaSeqRegisters[SVGA_SEQ_VCLK2_DENOMINATOR_REG];
470             break;
471         }
472 
473         case 3:
474         {
475             Numerator = VgaSeqRegisters[SVGA_SEQ_VCLK3_NUMERATOR_REG];
476             Denominator = VgaSeqRegisters[SVGA_SEQ_VCLK3_DENOMINATOR_REG];
477             break;
478         }
479     }
480 
481     /* The numerator is 7-bit */
482     Numerator &= ~(1 << 7);
483 
484     /* If bit 7 is clear, the denominator is 5-bit */
485     if (!(Denominator & (1 << 7))) Denominator &= ~(1 << 6);
486 
487     /* Bit 0 of the denominator is the post-scalar bit */
488     if (Denominator & 1) Denominator &= ~1;
489     else Denominator >>= 1;
490 
491     /* Return the clock frequency in Hz */
492     return (VGA_CLOCK_BASE * Numerator) / Denominator;
493 }
494 
VgaResetSequencer(VOID)495 static VOID VgaResetSequencer(VOID)
496 {
497     /* Lock extended SVGA registers */
498     VgaSeqRegisters[SVGA_SEQ_UNLOCK_REG] = SVGA_SEQ_LOCKED;
499 
500     /* Initialize the VCLKs */
501     VgaSeqRegisters[SVGA_SEQ_VCLK0_NUMERATOR_REG]   = 0x66;
502     VgaSeqRegisters[SVGA_SEQ_VCLK0_DENOMINATOR_REG] = 0x3B;
503     VgaSeqRegisters[SVGA_SEQ_VCLK1_NUMERATOR_REG]   = 0x5B;
504     VgaSeqRegisters[SVGA_SEQ_VCLK1_DENOMINATOR_REG] = 0x2F;
505     VgaSeqRegisters[SVGA_SEQ_VCLK2_NUMERATOR_REG]   = 0x45;
506     VgaSeqRegisters[SVGA_SEQ_VCLK2_DENOMINATOR_REG] = 0x30;
507     VgaSeqRegisters[SVGA_SEQ_VCLK3_NUMERATOR_REG]   = 0x7E;
508     VgaSeqRegisters[SVGA_SEQ_VCLK3_DENOMINATOR_REG] = 0x33;
509 
510     /* 50 MHz MCLK, not being used as the VCLK */
511     VgaSeqRegisters[SVGA_SEQ_MCLK_REG] = 0x1C;
512 }
513 
VgaRestoreDefaultPalette(PPALETTEENTRY Entries,USHORT NumOfEntries)514 static VOID VgaRestoreDefaultPalette(PPALETTEENTRY Entries, USHORT NumOfEntries)
515 {
516     USHORT i;
517 
518     /* Copy the colors of the default palette to the DAC and console palette */
519     for (i = 0; i < NumOfEntries; i++)
520     {
521         /* Set the palette entries */
522         Entries[i].peRed   = GetRValue(VgaDefaultPalette[i]);
523         Entries[i].peGreen = GetGValue(VgaDefaultPalette[i]);
524         Entries[i].peBlue  = GetBValue(VgaDefaultPalette[i]);
525         Entries[i].peFlags = 0;
526 
527         /* Set the DAC registers */
528         VgaDacRegisters[i * 3]     = VGA_COLOR_TO_DAC(GetRValue(VgaDefaultPalette[i]));
529         VgaDacRegisters[i * 3 + 1] = VGA_COLOR_TO_DAC(GetGValue(VgaDefaultPalette[i]));
530         VgaDacRegisters[i * 3 + 2] = VGA_COLOR_TO_DAC(GetBValue(VgaDefaultPalette[i]));
531     }
532 }
533 
VgaInitializePalette(VOID)534 static BOOLEAN VgaInitializePalette(VOID)
535 {
536     UINT i;
537     BOOLEAN Result = FALSE;
538     LPLOGPALETTE Palette, TextPalette;
539 
540     /* Allocate storage space for the palettes */
541     Palette = RtlAllocateHeap(RtlGetProcessHeap(),
542                               HEAP_ZERO_MEMORY,
543                               sizeof(LOGPALETTE) +
544                                   VGA_MAX_COLORS * sizeof(PALETTEENTRY));
545     TextPalette = RtlAllocateHeap(RtlGetProcessHeap(),
546                                   HEAP_ZERO_MEMORY,
547                                   sizeof(LOGPALETTE) +
548                                       (VGA_AC_PAL_F_REG + 1) * sizeof(PALETTEENTRY));
549     if ((Palette == NULL) || (TextPalette == NULL)) goto Cleanup;
550 
551     /* Initialize the palettes */
552     Palette->palVersion = TextPalette->palVersion = 0x0300;
553     Palette->palNumEntries = VGA_MAX_COLORS;
554     TextPalette->palNumEntries = VGA_AC_PAL_F_REG + 1;
555 
556     /* Restore the default graphics palette */
557     VgaRestoreDefaultPalette(Palette->palPalEntry, Palette->palNumEntries);
558 
559     /* Set the default text palette */
560     for (i = 0; i < TextPalette->palNumEntries; i++)
561     {
562         /* Set the palette entries */
563         TextPalette->palPalEntry[i].peRed   = GetRValue(ConsoleColors[i]);
564         TextPalette->palPalEntry[i].peGreen = GetGValue(ConsoleColors[i]);
565         TextPalette->palPalEntry[i].peBlue  = GetBValue(ConsoleColors[i]);
566         TextPalette->palPalEntry[i].peFlags = 0;
567     }
568 
569     /* Create the palettes */
570     PaletteHandle = CreatePalette(Palette);
571     TextPaletteHandle = CreatePalette(TextPalette);
572 
573     if (PaletteHandle != NULL && TextPaletteHandle != NULL)
574     {
575         /* The palettes have been created successfully */
576         Result = TRUE;
577     }
578 
579 Cleanup:
580     /* Free the palettes */
581     if (Palette) RtlFreeHeap(RtlGetProcessHeap(), 0, Palette);
582     if (TextPalette) RtlFreeHeap(RtlGetProcessHeap(), 0, TextPalette);
583 
584     if (!Result)
585     {
586         /* Something failed, delete the palettes */
587         if (PaletteHandle) DeleteObject(PaletteHandle);
588         if (TextPaletteHandle) DeleteObject(TextPaletteHandle);
589     }
590 
591     return Result;
592 }
593 
VgaResetPalette(VOID)594 static VOID VgaResetPalette(VOID)
595 {
596     PALETTEENTRY Entries[VGA_MAX_COLORS];
597 
598     /* Restore the default palette */
599     VgaRestoreDefaultPalette(Entries, VGA_MAX_COLORS);
600     SetPaletteEntries(PaletteHandle, 0, VGA_MAX_COLORS, Entries);
601     PaletteChanged = TRUE;
602 }
603 
VgaEnterNewMode(SCREEN_MODE NewScreenMode,PCOORD Resolution)604 static BOOL VgaEnterNewMode(SCREEN_MODE NewScreenMode, PCOORD Resolution)
605 {
606     /* Check if the new mode is alphanumeric */
607     if (NewScreenMode == TEXT_MODE)
608     {
609         /* Enter new text mode */
610 
611         if (!VgaConsoleCreateTextScreen(// &TextFramebuffer,
612                                         Resolution,
613                                         TextPaletteHandle))
614         {
615             DisplayMessage(L"An unexpected VGA error occurred while switching into text mode. Error: %u", GetLastError());
616             EmulatorTerminate();
617             return FALSE;
618         }
619 
620         /* The active framebuffer is now the text framebuffer */
621         ActiveFramebuffer = TextFramebuffer;
622 
623         /* Set the screen mode flag */
624         ScreenMode = TEXT_MODE;
625 
626         return TRUE;
627     }
628     else
629     {
630         /* Enter graphics mode */
631 
632         if (!VgaConsoleCreateGraphicsScreen(// &GraphicsFramebuffer,
633                                             Resolution,
634                                             PaletteHandle))
635         {
636             DisplayMessage(L"An unexpected VGA error occurred while switching into graphics mode. Error: %u", GetLastError());
637             EmulatorTerminate();
638             return FALSE;
639         }
640 
641         /* The active framebuffer is now the graphics framebuffer */
642         ActiveFramebuffer = GraphicsFramebuffer;
643 
644         /* Set the screen mode flag */
645         ScreenMode = GRAPHICS_MODE;
646 
647         return TRUE;
648     }
649 }
650 
VgaLeaveCurrentMode(VOID)651 static VOID VgaLeaveCurrentMode(VOID)
652 {
653     /* Leave the current video mode */
654     if (ScreenMode == GRAPHICS_MODE)
655     {
656         VgaConsoleDestroyGraphicsScreen();
657 
658         /* Cleanup the video data */
659         GraphicsFramebuffer = NULL;
660     }
661     else
662     {
663         VgaConsoleDestroyTextScreen();
664 
665         /* Cleanup the video data */
666         // TextFramebuffer = NULL;
667         // NEVER SET the ALWAYS-SET TextFramebuffer pointer to NULL!!
668     }
669 
670     /* Reset the active framebuffer */
671     ActiveFramebuffer = NULL;
672 }
673 
VgaChangeMode(VOID)674 static VOID VgaChangeMode(VOID)
675 {
676     COORD NewResolution = VgaGetDisplayResolution();
677     SCREEN_MODE NewScreenMode =
678         !(VgaGcRegisters[VGA_GC_MISC_REG] & VGA_GC_MISC_NOALPHA) ? TEXT_MODE
679                                                                  : GRAPHICS_MODE;
680 
681     /*
682      * Do not switch to a different screen mode + resolution if the new settings
683      * are the same as the old ones. Just repaint the full screen.
684      */
685     if ((ScreenMode == NewScreenMode) && // CurrResolution == NewResolution
686         (CurrResolution.X == NewResolution.X && CurrResolution.Y == NewResolution.Y))
687     {
688         goto Quit;
689     }
690 
691     // FIXME: Wouldn't it be preferrable to switch to the new console SB
692     // *ONLY* if we succeeded in setting the new mode??
693 
694     /* Leave the current video mode */
695     VgaLeaveCurrentMode(); // ScreenMode
696 
697     /* Update the current resolution */
698     CurrResolution = NewResolution;
699 
700     /* Change the screen mode */
701     if (!VgaEnterNewMode(NewScreenMode, &CurrResolution))
702         return;
703 
704 Quit:
705 
706     /* Trigger a full update of the screen */
707     NeedsUpdate = TRUE;
708     UpdateRectangle.Left = 0;
709     UpdateRectangle.Top  = 0;
710     UpdateRectangle.Right  = CurrResolution.X;
711     UpdateRectangle.Bottom = CurrResolution.Y;
712 
713     /* Reset the mode change flag */
714     ModeChanged = FALSE;
715 }
716 
VgaMarkForUpdate(SHORT Row,SHORT Column)717 static inline VOID VgaMarkForUpdate(SHORT Row, SHORT Column)
718 {
719     /* Check if this is the first time the rectangle is updated */
720     if (!NeedsUpdate)
721     {
722         UpdateRectangle.Left = UpdateRectangle.Top = MAXSHORT;
723         UpdateRectangle.Right = UpdateRectangle.Bottom = MINSHORT;
724     }
725 
726     /* Expand the rectangle to include the point */
727     UpdateRectangle.Left = min(UpdateRectangle.Left, Column);
728     UpdateRectangle.Right = max(UpdateRectangle.Right, Column);
729     UpdateRectangle.Top = min(UpdateRectangle.Top, Row);
730     UpdateRectangle.Bottom = max(UpdateRectangle.Bottom, Row);
731 
732     /* Set the update request flag */
733     NeedsUpdate = TRUE;
734 }
735 
VgaUpdateFramebuffer(VOID)736 static VOID VgaUpdateFramebuffer(VOID)
737 {
738     SHORT i, j, k;
739     DWORD AddressSize = VgaGetAddressSize();
740     DWORD Address = StartAddressLatch;
741     BYTE BytePanning = (VgaCrtcRegisters[VGA_CRTC_PRESET_ROW_SCAN_REG] >> 5) & 3;
742     WORD LineCompare = VgaCrtcRegisters[VGA_CRTC_LINE_COMPARE_REG]
743                        | ((VgaCrtcRegisters[VGA_CRTC_OVERFLOW_REG] & VGA_CRTC_OVERFLOW_LC8) << 4)
744                        | ((VgaCrtcRegisters[VGA_CRTC_MAX_SCAN_LINE_REG] & VGA_CRTC_MAXSCANLINE_LC9) << 3);
745     BYTE PixelShift = VgaAcRegisters[VGA_AC_HORZ_PANNING_REG] & 0x0F;
746 
747     /*
748      * If the console framebuffer is NULL, that means something
749      * went wrong earlier and this is the final display refresh.
750      */
751     if (ActiveFramebuffer == NULL) return;
752 
753     /* Check if we are in text or graphics mode */
754     if (ScreenMode == GRAPHICS_MODE)
755     {
756         /* Graphics mode */
757         PBYTE GraphicsBuffer = (PBYTE)ActiveFramebuffer;
758         DWORD InterlaceHighBit = VGA_INTERLACE_HIGH_BIT;
759         SHORT X;
760 
761         /*
762          * Synchronize access to the graphics framebuffer
763          * with the console framebuffer mutex.
764          */
765         WaitForSingleObject(ConsoleMutex, INFINITE);
766 
767         /* Shift the high bit right by 1 in odd/even mode */
768         if (VgaGcRegisters[VGA_GC_MODE_REG] & VGA_GC_MODE_OE)
769         {
770             InterlaceHighBit >>= 1;
771         }
772 
773         if (VgaCrtcRegisters[VGA_CRTC_MAX_SCAN_LINE_REG] & VGA_CRTC_MAXSCANLINE_DOUBLE)
774         {
775             /* Halve the line compare value */
776             LineCompare >>= 1;
777         }
778         else
779         {
780             /* Divide the line compare value by the maximum scan line */
781             LineCompare /= 1 + (VgaCrtcRegisters[VGA_CRTC_MAX_SCAN_LINE_REG] & 0x1F);
782         }
783 
784         /* Loop through the scanlines */
785         for (i = 0; i < CurrResolution.Y; i++)
786         {
787             if (i == LineCompare)
788             {
789                 if (VgaAcRegisters[VGA_AC_CONTROL_REG] & VGA_AC_CONTROL_PPM)
790                 {
791                     /*
792                      * Disable the pixel shift count and byte panning
793                      * for the rest of the display cycle
794                      */
795                     PixelShift = 0;
796                     BytePanning = 0;
797                 }
798 
799                 /* Reset the address, but assume the preset row scan is 0 */
800                 Address = BytePanning;
801             }
802 
803             if ((VgaGcRegisters[VGA_GC_MISC_REG] & VGA_GC_MISC_OE) && (i & 1))
804             {
805                 /* Odd-numbered line in interlaced mode - set the high bit */
806                 Address |= InterlaceHighBit;
807             }
808 
809             /* Loop through the pixels */
810             for (j = 0; j < CurrResolution.X; j++)
811             {
812                 BYTE PixelData = 0;
813 
814                 /* Apply horizontal pixel panning */
815                 if (VgaAcRegisters[VGA_AC_CONTROL_REG] & VGA_AC_CONTROL_8BIT)
816                 {
817                     X = j + ((PixelShift >> 1) & 0x03);
818                 }
819                 else
820                 {
821                     X = j + ((PixelShift < 8) ? PixelShift : -1);
822                 }
823 
824                 if (VgaSeqRegisters[SVGA_SEQ_EXT_MODE_REG] & SVGA_SEQ_EXT_MODE_HIGH_RES)
825                 {
826                     // TODO: Check for high color modes
827 
828                     /* 256 color mode */
829                     PixelData = VgaMemory[Address + X];
830                 }
831                 else
832                 {
833                     /* Check the shifting mode */
834                     if (VgaGcRegisters[VGA_GC_MODE_REG] & VGA_GC_MODE_SHIFT256)
835                     {
836                         /* 4 bits shifted from each plane */
837 
838                         /* Check if this is 16 or 256 color mode */
839                         if (VgaAcRegisters[VGA_AC_CONTROL_REG] & VGA_AC_CONTROL_8BIT)
840                         {
841                             /* One byte per pixel */
842                             PixelData = VgaMemory[WRAP_OFFSET((Address + (X / VGA_NUM_BANKS)) * AddressSize)
843                                                   * VGA_NUM_BANKS + (X % VGA_NUM_BANKS)];
844                         }
845                         else
846                         {
847                             /* 4-bits per pixel */
848 
849                             PixelData = VgaMemory[WRAP_OFFSET((Address + (X / (VGA_NUM_BANKS * 2))) * AddressSize)
850                                                   * VGA_NUM_BANKS + ((X / 2) % VGA_NUM_BANKS)];
851 
852                             /* Check if we should use the highest 4 bits or lowest 4 */
853                             if ((X % 2) == 0)
854                             {
855                                 /* Highest 4 */
856                                 PixelData >>= 4;
857                             }
858                             else
859                             {
860                                 /* Lowest 4 */
861                                 PixelData &= 0x0F;
862                             }
863                         }
864                     }
865                     else if (VgaGcRegisters[VGA_GC_MODE_REG] & VGA_GC_MODE_SHIFTREG)
866                     {
867                         /* Check if this is 16 or 256 color mode */
868                         if (VgaAcRegisters[VGA_AC_CONTROL_REG] & VGA_AC_CONTROL_8BIT)
869                         {
870                             // TODO: NOT IMPLEMENTED
871                             DPRINT1("8-bit interleaved mode is not implemented!\n");
872                         }
873                         else
874                         {
875                             /*
876                              * 2 bits shifted from plane 0 and 2 for the first 4 pixels,
877                              * then 2 bits shifted from plane 1 and 3 for the next 4
878                              */
879                             DWORD BankNumber = (X / 4) % 2;
880                             DWORD Offset = Address + (X / 8);
881                             BYTE LowPlaneData = VgaMemory[WRAP_OFFSET(Offset * AddressSize) * VGA_NUM_BANKS + BankNumber];
882                             BYTE HighPlaneData = VgaMemory[WRAP_OFFSET(Offset * AddressSize) * VGA_NUM_BANKS + (BankNumber + 2)];
883 
884                             /* Extract the two bits from each plane */
885                             LowPlaneData  = (LowPlaneData  >> (6 - ((X % 4) * 2))) & 0x03;
886                             HighPlaneData = (HighPlaneData >> (6 - ((X % 4) * 2))) & 0x03;
887 
888                             /* Combine them into the pixel */
889                             PixelData = LowPlaneData | (HighPlaneData << 2);
890                         }
891                     }
892                     else
893                     {
894                         /* 1 bit shifted from each plane */
895 
896                         /* Check if this is 16 or 256 color mode */
897                         if (VgaAcRegisters[VGA_AC_CONTROL_REG] & VGA_AC_CONTROL_8BIT)
898                         {
899                             /* 8 bits per pixel, 2 on each plane */
900 
901                             for (k = 0; k < VGA_NUM_BANKS; k++)
902                             {
903                                 /* The data is on plane k, 4 pixels per byte */
904                                 BYTE PlaneData = VgaMemory[WRAP_OFFSET((Address + (X >> 2)) * AddressSize) * VGA_NUM_BANKS + k];
905 
906                                 /* The mask of the first bit in the pair */
907                                 BYTE BitMask = 1 << (((3 - (X % VGA_NUM_BANKS)) * 2) + 1);
908 
909                                 /* Bits 0, 1, 2 and 3 come from the first bit of the pair */
910                                 if (PlaneData & BitMask) PixelData |= 1 << k;
911 
912                                 /* Bits 4, 5, 6 and 7 come from the second bit of the pair */
913                                 if (PlaneData & (BitMask >> 1)) PixelData |= 1 << (k + 4);
914                             }
915                         }
916                         else
917                         {
918                             /* 4 bits per pixel, 1 on each plane */
919 
920                             for (k = 0; k < VGA_NUM_BANKS; k++)
921                             {
922                                 BYTE PlaneData = VgaMemory[WRAP_OFFSET((Address + (X >> 3)) * AddressSize) * VGA_NUM_BANKS + k];
923 
924                                 /* If the bit on that plane is set, set it */
925                                 if (PlaneData & (1 << (7 - (X % 8)))) PixelData |= 1 << k;
926                             }
927                         }
928                     }
929                 }
930 
931                 if (!(VgaAcRegisters[VGA_AC_CONTROL_REG] & VGA_AC_CONTROL_8BIT))
932                 {
933                     /*
934                      * In 16 color mode, the value is an index to the AC registers
935                      * if external palette access is disabled, otherwise (in case
936                      * of palette loading) it is a blank pixel.
937                      */
938 
939                     if (VgaAcPalDisable)
940                     {
941                         if (!(VgaAcRegisters[VGA_AC_CONTROL_REG] & VGA_AC_CONTROL_P54S))
942                         {
943                             /* Bits 4 and 5 are taken from the palette register */
944                             PixelData = ((VgaAcRegisters[VGA_AC_COLOR_SEL_REG] << 4) & 0xC0)
945                                         | (VgaAcRegisters[PixelData & 0x0F] & 0x3F);
946                         }
947                         else
948                         {
949                             /* Bits 4 and 5 are taken from the color select register */
950                             PixelData = (VgaAcRegisters[VGA_AC_COLOR_SEL_REG] << 4)
951                                         | (VgaAcRegisters[PixelData & 0x0F] & 0x0F);
952                         }
953                     }
954                     else
955                     {
956                         PixelData = 0;
957                     }
958                 }
959 
960                 /* Take into account DoubleVision mode when checking for pixel updates */
961                 if (DoubleWidth && DoubleHeight)
962                 {
963                     /* Now check if the resulting pixel data has changed */
964                     if (GraphicsBuffer[(i * 2 * CurrResolution.X * 2) + (j * 2)] != PixelData)
965                     {
966                         /* Yes, write the new value */
967                         GraphicsBuffer[(i * 2 * CurrResolution.X * 2) + (j * 2)] = PixelData;
968                         GraphicsBuffer[(i * 2 * CurrResolution.X * 2) + (j * 2 + 1)] = PixelData;
969                         GraphicsBuffer[((i * 2 + 1) * CurrResolution.X * 2) + (j * 2)] = PixelData;
970                         GraphicsBuffer[((i * 2 + 1) * CurrResolution.X * 2) + (j * 2 + 1)] = PixelData;
971 
972                         /* Mark the specified pixel as changed */
973                         VgaMarkForUpdate(i, j);
974                     }
975                 }
976                 else if (DoubleWidth && !DoubleHeight)
977                 {
978                     /* Now check if the resulting pixel data has changed */
979                     if (GraphicsBuffer[(i * CurrResolution.X * 2) + (j * 2)] != PixelData)
980                     {
981                         /* Yes, write the new value */
982                         GraphicsBuffer[(i * CurrResolution.X * 2) + (j * 2)] = PixelData;
983                         GraphicsBuffer[(i * CurrResolution.X * 2) + (j * 2 + 1)] = PixelData;
984 
985                         /* Mark the specified pixel as changed */
986                         VgaMarkForUpdate(i, j);
987                     }
988                 }
989                 else if (!DoubleWidth && DoubleHeight)
990                 {
991                     /* Now check if the resulting pixel data has changed */
992                     if (GraphicsBuffer[(i * 2 * CurrResolution.X) + j] != PixelData)
993                     {
994                         /* Yes, write the new value */
995                         GraphicsBuffer[(i * 2 * CurrResolution.X) + j] = PixelData;
996                         GraphicsBuffer[((i * 2 + 1) * CurrResolution.X) + j] = PixelData;
997 
998                         /* Mark the specified pixel as changed */
999                         VgaMarkForUpdate(i, j);
1000                     }
1001                 }
1002                 else // if (!DoubleWidth && !DoubleHeight)
1003                 {
1004                     /* Now check if the resulting pixel data has changed */
1005                     if (GraphicsBuffer[i * CurrResolution.X + j] != PixelData)
1006                     {
1007                         /* Yes, write the new value */
1008                         GraphicsBuffer[i * CurrResolution.X + j] = PixelData;
1009 
1010                         /* Mark the specified pixel as changed */
1011                         VgaMarkForUpdate(i, j);
1012                     }
1013                 }
1014             }
1015 
1016             if ((VgaGcRegisters[VGA_GC_MISC_REG] & VGA_GC_MISC_OE) && (i & 1))
1017             {
1018                 /* Clear the high bit */
1019                 Address &= ~InterlaceHighBit;
1020             }
1021 
1022             if (!(VgaGcRegisters[VGA_GC_MISC_REG] & VGA_GC_MISC_OE) || (i & 1))
1023             {
1024                 /* Move to the next scanline */
1025                 Address += ScanlineSizeLatch;
1026             }
1027         }
1028 
1029         /*
1030          * Release the console framebuffer mutex
1031          * so that we allow for repainting.
1032          */
1033         ReleaseMutex(ConsoleMutex);
1034     }
1035     else
1036     {
1037         /* Text mode */
1038         DWORD CurrentAddr;
1039         PCHAR_CELL CharBuffer = (PCHAR_CELL)ActiveFramebuffer;
1040         CHAR_CELL CharInfo;
1041 
1042         /*
1043          * Technically, the horizontal panning and preset row count should
1044          * affect text mode too. However, it works on pixels and not characters,
1045          * so we can't support it currently.
1046          */
1047 
1048         /* Loop through the scanlines */
1049         for (i = 0; i < CurrResolution.Y; i++)
1050         {
1051             /* Loop through the characters */
1052             for (j = 0; j < CurrResolution.X; j++)
1053             {
1054                 CurrentAddr = WRAP_OFFSET((Address + j) * AddressSize);
1055 
1056                 /* Plane 0 holds the character itself */
1057                 CharInfo.Char = VgaMemory[CurrentAddr * VGA_NUM_BANKS];
1058 
1059                 /* Plane 1 holds the attribute */
1060                 CharInfo.Attributes = VgaMemory[CurrentAddr * VGA_NUM_BANKS + 1];
1061 
1062                 /* Now check if the resulting character data has changed */
1063                 if ((CharBuffer[i * CurrResolution.X + j].Char != CharInfo.Char) ||
1064                     (CharBuffer[i * CurrResolution.X + j].Attributes != CharInfo.Attributes))
1065                 {
1066                     /* Yes, write the new value */
1067                     CharBuffer[i * CurrResolution.X + j] = CharInfo;
1068 
1069                     /* Mark the specified cell as changed */
1070                     VgaMarkForUpdate(i, j);
1071                 }
1072             }
1073 
1074             /* Move to the next scanline */
1075             Address += ScanlineSizeLatch;
1076         }
1077     }
1078 }
1079 
VgaUpdateTextCursor(VOID)1080 static VOID VgaUpdateTextCursor(VOID)
1081 {
1082     BOOL CursorVisible = !(VgaCrtcRegisters[VGA_CRTC_CURSOR_START_REG] & 0x20);
1083     BYTE CursorStart   =   VgaCrtcRegisters[VGA_CRTC_CURSOR_START_REG] & 0x1F;
1084     BYTE CursorEnd     =   VgaCrtcRegisters[VGA_CRTC_CURSOR_END_REG]   & 0x1F;
1085 
1086     DWORD ScanlineSize = (DWORD)VgaCrtcRegisters[VGA_CRTC_OFFSET_REG] * 2;
1087     BYTE TextSize = 1 + (VgaCrtcRegisters[VGA_CRTC_MAX_SCAN_LINE_REG] & 0x1F);
1088     WORD Location = MAKEWORD(VgaCrtcRegisters[VGA_CRTC_CURSOR_LOC_LOW_REG],
1089                              VgaCrtcRegisters[VGA_CRTC_CURSOR_LOC_HIGH_REG]);
1090 
1091     /* Just return if we are not in text mode */
1092     if (ScreenMode != TEXT_MODE) return;
1093 
1094     /* Add the cursor skew to the location */
1095     Location += (VgaCrtcRegisters[VGA_CRTC_CURSOR_END_REG] >> 5) & 0x03;
1096 
1097     VgaConsoleUpdateTextCursor(CursorVisible, CursorStart, CursorEnd,
1098                                TextSize, ScanlineSize, Location);
1099 
1100     /* Reset the cursor changed flag */
1101     CursorChanged = FALSE;
1102 }
1103 
VgaReadPort(USHORT Port)1104 static BYTE WINAPI VgaReadPort(USHORT Port)
1105 {
1106     DPRINT("VgaReadPort: Port 0x%X\n", Port);
1107 
1108     if (Port != VGA_DAC_MASK) SvgaHdrCounter = 0;
1109 
1110     switch (Port)
1111     {
1112         case VGA_MISC_READ:
1113             return VgaMiscRegister;
1114 
1115         case VGA_INSTAT0_READ:
1116             return 0; // Not implemented
1117 
1118         case VGA_INSTAT1_READ_MONO:
1119         case VGA_INSTAT1_READ_COLOR:
1120         {
1121             BYTE Result = 0;
1122             BOOLEAN Vsync, Hsync;
1123             ULONGLONG Cycles = CurrentCycleCount;
1124             ULONG CyclesPerMicrosecond = (ULONG)((CurrentIps + 500000ULL) / 1000000ULL);
1125             ULONG Dots = (VgaSeqRegisters[VGA_SEQ_CLOCK_REG] & 1) ? 9 : 8;
1126             ULONG Clock = VgaGetClockFrequency() / 1000000;
1127             ULONG HblankStart, HblankEnd;
1128             ULONG HblankDuration;
1129             ULONG VerticalRetraceStart = VgaCrtcRegisters[VGA_CRTC_START_VERT_RETRACE_REG];
1130             ULONG VerticalRetraceEnd;
1131 
1132             VerticalRetraceStart |= (VgaCrtcRegisters[VGA_CRTC_OVERFLOW_REG] & VGA_CRTC_OVERFLOW_VRS8) << 6;
1133             VerticalRetraceStart |= (VgaCrtcRegisters[VGA_CRTC_OVERFLOW_REG] & VGA_CRTC_OVERFLOW_VRS9) << 2;
1134 
1135             VerticalRetraceEnd = VerticalRetraceStart + (VgaCrtcRegisters[VGA_CRTC_END_VERT_RETRACE_REG] & 0x0F);
1136 
1137             if (VgaGcRegisters[VGA_GC_MISC_REG] & VGA_GC_MISC_NOALPHA)
1138             {
1139                 BYTE MaximumScanLine = 1 + (VgaCrtcRegisters[VGA_CRTC_MAX_SCAN_LINE_REG] & 0x1F);
1140 
1141                 if (VgaCrtcRegisters[VGA_CRTC_MAX_SCAN_LINE_REG] & VGA_CRTC_MAXSCANLINE_DOUBLE)
1142                 {
1143                     VerticalRetraceStart <<= 1;
1144                     VerticalRetraceEnd <<= 1;
1145                 }
1146                 else
1147                 {
1148                     VerticalRetraceStart *= MaximumScanLine;
1149                     VerticalRetraceEnd *= MaximumScanLine;
1150                 }
1151             }
1152 
1153             /* Calculate the horizontal blanking duration in cycles */
1154             HblankStart = VgaCrtcRegisters[VGA_CRTC_START_HORZ_BLANKING_REG] & 0x1F;
1155             HblankEnd = VgaCrtcRegisters[VGA_CRTC_END_HORZ_BLANKING_REG] & 0x1F;
1156             if (HblankEnd < HblankStart) HblankEnd |= 0x20;
1157             HblankDuration = ((HblankEnd - HblankStart) * Dots
1158                              * CyclesPerMicrosecond + (Clock >> 1)) / Clock;
1159 
1160             Vsync = ScanlineCounter >= VerticalRetraceStart && ScanlineCounter <= VerticalRetraceEnd;
1161             Hsync = (Cycles - HorizontalRetraceCycle) < (ULONGLONG)HblankDuration;
1162 
1163             /* Reset the AC latch */
1164             VgaAcLatch = FALSE;
1165 
1166             /* Set a flag if there is a vertical or horizontal retrace */
1167             if (Vsync || Hsync) Result |= VGA_STAT_DD;
1168 
1169             /* Set an additional flag if there was a vertical retrace */
1170             if (Vsync) Result |= VGA_STAT_VRETRACE;
1171 
1172             return Result;
1173         }
1174 
1175         case VGA_FEATURE_READ:
1176             return VgaFeatureRegister;
1177 
1178         case VGA_AC_INDEX:
1179             return VgaAcIndex | (VgaAcPalDisable ? 0x20 : 0x00);
1180 
1181         case VGA_AC_READ:
1182             return VgaAcRegisters[VgaAcIndex];
1183 
1184         case VGA_SEQ_INDEX:
1185             return VgaSeqIndex;
1186 
1187         case VGA_SEQ_DATA:
1188             return VgaSeqRegisters[VgaSeqIndex];
1189 
1190         case VGA_DAC_MASK:
1191         {
1192             if (SvgaHdrCounter == 4)
1193             {
1194                 SvgaHdrCounter = 0;
1195                 return SvgaHiddenRegister;
1196             }
1197             else
1198             {
1199                 SvgaHdrCounter++;
1200                 return VgaDacMask;
1201             }
1202         }
1203 
1204         case VGA_DAC_READ_INDEX:
1205             /* This returns the read/write state */
1206             return (VgaDacReadWrite ? 0 : 3);
1207 
1208         case VGA_DAC_WRITE_INDEX:
1209             return VgaDacIndex;
1210 
1211         case VGA_DAC_DATA:
1212         {
1213             /* Ignore reads in write mode */
1214             if (!VgaDacReadWrite)
1215             {
1216                 BYTE Data = VgaDacRegisters[VgaDacIndex * 3 + VgaDacLatchCounter];
1217                 VgaDacLatchCounter++;
1218 
1219                 if (VgaDacLatchCounter == 3)
1220                 {
1221                     /* Reset the latch counter and increment the palette index */
1222                     VgaDacLatchCounter = 0;
1223                     VgaDacIndex++;
1224                     VgaDacIndex %= VGA_MAX_COLORS;
1225                 }
1226 
1227                 return Data;
1228             }
1229 
1230             break;
1231         }
1232 
1233         case VGA_CRTC_INDEX_MONO:
1234         case VGA_CRTC_INDEX_COLOR:
1235             return VgaCrtcIndex;
1236 
1237         case VGA_CRTC_DATA_MONO:
1238         case VGA_CRTC_DATA_COLOR:
1239             return VgaCrtcRegisters[VgaCrtcIndex];
1240 
1241         case VGA_GC_INDEX:
1242             return VgaGcIndex;
1243 
1244         case VGA_GC_DATA:
1245             return VgaGcRegisters[VgaGcIndex];
1246 
1247         default:
1248             DPRINT1("VgaReadPort: Unknown port 0x%X\n", Port);
1249             break;
1250     }
1251 
1252     return 0;
1253 }
1254 
VgaWriteSequencer(BYTE Data)1255 static inline VOID VgaWriteSequencer(BYTE Data)
1256 {
1257     /* Save the value */
1258     VgaSeqRegisters[VgaSeqIndex & VGA_SEQ_INDEX_MASK] = Data;
1259 
1260     /* Check the index */
1261     switch (VgaSeqIndex & VGA_SEQ_INDEX_MASK)
1262     {
1263         case SVGA_SEQ_UNLOCK_REG:
1264         {
1265             if ((Data & SVGA_SEQ_UNLOCK_MASK) == SVGA_SEQ_UNLOCKED)
1266             {
1267                 /* Unlock SVGA extensions */
1268                 VgaSeqRegisters[SVGA_SEQ_UNLOCK_REG] = SVGA_SEQ_UNLOCKED;
1269             }
1270             else
1271             {
1272                 /* Lock SVGA extensions */
1273                 VgaSeqRegisters[SVGA_SEQ_UNLOCK_REG] = SVGA_SEQ_LOCKED;
1274             }
1275 
1276             break;
1277         }
1278     }
1279 }
1280 
VgaWriteGc(BYTE Data)1281 static inline VOID VgaWriteGc(BYTE Data)
1282 {
1283     /* Save the value */
1284     VgaGcRegisters[VgaGcIndex & VGA_GC_INDEX_MASK] = Data;
1285 
1286     /* Check the index */
1287     switch (VgaGcIndex & VGA_GC_INDEX_MASK)
1288     {
1289         case VGA_GC_MISC_REG:
1290         {
1291             /* Remove any existing VGA memory hook */
1292             MemRemoveFastMemoryHook((PVOID)0xA0000, 0x20000);
1293 
1294             if (VgaMiscRegister & VGA_MISC_RAM_ENABLED)
1295             {
1296                 UCHAR MemoryMap = (VgaGcRegisters[VGA_GC_MISC_REG] >> 2) & 0x03;
1297 
1298                 /* Register a memory hook */
1299                 MemInstallFastMemoryHook(UlongToPtr(MemoryBase[MemoryMap]),
1300                                          MemorySize[MemoryMap],
1301                                          VgaReadMemory,
1302                                          VgaWriteMemory);
1303             }
1304 
1305             /* The GC misc register decides if it's text or graphics mode */
1306             ModeChanged = TRUE;
1307             break;
1308         }
1309     }
1310 }
1311 
VgaWriteCrtc(BYTE Data)1312 static inline VOID VgaWriteCrtc(BYTE Data)
1313 {
1314     /* Save the value */
1315     VgaCrtcRegisters[VgaCrtcIndex & VGA_CRTC_INDEX_MASK] = Data;
1316 
1317     /* Check the index */
1318     switch (VgaCrtcIndex & VGA_CRTC_INDEX_MASK)
1319     {
1320         case VGA_CRTC_END_HORZ_DISP_REG:
1321         case VGA_CRTC_VERT_DISP_END_REG:
1322         case VGA_CRTC_OVERFLOW_REG:
1323         case VGA_CRTC_MAX_SCAN_LINE_REG:
1324         {
1325             /* The video mode has changed */
1326             ModeChanged = TRUE;
1327             break;
1328         }
1329 
1330         case VGA_CRTC_CURSOR_LOC_LOW_REG:
1331         case VGA_CRTC_CURSOR_LOC_HIGH_REG:
1332         case VGA_CRTC_CURSOR_START_REG:
1333         case VGA_CRTC_CURSOR_END_REG:
1334         {
1335             /* Set the cursor changed flag */
1336             CursorChanged = TRUE;
1337             break;
1338         }
1339     }
1340 }
1341 
VgaWriteDac(BYTE Data)1342 static inline VOID VgaWriteDac(BYTE Data)
1343 {
1344     UINT i;
1345     PALETTEENTRY Entry;
1346 
1347     /* Store the value in the latch */
1348     VgaDacLatch[VgaDacLatchCounter++] = Data;
1349     if (VgaDacLatchCounter < 3) return;
1350 
1351     /* Reset the latch counter */
1352     VgaDacLatchCounter = 0;
1353 
1354     /* Set the DAC register values */
1355     VgaDacRegisters[VgaDacIndex * 3]     = VgaDacLatch[0];
1356     VgaDacRegisters[VgaDacIndex * 3 + 1] = VgaDacLatch[1];
1357     VgaDacRegisters[VgaDacIndex * 3 + 2] = VgaDacLatch[2];
1358 
1359     /* Fill the entry structure */
1360     Entry.peRed = VGA_DAC_TO_COLOR(VgaDacLatch[0]);
1361     Entry.peGreen = VGA_DAC_TO_COLOR(VgaDacLatch[1]);
1362     Entry.peBlue = VGA_DAC_TO_COLOR(VgaDacLatch[2]);
1363     Entry.peFlags = 0;
1364 
1365     /* Update the palette entry */
1366     SetPaletteEntries(PaletteHandle, VgaDacIndex, 1, &Entry);
1367 
1368     /* Check which text palette entries are affected */
1369     for (i = 0; i <= VGA_AC_PAL_F_REG; i++)
1370     {
1371         if (VgaAcRegisters[i] == VgaDacIndex)
1372         {
1373             /* Update the text palette entry */
1374             SetPaletteEntries(TextPaletteHandle, i, 1, &Entry);
1375         }
1376     }
1377 
1378     /* Set the palette changed flag */
1379     PaletteChanged = TRUE;
1380 
1381     /* Update the index */
1382     VgaDacIndex++;
1383     VgaDacIndex %= VGA_MAX_COLORS;
1384 }
1385 
VgaWriteAc(BYTE Data)1386 static inline VOID VgaWriteAc(BYTE Data)
1387 {
1388     PALETTEENTRY Entry;
1389 
1390     ASSERT(VgaAcIndex < VGA_AC_MAX_REG);
1391 
1392     /* Save the value */
1393     if (VgaAcIndex <= VGA_AC_PAL_F_REG)
1394     {
1395         if (VgaAcPalDisable) return;
1396 
1397         // DbgPrint("    AC Palette Writing %d to index %d\n", Data, VgaAcIndex);
1398         if (VgaAcRegisters[VgaAcIndex] != Data)
1399         {
1400             /* Update the AC register */
1401             VgaAcRegisters[VgaAcIndex] = Data;
1402 
1403             /* Fill the entry structure */
1404             Entry.peRed = VGA_DAC_TO_COLOR(VgaDacRegisters[Data * 3]);
1405             Entry.peGreen = VGA_DAC_TO_COLOR(VgaDacRegisters[Data * 3 + 1]);
1406             Entry.peBlue = VGA_DAC_TO_COLOR(VgaDacRegisters[Data * 3 + 2]);
1407             Entry.peFlags = 0;
1408 
1409             /* Update the palette entry and set the palette change flag */
1410             SetPaletteEntries(TextPaletteHandle, VgaAcIndex, 1, &Entry);
1411             PaletteChanged = TRUE;
1412         }
1413     }
1414     else
1415     {
1416         VgaAcRegisters[VgaAcIndex] = Data;
1417     }
1418 }
1419 
VgaWritePort(USHORT Port,BYTE Data)1420 static VOID WINAPI VgaWritePort(USHORT Port, BYTE Data)
1421 {
1422     DPRINT("VgaWritePort: Port 0x%X, Data 0x%02X\n", Port, Data);
1423 
1424     switch (Port)
1425     {
1426         case VGA_MISC_WRITE:
1427         {
1428             VgaMiscRegister = Data;
1429 
1430             if (VgaMiscRegister & 0x01)
1431             {
1432                 /* Color emulation */
1433                 DPRINT1("Color emulation\n");
1434 
1435                 /* Register the new I/O Ports */
1436                 RegisterIoPort(0x3D4, VgaReadPort, VgaWritePort);   // VGA_CRTC_INDEX_COLOR
1437                 RegisterIoPort(0x3D5, VgaReadPort, VgaWritePort);   // VGA_CRTC_DATA_COLOR
1438                 RegisterIoPort(0x3DA, VgaReadPort, VgaWritePort);   // VGA_INSTAT1_READ_COLOR, VGA_FEATURE_WRITE_COLOR
1439 
1440                 /* Unregister the old ones */
1441                 UnregisterIoPort(0x3B4);    // VGA_CRTC_INDEX_MONO
1442                 UnregisterIoPort(0x3B5);    // VGA_CRTC_DATA_MONO
1443                 UnregisterIoPort(0x3BA);    // VGA_INSTAT1_READ_MONO, VGA_FEATURE_WRITE_MONO
1444             }
1445             else
1446             {
1447                 /* Monochrome emulation */
1448                 DPRINT1("Monochrome emulation\n");
1449 
1450                 /* Register the new I/O Ports */
1451                 RegisterIoPort(0x3B4, VgaReadPort, VgaWritePort);   // VGA_CRTC_INDEX_MONO
1452                 RegisterIoPort(0x3B5, VgaReadPort, VgaWritePort);   // VGA_CRTC_DATA_MONO
1453                 RegisterIoPort(0x3BA, VgaReadPort, VgaWritePort);   // VGA_INSTAT1_READ_MONO, VGA_FEATURE_WRITE_MONO
1454 
1455                 /* Unregister the old ones */
1456                 UnregisterIoPort(0x3D4);    // VGA_CRTC_INDEX_COLOR
1457                 UnregisterIoPort(0x3D5);    // VGA_CRTC_DATA_COLOR
1458                 UnregisterIoPort(0x3DA);    // VGA_INSTAT1_READ_COLOR, VGA_FEATURE_WRITE_COLOR
1459             }
1460 
1461             /* Remove any existing VGA memory hook */
1462             MemRemoveFastMemoryHook((PVOID)0xA0000, 0x20000);
1463 
1464             if (VgaMiscRegister & VGA_MISC_RAM_ENABLED)
1465             {
1466                 UCHAR MemoryMap = (VgaGcRegisters[VGA_GC_MISC_REG] >> 2) & 0x03;
1467 
1468                 /* Register a memory hook */
1469                 MemInstallFastMemoryHook(UlongToPtr(MemoryBase[MemoryMap]),
1470                                          MemorySize[MemoryMap],
1471                                          VgaReadMemory,
1472                                          VgaWriteMemory);
1473             }
1474 
1475             break;
1476         }
1477 
1478         case VGA_FEATURE_WRITE_MONO:
1479         case VGA_FEATURE_WRITE_COLOR:
1480         {
1481             VgaFeatureRegister = Data;
1482             break;
1483         }
1484 
1485         case VGA_AC_INDEX:
1486         // case VGA_AC_WRITE:
1487         {
1488             if (!VgaAcLatch)
1489             {
1490                 /* Change the index */
1491                 BYTE Index = Data & 0x1F;
1492                 if (Index < VGA_AC_MAX_REG) VgaAcIndex = Index;
1493 
1494                 /*
1495                  * Change palette protection by checking for
1496                  * the Palette Address Source bit.
1497                  */
1498                 VgaAcPalDisable = (Data & 0x20) ? TRUE : FALSE;
1499             }
1500             else
1501             {
1502                 /* Write the data */
1503                 VgaWriteAc(Data);
1504             }
1505 
1506             /* Toggle the latch */
1507             VgaAcLatch = !VgaAcLatch;
1508             break;
1509         }
1510 
1511         case VGA_SEQ_INDEX:
1512         {
1513             /* Set the sequencer index register */
1514             if ((Data & 0x1F) < SVGA_SEQ_MAX_UNLOCKED_REG
1515                 && (Data & 0x1F) != VGA_SEQ_MAX_REG)
1516             {
1517                 VgaSeqIndex = Data;
1518             }
1519 
1520             break;
1521         }
1522 
1523         case VGA_SEQ_DATA:
1524         {
1525             /* Call the sequencer function */
1526             VgaWriteSequencer(Data);
1527             break;
1528         }
1529 
1530         case VGA_DAC_MASK:
1531         {
1532             if (SvgaHdrCounter == 4) SvgaHiddenRegister = Data;
1533             else VgaDacMask = Data;
1534 
1535             break;
1536         }
1537 
1538         case VGA_DAC_READ_INDEX:
1539         {
1540             VgaDacReadWrite = FALSE;
1541             VgaDacIndex = Data;
1542             VgaDacLatchCounter = 0;
1543             break;
1544         }
1545 
1546         case VGA_DAC_WRITE_INDEX:
1547         {
1548             VgaDacReadWrite = TRUE;
1549             VgaDacIndex = Data;
1550             VgaDacLatchCounter = 0;
1551             break;
1552         }
1553 
1554         case VGA_DAC_DATA:
1555         {
1556             /* Ignore writes in read mode */
1557             if (VgaDacReadWrite) VgaWriteDac(Data & 0x3F);
1558             break;
1559         }
1560 
1561         case VGA_CRTC_INDEX_MONO:
1562         case VGA_CRTC_INDEX_COLOR:
1563         {
1564             /* Set the CRTC index register */
1565             if (((Data & VGA_CRTC_INDEX_MASK) < SVGA_CRTC_MAX_UNLOCKED_REG)
1566                 && ((Data & VGA_CRTC_INDEX_MASK) < SVGA_CRTC_UNUSED0_REG
1567                 || (Data & VGA_CRTC_INDEX_MASK) > SVGA_CRTC_UNUSED6_REG)
1568                 && (Data & VGA_CRTC_INDEX_MASK) != SVGA_CRTC_UNUSED7_REG)
1569             {
1570                 VgaCrtcIndex = Data;
1571             }
1572 
1573             break;
1574         }
1575 
1576         case VGA_CRTC_DATA_MONO:
1577         case VGA_CRTC_DATA_COLOR:
1578         {
1579             /* Call the CRTC function */
1580             VgaWriteCrtc(Data);
1581             break;
1582         }
1583 
1584         case VGA_GC_INDEX:
1585         {
1586             /* Set the GC index register */
1587             if ((Data & VGA_GC_INDEX_MASK) < SVGA_GC_MAX_UNLOCKED_REG
1588                 && (Data & VGA_GC_INDEX_MASK) != SVGA_GC_UNUSED0_REG
1589                 && ((Data & VGA_GC_INDEX_MASK) < SVGA_GC_UNUSED1_REG
1590                 || (Data & VGA_GC_INDEX_MASK) > SVGA_GC_UNUSED10_REG))
1591             {
1592                 VgaGcIndex = Data;
1593             }
1594 
1595             break;
1596         }
1597 
1598         case VGA_GC_DATA:
1599         {
1600             /* Call the GC function */
1601             VgaWriteGc(Data);
1602             break;
1603         }
1604 
1605         default:
1606             DPRINT1("VgaWritePort: Unknown port 0x%X, Data 0x%02X\n", Port, Data);
1607             break;
1608     }
1609 
1610     SvgaHdrCounter = 0;
1611 }
1612 
VgaVerticalRetrace(VOID)1613 static inline VOID VgaVerticalRetrace(VOID)
1614 {
1615     /* If nothing has changed, just return */
1616     // if (!ModeChanged && !CursorChanged && !PaletteChanged && !NeedsUpdate)
1617         // return;
1618 
1619     /* Change the display mode */
1620     if (ModeChanged) VgaChangeMode();
1621 
1622     /* Change the text cursor appearance */
1623     if (CursorChanged) VgaUpdateTextCursor();
1624 
1625     if (PaletteChanged)
1626     {
1627         /* Trigger a full update of the screen */
1628         NeedsUpdate = TRUE;
1629         UpdateRectangle.Left = 0;
1630         UpdateRectangle.Top  = 0;
1631         UpdateRectangle.Right  = CurrResolution.X;
1632         UpdateRectangle.Bottom = CurrResolution.Y;
1633 
1634         PaletteChanged = FALSE;
1635     }
1636 
1637     /* Update the contents of the framebuffer */
1638     VgaUpdateFramebuffer();
1639 
1640     /* Ignore if there's nothing to update */
1641     if (!NeedsUpdate) return;
1642 
1643     DPRINT("Updating screen rectangle (%d, %d, %d, %d)\n",
1644            UpdateRectangle.Left,
1645            UpdateRectangle.Top,
1646            UpdateRectangle.Right,
1647            UpdateRectangle.Bottom);
1648 
1649     VgaConsoleRepaintScreen(&UpdateRectangle);
1650 
1651     /* Clear the update flag */
1652     NeedsUpdate = FALSE;
1653 }
1654 
VgaHorizontalRetrace(ULONGLONG ElapsedTime)1655 static VOID FASTCALL VgaHorizontalRetrace(ULONGLONG ElapsedTime)
1656 {
1657     ULONG VerticalTotal = VgaCrtcRegisters[VGA_CRTC_VERT_TOTAL_REG];
1658     ULONG VerticalRetraceStart = VgaCrtcRegisters[VGA_CRTC_START_VERT_RETRACE_REG];
1659     BOOLEAN BeforeVSync;
1660     ULONG ElapsedCycles = CurrentCycleCount - HorizontalRetraceCycle;
1661     ULONG Dots = (VgaSeqRegisters[VGA_SEQ_CLOCK_REG] & 1) ? 9 : 8;
1662     ULONG HorizTotalDots = ((ULONG)VgaCrtcRegisters[VGA_CRTC_HORZ_TOTAL_REG] + 5) * Dots;
1663     BYTE MaximumScanLine = 1 + (VgaCrtcRegisters[VGA_CRTC_MAX_SCAN_LINE_REG] & 0x1F);
1664     ULONG HSyncsPerSecond, HSyncs;
1665     UNREFERENCED_PARAMETER(ElapsedTime);
1666 
1667     if (VgaAcRegisters[VGA_AC_CONTROL_REG] & VGA_AC_CONTROL_8BIT) HorizTotalDots >>= 1;
1668 
1669     HSyncsPerSecond = VgaGetClockFrequency() / HorizTotalDots;
1670     HSyncs = (ElapsedCycles * HSyncsPerSecond + (CurrentIps >> 1)) / CurrentIps;
1671     if (HSyncs == 0) HSyncs = 1;
1672 
1673     VerticalTotal |= (VgaCrtcRegisters[VGA_CRTC_OVERFLOW_REG] & VGA_CRTC_OVERFLOW_VT8) << 8;
1674     VerticalTotal |= (VgaCrtcRegisters[VGA_CRTC_OVERFLOW_REG] & VGA_CRTC_OVERFLOW_VT9) << 4;
1675 
1676     VerticalRetraceStart |= (VgaCrtcRegisters[VGA_CRTC_OVERFLOW_REG] & VGA_CRTC_OVERFLOW_VRS8) << 6;
1677     VerticalRetraceStart |= (VgaCrtcRegisters[VGA_CRTC_OVERFLOW_REG] & VGA_CRTC_OVERFLOW_VRS9) << 2;
1678 
1679     if (VgaGcRegisters[VGA_GC_MISC_REG] & VGA_GC_MISC_NOALPHA)
1680     {
1681         if (VgaCrtcRegisters[VGA_CRTC_MAX_SCAN_LINE_REG] & VGA_CRTC_MAXSCANLINE_DOUBLE)
1682         {
1683             VerticalRetraceStart <<= 1;
1684             VerticalTotal <<= 1;
1685         }
1686         else
1687         {
1688             VerticalRetraceStart *= MaximumScanLine;
1689             VerticalTotal *= MaximumScanLine;
1690         }
1691     }
1692 
1693     /* Set the cycle */
1694     HorizontalRetraceCycle = CurrentCycleCount;
1695 
1696     /* Increment the scanline counter, but make sure we don't skip any part of the vertical retrace */
1697     BeforeVSync = (ScanlineCounter < VerticalRetraceStart);
1698     ScanlineCounter += HSyncs;
1699     if (BeforeVSync && ScanlineCounter >= VerticalRetraceStart) ScanlineCounter = VerticalRetraceStart;
1700 
1701     if (ScanlineCounter == VerticalRetraceStart)
1702     {
1703         /* Save the scanline size */
1704         ScanlineSizeLatch = ((DWORD)VgaCrtcRegisters[VGA_CRTC_OFFSET_REG]
1705                             + (((DWORD)VgaCrtcRegisters[SVGA_CRTC_EXT_DISPLAY_REG] & SVGA_CRTC_EXT_OFFSET_BIT8) << 4)) * 2;
1706         if (VgaSeqRegisters[SVGA_SEQ_EXT_MODE_REG] & SVGA_SEQ_EXT_MODE_HIGH_RES) ScanlineSizeLatch <<= 2;
1707 
1708         /* Save the starting address */
1709         StartAddressLatch = MAKEWORD(VgaCrtcRegisters[VGA_CRTC_START_ADDR_LOW_REG],
1710                                      VgaCrtcRegisters[VGA_CRTC_START_ADDR_HIGH_REG])
1711                             + ((VgaCrtcRegisters[SVGA_CRTC_EXT_DISPLAY_REG] & SVGA_CRTC_EXT_ADDR_BIT16) << 16)
1712                             + ((VgaCrtcRegisters[SVGA_CRTC_EXT_DISPLAY_REG] & SVGA_CRTC_EXT_ADDR_BITS1718) << 15)
1713                             + ((VgaCrtcRegisters[SVGA_CRTC_OVERLAY_REG] & SVGA_CRTC_EXT_ADDR_BIT19) << 12)
1714                             + (VgaCrtcRegisters[VGA_CRTC_PRESET_ROW_SCAN_REG] & 0x1F) * ScanlineSizeLatch
1715                             + ((VgaCrtcRegisters[VGA_CRTC_PRESET_ROW_SCAN_REG] >> 5) & 3);
1716     }
1717 
1718     if (ScanlineCounter > VerticalTotal)
1719     {
1720         ScanlineCounter = 0;
1721         VgaVerticalRetrace();
1722     }
1723 }
1724 
1725 /* PUBLIC FUNCTIONS ***********************************************************/
1726 
VgaGetDisplayResolution(VOID)1727 COORD VgaGetDisplayResolution(VOID)
1728 {
1729     COORD Resolution;
1730     BYTE MaximumScanLine = 1 + (VgaCrtcRegisters[VGA_CRTC_MAX_SCAN_LINE_REG] & 0x1F);
1731 
1732     /* The low 8 bits are in the display registers */
1733     Resolution.X = VgaCrtcRegisters[VGA_CRTC_END_HORZ_DISP_REG];
1734     Resolution.Y = VgaCrtcRegisters[VGA_CRTC_VERT_DISP_END_REG];
1735 
1736     /* Set the top bits from the overflow register */
1737     if (VgaCrtcRegisters[VGA_CRTC_OVERFLOW_REG] & VGA_CRTC_OVERFLOW_VDE8)
1738     {
1739         Resolution.Y |= 1 << 8;
1740     }
1741     if (VgaCrtcRegisters[VGA_CRTC_OVERFLOW_REG] & VGA_CRTC_OVERFLOW_VDE9)
1742     {
1743         Resolution.Y |= 1 << 9;
1744     }
1745 
1746     /* Increase the values by 1 */
1747     Resolution.X++;
1748     Resolution.Y++;
1749 
1750     if (VgaGcRegisters[VGA_GC_MISC_REG] & VGA_GC_MISC_NOALPHA)
1751     {
1752         /* In "High Resolution" mode, the width of a character is always 8 pixels */
1753         if (VgaSeqRegisters[SVGA_SEQ_EXT_MODE_REG] & SVGA_SEQ_EXT_MODE_HIGH_RES)
1754         {
1755             Resolution.X *= 8;
1756         }
1757         else
1758         {
1759             /* Multiply the horizontal resolution by the 9/8 dot mode */
1760             Resolution.X *= (VgaSeqRegisters[VGA_SEQ_CLOCK_REG] & VGA_SEQ_CLOCK_98DM)
1761                             ? 8 : 9;
1762 
1763             /* The horizontal resolution is halved in 8-bit mode */
1764             if (VgaAcRegisters[VGA_AC_CONTROL_REG] & VGA_AC_CONTROL_8BIT) Resolution.X /= 2;
1765         }
1766     }
1767 
1768     if (VgaCrtcRegisters[VGA_CRTC_MAX_SCAN_LINE_REG] & VGA_CRTC_MAXSCANLINE_DOUBLE)
1769     {
1770         /* Halve the vertical resolution */
1771         Resolution.Y >>= 1;
1772     }
1773     else
1774     {
1775         /* Divide the vertical resolution by the maximum scan line (== font size in text mode) */
1776         Resolution.Y /= MaximumScanLine;
1777     }
1778 
1779     /* Return the resolution */
1780     return Resolution;
1781 }
1782 
VgaRefreshDisplay(VOID)1783 VOID VgaRefreshDisplay(VOID)
1784 {
1785     /* Save the scanline size */
1786     ScanlineSizeLatch = ((DWORD)VgaCrtcRegisters[VGA_CRTC_OFFSET_REG]
1787                         + (((DWORD)VgaCrtcRegisters[SVGA_CRTC_EXT_DISPLAY_REG] & SVGA_CRTC_EXT_OFFSET_BIT8) << 4)) * 2;
1788     if (VgaSeqRegisters[SVGA_SEQ_EXT_MODE_REG] & SVGA_SEQ_EXT_MODE_HIGH_RES) ScanlineSizeLatch <<= 2;
1789 
1790     /* Save the starting address */
1791     StartAddressLatch = MAKEWORD(VgaCrtcRegisters[VGA_CRTC_START_ADDR_LOW_REG],
1792                                  VgaCrtcRegisters[VGA_CRTC_START_ADDR_HIGH_REG])
1793                         + ((VgaCrtcRegisters[SVGA_CRTC_EXT_DISPLAY_REG] & SVGA_CRTC_EXT_ADDR_BIT16) << 16)
1794                         + ((VgaCrtcRegisters[SVGA_CRTC_EXT_DISPLAY_REG] & SVGA_CRTC_EXT_ADDR_BITS1718) << 15)
1795                         + ((VgaCrtcRegisters[SVGA_CRTC_OVERLAY_REG] & SVGA_CRTC_EXT_ADDR_BIT19) << 12)
1796                         + (VgaCrtcRegisters[VGA_CRTC_PRESET_ROW_SCAN_REG] & 0x1F) * ScanlineSizeLatch
1797                         + ((VgaCrtcRegisters[VGA_CRTC_PRESET_ROW_SCAN_REG] >> 5) & 3);
1798 
1799     VgaVerticalRetrace();
1800 }
1801 
VgaReadMemory(ULONG Address,PVOID Buffer,ULONG Size)1802 VOID FASTCALL VgaReadMemory(ULONG Address, PVOID Buffer, ULONG Size)
1803 {
1804     DWORD i;
1805     DWORD VideoAddress;
1806     PUCHAR BufPtr = (PUCHAR)Buffer;
1807 
1808     DPRINT("VgaReadMemory: Address 0x%08X, Size %lu\n", Address, Size);
1809 
1810     /* Ignore if video RAM access is disabled */
1811     if (!Size) return;
1812     if ((VgaMiscRegister & VGA_MISC_RAM_ENABLED) == 0) return;
1813 
1814     if (!(VgaGcRegisters[VGA_GC_MODE_REG] & VGA_GC_MODE_READ))
1815     {
1816         VideoAddress = VgaTranslateAddress(Address);
1817 
1818         /* Check for packed pixel, chain-4, and odd-even mode */
1819         if (VgaSeqRegisters[SVGA_SEQ_EXT_MODE_REG] & SVGA_SEQ_EXT_MODE_HIGH_RES)
1820         {
1821             /* Just copy from the video memory */
1822             PVOID VideoMemory = &VgaMemory[VideoAddress + (Address & 3)];
1823 
1824             switch (Size)
1825             {
1826                 case sizeof(UCHAR):
1827                     *(PUCHAR)Buffer = *(PUCHAR)VideoMemory;
1828                     return;
1829 
1830                 case sizeof(USHORT):
1831                     *(PUSHORT)Buffer = *(PUSHORT)VideoMemory;
1832                     return;
1833 
1834                 case sizeof(ULONG):
1835                     *(PULONG)Buffer = *(PULONG)VideoMemory;
1836                     return;
1837 
1838                 case sizeof(ULONGLONG):
1839                     *(PULONGLONG)Buffer = *(PULONGLONG)VideoMemory;
1840                     return;
1841 
1842                 default:
1843 #if defined(__GNUC__)
1844                     __builtin_memcpy(Buffer, VideoMemory, Size);
1845 #else
1846                     RtlCopyMemory(Buffer, VideoMemory, Size);
1847 #endif
1848             }
1849         }
1850         else if (VgaSeqRegisters[VGA_SEQ_MEM_REG] & VGA_SEQ_MEM_C4)
1851         {
1852             i = 0;
1853 
1854             /* Write the unaligned part first */
1855             if (Address & 3)
1856             {
1857                 switch (Address & 3)
1858                 {
1859                     case 1:
1860                         BufPtr[i++] = VgaMemory[VideoAddress * VGA_NUM_BANKS + 1];
1861                     case 2:
1862                         BufPtr[i++] = VgaMemory[VideoAddress * VGA_NUM_BANKS + 2];
1863                     case 3:
1864                         BufPtr[i++] = VgaMemory[VideoAddress * VGA_NUM_BANKS + 3];
1865                 }
1866 
1867                 VideoAddress += 4;
1868             }
1869 
1870             /* Copy the aligned dwords */
1871             while ((i + 3) < Size)
1872             {
1873                 *(PULONG)&BufPtr[i] = *(PULONG)&VgaMemory[VideoAddress * VGA_NUM_BANKS];
1874 
1875                 i += 4;
1876                 VideoAddress += 4;
1877             }
1878 
1879             /* Write the remaining part */
1880             if (i < Size)
1881             {
1882                 switch (Size - i - 3)
1883                 {
1884                     case 3:
1885                         BufPtr[i] = VgaMemory[VideoAddress * VGA_NUM_BANKS + ((Address + i) & 3)];
1886                         i++;
1887                     case 2:
1888                         BufPtr[i] = VgaMemory[VideoAddress * VGA_NUM_BANKS + ((Address + i) & 3)];
1889                         i++;
1890                     case 1:
1891                         BufPtr[i] = VgaMemory[VideoAddress * VGA_NUM_BANKS + ((Address + i) & 3)];
1892                         i++;
1893                 }
1894             }
1895         }
1896         else if (VgaGcRegisters[VGA_GC_MODE_REG] & VGA_GC_MODE_OE)
1897         {
1898             i = 0;
1899 
1900             /* Check if the starting address is odd */
1901             if (Address & 1)
1902             {
1903                 BufPtr[i++] = VgaMemory[VideoAddress * VGA_NUM_BANKS + 1];
1904                 VideoAddress += 2;
1905             }
1906 
1907             while (i < (Size - 1))
1908             {
1909                 *(PUSHORT)&BufPtr[i] = *(PUSHORT)&VgaMemory[VideoAddress * VGA_NUM_BANKS];
1910 
1911                 i += 2;
1912                 VideoAddress += 2;
1913             }
1914 
1915             /* Check if there is one more byte to read */
1916             if (i == Size - 1) BufPtr[i] = VgaMemory[VideoAddress * VGA_NUM_BANKS + ((Address + i) & 1)];
1917         }
1918         else
1919         {
1920             /* Use the selected map */
1921             BYTE Plane = VgaGcRegisters[VGA_GC_READ_MAP_SEL_REG] & 0x03;
1922 
1923             for (i = 0; i < Size; i++)
1924             {
1925                 /* Copy the value to the buffer */
1926                 BufPtr[i] = VgaMemory[(VideoAddress++) * VGA_NUM_BANKS + Plane];
1927             }
1928         }
1929     }
1930     else
1931     {
1932         const ULONG BitExpandInvertTable[] =
1933         {
1934             0xFFFFFFFF, 0xFFFFFF00, 0xFFFF00FF, 0xFFFF0000,
1935             0xFF00FFFF, 0xFF00FF00, 0xFF0000FF, 0xFF000000,
1936             0x00FFFFFF, 0x00FFFF00, 0x00FF00FF, 0x00FF0000,
1937             0x0000FFFF, 0x0000FF00, 0x000000FF, 0x00000000
1938         };
1939 
1940         ULONG ColorCompareBytes = BitExpandInvertTable[VgaGcRegisters[VGA_GC_COLOR_COMPARE_REG] & 0x0F];
1941         ULONG ColorIgnoreBytes = BitExpandInvertTable[VgaGcRegisters[VGA_GC_COLOR_IGNORE_REG] & 0x0F];
1942 
1943         /*
1944          * These values can also be computed in the following way, but using the table seems to be faster:
1945          *
1946          * ColorCompareBytes = VgaGcRegisters[VGA_GC_COLOR_COMPARE_REG] * 0x000204081;
1947          * ColorCompareBytes &= 0x01010101;
1948          * ColorCompareBytes = ~((ColorCompareBytes << 8) - ColorCompareBytes);
1949          *
1950          * ColorIgnoreBytes = VgaGcRegisters[VGA_GC_COLOR_IGNORE_REG] * 0x000204081;
1951          * ColorIgnoreBytes &= 0x01010101;
1952          * ColorIgnoreBytes = ~((ColorIgnoreBytes << 8) - ColorIgnoreBytes);
1953          */
1954 
1955         /* Loop through each byte */
1956         for (i = 0; i < Size; i++)
1957         {
1958             ULONG PlaneData = 0;
1959 
1960             /* This should always return a plane 0 address */
1961             VideoAddress = VgaTranslateAddress(Address + i);
1962 
1963             /* Read all 4 planes */
1964             PlaneData = *(PULONG)&VgaMemory[VideoAddress * VGA_NUM_BANKS];
1965 
1966             /* Reverse the bytes for which the color compare register is zero */
1967             PlaneData ^= ColorCompareBytes;
1968 
1969             /* Apply the color ignore register */
1970             PlaneData |= ColorIgnoreBytes;
1971 
1972             /* Store the value in the buffer */
1973             BufPtr[i] = (PlaneData & (PlaneData >> 8) & (PlaneData >> 16) & (PlaneData >> 24)) & 0xFF;
1974         }
1975     }
1976 
1977     /* Load the latch registers */
1978     VideoAddress = VgaTranslateAddress(Address + Size - 1);
1979     *(PULONG)VgaLatchRegisters = *(PULONG)&VgaMemory[WRAP_OFFSET(VideoAddress) * VGA_NUM_BANKS];
1980 }
1981 
VgaWriteMemory(ULONG Address,PVOID Buffer,ULONG Size)1982 BOOLEAN FASTCALL VgaWriteMemory(ULONG Address, PVOID Buffer, ULONG Size)
1983 {
1984     DWORD i, j;
1985     DWORD VideoAddress;
1986     PUCHAR BufPtr = (PUCHAR)Buffer;
1987 
1988     DPRINT("VgaWriteMemory: Address 0x%08X, Size %lu\n", Address, Size);
1989 
1990     /* Ignore if video RAM access is disabled */
1991     if ((VgaMiscRegister & VGA_MISC_RAM_ENABLED) == 0) return TRUE;
1992 
1993     /* Also ignore if write access to all planes is disabled */
1994     if ((VgaSeqRegisters[VGA_SEQ_MASK_REG] & 0x0F) == 0x00) return TRUE;
1995 
1996     if (!(VgaSeqRegisters[SVGA_SEQ_EXT_MODE_REG] & SVGA_SEQ_EXT_MODE_HIGH_RES))
1997     {
1998         /* Loop through each byte */
1999         for (i = 0; i < Size; i++)
2000         {
2001             VideoAddress = VgaTranslateAddress(Address + i);
2002 
2003             for (j = 0; j < VGA_NUM_BANKS; j++)
2004             {
2005                 /* Make sure the page is writeable */
2006                 if (!(VgaSeqRegisters[VGA_SEQ_MASK_REG] & (1 << j))) continue;
2007 
2008                 /* Check if this is chain-4 mode */
2009                 if (VgaSeqRegisters[VGA_SEQ_MEM_REG] & VGA_SEQ_MEM_C4)
2010                 {
2011                     if (((Address + i) & 0x03) != j)
2012                     {
2013                         /* This plane will not be accessed */
2014                         continue;
2015                     }
2016                 }
2017 
2018                 /* Check if this is odd-even mode */
2019                 if (VgaGcRegisters[VGA_GC_MODE_REG] & VGA_GC_MODE_OE)
2020                 {
2021                     if (((Address + i) & 0x01) != (j & 1))
2022                     {
2023                         /* This plane will not be accessed */
2024                         continue;
2025                     }
2026                 }
2027 
2028                 /* Copy the value to the VGA memory */
2029                 VgaMemory[VideoAddress * VGA_NUM_BANKS + j] = VgaTranslateByteForWriting(BufPtr[i], j);
2030             }
2031         }
2032     }
2033     else
2034     {
2035         PVOID VideoMemory;
2036 
2037         // TODO: Apply the page write mask!
2038         // TODO: Check whether the write mode stuff applies to packed-pixel modes
2039 
2040         /* Just copy to the video memory */
2041         VideoAddress = VgaTranslateAddress(Address);
2042         VideoMemory = &VgaMemory[VideoAddress + (Address & 3)];
2043 
2044         switch (Size)
2045         {
2046             case sizeof(UCHAR):
2047                 *(PUCHAR)VideoMemory = *(PUCHAR)Buffer;
2048                 return TRUE;
2049 
2050             case sizeof(USHORT):
2051                 *(PUSHORT)VideoMemory = *(PUSHORT)Buffer;
2052                 return TRUE;
2053 
2054             case sizeof(ULONG):
2055                 *(PULONG)VideoMemory = *(PULONG)Buffer;
2056                 return TRUE;
2057 
2058             case sizeof(ULONGLONG):
2059                 *(PULONGLONG)VideoMemory = *(PULONGLONG)Buffer;
2060                 return TRUE;
2061 
2062             default:
2063 #if defined(__GNUC__)
2064                 __builtin_memcpy(VideoMemory, Buffer, Size);
2065 #else
2066                 RtlCopyMemory(VideoMemory, Buffer, Size);
2067 #endif
2068         }
2069     }
2070 
2071     return TRUE;
2072 }
2073 
VgaClearMemory(VOID)2074 VOID VgaClearMemory(VOID)
2075 {
2076     RtlZeroMemory(VgaMemory, sizeof(VgaMemory));
2077 }
2078 
VgaWriteTextModeFont(UINT FontNumber,CONST UCHAR * FontData,UINT Height)2079 VOID VgaWriteTextModeFont(UINT FontNumber, CONST UCHAR* FontData, UINT Height)
2080 {
2081     UINT i, j;
2082     ASSERT(Height <= VGA_MAX_FONT_HEIGHT);
2083 
2084     for (i = 0; i < VGA_FONT_CHARACTERS; i++)
2085     {
2086         /* Write the character */
2087         for (j = 0; j < Height; j++)
2088         {
2089             VgaMemory[(i * VGA_MAX_FONT_HEIGHT + j) * VGA_NUM_BANKS + VGA_FONT_BANK] = FontData[i * Height + j];
2090         }
2091 
2092         /* Clear the unused part */
2093         for (j = Height; j < VGA_MAX_FONT_HEIGHT; j++)
2094         {
2095             VgaMemory[(i * VGA_MAX_FONT_HEIGHT + j) * VGA_NUM_BANKS + VGA_FONT_BANK] = 0;
2096         }
2097     }
2098 }
2099 
VgaInitialize(HANDLE TextHandle)2100 BOOLEAN VgaInitialize(HANDLE TextHandle)
2101 {
2102     if (!VgaConsoleInitialize(TextHandle)) return FALSE;
2103 
2104     /* Clear the SEQ, GC, CRTC and AC registers */
2105     RtlZeroMemory(VgaSeqRegisters , sizeof(VgaSeqRegisters ));
2106     RtlZeroMemory(VgaGcRegisters  , sizeof(VgaGcRegisters  ));
2107     RtlZeroMemory(VgaCrtcRegisters, sizeof(VgaCrtcRegisters));
2108     RtlZeroMemory(VgaAcRegisters  , sizeof(VgaAcRegisters  ));
2109 
2110     /* Initialize the VGA palette and fail if it isn't successfully created */
2111     if (!VgaInitializePalette()) return FALSE;
2112     /***/ VgaResetPalette(); /***/
2113 
2114     /* Reset the sequencer */
2115     VgaResetSequencer();
2116 
2117     /* Clear the VGA memory */
2118     VgaClearMemory();
2119 
2120     /* Register the I/O Ports */
2121     RegisterIoPort(0x3CC, VgaReadPort,         NULL);   // VGA_MISC_READ
2122     RegisterIoPort(0x3C2, VgaReadPort, VgaWritePort);   // VGA_MISC_WRITE, VGA_INSTAT0_READ
2123     RegisterIoPort(0x3CA, VgaReadPort,         NULL);   // VGA_FEATURE_READ
2124     RegisterIoPort(0x3C0, VgaReadPort, VgaWritePort);   // VGA_AC_INDEX, VGA_AC_WRITE
2125     RegisterIoPort(0x3C1, VgaReadPort,         NULL);   // VGA_AC_READ
2126     RegisterIoPort(0x3C4, VgaReadPort, VgaWritePort);   // VGA_SEQ_INDEX
2127     RegisterIoPort(0x3C5, VgaReadPort, VgaWritePort);   // VGA_SEQ_DATA
2128     RegisterIoPort(0x3C6, VgaReadPort, VgaWritePort);   // VGA_DAC_MASK
2129     RegisterIoPort(0x3C7, VgaReadPort, VgaWritePort);   // VGA_DAC_READ_INDEX
2130     RegisterIoPort(0x3C8, VgaReadPort, VgaWritePort);   // VGA_DAC_WRITE_INDEX
2131     RegisterIoPort(0x3C9, VgaReadPort, VgaWritePort);   // VGA_DAC_DATA
2132     RegisterIoPort(0x3CE, VgaReadPort, VgaWritePort);   // VGA_GC_INDEX
2133     RegisterIoPort(0x3CF, VgaReadPort, VgaWritePort);   // VGA_GC_DATA
2134 
2135     /* CGA ports for compatibility, unimplemented */
2136     RegisterIoPort(0x3D8, VgaReadPort, VgaWritePort);   // CGA_MODE_CTRL_REG
2137     RegisterIoPort(0x3D9, VgaReadPort, VgaWritePort);   // CGA_PAL_CTRL_REG
2138 
2139     HSyncTimer = CreateHardwareTimer(HARDWARE_TIMER_ENABLED, HZ_TO_NS(31469), VgaHorizontalRetrace);
2140 
2141     /* Return success */
2142     return TRUE;
2143 }
2144 
VgaCleanup(VOID)2145 VOID VgaCleanup(VOID)
2146 {
2147     /* Do a final display refresh */
2148     VgaRefreshDisplay();
2149 
2150     DestroyHardwareTimer(HSyncTimer);
2151 
2152     /* Leave the current video mode */
2153     VgaLeaveCurrentMode(); // ScreenMode
2154 
2155     MemRemoveFastMemoryHook((PVOID)0xA0000, 0x20000);
2156 
2157     VgaConsoleCleanup();
2158 }
2159 
2160 /* EOF */
2161