Download as pdf or txt
Download as pdf or txt
You are on page 1of 10

Flags

ZF: Zero Flag, TRUE if the result of the previous operation was 0. CF: Carry Flag, stores the value of the carry (or borrow in case of subtraction) from the last executed operation. PF: Parity Flag AF: Auxiliary Flag, used for Binary Coded Decimal operations SF: Sign Flag, is in reality just a replica of the MSB of the result. It really represents the sign only for 2s complement operations. TF: Trap Flag, used to generate a Trap after each instruction, when debugging the program. IF: Interrupt Enable Flag DF: Direction Flag, useful for string operations OF: Overow Flag

Addressing Modes errors


Register addressing mode:
1 2

mov AX , BL mov AH , BX

; error ( compiler can t decide if it has to store in AH or AL ) ; error ( obviously )

Constant addressing mode:


1 2

mov BL , 5678900 mov 0 , AH

; error ( constant too big for the register ) ; error ( can t write to a constant ) .

Remember that AH is the register, while 0AH is the hexadecimal number. Direct addressing mode:
1 2 3 4 5

MOV CX , PIPPO +3 ; address of PIPPO increased by 3 then go to memory. ; NOT content of PIPPO + 3 in CX. ( compile time ) ; this is done by the following MOV CX , PIPPO ADD CX , 3

Indirect addressing mode Oset Register BX BP SI DI Otherwise:


1

Default Segment Register DS SS DS DS

VECT SS :[ BX ]

1 2 3 4 5 6 7 8 9 10 11

VETT DW . . . MOV AX , MOV AX , MOV AX , MOV AX ,

1000 DUP ? VETT +3[ BX ][ SI ] 3[ BX ][ SI ] VETT [ BX +3] VETT [ BX + SI ] ; dangerous for overflow ; bad programming. ; Ok , and equivalent to MOV AX , VETT +3[ BX ] ; Ok , and equivalent to MOV AX , VETT [ BX ][ SI ] ; no type definition ; correct version ! ; LSByte of VETT copied into AL ( little endian ) .

INC [ BX ] INC BYTE PTR [ BX ] MOV AL , BYTE PTR VETT

Double Square Brackets


1

MAT [ BX ] [ SI ] ; Address_ { MAT } + Contents_ { BX } + Contents_ { SI }

LEA versus OFFSET


1 2 3 4 5 6 7 8

LEA SI , VAR MOV SI , OFFSET VAR

; Load Effective Address of VAR into SI. ( run time ) . ; When the address is constant ( known at compile time ) we can transform it ; into a CONSTANT MOV instruction , using OFFSET. ; However , the LEA also works with this. ; With OFFSET we have to do the following :

LEA SI , VAR [ BX ] MOV SI , OFFSET VAR ADD SI , BX

Note that PUSH OFFSET VAR is not allowed. You rst need to store the address in some register. To pass an array to a procedure, we can LEA into SI and then push it into the stack.

JMP Instruction
If the jump is conditional, only the constant addressing mode is allowed. (only labels). Relative jumps are 8bits operations. The target for the jump can be anywhere between -128 and +127 addresses from the current one. Absolute jump is 16 bits long. All conditional jumps in the 8086 are relative. For non-conditional, there are 2 forms. Absolute: JMP <16bits target>, Relative: JMP SHORT <8bits target> If statement and jump platform If one branch is longer and the other is short, put the smaller section rst to exploit the unconditional JMP, which is 16 bits, to jump over the longer block. If both blocks are big, we can use a platform, that is to say a place to temporary jump, to perform a bigger jmp.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17

CMP AX , BX ; if AX != BX JZ aux ... < first 100 bytes > ... JMP continue ; we don t want to jump on the platform from this block aux : JMP axeqbx ; longer 16 bits jump continue : ... < remaining 900 bytes of the block > ... JMP join axeqbx : <" else " block > ; i am here because AX = BX ... join : ... < rest of program >

Common erros with jump and addressing modes:


1 2 3 4 5

JMP [ BX ]

; uses the content of the memory location pointed by BX , ; as a target address. ; uses the content of BX as a target address. ; It can , because it is unco nditiona l.

JMP BX

Change segment with JMP:


1 2 3 4 5 6 7 8 9 10 11

SEGMENT_B DD ? ... MOV MOV LEA JMP

