[Back to FAQ SWAG index] [Back to Main SWAG index] [Original]
The non-general use registers, What are they for?
***********************************************************************
*GENERAL REGISTERS *register* definition *
* * AX * accumulator (16 bit) *
* * AH * accumulator high-order byte ( 8 bit) *
* * AL * accumulator low order byte ( 8 bit) *
* * BX * base (16 bit) *
* * BH * base high-order byte ( 8 bit) *
* * BL * base low-order byte ( 8 bit) *
* * CX * count (16 bit) *
* * CH * count high order byte ( 8 bit) *
* * CL * count low order byte ( 8 bit) *
* * DX * data (16 bit) *
* * DH * date high order byte ( 8 bit) *
* * DL * data low order byte ( 8 bit) *
***********************************************************************
*SEGMENT REGISTERS *register* definition *
* * CS * code segment (16 bit) *
* * DS * data segment (16 bit) *
* * SS * stack segment (16 bit) *
* * ES * extra segment (16 bit) *
***********************************************************************
*INDEX REGISTERS *register* definition *
* * DI * destination index (16 bit) *
* * SI * source index (16 bit) *
***********************************************************************
*POINTERS *register* definition *
* * SP * stack pointer (16 bit) *
* * BP * base pointer (16 bit) *
* * IP * instruction pointer (16 bit) *
***********************************************************************
*FLAGS AF, CF, DF, IF, OF, PF, SF, TF, ZF *
Once again here is the list of registers [and flags] on you 80xxx
processor. As was said before registers AX-DX are general use;
however they do have some other special uses. In part II we saw
that CX is known as the counting register because in is can be
automatically inc/dec durring a loop. It can also be used to
repeat a single type of machine instruction. [scambling for Doc]
The "prefix" and the instructions are as follows:
Prefix = REP
Instructions = Movs,Lods,Stos,Ins, or outs
We already know that Mov is used to move a value to a register or
a register value some address, but what's a (lod,sto,ins,out)?
That's were are other registers come into play.
In order to do operation like in pascal, you must use to special
pointers to get information that is far away from the current
code being executed. These pointers can be thought of as [es:di],
and [ds:si]. I like to label them as
[es:di] -> put
[ds:si] -> get
These two are used to get or put the value that they point to.
Notice that DS is called the data segment register, and it is
used to "get" values from where DS points. To get back to pascal,
lets use some examples.
var x : array[1..22] of byte;
[...]
fillchar(X,32,#0); {I may have this in reverse}
This procedure takes the address of X and fills is with 32 zero
values.
now...
asm
push es
push di
mov ax,seg X
mov es,ax
mov di,offset X
mov cx,32d {number of times to repeat}
mov ax,0 {the "char" we want to move}
REP {tells the processor to repeat the next repeatable}
{instruction CX times }
stosB {store whats in AX to [es:di] and increment di}
pop di
pop es
end;
There's alot of extra stuff there and you may want to know why.
The non-general use registers are used by pascal and they
_must_ remain the same value in order for pascal to run correctly.
That's why we push and pop
what's push & pop? If you know, skip the next paragraph.
Push and pop "Push" and "pop" values onto the stack. The stack is
part of the operation system and it is used by most calling programs.
Misuse of the stack can cause you program to crash the computer.
Think of the stack as like a deck of cards. IF you put a Jack, then
and Ace, and then a King in a pile you have just pushed Jack,Ace, and
King. Know when you pick up the cards you "pop" King,Ace,Jack. This
is known as a "last in first out" way of storage, and any storage
using the scheme can be called a stack. A stack must always take
the last value first and it can't jump around. What you put into
the stack always comes out in reverse order. That's why when I
push ES and DI, I must Pop Di then ES. The stack is a quick way
of storing and retrieving values.
Next, whats that "Seg" and "offset"?
These are Key words that tell the compiler to substitute at that
position the absolute address of the Variable refrenced. It's kinda
like pascal's Addr(variable) procedure. In order for you to access
variables that aren't part of a procedure call, its best to use
this method. Remeber that ES:DI must point to the variable you
are wanting to change in the code about - so you must tell the
compiler - "I want you to give the location of this variable, and
not the variables value" using the segment and offset key words.
Why didn't you move the segment of array X dirrectly to DS?
Answer, you can't. You can move the value of a register to a
segment register, but you can't move immediate values.
Illegal
mov DS,938d
mov DS,seg X
mov CS,832d
mov ES,21h
Legal
mov ax,938d
mov ds,ax
mov ax,seg X
mov ds,ax
or also legal
push 938d
pop DS
push seg X
pop DS
Tpas -> asmb
part III [2 of 2]
This section may have a bit too much information for now. If you don't
quite get all of it, don't worry! Most of this section will be repeated
and explain in greater detail in the next upcomming sections.
var x : array[1..22] of byte;
[...]
asm
push es
push di
mov ax,seg X
mov es,ax
mov di,offset X
mov cx,32d {number of times to repeat}
mov ax,0 {the "char" we want to move}
REP {tells the processor to repeat the next repeatable}
{instruction CX times }
stosB {store whats in AX to [es:di] and increment di}
pop di
pop es
end;
Starting from the top, we know that we should push the original
values of registers that aren't general use [non AX-DX]. Next,
we know that we are telling the compiler to give us the address
that X is located at and not to give us the value of X. Segment
registers can only be assinged values by a Register or a Pop.
That bring us to CX gets the number of times we want to REPeat,
and AX get the value we want to move to X. We are know at the
meaty instruction and that is STOSB. STOSB does a lot at once.
First, it moves the byte located in AL to [es:di].
Second, it increments DI so it points to the next byte of X.
Third, CX is decremented
fourth, if CX in not Zero then the process is repeated
When you have a simple loop like
" for I := 1 to 32 do x[i] := 0; ";
then, the above is a _really_quick_ way to do the same thing.
Unlike in Part II, this loop is not as general, and cant as
easily be used to do many things durring a loop. The REP only
works for certain instruction and can only repeat that instruction
CX times.
"OK, now what's LOD,INS,OUT ?"
First off, the STOS can be use two other ways. There is a STOSW
that moves a word at a time [AX] and advances DI two bytes. The
other one is STOS and truthfully, I haven't and don't know how
to use it yet.
LODS is kinda the oposite of STOS. IF stosB, it moves the byte at
DS:SI into AL, and if stosW, it moves the word at DS:SI into AX.
!Unless you know your hardware ports, skip INS and OUT for now.!
]INS is not part of the 8088 and 8086 processor and won't execute.
]IT takes a byte or word [insB, insW] from the port listed in DX
]and moves it the addess located in [ES:ID].
]
]OUT takes a byte or word and moves it to a port. It can be done
]as follows
]
]OUT 13h,AL {moves byte in AL to port 13h}
]OUT 13h,AX {moves word in AX to port 13h}
]OUT DX,al {move byte in al to port listed DX}
]out DX,ax {move word in ax to port listed DX}
]
]outs, outsB,outsW are not part of the 8088 and 8086 instruction
]outsB moves byte [ds:si] to port listed in DX and advances SI
]outsW moves word [ds:si] to port listed in DX and advances SI
]I've not used OUTS & don't yet know how.
That brings us back to the rest of the special use registers,
And they are
CS * code segment (16 bit) *
SS * stack segment (16 bit) *.
My best advice is DON'T TOUCH! Your processor uses pointers
just like you so it knows what to execute next and where the
top of the stack is. CS:IP points the next instuction to execute
and SS:SP points to the top of the stack.
CS:IP are changed by jumps and calls.
SS:SP are changed by pushes and pops
-------------------------------------------------------------
I screwed up a little bit in order so I need to rectify this
now.
I need to define immediate values, effective addresses, and so forth.
mov ax,983d
An immediate value is a byte or word that is part of the instruction.
In the example above, 938d is the immediate value that is going to
be moved into ax.
"mov ax,bx" has no immediate values. The value is stored in BX and
the word associated is not part of the instruction.
mov ax,[0000]
An effective address can be a word value that is part of the instuction
but is a location and an immediate value. When this is compiled
0000 is not moved into ax, the word pointed to by cs:[0000] is moved
into ax. Why CS? If you don't overide the segment the compiler used
defaults. Unfortunatly I don't readily know which are which, but
seeing that you might be a beginner, this won't be a problem that
has to be delt with know. In other word ignore for now.
mov ax,[bx]
This has [bx] as the effective address. The value in BX is thought
of as an address and the word pointed to by BX is moved into ax.
There are several addressing modes and I will try to explain them as
I get to them and as they are needed.
_I HIGHLY suggest that we start out with assembler procedure and
functions in Pascal and leave it at that_! I think that asm should
be used only for critical procedures that are too slow in pascal
or are things not supported by native pascal. This way you code can
be effiecient and still easily understandable.
Next section Part IV - assembler functions and procedures in pascal.
tpas -> asmb
part IV - assembler functions and procedures in pascal.
[1 of 2]
Now that we know just a little bit, let learn through example.
Translation from tpas to asm is not an exact science. There
are several way to do about the same structure as pascal and
it is this reason that ASM procedures can be so efficient. You
can completetly eliminate the legnthy and general machine code
that pascal produces when things like overflow,range checking,
and so forth, are not as important as speeding things up.
For the first example, we are going to write a procedure in
Tpascal that clears the screen in mode $13. We will assume
that we are already in mode $13.
mov ax,13h
int 10h {bios call}
procedure ClearScrn13;
var i,j : word;
begin
for I := 0 to 199 do
For J := 0 to 319 do
mem[$a000:(i*320) + j] := 0;
end;
First off, I assume you know that in ram at $a000:0000 is
were the vga screen memory is stored. I can be thought of
as an array of 64,000 bytes, and you must do the Row_Major
math to access it by Row and Column.
For every row there are 320 bytes, in order to access [2,2]
of a [320,200] array we must pass up 320 bytes in the first row
and and 1 more byte to get to [2,2].
In this case, who cares about rows and colums. We know the
size of the 1 dimesional array so when can just loop 64000 times.
This keeps us from having to do any math - which will slow every-
thing down.
procedure clearScrn13asm;
begin
asm
push es {remeber to store the values of non-general}
push di
mov ax,0a000h
mov es,ax {es := $a000}
xor di,di {di := 0}
mov cx,32000d {cx := 64000 div 2;}
xor ax,ax {ax := 0;}
rep stosW
pop di
pop es
end;
end;
I know, you saying "what the f..?". Remember first we point our
"put" pointer [es:di] to where we are going to store stuff. So what
is "xor di,di"? "Xor" or is "exclusive or". It means either A or B
but not A and B. The truth table is as follows
true xor false = true
false xor true = true
false xor false = false
true xor true = false
in bits
1 xor 0 = 1
0 xor 1 = 1
0 xor 0 = 0
1 xor 1 = 0
So any number xor'd it self is zero. For example, 48 decimal is 30
hexidecimal. In binary 30 is 00110000. Now if you xor each
individual bit by using the table above you get
0 0 1 1 0 0 0 0 |
xor 0 0 1 1 0 0 0 0 |
------------------- v
= 0 0 0 0 0 0 0 0
For each column use the table. From left to right 0 xor 0 is 0,
0 xor 0 is 0, 1 xor 1 is 0 and so forth.
"Why not mov di,0 ? or mov ax,0 ?"
Code size. Mov di,0 will produce 3 bytes of code and "xor di,di"
should produce 1 byte of code. For more information, get the
opcode list from "ftp.intel.com". It list all possible and valid
instructions.
"Why is is mov cx,32000 and not mov cx,64000?"
Well If you look at the repeated instruction, is will move
a word at a time, and a word is two bytes. So moving 32000
words is the same as moving 64000 bytes but just much
quicker.
Remeber the "REP stosW" will automatically mov ax to es:di
and increment di and decrement cx until repeated 32000 times.
Know lets use an example that won't let us use the repeat prefix.
Lets mov a virtual screen to the physical screen.
type V_scrn : array[0..319,0..199] of byte;
var V_P : ^V_scrn;
procedure Paste_scrn( P : V_P );
var i,j : word;
begin
for I := 0 to 199 do
For J := 0 to 319 do
mem[$a000:(i*320) + j] := V^[j,i];; {or ist ^V[j,i]?}
end;
part IV - assembler functions and procedures in pascal.
[2 of 2]
procedure Paste_scrnASM( P : V_P );
begin
asm
push es
push di
push ds
push si
{: Setup or Get and Put pointers :}
{get}
mov ax,word ptr P[2] {ds:si -> V_screen }
mov ds,ax
mov si,word ptr P
{put}
mov ax,0a000h {es:di -> screen}
mov es,ax
xor di,di
mov cx,32000d { for I := 1 to 32000 do begin }
@looper:
lodsW { ax := -> get } { inc si }
stosW { put := ax } { inc di }
loop @looper { end; } { dec CX }
pop si
pop ds
pop di
pop es
end;
end;
OK lets start with "P[2]" a Pointer type is 4 bytes in legnth.
The first 2 bytes are the offset that it points to and the
second 2 bytes are the segment that it point to.
The "[]" symbols also mean indexing - much like an 1 dimensional
array in pascal. Seeing that the Segment is 2 bytes passed the
begining of the pointer, we tell th copmiler that we are talking
about the word 2 bytes passed the begining of the 4 byte pointer.
"word ptr?"
If we didn't tell the copmiler that we want that this is a word
and it an effective address and not a varialbe, we'd have a
problem. We can't use the Offset and Seg key words; becuase, we
we want the value of the of the pointer and not its location.
Pascal takes all the parameters of the procedure and
pushes them on the stack write before a call to the procedure.
In a procedure when you use one of those variables you are actually
using a values that is on the stack. When you use the "VAR" keyword
is pushes the address of the variable on the stack, and therefore
any changes made to that variable are actually chaning the value
of the original variable. Otherwise, is just pushes the value of
the variable on the stack and any changes to that value are made
only in the stack and are thrown away after completion.
example
Procedure test(VAR X : byte; Y,Z : byte);
begin
end;
a:= 1;
b:= 2;
c:= 3;
When you call test(a,b,c);
It pushed all the paramters starting backwards with C
STACK
SP -> [ addr(A) ] a
[ 2 ] b
[ 3 ] c
to move C's value into AX you could say
mov ax,word ptr Z
to move B's value into AX you could say
mov ax,word ptr Y
to move A's value into AX you could say
mov ax,word ptr X[2]
mov ds,ax
mov si,word ptr X {[ds:si] -> A}
lodsB {ax := [ds:si] }
because the value of A is not on the stack, but A's address is.
!Back to the code!
Next es:di points to the vga memory in ram.
This...
mov cx,32000d { for I := 1 to 32000 do begin }
@looper:
lodsW { ax := -> get } { inc si }
stosW { put := ax } { inc di }
loop @looper { end; } { dec CX }
sets up our loop counter CX
lodsW gets from out virtual screen the first word and increments si 2
bytes [word size in bytes]
AX holds the word
stosW takes the word in AX and puts it to the screen and increments
di 2 bytes.
Loop decrements CX and compares it to zero, if its not equal to zero
it jumps to @Looper [this changes the values of CS:IP].
You get all that done with just a tinty bit of speedy code.
I didn't get to functions this time, but in part V I'll get to functions
and how to acccess pascal variables like a string.
As always, I'll be glad to answer any questions. Just one warning,_all
the code in these section have _NOT_ been compiled and are sure to have
errors. If you find these errors then maybe these lessons are too simple
for you and you may be ready to start learning from an intermediate to
advanced asm book. However, I'll try to be as unassuming as possible,
but if I loose you on some concept, just mail me.
Later
**%CpC%**
[Back to FAQ SWAG index] [Back to Main SWAG index] [Original]