From: Erik P. <epe...@iv...> - 2004-10-29 04:59:05
|
On Thu, 28 Oct 2004, Lon Howze - ID wrote: > 1) Why are parenthesis required around the single statement for while(1) ? > This doesn't work: (compiler warns about Delay_J() being unreachable code) > void main() > { > While(1) > Delay_J(); > } > > This does: > void main() > { > While(1) > { > Delay_J(); > } > } This is because of a problem with the macro definition: #define DELAY_COUNT #29 #define delay_J(); \ _asm \ push acc \ mov a, DELAY_COUNT \ lab1: \ djnz acc, lab1 \ pop acc \ _endasm; So after macro substitution, the preprocessor hands the next stage of the compiler this: void main() { while (1) ; _asm push acc mov a, #29 lab1: djnz acc, lab1 pop acc _endasm; } Because of the excess semicolon at the very beginning of the macro definition, the body of the while loop is a null statement. Since the compiler can tell that the while loop will loop forever, it is warning that the inline assembly following the loop is not reachable. > 2) Why didn't the above code assemble? It looks like the assembler couldn't > resolve the symbol 00102$ which the compiler created. I manually edited the > asm file and changed the '00102$' to 'label1' and it compiled correctly with > the following command: > > asx8051 -jlos orig.asm The problem is that the compiler generated '00102$' is a local label; the scope of a local label extends to any preceeding and following non-local label. The 'lab1' in the macro is in the form of a non-local label, so its definition prevents the jump at the end of the while loop from finding the label defining the start of the while loop. To avoid this problem within inline assembly, you too should use local labels; these are in the form 'nnnnn$' where nnnnn is a non-negative integer. To avoid conflicting with the compiler generated local labels, you should use values less than 100. Since this inline assembly is inside a macro, you really shouldn't use a label at all. If the macro is expanded more than once, your labels will be multiply defined to more than one address. A better implementation of the macro would be: #define DELAY_COUNT #29 #define delay_J() {\ _asm push acc _endasm; \ _asm mov a,DELAY_COUNT _endasm; \ _asm djnz acc,.-2 _endasm; \ _asm pop acc _endasm; } or (avoiding the problem with # by disabling the preprocessor within inline assembly code): #pragma preproc_asm - #define delay_J() {\ _asm push acc _endasm; \ _asm mov a,#29 _endasm; \ _asm djnz acc,.-2 _endasm; \ _asm pop acc _endasm; } The '.-2' specifies the offset to the first byte of the djnz instruction relative to its last byte (where the offset is stored). Also, the _asm ... _endasm pairs on each line ensure that the assembler will see each instruction on its own line, rather than run together. It is accidental that the assembler currently accepts multiple instructions on one line like this, and may be rejected in the future since it really confuses the peephole optimizer. Erik |