我有一些函数设计用来处理1-256个字节,在嵌入式C平台上运行,其中传递一个字节比传递一个int(一条指令对三条指令)快得多,也更紧凑,首选的编码方式是什么:
-
接受int,如果为零则提前退出,否则将count值的LSB复制到无符号字符中,并在do{}while(--count);循环中使用它(参数值256将转换为0,但将运行256次)
-
接受一个无符号字符,如果为0,则提前退出,并具有256字节的函数的特殊版本(这些情况将提前知道)。
-
-
有一个类似于上面的函数,但是通过包装器函数调用它,包装器函数的行为是(0-255)和(256)。
-
有一个类似于上面的函数,但是通过包装器宏调用它,包装器宏的行为是(0-255)和(256)。
当系统繁忙时,预期函数的内环可能代表处理器执行时间的15%-30%;有时用于小字节数,有时用于大字节数。该函数使用的内存芯片有一个事务开销,我更喜欢让我的内存访问函数在内部执行启动事务/执行事务/结束事务序列。
最有效的代码是简单地接受一个无符号字符,并将参数值0视为执行256字节的请求,依靠调用方避免任何意外尝试读取0字节。不过,这似乎有点危险。其他人在嵌入式系统上处理过这样的问题吗?他们是怎么处理的?
编辑
该平台是一个PIC18Fxx(128K代码空间;3.5K RAM),连接到一个SPI闪存芯片;如果读取的字节数较少,则可能会超出PIC中的读取缓冲区。写入256字节而不是0会损坏闪存芯片中的数据。如果不检查忙状态,PIC的SPI端口被限制为每12个指令次一个字节;如果检查忙状态,则速度会变慢。典型的写事务除了要接收的数据外还需要发送4个字节;读事务需要额外的字节来实现“SPI周转”(访问SPI端口的最快方法是在发送下一个字节之前读取最后一个字节)。
编译器为HiTech PICC-18std。
我通常喜欢HiTech的PICC-16编译器;HiTech似乎把精力从PICC-18std产品转移到了他们的PICC-18pro系列上,该系列的编译时间更慢,似乎需要使用3字节的“const”指针,而不是2字节指针,并且对内存分配有自己的想法。也许我应该多看看PICC-18pro,但当我尝试在PICC-18pro的评估版上编译我的项目时,它不起作用,我也没有弄清楚确切的原因——也许是变量布局不符合我的asm例程——我只是一直使用PICC-18std。
do
{
local_test++;
--lpw;
} while(lpw);
2533 ;newflashpic.c: 792: do
2534 ;newflashpic.c: 793: {
2535 0144A8 2AD9 incf fsr2l,f,c
2536 ;newflashpic.c: 795: } while(--lpw);
2537 0144AA 0E00 movlw low ?_var_test
2538 0144AC 6EE9 movwf fsr0l,c
2539 0144AE 0E01 movlw high ?_var_test
2540 0144B0 6EEA movwf fsr0h,c
2541 0144B2 06EE decf postinc0,f,c
2542 0144B4 0E00 movlw 0
2543 0144B6 5AED subwfb postdec0,f,c
2544 0144B8 50EE movf postinc0,w,c
2545 0144BA 10ED iorwf postdec0,w,c
2546 0144BC E1F5 bnz l242
编译器加载指向变量的指针,甚至不使用LFSR指令(需要两个字),而是使用MOVLW/MOVWF的组合(需要四个字)。然后它使用这个指针进行递减和比较。尽管我承认do{}While(--wordvar);不能产生像do{}While(wordvar--)那样好的代码,但代码比后者实际生成的更好。执行单独的减量和while测试(例如while(--lpw,lpw))会产生合理的代码,但看起来有点难看。后减量运算符可以为倒计时循环生成最佳代码:
decf _lpw
btfss _STATUS,0 ; Skip next inst if carry (i.e. wasn't zero)
decf _lpw+1
bc loop ; Carry will be clear only if lpw was zero
但它生成的代码却比lpw更糟糕。最好的代码是递增计数循环:
infsnz _lpw
incfsz _lpw+1
bra loop
编辑2
我可能使用的另一种方法是:为字节数分配一个全局16位变量,并编写函数,以便在退出之前计数器总是归零。如果只需要8位值,则只需要加载8位。我会用宏来处理一些东西,这样就可以调整它们以获得最佳的效率。在PIC上,对一个已知为零的变量使用|=绝不比使用=,有时更快。例如,intvar |=15或intvar |=0x300将是两条指令(每种情况只需处理结果的一个字节,可以忽略另一个字节);intvar |=4(或2的任意幂)是一条指令。显然,在其他一些处理器上,intvar=0x300要比intvar |=0x300快;如果我使用宏,可以根据需要对其进行调整。