When developing SS881X/SS880X series chips with keil C51, there will be the following two different sounds for the initialization of some global variables:
First, when defining this global variable, assign the variable a value at the same time, the code is as follows:
char tmp0 = 0x55; // Not Recommended
char tmp1 = 0xAA;
void main(void)
{
while (1);
}
Second, after defining the global variable, assign the variable a value, the code is as follows:
char tmp0;
char tmp1;
void main(void)
{
tmp0 = 0x55; // GOOD
tmp1 = 0xAA;
while (1);
}
So what are the similarities and differences between these two methods for some global variable initialization? Obviously, tmp0 and tmp1 are eventually assigned 0x55 and 0xAA, respectively, so are they really no different? Next, let's look at the size of the code compiled by these two methods, the first compiles 152 bytes, and the second compiles 23 bytes. It is clear that the difference between the two methods is huge.
Next, we need to get to the bottom, starting with the compilation:
Let's take a look at the disassembly of Method 2 first, because its results are more in line with our common sense.
C_STARTUP:
C:0x0000 020003 LJMP C:0003
C:0x0003 787F MOV R0,#0x7F
C:0x0005 E4 CLR A
C:0x0006 F6 MOV @R0,A
C:0x0007 D8FD DJNZ R0,C:0006
C:0x0009 758109 MOV SP(0x81),#tmp1(0x09)
C:0x000C 02000F LJMP main(C:000F)
main:
C:0x000F 750855 MOV tmp0(0x08),#0x55
C:0x0012 7509AA MOV tmp1(0x09),#PDRV0(0xAA)
C:0x0015 80FE SJMP C:0015
You can see that before executing main, there are some instructions, and this code segment is named C_STARTUP, C_STARTUP is actually the entry of the entire program execution, and the address must be 0x0000. Then there is a loop, from 0x0003->0x0007, these instructions actually do one thing, that is, clearing the 00H ~ 7FH address (128 bytes) of RAM, and use the method of indirect addressing (the first 128 bytes of RAM of SS880X/SS881X can be directly addressed or indirectly addressed), and when the 128 bytes of RAM are cleared, initialize the stack pointer register, Then jump to the main function,
In the main function, it directly assigns value to the tmp0 and tmp1 that have been assigned addresses, here is the instruction that directly assigns the constant to the address (MOV direct, #data), these two lines directly initialize the global variable.
So look at the disassembly of Method 1 to see what it did.
C_STARTUP:
C:0x0000 020003 LJMP C:0003
C:0x0003 787F MOV R0,#0x7F
C:0x0005 E4 CLR A
C:0x0006 F6 MOV @R0,A
C:0x0007 D8FD DJNZ R0,C:0006
C:0x0009 758109 MOV SP(0x81),#tmp1(0x09)
C:0x000C 02004A LJMP C_START(C:004A)
C:0x000F 020096 LJMP main(C:0096)
C:0x0012 E4 CLR A
C:0x0013 93 MOVC A,@A+DPTR
C:0x0014 A3 INC DPTR
C:0x0015 F8 MOV R0,A
C:0x0016 E4 CLR A
C:0x0017 93 MOVC A,@A+DPTR
C:0x0018 A3 INC DPTR
C:0x0019 4003 JC C:001E
C:0x001B F6 MOV @R0,A
C:0x001C 8001 SJMP C:001F
C:0x001E F2 MOVX @R0,A
C:0x001F 08 INC R0
C:0x0020 DFF4 DJNZ R7,C:0016
C:0x0022 8029 SJMP C:004D
C:0x0024 E4 CLR A
C:0x0025 93 MOVC A,@A+DPTR
C:0x0026 A3 INC DPTR
C:0x0027 F8 MOV R0,A
C:0x0028 5407 ANL A,#0x07
C:0x002A 240C ADD A,#0x0C
C:0x002C C8 XCH A,R0
C:0x002D C3 CLR C
C:0x002E 33 RLC A
C:0x002F C4 SWAP A
C:0x0030 540F ANL A,#0x0F
C:0x0032 4420 ORL A,#0x20
C:0x0034 C8 XCH A,R0
C:0x0035 83 MOVC A,@A+PC
C:0x0036 4004 JC C:003C
C:0x0038 F4 CPL A
C:0x0039 56 ANL A,@R0
C:0x003A 8001 SJMP C:003D
C:0x003C 46 ORL A,@R0
C:0x003D F6 MOV @R0,A
C:0x003E DFE4 DJNZ R7,C:0024
C:0x0040 800B SJMP C:004D
C:0x0042 0102 AJMP C:0002
C:0x0044 04 INC A
C:0x0045 08 INC R0
C:0x0046 102040 JBC 0x24.0,C:0089
C:0x0049 8090 SJMP C:FFDB
C:0x004B 00 NOP
C:0x004C 8FE4 MOV 0xE4,R7
C:0x004E 7E01 MOV R6,#0x01
C:0x0050 93 MOVC A,@A+DPTR
C:0x0051 60BC JZ C:000F
C:0x0053 A3 INC DPTR
C:0x0054 FF MOV R7,A
C:0x0055 543F ANL A,#0x3F
C:0x0057 30E509 JNB 0xE0.5,C:0063
C:0x005A 541F ANL A,#0x1F
C:0x005C FE MOV R6,A
C:0x005D E4 CLR A
C:0x005E 93 MOVC A,@A+DPTR
C:0x005F A3 INC DPTR
C:0x0060 6001 JZ C:0063
C:0x0062 0E INC R6
C:0x0063 CF XCH A,R7
C:0x0064 54C0 ANL A,#INTCON2(0xC0)
C:0x0066 25E0 ADD A,ACC(0xE0)
C:0x0068 60A8 JZ C:0012
C:0x006A 40B8 JC C:0024
C:0x006C E4 CLR A
C:0x006D 93 MOVC A,@A+DPTR
C:0x006E A3 INC DPTR
C:0x006F FA MOV R2,A
C:0x0070 E4 CLR A
C:0x0071 93 MOVC A,@A+DPTR
C:0x0072 A3 INC DPTR
C:0x0073 F8 MOV R0,A
C:0x0074 E4 CLR A
C:0x0075 93 MOVC A,@A+DPTR
C:0x0076 A3 INC DPTR
C:0x0077 C8 XCH A,R0
C:0x0078 C582 XCH A,DPL(0x82)
C:0x007A C8 XCH A,R0
C:0x007B CA XCH A,R2
C:0x007C C583 XCH A,DPH(0x83)
C:0x007E CA XCH A,R2
C:0x007F F0 MOVX @DPTR,A
C:0x0080 A3 INC DPTR
C:0x0081 C8 XCH A,R0
C:0x0082 C582 XCH A,DPL(0x82)
C:0x0084 C8 XCH A,R0
C:0x0085 CA XCH A,R2
C:0x0086 C583 XCH A,DPH(0x83)
C:0x0088 CA XCH A,R2
C:0x0089 DFE9 DJNZ R7,C:0074
C:0x008B DEE7 DJNZ R6,C:0074
C:0x008D 80BE SJMP C:004D
C:0x008F 0108 AJMP C:0008
C:0x0091 5501 ANL A,0x01
C:0x0093 09 INC R1
C:0x0094 AA00 MOV R2,0x00
4: void main(void)
C:0x0096 80FE SJMP main(C:0096)
Good guys, so much. The author also did not go to see what he was doing one by one, only paid attention to where RAM was initialized, and after single-step debugging, it was found that the instructions for initializing RAM were summarized in the following lines:
C:0x0016 E4 CLR A
C:0x0017 93 MOVC A,@A+DPTR
C:0x0018 A3 INC DPTR
C:0x0019 4003 JC C:001E
C:0x001B F6 MOV @R0,A
The focus is here (MOVC A, @A+DPTR), seeing this instruction, the author guesses: while defining a global variable, the operation of initializing the variable, for the compiler, is actually the initial value that needs to be written to RAM, read out a certain section of the code area in the form of a lookup table, and then write it to RAM. (It can be analogously referred to as read-write XDATA)
So what is the way to argue this, you can combine the compiled BIN file and disassembly, what we want to do is to write 0x55 to 08H of RAM, and write 0xAA to 09H of RAM, so the following disassembly is actually meaningless (and will not run), his role is to make a table, and then put it in a certain address in the code area, and compile this table when running the code, so the amount of code has increased so much.
C:0x008F 0108 AJMP C:0008
C:0x0091 5501 ANL A,0x01
C:0x0093 09 INC R1
C:0x0094 AA00 MOV R2,0x00
If you have the patience to read this, you must have understood the trap of keil C51 when initializing global variables, and finally give a conclusion:
After defining a global variable, be sure to assign the initial value of the variable in the function (such as when initializing) (if the initial value is 0, it does not need to be assigned, and it will be cleared by default when the system starts), rather than when the variable is defined.
Original article, Please mark the attribution when reprinting. SINHMICRO,www.sinhmicro.com。