
      ͻ
                                                                   
                                                                     
        ۰                   ۰                             
        ۰    ۰ ۰   ۰ ۰ ۰     ۰ ۰     ۰   
        ۰    ۰ ۰   ۰   ۰   ۰     ۰   ۰ ۰     ۰   
        ۰    ۰ ۰   ۰   ۰   ۰     ۰ ۰     ۰   
        ۰    ۰ ۰   ۰   ۰   ۰     ۰   ۰ ۰ ۰ ۰   
        ۰ ۰   ۰   ۰ ۰   ۰  ۰ ۰    
                                                                     
                              T  R  I  A  D                      
                                                                   
      Ľ
                               ͻ
                                 PRESENTS  
                               ͼ


                        Chain-4 Documentary Version 2.0

  Written By : Vulture                    Total Files  : 2
  File Type  : Textfile                   Release Date : 17th of June 1995
  Difficulty : Medium level               Filename     : CHAINDOC.ZIP


Note: This is version 2.0. It includes some pascal procedures at the end of
      the document.

I started writing this little document as a helpfile for myself coz I think
a great way to learn is writing things down. I found myself having troubles
understanding the assembler code found in various trainers so I thought it
was a good idea to make a textfile wich covered some of the main tricks there
are concerning chain-4 code. Worked out great! Infact, I think this file can
be of great help to all starting gfxcoders out there, so I have decided to
release it into the public domain. There are already lots of docs available
on the subject but there's always room for one more, eh? :)
Hmm, I will assume you know a little about VGA programming and assembler code.
If you don't know anything about it yet, this doc might be a little hard to
understand. If you are already a chain-4 guru, you can go back to sleep coz
this is probably too easy for you. This document describes the very basics of
chain-4. But anyway, enough of thiz cr*p. . . on with the real stuff :)


=-=-=-=-=-=-=-=-=-=-=-=-= CHAIN-4 VIDEOMODE DOCFILE =-=-=-=-=-=-=-=-=-=-=-=-=-

=-= What is chain-4 ? =-=

Most VGA intros are written in mode 13h. This is 320*200*256 mode. The memory
in this mode is lineair and thus fairly easy to handle. The resolution isn't
that great but for most intros it's enough. One can make very cewl graphics
in this mode. So all in all this is a great mode to use. However, a major
disadvantage is the fact that only 64 kB of VGA memory can be accessed.
This is the entire screen (320*200 = almost 64kB = 1 page) you see in front
of you. So, when you use this mode you aren't using the full standard 256kB
of memory present on the VGA-card but just 64kB. For most people mode 13h is
sufficient but for the more serious coders it just isn't enough. They want to
use the full 256 kB of memory available for e.g fast pageflipping, full screen
scrolling and lots of other cewl things. Here we go:
Chain-4 is a method of accessing 256 kB of memory on a standard VGA-card.
When using chain-4 the VGA memory is unchained wich bassicly means that the
memory is no longer lineair as were the case in standard mode 13h. Due to VGA
hardware this gives us 256 kB of memory. On a chain-4 screen pixels are placed
on so-called bitplanes. Normally there are four pages (=planes) available,
each 64kB big. This is coz a segment can only be 64 kB big. And 4*64kB=256kB.
It is also possible to 'tweak' the videomode and get into higher resolutions.
E.g 320*240*256. This results in you having less pages available because
you have more pixels on a page. However, in this doc I will not go into
tweaking the videomode but stay with the basics.
Take a look at the following diagram. It shows a possible chain-4 screen.

  0            X         640
   Ŀ
         =>Ŀ    
             View         The viewport always shows 1/4=64k of the
             Port         total chain-4 screen. In this case the
                          chain-4 screen is 2 pages width and 2
 Y                pages high. The total chain-4 screen can
                            be anything that adds up to 4 pages.
      Chain-4 screen        More of this l8r downbelow.
                         
   
 400

The memory layout of the chain-4 screen is rather different from the normal
MCGA gfxmode. Like I said previously, the memory is divided into 4 bitplanes.
Each 64 kB big because of segmentlimitations. The following picture should
clear some things. Suppose you are plotting pixels with colors 0 to 9.
If the color has reached value 9, it's set to 0 again. Take a look:

The standard lineair MCGA mode gives us:

             Ŀ
             000102030405060708090001...etc...


