Hi,
Maybe it is somewhat too special, but consider the following
assembler code which is part of a project using async motor control
by the PWMs of an 80C552. It is, in this case, the service routine
for timer 1 interrupts.
[..pushes..]
mov a,_pwmacc ; 1 get PWM phase-accu, low byte
add a,_phsinc ; 1 add frequency increment
mov _pwmacc,a ; 1 store back
mov a,_pwmacc + 1 ; 1 get PWM phase-accu, high byte
addc a,_phsinc + 1 ; 1 add frequency increment
mov _pwmacc + 1,a ; 1 store back
mov dptr,#_sintab ; 2 get address of sin/cos table
mov a,_pwmacc + 1 ; 1 get high-byte of phase again
movc a,@a+dptr ; 2 get sin value
mov b,_pwampl ; 2 get amplitude
mul ab ; 4 multiply both
mov a,_pwoffs ; 1 get offset in A
add a,b ; 1 add high byte of mult. result
mov PWM0,a ; 1 output new PWM value to hardware
mov a,_pwmacc + 1 ; 1 get high-byte of phase again
add a,#64 ; 1 add 90 degree phase shift
movc a,@a+dptr ; 2 get cos value
mov b,_pwampl ; 2 get amplitude
mul ab ; 4 multiply both
mov a,_pwoffs ; 1 get offset in A
add a,b ; 1 add high byte of mult. result
mov PWM1,A ; 1 output new PWM value to hardware
[..pops..]
(The numbers in the comments denote the number of cycles needed)
Now, consider the following C code doing exactly the same:
#include <reg552.h>
code unsigned char sintab[] = { [..omitted..] };
unsigned int pwmacc;
unsigned int phsinc;
unsigned char pwampl;
unsigned char pwoffs;
void t1intr(void) interrupt 3
{
unsigned char tabadr;
pwmacc += phsinc; /* add frequency to accumulator */
tabadr = pwmacc >> 8; /* use high 8 bits for table offset */
/* multiply table entry with amplitude, use only high 8 bits of
the product. Then, add the offset to correct for zero DC */
PWM0 = pwoffs + (unsigned char)
((unsigned int)(sintab[tabadr] * pwampl) >> 8)
tabadr += 64; /* use 90 deg. shift for 2nd PWM channel */
PWM1 = pwoffs + (unsigned char)
((unsigned int)(sintab[tabadr] * pwampl) >> 8)
}
I ran this through "sdcc -c t1.c", and found the following rules
useful when adding to the peephole-optimizer-defines in
~sdcc/src/mcs51/peeph.def:
replace {
mov %1,a
mov b,%2
mov a,%1
mul ab
mov %1,a
} by {
; Peephole 223 removed move A -> reg -> A
mov b,%2
mul ab
mov %1,a
}
replace {
mov r%1,a
mov r%2,b
mov ar%1,r%2
mov r%2,#0x00
mov a,r%1
} by {
; Peephole 224 removed register acrobatic from >> 8
mov a,b
mov r%1,a
mov r%2,#0x00
}
Even if the code is still not as compact as the direct coded assembler,
one can gain some cycles in time-critical service routines.
I have not verified in which other cases these rules may be applied,
and hope that they do not break anything in other cases.
Look also at the way how sintab is addressed. The use of
"movc a,@a+dptr" can save some code if the array index is an unsigned
character and the array is stored in code space
(well, I admit, a very special case).
Comments are welcome. Keep up the good work !
Regards,
Andreas.
--
Sent through GMX FreeMail - http://www.gmx.net
|