这个只是Keil编译器下的一个巧合罢了,只是刚好被老Hot找出来的。
要实现CY = ACC & 0X80;,最直接的语句就是编译成
MOV C,ACC.7
这条语句执行时间是一个机器周期,但是需要2个字节来保存,但肯定不会破坏ACC;
而要现CY = ACC & 0X80;,直接用RLC左移一位,ACC.7当然就会被移入CY中,所以用
RLC A
的话,也能达到同样的目的,只是这时ACC是变化的(左移了一位)。
而这条语句执行时间也是一个机器周期,但是只需要1个字节来保存,所以在不需保留ACC或者ACC本来就是要移位时,当然就会被编译器优先考虑。
最后,猜测下老Hot发现这个的过程:
我们要移位输出一个字节的每一位是,通常会这样写:
void send(uchar dat)
uchar i;
for(i=0;i<8;i++)
{
PORT=dat&0x80;
dat<<=1;
}
而这时,只要肯观察下Keil的汇编代码,就会发现:Keil很聪明的把它编译成了:
MOV ACC,dat
...
RLC A ;1周期1字节
MOV PORT,C ;2周期2字节
...
Keil太聪明了,直接把
PORT=dat&0x80;
dat<<=1;
编译成了RLC A。而且只要你把for(i=0;i<8;i++)写成for(i=8;i;i--),它还会把循环自动优化成DJNZ!
(Keil的优化确实聪明。当然,这还是设计的人聪明,肯花功夫优化:))
而老Hot的红杏出墙是为了得到用C语句出一对一的汇编的效果,当然会仔细观察编译器的语句对应关系,而要得出RLC A的只要写cy=acc&0x80即可,而不会被编译成MOV C,ACC.7,所以红杏出墙里也就有了对应RLC A的C语句定义。
——虽然cy=acc&0x80的语义并不只是RLC A:lol
|