In unchained VGA memory, the screen will be represented as follows:

Plane 0:

    Address:  0         10                70       79 (Not 319 anymore)
             Ŀ
             0482604826048260    .....   0482604826
                                                   

Plane 1:

    Address:  0         10                70       79
             Ŀ
             1593715937159371    .....   1593715937
                                                   

Plane 2:

    Address:  0         10                70       79
             Ŀ
             2604826048260482    .....   2604826048
                                                   

Plane 3:

    Address:  0         10                70       79
             Ŀ
             3715937159371593    .....   3715937159
                                                   

This means that when you point to an address, you are actually pointing to
the addresses of FOUR neighbouring pixels. To be more exact: address 0
points to pixels 0,1,2 and 3, each on different planes. Adress 1 points to
pixels 4,5,6 and 7, etcetera. Now, before writing the pixel, you will have to
enable the plane of the pixel you want. If pixel P is in plane I, pixel P+1
will be in plane (I+1)%4. The screenwidth is now set to 80 instead of 320.
This should make perfect sence. Think about it. One adress points to 4 pixels.
Multiply 80 by 4 and you'll get your basic 320 again. And there are still 320
pixels across visible. 200 pixels in height remains the same. Simple!

So, that's a bit different, eh? Also more difficult to code. But don't let it
scare you. The advantages you gain from using this mode are well worth the
effort. And besides, you have this doc so it's not that hard anymore :)

This document explains how to access the unchained videomode, enable
planes for writing and reading, moving across the screens and putting
pixels on the screens.

A. How to access the unchained VGA mode.
B. How to activate the plane we want to write to.
C. How to activate the plane we want to read from.
D. How to move across the various planes (screens).
E. How to place a pixel on the chain-4 screen.
F. Various pascal procedures concerning this code.
G. Closing words.

=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

A. HOW TO ACCESS THE UNCHAINED VGA MODE.

This is done by setting various vga registers. The code below is very
basic and can be expanded but it's suitable for our needs right now.

1. Get into MCGA mode.
   Done by a simple bios-call.

   mov   ax,0013h          ; Videomode 13h  320*200*256
   int   10h               ; Set the mode

2. Unchain VGA-mode.
   This is done by turning the 3rd bit in index 4 of the sequencer off.

   mov   dx,03c4h         ; Sequencer Address Register
   mov   al,4             ; Index 4 - Memory mode
   out   dx,al            ; Select it
   inc   dx               ; 03c5h - Here we set the mem mode.
   in    al,dx            ; Get settings inside register
   and   al,11110111b     ; Disable 3rd bit will give us chain-4
   or    al,00000100b     ; Bit 2 enabled => no odd/even-scheme
   out   dx,al            ; Inform VGA

3. Turn off doubleword mode by setting the Underline Location register
   Use CRT controllers port 3d4h index 14h

   mov   dx,3d4h
   mov   al,14h           ; Select index 14 "Underline Location Register"
   out   dx,al
   inc   dx
   in    al,dx
   and   al,10111111b     ; Bit 6 := 0 => Disable double word adressing
   out   dx,al

4. Turn off word adressing by setting the Mode Control register.
   Now use CRT controllers port 3d4h index 17h

   mov   dx,3d4h
   mov   al,17h           ; Mode Control Register
   out   dx,al
   inc   dx
   in    al,dx            ; Get what's in the register
   or    al,01000000b     ; Bit 6 := 1
   out   dx,al            ; Thus disabling wordmode

5. Set the logical screen width.
   To do this, use the CRT controllers port 3d4h index 13h.

   mov   dx,3d4h         ; Select the port
   mov   al,13h          ; Select index Logical Screen Width
   out   dx,al           ; Inform VGA about it
   inc   dx              ; Increase port value
   mov   al,[Size]       ; Set the size
   out   dx,al           ; Give info to VGA

Like I stated previously, the chain-4 screen can be any size that adds
up to 4 screens with a screen being 320*200 pixels large (=64kB).
Size * 8 is how many pixels across there are on the chain-4 screen.
Examine this:
Size = 40  =>  320 pixels across = 1 screen across, 4 screens down
Size = 80  =>  640 pixels across = 2 screens across, 2 screens down
Size = 160 => 1280 pixels across = 4 screens across, 1 screen down
These are all possibilities. Remember, only 320 pixels across are visible.
We need to know the size of the screen for almost all dealings with the
chain-4 screen so it's clever to put the size in a constant. Just like I did
in the example code.

