6 OPERANDS AND EXPRESSIONS

This chapter contains the following sections:

Operands
Operands and Addressing Modes
Indirect Addressing
Immediate Data
Data Addressing
Bit Addressing
Code Addressing
Expressions
Number
Expression String
Symbol
Operators
Addition and Subtraction
Sign Operators
Multiplication and Division
Relational Operators
Bitwise Operators
Shift Operators
Selection Operators
Segment Type of Expressions
Predefined Symbols
Include Files

6.1 Operands

An operand is the part of the instruction that follows the instruction opcode. There can be one, two or even no operands in an instruction. The operands of the assembly instruction can be divided into the following six classes:

Operands of the last four classes are expressions evaluating into a number. Depending on the instruction, the number is interpreted as a plain number or as an address. The expression may have an associated 'segment type', which is used by the assembler to perform type checking. The segment types correspond with the available address spaces of the 8051 processor:

Type Description
BIT bit address space (on-chip)
CODE code address space
DATA direct addressable data (on-chip)
IDATA indirect addressable space (on-chip)
XDATA external address space

Table 6-1: Segment memory types

Additionally, the segment type NUMBER is used for expressions representing a typeless number. If the expression can be completely evaluated at assembly time, it is called an absolute expression; if it is not, it is called a relocatable expression. See the section Expressions for more details.

6.1.1 Operands and Addressing Modes

6.1.1.1 Indirect Addressing

In an instruction using indirect addressing, the operand does not directly specify the memory address used in the operation. Rather, a register is specified whose contents is used to access the required data. Indirect addressing is specified with the @ character before the register name.

In most instructions, indirect addresses affect on-chip RAM. However, the MOVC and MOVX instructions use an indirect address operand to address code memory and external data memory, respectively.

In on-chip indirect addressing (IDATA addressing space), either register R0 or R1 can be specified as an indirect address operand. On the 8051 the address contained in the specified register must be between 0 and 127 (since you cannot access hardware registers through indirect addressing.) If an indirect address register contains a value greater than 127 when it is used as a source operand, a byte containing undefined data is returned. If it is used as destination operand, the data is lost. Processors supporting IDATA above 127 (e.g. 8052, 80C552) will execute these instructions as expected.

In the MOVX instruction, the 16 bit DPTR register is used as indirect address register to access external data space. The registers R0 and R1 can be used within a 256 byte 'page' of external RAM, since the high word of the address (P2) is not influenced by these instructions.

6.1.1.2 Immediate Data

An immediate operand is an 8 or 16 bit number, which is encoded as part of the instruction. Immediate operands are indicated by the # character before the expression defining the value of the operand.

Most instructions with immediate operands, require the operand to fit into a byte. The value of the expression must be in the range of -256 to +255, thus must be representable with 9 bits. The lower 8 bits of this value is used in the instruction.

Immediate data operands do not require any specific segment type. Operands of type XDATA and IDATA can not be used as immediate operand. Data in these address spaces can be accessed only by first loading the address into a register, and then using indirect addressing.

6.1.1.3 Data Addressing

A data address operand is an expression specifying one of the 128 on-chip RAM locations or one of the hardware locations. Addresses 0-127 access the internal RAM and addresses 128-255 access the hardware registers. The value of the expression must be in the range of -256 to +255.

Note that it is not possible to access the hardware registers using indirect addressing. Indirect addressing with an address above 127, will access IDATA space rather that the hardware register space if the processor type involved supports IDATA in this range.

6.1.1.4 Bit Addressing

A bit address represents a bit-addressable location in bytes 32 through 47 of the internal RAM, or a bit in one of the bit-addressable hardware registers. You can specify a bit address by giving the bit number explicitly. The expression now represents the bit address in bit space. The segment type of the expression should be BIT or NUMBER. Alternatively, you can select one bit of a bit-addressable byte with the bit selection operator (.). The segment type of the expression denoting the byte should be DATA or NUMBER. If the byte is in a relocatable DATA segment, the segment must have the BITADDRESSABLE attribute.

Bit addresses 0 through 127 map onto bytes 32 through 47 of the on-chip RAM, bits 128 through 255 map onto the hardware registers whose addresses are divisible by 8.

6.1.1.5 Code Addressing

A code address is an expression with a value in the range of 0 through 65535, specifying an address in the code space. The segment type of a code address expression should be CODE or NUMBER. There are three types of instructions requiring a code address in their operands. They are relative jumps, in-block (2K page) jumps or calls, and long jumps or calls. The long jump/call instructions accept any code address as their operand, but the other instructions impose restrictions on the code address.

For relative jumps, a signed 8 bit offset is encoded in the instruction, so the code address must be within -128 to +127 bytes from the first byte of the following instruction.

For in-block jumps and calls, the lower 11 bits of the destination address are encoded into the instruction, so the address must be within the same 2K-page as the next instruction.

