The 80x86 CPU family provides from just over a hundred to many thousands of different machine instructions, depending on how you define a machine instruction. Even at the low end of the count (greater than 100), it appears as though there are far too many machine instructions to learn in a short time. Fortunately, you don't need to know all the machine instructions. In fact, most assembly language programs probably use around 30 different machine instructions.[6] Indeed, you can certainly write several meaningful programs with only a few machine instructions. The purpose of this section is to provide a small handful of machine instructions so you can start writing simple HLA assembly language programs right away.
Without question, the mov
instruction is the most oft-used assembly language statement. In a typical program, anywhere from 25 percent to 40 percent of the instructions are mov
instructions. As its name suggests, this instruction moves data from one location to another.[7] The HLA syntax for this instruction is:
mov(source_operand
,destination_operand
);
The source_operand
can be a register, a memory variable, or a constant. The destination_operand
may be a register or a memory variable. Technically the 80x86 instruction set does not allow both operands to be memory variables. HLA, however, will automatically translate a mov
instruction with two-word or double-word memory operands into a pair of instructions that will copy the data from one location to another. In a high-level language like Pascal or C/C++, the mov
instruction is roughly equivalent to the following assignment statement:
destination_operand
=source_operand
;
Perhaps the major restriction on the mov
instruction's operands is that they must both be the same size. That is, you can move data between a pair of byte (8-bit) objects, word (16-bit) objects, or double-word (32-bit) objects; you may not, however, mix the sizes of the operands. Table 1-1 lists all the legal combinations for the mov
instruction.
You should study this table carefully because most of the general-purpose 80x86 instructions use this syntax.
Table 1-1. Legal 80x86 mov
Instruction Operands
Destination | |
---|---|
Reg8[a] | Reg8 |
Reg8 | Mem8 |
Mem8 | Reg8 |
Constant[b] | Reg8 |
Constant | Mem8 |
Reg16 | Reg16 |
Reg16 | Mem16 |
Mem16 | Reg16 |
Constant | Reg16 |
Constant | Mem16 |
Reg32 | Reg32 |
Reg32 | Mem32 |
Mem32 | Reg32 |
Constant | Reg32 |
Constant | Mem32 |
[a] The suffix denotes the size of the register or memory location. [b] The constant must be small enough to fit in the specified destination operand. |
The 80x86 add
and sub
instructions let you add and subtract two operands. Their syntax is nearly identical to the mov
instruction:
add(source_operand
,destination_operand
); sub(source_operand
,destination_operand
);
The add
and sub
operands take the same form as the mov
instruction.[8] The add
instruction does the following:
destination_operand
=destination_operand
+source_operand
;destination_operand
+=source_operand
; // For those who prefer C syntax.
The sub
instruction does the calculation:
destination_operand
=destination_operand
-source_operand
;destination_operand
-=source_operand
; // For C fans.
With nothing more than these three instructions, plus the HLA control structures that the next section discusses, you can actually write some sophisticated programs. Example 1-3 provides a sample HLA program that demonstrates these three instructions.
Example 1-3. Demonstration of the mov
, add
, and sub
instructions
program DemoMOVaddSUB; #include( "stdlib.hhf" ) static i8: int8 := −8; i16: int16 := −16; i32: int32 := −32; begin DemoMOVaddSUB; // First, print the initial values // of our variables. stdout.put ( nl, "Initialized values: i8=", i8, ", i16=", i16, ", i32=", i32, nl ); // Compute the absolute value of the // three different variables and // print the result. // Note: Because all the numbers are // negative, we have to negate them. // Using only the mov, add, and sub // instructions, we can negate a value // by subtracting it from zero. mov( 0, al ); // Compute i8 := -i8; sub( i8, al ); mov( al, i8 ); mov( 0, ax ); // Compute i16 := -i16; sub( i16, ax ); mov( ax, i16 ); mov( 0, eax ); // Compute i32 := -i32; sub( i32, eax ); mov( eax, i32 ); // Display the absolute values: stdout.put ( nl, "After negation: i8=", i8, ", i16=", i16, ", i32=", i32, nl ); // Demonstrate add and constant-to-memory // operations: add( 32323200, i32 ); stdout.put( nl, "After add: i32=", i32, nl ); end DemoMOVaddSUB;
[6] Different programs may use a different set of 30 instructions, but few programs use more than 30 distinct instructions.
[7] Technically, mov
actually copies data from one location to another. It does not destroy the original data in the source operand. Perhaps a better name for this instruction would have been copy
. Alas, it's too late to change it now.
[8] Remember, though, that add
and sub
do not support memory-to-memory operations.