=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

B. HOW TO ACTIVATE THE PLANE WE WANT TO WRITE TO.

Before we can plot a pixel on the chain-4 screen, we have to select and
activate the plane we want to write to. You must alter the 4 least signifi-
cant bits (bits 0,1,2 and/or 3) in index 2 (set/reset enable register) of
the graphics controller. This is done as follows:

1. Select gfx controller: port 3ceh
   mov   dx,3ceh
2. Select index 2 => Set/reset enable register
   mov   al,02
3. Pass info to VGA
   out   dx,al
4. Increase port value
   inc   dx
5. Select plane for writing      ; 1 = on  0 = off
   mov   al,00000001b            ; enables plane 0    (byte=76543210)
6. Give info to VGA
   out   dx,al

So, to enable plane 0 for writing:

   mov   dx,3ceh          ; Select port
   mov   al,02            ; Select index
   out   dx,al            ; Give info to VGA
   inc   dx               ; Increase port value (datafield)
   mov   al,00000001b     ; Enable plane 0   (bit 0 is now set)
   out   dx,al            ; Inform VGA 'bout thiz

For all other planes the same code can be used. Just change the MOV command.
You can also use the AND command for this purpose. Play with it and learn.
All 4 planes can be set for writing to so you can set 4 pixels at the same
time with just 1 movsb. Simply enable the 4 least significant bits at once.
Wow! This is fast...  :)

=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

C. HOW TO ACTIVATE THE PLANE WE WANT TO READ FROM.

Same goes for reading. First activate the plane and then read the pixel.
Do it like thiz:

1. Select gfx controller port 3ceh
   mov   dx,3ceh
2. Select index
   mov   al,04                  ; Read plane index
3. Inform VGA about this
   out   dx,al
4. Increase port value
   inc   dx
5. Select plane for reading
   mov   al,00000000b           ; Select plane 0 for reading
6. Inform VGA
   out   dx,al

Bits 0 and 1 must be altered to select a plane for reading. (byte=76543210)
00: plane 0 read enable.
01: plane 1 read enable.
10: plane 2 read enable.
11: plane 3 read enable.
As you might have guessed, you cannot read from all planes at the same time.

So, to enable plane 0 for reading, you'd do the following:

   mov   dx,3ceh          ; Select port
   mov   al,04            ; Select index
   out   dx,al            ; Give info to VGA
   inc   dx               ; Increase port value
   mov   al,00000000b     ; Enable plane 0 (since all bits are zero)
   out   dx,al            ; Inform VGA

That's it. Easy enough, eh?  :)

=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

D. HOW TO MOVE ACROSS THE VARIOUS PLANES (=screens).

We move across the screens by changing the upperleft adress of the viewport.

Ŀ
      =>Ŀ                   
          View     Chain-4          The viewport always shows 1/4 of the
          Port     Screen           total Chain-4 screen.
                                   
                           


This is of course an excellent way to scroll. Having a big picture on two or
more screens and then moving the viewport over the screens is much faster than
trying to scroll the screen in plain MCGA mode. Just takes a view port-writes.
To do this trick, we have to use the Crt controller port 03d4h. We need index
0Ch and 0Dh. That's Start Adress High and Start Adress Low.

1. Select Crt port
   mov   dx,03d4h
2. Select index 0Ch
   mov   al,0Ch             ; Start adress High
3. Inform VGA
   out   dx,al
4. Increase port-value
   inc   dx                 ; Data register
5. Move high byte into al
   mov   al,bh              ; Assuming bx contains total adress
6. Change VGA settings
   out   dx,al

Now we have set the high byte of the total adress. Only thing left to do is
set the low byte too. This is done the similar way except we use index 0Dh.

1. Select Crt port
   mov   dx,03d4h
2. Select index 0Dh
   mov   al,0Dh             ; Start adress Low
3. Inform VGA
   out   dx,al
4. Increase port-value
   inc   dx
5. Move low byte into al
   mov   al,bl              ; Assuming bx contains total adress
6. Change VGA settings
   out   dx,al