WORD PTR SEGMENT_B +2 , 1234 h ; little endian WORD PTR SEGMENT_B , 0000 h BX , SEGMENT_B DWORD PTR [ BX ] ; take the content of " segment_b " and ; use it as target for the jump , ; knowing that it is 32 bits and the ; most significant 16 are CS , ; the least 16 are IP

The LOOP instruction


Using separate counter and pointer:
1 2 3 4 5 6 7 8

ARRAY2 DW N DUP (?) .... MOV CX , N XOR BX , BX CYC_2 : MOV ARRAY2 [ BX ] , 0 INC BX ; increment by two because the array is of words INC BX LOOP CYC_2

Initialize CX or check its value with an if, then, else block before entering the loop. Nested Loops:
1 2 3 4 5 6 7 8 9 10 11

MOV CX , N L1 : < first instructions of the outer loop > PUSH CX MOV CX , M L2 : < instructions of the inner loop > LOOP L2 < last instructions of the outer loop > POP CX LOOP L1

Or use DI and SI with CMP and JMP.

The ADD and SUB instructions


Overow is detected with the carry ag (CF) for unsigned, and with the overow ag (OF) for twos complement. For unsigned subtraction, no borrow ag is present. This role is taken by the carry ag again. Adding 32bit data
1 2 3 4 5 6 7 8

PUSHA MOV AX , WORD MOV BX , WORD ADD AX , WORD ADC BX , WORD MOV WORD PTR MOV WORD PTR POPA

PTR VAR1 PTR VAR1 + 2 PTR VAR2 PTR VAR2 +2 SUM , AX SUM + 2 , BX

; add " LSW " ; add " MSW "

The SBB is the equivalent for the subtraction. It subtracts 1 from the result if the carry ag is set. The CBW instruction and CWD How to implement AX <= AX + BL? ADD AX, BL doesnt work. So possible solutions are:
1 2

CBW ADD BX , AX

Important: only usable for 2s complement number (not unsigned), and the implicit operand is AL. For unsigned use XOR AH, AH. CWD is the same but extends the sign of AX in DX::AX.

MUL and IMUL instruction


MUL <8bitop> does AL*operand and saves in AX. MUL <16bitop> does AX*operand and saves in DX::AX. 32x32 multiplication We perform SI::DI x BX::BP. (A1 216 + A0) (B 1 216 + B 0) = A1 B 1 232 + (A1 B 0 + A0 B 1) 216 + A0 B 0 20

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32

.data result db 8 dup (?) ... .code .startup ... push ax push dx mov ax , di mul bp mov word ptr result , ax mov word ptr result +2 , dx mov ax , si mul bp add ax , word ptr result +2 adc dx , 0 mov word ptr result +2 , ax mov word ptr result +4 , dx mov ax , di mul bx add ax , word ptr result +2 adc dx , word ptr result +4 mov word ptr result +2 , ax mov word ptr result +4 , dx mov ax , si mul bx add ax , word ptr result +4 adx dx ,0 mov word ptr result +4 , ax mov word ptr result +6 , dx pop dx pop ax

; A0 * B0 ; save result s least significant word ; temporarily store the other part of the result ; A1 * B0 ; inc DX in case of carry in the previous add ; temporarily store the result

; A0 * B1

; save result s second - least sign. word ; temporarily store the other part of the result ; A1 * B1

DIV and IDIV instruction


Supported data types are: 16 bits/ 8bits: (e.g. DIV BL), AX is implicitly the dividend. After division, AL will hold the quotient, AH will hold the residual. 32 bits/ 16bits: (eg. DIV CX), DX, AX contain the dividend. After division, AX stores the quotient, DX the residual. Problem: AL is not always sucient to store the quotient. Can generate exception. Solution: extend the division to 32 to 16 (putting 0 or extend sign with CWD). For signed division, remember: 32768 = 32768. We need a 17 bits result. 1 Extend sign of divisor
1 2 3 4 5 6 7 8

PUSH AX MOV AL , CBW MOV BX , POP AX CWD DIV BX

; save AX BL ; extend sign AX ; copy back ; extend sign of dividend

Binary to decimal conversion


1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16

.data decimal 5 dup (?) ... ; AX contains the binary number to convert mov cx , 10 mov bx ,5 -1 div_loop : xor dx , dx div cx mov decimal [ bx ] , dl dec bx , cmp ax , 0 jne div_loop ; divisor ; least significant digit is stored in last position of the array ; kind of big endian , but it can be easily done the opposite way. ; extension of division to 32 to16 bits ; the remainder is >0 and <10 , so it is completely contained in DL

