MOV* Move String: moves byte, word or double word at DS:SI
CMPS* Compare string: compares byte, word or double word at DS:SI to ES:DImovsb ; move byte movsw ; move word movsd ; move double word
Note: This instruction is normally used with the REP prefix.cmpsb ; compare byte cmpsw ; compare word cmpsd ; compare double word
SCAS* Search string: search for AL, AX, or EAX in string at ES:DI
Note: This instruction is usually used with the REPZ or REPNZ prefix.scasb ; search for AL scasw ; search for AX scasd ; search for EAX
REP Prefix for string instruction repeats instruction CX times
STOS* Move byte, word or double word from AL, AX or EAX to ES:DIrep StringInstruction
LODS* Move byte, word or double word from DS:SI to AL, AX or EAXstosb ; move AL into ES:DI stosw ; move AX into ES:DI stosd ; move EAX into ES:DI
The next example demonstrates how to use these instructions.lodsb ; move ES:DI into AL lodsw ; move ES:DI into AX lodsd ; move ES:DI into EAX
Listing 11: STRINGS.ASM .model small .stack .code mov ax,@data ; ax points to of data segment mov ds,ax ; put it into ds mov es,ax ; put it in es too mov ah,9 ; function 9 - display string mov dx,OFFSET Message1 ; ds:dx points to message int 21h ; call dos function cld ; clear direction flag mov si,OFFSET String1 ; make ds:si point to String1 mov di,OFFSET String2 ; make es:di point to String2 mov cx,18 ; length of strings rep movsb ; copy string1 into string2 mov ah,9 ; function 9 - display string mov dx,OFFSET Message2 ; ds:dx points to message int 21h ; call dos function mov dx,OFFSET String1 ; display String1 int 21h ; call DOS service mov dx,OFFSET Message3 ; ds:dx points to message int 21h ; call dos function mov dx,OFFSET String2 ; display String2 int 21h ; call DOS service mov si,OFFSET Diff1 ; make ds:si point to Diff1 mov di,OFFSET Diff2 ; make es:di point to Diff2 mov cx,39 ; length of strings repz cmpsb ; compare strings jnz Not_Equal ; jump if they are not the same mov ah,9 ; function 9 - display string mov dx,OFFSET Message4 ; ds:dx points to message int 21h ; call dos function jmp Next_Operation Not_Equal: mov ah,9 ; function 9 - display string mov dx,OFFSET Message5 ; ds:dx points to message int 21h ; call dos function Next_Operation: mov di,OFFSET SearchString ; make es:di point to string mov cx,36 ; length of string mov al,'H' ; character to search for repne scasb ; find first match jnz Not_Found mov ah,9 ; function 9 - display string mov dx,OFFSET Message6 ; ds:dx points to message int 21h ; call dos function jmp Lodsb_Example Not_Found: mov ah,9 ; function 9 - display string mov dx,OFFSET Message7 ; ds:dx points to message int 21h ; call dos function Lodsb_Example: mov ah,9 ; function 9 - display string mov dx,OFFSET NewLine ; ds:dx points to message int 21h ; call dos function mov cx,17 ; length of string mov si,OFFSET Message ; DS:SI - address of string xor bh,bh ; video page - 0 mov ah,0Eh ; function 0Eh - write character NextChar: lodsb ; AL = next character in string int 10h ; call BIOS service loop NextChar mov ax,4C00h ; return to DOS int 21h .data CR equ 13 LF equ 10 NewLine db CR,LF,"$" String1 db "This is a string!$" String2 db 18 dup(0) Diff1 db "This string is nearly the same as Diff2$" Diff2 db "This string is nearly the same as Diff1$" Equal1 db "The strings are equal$" Equal2 db "The strings are not equal$" Message db "This is a message" SearchString db "1293ijdkfjiu938uHello983fjkfjsi98934$" Message1 db "Using String instructions example program.$" Message2 db CR,LF,"String1 is now: $" Message3 db CR,LF,"String2 is now: $" Message4 db CR,LF,"Strings are equal!$" Message5 db CR,LF,"Strings are not equal!$" Message6 db CR,LF,"Character was found.$" Message7 db CR,LF,"Character was not found.$" end
Firstly this method simply finds out what the version is.
This function returns the major version number in AL and the minor version number in AH. For example if it was version 4.01, AL would be 4 and AH would be 01. The problem is that if on DOS 5 and highermov ah,30h ; function 30h - get MS-DOS version int 21h ; call DOS function
SETVER can change the version that is returned. The way to get round this is to use this method.
This will only work on DOS version 5 and above so you need to check using the former method. This will return the actual version of DOS even if SETVER has changed the version. This returns the major version in BL and the minor version in BH.mov ah,33h ; function 33h - actual DOS version mov al,06h ; subfunction 06h int 21h ; call interrupt 21h
When TASM (or A86) compiles these lines it translates it into separate pushes an pops. This way just saves you time typing and makes it easier to understand.push ax bx cx dx ; save registers pop dx cx bx ax ; restore registers
Note: To make these lines compile in A86 you need to put commas
(,) in between the registers.
The PUSHA/PUSHAD and POPA/POPAD Instructions
PUSHA is a useful instruction that pushes all general purpose
registers onto the stack. It accomplishes the same as the following:
The main advantage is that it is less typing, a smaller instruction and it is a lot faster. POPA does the reverse and pops these registers off the stack. PUSHAD and POPAD do the same but with the 32-bit registers ESP, EAX, ECX, EDX, EBX, EBP, ESI and EDI.temp = SP push ax push cx push dx push bx push temp push bp push si push di
There are four different ways of shifting numbers either left or right one binary position.
SHL Unsigned multiple by two
SHR Unsigned divide by two
SAR Signed divide by two
SAL same as SHL
The syntax for all four is the same:
Note: The 8086 cannot have the value of opperand2 other than 1. The 286/386 cannot have operand2 higher than 31.SHL operand1,operand2
This is exactly the same as the following piece of code without using loop:mov cx,100 ; 100 times to loop Label: . . . Loop Label: ; decrement CX and loop to Label
Which do you think is easier to understand? Using DEC/JNZ is faster on 486's and above and it is useful as you don't have to use CX.mov cx,100 ; 100 times to loop Label: dec cx ; CX = CX-1 jnz Label ; continue until done
This works because JNZ will jump if the zero flag has not been
set. Setting CX to 0 will set this flag.
How to use a debugger
This is a good time to use a debugger to find out what your program
is actually doing. I am going to demonstrate how to use Turbo
Debugger to check what the program is actually doing. First we
need a program which we can look at.
Now compile it to a .COM file and then type:Listing 12: DEBUG.ASM ; example program to demonstrate how to use a debugger .model tiny .code org 100h start: push ax ; save value of ax push bx ; save value of bx push cx ; save value of cx mov ax,10 ; first parameter is 10 mov bx,20 ; second parameter is 20 mov cx,3 ; third parameter is 3 Call ChangeNumbers pop cx ; restore cx pop bx ; restore bx pop ax ; restore dx mov ax,4C00h ; exit to dos int 21h ChangeNumbers PROC add ax,bx ; adds number in bx to ax mul cx ; multiply ax by cx mov dx,ax ; return answer in dx ret ChangeNumbers ENDP end start
Turbo Debugger then loads. You can see the instructions that make up your program.td name of file
For example the first few lines of this program is shown as:
cs:0000 50 push ax cs:0001 53 push bx cs:0002 51 push cxSome useful keys for Turbo Debugger:
F5 Size Window F7 Next Instruction F9 Run ALT F4 Step BackwardsThe numbers that are moved into the registers are different that the ones that in the source code because they are represented in their hex form (base 16) as this is the easiest base to convert to and from binary and that it is easier to understand than binary also.
At the left of this display there is a box showing the contents of the registers. At this time all the main registers are empty. Now press F7 this means that the first line of the program is run. As the first line pushed the AX register into the stack, you can see that the stack pointer (SP) has changed. Press F7 until the line which contains mov ax,000A is highlighted. Now press it again.
Now if you look at the box which contains the contents of the registers you can see that AX contains A. Press it again and BX now contains 14, press it again and CX contains 3. Now if you press F7 again you can see that AX now contains 1E which is A+14. Press it again and now AX contains 5A, 1E multiplied by 3. Press F7 again and you will see that DX now also contains 5A. Press it three more times and you can see that CX, BX and AX are all set back to their original values of zero.