148 lines
6.8 KiB
Markdown
148 lines
6.8 KiB
Markdown
Given the tremendous advantages of Mode X over the documented mode 13H,
|
|
I'd very much like to get it into the hands of as many developers as
|
|
possible, so I'm going to spend the next few chapters exploring this odd
|
|
but worthy mode. I'll provide mode set code, delineate the bitmap
|
|
organization, and show how the basic write pixel and read pixel
|
|
operations work. Then, I'll move on to the magic stuff: rectangle fills,
|
|
screen clears, scrolls, image copies, pixel inversion, and, yes, polygon
|
|
fills (just a different driver for the polygon code), all blurry fast;
|
|
hardware raster ops; and page flipping. In the end, I'll build a working
|
|
animation program that shows many of the features of Mode X in action.
|
|
|
|
The mode set code is the logical place to begin.
|
|
|
|
### Selecting 320x240 256-Color Mode {#Heading4}
|
|
|
|
We could, if we wished, write our own mode set code for Mode X from
|
|
scratch—but why bother? Instead, we'll let the BIOS do most of the work
|
|
by having it set up mode 13H, which we'll then turn into Mode X by
|
|
changing a few registers. Listing 47.1 does exactly that.
|
|
|
|
The code in Listing 47.1 has been around for some time, and the very
|
|
first version had a bug that serves up an interesting lesson. The
|
|
original *DDJ* version made images roll on IBM's fixed-frequency VGA
|
|
monitors, a problem that didn't come to my attention until the code was
|
|
in print and shipped to 100,000 readers.
|
|
|
|
The bug came about this way: The code I modified to make the Mode X mode
|
|
set code used the VGA's 28-MHz clock. Mode X should have used the 25-MHz
|
|
clock, a simple matter of setting bit 2 of the Miscellaneous Output
|
|
register (3C2H) to 0 instead of 1.
|
|
|
|
Alas, I neglected to change that single bit, so frames were drawn at a
|
|
faster rate than they should have been; however, both of my monitors are
|
|
multifrequency types, and they automatically compensated for the faster
|
|
frame rate. Consequently, my clock-selection bug was invisible and
|
|
innocuous—until it was distributed broadly and everybody started banging
|
|
on it.
|
|
|
|
IBM makes only fixed-frequency VGA monitors, which require very specific
|
|
frame rates; if they don't get what you've told them to expect, the
|
|
image rolls. The corrected version is the one shown here as Listing
|
|
47.1; it does select the 25-MHz clock, and works just fine on
|
|
fixed-frequency monitors.
|
|
|
|
Why didn't I catch this bug? Neither I nor a single one of my testers
|
|
had a fixed-frequency monitor! This nicely illustrates how difficult it
|
|
is these days to test code in all the PC-compatible environments in
|
|
which it might run. The problem is particularly severe for small
|
|
developers, who can't afford to buy every model of every hardware
|
|
component from every manufacturer; just imagine trying to test
|
|
network-aware software in all possible configurations!
|
|
|
|
When people ask why software isn't bulletproof; why it crashes or
|
|
doesn't coexist with certain programs; why PC clones aren't always
|
|
compatible; why, in short, the myriad irritations of using a PC
|
|
exist—this is a big part of the reason. I guess that's just the price we
|
|
pay for the unfettered creativity and vast choice of the PC market.
|
|
|
|
**LISTING 47.1 L47-1.ASM**
|
|
|
|
; Mode X (320x240, 256 colors) mode set routine. Works on all VGAs.
|
|
; ****************************************************************
|
|
; * Revised 6/19/91 to select correct clock; fixes vertical roll *
|
|
; * problems on fixed-frequency (IBM 851X-type) monitors. *
|
|
; ****************************************************************
|
|
; C near-callable as:
|
|
; void Set320x240Mode(void);
|
|
; Tested with TASM
|
|
; Modified from public-domain mode set code by John Bridges.
|
|
|
|
SC_INDEX equ 03c4h ;Sequence Controller Index
|
|
CRTC_INDEX equ 03d4h ;CRT Controller Index
|
|
MISC_OUTPUT equ 03c2h ;Miscellaneous Output register
|
|
SCREEN_SEG equ 0a000h ;segment of display memory in mode X
|
|
|
|
.model small
|
|
.data
|
|
; Index/data pairs for CRT Controller registers that differ between
|
|
; mode 13h and mode X.
|
|
CRTParms label word
|
|
dw 00d06h ;vertical total
|
|
dw 03e07h ;overflow (bit 8 of vertical counts)
|
|
dw 04109h ;cell height (2 to double-scan)
|
|
dw 0ea10h ;v sync start
|
|
dw 0ac11h ;v sync end and protect cr0-cr7
|
|
dw 0df12h ;vertical displayed
|
|
dw 00014h ;turn off dword mode
|
|
dw 0e715h ;v blank start
|
|
dw 00616h ;v blank end
|
|
dw 0e317h ;turn on byte mode
|
|
CRT_PARM_LENGTH equ (($-CRTParms)/2)
|
|
|
|
.code
|
|
public _Set320x240Mode
|
|
_Set320x240Mode proc near
|
|
push bp ;preserve caller's stack frame
|
|
push si ;preserve C register vars
|
|
push di ; (don't count on BIOS preserving anything)
|
|
|
|
mov ax,13h ;let the BIOS set standard 256-color
|
|
int 10h ; mode (320x200 linear)
|
|
|
|
mov dx,SC_INDEX
|
|
mov ax,0604h
|
|
out dx,ax ;disable chain4 mode
|
|
mov ax,0100h
|
|
out dx,ax ;synchronous reset while setting Misc Output
|
|
; for safety, even though clock unchanged
|
|
mov dx,MISC_OUTPUT
|
|
mov al,0e3h
|
|
out dx,al ;select 25 MHz dot clock & 60 Hz scanning rate
|
|
|
|
mov dx,SC_INDEX
|
|
mov ax,0300h
|
|
out dx,ax ;undo reset (restart sequencer)
|
|
|
|
mov dx,CRTC_INDEX ;reprogram the CRT Controller
|
|
mov al,11h ;VSync End reg contains register write
|
|
out dx,al ; protect bit
|
|
inc dx ;CRT Controller Data register
|
|
in al,dx ;get current VSync End register setting
|
|
and al,7fh ;remove write protect on various
|
|
out dx,al ; CRTC registers
|
|
dec dx ;CRT Controller Index
|
|
cld
|
|
mov si,offset CRTParms ;point to CRT parameter table
|
|
mov cx,CRT_PARM_LENGTH ;# of table entries
|
|
SetCRTParmsLoop:
|
|
lodsw ;get the next CRT Index/Data pair
|
|
out dx,ax ;set the next CRT Index/Data pair
|
|
loop SetCRTParmsLoop
|
|
|
|
mov dx,SC_INDEX
|
|
mov ax,0f02h
|
|
out dx,ax ;enable writes to all four planes
|
|
mov ax,SCREEN_SEG ;now clear all display memory, 8 pixels
|
|
mov es,ax ; at a time
|
|
sub di,di ;point ES:DI to display memory
|
|
sub ax,ax ;clear to zero-value pixels
|
|
mov cx,8000h ;# of words in display memory
|
|
rep stosw ;clear all of display memory
|
|
|
|
pop di ;restore C register vars
|
|
pop si
|
|
pop bp ;restore caller's stack frame
|
|
ret
|
|
_Set320x240Mode endp
|
|
end
|