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