DEV Community

ddupard
ddupard

Posted on

8051 What does SDCC do part 2 ?

1. Introduction and Problem Statement

A good way to learn what a compiler really does when transforming a C source code into a binary is to disassemble the binary and compare it with the C source code. It is especially true for 8 bits microcontrollers like the 8051.

In order to test SDCC we are going to use the following C source code.

/* ========================================================================== *
 * Universal Test Corpus - Heterogeneous Architecture Analysis          *
 * ========================================================================== */


#include <stdint.h>

// 1. Global variables (testing absolute/relative addressing modes)
volatile uint32_t global_var_32 = 0xDEADBEEF;
volatile uint8_t  global_var_8  = 0x42;
const    char     string_const[] = "TARGET_STRING";

// 2. Function with parameter passing and local variables (stack / Frame Pointer test)
int32_t callee_function(int16_t a, int16_t b) {
    volatile int32_t local_result = 0;

    // Basic and mixed arithmetic operations (8, 16, 32 bits)
    local_result += (int32_t)(a * b);
    local_result -= (int32_t)(a / (b | 1)); // Avoid division by zero

    // Shift tests and logical operations (highly variable depending on ISAs)
    local_result = (local_result << 2) ^ 0x55AA55AA;
    local_result = (local_result >> 1) | (int32_t)global_var_8;

    return local_result;
}

// 3. Main function grouping complex control flows
int main(void) {
    volatile int32_t accumulator = 0;
    int16_t i;

    // Loop test (Conditional jumps, decrement, comparison tests)
    for (i = 0; i < 10; i++) {
        if (i == 5) {
            accumulator += 100;
        } else {
            accumulator += i;
        }
    }

    // Multiple branching test (Switch / Jump Table or cascaded if-else)
    switch (global_var_8) {
        case 0x10:
            accumulator += 10;
            break;
        case 0x20:
            accumulator += 20;
            break;
        default:
            accumulator -= 5;
            break;
    }

    // Function call (Stack management, save registers Link Register/PC)
    accumulator += callee_function((int16_t)accumulator, 3);

    // Pointer and indirect memory access test
    volatile uint32_t *ptr = (volatile uint32_t *)&global_var_32;
    *ptr = (uint32_t)accumulator;

    // Terminal infinite loop (classic for raw binaries / microcontrollers)
    while (1) {
        accumulator ^= *ptr;
    }

    return 0;
}
Enter fullscreen mode Exit fullscreen mode

To compile it, we will use SDCC which produces an Intel HEX file. This file will be transformed in a ROM file using either objcopy or makebin (see below).

sdcc  "$SRC/test1.c" -o "8/test1_8051" 
objcopy -I ihex -O binary "8/test1_8051" "8/bin/test1_8051_bin" 
makebin -p "8/test1_8051" "8/bin/test1_8051.rom"
Enter fullscreen mode Exit fullscreen mode

Moreover, to simulate the 8051, I use the MCU 8051 IDE (command mcu8051ide).

In our first article, we studied the stub generated by SDCC. In this article we will study the main function except what is related to the call of callee_function.

This C file is particularly interesting, because in a small source code we have a lot of different cases (for example, some of the variables have a 32 bits size).

2. Variable Initialization

Before any instruction related to our program being executed, the state of the 8051 is the following

in our C source code , there are 3 global variables

// 1. Global variables (testing absolute/relative addressing modes)
volatile uint32_t global_var_32 = 0xDEADBEEF;
volatile uint8_t  global_var_8  = 0x42;
const    char     string_const[] = "TARGET_STRING";
Enter fullscreen mode Exit fullscreen mode

The first 2 global variables ( global_var_32 and global_var_8 ) are initialized by the following code

  005F 7508EF       MOV 8h, #0EFh
  0062 7509BE       MOV 9h, #0BEh
  0065 750AAD       MOV 0Ah, #0ADh
  0068 750BDE       MOV 0Bh, #0DEh
  006B 750C42       MOV 0Ch, #42h
Enter fullscreen mode Exit fullscreen mode

See how the memory has changed

