2 * COPYRIGHT: GPL - See COPYING in the top level directory
3 * PROJECT: ReactOS Virtual DOS Machine
5 * PURPOSE: VGA hardware emulation
6 * PROGRAMMERS: Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
9 /* INCLUDES *******************************************************************/
16 /* PRIVATE VARIABLES **********************************************************/
18 static BYTE VgaMemory
[VGA_NUM_BANKS
* VGA_BANK_SIZE
];
19 static BYTE VgaMiscRegister
;
20 static BYTE VgaSeqIndex
= VGA_SEQ_RESET_REG
;
21 static BYTE VgaSeqRegisters
[VGA_SEQ_MAX_REG
];
22 static BYTE VgaGcIndex
= VGA_GC_RESET_REG
;
23 static BYTE VgaGcRegisters
[VGA_GC_MAX_REG
];
24 static BYTE VgaCrtcIndex
= VGA_CRTC_HORZ_TOTAL_REG
;
25 static BYTE VgaCrtcRegisters
[VGA_CRTC_MAX_REG
];
26 static BYTE VgaAcIndex
= VGA_AC_PAL_0_REG
;
27 static BOOLEAN VgaAcLatch
= FALSE
;
28 static BYTE VgaAcRegisters
[VGA_AC_MAX_REG
];
29 static BYTE VgaDacIndex
= 0;
30 static BOOLEAN VgaDacReadWrite
= FALSE
;
31 static BYTE VgaDacRegisters
[VGA_PALETTE_SIZE
];
32 static BOOLEAN InVerticalRetrace
= FALSE
;
33 static BOOLEAN InHorizontalRetrace
= FALSE
;
34 static HANDLE TextConsoleBuffer
= NULL
;
35 static HANDLE GraphicsConsoleBuffer
= NULL
;
36 static LPVOID ConsoleFramebuffer
= NULL
;
37 static HANDLE ConsoleMutex
= NULL
;
38 static BOOLEAN NeedsUpdate
= FALSE
;
39 static BOOLEAN ModeChanged
= TRUE
;
40 static BOOLEAN CursorMoved
= FALSE
;
41 static BOOLEAN TextMode
= TRUE
;
42 static SMALL_RECT UpdateRectangle
= { 0, 0, 0, 0 };
44 /* PRIVATE FUNCTIONS **********************************************************/
46 static inline INT
VgaGetAddressSize(VOID
)
48 if (VgaCrtcRegisters
[VGA_CRTC_UNDERLINE_REG
] & VGA_CRTC_UNDERLINE_DWORD
)
50 /* Double-word addressing */
54 if (VgaCrtcRegisters
[VGA_CRTC_MODE_CONTROL_REG
] & VGA_CRTC_MODE_CONTROL_BYTE
)
64 static inline DWORD
VgaTranslateReadAddress(DWORD Address
)
66 CONST DWORD MemoryBase
[] = { 0xA0000, 0xA0000, 0xB0000, 0xB8000 };
67 DWORD Offset
= Address
- MemoryBase
[(VgaGcRegisters
[VGA_GC_MISC_REG
] >> 2) & 0x03];
70 /* Check for chain-4 and odd-even mode */
71 if (VgaSeqRegisters
[VGA_SEQ_MEM_REG
] & VGA_SEQ_MEM_C4
)
73 /* The lowest two bits are the plane number */
77 else if (VgaGcRegisters
[VGA_GC_MODE_REG
] & VGA_GC_MODE_OE
)
79 /* The LSB is the plane number */
85 /* Use the read mode */
86 Plane
= VgaGcRegisters
[VGA_GC_READ_MAP_SEL_REG
] & 0x03;
89 /* Multiply the offset by the address size */
90 Offset
*= VgaGetAddressSize();
92 return Offset
+ Plane
* VGA_BANK_SIZE
;
95 static inline DWORD
VgaTranslateWriteAddress(DWORD Address
)
97 CONST DWORD MemoryBase
[] = { 0xA0000, 0xA0000, 0xB0000, 0xB8000 };
98 DWORD Offset
= Address
- MemoryBase
[(VgaGcRegisters
[VGA_GC_MISC_REG
] >> 2) & 0x03];
100 /* Check for chain-4 and odd-even mode */
101 if (VgaSeqRegisters
[VGA_SEQ_MEM_REG
] & VGA_SEQ_MEM_C4
)
103 /* Shift the offset to the right by 2 */
106 else if (VgaGcRegisters
[VGA_GC_MODE_REG
] & VGA_GC_MODE_OE
)
108 /* Shift the offset to the right by 1 */
112 /* Multiply the offset by the address size */
113 Offset
*= VgaGetAddressSize();
115 /* Return the offset on plane 0 */
119 static inline VOID
VgaMarkForUpdate(SHORT Row
, SHORT Column
)
121 DPRINT("VgaMarkForUpdate: Row %d, Column %d\n", Row
, Column
);
123 /* Check if this is the first time the rectangle is updated */
126 UpdateRectangle
.Left
= UpdateRectangle
.Top
= (SHORT
)0x7FFF;
127 UpdateRectangle
.Right
= UpdateRectangle
.Bottom
= (SHORT
)0x8000;
130 /* Expand the rectangle to include the point */
131 UpdateRectangle
.Left
= min(UpdateRectangle
.Left
, Column
);
132 UpdateRectangle
.Right
= max(UpdateRectangle
.Right
, Column
);
133 UpdateRectangle
.Top
= min(UpdateRectangle
.Top
, Row
);
134 UpdateRectangle
.Bottom
= max(UpdateRectangle
.Bottom
, Row
);
136 /* Set the update request flag */
140 static VOID
VgaWriteSequencer(BYTE Data
)
142 ASSERT(VgaSeqIndex
< VGA_SEQ_MAX_REG
);
145 VgaSeqRegisters
[VgaSeqIndex
] = Data
;
148 static VOID
VgaWriteGc(BYTE Data
)
150 ASSERT(VgaGcIndex
< VGA_GC_MAX_REG
);
153 VgaGcRegisters
[VgaGcIndex
] = Data
;
155 /* Check the index */
158 case VGA_GC_MISC_REG
:
160 /* The GC misc register decides if it's text or graphics mode */
168 static VOID
VgaWriteCrtc(BYTE Data
)
170 ASSERT(VgaGcIndex
< VGA_CRTC_MAX_REG
);
173 VgaCrtcRegisters
[VgaCrtcIndex
] = Data
;
175 /* Check the index */
176 switch (VgaCrtcIndex
)
178 case VGA_CRTC_END_HORZ_DISP_REG
:
179 case VGA_CRTC_VERT_DISP_END_REG
:
180 case VGA_CRTC_OVERFLOW_REG
:
182 /* The video mode has changed */
188 case VGA_CRTC_CURSOR_LOC_LOW_REG
:
189 case VGA_CRTC_CURSOR_LOC_HIGH_REG
:
190 case VGA_CRTC_CURSOR_START_REG
:
191 case VGA_CRTC_CURSOR_END_REG
:
193 /* Set the cursor moved flag */
201 static VOID
VgaWriteDac(BYTE Data
)
204 VgaDacRegisters
[VgaDacIndex
++] = Data
;
205 VgaDacIndex
%= VGA_PALETTE_SIZE
;
207 // TODO: Change the palette!
210 static VOID
VgaWriteAc(BYTE Data
)
212 ASSERT(VgaAcIndex
< VGA_AC_MAX_REG
);
215 VgaAcRegisters
[VgaAcIndex
] = Data
;
218 static VOID
VgaEnterGraphicsMode(UINT Width
, UINT Height
, UINT BitDepth
)
221 CONSOLE_GRAPHICS_BUFFER_INFO GraphicsBufferInfo
;
222 BYTE BitmapInfoBuffer
[VGA_BITMAP_INFO_SIZE
];
223 LPBITMAPINFO BitmapInfo
= (LPBITMAPINFO
)BitmapInfoBuffer
;
224 LPWORD PaletteIndex
= (LPWORD
)(BitmapInfoBuffer
+ sizeof(BITMAPINFOHEADER
));
226 /* Fill the bitmap info header */
227 ZeroMemory(&BitmapInfo
->bmiHeader
, sizeof(BITMAPINFOHEADER
));
228 BitmapInfo
->bmiHeader
.biSize
= sizeof(BITMAPINFOHEADER
);
229 BitmapInfo
->bmiHeader
.biWidth
= Width
;
230 BitmapInfo
->bmiHeader
.biHeight
= Height
;
231 BitmapInfo
->bmiHeader
.biBitCount
= 8;
232 BitmapInfo
->bmiHeader
.biPlanes
= 1;
233 BitmapInfo
->bmiHeader
.biCompression
= BI_RGB
;
234 BitmapInfo
->bmiHeader
.biSizeImage
= Width
* Height
* (BitDepth
/ 8);
236 /* Fill the palette data */
237 for (i
= 0; i
< BitDepth
; i
++) PaletteIndex
[i
] = i
;
239 /* Fill the console graphics buffer info */
240 GraphicsBufferInfo
.dwBitMapInfoLength
= VGA_BITMAP_INFO_SIZE
;
241 GraphicsBufferInfo
.lpBitMapInfo
= BitmapInfo
;
242 GraphicsBufferInfo
.dwUsage
= DIB_PAL_COLORS
;
244 /* Create the buffer */
245 GraphicsConsoleBuffer
= CreateConsoleScreenBuffer(GENERIC_READ
| GENERIC_WRITE
,
246 FILE_SHARE_READ
| FILE_SHARE_WRITE
,
248 CONSOLE_GRAPHICS_BUFFER
,
249 &GraphicsBufferInfo
);
251 /* Save the framebuffer address and mutex */
252 ConsoleFramebuffer
= GraphicsBufferInfo
.lpBitMap
;
253 ConsoleMutex
= GraphicsBufferInfo
.hMutex
;
255 /* Set the active buffer */
256 SetConsoleActiveScreenBuffer(GraphicsConsoleBuffer
);
259 static VOID
VgaLeaveGraphicsMode()
261 /* Switch back to the text buffer */
262 SetConsoleActiveScreenBuffer(TextConsoleBuffer
);
264 /* Cleanup the video data */
265 CloseHandle(ConsoleMutex
);
266 CloseHandle(GraphicsConsoleBuffer
);
267 GraphicsConsoleBuffer
= NULL
;
270 static VOID
VgaUpdateMode(VOID
)
272 COORD Resolution
= VgaGetDisplayResolution();
276 /* Switching from graphics mode to text mode */
277 VgaLeaveGraphicsMode();
281 /* Free the old framebuffer */
282 HeapFree(GetProcessHeap(), 0, ConsoleFramebuffer
);
283 ConsoleFramebuffer
= NULL
;
286 /* Check if the new mode is alphanumeric */
287 if (!(VgaGcRegisters
[VGA_GC_MISC_REG
] & VGA_GC_MISC_NOALPHA
))
289 /* Resize the console */
290 SetConsoleScreenBufferSize(TextConsoleBuffer
, Resolution
);
292 /* Allocate a framebuffer */
293 ConsoleFramebuffer
= HeapAlloc(GetProcessHeap(),
298 if (ConsoleFramebuffer
== NULL
)
300 DisplayMessage(L
"An unexpected error occurred!\n");
305 /* Set the text mode flag */
310 /* Enter 8-bit graphics mode */
311 VgaEnterGraphicsMode(Resolution
.X
, Resolution
.Y
, 8);
313 /* Clear the text mode flag */
317 /* Perform a full update */
319 UpdateRectangle
.Left
= 0;
320 UpdateRectangle
.Top
= 0;
321 UpdateRectangle
.Right
= Resolution
.X
;
322 UpdateRectangle
.Bottom
= Resolution
.Y
;
325 static VOID
VgaUpdateFramebuffer(VOID
)
328 COORD Resolution
= VgaGetDisplayResolution();
329 INT AddressSize
= VgaGetAddressSize();
330 DWORD Address
= (VgaCrtcRegisters
[VGA_CRTC_START_ADDR_HIGH_REG
] << 8)
331 + VgaCrtcRegisters
[VGA_CRTC_START_ADDR_LOW_REG
];
332 DWORD ScanlineSize
= (DWORD
)VgaCrtcRegisters
[VGA_CRTC_OFFSET_REG
] * 2;
333 PCHAR_INFO CharBuffer
= (PCHAR_INFO
)ConsoleFramebuffer
;
334 PBYTE GraphicsBuffer
= (PBYTE
)ConsoleFramebuffer
;
336 /* Loop through the scanlines */
337 for (i
= 0; i
< Resolution
.Y
; i
++)
339 /* Check if this is text mode or graphics mode */
340 if (VgaGcRegisters
[VGA_GC_MISC_REG
] & VGA_GC_MISC_NOALPHA
)
344 /* Loop through the pixels */
345 for (j
= 0; j
< Resolution
.X
; j
++)
349 /* Check the shifting mode */
350 if (VgaGcRegisters
[VGA_GC_MODE_REG
] & VGA_GC_MODE_SHIFT256
)
352 /* 4 bits shifted from each plane */
354 /* Check if this is 16 or 256 color mode */
355 if (VgaAcRegisters
[VGA_AC_CONTROL_REG
] & VGA_AC_CONTROL_8BIT
)
357 /* One byte per pixel */
358 PixelData
= VgaMemory
[(j
% VGA_NUM_BANKS
) * VGA_BANK_SIZE
359 + (Address
+ (j
/ VGA_NUM_BANKS
))
364 /* 4-bits per pixel */
366 PixelData
= VgaMemory
[(j
% VGA_NUM_BANKS
) * VGA_BANK_SIZE
367 + (Address
+ (j
/ (VGA_NUM_BANKS
* 2)))
370 /* Check if we should use the highest 4 bits or lowest 4 */
371 if (((j
/ VGA_NUM_BANKS
) % 2) == 0)
383 else if (VgaGcRegisters
[VGA_GC_MODE_REG
] & VGA_GC_MODE_SHIFTREG
)
386 * 2 bits shifted from plane 0 and 2 for the first 4 pixels,
387 * then 2 bits shifted from plane 1 and 3 for the next 4
390 // TODO: NOT IMPLEMENTED!
391 DPRINT1("Interleaved shift mode is not implemented!\n");
395 /* 1 bit shifted from each plane */
397 /* Check if this is 16 or 256 color mode */
398 if (VgaAcRegisters
[VGA_AC_CONTROL_REG
] & VGA_AC_CONTROL_8BIT
)
400 /* 8 bits per pixel, 2 on each plane */
402 for (k
= 0; k
< VGA_NUM_BANKS
; k
++)
404 /* The data is on plane k, 4 pixels per byte */
405 BYTE PlaneData
= VgaMemory
[k
* VGA_BANK_SIZE
406 + (Address
+ (j
/ 4)) * AddressSize
];
408 /* The mask of the first bit in the pair */
409 BYTE BitMask
= 1 << (((3 - (j
% 4)) * 2) + 1);
411 /* Bits 0, 1, 2 and 3 come from the first bit of the pair */
412 if (PlaneData
& BitMask
) PixelData
|= 1 << k
;
414 /* Bits 4, 5, 6 and 7 come from the second bit of the pair */
415 if (PlaneData
& (BitMask
>> 1)) PixelData
|= 1 << (k
+ 4);
420 /* 4 bits per pixel, 1 on each plane */
422 for (k
= 0; k
< VGA_NUM_BANKS
; k
++)
424 BYTE PlaneData
= VgaMemory
[k
* VGA_BANK_SIZE
425 + (Address
+ (j
/ 8)) * AddressSize
];
427 /* If the bit on that plane is set, set it */
428 if (PlaneData
& (1 << (7 - (j
% 8)))) PixelData
|= 1 << k
;
433 /* Now check if the resulting pixel data has changed */
434 if (GraphicsBuffer
[i
* Resolution
.X
+ j
] != PixelData
)
436 /* Yes, write the new value */
437 GraphicsBuffer
[i
* Resolution
.X
+ j
] = PixelData
;
439 /* Mark the specified pixel as changed */
440 VgaMarkForUpdate(i
, j
);
448 /* Loop through the characters */
449 for (j
= 0; j
< Resolution
.X
; j
++)
451 DWORD CurrentAddr
= LOWORD((Address
+ j
) * AddressSize
);
454 /* Plane 0 holds the character itself */
455 CharInfo
.Char
.AsciiChar
= VgaMemory
[CurrentAddr
];
457 /* Plane 1 holds the attribute */
458 CharInfo
.Attributes
= VgaMemory
[CurrentAddr
+ VGA_BANK_SIZE
];
460 /* Now check if the resulting character data has changed */
461 if ((CharBuffer
[i
* Resolution
.X
+ j
].Char
.AsciiChar
!= CharInfo
.Char
.AsciiChar
)
462 || (CharBuffer
[i
* Resolution
.X
+ j
].Attributes
!= CharInfo
.Attributes
))
464 /* Yes, write the new value */
465 CharBuffer
[i
* Resolution
.X
+ j
] = CharInfo
;
467 /* Mark the specified pixel as changed */
468 VgaMarkForUpdate(i
, j
);
473 /* Move to the next scanline */
474 Address
+= ScanlineSize
;
478 static VOID
VgaUpdateTextCursor(VOID
)
481 CONSOLE_CURSOR_INFO CursorInfo
;
482 BYTE CursorStart
= VgaCrtcRegisters
[VGA_CRTC_CURSOR_START_REG
] & 0x3F;
483 BYTE CursorEnd
= VgaCrtcRegisters
[VGA_CRTC_CURSOR_END_REG
] & 0x1F;
484 DWORD ScanlineSize
= (DWORD
)VgaCrtcRegisters
[VGA_CRTC_OFFSET_REG
] * 2;
485 WORD Location
= MAKEWORD(VgaCrtcRegisters
[VGA_CRTC_CURSOR_LOC_LOW_REG
],
486 VgaCrtcRegisters
[VGA_CRTC_CURSOR_LOC_HIGH_REG
]);
488 if (CursorStart
< CursorEnd
)
491 CursorInfo
.bVisible
= TRUE
;
492 CursorInfo
.dwSize
= (100 * (CursorEnd
- CursorStart
)) >> 5;
497 CursorInfo
.bVisible
= FALSE
;
498 CursorInfo
.dwSize
= 0;
501 /* Add the cursor skew to the location */
502 Location
+= (VgaCrtcRegisters
[VGA_CRTC_CURSOR_END_REG
] >> 5) & 3;
504 /* Find the coordinates of the new position */
505 Position
.X
= Location
% ScanlineSize
;
506 Position
.Y
= Location
/ ScanlineSize
;
508 /* Update the physical cursor */
509 SetConsoleCursorInfo(TextConsoleBuffer
, &CursorInfo
);
510 SetConsoleCursorPosition(TextConsoleBuffer
, Position
);
513 /* PUBLIC FUNCTIONS ***********************************************************/
515 DWORD
VgaGetVideoBaseAddress(VOID
)
517 CONST DWORD MemoryBase
[] = { 0xA0000, 0xA0000, 0xB0000, 0xB8000 };
518 return MemoryBase
[(VgaGcRegisters
[VGA_GC_MISC_REG
] >> 2) & 0x03];
521 DWORD
VgaGetVideoLimitAddress(VOID
)
523 CONST DWORD MemoryLimit
[] = { 0xA7FFF, 0xA7FFF, 0xB7FFF, 0xBFFFF };
524 return MemoryLimit
[(VgaGcRegisters
[VGA_GC_MISC_REG
] >> 2) & 0x03];
527 COORD
VgaGetDisplayResolution(VOID
)
531 /* The low 8 bits are in the display registers */
532 Resolution
.X
= VgaCrtcRegisters
[VGA_CRTC_END_HORZ_DISP_REG
];
533 Resolution
.Y
= VgaCrtcRegisters
[VGA_CRTC_VERT_DISP_END_REG
];
535 /* Set the top bits from the overflow register */
536 if (VgaCrtcRegisters
[VGA_CRTC_OVERFLOW_REG
] & VGA_CRTC_OVERFLOW_VDE8
)
538 Resolution
.Y
|= 1 << 8;
540 if (VgaCrtcRegisters
[VGA_CRTC_OVERFLOW_REG
] & VGA_CRTC_OVERFLOW_VDE9
)
542 Resolution
.Y
|= 1 << 9;
545 /* Increase the values by 1 */
549 if (VgaGcRegisters
[VGA_GC_MISC_REG
] & VGA_GC_MISC_NOALPHA
)
551 /* Multiply the horizontal resolution by the 9/8 dot mode */
552 Resolution
.X
*= (VgaSeqRegisters
[VGA_SEQ_CLOCK_REG
] & VGA_SEQ_CLOCK_98DM
)
555 /* The horizontal resolution is halved in 8-bit mode */
556 if (VgaAcRegisters
[VGA_AC_CONTROL_REG
] & VGA_AC_CONTROL_8BIT
) Resolution
.X
/= 2;
558 /* Divide the vertical resolution by the maximum scan line */
559 Resolution
.Y
/= ((DWORD
)VgaCrtcRegisters
[VGA_CRTC_MAX_SCAN_LINE_REG
] & 0x1F) + 1;
563 /* Divide the number of scanlines by the font size */
567 /* Return the resolution */
571 VOID
VgaRefreshDisplay(VOID
)
573 COORD Resolution
= VgaGetDisplayResolution();
575 DPRINT("VgaRefreshDisplay\n");
579 /* Change the display mode */
582 /* Reset the mode change flag */
588 /* Change the text cursor location */
589 VgaUpdateTextCursor();
591 /* Reset the cursor move flag */
595 /* Update the contents of the framebuffer */
596 VgaUpdateFramebuffer();
598 /* Set the vertical retrace flag */
599 InVerticalRetrace
= TRUE
;
601 /* Ignore if there's nothing to update */
602 if (!NeedsUpdate
) return;
604 DPRINT("Updating screen rectangle (%d, %d, %d, %d)\n",
605 UpdateRectangle
.Left
,
607 UpdateRectangle
.Right
,
608 UpdateRectangle
.Bottom
);
610 /* Check if this is text mode or graphics mode */
611 if (VgaGcRegisters
[VGA_GC_MISC_REG
] & VGA_GC_MISC_NOALPHA
)
615 /* Redraw the screen */
616 InvalidateConsoleDIBits(GraphicsConsoleBuffer
, &UpdateRectangle
);
621 COORD Origin
= { UpdateRectangle
.Left
, UpdateRectangle
.Top
};
623 /* Write the data to the console */
624 WriteConsoleOutputA(TextConsoleBuffer
,
625 (PCHAR_INFO
)ConsoleFramebuffer
,
632 /* Clear the update flag */
636 VOID
VgaHorizontalRetrace(VOID
)
639 InHorizontalRetrace
= TRUE
;
642 VOID
VgaReadMemory(DWORD Address
, LPBYTE Buffer
, DWORD Size
)
646 DPRINT("VgaReadMemory: Address 0x%08X, Size %lu\n",
650 /* Ignore if video RAM access is disabled */
651 if (!(VgaMiscRegister
& VGA_MISC_RAM_ENABLED
)) return;
653 /* Loop through each byte */
654 for (i
= 0; i
< Size
; i
++)
656 DWORD VideoAddress
= VgaTranslateReadAddress(Address
+ i
);
658 /* Copy the value to the buffer */
659 Buffer
[i
] = VgaMemory
[VideoAddress
];
663 VOID
VgaWriteMemory(DWORD Address
, LPBYTE Buffer
, DWORD Size
)
667 DPRINT("VgaWriteMemory: Address 0x%08X, Size %lu\n",
671 /* Ignore if video RAM access is disabled */
672 if (!(VgaMiscRegister
& VGA_MISC_RAM_ENABLED
)) return;
674 /* Also ignore if write access to all planes is disabled */
675 if ((VgaSeqRegisters
[VGA_SEQ_MASK_REG
] & 0x0F) == 0x00) return;
677 /* Loop through each byte */
678 for (i
= 0; i
< Size
; i
++)
680 DWORD VideoAddress
= VgaTranslateWriteAddress(Address
+ i
);
682 for (j
= 0; j
< VGA_NUM_BANKS
; j
++)
684 /* Make sure the page is writeable */
685 if (!(VgaSeqRegisters
[VGA_SEQ_MASK_REG
] & (1 << j
))) continue;
687 /* Check if this is chain-4 mode */
688 if (VgaSeqRegisters
[VGA_SEQ_MEM_REG
] & VGA_SEQ_MEM_C4
)
690 if (((Address
+ i
) & 3) != j
)
692 /* This plane will not be accessed */
697 /* Check if this is odd-even mode */
698 if (VgaGcRegisters
[VGA_GC_MODE_REG
] & VGA_GC_MODE_OE
)
700 if (((Address
+ i
) & 1) != (j
& 1))
702 /* This plane will not be accessed */
707 /* Copy the value to the VGA memory */
708 VgaMemory
[VideoAddress
+ j
* VGA_BANK_SIZE
] = Buffer
[i
];
713 BYTE
VgaReadPort(WORD Port
)
715 DPRINT("VgaReadPort: Port 0x%04X\n", Port
);
726 return VgaAcRegisters
[VgaAcIndex
];
736 return VgaSeqRegisters
[VgaSeqIndex
];
739 case VGA_DAC_READ_INDEX
:
741 /* This returns the read/write state */
742 return VgaDacReadWrite
? 0 : 3;
745 case VGA_DAC_WRITE_INDEX
:
752 /* Ignore reads in write mode */
753 if (!VgaDacReadWrite
)
755 BYTE Data
= VgaDacRegisters
[VgaDacIndex
++];
756 VgaDacIndex
%= VGA_PALETTE_SIZE
;
765 return VgaMiscRegister
;
775 return VgaCrtcRegisters
[VgaCrtcIndex
];
785 return VgaGcRegisters
[VgaGcIndex
];
793 /* Reset the AC latch */
796 /* Set a flag if there is a vertical or horizontal retrace */
797 if (InVerticalRetrace
|| InHorizontalRetrace
) Result
|= VGA_STAT_DD
;
799 /* Set an additional flag if there was a vertical retrace */
800 if (InVerticalRetrace
) Result
|= VGA_STAT_VRETRACE
;
802 /* Clear the flags */
803 InHorizontalRetrace
= InVerticalRetrace
= FALSE
;
812 VOID
VgaWritePort(WORD Port
, BYTE Data
)
814 DPRINT("VgaWritePort: Port 0x%04X, Data 0x%02X\n", Port
, Data
);
822 /* Change the index */
823 if (Data
< VGA_AC_MAX_REG
) VgaAcIndex
= Data
;
831 /* Toggle the latch */
832 VgaAcLatch
= !VgaAcLatch
;
839 /* Set the sequencer index register */
840 if (Data
< VGA_SEQ_MAX_REG
) VgaSeqIndex
= Data
;
847 /* Call the sequencer function */
848 VgaWriteSequencer(Data
);
853 case VGA_DAC_READ_INDEX
:
855 VgaDacReadWrite
= FALSE
;
856 VgaDacIndex
= Data
% VGA_PALETTE_SIZE
;
861 case VGA_DAC_WRITE_INDEX
:
863 VgaDacReadWrite
= TRUE
;
864 VgaDacIndex
= Data
% VGA_PALETTE_SIZE
;
871 /* Ignore writes in read mode */
872 if (VgaDacReadWrite
) VgaWriteDac(Data
& 0x3F);
879 VgaMiscRegister
= Data
;
886 /* Set the CRTC index register */
887 if (Data
< VGA_CRTC_MAX_REG
) VgaCrtcIndex
= Data
;
894 /* Call the CRTC function */
902 /* Set the GC index register */
903 if (Data
< VGA_GC_MAX_REG
) VgaGcIndex
= Data
;
909 /* Call the GC function */
917 VOID
VgaInitialize(HANDLE TextHandle
)
923 COORD Origin
= { 0, 0 };
924 SMALL_RECT ScreenRect
;
925 PCHAR_INFO CharBuffer
;
928 /* Set the global handle */
929 TextConsoleBuffer
= TextHandle
;
931 /* Set the default video mode */
932 BiosSetVideoMode(BIOS_DEFAULT_VIDEO_MODE
);
937 Resolution
= VgaGetDisplayResolution();
938 CharBuffer
= (PCHAR_INFO
)ConsoleFramebuffer
;
939 AddressSize
= VgaGetAddressSize();
940 ScreenRect
.Left
= ScreenRect
.Top
= 0;
941 ScreenRect
.Right
= Resolution
.X
;
942 ScreenRect
.Bottom
= Resolution
.Y
;
943 ScanlineSize
= (DWORD
)VgaCrtcRegisters
[VGA_CRTC_OFFSET_REG
] * 2;
945 /* Read the data from the console into the framebuffer */
946 ReadConsoleOutputA(TextConsoleBuffer
,
953 /* Loop through the scanlines */
954 for (i
= 0; i
< Resolution
.Y
; i
++)
956 /* Loop through the characters */
957 for (j
= 0; j
< Resolution
.X
; j
++)
959 DWORD CurrentAddr
= LOWORD((Address
+ j
) * AddressSize
);
961 /* Store the character in plane 0 */
962 VgaMemory
[CurrentAddr
] = CharBuffer
[i
* Resolution
.X
+ j
].Char
.AsciiChar
;
964 /* Store the attribute in plane 1 */
965 VgaMemory
[CurrentAddr
+ VGA_BANK_SIZE
] = CharBuffer
[i
* Resolution
.X
+ j
].Attributes
;
968 /* Move to the next scanline */
969 Address
+= ScanlineSize
;