Registers

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 integer 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 integer 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

The Inline Assembler

Data types in registers

MMX registers

Saving registers

Saving Registers at the Sub/Function level

Tricks in preserving registers

Saving the FPU registers

Using ESP and EBP