• No results found

String Instructions

LODSW STOSB,

STOSW

Note that Windows 3.x and 95 applications still have a PSP. The value in the location pointed to by DS:SI is loaded into AL or AX. SI is automatically incremented (+/-1 if LODSB, or +/-2 if LODSW).

The value in AL or AX is stored at the location pointed to by ES:DI. is automatically incremented (+/-1 if STOSB, or +/-2 if STOSW).

STOS and LODS are most useful for video access, as the format of video-RAM in text-mode requires every odd byte to be an attribute character: setup ES:DI.... . . . setup DS:SI.... c x , s t r i n g l e n g t h mov n e x t c h a r : s t o s w l o o p n e x t c h a r t h i s c o d e w i l l s e n d c h a r a c t e r s t o t h e s c r e e n

Arithmetic Instructions

PREREQUISITES

These include addition, subtraction, multiplication, and division. I expect you to have a working knowledge of principles of binary arithmetic: unsigned binary numbers,

2's complement binary numbers, radix conversion among hex/binary/decimal. For example, suppose I ask you to express -2 as a 32-bit binary number, and also as a

32-bit hexadecimal number. Can you do it? If the answer is yes, then you do have a

few clues, so read on. Otherwise look back at Chapter 1, and consolidate with further study if required.

The CMP instruction has already been introduced but involves instruction arithmetic comparisons, so it will be considered again here.

The example below subtracts 127 from AL, and the result sets the appropriate flags. Decimal is the default with an assembler, unless an is appended to designate hex. DEBUG can only have hex. We will treat 127 as being decimal in this case.

al, 127 s u b t r a c t .

The CMP instruction can be followed by a conditional jump that jumps or doesn’t jump depending upon the flags.

Although CMP subtracts the two values, it is only done hypothetically, and the two operands are left unchanged. CMP doesn’t care whether the number is unsigned or 2’s complement it just subtracts them. It is the same for all the addition/subtraction arithmetic instructions it is up to the programmer to decide how to treat the operands and the result.

This point can be clarified. Since the above example is dealing c o m p l e m e n t with S-bit operands, the range of values depends upon whether we versus are treating them as 2’s complement or unsigned number:

u n s i g n e d

Unsigned : 0 255 o r 00 FF in Hex.

compl: -128 o r 80 7F in Hex.

So if AL = 128, the example CMP instruction will give a hypothetical result

128 127 = 1, i.e., the result is or in binary 00000001.

Obviously AL is greater than 127, but that is only if you treat the numbers as unsigned. As a 2’s complement number, 128 is actually

Unsigned or in Hex.

compl: or in Hex.

So from a point of view, AL is less than the

operand 127. That is why there are different conditional jump instructions for signed and unsigned numbers.

Following the we could have any one of the

following, depending upon how we want to treat the number:

J A l a b e l if AL above 127, unsigned.

JB label ii AL below 127, unsigned. JG label jump if AL greater than 127, signed.

JL label jump if AL less than 127, signed.

This can be a point of confusion for novice programmers, so be careful. It is a good policy to stick with unsigned compares, unless you have particular reason to do otherwise.

N E G This is strictly for 2’s complement numbers it changes the sign of an operand. For this example, the result will be -127 in AL:

mov neg al mov al,-127

A useful point to note about the assembler is that you don’t ever have to calculate the binary or hex negative 2’s complement number; just put a minus sign in front and the assembler will do the conversion. The last line shows this.

D E C These two do what their names

i n s t r u c t i o n s suggest; add 1 to an operand or subtract 1 from it.

Since we have specified an 8-bit operand in the examples below, if INC goes beyond 255 (FF hex), then it will simply roll around and start zero. Ditto, but the opposite, for DEC.

inc al dec al

A D D , S U B Recall from the above notes that ADD/SUB arithmetic instructions don’t know whether your operands are 2’s complement or unsigned numbers that interpretation is up to you. The size of the operands are important in these calculations, and the instruction determines that from the operands themselves.

SUB works just like CMP, setting the same flags (and so can be followed by a conditional jump), but the subtraction is not hypothetical the result of the subtraction is left in AX.

add sub

These instructions can handle numbers bigger than 16 bits. Of course so can the 386, since it has 32-bit registers, but for now assume I only have 16-bit registers and I want to add numbers that could possibly have a 32-bit result.

add ;add cx to ax, result in ax. adc bx,dx ;add dx to bx, with carry.

instructions

DAA, DAS

For this example we have two 32-bit values in and DX:CX. The two lower halves are added, leaving the result in AX. The ADD instruction will set the carry flag if the unsigned result is greater than the limit (FFFF hex).

ADC means ADd-with-Carry, and adds the carry flag bit plus DX, to BX, with the result in BX. Thus the total result is in

For subtraction of 32-bit numbers, the principle is the same, and there is an appropriate instruction: SBB with Borrow). For addition and subtraction of BCD numbers, you need to use DAA and DAS.

The operation of DAA (Decimal Adjust for Addition) is shown pictorially in Figure 2.6. It corrects the result of adding two BCD (packed decimal) values. Operates on the AL register. If the rightmost four bits of AL have a value greater than 9 or the half (auxiliary) carry flag is 1, DAA adds 6 to AL and sets the half-carry flag. If AL contains a value greater than 9Fh or the carry flag is adds 60h to AL and sets the carry flag.

Figure 2.6: Decimal arithmetic.

8 5 h e x (these numbers are 50 hex

hex packed BCD) -21 hex (these numbers arepacked BCD)

DAS (Decimal Adjust for Subtraction) is the opposite of

After subtracting two numbers, perform DAS operation on AL. If the rightmost 4 bits have a value greater than 9 or the half-can-y flag is set, DAS subtracts 6 from AL and sets the Carry Flag. There are two groups of multiply and divide; MUL and DIV for unsigned numbers and IMUL and IDIV for signed numbers. One problem we have with multiply is that two 16-bit operands can produce a result up to 32 bits long. Thus in the case of with only 16-bit registers, the result may have to reside in two registers. The MUL instruction uses AL and AX, or AX and DX, by default.

bx

;al*bl ax ;ax*bx dx:ax

The first example makes the assumption that the other operand is in AL, so the result will appear in AX. The second example makes the assumption that the other operand is in AX, and the result will be in

Division has problems of its own. The dividend (the operand to be divided) is in either AX or DX:AX, and the divisor is in any other register or variable (8 or 16 bits).

d i v a h a n d a l .

d i v b x ; d x : a x / b x dx and ax.

The first example assumes the dividend to be in AX and puts the result in AX in this format: AH = remainder (left over), AL = quotient (result).

The second example specifies a 16-bit divisor, which assumes that the dividend is in DX:AX and the result in DX:AX as follows: DX = remainder, AX = quotient.

A feature built into the CPU is that if there is an error in the calculation, a certain interrupt is generated, and DOS displays an appropriate error message. In the case of DIV, it is possible for the quotient to be too big for AL or AX DOS will abort your program with a “division overflow” message.