Operands often contain expressions which will be evaluated into a single value.
Internally all values are 32 bit long integers, no matter what the requirements for the operand are.
Expressions consist of at least one element.
Every extra element should be separated from the previous element by an operation.
The following operations can be used in expressions:
All expressions are evaluated from left to right. No priority is given to multiplication and division over addition and subtraction like in normal math. Parentheses can not be used to change priority in expressions for they may serve a completely different purpose in some Crosses. I personally never ran into problems by the limitations of the math functions provided by the SB-Assembler. If you do, I think you should retrace your calculation. Remember: this is an assembler, not a spreadsheet program!
Overflows in expressions are ignored and the result is always truncated to 32 bits.
The SB-Assembler makes no distinction between signed and unsigned integers.
It's up to the program(mer) to interpret the results of calculationas as either be signed or unsigned.
You can, of course, use negative numbers.
Entering -126 in an 8 bit number will result in the binary value %1000.0010, just as if you had used the positive value 130.
Some assemblers also support shift operators which shift the entire value 1 or more bits to the left or to the right. The SB-Assembler does not support these operators because they can easily be replaced by multiplcations or divisions. Shifting 4 bits to the left is exactly the same as multiplying by 16. Whereas shifting 5 bits to the right is the same as dividing by 32.
Some examples of expressions:
MOV DPTR,#INDEX*2+OFFSET (index*2)+offset MOV DPTR,#OFFSET+INDEX*2 (offset+index)*2 .DA ADDRESS/$100 Integer division NEXT .EQ LABEL+2 .DA 7/8*100 (7/8)*100=0 wrong result .DA 100*7/8 (100*7)/8=87 better result .DO $=>$1000
Please note that the order in which you give the expressions is very important. The SB-Assembler evaluates all expressions from left to right. That is why 7/8*100 results in 0. This is because 7/8 is 0.875, which is truncated to 0 caused by the integer division. You'll get a much better result by rewriting the expression to 100*7/8, which is still an integer.
Elements Of An Expression
An element is:
Elements are internally represented by a 32 bit value.
Every element may be preceded by one of the two sign characters + or - .
The + sign is optional and does not change the polarity of an element at all.
A total of 4 different prefixes are defined to indicate immediate operands.
The most common prefix of the 4 types is the # symbol. Most processor families use this prefix to specify immediate operands. The other 3 prefix types are not as common and may even be unique to the SB-Assembler. All 4 prefixes have in common that the immediate addressing mode will be used. The value following the operand is used literally by the instruction.
MOV A,#10 ANL A,#%1111.000
Some processor families don't use the immediate prefix at all. In those cases the use of the # prefix will be optional in the corresponding SB-Assembler Crosses.
In Version 3 of the SB-Assembler the shifted values are sign extended. This means that instead of shifting in zeroes from the left, the most significant bit is repeated over the shift length. This way the sign of the value doesn't change.
.CR 8051 MOV A,#$12345678 Uses only lowest byte $78 MOV DPTR,#$12345678 Uses lowest 16 bits $5678 MOV A,/$12345678 Uses only 2nd lowest byte $56 MOV DPTR,/$12345678 Uses bytes 2 and 3 $3456 MOV A,=$12345678 Uses only 2nd highest byte $34 MOV DPTR,=$12345678 Uses highest 16 bits $1234 MOV A,\$12345678 Uses only highest byte $12 MOV DPTR,\$12345678 Uses highest byte as 16 bit value $0012
These prefixes are very easy when you have to use the immediate addressing mode of the processor. But sometimes you want the same function for other addressing modes as well. You can't use the prefixes there because they would change the addressing mode along with it. In those situations you could divide the value by $100, $10000 or by $1000000 respectively.
We humans are very familiar with the base10 or so called decimal radix. Computers prefer to use base2 or so called binary radix. Binary numbers can come in very handy to define bit masks. But for other situations they are not very useful to us humans. Normal numbers can be represented in decimal as well, but addresses are better represented in base16 or so called hexadecimal radix.
Many different representations exist in the world of assemblers to identify the different radixes.
The SB-Assembler initially only used the Motorola representation where every radix, except base10, is preceded by a special identifier symbol.
As of Version 3 of the SB-Assembler the C-style notation can also be used. Hexadecimal numbers for instance can also be written as 0xABCD.
Remember that all numbers are internally stored as 32 bit values. Entering larger values will result in an "Overflow error" message to be reported.
If an element starts with a digit from 0 to 9 it is very likely to be interpreted as a normal decimal number.
Unless the total number is followed by a B, O, Q or H, in which case the Intel radix representation is used to evaluate the number.
1234 -100 +65535
In the Motorola representation hexadecimal numbers are preceded by a $ symbol and may contain the digits 0 to 9 and A to F.
The assembler stops interpreting the number when a non HEX digit is encountered.
Using the $ symbol without a legal HEX digit following it will result in the current program location being returned.
$ABCD -$1234 +$ffff0000 0ABCDH -1234H +0ffff0000h 0xABCD -0x1234 +0xffff0000
In the Motorola representation octal numbers are preceded by an @ symbol and may contain the digits 0 to 7.
The assembler stops interpreting the number when a non octal digit is encountered.
At least one digit should follow the @ symbol otherwise a "Value expected error" is reported.
Some Crosses may limit the use of octal numbers in situations where the @ symbol can represent indirect addressing mode. In most such cases it is sufficient to add the + sign in front of the @ symbol, like in: +@123, to avoid confusion with indirect addressing mode.
Neither Version 2 nor Version 3 uses C-style representation for octal numbers.
@12345 -@1234 +@777000 12345Q -1234Q +777000Q
In the Motorola representation binary numbers are preceded by a % symbol and may contain only the digits 0 and 1.
The assembler stops interpreting the number when a non binary digit is encountered.
At least one digit should follow the % symbol otherwise a "Value expected error" is reported.
Only with the Motorola representation you may add dots in long binary numbers to make them easier to read for us humans.
A long binary number is usually very hard to read, therefore you can insert dots between the bits at any position.
Usually binary digits are grouped together in blocks of 4 bits, enabling easy translation to HEX.
+%1111.1111.1111.1111.1111.1111.1111.1111 and -%1.0000.0000.0000.0000.0000.0000.0000.0000 are the maximum values of a 32 bit binary number.
Larger numbers will result in an "Overflow error".
%1010 %1111.0000 %10.111.000 -%11 +%111 %1010.1111.0011.1000 1010B 11110000B 10111000B -11B +111B 1010111100111000B 0b1010 0b1111.0000 0b10.111.000 -0b11 +0b111 0b1010111100111000
ASCII values are often used in operands and expressions. The SB-Assembler knows two different ASCII identifiers.
The ASCII character is considered to be a string literal, which is case sensitive in the SB-Assembler. So the character 'a' is a different character than 'A'.
The value of the character following the single or double quote is used. After that character the same quote type may be used to fully enclose the ASCII character. This closing quote is optional, but it should be the same type as the opening quote if it's used. To avoid confusion or error messages it is recommended to fully enclose the ASCII space character, especially if the space is located at the end of the program line. Some editors will strip off all trailing spaces on a line, killing your space that should be there.
It is perfectly legal to write ''' or """ to use ASCII values of ' and " respectively.
'a' 'A' 'a ' ' ''' "a" "A" "a " " """
The current location value holds the program counter value PC of the first byte of the current program line. It can be used for addressing relative to the current location of the program.
In versions of the SB-Assembler prior to Version 2 only the * symbol was used to represent the current location value. But since most assemblers use the $ symbol as current location value I decided to teach the SB-Assembler that same trick too. So it doesn't matter whether you use * or $ as current location value.
To us humans it may be a bit confusing if one of the current location values is used in expressions. Consider the following silly example:
This means take the current location value (1st *) multiply it (2nd *) by the current location value (3d *), which is in effect raise the current location value to the power of 2.
It could also have been written as $*$ .
The following program line is the shortest possible endless loop:
It can also be written as:
The Pass Identifier
The pass identifier can be used to know whether we are in pass 1 or pass 2 of the assembling process. The ? symbol is used as pass identifier element. The pass identifier will be 0 during pass 1, and 1 during pass 2.
The pass identifier is only useful during debugging when used with conditional assembly functions.