Now we have set the total new adress of the viewport and have moved the
entire viewport across the entire chain-4 screen. E.g you can go into a loop
where you let a picture bounce on the bottom of the screen by changing the
startingadress of the viewport. That would be pretty cewl, eh? :)

=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

E. HOW TO PLACE PIXELS ON THE CHAIN-4 SCREEN.

Ofcourse we want to plot pixels on the screen. But since we are dealing with
various planes, this is not so simple as on a MCGA screen. We have to know
on wich plane we want to plot the pixel and howfar into the plane we must be.
To find the plane we wish to plot on, we do this calculation (x mod 4), and
the x-coordinate on that plane is found by (x div 4). We work out our y by
multiplying it by the size of our chain-4 screen. This all might sound a bit
strange. Why not make a small program to see what I mean? Anyway, in steps:

1. Multiply Y by our screensize (40,80 or 160)
   y*size
2. Find out hofar in the plane we must be
   x div 4
3. Finalize location
   y:=y+x
4. Find out on wich plane to plot
   x mod 4
5. Set that plane
6. Plot the pixel

And now for the assember code:

   mov    ax,[Y]                   ; Put Y in ax
   xor    bx,bx                    ; Reset bx to zero
   mov    bl,[Size]                ; Size in bl (it's a byte!)
   imul   bx                       ; Now ax:=ax*bx => Y:=Y*Size
   shl    ax,1                     ; Multiply by 2 => Y:=Y*2 (Dunno why)
   mov    bx,ax                    ; Save Y-value in bx
   mov    ax,[X]                   ; Move X-value into ax
   mov    cx,ax                    ; And in cx
   shr    ax,2                     ; Divide ax by 4  (x div 4)
   add    bx,ax                    ; Y:=Y+X   bx contains final location
   and    cx,00000011b             ; cl:=0,1,2 or 3  (x mod 4)
   mov    ah,00000001b             ; Start value = plane 0
   shl    ah,cl                    ; E.g plane 2: 00000001 => 00000100
   mov    dx,3c4h                  ; Sequencer Register
   mov    al,2                     ; Select index 2 => plane enable
   out    dx,ax                    ; Enable selected plane
   mov    ax,0a000h                ; VGA segment
   mov    es,ax                    ; es points to VGA
   mov    al,[col]                 ; Color in al
   mov    es:[bx], al              ; Place it

This is a complete chain-4 putpixel procedure. You can ofcourse make a pascal
procedure out of it. Look at the next chapter for that one. The procedure can
ofcourse be optimized but then... what can't :)

=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

F. VARIOUS PASCAL PROCEDURES CONVERNING THIS CODE.

I have included some pascal procedures for you to examine/use. The code works
just fine and you should not have any troubles implementing this in your own
programs.

Procedure SetChain4; Assembler;  { Get into Chain-4 videomode }
Asm
   mov   ax,0013h         { Videomode 13h  320*200*256 }
   int   10h              { Set the mode }

   mov   dx,03c4h         { Sequencer Address Register }
   mov   al,4             { Index 4 - Memory mode }
   out   dx,al            { Select it }
   inc   dx               { 03c5h - Here we set the mem mode }
   in    al,dx            { Get settings inside register }
   and   al,11110111b     { Disable 3rd bit will give us chain4 }
   or    al,00000100b     { Bit 2 enabled => no odd/even-scheme }
   out   dx,al            { Inform VGA }

   mov   dx,3d4h
   mov   al,14h           { Turn off Double Word mode }
   out   dx,al
   inc   dx
   in    al,dx
   and   al,10111111b     { Bit 6 := 0 => Disable double word adressing }
   out   dx,al
   mov   dx,3d4h
   mov   al,17h           { Mode Control Register }
   out   dx,al
   inc   dx
   in    al,dx            { Get what's in the register }
   or    al,01000000b     { Bit 6 := 1 => Address memory as lineair array }
   out   dx,al

   mov   dx,3d4h          { Select the port }
   mov   al,13h           { Select the index Logical Screen Width }
   out   dx,al            { Inform VGA about it }
   inc   dx               { Increase port value }
   mov   al,[Size]        { Set the size }
   out   dx,al            { Give info to VGA }
End;

Procedure Cls_C4; Assembler;
Asm
   mov   dx,03c4h         { Select port 03c4h }
   mov   al,2             { Map Mask Register }
   out   dx,al
   inc   dx
   mov   al,00001111b     { Select all planes for writing }
   out   dx,al            { So we can clear all planes at once }

   mov   ax,0a000h
   mov   es,ax
   xor   di,di            { Set es:di = Screen Mem }
   mov   ax,0             { Color to put = black }
   mov   cx,32768         { 32768 (words) * 2 = 65536 bytes = 1 screen }

   cld
   rep   stosw            { Clear it }
End;

Procedure SetPixelC4(X,Y:Integer; Color:Byte); Assembler;
Asm
   mov    ax,[Y]                   { Put Y in ax }
   xor    bx,bx                    { Reset bx to zero }
   mov    bl,[Size]                { Size in bl (it's a Byte!) }
   imul   bx                       { Now ax:=ax*bx => Y:=Y*Size }
   shl    ax,1                     { Multiply by 2 => Y:=Y*2 (Dunno why) }
   mov    bx,ax                    { Save Y-value in bx }
   mov    ax,[X]                   { Move X-value into ax }
   mov    cx,ax                    { And in cx }
   shr    ax,2                     { Divide ax by 4  (x div 4) }
   add    bx,ax                    { Y:=Y+X   bx contains final location }
   and    cx,00000011b             { cl:=0,1,2 or 3  (x mod 4) }
   mov    ah,00000001b             { Start value (plane 0) }
   shl    ah,cl                    { Eg plane 2: 00000001 => 00000100 }
   mov    dx,3c4h                  { Sequencer Register }
   mov    al,2                     { Select index 2 => plane enable }
   out    dx,ax                    { Enable selected plane }
   mov    ax,0a000h                { VGA segment }
   mov    es,ax                    { es points to VGA }
   mov    al,[Color]               { Color in al }
   mov    es:[bx], al              { Place it }
End;

Procedure MoveTo(X,Y : Integer); Assembler;
Asm
   mov   ax,[Y]           { Y value }
   xor   bx,bx            { Reset bx to zero }
   mov   bl,[Size]        { Size in bl }
   shl   bx,1             { *2 (dunno why) }
   imul  bx               { Multiply Y with size }
   mov   bx,ax            { Save Y into BX }

   add   bx,[X]           { Y:=Y+X }

   mov   dx,03d4h         { CRTC address register }
   mov   al,0ch           { Start Address High register }
   out   dx,al
   inc   dx
   mov   al,bh            { Send high byte of start address }
   out   dx,al

   dec   dx
   mov   al,0dh           { Start Address Low register }
   out   dx,al
   inc   dx
   mov   al,bl            { Send low byte of start address }
   out   dx,al
End;

That's it. It should be easy enough to make a small sample-program with these
procedures. Why don't you try to scroll a fullscreen picture with this...

=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

G. CLOSING WORDS

Thanx must go to Denthor & Eze of Aphyxia and Robert Smith for providing info
on the topic. If you haven't got their documents, I suggest you get them.
They are quite good and can be found on various FTP-sites and BBSses.

Hmm, well, the following cr*p is supposed to be stated so here we go:
I (Vulture) take no responsibility for any mistakes found in this document.
So use at your own risk. I have used this code myself and did not have any
problems with it so this code should not give ya a hard time.

Wanna contact Outlaw for some reason? Then call one of the Outlaw distros
and leave a message.

If U actually use this info, a greet to all people stated above would be
appreciated. A little graditude doesn't hurt, does it? :)

One thing left to say. Be carefull doing this kinda stuff when you are a
beginner. Just take it one step at the time. (I did)



          Signed:   Vulture / Outlaw Triad / Cri



 Outlaw Triad Distros :    Greetz from Outlaw:    Releases sofar:

                                                
     Blue Thunder         - DemoLisher            MESSAGE  (dosscroller)
  +31 (0)36-5346967       - ThunderHawk       
                            - Ash                   VGA-VUL1 (sources)
                            - The Machine       
      FireHouse           - XNTRiC              CHAINDOC (textfile)
  +31 (0)58-2661590       - Utter Chaos       
                            - Crusher               VGA-VUL2 (sources)
                                                
                            - Critical              BASICDOC (textfile)
     Open for more!         - Da Frisian Force  
                            - Tribal               + various bbs-intros
                                                


                    (C) 1995  OUTLAW   TRIAD 


