[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]