## CHAPTER 9

### Assembly Language Linkage

9.1 OVERVIEW

NOTE: This section assumes that the designer has an understanding of the architecture and assembly language of the MCS-51 Microcontroller family!!!

MCS BASIC-52 contains a complete library of routines that can easily be accessed with assembly language call instructions. The advantage of using assembly language is that it offers a significant improvement in execution speed relative to interpreted BASIC. In order to successfully interface MCS BASIC-52 with an assembly language program, the software designer must be aware of a few simple facts.

READ THIS CAREFULLY!!!

1. MCS BASIC-52 uses register banks 0, 1, and 2 (RB0, RB1, and RB2). Register bank 3 (RB3) is never used except during a PGM statement. RB3 is designated the user register bank and the users can do whatever they want to with register bank 3 (RB3) and MCS BASIC-52 will never alter the contents of this register bank except during the execution of a PGM statement. The contents of register bank 3 (RB3) can be changed by executing a DBY ([expr]) = [0 to 255] statement. Where the [expr] evaluates to a number between 24 (18H) and 31 (1FH) inclusive. In addition, internal memory locations 32 (20H) and 33 (21 H) are also never used by MCS BASIC-52. These two bit and/or byte addressable locations are specifically reserved for assembly language programs.

2. MCS BASIC-52 uses register bank 0 (RB0) as the working register file. Whenever assembly language is used to access MCS BASlC-52's routines, the working register file, register bank 0 (RB0) must be selected!!! This means that the user must make sure that register bank 0 (RB0) is selected before calling any of MCS BASlC-52's routines. This is done simply by setting bits 3 and 4 in the PSW equal to zero. If this is not done, MCS BASIC-52 will "kick out" the user and no operation will be performed. When an assembly language program is accessed by using the MCS BASlC-52's CALL instruction, register bank 0 (RB0) will always be selected. So unless the user selects register bank 3 (RB3) in assembly language, it is not necessary to change the designated register bank.

3. Always assume that MCS BASIC-52 destroys the contents of the working register file and the DPTR, unless otherwise stated in the following documentation.

4. Certain routines in MCS BASIC-52 require that registers be initialized before the user calls that specific routine. These registers are always in the working register file, register bank 0 (RB0).

5. Certain routines in MCS BASIC-52 return the result of an operation in a register or registers. The result registers are always in the working register file, register bank 0, (RB0).

6. MCS BASIC-52 loads the internal stack pointer (special function register - SP) with the value that is in internal memory location 62 (3EH). MCS BASIC-52 initializes internal memory location 62 (3EH) by writing a 77 (4DH) to this location after a hardware reset. MCS BASIC-52 does not use any memory beyond 77 (4DH) for anything except stack space. If the user wants to allocate some additional intemal memory for their application, this is done by changing the contents of internal memory location 62 (3EH) to a value that is greater than 77 (4DH). This will allocate the internal memory locations from 77 (4DH) to the value that is placed in internal memory location 62 (3EH) to the user. As a guideline, it is a good idea to allow at least 48 (30H) bytes of stack space for MCS BASIC-52. The bad news about reducing the stack space is that it will reduce the amount of nested parentheses that MCS BASIC-52 can evaluate in an expression [expr]. This will either cause a I-STACK error or will cause a fatal CPU "crash." Use caution and don't allocate more memory than you need.

EXAMPLE OF THE EFFECTS OF ALTERING THE STACK ALLOCATION:

                            COMMENTS

    >PRINT DBY(62)          AFTER RESET INTERNAL MEMORY LOCATION 6
     77                     CONTAINS A 77

    >PRINT (1*(2*(3)))      BASIC HAS NO PROBLEM EVALUATING 3 LEVELS
     6                      OF NESTED PARENRHESIS

    >DBY(62)=230            NOW ALLOCATE 255-230 = 25 BYTES OF STACK
                            SPACE TO BASIC, REMEMBER, THE STACK ON
    >PRINT (1*(2*(3)))      THE 80S2AH GROWS "UP"

    ERROR: I-STACK          BASIC CANNOT EVALUATE THIS EXPRESSION
    READY                   BECAUSE IT DOES NOT HAVE ENOUGH STACK
    >DBY(62)=210            NOW ALLOCATE 255-210 = 45 BYTES OF STACK
                            SPACE TO BASIC
    >PRINT (1*(2*(3)))      THE I-STACK ERROR GOES AWAY
     6

7. Throughout this section a 16-bit register pair is designated - Rx:Ry, where Rx is the most significant byte and Ry is the least significant byte.

EXAMPLE:

R3:R1 - R3 = Most significant byte. R1=Least significant byte.

9.2 GENERAL PURPOSE ROUTINES

Accessing MCS BASIC-52 routines with assembly language is easy. The user just loads the ACCumulator with a specific value and calls location 48 (30H). The value placed in the ACCumulator determines what operation will be performed. Unless otherwise stated, the contents of the DPTR and register bank 0 (RB0) will always be altered when calling these routines. The generalized form for accessing MCS BASlC-52's routines is as follows:

    ANL PSW,#11100111B     ;make sure
                           ;RB0 is
                           ;selected
    MOV A,#OPBYTE          ;load the
                           ;instruction
    CALL 30H               ;execute the
                           ;instruction

The value of OPBYTE determines what operation will be performed. The following operations can be performed:

OPBYTE = 0 (00H) RETURN TO COMMAND MODE

This instruction causes MCS BASIC-52 to enter the command mode. Control of the CPU is handed back to the MCS BASIC-52 interpreter and BASIC will respond by outputting a READY and a prompt character (>).

