4.2 Some Additional Instructions: INTMUL, BOUND, INTO


4.2 Some Additional Instructions: INTMUL, BOUND, INTO

This chapter introduces arrays and other concepts that will require the expansion of your 80x86 instruction set knowledge. In particular, you will need to learn how to multiply two values; hence the first instruction we will look at is the intmul (integer multiply) instruction. Another common task when accessing arrays is to check to see if an array index is within bounds. The 80x86 bounds instruction provides a convenient way to check a register's value to see if it is within some range. Finally, the into (interrupt on overflow) instruction provides a quick check for signed arithmetic overflow. Although into isn't really necessary for array (or other data type access), its function is very similar to bound, hence the presentation at this point.

The intmul instruction takes one of the following forms:

      // The following compute destreg = destreg * constant      intmul( constant, destreg16 );      intmul( constant, destreg32 );      // The following compute dest = src * constant      intmul( constant, srcreg16, destreg16 );      intmul( constant, srcmem16, destreg16 );      intmul( constant, srcreg32, destreg32 );      intmul( constant, srcmem32, destreg32 );      // The following compute dest = dest * src      intmul( srcreg16, destreg16 );      intmul( srcmem16, destreg16 );      intmul( srcreg32, destreg32 );      intmul( srcmem32, destreg32 ); 

Note that the syntax of the intmul instruction is different than the add and sub instructions. In particular, note that the destination operand must be a register (add and sub both allow a memory operand as a destination). Also note that intmul allows three operands when the first operand is a constant. Another important difference is that the intmul instruction only allows 16-bit and 32-bit operands; it does not multiply 8-bit operands.

intmul computes the product of its specified operands and stores the result into the destination register. If an overflow occurs (which is always a signed overflow, because intmul only multiplies signed integer values), then this instruction sets both the carry and overflow flags. intmul leaves the other condition code flags undefined (so, for example, you cannot check the sign flag or the zero flag after intmul and expect them to tell you anything about the intmul operation).

The bound instruction checks a 16-bit or 32-bit register to see if it is between one of two values. If the value is outside this range, the program raises an exception and aborts. This instruction is particularly useful for checking to see if an array index is within a given range. The bound instruction takes one of the following forms:

      bound( reg16, LBconstant, UBconstant );      bound( reg32, LBconstant, UBconstant );      bound( reg16, Mem16[2] );[1]      bound( reg16, Mem32[2] );[2] 

The bound instruction compares its register operand against an unsigned lower bound value and an unsigned upper bound value to ensure that the register is in the range:

 lower_bound <= register <= upper_bound 

The form of the bound instruction with three operands compares the register against the second and third parameters (the lower bound and upper bound, respectively).[3] The bound instruction with two operands checks the register against one of the following ranges:

                Mem16[0] <= register16 <= Mem16[2]                Mem32[0] <= register32 <= Mem32[4] 

If the specified register is not within the given range, then the 80x86 raises an exception. You can trap this exception using the HLA try..endtry exception handling statement. The excepts.hhf header file defines an exception, ex.BoundInstr, specifically for this purpose. The program in Listing 4-1 demonstrates how to use the bound instruction to check some user input.

Listing 4-1: Demonstration of the BOUND Instruction.

start example
 program BoundDemo; #include( "stdlib.hhf" ); static      InputValue:int32;      GoodInput:boolean; begin BoundDemo; // Repeat until the user enters a good value: repeat      // Assume the user enters a bad value.      mov( false, GoodInput );      // Catch bad numeric input via the try..endtry statement.      try           stdout.put( "Enter an integer between 1 and 10: " );           stdin.flushInput();           stdin.get.geti32();           mov( eax, InputValue );           // Use the BOUND instruction to verify that the           // value is in the range 1..10.           bound( eax, 1, 10 );           // If we get to this point, the value was in the           // range 1..10, so set the boolean "GoodInput"           // flag to true so we can exit the loop.           mov( true, GoodInput );           // Handle inputs that are not legal integers.        exception( ex.ConversionError )           stdout.put( "Illegal numeric format, reenter", nl );           // Handle integer inputs that don't fit into an int32.        exception( ex.ValueOutOfRange )           stdout.put( "Value is *way* too big, reenter", nl );           // Handle values outside the range 1..10 (BOUND instruction)        /*        exception( ex.BoundInstr )           stdout.put           (               "Value was ",               InputValue,               ", it must be between 1 and 10, reenter",               nl           );         */      endtry;    until( GoodInput );    stdout.put( "The value you entered, ", InputValue, " is valid.", nl ); end BoundDemo; 
end example

The into instruction, like bound, also generates an exception under certain conditions. Specifically, into generates an exception if the overflow flag is set. Normally, you would use into immediately after a signed arithmetic operation (e.g., intmul) to see if an overflow occurs. If the overflow flag is not set, the system ignores the into instruction; however, if the overflow flag is set, then the into instruction raises the HLA ex.IntoInstr exception. The program in Listing 4-2 demonstrates the use of the into instruction.

Listing 4-2: Demonstration of the INTO Instruction.

start example
 program INTOdemo; #include( "stdlib.hhf" ); static      LOperand:int8;      ResultOp:int8; begin INTOdemo;      // The following try..endtry checks for bad numeric      // input and handles the integer overflow check:      try           // Get the first of two operands:           stdout.put( "Enter a small integer value (-128..+127):" );           stdin.geti8();           mov( al, LOperand );           // Get the second operand:           stdout.put( "Enter a second small integer value (-128..+127):" );           stdin.geti8();           // Produce their sum and check for overflow:           add( LOperand, al );           into();           // Display the sum:           stdout.put( "The eight-bit sum is ", (type int8 al), nl );           // Handle bad input here:         exception( ex.ConversionError )           stdout.put( "You entered illegal characters in the number", nl );           // Handle values that don't fit in a byte here:         exception( ex.ValueOutOfRange )           stdout.put( "The value must be in the range -128..+127", nl );           // Handle integer overflow here:         /*         exception( ex.IntoInstr )           stdout.put           (                "The sum of the two values is outside the range -128..+127",                nl           );          */      endtry; end INTOdemo; 
end example

[1]The "[2]" suggests that this variable must be an array of two consecutive word values in memory.

[2]Likewise, this memory operand must be two consecutive dwords in memory.

[3]This form isn't a true 80x86 instruction. HLA converts this form of the bound instruction to the two-operand form by creating two readonly memory variables initialized with the specified constants.




The Art of Assembly Language
The Art of Assembly Language
ISBN: 1593272073
EAN: 2147483647
Year: 2005
Pages: 246
Authors: Randall Hyde

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net