Spellcaster presents:


TTTTTTTTTT HH      HH EEEEEEEEEE    MM      MM    AAAA     GGGGGGGGG
    TT     HH      HH EE            MMM    MMM   AA  AA   GG
    TT     HH      HH EE            MM M  M MM  AA    AA  GG  
    TT     HHHHHHHHHH EEEEEE        MM  MM  MM  AAAAAAAA  GG   
    TT     HH      HH EE            MM      MM  AA    AA  GG    GGGG
    TT     HH      HH EE            MM      MM  AA    AA  GG      GG
    TT     HH      HH EEEEEEEEEE    MM      MM  AA    AA   GGGGGGGG

                                                        Issue 5
                                                        5-11-95



þ Index

        1. Introduction
          1.1. About the magazine
          1.2. About the author
          1.3. Distribution
          1.4. Contribuitions
          1.5. Hellos and greets
        2. Other types of variables
        3. ASM Op-codes
        4. Graphics, part 4 : Lookup Tables and Virtual Screens
          4.1. Lookup Tables
            4.1.1. What is this ?
            4.1.2. How to use ?
          4.2. Virtual Screens
            4.2.1. What are they ?
            4.2.2. How to implement ?
        5. Hints and tips
        6. Points of view
        7. The adventures of Spellcaster, part 5