OPBYTE = 1 (01H) POP ARGUMENT STACK AND PUT VALUE IN R3:R1

This instruction converts the value that is on the argument stack to a 16-bit binary integer and returns the binary integer in registers R3 (high byte) and R1 (low byte) of register bank 0 (RB0). The argument stack gets popped after this instruction is executed. If the value on the argument stack cannot be represented by a 16-bit binary number (i.e. it is not between 0 and 65535 (0FFFFH) inclusive), BASIC will trap the error and print a BAD ARGUMENT error message. The binary value returned is truncated, not rounded.

EXAMPLE:

    BASIC PROGRAM -         10 PUSH 20
                            20 CALL 5000H

    ASSEMBLY PROGRAM -      ORG 5000H
                            MOV A.#01H      ; load opbyte
                            CALL 30H        ; RB0 still selected
                                            ;
                                            ; at this point R3 (of RB0) = 01H
                                            ; and R1 (of RB0) = 04H
                                            ; so, R3:R1 = 260, which was the value
                                            ; that was placed on the ARGUGENT STACK

Comments on the next two instructions:

The next two instructions permit the user to transfer floating point numbers between an assembly language program and MCS BASIC-52. The user provides the address where a floating point number is stored or will be stored in a 16-bit register pair. Depending on the operation requested, the floating point numbers are either pushed on or popped off MCS BASlC-52's argument stack. This instruction permits the user to keep track of variables in assembly language and bypass the relatively slow procedure BASIC must follow.

As mentioned earlier, when a floating point number is pushed onto the argument stack, the argument stack pointer is decremented by a count of 6. This is because a floating point number requires 6 bytes of RAM storage. Although it may seem confusing to the novice, the last value placed on the argument stack is referred to as the value on the TOP of the argument stack, even though it is on the BOTTOM of the stack relative to the sequential numbering of memory addresses. No one knows why this is so.

The argument stack resides in external RAM locations 301 (12DH) through 510 (1FEH). The lower byte of the argument stack pointer resides in internal memory location 9 (09H). MCS BASIC-52 always assumes that the upper byte (higher order address) of the argument stack pointer is 1 (01H). The software designer can use this information, along with the next two instructions to perform operations like copying the stack.

OPBYTE = 2 (02H) PUSH THE FLOATING POINT NUMBER ADDRESSED BY REGISTER PAIR R2:R0 ONTO THE ARGUMENT STACK.

R2 and R0 (in register bank 0, RB0) contain the address (R2 = high byte, R0 = low byte) of the location where the floating point number is stored. After this instruction is executed the floating point number that the register pair R2:R0 points to is pushed onto the top of the argument stack. The argument stack pointer automatically gets decremented, by a count of 6, when the value is placed on the stack. A floating point number in MCS BASIC-52 requires 6 bytes of RAM storage. The register Pair R2:R0 points to the most significant byte of the floating point number and is decremented by 6 after the call instruction is executed. So, if R2:R0 = 7F18H before this instruction was executed, it would equal 7F12H after this instruction was executed.

OPBYTE = 3 (03H) POP THE ARGUMENT STACK AND SAVE THE FLOATING POINT NUMBER IN THE LOCATION ADDRESSED BY R3:R1.

The top of the argument stack is moved to the location pointed to by the register pair R3:R1(R3 = high byte, R1 = low byte, in register bank 0, RB0). The argument stack pointer is automatically incremented by 6. Just as in the previous push instruction, the register pair R3:R1 points to the most significant byte of the floating point number and is decremented by 6 after the call instruction is executed.

EXAMPLE OF USER PUSH AND POP:

    BASIC PROGRAM:

    >5 REM PUT 100 AND 200 ON THE ARGUMENT STACK
    >10 PUSH 100,200
    >15 REM CALL THE USER ROUTINE TO SAVE NUMBERS
    >20 CALL 5000H
    >25 REM CLEAR THE STACK
    >30 CLEARS
    >35 REM USE ASM TO PUT NUMBERS BACK ON STACK
    >40 CALL 5010H
    >50 POP A,B
    >60 PRINT A,B
    >RUN

     100 200

    READY

    ASM PROGRAM:

          ORG 5000H
          MOV R3,#HIGH USER SAVE        ; LOAD POINTERS TO WHERE
          MOV R1.#LOW USER_SAVE         ; NUMBERS WILL BE SAVED.
          MOV A,#03H                    ; LOAD OPBYTE
          CALL 30H                      ; SAVE ONE NUMBER
          MOV A,#03H                    ; LOAD OPBYTE AGAIN
          CALL 30H                      ; SAVE ANOTHER NUMBER
          RET                           ; BACK TO BASIC
                                        ;
          ORG 5010H
          MOV R2,#HIGH USER_SAVE        ;LOAD ADDRESS WHERE
          MOV R0,#LOW USER_SAVE         ;NUMBERS ARE STORED
          MOV A,#02H                    ;LOAD OPBYTE
          CALL 30H                      ;PUT ONE NUMBER ON STACK
          MOV A,#02H                    ;LOAD OPBYTE
          CALL 30H                      ;NEXT NUMBER ON STACK
          RET                           ;BACK TO BASIC

OPBYTE = 4 (04H) PROGRAM A PROM USING R3:R1 AS THE SOURCE ADDRESS POINTER, R2:R0 AS THE DESTINATION (PROM) ADDRESS POINTER, AND R7:R6 AS THE BYTE COUNTER.