The assembler provides yet another type of jump and call instruction: the generic jump and call. The mnemonics jmp and call are recognized by the assembler although they are not 8051 instructions. The assembler replaces jmp by an sjmp, ajmp or ljmp, and call by an acall or lcall, depending on the destination address. The assembler selects the shortest instruction possible, provided that the difference between the current location and the destination address can be calculated at assembly time.

Note that this jmp/call optimization can be turned off with the NOOPTIMIZE control. In that case, all generic instructions are translated into the long form.

6.2 Expressions

An operand of an assembler instruction or directive is either an assembler symbol or an expression. The assembler symbols for the 8051 are: A, AB, C, DPTR, PC and R0 to R7. An expression denotes an address in a particular memory space or a number. Expressions that can be evaluated at assembly time are called absolute expressions. Expressions where the result can not be known until logical sections have been combined and located are called relocatable expressions.

The syntax of an expression can be any of the following:

- number

- expression_string

- symbol

- $

- expression binary_operator expression

- unary_operator expression

- ( expression )

All types of expressions are explained below and in following sections.

$ represents the current location counter value in the section currently active.

( ) You can use parentheses to control the evaluation order of the operators. What is between parentheses is evaluated first.

Examples:

(3+4)*5   ; Result is 35.
          ; 3 + 4 is evaluated first.
3+(4*5)   ; Result is 23.
          ; 4 * 5 is evaluated first.
          ; parentheses are superfluous
          ; here

6.2.1 Number

number can be one of the following:
- bin_numB
- dec_num (or dec_numD)
- oct_numO (or oct_numQ)
- hex_numH

Lowercase equivalences are allowed: b, d, t, o, q, h.

bin_num is a binary number formed of '0'-'1' ending with a 'B' or 'b'.

dec_num is a decimal number formed of '0'-'9', optionally followed by the letter 'D' or 'd'.

oct_num is an octal number formed of '0'-'7' ending with an 'O', 'o', 'Q' or 'q'.

hex_num is a hexadecimal number formed of the characters '0'-'9' and 'a'-'f' or 'A'-'F' ending with a 'H' or 'h'. The first character must be a decimal digit, so it may be necessary to prefix a hexadecimal number with the '0' character.

6.2.2 Expression String

An expression_string is a string with a length of 0, 1 or 2 bytes. The value of the string is calculated by putting the last character (if any) in the least significant byte of a word and the second last character (if any) in the most significant byte of the word.

