[Back to EGAVGA SWAG index] [Back to Main SWAG index] [Original]
{
KAI ROHRBACHER
> explain MODE X.
Well, I don't care much about Mode X (which is 320x240x256), but use Mode Y
(=320x200x256) --at least I think that this mode is called "Mode Y" (as far
as I know, the terms were introduced by a series of Michael Abrash in "Dr.
Dobb's Journal" (?)). Nevertheless, things are identical With the exception
of initialising the VGA card! So here we go; note that the Asm code examples
were taken from my ANIVGA-toolkit: the PASCAL-equivalents when given are "on
the fly" Asm->PASCAL translations For improved clarity (I hope...); in
doubt, rely on the Asm part.
MODE Y in a nutshell
~~~~~~~~~~~~~~~~~~~~
Basically, Mode Y works like this: use the BIOS to switch into normal
320x200x256 mode, then reProgram the sequencer to unchain the 4 bitplanes.
This results in a bitplaned VRAM layout very similiar to the EGA/VGA's 16
color modes:
}
Procedure InitGraph; Assembler;
Asm
MOV AX,0013h
INT 10h
MOV DX,03C4h
MOV AL,04
OUT DX,AL
INC DX
in AL,DX
and AL,0F7h
or AL,04
OUT DX,AL
MOV DX,03C4h
MOV AL,02
OUT DX,AL
INC DX
MOV AL,0Fh
OUT DX,AL
MOV AX,0A000h
MOV ES,AX
SUB DI,DI
MOV AX,DI
MOV CX,8000h
CLD
REP STOSW
MOV DX,CrtAddress
MOV AL,14h
OUT DX,AL
INC DX
in AL,DX
and AL,0BFh
OUT DX,AL
DEC DX
MOV AL,17h
OUT DX,AL
INC DX
in AL,DX
or AL,40h
OUT DX,AL
end;
{
CrtAddress and StatusReg are the port addresses For the VGA ports needed;
they are 3B4h and 3BAh on a monochrome display and 3D4h and 3DAh on a color
display, but can be determined at run-time, too:
}
Asm
MOV DX,3CCh
in AL,DX
TEST AL,1
MOV DX,3D4h
JNZ @L1
MOV DX,3B4h
@L1:
MOV CrtAddress,DX
ADD DX,6
MOV StatusReg,DX
end;
{
The VRAM layout is this: underneath each memory address in the range
$A000:0000..$A000:$FFFF, there are 4 Bytes, each representing one pixel's
color.
Whenever you Write to or read from such an address, an internal logic of the
VGA-card determines which one of those 4 pixels is accessed.
A line of 320 pixels (=320 Bytes) thus only takes 320/4=80 Bytes address
space, but to address a pixel, you need a) its VRAM address and b) which
bitplane it's on.
The pixels are arranged linearly: thus, the mapping from point coordinates
to memory addresses is done by (x,y) <-> mem[$A000: y*80+ (x div 4)] and the
bitplane is determined by (x mod 4).
(Note coordinates start With 0 and that "div 4" can be computed very fast by
"shr 2"; "mod 4" by "and 3").
So you computed the proper address and bitplane. If you want to _read_ the
pixel's color, you issue commands like this:
portw[$3CE]:=(bitplane SHL 8)+4; color:=mem[$A000:y*80+(x shr 2)]
Or For better speed & control, do it in Asm:
MOV AL,4
MOV AH,bitplane
MOV DX,3CEh
CLI
OUT DX,AX
MOV AL,ES:[DI]
STI
_Writing_ a pixel's color works similiar, but needs an additional step: the
mask is computed by 1 SHL bitplane (that is: 1/2/4/8 For mod4 values 0/1/2/3
respectively):
portw[$3C4]:=(1 SHL bitplane+8)+2; mem[$A000:y*80+(x shr 2)]:=color
Or using Asm again:
MOV CL,bitplane
MOV AH,1
SHL AH,CL
MOV AL,2
MOV DX,3C4h
CLI
OUT DX,AX
STOSB
STI
As stated above, one address represents 4 pixels, so 320x200 pixels occupy
16000 address Bytes. We do have 65536 (=$A000:0..$A000:$FFFF) though,
therefore a bit more than 4 pages are possible. It's up to you to define
your pages, 0..15999=page 0, 16000..31999=page 1, 32000..47999=page 2,
48000..63999=page 3, 64000..65535=unused is the most obvious layout.
Which part of the VRAM is actually displayed can be Programmed by writing
the offset part of the starting address to the Crt-controller (the segment
part is implicitly set to $A000):
Asm
MOV DX,CrtAddress
MOV AL,$0D
CLI
OUT DX,AL
INC DX
MOV AL,low Byte of starting offset
OUT DX,AL
DEC DX
MOV AL,$0C
OUT DX,AL
INC DX
MOV AL,high Byte of starting offset
OUT DX,AL
STI
end;
N.B.: if you reProgram the display's starting address more often than "every
now and then", you better synchronize that to the vertical retrace or
horizontal enable signal of your VGA card; otherwise, an annoying screen
flicker will become visible during switching!
For example, if you do a "FOR i:=1 to 100 do SetAddress(i*80)", this will
result in a blinding fast hardware scroll: With each iteration of the loop,
the display will start 80 address Bytes (=320 pixels = 1 row) later, giving
the impression of the display scrolling upwards.
Note that Mode X/Y do not differ in any other respect than their memory
layouts from all the other bitplaned VGA modes: palette handling is the
same, as is usage of the VGA's Write modes! In (default) Write mode 0, you
can access the VRAM by Bytes, Words or dWords. Write mode 1 is handy to copy
the contents of one Graphic page to another: you are restricted to Byte
accesses, but each one will transfer 4 Bytes at once.
For example, a sequence like the following...
portw[$3C4]:=$0f02; portw[$3CE]:=$4105;
move(mem[$a000:0000],mem[$a000:$3e80],16000);
portw[$3CE]:=$4005
...enables all 4 planes, switches to Write mode 1, copies the (64000 Bytes)
contents of the 2nd Graphic page to the 1st one and then switches back to
Write mode 0 again.
}
[Back to EGAVGA SWAG index] [Back to Main SWAG index] [Original]