This instruction assumes that the data to be programmed into a PROM is stored in external memory and that the register pair R3:R1 (in RB0) contains the address of this external memory. register pair R7:R6 contains the total number of bytes that are to be programmed. The PROM is programmed sequentially and everytime a byte is programmed the register pair R7:R6 is decremented and the register pairs R3:R1 and R2:R0 are incremented. Programming continues until R7:R6 equals zero. The register pair R2:R0 must be initialized with the desired address of the EPROM to be programmed minus 1. This may sound strange, but that is the way it works. So, if you wanted to program an EPROM starting at address 9000H, with the data stored in address 0D00H and you wanted to program 500 bytes, then the registers would be set up as follows: R2:R0 = 8FFFH, R3:R1 = 0D00H, and R7:R6 = 01F4H (500 decimal). You would then put a 4 (04H) in the ACC and CALL location 30H.

NOTE: In Version 1.0, if an error occurs during programming, MCS BASIC-52 will trap the error and enter the command mode. The user cannot handle errors that occur during the EPROM programming operation!!!!

In Version 1.1, programming errors will only be trapped if the MCS BASIC-52 device is in the command mode. If the MCS BASIC-52 device is in the run mode, control will be passed back to the user. The user must then examine registers R6 and R7. If R6 = R7 = 0, then the programming operation was successfully completed, if these registers do not equal zero then registers R2:R0 contain the address of the EPROM location that failed to program. This feature in Version 1.1 permits the user to program EPROMS in embedded applications and manage errors, should they occur in the programming process, without trapping to the command mode.

In addition to setting up the pointers previously described, the user must also initialize the internal memory locations that control the width of the programming pulse. This gives the user complete control over this critical PROM programming parameter. The internal memory locations that must be initialized with this information are 64 (40H) and 65 (41H). These locations are treated as a 16 bit register pair with location 64 (40H) designated as the most significant byte and location 65 (41H) as the least significant byte. Locations 64 (40H) and 65 (41H) are loaded into TH1 (TIMER1 high byte) and TL1 (TIMER1 low byte) respectively. The width of the programming pulse, in microseconds is determined by the following equation:

Width = (65536-256*DBY(64)+DBY(65))*12/XTAL microseconds

conversely;

DBY(64):DBY(65) = 65536-Width*XTAL/12

The proper values for the "normal" 50 millisecond programming algorithm and the 1 millisecond "INTELligent" algorithm are calculated and stored by MCS BASIC-52 in external memory locations 296:297 (128H: 129H) and 298:299 ( 12AH: 12BH) respectively. If the user wants to use the pre-calculated values the statements DBY(64) = XBY(296) and DBY(65) = XBY(297) may be used to initialize the PROM programming width for the normal algorithm and the statements DBY(64) = XBY(298) and DBY(65) = XBY(299) can be used to initialize for the INTELligent algorithm.

To select the "intelligent" EPROM programming algorithm the directly addressable bit 51 (33H) must be set to 1 before the EPROM programming routine is called. The "standard" 50 ms EPROM programming algorithm is selected by clearing bit 51 (33H) (i.e. bit 51 = 0) before calling the EPROM programming routine. The directly addressable bit 51 is located in internal memory location 38.3 (26.3H) (bit 3 of byte 38 (26H) in internal memory). This bit can be set or cleared by the BASIC statements DBY(38) = DBY(38) .0R. 08H to set and DBY(38)=DBY(38) .AND. 0F7H to clear. Of course, the user can set or clear this bit in assembly language with a SETB 51 or CLR 51 instruction.

The user must also turn on the EPROM programming voltage before calling the EPROM programming routine. This is done by clearing bit P1.5, the fifth bit on PORT 1. This too can be done in BASIC with a PORT1 = PORT1 .AND. 0DFH instruction or in assembly language with a CLR P1.5 instruction. The user must also set this bit when the PROM programming procedure is complete.

This instruction assumes that the hardware surrounding the MCS BASIC-52 device is the same as the suggestions in the EPROM programming chapter of this manual.

OPBYTE = 5 (05H) INPUT A STRING OF CHARACTERS AND STORE IN THE BASIC INPUT BUFFER.

This instruction inputs a line of text from the console device and saves the information in the MCS BASIC- 52's input buffer. MCS BASlC-52's input buffer begins at external memory location 7 (0007H). All of the line editing features available in MCS BASIC-52 are implemented in this instruction. If a control-C is typed during the input process, MCS BASIC-52 will trap back into the command mode. A carriage return (cr) terminates the input procedure.

OPBYTE = 6 (06H) OUTPUT THE STRING OF CHARACTERS POINTED TO BY THE REGISTER PAIR R3:R1 TO THE CONSOLE DEVICE.

This instruction is used to output a string of characters to the console device. R3:R1 contains the initial address of this string. The string can either be stored in program memory or external data memory. If bit 52 (34H) (which is bit 4 of internal RAM location 38 (26H)) is set, the output will be from program memory. If bit 52 is cleared, the output will be from external data memory. The data stored in memory is sent out to the console device one byte at a time and the memory pointer is incremented. The output is stopped when a termination character is read. The termination character for program memory and external data memory are different. The termination character for external data memory is a (cr) 0DH. The termination character for program memory is a " or 22H.

OPBYTE = 7 (07H) OUTPUT A CARRIAGE RETURN-LINE FEED SEQUENCE TO THE CONSOLE DEVICE.

Enough said.

OPBYTE = 128 (80H) OUTPUT THE CHARACTER IN R5 (REGISTER BANK 0) TO THE CONSOLE DEVICE.

This routine takes the character that is in R5 (register bank 0) and directs it to the console device. Any console device may be selected (i.e. U0 or UI or the software serial port).

OPBYTE = 144 (90H) OUTPUT THE NUMBER ON THE TOP OF ARGUMENT STACK TO THE CONSOLE DEVICE.