string is a string of ASCII characters, enclosed in single (') or double (") quotes. The starting and closing quote must be the same. To include the enclosing quote in the string, double it. E.g. the string containing both quotes can be denoted as: " ' ""  " or ' ' ' " '.

Examples:

'A' + 1    ; a 1-byte ASCII string, result 42H
"9C" + 1   ; a 2-byte ASCII string, result 3944H

6.2.3 Symbol

A symbol is an identifier. A symbol represents the value of an identifier which is already defined, or will be defined in the current source module by means of a label declaration, equate directive or the EXTRN directive. Symbols result in relocatable expressions.

Examples:

CON1 EQU 3H    ; The variable CON1 represents
               ; the value of 3

MOV R1, CON1 + 0FFD3H    ; Move contents of address
                         ; 0FFD7H to register R1

6.3 Opera tors

There are two types of operators:

- unary operators

- binary operators

Operators can be arithmetic operators, relational operators, logical operators, or special operators. All operators are described in the following sections.

If the grouping of the operators is not specified with parentheses, the operator precedence is used to determine evaluation order. Every operator has a precedence level associated with it. The following table lists the operators and their order of precedence (in descending order).

Operators Type
LOW, HIGH unary
+, - unary
*, /, MOD, SHL, SHR binary
+, - binary
EQ, NE, LT, LE, GT, GE, =, <>, <, <=, >, >= binary
NOT unary
AND binary
OR, XOR binary
. binary

Table 6-2: Operators Precedence List

Except for the unary operators, the assembler evaluates expressions with operators of the same precedence level left-to-right. The unary operators are evaluated right-to-left . So, -4 + 3 * 2 evaluates to (-4) + (3 * 2). Note that you can also use the '.' operator in expressions (for bit selection in a byte)!

6.3.1 Addition and Subtraction

Synopsis:

Addition: operand + operand

Subtraction: operand - operand

The + operator adds its two operands and the - operator subtracts them. The operands can be any expression evaluating to an absolute number or a relocatable operand.

Examples:

0a342h  + 23h       ; addition of absolute numbers
0ff1ah  - AVAR      ; subtraction with a variable

6.3.2 Sign Operators

Synopsis:

Plus: +operand
Minus: -operand

The + operator does not modify its operand. The - operator subtracts its operand from zero.

Example:

5  +  -3  ; result is 2

6.3.3 Multiplication and Division

Synopsis:

Multiplication: operand * operand
Division: operand / operand
Modulo: operand MOD operand

The * operator multiplies its two operands, the / operator performs an integer division, discarding any remainder. The MOD operator also perform an integer division, but discards the quotient and returns the remainder. The operands can be any expression evaluating to an absolute number or a relocatable operand.

Examples:

AVAR  *   2         ; multiplication
0ff3cH /  COUNT     ; division
23    mod 4         ; modulo, result is 3

6.3.4 Relational Operators

Synopsis:

Equal: operand EQ operand
operand
= operand
Not equal: operand NE operand
operand
<> operand
Less than: operand LT operand
operand
< operand
Less than or equal: operand LE operand
operand
<= operand
Greater than: operand GT operand
operand
> operand
Greater than or equal: operand GE operand
operand
>= operand

These operators compare their operands and return an absolute number (a bit) of 0ffffH for 'true' and 0 for 'false'. The operands can be any expression evaluating to an absolute number or a relocatable operand.

Examples:

3 GE 4         ; result is 0 (false)
4 EQ COUNT     ; 0ffffH (true), if COUNT is 4.
               ; 0 otherwise.
9 LT 0Ah       ; result is 0ffffH (true)

6.3.5 Bitwise Operators

Synopsis:

Bitwise AND: operand AND operand
Bitwise OR: operand OR operand
Bitwise XOR: operand XOR operand
Bitwise NOT: NOT operand

The AND, OR and XOR operators take the bit-wise AND, OR respectively XOR of the left and right operand. The NOT operator performs a bit-wise complement on its operand. The operands can be any expression evaluating to an absolute number or a relocatable operand.

Examples:

0Bh  and  3    ; result is 3
                    1011b
                    0011b  and
                    0011b

NOT  0Ah       ; result is 5
                    not 1010b = 0101b
NOT  0Ah       ; result is 0fff5h
                    not 0000000000001010b
                     =  1111111111110101b

6.3.6 Shift Operators

Synopsis:

Shift left: operand SHL count
Shift right: operand SHR count

These operators shift their left operand (operand) either left (SHL) or right (SHR) by the number of bits (absolute number) specified with the right operand (count). The operands can be any expression evaluating to an absolute number or a relocatable operand.

Examples:

AVAR shr  COUNT ; shift right variable AVAR,
                ; COUNT times

6.3.7 Selection Operators

Synopsis:

Select high byte: HIGH operand
Select low byte: LOW operand

Dot operator: bitbyte.bitpos

LOW selects the least significant byte of its operand, HIGH selects the most significant byte.

The . (dot) operator singles out the bit number specified by the bitpos from the bitbyte. The result is an address in the BIT addressable memory space.

bitbyte can have the following absolute values:

bitpos can have the following values:

Examples:

DB  HIGH  1234H ; stores 12H
DB  LOW   1234H ; stores 34H

6.4 Segment Type of Expressions

The segment type of an expression involving more than one operand is assigned according to the following rules:

1. The segment type of a unary operation (+, -, NOT, LOW, HIGH) will be the same as the segment type of the operand.

2. The segment type of a binary + or - operation is NUMBER, unless one of the operands has type NUMBER, in which case the segment type will be the type of the other operand.

3. The segment type of the binary operations except + and - will be NUMBER.

6.5 Predefined Symbols

Built into the assembler are a number of symbol definitions for various 8051 addresses in bit, data and code memory space. These symbols are treated by the assembler as though they were defined with the BIT , DATA and CODE assembler directives. The predefined symbols are listed on the next page.

BIT Addresses

Symbol BIT Address Symbol BIT Address
EA BIT 0AFH RS1 BIT 0D4H
P BIT 0D0H F0 BIT 0D5H
OV BIT 0D2H AC BIT 0D6H
RS0 BIT 0D3H CY BIT 0D7H

DATA Addresses

Symbol DATA Address Symbol DATA Address
P0 DATA 080H P1 DATA 090H
SP DATA 081H SCON DATA 098H
DPL DATA 082H SBUF DATA 099H
DPH DATA 083H P2 DATA 0A0H
TCON DATA 088H IE DATA 0A8H
TMOD DATA 089H P3 DATA 0B0H
TL0 DATA 08AH IP DATA 0B8H
TL1 DATA 08BH PSW DATA 0D0H
TH0 DATA 08CH ACC DATA 0E0H
TH1 DATA 08DH B DATA 0F0H

Table 6-3: DATA Addresses

CODE Addresses

Symbol CODE Address Symbol CODE Address
RESET CODE 000H EXTI1 CODE 013H
EXTI0 CODE 003H TIMER1 CODE 01BH
TIMER0 CODE 00BH SINT CODE 023H

Table 6-4: CODE Addresses

6.6 Include Files

Included in the assembler package (subdirectory 8051 of the directory include) are a number of include files, containing symbol definitions for the extra hardware registers and bits of the various 8051 derivatives. By including the right definition file, it is possible to use all symbolic register and bit names of a particular derivative, as defined by the manufacturer. For example, reg44.inc for the 8044 processor.


Copyright © 2002 Altium BV