Shift Overow
In binary, to check the overow we simply have to check the carry ag. On the contrary, in twos complement, the shift of 01000000B produces 10000000B, which is negative, so we had an overow. To detect it, we have to compare the carry ag and the sign ag. On the other side, division through shifting will produce always a positive residual. Multiplication through shift, Approach 1 To perform Ax57, rst you convert the 57 in binary, obtaining 111001B. The algorithm is the following: A (1110012 ) = A (12 + 10002 + 100002 + 1000002 ) = A + 8A + 16A + 32A. So it is a sum of A shifted 0 times, plus A shifted 3 times, plus A shifted 4 times, plus A shifted 5 times.
1 2 3 4 5 6 7 8 9

mov shl shl shl add shl add shl add

bx , ax , ax , ax , bx , ax , bx , ax , bx ,

ax 1 1 1 ax 1 ax 1 ax

Clearly the result is (A 57)mod(216 (you can have overow). Multiplication through shift, Approach 2 If for example you want to perform A 57, rst you convert the 57 in binary, obtaining 111001B. Then we note that: A (1110012 ) = (A (1112 )) 10002 + A 1. This allows us to use the following algorithm: mov shl add shl add shl shl shl add bx, bx, bx, bx, bx, bx, bx, bx, bx, ax 1 ax 1 ax 1 1 1 ax

Rotate instruction
Mean of 2 numbers, rst approach: sum rst. This solution is very compact, but it is tough to be extended for signed numbers.
1 2 3

mov cx , ax add cx , bx rcr cx , 1

Mean of 2 numbers, second approach: division rst.


1 2 3 4 5 6 7 8 9 10 11 12 13 14 15

push dx push ax xor mov shr adc shr adc shr add add dx , cx , ax , dx , cx , dx , dx , cx , cx , dx bx 1 ; 0 ; 1 ; 0 ; 1 ; ax dx ; dx used to store the residuals of the division ax if cx if dx = ax /2 residual ( in CF ) then dx +=1 = original_bx /2 residual dx +=1 = dx /2

pop ax pop dx

This works because we can write a division as RB QA + QB + RA + 2 Mean of 4 numbers: division rst.

X Y

= Q+

R Y .

So in our case:

A+B 2

A 2

B 2

= QA +

RA 2

+ QB +

RB 2

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23

pusha xor dx , dx shr adc shr adc shr adc shr adc ax , dx , bx , dx , si , dx , di , dx , 1 0 1 0 1 0 1 0

shr dx , 1 mov add add add add shr popa


(A+B+C+D)

cx , cx , cx , cx , cx , cx ,

ax bx di si dx 1

C +D The approach here is to perform the mean of four numbers as: A+B + = 2 2 2 2 2 . The numerator can be 4 obtained in a similar way as in the previous solution. We divide all the variables and sum the residuals in DX. Then we divide DX as well, and sum everything together to obtain the result.

Mean of 4 numbers: division rst.


1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20

pusha xor dx , dx mov cx , ax add cx , bx adc dx , 0 add cx , si adc dx , 0 add cx , di adc dx , 0 shr rcr shr rcr popa dx , cx , dx , cx , 1 1 1 1

What we do here is to perform the addition as if it was on 32 bits. Clearly, since the addition of two 16 numbers requires 17 bits, the addition of four numbers requires 18. Thus, at the end of the algorithm, we obtain the result in CX by means of an ideal shift right by two positions of the DX::CX 32bits register. Rounding of 2 numbers: addition rst
1 2 3 4 5

mov cx , ax add cx , bx rcr cx , 1 ; identical to the " FLOORING " performed before up to this point adc cx , 0

Rounding of 2 numbers: division rst


1 2 3 4 5

mov shr adc rcr adc

cx , cx , bx , bx , cx ,

ax 1 0 1 bx

This last example needs a little more explanation. We use the rule of the integer division which we have seen in the rst, RA B exercise, but with a variation: A+ = QA + B + . In fact we add the rst residual to bx. Also, if this rst residual is 2 2 1, the subsequent addition can cause an overow (if ax is 1....111). So we use a rotate right for the second division, instead of a simple shift. 6

Passing parameters to procedures


1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32

; MAIN ; in the main we need to add BP and SI ; and save the result in DI. PUSH BP PUSH SI CALL ADDITION POP DI POP DI ... ; PROCEDURE ADDITION PROC PUSH BP MOV BP , SP PUSHA

; ; ; ; ; ;

BP will be always pushed by procedures. Then we make a copy of stack pointer into BP push all the registers i will use , can also use individual pushes. up to this instruction , the code is general for all procedures.

MOV AX , SS :[ BP +4]

; remember that BP by default uses SS as segment register ; to compute the effective address. So the SS : is not needed ; we write it here for clarity.

MOV BX , SS :[ BP +6] ADD AX , BX MOV SS :[ BP +6] , AX POPA POP BP RET ADDITION ENDP

Remember NEAR and FAR dierence. Usually it is NEAR in our programs. For the RETURN parameter, remember to balance the stack with pops.

DOS Interrupts
AH = 01h - READ CHARACTER FROM STANDARD INPUT, WITH ECHO Return: AL = character read AH = 02h -WRITE CHARACTER TO STANDARD OUTPUT Entry: DL = character to write Return: AL = last character output (same value put in DL before, basically). AH = 09h - WRITE STRING TO STANDARD OUTPUT Entry: DS:DX - address of a $-terminated string Return: AL = 24h AH = 0Ah - BUFFERED INPUT Entry: DS:DX - buer (see below) Return: buer lled with user input Format of DOS input buer: Offset 00 01 02 Size 1 1 n Description maximum characters buffer can hold number of chars from last input which may be recalled OR number of characters actually read, excluding CR actual characters read, including the final carriage return

Macros
1 2 3 4 5 6 7 8 9

SCANM macro column , lenght ; Push parameters lea si , column push si mov si , lenght push si ; Call procedure

10 11 12 13 14 15 16 17

call SCAN ; Pops to balance the stack pop si pop si ; Last pop contains the return value. endm

The macro has to be put inside the .code segment (before .startup).

Selection Sort
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19

xor di , di l1 : cmp jae mov mov mov l2 : inc cmp jae

; use di such as first index

di , N_MAX out al , BUFF [ di ] pos_min , di si , di si ; use si as second index si , N_MAX end_l1

20 21 22 23 24 25 26 27 28 29 30

cmp al , BUFF [ si ] ; test what we want jb l2 mov pos_min , si mov al , BUFF [ si ] ; find the value that satisfies our condiction and exchange it with the value pointed by di jmp l2 end_l1 : mov si , pos_min ; exchange procedure mov dl , BUFF [ di ] mov BUFF [ si ] , dl mov BUFF [ di ] , al inc di jmp l1 out :

Print number (stored in a word) procedure, any number of digits


1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29

PRINTNUM proc push bp mov bp , sp push push push push ax bx cx dx

mov ax , [ bp +4] mov bl , 10 xor cx , cx deco mpose_lo op : div bl ; quotient in al , residual in ah push ax inc cx ; counts the digits xor ah , ah cmp al , 0 jne decompo se_loop mov ah , 02 h print_loop : pop bx mov dl , bh ; move residual in AL. add dl , 0 int 21 h loop print_loop

30 31 32 33 34 35 36

pop dx pop cx pop bx pop ax pop bp ret PRINTNUM endp

Convert a buer (with DOS format) into an unsigned number


1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38

STR2NUM proc push bp mov bp , sp push push push push push ax bx cx dx di

mov bx ,[ bp +4] inc bx mov cl , byte ptr [ bx ] ; length of the string xor ch , ch inc bx ; to point at the first digit xor dh , dh xor ax , ax ; clear accumulator mov di , 10 ; multiplier factor str2num_loop : mul di ; result in dx , ax , but works only if contained ; in AX completely. mov dl , [ bx ] sub dl , 0 add ax , dx inc bx loop str2num_loop mov [ bp +4] , ax ; save result pop pop pop pop pop pop di dx cx bx ax bp

ret STR2NUM endp

Puts, Gets and Newline Macros


1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25

PUTS macro str push ax push dx lea dx , str mov ah , 09 h int 21 h pop dx pop ax endm GETS macro buff push ax push dx lea dx , buff mov ah , 0 Ah int 21 h pop dx pop ax endm

; remember that str must terminate with a dollar sign

NEWLINE macro push ax push dx mov ah , 02 h mov dl , 0 AH ; ( LF )

26 27 28 29 30 31

int mov int pop pop endm

21 h dl , 0 DH ; ( CR ) 21 h dx ax

ASCII table

10

You might also like