The floating point number that is on the top of the argument stack is outputted to the console device. The format is determined by the USING statement. The argument stack is popped after the output operation.

OPBYTE = 154 (9AH) THE 16 BIT NUMBER REPRESENTED BY REGISTER PAIR R2:R0 IS PUSHED ON THE ARGUMENT STACK.

This instruction converts the 16 bit register pair R2:R0 to a floating point number and pushes this number onto the argument stack. This instruction is the converse of the OPBYTE = 1 instruction.

9.3 UNARY OPERATORS

The next group of instructions perform an operation on the number that is on the top of the argument stack. If the top of the argument stack is represented by the symbol [TOS], then the following instructions would take the general form:

[TOS] < OP [TOS]

Where OP is one of the following operators:

OPBYTE = 24 (18H) - ABSOLUTE VALUE

[TOS] < ABS([TOS]). The [TOS] is replaced by the absolute value of [TOS].

OPBYTE = 25 (19H) - INTEGER

[TOS] < INT([TOS]). The [TOS] is replaced by the integer portion of [TOS].

OPBYTE = 26 (1AH) - SIGN

[TOS] < SGN([TOS]). If [TOS] > 0 then [TOS] = 1, if [TOS] = 0 then [TOS] = 0, and if [TOS] < O then [TOS] = -1.

OPBYTE = 27 (1BH) - ONE'S COMPLEMENT

[TOS] < NOT([TOS]). [TOS] must be a valid integer.

OPBYTE = 28 (1CH) - COSINE OPERATOR

[TOS] < COS([TOS]). [TOS] must be between +-200000.

OPBYTE = 29 (1DH) - TANGENT OPERATOR

