Registers are a special working area within the processor. Registers are faster than memory operands, and are designed to work with the processor's opcodes.
Registers in an Intel or compatible processor are a very limited resource when writing assembler. In essence, there are eight general-purpose registers, EAX, EBX, ECX, EDX, ESI, EDI, ESP, and EBP. In most instances, ESP and EBP should remain unused as PowerBASIC uses them for entry and exit of procedures.
This means that you have six 32-bit registers to use in your assembly code, plus any other memory locations that are useful in the procedure. ESI and EDI can be used in the normal manner in most instances but neither can be accessed at a Byte level. You can read the low WORD of ESI as SI and the low WORD of EDI as DI.
Understanding the size of registers and the data that you can place in them is very important when using assembler. A 32-bit Intel or compatible processor has three native data sizes that can be used by the normal integral instructions, BYTE, WORD, and DWORD corresponding to 8-bit, 16-bit and 32-bit.
This can be shown in HEX notation.
BYTE 00
WORD 00 00
DWORD 00 00 00 00
In terms of registers, this corresponds to the three sizes that can be addressed with the normal integral registers. Intel and compatible processors are backwards compatible with older code that uses 8 and 16-bit registers, and it is done by accessing any of the general purpose registers in three different ways. Using the EAX register as an example:
AL or AH = 8 bit
AX = 16 bit
EAX = 32 bit
This is the schematic of a general purpose 32-bit register:
This schematic is easier to understand at a bit level. Reading from the right side, you have 32 bits in the register, bits 0 to 31. Because of the bit positions for each piece of data that can be accessed in a 32-bit register, AL is called the Low (low-order) byte, AH is called the High (high-order) byte and AX is called the Low word.
To read the first BYTE in the register (bits 0 to 7) you use:
! MOV byteval, AL ; Copy the low-order byte into variable
Likewise, to read the second byte in the register (bits 8 to 15) you use:
! MOV byteval, AH ; Copy the high-order byte into bytevar
If you want to read the first WORD in the register (bits 0 to 15) you use:
! MOV wordval, AX ; Copy the low-order Word into a variable.
To get at bits 16 to 31, you must rotate the bits in the register so they can be accessed by the previous instructions. Rotating a 32-bit register in either direction by 16 bits move the low-order 16-bits into the high-order 16-bit positions, and the high-order 16 bits into the low-order 16-bit positions of the register.
! ROL EAX, 16 ; Rotate EAX left by 16-bits
…or:
! ROR EAX, 16 ; Rotate EAX right by 16-bits
You cannot put a different size piece of data into a register than its correct size and you cannot mix different register sizes:
! MOV EAX, CL ; This fails as EAX is 32-bit, CL 8-bit
If you need to put the value in CL into a 32-bit register, you must first convert it using one of a number of different techniques:
! MOVZX EAX, CL ; Zero extend unsigned Integer
! MOVSX EAX, CL ; Sign extend signed Integer
In some instances you can use:
! XOR EAX, EAX ; Clear EAX
! MOV AL, CL ; Copy CL into AL
In addition, there are also some "older" mnemonics that will do the conversions too:.
! MOV AL, CL ; Copy CL into AL
! CBW ; Convert Byte in AL to Word in AX
! CWDE ; Convert Word in AX to DWORD in EAX
See Also
Saving Registers at the Sub/Function level
Tricks in preserving registers