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;
}
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"
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";
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
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
then at the beginning of the main function we find
int main(void) {
volatile int32_t accumulator = 0;
int16_t i;
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
for volatile int32_t accumulator = 0
3. Loop and Test
for (i = 0; i < 10; i++) {
if (i == 5) {
accumulator += 100;
} else {
accumulator += i;
}
}
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
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
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;
}
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
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
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;
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
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;
}
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
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



Top comments (0)