and the third one being a constant, SDCC adds it at the end of the program in ROM

  02CA 54           DB 054h ; 'T'
  02CB 41           DB 041h ; 'A'
  02CC 52           DB 052h ; 'R'
  02CD 47           DB 047h ; 'G'
  02CE 45           DB 045h ; 'E'
  02CF 54           DB 054h ; 'T'
  02D0 5F           DB 05Fh ; '_'
  02D1 53           DB 053h ; 'S'
  02D2 54           DB 054h ; 'T'
  02D3 52           DB 052h ; 'R'
  02D4 49           DB 049h ; 'I'
  02D5 4E           DB 04Eh ; 'N'
  02D6 47           DB 047h ; 'G'
  02D7 00           DB 000h 
END
Enter fullscreen mode Exit fullscreen mode

then at the beginning of the main function we find

int main(void) {
    volatile int32_t accumulator = 0;
    int16_t i;

Enter fullscreen mode Exit fullscreen mode

which corresponds to

L0005:
  0147 E4           CLR A
  0148 F513         MOV 13h, A
  014A F514         MOV 14h, A
  014C F515         MOV 15h, A
  014E F516         MOV 16h, A
Enter fullscreen mode Exit fullscreen mode

for volatile int32_t accumulator = 0

3. Loop and Test

for (i = 0; i < 10; i++) {
        if (i == 5) {
            accumulator += 100;
        } else {
            accumulator += i;
        }
    }
Enter fullscreen mode Exit fullscreen mode

The assembly code which corresponds to the C code above is below.

L0005:
  0147 E4           CLR A
  0148 F513         MOV 13h, A
  014A F514         MOV 14h, A
  014C F515         MOV 15h, A
  014E F516         MOV 16h, A
  0150 7E00         MOV R6, #0h
  0152 7F00         MOV R7, #0h
L0009:
  0154 8E04         MOV 4h, R6
  0156 8F05         MOV 5h, R7
  0158 BC051A       CJNE R4, #5h, L0006
  015B BD0017       CJNE R5, #0h, L0006
  015E 7464         MOV A, #64h
  0160 2513         ADD A, 13h
  0162 F513         MOV 13h, A
  0164 E4           CLR A
  0165 3514         ADDC A, 14h
  0167 F514         MOV 14h, A
  0169 E4           CLR A
  016A 3515         ADDC A, 15h
  016C F515         MOV 15h, A
  016E E4           CLR A
  016F 3516         ADDC A, 16h
  0171 F516         MOV 16h, A
  0173 801D         SJMP L0007

L0006:
  0175 8E02         MOV 2h, R6
  0177 EF           MOV A, R7
  0178 FB           MOV R3, A
  0179 33           RLC A
  017A 95E0         SUBB A, ACC
  017C FC           MOV R4, A
  017D FD           MOV R5, A
  017E EA           MOV A, R2
  017F 2513         ADD A, 13h
  0181 F513         MOV 13h, A
  0183 EB           MOV A, R3
  0184 3514         ADDC A, 14h
  0186 F514         MOV 14h, A
  0188 EC           MOV A, R4
  0189 3515         ADDC A, 15h
  018B F515         MOV 15h, A
  018D ED           MOV A, R5
  018E 3516         ADDC A, 16h
  0190 F516         MOV 16h, A
L0007:
  0192 0E           INC R6
  0193 BE0001       CJNE R6, #0h, L0008
  0196 0F           INC R7
L0008:
  0197 8E04         MOV 4h, R6
  0199 8F05         MOV 5h, R7
  019B C3           CLR C
  019C EC           MOV A, R4
  019D 940A         SUBB A, #0Ah
  019F ED           MOV A, R5
  01A0 6480         XRL A, #80h
  01A2 9480         SUBB A, #80h
  01A4 40AE         JC L0009
Enter fullscreen mode Exit fullscreen mode

It is quite complicated essentially because i is a 16 bits integer and the accumulator variable is a 32 bits integer. And since there is no native, general-purpose 16-bit register easy to manipulate for a simple counting loop. The compiler must simulate the variable i (which is an int16_t in our code) by combining multiple registers (such as R6 and R7), which significantly weighs down every increment and loop-end test.
The compiler must also must make heavy generation of comparisons (CJNE) and jumps to handle control structures and nested if/else statements and laborious manipulation of 32-bit types (accumulator += 100 or += i) on an 8-bit machine, where each addition requires propagating carries byte by byte across multiple internal memory addresses.

  017E EA           MOV A, R2
  017F 2513         ADD A, 13h
  0181 F513         MOV 13h, A
  0183 EB           MOV A, R3
  0184 3514         ADDC A, 14h
  0186 F514         MOV 14h, A
  0188 EC           MOV A, R4
  0189 3515         ADDC A, 15h
  018B F515         MOV 15h, A
  018D ED           MOV A, R5
  018E 3516         ADDC A, 16h
  0190 F516         MOV 16h, A
Enter fullscreen mode Exit fullscreen mode

The generated assembly code is therefore verbose, packed with intermediate calls and conditional jumps (JC, CJNE, SJMP). It is a textbook case showing why, on 4 KB ROM microcontrollers, critical developers often end up rewriting critical loops or mathematical functions directly in hand-optimized assembly to avoid the bloat of C compiler-generated code.

An optimized assembly code, should not use more than 6 registers for this loop: R0, R1, R2, R3 for the 32 bits variable
( accumulator ) and R4,R5 for the 16 bits variable ( i ) and no save in the memory. Even more, the optimized assembly code should use only 5 registers because i could be a uint8_t instead of a uint16_t. There is no need for i to be a uint16_t.

The code generated by SDCC uses memory to store the 32 bits variable (addresses 13h,14h,15h, 16h) and for the 16 bits variable (adresses 4h,5h) and then it constantly moves data from the memory to the registers and vice versa which is really really inefficient.

See below for the state of the processor after the loop

4. Switch

 // Multiple branching test (Switch / Jump Table or cascaded if-else)
    switch (global_var_8) {
        case 0x10:
            accumulator += 10;
            break;
        case 0x20:
            accumulator += 20;
            break;
        default:
            accumulator -= 5;
            break;
    }
Enter fullscreen mode Exit fullscreen mode

The code above corresponds to the code below. It is pretty straightforward since global_var_8 is stored at address 0Ch (see 4. variable initialization).

  01A6 AF0C         MOV R7, 0Ch
  01A8 BF1002       CJNE R7, #10h, L0010
  01AB 8005         SJMP L0011

L0010:
  01AD BF2030       CJNE R7, #20h, L0023
  01B0 8017         SJMP L0024

L0011:
  01B2 740A         MOV A, #0Ah
  01B4 2513         ADD A, 13h
  01B6 F513         MOV 13h, A
  01B8 E4           CLR A
  01B9 3514         ADDC A, 14h
  01BB F514         MOV 14h, A
  01BD E4           CLR A
  01BE 3515         ADDC A, 15h
  01C0 F515         MOV 15h, A
  01C2 E4           CLR A
  01C3 3516         ADDC A, 16h
  01C5 F516         MOV 16h, A
  01C7 802F         SJMP L0012

L0024:
  01C9 7414         MOV A, #14h
  01CB 2513         ADD A, 13h
  01CD F513         MOV 13h, A
  01CF E4           CLR A
  01D0 3514         ADDC A, 14h
  01D2 F514         MOV 14h, A
  01D4 E4           CLR A
  01D5 3515         ADDC A, 15h
  01D7 F515         MOV 15h, A
  01D9 E4           CLR A
  01DA 3516         ADDC A, 16h
  01DC F516         MOV 16h, A
  01DE 8018         SJMP L0012

L0023:
  01E0 E513         MOV A, 13h
  01E2 24FB         ADD A, #0FBh
  01E4 F513         MOV 13h, A
  01E6 E514         MOV A, 14h
  01E8 34FF         ADDC A, #0FFh
  01EA F514         MOV 14h, A
  01EC E515         MOV A, 15h
  01EE 34FF         ADDC A, #0FFh
  01F0 F515         MOV 15h, A
  01F2 E516         MOV A, 16h
  01F4 34FF         ADDC A, #0FFh
  01F6 F516         MOV 16h, A
Enter fullscreen mode Exit fullscreen mode

Once again since the variable accumulator is a 32 bits integer, there is a carry propagation.
The only little trick is how the line accumulator -=5 is translated. It's calculated by adding #0FBh in the following instruction

01E2 24FB       ADD A, #0FBh
Enter fullscreen mode Exit fullscreen mode

5. Memory and access tests

  // Pointer and indirect memory access test
    volatile uint32_t *ptr = (volatile uint32_t *)&global_var_32;
    *ptr = (uint32_t)accumulator;
Enter fullscreen mode Exit fullscreen mode

The code above is translated by SDCC in the lines below

  0222 AC13         MOV R4, 13h
  0224 AD14         MOV R5, 14h
  0226 AE15         MOV R6, 15h
  0228 AF16         MOV R7, 16h
  022A 8C08         MOV 8h, R4
  022C 8D09         MOV 9h, R5
  022E 8E0A         MOV 0Ah, R6
  0230 8F0B         MOV 0Bh, R7
Enter fullscreen mode Exit fullscreen mode

Nothing much to say.
The accumulator variable is stored at addresses 13h,14h,15h,16h. and is sent to adresses 8h,9h,0Ah,0Bh which are the precise adresses of global_var_32. The compiler is quite clever since it automatically sees that ptr as the exact same adress than global_var_32, so all this block is equivalent to a transfer of data from the accumator variable to global_var_32

6. Terminal and infinite loop

    // Terminal infinite loop (classic for raw binaries / microcontrollers)
    while (1) {
        accumulator ^= *ptr;
    }
Enter fullscreen mode Exit fullscreen mode

The code above is translated by SDCC in the lines below

L0014:
  0232 AC08         MOV R4, 8h
  0234 AD09         MOV R5, 9h
  0236 AE0A         MOV R6, 0Ah
  0238 AF0B         MOV R7, 0Bh
  023A EC           MOV A, R4
  023B 6213         XRL 13h, A
  023D ED           MOV A, R5
  023E 6214         XRL 14h, A
  0240 EE           MOV A, R6
  0241 6215         XRL 15h, A
  0243 EF           MOV A, R7
  0244 6216         XRL 16h, A
  0246 80EA         SJMP L0014
Enter fullscreen mode Exit fullscreen mode

pretty straightforward

7. Conclusion

This example is a textbook case demonstrating that writing standard C without regard for the target model on an 8-bit microcontroller leads to heavy and slow object code. The constant data shuttling between internal memory and registers (MOV 13h, A, etc.) illustrates why, back then, low-level developers invariably ended up bypassing the compiler to rewrite critical portions directly by hand.

The 8051, being an 8-bit chip, may seem uninteresting at first glance in a world dominated by 32-bit and 64-bit processors, but it remains the most widely used microcontroller in the world, and without knowing it, you find it in almost everything around you (from your television remote control to washing machines, microwave ovens, fridges, smart cards, car key fobs, and power supplies).

8. The full disassembly code

CSEG AT 0000h
  0000 020006       LJMP L0001

L0004:
  0003 020147       LJMP L0005

L0001:
  0006 758118       MOV SP, #18h
  0009 1202C6       LCALL L0002
  000C E582         MOV A, DPL
  000E 6003         JZ L0003
  0010 020003       LJMP L0004

L0003:
  0013 7900         MOV R1, #0h
  0015 E9           MOV A, R1
  0016 4400         ORL A, #0h
  0018 601B         JZ L0025
  001A 7A00         MOV R2, #0h
  001C 9002D8       MOV DPTR, #02D8h
  001F 7801         MOV R0, #1h
  0021 75A000       MOV P2, #0h
L0027:
  0024 E4           CLR A
  0025 93           MOVC A, @A+DPTR
  0026 F2           MOVX @R0, A
  0027 A3           INC DPTR
  0028 08           INC R0
  0029 B80002       CJNE R0, #0h, L0026
  002C 05A0         INC P2
L0026:
  002E D9F4         DJNZ R1, L0027
  0030 DAF2         DJNZ R2, L0027
  0032 75A0FF       MOV P2, #0FFh
L0025:
  0035 E4           CLR A
  0036 78FF         MOV R0, #0FFh
L0028:
  0038 F6           MOV @R0, A
  0039 D8FD         DJNZ R0, L0028
  003B 7800         MOV R0, #0h
  003D E8           MOV A, R0
  003E 4400         ORL A, #0h
  0040 600A         JZ L0029
  0042 7901         MOV R1, #1h
  0044 75A000       MOV P2, #0h
  0047 E4           CLR A
L0030:
  0048 F3           MOVX @R1, A
  0049 09           INC R1
  004A D8FC         DJNZ R0, L0030
L0029:
  004C 7800         MOV R0, #0h
  004E E8           MOV A, R0
  004F 4400         ORL A, #0h
  0051 600C         JZ L0031
  0053 7900         MOV R1, #0h
  0055 900001       MOV DPTR, #0001h
  0058 E4           CLR A
L0032:
  0059 F0           MOVX @DPTR, A
  005A A3           INC DPTR
  005B D8FC         DJNZ R0, L0032
  005D D9FA         DJNZ R1, L0032
L0031:
  005F 7508EF       MOV 8h, #0EFh
  0062 7509BE       MOV 9h, #0BEh
  0065 750AAD       MOV 0Ah, #0ADh
  0068 750BDE       MOV 0Bh, #0DEh
  006B 750C42       MOV 0Ch, #42h
  006E 020003       LJMP L0004

L0013:
  0071 AE82         MOV R6, DPL
  0073 AF83         MOV R7, DPH
  0075 E4           CLR A
  0076 F50F         MOV 0Fh, A
  0078 F510         MOV 10h, A
  007A F511         MOV 11h, A
  007C F512         MOV 12h, A
  007E 850D17       MOV 17h, 0Dh
  0081 850E18       MOV 18h, 0Eh
  0084 8E82         MOV DPL, R6
  0086 8F83         MOV DPH, R7
  0088 C007         PUSH 7h
  008A C006         PUSH 6h
  008C 120248       LCALL L0015
  008F AC82         MOV R4, DPL
  0091 AD83         MOV R5, DPH
  0093 D006         POP 6h
  0095 D007         POP 7h
  0097 ED           MOV A, R5
  0098 33           RLC A
  0099 95E0         SUBB A, ACC
  009B FB           MOV R3, A
  009C FA           MOV R2, A
  009D EC           MOV A, R4
  009E 250F         ADD A, 0Fh
  00A0 F50F         MOV 0Fh, A
  00A2 ED           MOV A, R5
  00A3 3510         ADDC A, 10h
  00A5 F510         MOV 10h, A
  00A7 EB           MOV A, R3
  00A8 3511         ADDC A, 11h
  00AA F511         MOV 11h, A
  00AC EA           MOV A, R2
  00AD 3512         ADDC A, 12h
  00AF F512         MOV 12h, A
  00B1 AC0D         MOV R4, 0Dh
  00B3 AD0E         MOV R5, 0Eh
  00B5 7401         MOV A, #1h
  00B7 4C           ORL A, R4
  00B8 F517         MOV 17h, A
  00BA 8D18         MOV 18h, R5
  00BC 8E82         MOV DPL, R6
  00BE 8F83         MOV DPH, R7
  00C0 12028E       LCALL L0016
  00C3 AE82         MOV R6, DPL
  00C5 E583         MOV A, DPH
  00C7 FF           MOV R7, A
  00C8 33           RLC A
  00C9 95E0         SUBB A, ACC
  00CB FD           MOV R5, A
  00CC FC           MOV R4, A
  00CD E50F         MOV A, 0Fh
  00CF C3           CLR C
  00D0 9E           SUBB A, R6
  00D1 F50F         MOV 0Fh, A
  00D3 E510         MOV A, 10h
  00D5 9F           SUBB A, R7
  00D6 F510         MOV 10h, A
  00D8 E511         MOV A, 11h
  00DA 9D           SUBB A, R5
  00DB F511         MOV 11h, A
  00DD E512         MOV A, 12h
  00DF 9C           SUBB A, R4
  00E0 F512         MOV 12h, A
  00E2 E50F         MOV A, 0Fh
  00E4 25E0         ADD A, ACC
  00E6 FC           MOV R4, A
  00E7 E510         MOV A, 10h
  00E9 33           RLC A
  00EA FD           MOV R5, A
  00EB E511         MOV A, 11h
  00ED 33           RLC A
  00EE FE           MOV R6, A
  00EF E512         MOV A, 12h
  00F1 33           RLC A
  00F2 FF           MOV R7, A
  00F3 EC           MOV A, R4
  00F4 2C           ADD A, R4
  00F5 FC           MOV R4, A
  00F6 ED           MOV A, R5
  00F7 33           RLC A
  00F8 FD           MOV R5, A
  00F9 EE           MOV A, R6
  00FA 33           RLC A
  00FB FE           MOV R6, A
  00FC EF           MOV A, R7
  00FD 33           RLC A
  00FE FF           MOV R7, A
  00FF 74AA         MOV A, #0AAh
  0101 6C           XRL A, R4
  0102 F50F         MOV 0Fh, A
  0104 7455         MOV A, #55h
  0106 6D           XRL A, R5
  0107 F510         MOV 10h, A
  0109 74AA         MOV A, #0AAh
  010B 6E           XRL A, R6
  010C F511         MOV 11h, A
  010E 7455         MOV A, #55h
  0110 6F           XRL A, R7
  0111 F512         MOV 12h, A
  0113 E512         MOV A, 12h
  0115 A2E7         MOV C, ACC.7
  0117 13           RRC A
  0118 FF           MOV R7, A
  0119 E511         MOV A, 11h
  011B 13           RRC A
  011C FE           MOV R6, A
  011D E510         MOV A, 10h
  011F 13           RRC A
  0120 FD           MOV R5, A
  0121 E50F         MOV A, 0Fh
  0123 13           RRC A
  0124 FC           MOV R4, A
  0125 A80C         MOV R0, 0Ch
  0127 E4           CLR A
  0128 F9           MOV R1, A
  0129 FA           MOV R2, A
  012A FB           MOV R3, A
  012B E8           MOV A, R0
  012C 4C           ORL A, R4
  012D F50F         MOV 0Fh, A
  012F E9           MOV A, R1
  0130 4D           ORL A, R5
  0131 F510         MOV 10h, A
  0133 EA           MOV A, R2
  0134 4E           ORL A, R6
  0135 F511         MOV 11h, A
  0137 EB           MOV A, R3
  0138 4F           ORL A, R7
  0139 F512         MOV 12h, A
  013B 850F82       MOV DPL, 0Fh
  013E 851083       MOV DPH, 10h
  0141 8511F0       MOV B, 11h
  0144 E512         MOV A, 12h
  0146 22           RET

L0005:
  0147 E4           CLR A
  0148 F513         MOV 13h, A
  014A F514         MOV 14h, A
  014C F515         MOV 15h, A
  014E F516         MOV 16h, A
  0150 7E00         MOV R6, #0h
  0152 7F00         MOV R7, #0h
L0009:
  0154 8E04         MOV 4h, R6
  0156 8F05         MOV 5h, R7
  0158 BC051A       CJNE R4, #5h, L0006
  015B BD0017       CJNE R5, #0h, L0006
  015E 7464         MOV A, #64h
  0160 2513         ADD A, 13h
  0162 F513         MOV 13h, A
  0164 E4           CLR A
  0165 3514         ADDC A, 14h
  0167 F514         MOV 14h, A
  0169 E4           CLR A
  016A 3515         ADDC A, 15h
  016C F515         MOV 15h, A
  016E E4           CLR A
  016F 3516         ADDC A, 16h
  0171 F516         MOV 16h, A
  0173 801D         SJMP L0007

L0006:
  0175 8E02         MOV 2h, R6
  0177 EF           MOV A, R7
  0178 FB           MOV R3, A
  0179 33           RLC A
  017A 95E0         SUBB A, ACC
  017C FC           MOV R4, A
  017D FD           MOV R5, A
  017E EA           MOV A, R2
  017F 2513         ADD A, 13h
  0181 F513         MOV 13h, A
  0183 EB           MOV A, R3
  0184 3514         ADDC A, 14h
  0186 F514         MOV 14h, A
  0188 EC           MOV A, R4
  0189 3515         ADDC A, 15h
  018B F515         MOV 15h, A
  018D ED           MOV A, R5
  018E 3516         ADDC A, 16h
  0190 F516         MOV 16h, A
L0007:
  0192 0E           INC R6
  0193 BE0001       CJNE R6, #0h, L0008
  0196 0F           INC R7
L0008:
  0197 8E04         MOV 4h, R6
  0199 8F05         MOV 5h, R7
  019B C3           CLR C
  019C EC           MOV A, R4
  019D 940A         SUBB A, #0Ah
  019F ED           MOV A, R5
  01A0 6480         XRL A, #80h
  01A2 9480         SUBB A, #80h
  01A4 40AE         JC L0009
  01A6 AF0C         MOV R7, 0Ch
  01A8 BF1002       CJNE R7, #10h, L0010
  01AB 8005         SJMP L0011

L0010:
  01AD BF2030       CJNE R7, #20h, L0023
  01B0 8017         SJMP L0024

L0011:
  01B2 740A         MOV A, #0Ah
  01B4 2513         ADD A, 13h
  01B6 F513         MOV 13h, A
  01B8 E4           CLR A
  01B9 3514         ADDC A, 14h
  01BB F514         MOV 14h, A
  01BD E4           CLR A
  01BE 3515         ADDC A, 15h
  01C0 F515         MOV 15h, A
  01C2 E4           CLR A
  01C3 3516         ADDC A, 16h
  01C5 F516         MOV 16h, A
  01C7 802F         SJMP L0012

L0024:
  01C9 7414         MOV A, #14h
  01CB 2513         ADD A, 13h
  01CD F513         MOV 13h, A
  01CF E4           CLR A
  01D0 3514         ADDC A, 14h
  01D2 F514         MOV 14h, A
  01D4 E4           CLR A
  01D5 3515         ADDC A, 15h
  01D7 F515         MOV 15h, A
  01D9 E4           CLR A
  01DA 3516         ADDC A, 16h
  01DC F516         MOV 16h, A
  01DE 8018         SJMP L0012

L0023:
  01E0 E513         MOV A, 13h
  01E2 24FB         ADD A, #0FBh
  01E4 F513         MOV 13h, A
  01E6 E514         MOV A, 14h
  01E8 34FF         ADDC A, #0FFh
  01EA F514         MOV 14h, A
  01EC E515         MOV A, 15h
  01EE 34FF         ADDC A, #0FFh
  01F0 F515         MOV 15h, A
  01F2 E516         MOV A, 16h
  01F4 34FF         ADDC A, #0FFh
  01F6 F516         MOV 16h, A
L0012:
  01F8 851382       MOV DPL, 13h
  01FB 851483       MOV DPH, 14h
  01FE 750D03       MOV 0Dh, #3h
  0201 750E00       MOV 0Eh, #0h
  0204 120071       LCALL L0013
  0207 AC82         MOV R4, DPL
  0209 AD83         MOV R5, DPH
  020B AEF0         MOV R6, B
  020D FF           MOV R7, A
  020E EC           MOV A, R4
  020F 2513         ADD A, 13h
  0211 F513         MOV 13h, A
  0213 ED           MOV A, R5
  0214 3514         ADDC A, 14h
  0216 F514         MOV 14h, A
  0218 EE           MOV A, R6
  0219 3515         ADDC A, 15h
  021B F515         MOV 15h, A
  021D EF           MOV A, R7
  021E 3516         ADDC A, 16h
  0220 F516         MOV 16h, A
  0222 AC13         MOV R4, 13h
  0224 AD14         MOV R5, 14h
  0226 AE15         MOV R6, 15h
  0228 AF16         MOV R7, 16h
  022A 8C08         MOV 8h, R4
  022C 8D09         MOV 9h, R5
  022E 8E0A         MOV 0Ah, R6
  0230 8F0B         MOV 0Bh, R7
L0014:
  0232 AC08         MOV R4, 8h
  0234 AD09         MOV R5, 9h
  0236 AE0A         MOV R6, 0Ah
  0238 AF0B         MOV R7, 0Bh
  023A EC           MOV A, R4
  023B 6213         XRL 13h, A
  023D ED           MOV A, R5
  023E 6214         XRL 14h, A
  0240 EE           MOV A, R6
  0241 6215         XRL 15h, A
  0243 EF           MOV A, R7
  0244 6216         XRL 16h, A
  0246 80EA         SJMP L0014

L0015:
  0248 E582         MOV A, DPL
  024A 8517F0       MOV B, 17h
  024D A4           MUL AB
  024E C582         XCH A, DPL
  0250 C0F0         PUSH B
  0252 8518F0       MOV B, 18h
  0255 A4           MUL AB
  0256 D0F0         POP B
  0258 25F0         ADD A, B
  025A C583         XCH A, DPH
  025C 8517F0       MOV B, 17h
  025F A4           MUL AB
  0260 2583         ADD A, DPH
  0262 F583         MOV DPH, A
  0264 22           RET

L0019:
  0265 7A10         MOV R2, #10h
  0267 E4           CLR A
  0268 FB           MOV R3, A
  0269 FC           MOV R4, A
L0022:
  026A E582         MOV A, DPL
  026C 25E0         ADD A, ACC
  026E F582         MOV DPL, A
  0270 E583         MOV A, DPH
  0272 33           RLC A
  0273 F583         MOV DPH, A
  0275 EB           MOV A, R3
  0276 33           RLC A
  0277 FB           MOV R3, A
  0278 EC           MOV A, R4
  0279 33           RLC A
  027A FC           MOV R4, A
  027B EB           MOV A, R3
  027C 9517         SUBB A, 17h
  027E F5F0         MOV B, A
  0280 EC           MOV A, R4
  0281 9518         SUBB A, 18h
  0283 4006         JC L0021
  0285 FC           MOV R4, A
  0286 ABF0         MOV R3, B
  0288 438201       ORL DPL, #1h
L0021:
  028B DADD         DJNZ R2, L0022
  028D 22           RET

L0016:
  028E C2D5         CLR F0
  0290 E583         MOV A, DPH
  0292 30E70D       JNB ACC.7, L0017
  0295 D2D5         SETB F0
  0297 E4           CLR A
  0298 C3           CLR C
  0299 9582         SUBB A, DPL
  029B F582         MOV DPL, A
  029D E4           CLR A
  029E 9583         SUBB A, DPH
  02A0 F583         MOV DPH, A
L0017:
  02A2 E518         MOV A, 18h
  02A4 30E70D       JNB ACC.7, L0018
  02A7 B2D5         CPL F0
  02A9 E4           CLR A
  02AA C3           CLR C
  02AB 9517         SUBB A, 17h
  02AD F517         MOV 17h, A
  02AF E4           CLR A
  02B0 9518         SUBB A, 18h
  02B2 F518         MOV 18h, A
L0018:
  02B4 120265       LCALL L0019
  02B7 30D50B       JNB F0, L0020
  02BA E4           CLR A
  02BB C3           CLR C
  02BC 9582         SUBB A, DPL
  02BE F582         MOV DPL, A
  02C0 E4           CLR A
  02C1 9583         SUBB A, DPH
  02C3 F583         MOV DPH, A
L0020:
  02C5 22           RET

L0002:
  02C6 758200       MOV DPL, #0h
  02C9 22           RET

  02CA 54           DB 054h ; 'T'
  02CB 41           DB 041h ; 'A'
  02CC 52           DB 052h ; 'R'
  02CD 47           DB 047h ; 'G'
  02CE 45           DB 045h ; 'E'
  02CF 54           DB 054h ; 'T'
  02D0 5F           DB 05Fh ; '_'
  02D1 53           DB 053h ; 'S'
  02D2 54           DB 054h ; 'T'
  02D3 52           DB 052h ; 'R'
  02D4 49           DB 049h ; 'I'
  02D5 4E           DB 04Eh ; 'N'
  02D6 47           DB 047h ; 'G'
  02D7 00           DB 000h 
END
Enter fullscreen mode Exit fullscreen mode

Top comments (0)