þ 1. Introduction

  þ 1.1. About the magazine

    Welcome to number 5 of 'The Mag', brought to you, as usual, by Spellcaster,
  alias Diogo de Andrade.
    This issue includes part IV of my mode 13h tutorial, more begginers
  teaching, ASM Op-Codes, hints and tips, and another part of the adventures
  of Spellcaster.
    This magazine is dedicated to all the programmers and would-be programmers
  out there, especially to those that (like me) can't access the Net easily to 
  get valuable information, and to those who wish to learn how to program 
  anything, from demos to games, passing through utilities and all sort of 
  thing your mind can think of.

    Now, this is time for excuses... A friend of mine told me that I had an
  error in my assembly article in issue 3. I searched for it, and I realized he
  was right. In line 453, where it reads:

                     AX=256 =>   AL=1
                                 AH=1

  you should read:

                     AX=256 =>   AL=0
                                 AH=1

  Sorry about that unforgivable error...

    Someone told me that my mode 13h tutorial was a perfect ripoff of the
  Asphyxia's VGA tuts... I don't totally deny the similarities, but I must say
  that it isn't a ripoff. First, I must say that I'm a fan of the Asphyxia's
  tutorial, and I think it's so perfect that I'm even following a similar
  order. But, the explanations are differents, and most of the code. So,
  if anyone out there has a chance, get the Asphyxia's tutorials. They're
  great, especially if you're in demo coding. If you can't get them, ask me
  for them. I have all until number 15. I'm just a big fan that I have something
  to say to Denthor:

            "Hello... Love your tuts... Where can I contact you ?"

    Deep, wasn't it ?...

    When you read this magazine, I'll assume some things. First, I assume you
  have Borland's Turbo Pascal, version 6 and upwards (and TASM for the assembly
  tutorials). I'll also think you have a 80386 (or 386 for short; a 486 would
  be even better), a load of patience and a sense of humor. This last is almost
  essencial, because I don't receive any money for doing this, so I must have
  fun doing it. I will also take for certain you have the 9th grade (or
  equivelent). Finally, I will assume that you have the last issues of
  'The Mag', and that you have grasped the concepts I tried to transmit. If
  you don't have the issues, you can get them by mail, writing to one of the
  adresses shown below (Snail mail and Email).

    As I stated above, this magazine will be made especially for those who don't
  know where to get information, or want it all in the same place, and to those
  who want to learn how to program, so I'll try to build knowledge, building up
  your skills issue by issue. If you sometimes fail to grasp some concept, don't
  despair; try to work it out.
    That's what I did... Almost everything I know was learnt from painfull
  experience. If you re-re-re-read the article, and still can't understand it,
  just drop a line, by mail, or just plain forget it. Most of the things I 
  try to teach here aren't linked to each other (unless I say so), so if you
  don't understand something, skip it and go back to it some weeks later. It
  should be clearer for you then. Likewise, if you see any terms or words you 
  don't understand, follow the same measures as before.

    Ok, as I'm earing the Net gurus and other god-like creatures talking
  already, I'm just going to explain why I use Pascal.
  For starters, Pascal is a very good language, ideal for the beginner, like 
  BASIC (yech!), but it's powerfull enough to make top-notch programms.
  Also, I'll will be using assembly language in later issues, and Pascal makes
  it so EASY to use. 
  Finally, if you don't like my choice of language, you can stop whining. The
  teory behind each article is very simple, and common with any of the main
  languages (C, C++, Assembly - Yes, that's true... BASIC isn't a decent
  language).

    Just one last thing... The final part of the magazine is a little story
  made up by my distorted mind. It's just a little humor I like to write, and
  it hasn't got nothing to do with programming (well, it has a little), but, 
  as I said before, I just like to write it.

  þ 1.2. About the author

    Ok, so I'm a little egocentric, but tell me... If you had the trouble of 
  writing hundreds of lines, wouldn't you like someone to know you, even by 
  name ?

    My name is Diogo de Andrade, alias Spellcaster, and I'm the creator, 
  editor and writer of this magazine. 
    I live in a small town called Set£bal, just near Lisbon, the capital of
  Portugal... If you don't know where it is, get an encyclopedia, and look for
  Europe. Then, look for Spain. Next to it, there's Portugal, and Set£bal is in
  the middle.

    I'm 18 years old, and I just made it in to the university (if you do want
  to know, I'm in the Technical Institute of Lisbon, Portugal), so I'm not 
  a God-Like creature, with dozens of years of practice (I only program by 
  eight years now, and I started in a Spectrum, progressing later to an Amiga.
  I only program in the PC for a year or so), with a mega-computer (I own a 
  386SX, 16 Mhz), that wear glasses with lens that look like the bottom of a 
  bottle (I use glasses, but only sometimes), that has his head bigger than a 
  pumpkin (I have a normal sized head) and with an IQ of over 220 (mine is 
  actually something like 180). I can program in C, C++, Pascal, Assembly 
  and even BASIC (yech!).

    So, if I am a normal person, why do I spend time writing this ?
  Well, because I have the insane urge to write thousands of words every now
  and then, and while I'm at it, I may do something productive, like teaching
  someone. I may be young, but I know a lot about computers (how humble I am;
  I know, modesty isn't one of my qualities).

    Just one more thing, if you ever program anything, please send to me... I
  would love to see some work you got, maybe I could learn something with it.
  Also, give me a greet in your program/game/demo... I love seeing my name.

  þ 1.3. Distribution

    I don't really know when can I do another issue, so, there isn't a fixed
  space of time between two issues. General rule, I will try to do one every two
  weeks, maybe more or maybe less.
    'The Mag' is available by the following means:

    - Snail Mail : My address is below, in the Contributions seccion... Just
                   send me a disk and tell me what issues you want, and I
                   will send you them...

    - E-Mail : If you E-mail me and ask me for some issues, I will Email you
               back with the relevant issues attached.

    - BBS's : I don't know for sure what BBS's have or will have my magazine,
              but I will try to post it in the Skyship BBS.
              If you have a BBS and you want to receive 'The Mag', contact me.

                 Skyship BBS numbers: (351)+01-3158088
                                      (351)+01-3151435

    By the end of this year (1995), I should have an Internet Page, and some
  more BBS's in my list, besides some ftp's.

  þ 1.4. Contributions

    I as I stated before, I'm not a God... I do make mistakes, and I don't 
  have (always) the best way of doing things. So, if you think you've spotted
  an error, or you have thought of a better way of doing things, let me know.
  I'll be happy to receive anything, even if it is just mail saying 'Keep it 
  up'. As all human beings, I need incentive.

    Also, if you do like to write, please do... Send in articles, they will be
  welcome, and you will have the chance to see your names up in lights.
    They can be about anything, for a review of a book or program that can
  help a programmer, to a point of view or a moan. I'm specially interested in
  articles explaining XMS, EMS, DMA and Soundblaster/GUS.

    If anyone out there has a question or wants to see an article about 
  something in particular, feel free to write... All letters will be answered,
  provided you give me your address.

    I'm also trying to start a new demo/game/utility group, and I need all sort 
  of people, from coders (sometimes, one isn't enough), musicians (I can 
  compose, but I'm a bit limited), graphics artists (I can't draw nothing) and
  spreaders... I mean, by a spreader, someone who spreads things, like this mag.
  If you have a BBS and you want it to include this magazine, feel free to
  write me...

    You can also contact me personally, if study on the IST (if you don't
  know what the IST is, you don't study there). I'm the freshman with the 
  black hair and dark-brown eyes... The one that is sleeping in Linear
  Algebra class... I recommend you to contact me personally, if you can,
  especially if you are a member of the opposite sex (I'm a man, for those
  of you who are wondering).

    My adress is:
                 Praceta Carlos Manito Torres, n§4/6§C
                 2900 Set£bal
                 Portugal

    Email: dgan@rnl.ist.utl


  1.5. Hellos and greets

    I'll say hellos and thanks to all my friend, especially for those who put 
  up with my constant whining:
    Special greets go to Denthor from Asphyxia (for the excelent VGA trainers),
  Draeden from VLA (for assembly tutorials), Joaquim Elder Guerreiro, alias
  Dr.Shadow (Delta Team is still up), Alex "Darkfox" (thanks for letting me
  use your BBS), Jo„o Neves for sugestions, testing and BBS services, and all
  the demo groups out there.
    I also want to send a special greet to the first person (and the only one,
  'till now) that responded to my magazine: Pedro Rocha (Thanks, man...).


þ 2. Other Types of Variables

    In issue one I told you of variables and variable's types. As I think I
  said back then, the list was incomplete. The list of types is gigantic,
  because Pascal gives you the hability to make new types of variables. I will
  talk about that in a future issue. This article is about the variables of
  type real and arrays of variables.

  þ 2.1. Reals

    The real type of variables is, as the name sugests, a real. A real is a
  number with a floating point. For example, if you divide 5 by 2, you would
  get a real number (2.5).
    You can use real numbers in the same way you use normal numbers. You can
  even use the same operations.
    You have, with reals, another operation, called /. It is equal to DIV,
  but it doesn't discard the decimal part. So:

       Var A:Real
       ........
       ........
       A:=5 Div 2;      -> Var A would be equal to 2
       A:=5 / 2;        -> Var A would be equal to 2.5

    Reals have a downside, as everything in life. They are SLOWWWWW...
    But they have great flexibility, because they can store gigantic numbers
  and very small numbers.
    Another thing peculiar about reals is that they store the number in
  scientific format, so if you do Writeln of a real number, you would get
  something like this:
                           1.0000000000E+02

    This is equal to 100 ! This could appear if you did something like:

         Var A:Real;
         Begin
              A:=100;
              WriteLn(A);
         End;

    If you wanted a simpler representation of the number, you'd have to
    change the
              Writeln(A);
    to
              Writeln(A:7:2);
    where 7 is the maximum number of numbers to display and 2 is the number
    of decimal numbers.

  þ 2.2. Arrays

    An array is like a table fo variables. It can store various variables
  under a name and an index. So, every individual value in an array has a
  designatory index.
    For example, if you wanted to store the goals your favorite team has scored
  in every game, you'd could do an array, like this:

     Var Goals:Array[1..36] Of Byte;
     ..............
     ..............
     Goals[4]:=3;
     ..............
     ..............

    This tells the computer to store the value 3 in the forth position of the
  'super-variable' Goals. So, your team has scored 3 goals in the forth match.
    As you can see, arrays are very usefull. In the above example, the array
  was unidimensional, because you only needed one index to access the desired
  value. Now imagine that you wanted to store also the goals the other team
  scored:

     Var Goals:Array[1..36,1..2] Of Byte;
     ..............
     ..............
     Goals[1,1]:=3;
     Goals[1,2]:=0;
     ..............
     ..............

    So, your team has won the first game, scoring 3 goals, while the other team
  scored none ! This a bi-dimensional array.
    Arrays can have how many dimensions you want, limited to the available
  memory. Don't forget that the memory limit for variables in Pascal is 64Kb.
    Oh, I almost forgot. When you define variable Goals, in the above example,
  you said that each element of Goals was a variable of type Byte. You can
  change that to whetever variable you want (strings, bytes, chars, word, etc).

    If you're very, very bright, you figured out something funny. Variable type
  string is a special array of type char. So, when you do something like:

     Var A:String[10];

    is the almost the same as doing:

     Var A:Array[1..10] Of Char;

    Following this theory, you can access each char of a string individually,
  specifying the char's index. Example:

     Var A:String;
     ...............
     ...............
     A:='Spellchster';
     A[7]:='a';
     ...............
     ...............

    A should now contain the correct word 'Spellcaster', instead of the wrong
  'Spellchster'.



þ 3. ASM Op-Codes

    This article was made by request. It is about the assembly instructions of
  the 80x86 processor family. Not all of the instructions are here, because
  most of them are only useful for advanced programmers. Not even I use them,
  most of the time.
    Notice that all timings are for best case and are just there to give you an
  idea of the speed the instruction runs (to give you the hability to know if
  a PUSH/POP is faster than a MOV instruction).

    imed  - Imediate value.
    reg   - Register
    reg8  - 8 bit register (ex. AL)
    reg16 - 16 bit register (ex. AH)
    reg32 - 32 bit register (ex. DX:AX)
    mem   - Memory adress
    mem8  - 8 bits of memory address
    mem16 - 16 bits of memory address
    mem32 - 32 bits of memory address
    segreg- Segment register
    acumm - Acumulator (AX, AL, DX:AX)

  ADD - Arithmetic Addition

        Usage: ADD dest,src
        Modifies flags: AF CF OF PF SF ZF

        Adds "src" to "dest" and replacing the original contents of "dest".

                                 Clocks
        Operands         808x  286   386   486

        reg,reg           3     2     2     1
        mem,reg          16     7     7     3
        reg,mem           9     7     6     2
        reg,immed         4     3     2     1
        mem,immed        17     7     7     3
        accum,immed       4     3     2     1

  AND - Logical And

        Usage: AND dest,src
        Modifies flags: CF OF PF SF ZF

        Performs a logical AND of the two operands replacing the destination
        with the result.

                                Clocks
        Operands         808x  286   386   486

        reg,reg           3     2     2     1
        mem,reg          16     7     7     3
        reg,mem           9     7     6     1
        reg,immed         4     3     2     1
        mem,immed        17     7     7     3
        accum,immed       4     3     2     1

  BSF - Bit Scan Forward (386+)
  BSR - Bit Scan Reverse (386+)

        Usage: BSF dest,src
               BSR dest,src
        Modifies flags: ZF

        Scans source operand for first bit set.  Sets ZF if a bit is found
        set and loads the destination with an index to first set bit.  Clears
        ZF is no bits are found set.  BSF scans forward across bit pattern
        (0-n) while BSR scans in reverse (n-0).

                                 Clocks
        Operands         808x  286   386   486

        reg,reg           -     -   10+3n  6-42   (n is the number of bits in
        reg,mem           -     -   10+3n  7-43    source operand.)
        reg32,reg32       -     -   10+3n  6-42
        reg32,mem32       -     -   10+3n  7-43

  BT - Bit Test (386+)

        Usage: BT dest,src
        Modifies flags: CF

        The destination bit indexed by the source value is copied into the
        Carry Flag.

                                 Clocks
        Operands         808x  286   386   486

        reg16,immed8      -     -     3     3
        mem16,immed8      -     -     6     6
        reg16,reg16       -     -     3     3
        mem16,reg16       -     -     12    12

  CALL - Procedure Call

        Usage: CALL destination
        Modifies flags: None

        Pushes Instruction Pointer (and Code Segment for far calls) onto
        stack and loads Instruction Pointer with the address of proc-name.
        Code continues with execution at CS:IP.

  CLC - Clear Carry

        Usage: CLC
        Modifies flags: CF

        Clears the Carry Flag.

                                 Clocks
        Operands         808x  286   386   486

        none              2     2     2     2

  CLD - Clear Direction Flag

        Usage: CLD
        Modifies flags: DF

        Clears the Direction Flag causing string instructions to increment
        the SI and DI index registers.

                                 Clocks
        Operands         808x  286   386   486

        none              2     2     2     2

  CLI - Clear Interrupt Flag (disable)

        Usage:  CLI
        Modifies flags: IF

        Disables the maskable hardware interrupts by clearing the Interrupt
        flag.

                                 Clocks
        Operands         808x  286   386   486

        none              2     2     3     5


  CMC - Complement Carry Flag

        Usage: CMC
        Modifies flags: CF

        Toggles (inverts) the Carry Flag

                                 Clocks
        Operands         808x  286   386   486

        none              2     2     2     2

  CMP - Compare

        Usage: CMP dest,src
        Modifies flags: AF CF OF PF SF ZF

        Subtracts source from destination and updates the flags but does
        not save result.  Flags can subsequently be checked for conditions.

                                 Clocks
        Operands         808x  286   386   486

        reg,reg           3     2     2     1
        mem,reg           9     7     5     2
        reg,mem           9     6     6     2
        reg,immed         4     3     2     1
        mem,immed        10     6     5     2
        accum,immed       4     3     2     1

  DEC - Decrement

        Usage: DEC dest
        Modifies flags: AF OF PF SF ZF

        Unsigned binary subtraction of one from the destination.

                                 Clocks
        Operands         808x  286   386   486

        reg8              3     2     2     1
        mem              15     7     6     3
        reg16/32          3     2     2     1

  DIV - Divide

        Usage: DIV src
        Modifies flags: (AF,CF,OF,PF,SF,ZF undefined)

        Unsigned binary division of accumulator by source.  If the source
        divisor is a byte value then AX is divided by "src" and the quotient
        is placed in AL and the remainder in AH.  If source operand is a word
        value, then DX:AX is divided by "src" and the quotient is stored in AX
        and the remainder in DX.

                                 Clocks
        Operands         808x   286   386   486

        reg8             80-90   14    14    16
        reg16           144-162  22    22    24
        reg32              -     -     38    40
        mem8             86-96   17    17    16
        mem16           150-168  25    25    24
        mem32              -     -     41    40

  HLT - Halt CPU

        Usage: HLT
        Modifies flags: None

        Halts CPU until RESET line is activated, NMI or maskable interrupt
        received.  The CPU becomes dormant but retains the current CS:IP
        for later restart.

                                 Clocks
        Operands         808x  286   386   486

        none              2     2     5     4

  IN - Input Byte or Word From Port

        Usage: IN accum,port
        Modifies flags: None

        A byte, word or dword is read from "port" and placed in AL, AX or
        EAX respectively.  If the port number is in the range of 0-255
        it can be specified as an immediate, otherwise the port number
        must be specified in DX.  Valid port ranges on the PC are 0-1024,
        though values through 65535 may be specified and recognized by
        third party vendors and PS/2's.

                                 Clocks
        Operands         808x  286   386    486

        accum,immed8    10/14   5     12     14
        accum,DX         8/12   5     13     14

  INC - Increment

        Usage: INC dest
        Modifies flags: AF OF PF SF ZF

        Adds one to destination unsigned binary operand.

                                 Clocks
        Operands         808x  286   386   486

        reg8              3     2     2     1
        reg16             3     2     2     1
        reg32             3     2     2     1
        mem              15     7     6     3

  INT - Interrupt

        Usage: INT num
        Modifies flags: TF IF

        Initiates a software interrupt by pushing the flags, clearing the
        Trap and Interrupt Flags, pushing CS followed by IP and loading
        CS:IP with the value found in the interrupt vector table.  Execution
        then begins at the location addressed by the new CS:IP

  IRET/IRETD - Interrupt Return

        Usage:  IRET
                IRETD  (386+)
        Modifies flags: AF CF DF IF PF SF TF ZF

        Returns control to point of interruption by popping IP, CS
        and then the Flags from the stack and continues execution at
        this location.  CPU exception interrupts will return to the
        instruction that cause the exception because the CS:IP placed
        on the stack during the interrupt is the address of the offending
        instruction.

  Jxx - Jump Instructions Table

       ÚÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿
       ³Mnemonic ³ Meaning                           ³ Jump Condition  ³
       ÃÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
       ³  JA     ³ Jump if Above                     ³ CF=0 and ZF=0   ³
       ³  JAE    ³ Jump if Above or Equal            ³ CF=0            ³
       ³  JB     ³ Jump if Below                     ³ CF=1            ³
       ³  JBE    ³ Jump if Below or Equal            ³ CF=1 or ZF=1    ³
       ³  JC     ³ Jump if Carry                     ³ CF=1            ³
       ³  JCXZ   ³ Jump if CX Zero                   ³ CX=0            ³
       ³  JE     ³ Jump if Equal                     ³ ZF=1            ³
       ³  JG     ³ Jump if Greater (signed)          ³ ZF=0 and SF=OF  ³
       ³  JGE    ³ Jump if Greater or Equal (signed) ³ SF=OF           ³
       ³  JL     ³ Jump if Less (signed)             ³ SF <> OF        ³
       ³  JLE    ³ Jump if Less or Equal (signed)    ³ ZF=1 or SF <> OF³
       ³  JMP    ³ Unconditional Jump                ³ unconditional   ³
       ³  JNA    ³ Jump if Not Above                 ³ CF=1 or ZF=1    ³
       ³  JNAE   ³ Jump if Not Above or Equal        ³ CF=1            ³
       ³  JNB    ³ Jump if Not Below                 ³ CF=0            ³
       ³  JNBE   ³ Jump if Not Below or Equal        ³ CF=0 and ZF=0   ³
       ³  JNC    ³ Jump if Not Carry                 ³ CF=0            ³
       ³  JNE    ³ Jump if Not Equal                 ³ ZF=0            ³
       ³  JNG    ³ Jump if Not Greater (signed)      ³ ZF=1 or SF <> OF³
       ³  JNGE   ³ Jump if Not Greater or Equal (sgn)³ SF <> OF        ³
       ³  JNL    ³ Jump if Not Less (signed)         ³ SF=OF           ³
       ³  JNLE   ³ Jump if Not Less or Equal (signed)³ ZF=0 and SF=OF  ³
       ³  JNO    ³ Jump if Not Overflow (signed)     ³ OF=0            ³
       ³  JNP    ³ Jump if No Parity                 ³ PF=0            ³
       ³  JNS    ³ Jump if Not Signed (signed)       ³ SF=0            ³
       ³  JNZ    ³ Jump if Not Zero                  ³ ZF=0            ³
       ³  JO     ³ Jump if Overflow (signed)         ³ OF=1            ³
       ³  JP     ³ Jump if Parity                    ³ PF=1            ³
       ³  JPE    ³ Jump if Parity Even               ³ PF=1            ³
       ³  JPO    ³ Jump if Parity Odd                ³ PF=0            ³
       ³  JS     ³ Jump if Signed (signed)           ³ SF=1            ³
       ³  JZ     ³ Jump if Zero                      ³ ZF=1            ³
       ÀÄÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ

  JMP - Unconditional Jump

        Usage: JMP target
        Modifies flags: None

        Unconditionally transfers control to "label".  Jumps by default
        are within -32768 to 32767 bytes from the instruction following
        the jump.  NEAR and SHORT jumps cause the IP to be updated while FAR
        jumps cause CS and IP to be updated.

  LAHF - Load Register AH From Flags

        Usage:  LAHF
        Modifies flags: None

        Copies bits 0-7 of the flags register into AH.  This includes flags
        AF, CF, PF, SF and ZF other bits are undefined.

        AH := SF ZF xx AF xx PF xx CF

                                 Clocks
        Operands         808x  286   386   486

        none              4     2     2     3

  LDS - Load Pointer Using DS

        Usage: LDS dest,src
        Modifies flags: None

        Loads 32-bit pointer from memory source to destination register
        and DS.  The offset is placed in the destination register and the
        segment is placed in DS.  To use this instruction the word at the
        lower memory address must contain the offset and the word at the
        higher address must contain the segment.

                                 Clocks
        Operands         808x  286   386   486

        reg16,mem32       16    7     7     6


  LES - Load Pointer Using ES

        Usage: LES dest,src
        Modifies flags: None

        Loads 32-bit pointer from memory source to destination register
        and ES.  The offset is placed in the destination register and the
        segment is placed in ES.  To use this instruction the word at the
        lower memory address must contain the offset and the word at the
        higher address must contain the segment.

                                 Clocks
        Operands         808x  286   386   486

        reg,mem           16    7     7     6

  LFS - Load Pointer Using FS (386+)

        Usage: LFS dest,src
        Modifies flags: None

        Loads 32-bit pointer from memory source to destination register
        and FS.  The offset is placed in the destination register and the
        segment is placed in FS.  To use this instruction the word at the
        lower memory address must contain the offset and the word at the
        higher address must contain the segment.

                                 Clocks
        Operands         808x  286   386   486

        reg,mem           -     -     7     6

  LODS - Load String (Byte, Word or Double)

        Usage:  LODS    src
                LODSB
                LODSW
                LODSD  (386+)
        Modifies flags: None

        Transfers string element addressed by DS:SI (even if an operand is
        supplied) to the accumulator.   SI is incremented based on the size
        of the operand or based on the instruction used.  If the Direction
        Flag is set SI is decremented, if the Direction Flag is clear SI
        is incremented.  You can use it with REP prefixes.

                                 Clocks
        Operands         808x  286   386   486

        src             12/16   5     5     5

  LOOP - Decrement CX and Loop if CX Not Zero

        Usage: LOOP label
        Modifies flags: None

        Decrements CX by 1 and transfers control to "label" if CX is not
        Zero.  The "label" operand must be within -128 or 127 bytes of the
        instruction following the loop instruction

  LOOPE/LOOPZ - Loop While Equal / Loop While Zero

        Usage:  LOOPE   label
                LOOPZ   label
        Modifies flags: None

        Decrements CX by 1 (without modifying the flags) and transfers
        control to "label" if CX <> 0 and the Zero Flag is set.  The
        "label" operand must be within -128 or 127 bytes of the instruction
        following the loop instruction.

  MOV - Move Byte or Word

        Usage: MOV dest,src
        Modifies flags: None

        Copies byte or word from the source operand to the destination
        operand.

                                 Clocks
        Operands         808x  286   386   486

        reg,reg           2     2     2     1
        mem,reg           9     3     2     1
        reg,mem           8     5     4     1
        mem,immed        10     3     2     1
        reg,immed         4     2     2     1
        mem,accum        10     3     2     1
        accum,mem        10     5     4     1
        segreg,reg16      2     2     2     3
        segreg,mem16      8     5     5     9
        reg16,segreg      2     2     2     3
        mem16,segreg      9     3     2     3

  MOVS - Move String (Byte or Word)

        Usage:  MOVS    dest,src
                MOVSB
                MOVSW
                MOVSD  (386+)
        Modifies flags: None

        Copies data from addressed by DS:SI (even if operands are given) to
        the location ES:DI destination and updates SI and DI based on the
        size of the operand or instruction used.  SI and DI are incremented
        when the Direction Flag is cleared and decremented when the Direction
        Flag is Set.  You can use it with REP prefixes.

                                 Clocks
        Operands         808x  286   386   486

        dest,src          18    5     7     7


  MUL - Unsigned Multiply

        Usage: MUL src
        Modifies flags: CF OF (AF,PF,SF,ZF undefined)

        Unsigned multiply of the accumulator by the source. If "src" is
        a byte value, then AL is used as the other multiplicand and the
        result is placed in AX.  If "src" is a word value, then AX is
        multiplied by "src" and DX:AX receives the result.  If "src" is
        a double word value, then EAX is multiplied by "src" and EDX:EAX
        receives the result.  The 386+ uses an early out algorithm which
        makes multiplying any size value in EAX as fast as in the 8 or 16
        bit registers.

                                 Clocks
        Operands         808x  286   386   486

        reg8            70-77   13   9-14  13-18
        reg16          118-113  21   9-22  13-26
        reg32             -     -    9-38  13-42
        mem8            76-83   16  12-17  13-18
        mem16          124-139  24  12-25  13-26
        mem32             -     -   12-21  13-42

  NEG - Two's Complement Negation

        Usage: NEG dest
        Modifies flags: AF CF OF PF SF ZF

        Subtracts the destination from 0 and saves the 2s complement of
        "dest" back into "dest".

                                 Clocks
        Operands         808x  286   386   486

        reg               3     2     2     1
        mem              16     7     6     3

  NOP - No Operation (90h)

        Usage: NOP
        Modifies flags: None

        This is a do nothing instruction.  It results in occupation of both
        space and time and is most useful for patching code segments.
        (This is the original XCHG AL,AL instruction)

                                 Clocks
        Operands         808x  286   386   486

        none              3     3     3     1

  NOT - One's Compliment Negation (Logical NOT)

        Usage: NOT dest
        Modifies flags: None

        Inverts the bits of the "dest" operand forming the 1s complement.

                                 Clocks
        Operands         808x  286   386   486

        reg               3     2     2     1
        mem              16     7     6     3

  OR - Inclusive Logical OR

        Usage: OR dest,src
        Modifies flags: CF OF PF SF ZF (AF undefined)

        Logical inclusive OR of the two operands returning the result in
        the destination.  Any bit set in either operand will be set in the
        destination.

                                 Clocks
        Operands         808x  286   386   486

        reg,reg           3     2     2     1
        mem,reg          16     7     7     3
        reg,mem           9     7     6     2
        reg,immed         4     3     2     1
        mem8,immed8      17     7     7     3
        mem16,immed16    25     7     7     3
        accum,immed       4     3     2     1

  OUT - Output Data to Port

        Usage: OUT port,accum
        Modifies flags: None

        Transfers byte in AL,word in AX or dword in EAX to the specified
        hardware port address.  If the port number is in the range of 0-255
        it can be specified as an immediate.  If greater than 255 then the
        port number must be specified in DX.  Since the PC only decodes 10
        bits of the port address, values over 1023 can only be decoded by
        third party vendor equipment and also map to the port range 0-1023.

                                 Clocks
        Operands         808x  286   386    486

        immed8,accum    10/14   3     10     16
        DX,accum         8/12   3     11     16

  POP - Pop Word off Stack

        Usage: POP dest
        Modifies flags: None

        Transfers word at the current stack top (SS:SP) to the destination
        then increments SP by two to point to the new stack top.  CS is not
        a valid destination.

                                 Clocks
        Operands         808x  286   386   486

        reg16             8     5     4     4
        reg32             4     -     -     4
        segreg            8     5     7     3
        mem16            17     5     5     6
        mem32             5     -     -     6

  POPA/POPAD - Pop All Registers onto Stack (8086+)

        Usage:  POPA
                POPAD (386+)
        Modifies flags: None

        Pops the top 8 words off the stack into the 8 general purpose 16/32
        bit registers.   Registers are popped in the following order: (E)DI,
        (E)SI, (E)BP, (E)SP, (E)DX, (E)CX and (E)AX.  The (E)SP value popped
        from the stack is actually discarded.

                                 Clocks
        Operands         808x  286   386   486

        none              -     19    24    9


  POPF/POPFD - Pop Flags off Stack

        Usage:  POPF
                POPFD (386+)
        Modifies flags: all flags

        Pops word/doubleword from stack into the Flags Register and then
        increments SP by 2 (for POPF) or 4 (for POPFD).

                                 Clocks
        Operands         808x  286   386   486

        none             8/12   5     5     9

  PUSH - Push Word onto Stack

        Usage:  PUSH src
                PUSH immed
        Modifies flags: None

        Decrements SP by the size of the operand (two or four, byte values
        are sign extended) and transfers one word from source to the stack
        top (SS:SP).

                                 Clocks
        Operands         808x  286   386   486

        reg16           11/15   3     2     1
        reg32             -     -     2     1
        mem16             16    5     5     4
        mem32             -     -     5     4
        segreg          10/14   3     2     3
        immed             -     3     2     1


  PUSHA/PUSHAD - Push All Registers onto Stack (8086+)

        Usage:  PUSHA
                PUSHAD (386+)
        Modifies flags: None

        Pushes all general purpose registers onto the stack in the following
        order: (E)AX, (E)CX, (E)DX, (E)BX, (E)SP, (E)BP, (E)SI, (E)DI.  The
        value of SP is the value before the actual push of SP.

                                 Clocks
        Operands         808x  286   386   486

        none              -     19    24    11

  PUSHF/PUSHFD - Push Flags onto Stack

        Usage:  PUSHF
                PUSHFD (386+)
        Modifies flags: None

        Transfers the Flags Register onto the stack.  PUSHF saves a 16 bit
        value while PUSHFD saves a 32 bit value.

                                 Clocks
        Operands         808x  286   386   486

        none            10/14   3     4     4

  RCL - Rotate Through Carry Left

        Usage: RCL dest,n
        Modifies flags: CF OF

           ÚÄ¿     ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿
        ÚÄþ³C³<þÄÄþ³7 <ÄÄÄÄÄÄÄÄÄÄ 0³<Ä¿
        ³  ÀÄÙ     ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ  ³
        ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ

        Rotates the bits in the destination to the left "n" times with
        all data pushed out the left side re-entering on the right.  The
        Carry Flag holds the last bit rotated out.

                                 Clocks
        Operands         808x  286   386   486

        reg,1             2     2     9     3
        mem,1             15    7     10    4
        reg,CL           8+4n  5+n    9    8-30
        mem,CL          20+4n  8+n    10   9-31
        reg,immed8        -    5+n     9   8-30
        mem,immed8        -    8+n    10   9-31

  RCR - Rotate Through Carry Right

        Usage: RCR dest,n
        Modifies flags: CF OF

           ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿     ÚÄ¿
        ÚÄ>³7 þÄÄÄÄÄÄÄÄÄ> 0³þÄÄÄ>³C³þÄ¿
        ³  ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ     ÀÄÙ  ³
        ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ

        Rotates the bits in the destination to the right "n" times with
        all data pushed out the right side re-entering on the left.  The
        Carry Flag holds the last bit rotated out.

                                 Clocks
        Operands         808x  286   386   486

        reg,1             2     2     9     3
        mem,1            15     7     10    4
        reg,CL            8    5+n    9    8-30
        mem,CL          20+4n  8+n    10   9-31
        reg,immed8        -    5+n    9    8-30
        mem,immed8        -    8+n    10   9-31

  REP - Repeat String Operation

        Usage:  REP
        Modifies flags: None

        Repeats execution of string instructions while CX<>0.  After
        each string operation, CX is decremented and the Zero Flag is
        tested.

                                 Clocks
        Operands         808x  286   386   486

        none              2     2     2

  REPE/REPZ - Repeat Equal/Repeat Zero

        Usage:  REPE
                REPZ
        Modifies flags: None

        Repeats execution of string instructions while CX<>0 and the Zero
        Flag is set.  CX is decremented and the Zero Flag tested after
        each string operation.

                                 Clocks
        Operands         808x  286   386   486

        none              2     2     2

  REPNE/REPNZ - Repeat Not Equal/Repeat Not Zero

        Usage:  REPNE
                REPNZ
        Modifies flags: None

        Repeats execution of string instructions while CX<>0 and the Zero
        Flag is clear. CX is decremented and the Zero Flag tested after
        each string operation. The combination of a repeat prefix and a
        segment override on processors other than the 386 may result in
        errors if an interrupt occurs before CX=0.

                                 Clocks
        Operands         808x  286   386   486

        none              2     2     2

  RET/RETF - Return From Procedure

        Usage:  RET  nBytes
                RETF nBytes
                RETN nBytes
        Modifies flags: None

        Transfers control from a procedure back to the instruction address
        saved on the stack.  "n bytes" is an optional number of bytes to
        release.  Far returns pop the IP followed by the CS, while near
        returns pop only the IP register.

  ROL - Rotate Left

        Usage: ROL dest,n
        Modifies flags: CF OF

        ÚÄ¿     ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿
        ³C³<þÂÄþ³7 <ÄÄÄÄÄÄÄÄÄÄ 0³<Ä¿
        ÀÄÙ  ³  ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ  ³
             ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ

        Rotates the bits in the destination to the left "n" times with
        all data pushed out the left side re-entering on the right.  The
        Carry Flag will contain the value of the last bit rotated out.

                                 Clocks
        Operands         808x  286   386   486

        reg,1             2     2     3     3
        mem,1            15     7     7     4
        reg,CL           8+4n  5+n    3     3
        mem,CL          20+4n  8+n    7     4
        reg,immed8        -    5+n    3     2
        mem,immed8        -    8+n    7     4

  ROR - Rotate Right

        Usage:  ROR     dest,n
        Modifies flags: CF OF

           ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿     ÚÄ¿
        ÚÄ>³7 þÄÄÄÄÄÄÄÄÄ> 0³þÄÂÄ>³C³   
        ³  ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ  ³  ÀÄÙ   
        ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ        

        Rotates the bits in the destination to the right "n" times with
        all data pushed out the right side re-entering on the left.  The
        Carry Flag will contain the value of the last bit rotated out.

                                 Clocks
        Operands         808x  286   386   486

        reg,1             2     2     3     3
        mem,1            15     7     7     4
        reg,CL           8+4n  5+n    3     3
        mem,CL          20+4n  8+n    7     4
        reg,immed8        -    5+n    3     2
        mem,immed8        -    8+n    7     4

  SAHF - Store AH Register into FLAGS

        Usage: SAHF
        Modifies flags: AF CF PF SF ZF

        Transfers bits 0-7 of AH into the Flags Register.  This includes
        AF, CF, PF, SF and ZF.

                                 Clocks
        Operands         808x  286   386   486

        none              4     2     3     2

  SAL/SHL - Shift Arithmetic Left/Shift Logical Left

        Usage:  SAL dest,n
                SHL dest,n
        Modifies flags: CF OF PF SF ZF

        ÚÄ¿     ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿     ÚÄ¿
        ³C³<ÄÄÄþ³7 <ÄÄÄÄÄÄÄÄÄÄ 0³<ÄÄÄþ³0³
        ÀÄÙ     ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ     ÀÄÙ

        Shifts the destination left by "n" bits with zeroes shifted
        in on right.  The Carry Flag contains the last bit shifted out.

                                 Clocks
        Operands         808x  286   386   486

        reg,1             2     2     3     3
        mem,1            15     7     7     4
        reg,CL           8+4n  5+n    3     3
        mem,CL          20+4n  8+n    7     4
        reg,immed8        -    5+n    3     2
        mem,immed8        -    8+n    7     4

  SAR - Shift Arithmetic Right

        Usage: SAR dest,n
        Modifies flags: CF OF PF SF ZF (AF undefined)

           ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿     ÚÄ¿
        ÚÄþ³7 ÄÄÄÄÄÄÄÄÄÄ> 0³ÄÄÄþ>³C³
        ³  ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ     ÀÄÙ
        ÀÄÄÄ^

        Shifts the destination right by "n" bits with the current sign
        bit replicated in the leftmost bit.  The Carry Flag contains the
        last bit shifted out.

                                 Clocks
        Operands         808x  286   386   486

        reg,1             2     2     3     3
        mem,1            15     7     7     4
        reg,CL           8+4n  5+n    3     3
        mem,CL          20+4n  8+n    7     4
        reg,immed8        -    5+n    3     2
        mem,immed8        -    8+n    7     4

  SHL - Shift Logical Left

        See: SAL

  SHR - Shift Logical Right

        Usage: SHR dest,count
        Modifies flags: CF OF PF SF ZF (AF undefined)

        ÚÄ¿     ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿     ÚÄ¿
        ³0³ÄÄÄþ>³7 ÄÄÄÄÄÄÄÄÄÄ> 0³ÄÄÄþ>³C³
        ÀÄÙ     ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ     ÀÄÙ

        Shifts the destination right by "count" bits with zeroes shifted
        in on the left.  The Carry Flag contains the last bit shifted out.

                                 Clocks
        Operands         808x  286   386   486

        reg,1             2     2     3
        mem,1           15+EA   7     7
        reg,CL           8+4n  5+n    3
        mem,CL        20+EA+4n 8+n    7
        reg,immed8        -    5+n    3
        mem,immed8        -    8+n    7

  STC - Set Carry Flag

        Usage: STC
        Modifies flags: CF

        Sets the Carry Flag to 1.

                                 Clocks
        Operands         808x  286   386   486

        none              2     2     2     2

  STD - Set Direction Flag

        Usage: STD
        Modifies flags: DF

        Sets the Direction Flag to 1 causing string instructions to
        auto-decrement SI and DI instead of auto-increment.

                                 Clocks
        Operands         808x  286   386   486

        none              2     2     2     2

  STI - Set Interrupt Flag

        Usage: STI
        Modifies flags: IF

        Sets the Interrupt Flag to 1, which enables recognition of all
        hardware interrupts.

                                 Clocks
        Operands         808x  286   386   486

        none              2     2     2     5

  STOS - Store String (Byte, Word or Doubleword)

        Usage: STOS dest
               STOSB
               STOSW
               STOSD
        Modifies flags: None

        Stores value in accumulator to location at ES:(E)DI (even if operand
        is given).  (E)DI is incremented/decremented based on the size of
        the operand (or instruction format) and the state of the Direction
        Flag. You can use it with REP prefixes.

                                 Clocks
        Operands         808x  286   386   486

        dest              11    3     4     5


  SUB - Subtract

        Usage: SUB dest,src
        Modifies flags: AF CF OF PF SF ZF

        The source is subtracted from the destination and the result is
        stored in the destination.

                                 Clocks
        Operands         808x  286   386   486

        reg,reg           3     2     2     1
        mem,reg          16     7     6     3
        reg,mem           9     7     7     2
        reg,immed         4     3     2     1
        mem,immed        17     7     7     3
        accum,immed       4     3     2     1

  XCHG - Exchange

        Usage: XCHG dest,src
        Modifies flags: None

        Exchanges contents of source and destination.

                                 Clocks
        Operands         808x  286   386   486

        reg,reg           4     3     3     3
        mem,reg          17     5     5     5
        reg,mem          17     5     5     3
        accum,reg         3     3     3     3
        reg,accum         3     3     3     3


  XOR - Exclusive OR

        Usage: XOR dest,src
        Modifies flags: CF OF PF SF ZF

        Performs a bitwise exclusive OR of the operands and returns
        the result in the destination.

                                 Clocks
        Operands         808x  286   386   486

        reg,reg           3     2     2     1
        mem,reg         16+EA   7     6     3
        reg,mem          9+EA   7     7     2
        reg,immed         4     3     2     1
        mem,immed       17+EA   7     7     3
        accum,immed       4     3     2     1



þ 4. Graphics Part IV - Lookup Tables and Virtual Screens

    Well, this issues graphics tutorial will cover two of the more powerfull
  tools you can have. One increases speed, the other makes possible for you to
  play games. I'll start with the simpler one...

  þ 4.1. Lookup Tables

    þ 4.1.1. What is this ?

    As you may noticed, last issue's circle algorithm wasn't very good. It was
  too SLOWWWWW. How come ?
    Well, because the computer had to make a sine/cosine calculation for each
  pixel. Sine and cosines calculations are very slow, even with a maths
  co-processor.
    So, what can you do to prevent this ?
    Well, you can buy a Pentium or you can use Lookup Tables.

    The Lookup Tables are, like the name sugests, a table where you can search
  for various data.
    For example, you could do, in the above case, do a sine/cosine table, which
  holded the values of the sines and cosines of the 360ø. As memory access is
  faster than any calculations, the circle algorithm would become faster.

    þ 4.1.2. How to use ?

    First, before using the lookup tables, you'll have to allocate them. This
  is were the tricky stuff begins. A sine table would have to be a table with
  at least 360 real-type values. And you can't have only the sine values of the
  'normal' angles (this is, the integer ones). You must have middle angles. For
  the circle, you'll need about 1800 values, altough this values varies with
  the size of the circle (the smaller the circle is, the less values it needs).
  If you do some calculation, you would need 10800 bytes to store a sine table
  with a 0.2 precision. Adding this with the memory needed for the cosine table,
  you would have to spend 21600 bytes. This a third of the available memory
  Pascal allocates for variables.
    As a normal Pascal array isn't praticle, we must use pointers (for an
  explanation of pointers, get issue 1. It has an article on pointers).
    To generate the table, we must first setup some types and variables:

    Type Table=Array[0..1799] Of Real;
         PTable=^Table;

    Var Sines:Ptable;
        Cosines:Ptable;

    Then, you must initialize the table:

    Procedure InitTables;
    Var A:Word;
        B:Real;
    Begin
         Getmem(Sines,Sizeof(Sines^));
         Getmem(Cosines,Sizeof(Cosines^));
         B:=0;
         For A:=0 To 1799 Do
         Begin
              Sines^[A]:=Sin(B);
              Cosines^[A]:=Cos(B);
              B:=B+0.005;
         End;
    End;

    After this, you can use it in the circle algorithm...

    Procedure Circle(X,Y,R:Integer;Col:Byte);
    Var Px,Py:Integer;
        Deg:Word;
    Begin
         For Deg:=0 to 1799 Do
         Begin
              Px:=R*Sines^[Deg]+X;
              Py:=R*Cosines^[Deg]+Y;
              PutPixel(Px,Py,Col);
         End;
    End;

    ...and when you're program is over, you delete the tables of the memory:

    Procedure ClearTables;
    Begin
         Freemem(Sines,Sizeof(Sines^));
         Freemem(Cosines,Sizeof(Cosines^));
    End;

    This is pretty straighforward. The only quirk is the pointers, but if you
  have issue 1 and you have read the article on pointers, you should be fine.
    With this issue, you should have a file called 'Tunnel.Pas'. It is last
  issue's program without the lines part and rewriten to use the new circle
  algorithm.

  þ 4.2. Virtual Screens

    þ 4.2.1. What are they ?

    Virtual screens are one of the most powerfull resources you can have in a
  program you make. Almost every program I make uses them.
    I can't quite explain what are they. Think of them as an extra screen, a
  screen where you can write what you want, without changing the current
  display.

    Imagine the following example: you are making a game, a horizontal shoot'em
  up, where a ship goes around kicking some alien butt around, in front of a
  scrolling background. For every moment of the game, you would have to do
  this:

                1. Update variables
                2. Clear Screen
                3. Scroll Background
                4. Put Your Ship
                5. Put Alien Ships
                6. Return to Step 1

    This looks fine, but have some errors. Note that between step 1 and 3, the
  screen would become totally black. At the rate a computer goes, this would
  make a terrible flicker on the screen.
    But how can we mend this ?
    Using Virtual Screens ! If you wrote all the new image in a spare screen,
  a screen you can't see, and then you copied that screen to the real screen,
  the flicker would cease... Now, the course of the program should be something
  like this:

                1. Update variables
                2. Clear Virtual Screen
                3. Scroll Background In Virtual Screen
                4. Put Your Ship In Virtual Screen
                5. Put Alien Ships In Virtual Screen
                6. Copy Virtual Screen To Real Screen
                7. Return to Step 1

    þ 4.2.2. How to implement ?

    Well, remember when I said in the first part, the mode 13h is a linear
  mode. Also, if you do calculations, you'll find out that a MCGA screen,
  320x200x256 uses 64000 bytes of memory. Knowing that, you can define virtual
  screens. Virtual screens are commonly called Virtual Pages, or just Pages.
    First, you have to define some variables:

           Const Npages=2
                 VGA=$A000

           Var Virt:Array[1..Npages] Of Pointer;
               VP:Array[1..Npages] Of Word;

    'Npages' represents the number of virtual pages you use. I usually use two,
  sometimes three. Don't forget, the more pages you use, the less memory you'll
  have for other stuff... The two variables (Virt and VP) store the Virtual
  Pages (Virt) and their Segment (Virt). The segment of the page is very
  important, because it forms the basis for all drawing operations.
    In the second  stage, you'll have to initialize the pages:

    Procedure InitVirt;
    Var A:Byte;
    Begin
         For A:=1 To Npages Do
         Begin
              GetMem(Virt[A],64000);
              VP[A]:=Segment(Virt[A]^);
         End;
    End.

    This procedure generates a 64000 bytes space full of 0's. We know have our
  virtual screens.
    Now, to use our virtual screens, you'll have to re-write the drawing
  procedures. I'll only give you the re-writen PutPixel procedure... It's pretty
  easy to figure out the other...

    Procedure PutPixel(X,Y:word;Col:Byte;Where:Word);
    Begin
         Mem[Where:(y*320)+x]:=Col;
    End;

    Now, everytime you call the PutPixel procedure, you'll have to tell him
  where to put the pixel... Examples:

    PutPixel(100,100,10,VGA);        -> This puts a pixel in (100,100) in
                                        the normal screen.

    PutPixel(100,100,10,VP[1]);      -> This puts a pixel in (100,100) in
                                        the first virtual page.

    PutPixel(100,100,10,VP[2]);      -> This puts a pixel in (100,100) in
                                        the second virtual page...

    So, as you can see, it is pretty easy to change the procedures... You just
  had the Where parameter and take it in account.
    But, I hear you cry, how can we see the pixels that we have in the virtual
  pages ?
    That's easy... You copy the contents of the virtual page to the VGA page.
  You don't have to clear the screen, because the information in the virtual
  page overwrites the information the VGA page. You can use the following
  procedure:

    Procedure CopyPage(From,Too:Word);
    Begin
         WaitVbl;
         Move(Mem[From:0],Mem[Too:0],64000);
    End;

    This copies 64000 bytes from location From:0 to location Too:0. This
  procedure can also be used to copy from page 1 to page 2, etc... Examples:

    CopyPage(VGA,PG[1]);        -> This copies the contents of the VGA screen
                                   to the first virtual page.
    CopyPage(PG[1],PG[2]);      -> This copies the contents of the first virtual
                                   page to the second page.
    CopyPage(PG[2],VGA);        -> This copies the contents of page two to the
                                   VGA page...

    I think the principle behind virtual screens is pretty easy to understand,
  and once you understand it, it is easy to implement, and when it is
  implemented, your programms will definetly improve...
    Just one more thing... Don't waste time trying to figure out how to change
  the palette in a virtual screen... There is only ONE palette, and that
  palette is used for everything in the screen, including the virtual screens.



þ 5. Hints and Tips

                *   - Begginners tip
                **  - Medium tip
                *** - Advanced tip


    - Extended Sintax (**)

      If you write {$X+} in the start of a program, you'll enable the Pascal's
      extended sintax feature. This feature enables you to use functions as
      they were procedures. In that case, the result would be discarded. The
      extended sintax enables to do an instruction like:

               Readkey;

      instead of

              C:=Readkey;

      So, you'll save up a variable and some typing...

    - Speeding up some routines (**)

      Sometimes, routines can be optimised by some clever thinking. For
      instance, you should pre-calculate every value you can. For example, let's
      assume that used the Sin(PI)+Cos(PI/2) expression (I know this is two, but
      that's not the point). If you pre-calculate this and store that value in a
      variable, using the variable from thereafter, your program could be get a
      major speed up, specially if you used to calculate this inside loops.


þ 6. Points of view

    Well, this issue is almost over, but don't despair... In a couple of weeks
  or so there will be another one... I think this is the largest issue 'till
  now (speaking of the text file alone), with over 60k in size... That means
  more than 61440 characters... My fingers ache just thinking of it.

    I have no idea of what I'm going to talk today (as in every other days, as
  the matter of fact...).
    I think I'll talk about extra-terrestrial life and it's influence in
  games...
    I just finishing reading COSMOS by Carl Sagan. I know this is an old book,
  but I needed something to read during classes. The book is very interesting,
  because it speaks of aliens and alien lifeforms. As I'm a sci-fi fanatic, I
  just love it. But, at the same time I love it, I hate it, because it tells me
  that I'll probably never see aliens and another worlds, unless I put myself
  in cryogenic sleep when I have my mega-corporation (something like Spellcaster
  Software Systems) and I'm mega-wealthy.
    But, if I can't see aliens, I can dream of them and make them real in my
  games and demos. This has been done before countless times by big software
  companies. But, everyone of them has different ideas on how aliens are and
  how they behave. The description I like most is in David Braben's "Elite II",
  because in his game, aliens aren't all bad or all good. There's a mix of the
  two, like there is here on good old Earth.

    I don't know when is the next issue gonna come, because I'm now re-starting
  an old project, called 'Titans', that I had to drop because lack of memory.
  The game is based on the Battletech board game and books (I have writen a
  couple of books now, that have something to do with Battlemechs, altough
  their part is relatively small. Besides, they are in portuguese). It is a
  multi-player strategy game, with lots of missions and expansion capabilities.
  I'm also working on a movie-demo. A movie-demo is a demo with a story behind
  it, presented to look like a movie. It will have lots of effects, specially
  solid 3d poligons. So, if anyone out there wants to lend me a hand on these
  two projects, just contact me... I need help especially in the graphics
  department, and in the Soundsystem programming.
    Next issue, I think I'm gonna talk about file accessing (for beginners and
  more advanced programmers). I'm also gonna teach you how to read a PCX file
  in the Graphics section. There will be more other stuff, but I still don't
  know what more to put. If you have any sugestions, mail me...

    Well, my friends, I must bid you farewell now... Enjoy yourself with:



þ 7. The adventures of Spellcaster, the rebel programmer of the year 2018.

  Episode 5 - A New Dawn

    The Brotherhood of the Rebel Programmer was going nicely for a month now.
  Our effort to destroy Comptel was in the meanwhile limited to robbing some
  computer stores to get the material to penetrate the Gate. We were just in
  need of some last pieces of equipment. Unfortunely,  the components we were
  looking for were rare, and they were all kept in Comptel's High Security
  Stores, the COHISS. Me and Deathripper had a plan, but we needed someone else
  to drive the getaway jetcar.
  - So, what are we going to do, man ? - asked Deathripper.
  - I have a brilliant plan, Karl, - I said ironically - let's walk down the
    street, aproach the first person we see and say to him: "Excuse me sir,
    would you mind driving the jetcar in a dangerous and pottencially suicidal
    mission against Comptel ?".
  - Don't be stupid, Spellcaster... We must know the person...
  - Well, last time I checked, all my friends are now friends of Comptel, and
    they won't help us.
  - I know someone that could help us, but...
  - But what ?! - I asked, entusiatically.
  - ...but, she's in the Sega Corporate Prison.
  - She ?! You mean a women ?!
  - Yes... A women... So ?
  - So ?! We need a man for the job, not a bloody woman !
  - That 'bloody woman' is my sister... And she is as good with the computer
    as you and me...
  I stared at Gundsen. I noticed by his face that in this momment he didn't
  cared about our plan... He just wanted to save his sister...
  - Ok, ok... - I said, making Karl smile.
    In a couple of days, another escape plan was made, again using my Final
  Judgement Virus... At the end of the night, we went to the Sega Prison,
  looking down to it from a hill. Morning was breaking, and the sun was rising
  from behind the mountains ahead of us. A ray of light cut the darkness and
  hitted me in the eyes. I semi-closed my eyes, seeing the sky in tones of
  orange. A new dawn for the Brotherhood was about to appear...

                                             See you in the next issue
                                            Diogo "SpellCaster" Andrade