[TOS] < TAN([TOS]). [TOS] must be between +- 200000 and [TOSl cannot equal PI/2, 3*PI/2, 5*PI/2..... (2*N+1)*PI/2.

OPBYTE = 30 (1EH) - SINE OPERATOR

[TOSl < SIN([TOS]). [TOS] must be between +-200000.

OPBYTE = 31 (1FH) - SQUARE ROOT

[TOS] < SQR ([TOS]). [TOS] must be >= 0.

OPBYTE = 32 (20H) - CBY OPERATOR

[TOS] < CBY ([TOS]). [TOS] must be a valid integer.

OPBYTE = 33 (21H) - E TO THE [TOS] OPERATOR

[TOS] < EXP ([TOS]). e is raised to the [TOS] power.

OPBYTE = 34 (22H) - ATN OPERATOR

[TOS] < ATN([TOS]). Arctangent, the value returned is between +- PI/2.

OPBYTE = 35 (23H) - LOG OPERATOR (natural LOG)

[TOS] < LOG([TOS]) - [TOS] must be > 0.

OPBYTE = 36 (24H) - DBY OPERATOR

[TOS] < DBY([TOS]). [TOS] must be between 0 and 255 inclusive.

OPBYTE = 37 (25H) - XBY OPERATOR

[TOS] < XBY([TOS]). [TOS] must be a valid integer.

9.4 SPECIAL OPERATORS

The next group of instructions place a value on the stack. The value placed on the stack is as follows:

OPBYTE = 38 (26H) - PI

[TOS] = PI. PI (3.1415926) is placed on the [TOS].

OPBYTE = 39 (27H) - RND

[TOS] = RND. A random number is placed on the [TOS].

OPBYTE = 40 (28H) - GET

[TOS] = GET. The value of the special function operator, GET is put on the [TOS].

OPBYTE = 41 (29H) - FREE

[TOS] = FREE. The value of the system control value, FREE is put on the [TOS].

OPBYTE = 42 (2AH) - LEN

[TOS] = LEN. The value of the system control value, LEN is put on the [TOS].

OPBYTE = 43 (2BH) - XTAL

[TOS] = XTAL. The value of the special function operator, XTAL is put on the [TOS].

OPBYTE = 44 (2CH) - MTOP

[TOS] = MTOP. The value of the system control value, MTOP is put on the [TOS].

OPBYTE = 45 (2DH) - TIME

[TOS] = TIME. The value of the special function operator, TIME is put on the [TOS].

OPBYTE = 46 (2EH) - IE

[TOS] = IE The value of the IE register is put on the [TOS].

OPBYTE = 47 (2FH) - IP

[TOS] = IP. The value of the IP register is put on the [TOS].

OPBYTE = 48 (30H) - TIMER0

[TOS] = TIMER0. The value of TIMER0 (TH0:TL0) is put on the [TOS].

OPBYTE = 49(31H) - TIMER1

[TOS] = TIMER1. The value of TIMER1 (TH1:TL1) is put on the [TOS].

OPBYTE = 50 (32H) - TIMER2

[TOS] = TIMER2. The value of TIMER2 (TH2:TL2) is put on the [TOS].

OPBYTE = 51 (33H) - T2CON

[TOS] = T2CON. The value of the T2CON register is put on the [TOS].

OPBYTE = 52 (34H) - TCON

[TOS] = TCON. The value of the TCON register is put on the [TOS].

OPBYTE = 53 (35H) - TMOD

[TOS] = TMOD. The value of the TMOD register is put on the [TOS].

OPBYTE = 54 (36H) - RCAP2

[TOS] = RCAP2. The value of the RCAP2 registers (RCAP2H:RCAP2L) is put on the [TOS].

OPBYTE = 55 (37H) - PORT1

[TOS] = PORT1. The value of the PORT1 (P1) pins is placed on the [TOS].

OPBYTE = 56 (38H) - PCON

[TOS] = PCON. The value of the PCON register is put on the [TOS].

9.5 DUAL OPERAND OPERATORS

The next group of instructions assume that two values are on the argument stack. If number on the top of the argument stack is represented by the symbol [TOS] and the number next to top of the argument stack is represented by the symbol [NxTOS] and the argument stack pointer is represented by the symbol [AGSP], then the following instructions would take the general form:

    TEMP1 = [TOS]
    TEMP2 = [NxTOS]
    [AGSP] < [AGSP] + 6
    RESULT = TEMP2 OP TEMP1
    [TOS] = RESULT

Where OP is one of the following operators to be described. Note that the group of instructions always pop the argument stack by one floating point number size (i.e. 6 bytes).

Errors can be handled in two different ways with the add, subtract, multipy and divide routines. One option is to let MCS BASIC-52 trap errors, should they occur during the operation. With this option MCS BASIC-52 will print the appropriate error message to the console device. The other option passes a status code to the user. After the operation the ACCumulator contains the status code information. The status information is as follows:

      ACC.0 - ARITHMETIC UNDERFLOW
      ACC.1 - ARITHMETIC OVERFLOW
      ACC.2 - RESULT WAS ZERO (not an error, just a condition)
      ACC.3 - DIVIDE BY ZERO
      ACC.4 - NOT USED, ZERO RETURNED
      ACC.5 - NOT USED, ZERO RETURNED
      ACC.6 - NOT USED, ZERO RETURNED
      ACC.7 - NOT USED, ZERO RETURNED

If an ARITH. OVERFLOW or a DIVIDE BY ZERO error occurs and the user is handling the error condition, the floating point processor will retum a result of +- 99999999E+ 127 to the argument stack. The user can do what they want to with this result (i.e. use it or waste it). An ARITH. UNDERFLOW error will return to the argument stack a result of 0 (zero).

MCS BASIC-52 can perform the following dual operand operations:

OPBYTE = 9 (09H) - EXPONENTIATION

RESULT= [NxTOS] ** [TOS]. NOTE - [TOS] must be less than 256. The [NxTOS] value is raised to the [TOS] power.

OPBYTE = 10 (0AH) - MULTIPLY

RESULT = [NxTOS] * [TOS]. If an error occurs during this operation (i.e. ARITH. OVERFLOW or ARITH. UNDERFLOW) MCS BASIC-52 will trap the error and print the error message to the console device.

OPBYTE = 136 (88H) - MULTIPLY

RESULT = [NxTOS] * [TOS]. If an error occurs during this operation, the status byte previously discussed will be returned to the user.

OPBYTE = 11 (0BH) - ADD

RESULT = [NxTOS] + [TOS]. BASIC handles errors.

OPBYTE = 130 (82H) - ADD

RESULT = [NxTOS] + [TOS]. User handles errors.

OPBYTE = 12 (0CH) - DIVIDE

RESULT = [NxTOS] / [TOS]. BASIC handles errors.

OPBYTE = 138 (8AH) - DIVIDE

RESULT = [NxTOS] / [TOS]. User handles errors.

OPBYTE = 13 (0DH) - SUBTRACT

RESULT = [NxTOS] - [TOS]. BASIC handles errors.

OPBYTE = 132 (84H) - SUBTRACT

RESULT = [NxTOS] - [TOS]. User handles errors.

OPBYTE = 14 (0EH) - EXCLUSIVE OR

RESULT = [NxTOS] XOR [TOS], both values must be greater than or equal to zero and less than or equal to 65535 (0FFFFH).

OPBYTE = 15 (0FH) - LOGICAL AND

RESULT = [NxTOS] AND [TOS], both values must be greater than or equal to zero and less than or equal to 65535 (0FFFFH).

OPBYTE = 16 (10H) - LOGICAL OR

RESULT = [NxTOS] OR [TOS], both values must be greater than or equal to zero and less than or equal to 65535 (0FFFFH).

OPBYTE = 18 (12H) - TEST FOR EQUALITY

IF [NxTOS] = [TOS] then, RESULT = 65535 (0FFFFH), else RESULT = 0.

OPBYTE = 19 (13H) - TEST FOR GREATER THAN OR EQUAL TO

IF [NxTOS] >= [TOS] then, RESULT = 65535 (0FFFFH), else RESULT = 0.

OPBYTE = 20 (14H) - TEST FOR LESS THAN OR EQUAL

IF [NxTOS] <= [TOS] then, RESULT = 65535 (0FFFFH), else RESULT = 0.

OPBYTE = 21(15H) - TEST FOR NOT EQUAL

IF [NxTOS] <> [TOS] then, RESULT = 65535 (0FFFFH), else RESULT = 0.

OPBYTE = 22(16H) - TEST FOR LESS THAN

IF [NxTOS] < [TOS] then, RESULT = 65535 (0FFFFH), else RESULT = 0.

OPBYTE = 23(17H) - TEST FOR GREATER THAN

IF [NxTOS] > [TOS] then, RESULT = 65535 (0FFFFH), else RESULT = 0.

9.6 ADDED LINK ROUTINES TO VERSION 1.1

Version 1.1 of MCS BASIC-52 contains a number of useful assembly language link routines that were not available in Version 1.0. Most of these routines were designed to be used in conjunction with the new command/statement extensions. The added link routines are as follows:

OPBYTE = 57 (39H) - EVALUATE AN EXPRESSION WITHIN THE BASIC TEXT STRING AND PLACE THE RESULT ON THE ARGUMENT STACK

This routine permits the user to evaluate a BASIC expression [expr] containing variables, operators and constants. The result of the evaluated expression is placed on the floating point argument stack. This lets the user evaluate expressions in "customized" statements and commands. An example of use of this OPBYTE is given at the end of this section.

OPBYTE = 58 (3AH) - PERFORM CRYSTAL DEPENDENT CALCULATIONS WITH THE VALUE THAT IS ON THE ARGUMENT STACK

This routine is provided mainly to let the user write an assembly language reset routine and perform all of the crystal dependent calculations that are required by MCS BASIC-52. An example of a customized reset routine that uses this OPBYTE is presented in Chapter 11 of this manual.

OPBYTE = 63 (3FH) - GET A CHARACTER OUT OF THE BASIC TEXT STRING

This routine permits the user to "pick" a character out of the BASIC program. For instance, in BASIC the user could have the following:

    10   CALL 1000H A

If the user executed the following in assembly language at 1000H:

          MOV A, #63
          LCALL 30H

The character A would be returned in the accumulator. The Basic text pointer is located in location 8 (8H) (low byte) and 10 (0AH) (high byte) of the internal ram on the MCS BASIC-52 device. If the user were to implement the above function, the basic text pointer must be advanced to the carriage return at the end of the statement before retuming back to BASIC. Failure to do this will cause a BAD SYNTAX error when the user retums back to BASIC. The following OPBYTE can be used to advance the BASIC text pointer.

OPBYTE = 64 (40H) - GET CHARACTER, THEN INCREMENT TEXT POINTER

This OPBYTE does the same thing as the previous one described, except that the BASIC text pointer is incremented after the character is read. An example of this OPBYTE is presented at the end of this section.

OPBYTE = 65 (41H) - INPUT A CHARACTER FROM THE CONSOLE DEVICE, PUT IT IN THE ACCUMULATOR, THEN RETURN

This OPBYTE permits the user to input characters from MCS BASlC-52's console input routine. The character is placed in the accumulator upon return.

OPBYTE = 66 (42H) - ENTER THE RUN MODE

This OPBYTE permits the user to start the execution of an MCS BASIC-52 program from assembly language. The user need only insure that locations 19 (13H) and 20 (14H) of internal data memory contain the start address (high byte, low byte respectively) of the BASIC program.

OPBYTE = 129 (81H) - INPUT AN ASCII FLOATING POINT NUMBER AND PLACE IT ON THE ARGUMENT STACK. THE DPTR POINTS TO THE EXTERNAL RAM LOCATION, WHERE THE ASCII TEXT STRING IS STORED

This routine assumes that the user has placed an ASCII text string somewhere in memory and that this ASCII text string represents a valid floating point number. The user then puts the DPTR to the starting address of this text string. After this OPBYTE is executed the text string will be converted to a valid MCS BASIC-52 floating point number and placed on the argument stack and the DPTR will be advanced to the end of the floating point number. If the DPTR does not point to a text string that contains a valid floating point number, the accumulator will contain an 0FFH upon return.

OPBYTE = 152 (98) - OUTPUT, IN HEX, TO THE CONSOLE OUTPUT DRIVER, THE CONTENTS OF R3:R1

This routine is used to display HEX numbers, assuming that they are in registers R3:R1. If R3 = 0, leading zeros can be supressed by setting bit 54 (36H) before calling this routine. If bit 54 (36H) is cleared when this routine is called, the driver will always output four hex digits followed by the character H. This routine always outputs a space character (20H) to the console device, before any hex digits are output. BIT 54 (36H) is bit 6 of internal RAM location 38.

    MCS-51 MACRO ASSEMBLER

    ISIS-II MCS-51 MACRO ASSEMBLER V1.0
    OBJECT MODULE PLACED IN:F4:DEMO HEX
    ASSEMBLER INVOKED BY: ASM51 :F4:DEMO

    LOC OBJ             LINE  SOURCE

                           1  ; *********************************************************************
                           2  ;
                           3  ; The following is an example of a program that uses the new OPPYTES
                           4  ; available in version 1.1 of MCS BASIC-52. This code is by no means
                           5  ; optimized but it is meant to demonstrate how the user can define
                           6  ; "customized" commands and statements in version 1.1 of MCS BASIC-52.
                           7  ;
                           8  ; The new command defined here is DISPLAY. What it does is display a
                           9  ; region of external data memory to the console device. The syntax
                          1O  ; for this statement is:
                          11  ;
                          12  ;             DISPLAY [expr], [expr]
                          13  ;
                          14  ; Where the first expression is the starting address and the last
                          15  ; expression is the ending address. In this example the DISPLAY is
                          16  ; treated like a command which means that it cannot be executed in
                          17  ; RUN mode.
                          18  ;
                          19  ; The output for the DlSPLAY command is as follows:
                          20  ;
                          21  ; ADDRESS then 16 Bytes of Characters i. e.
                          22  ;
                          23  ; 1000H 00H 22H 33H 27H . . . . . . . .
                          24  ;
                          25  ; Now on to the program.
                          26  ;**********************************************************************
                          27
    2002                  28          ORG     2002H
                          29
    2002 5A               30          DB      5AH             ; Tell basic that expanslon option is
                          31                                  ; present
    2048                  32          ORG     2048H
                          33
    2048 D22D             34          SETB    45              ; Set the bit that sags so
    204A 22               35          RET
                          36
    2070                  37          ORG     2070H           ; Set up DPTR to Jump table
                          38
    2070 90207C           39          MOV     DPTR,#VECTOR_TABLE
    2073 22               40          RET
                          41
    2078                  42          ORG     2078H           ; Set up DPTR to expansion table
                          43
    2078 90207E           44          MOV     DPTR,#USER_TABLE
    2078 22               45          RET
                          46
                          47  VECTOR TABLE:
                          48
    207C 2087             49          DW      DO_DISPLAY      ; This is the address of DISPLAY
                          50
                          51  USER TABLE:
                          52
    207E 10               53          DB      10H             ; Token for Display
    207F 44495350         54          DB      'DISPLAY'       ; ASCII for display
    2083 4C4159
    2086 FF               55          DB      0FFH            ; End of table (short table)
                          56
                          57
                          58
                          59  DO DISPLAY:
                          60
    2087 302F63           61          JNP     47,DUMMY        ; make sure that MCS BASIC-52 is in
                          62                                  ; the command mode. Bit 47 is set
                          63                                  ; if it is.
                          64
    208A 7439             65          MOV     A,#57           ; Evaluate the first expression after
    208C 120030           66          LCALL   30H             ; the keyword dlsplay, MCS BASIC-52
                          67                                  ; will handle any errors. The value
                          68                                  ; of the expression will be on the
                          69                                  ; Argument Stack.
                          70
    208F 7440             71          MOV     A,#64           ; Get the character after the expression
    2091 120030           72          LCALL   30H             ; and bump the BASIC text pointer
                          73
    2094 B42C6A           74          CJNE    A,#',',C_ERROR  ; Make sure it is a comma, if not do an
                          79                                  ; error
                          76
    2097 7439             77          MOV     A,#57           ; Evaluate the next expression (the
    2099 120030           78          LCALL   30H             ; ending address) and put it on the
                          79                                  ; Argument Stack
                          80
    209C 7401             81          MOV     A,#1            ; Convert the last expression (the
    209E 120030           82          LCALL   30H             ; ending address) on the stack to
                          83                                  ; an integer and put it in R3:R1
                          84
    20A1 8918             85          MOV     18H,R1          ; Save the endlng address in the user
    20A3 8B19             86          MOV     19H,R3          ; reserved locations 18H and 19H. This
                          87                                  ; is reserved as register bank 3
                          88
    20A5 7401             89          MOV     A,#1            ; Convert the first expression (the
    20A7 120030           90          LCALL   30H             ; starting address) on the stack to
                          9l                                  ; an Integer and put it in R3:R1
                          92
    20AA 891A             93          MOV     1AH.R1          ; Save the starting address in the user
    20AC 8B1B             94          MOV     1BH.R3          ; reserved locations 1AH and 18H
                          95
                          96                                  ; Now everythlng is set up to loop
                          97
    20AE C3               98  LOOP1:  CLR     C               ; Check to make sure that the starting
    20AF E518             99          MOV     A,18H           ; or current address is <= the ending
    20B1 951A            100          SUB8    A,1AH           ; address
    20B3 E519            101          MOV     A,19H
    20B5 951B            102          SUBB    A,1BH
    20B7 5004            103          JNC     LOOP2           ; If the carry is set, it's over
    20B9 E4              104          CLR     A               ; Go to the command mode
    20BA 020030          105          LJMP    30H             ; (if display was a statement instead
                         106                                  ; of a command. this routine would
                         107                                  ; exit with a RET)
                         108
    20BD 7407            109  LOOP2:  MOV     A,#7            ; Do a carriage return, line feed
    20BF 120030          110          LCALL   30H
                         111
    20C2 A91A            112          MOV     R1.1AH          ; Output the Starting address
    20C4 AB1B            113          MOV     R3.18H
                         114
    20C6 C236            115          CLR     36H             ; Don't supress leading zeros
    20C8 7498            116          MOV     A,#98H
    20CA 120030          117          LCALL   30H
                         118
    20CD 851A82          119   LOOP3: MOV     DPL,1AH         ; Now, set up to read 16 bytes
    20D0 851B83          120          MOV     DPH,1BH         ; put address in DPTR
                         121
    20D3 E0              122          MOVX    A,@DPTR         ; Read the byte in external RAM
    20D4 A3              123          INC     DPTR            ; Bump to the next location
                         124
    20D5 85821A          125          MOV     1AH,DPL         ; Save the Address
    20D8 85831B          126          MOV     1BH,DPH
                         127
    20DB F9              128          MOV     R1,A            ; Output the byte
    20DC 7B00            l29          MOV     R3,#0           ; The high byte is always zero
    20DE D236            130          SETB    36H             ; Supress leading Zeros
    20E0 7498            131          MOV     A,#98H
    20E2 120030          132          LCALL   30H
                         133
    20E5 E51A            134          MOV     A,1AH           ; Check to see if on a 16 byte boundry
    20E7 540F            135          ANL     A,#0FH
    20E9 70E2            136          JNZ     LOOP3           ; Loop until on a 16 Byte Boundry
    20EB 80C1            137          SJMP    LOOP1
                         138
                         139   DUMMY:
                         140
    20ED 7407            141          MOV     A,#7            ; Do a carriage return-line feed
    20EF 120030          142          LCALL   30H
                         143
    20F2 7B21            144          MOV     R3,#HIGH D_MSG  ; Display the error message
    20F4 7915            145          MOV     R1,#LOW D_MSG
    20F6 D234            146          SETB    52              ; Print from ROM
    20F8 7406            147          MOV     A,#6
    20FA 120030          148          LCALL   30H
    20FD E4              149          CLR     A               ; Go back to the command mode
    20FE 020030          150          LJMP    30H
                         151
                         152   C_ERROR:
                         153
    2101 7407            154          MOV     A,#7            ; Do what we did before
    2103 120030          155          LCALL   30H
                         156
    2106 7B21            157          MOV     R3,#HIGH C_MSG
    2108 793B            158          MOV     R1,#LOW C_MSG
    210A D234            159          SETB    52
    210C 7406            160          MOV     A,#6
    210E 120030          161          LCALL   30H
    2111 E4              162          CLR     A
    2112 020030          163          LJMP    30H
                         164
    2115 44495350        165   D_MSG: DB      "DISPLAY IS A COMMAND, NOT A STATEMENT"
    2119 4C415920
    211D 49532041
    2121 20434F4D
    2125 4D414E44
    2129 2C204E4F
    212D 54204120
    2131 53544154
    2135 454D454E
    2139 5422
                         166
    213B 594F5520        167   C_MSG: DB      "YOU NEED A COMMA TO MAKE DISPLAY WORK"
    213F 4E454544
    2143 20412043
    2147 4F4D4D41
    214B 20544F20
    214F 4D414B45
    2153 20444953
    2157 504C4159
    215B 20574F52

    215F 4B22
                         168
                         169          END

    ASSEMBLY COMPLETE. NO ERRORS FOUND
    (that'- all it takes)

9.7 INTERRUPTS

Interrupts can be handled by MCS BASIC-52 in two distinct ways. The first, which has already been discussed, allows statements in an MCS BASIC-52 program to perform the required interrupt routine. The ONTIME and ONEX1 statements enable this particular interrupt mode. Additionally, setting bit 26.1H permits external interrupt 0 to act as a "fake" DMA input and the details of this feature are in the bells, whistles and anomalies section of this manual. The second method of handling interrupts in MCS BASIC-52 allows the programmer to write assembly language routines to perform the interrupt task. This method yields a much faster interrupt response time, but, the programmer must exercise some caution.

All interrupt vectors on the MCS BASIC-52 device are "mirrored" to external program memory locations 4003H through 402BH inclusive. The only MCS BASIC-52 statements that enable the interrupts on the 8052AH are the CLOCK1 and the ONEX1 statements. If interrupts are not enabled by these statements, BASIC assumes that the user is providing the interrupt routine in assembly language. The vectors for the various interrupts are as follows:

    LOCATION    INTERRUPT

    4003H       EXTERNAL INTERRUPT 0
    400BH       TIMER 0 OVERFLOW
    4013H       EXTERNAL INTERRUPT 1
    401BH       TIMER 1 OVERFLOW
    4023H       SERIAL PORT
    402BH       TIMER 2 OVERFLOW/EXTERNAL INTERRUPT 2

The programmer can enable interrupts in MCS BASIC-52 by using the statement IE = IE .OR. XXH, where XX enables the appropriate interrupts. The bits in the interrupt register (IE) on the 8052AH are defined as follows:

    BIT    7        6        5       4       3       2       1       0
          EA        X       ET2      ES     ET1     EX1     ET0     EX0

         ENABLE    UNDE-  TIMER2    SERIAL TIMER1   EXT1    TIMER0  EXT 0
         ALL       FINED            PORT

Interrupts are enabled when the appropriate bits in the IE register are set to a one. Details of the 8052AH interrupt structure are available in the microcontroller users manual available from INTEL.

IMPORTANT NOTE!!

Before MCS BASIC-52 vectors to the user interrupt locations just described, the procesor status word (PSW) is pushed onto the stack. So, the user does not have to save the PSW in the assembly language interrupt routine!!! However, the user must pop the PSW before returning from the interrupt.

VERY IMPORTANT NOTE!!!

If the user is running some interrupt driven "background" routine while MCS BASIC-52 is running a program, the user must not call any of the assembly language routines available in the MCS BASIC-52 device. The only way the routines in the MCS BASIC-52 device can be accessed is when the CALL statement in MCS BASIC-52 is used to transfer control to the users assembly language program. The reason for this is that the MCS BASIC-52 interpreter must be in a "known" state before the user can call the routines available in the MCS BASIC-52 device and a "random" interrupt does not guarantee that the interpreter is in this known state. The user should use register bank 3 to handle interrupt routines in assembly language.

9.8 RESOURCE ALLOCATION

Specific statements in MCS BASIC-52 require the use of certain hardware features on the device. If the user wants to use these hardware features for interrupt driven routines, conflicts between BASIC and the assembly language routine may occur. To avoid these potential conflicts, the programmer needs to know what hardware features are used by MCS BASIC-52. The following is a list of the commands and/or statements that use the hardware features on the 8052AH.

CLOCK1 | uses TIMER/COUNTER 0 in the 13 bit 8048 mode
PWM | uses TIMER/COUNTER1 in the 16 bit mode
LIST# | uses TIMER/COUNTER1 to generate baud rate in 16 bit mode
PRINT# | same as LIST#
PROG | uses TIMER/COUNTER1 for programming pulse
ONEX1 | uses EXTERNAL INTERRUPT 1

In addition, TIMER/COUNTER 2 is used to generate the baud rate for the serial port. What the preceding list means is that if CLOCK1, PWM, ONEX1, LIST#, PRINT#, and PROG commands/statements are used by the programmer, the user may not use the associated TIMER/COUNTER or external interrupt pins for an assembly language routine.

MCS BASIC-52 initializes the TIMER/COUNTER modes by writing a 244 (0F4H), 16 (10H), and 52 (34H) to the TCON, TMOD, and T2CON registers respectively. These registers are initialized only during the reset initialization sequence, and MCS BASIC-52 assumes that these registers are never changed. So, if the user changes the contents of TCON, TMOD, or T2CON, something funny and/or disastrous is bound to happen if the statements/commands listed above are executed. If the user does not execute any of the previously mentioned statements or commands, the user is free to use the interrupts in any way suitable to the application.