市面上有很多种芯片,其中对应的指令集也很丰富,可是不同的指令集对于各种基本功能的支持力度是不同的,以PIC16芯片和X86芯片相比较,举出一个很简单的例子,就是乘法,比如实现c = a * b:
在X86中,实现如下:
movl b, %eax
mul b
这里不敢说乘法指令的全部操作只需要一条指令,但是乘法的本身还是只需要一条指令的,即mul b,但是在PIC16中会变成什么样子呢,代码如下:
movf a, w
movf mul.atmp, f
movf b, w
movf mul.btmp, f
callmul.i8
movf mul.result, w
movf c, 1
这里可能写的不规范,但是总体的意思是,将变量a 和 b 分别放到乘法库函数定义的符号mul.atmp和mul.btmp的符号里面,然后调用乘法库函数mul.i8,最后从库函数预先设定的符号里面取值,放到符号c中,如果觉得不好理解,可以先看成下面的高级函数形式的声明:
char mul.i8(char mul.atmp, char mul.btmp);
然后用户调用这个函数:
mul.result = mul.i8(a, b);
c = mul.result;
rlf mem, w
将符号mem的值循环左移一位,最高位进入进位位,最终的值写入寄存器,不写入f中
rlf mem, f
将符号mem的值循环左移一位,最高位进入进位位,原本符号位进入mem的最低位,写回到f中
clrf mem
将mem处的值清零
decf mem, f
将mem的值减一,并进行回写
comf mem, f
将mem的值取反,并进行回写
bcf mem, b
将mem的第b为清零
本芯片中如何用两条指令完成一次算数右移
先告诉你们一个不幸的消息,PIC16芯片中关于移位只有循环右移和循环左移,没有算数右移算数左移和逻辑右移。而且PIC16里面也没有相应的标志位寄存器,对于标志位,PIC16的策略是保存在一个内存符号里面,好在PIC16有一条指令bcf,这条指令可以将某个内存符号中的特定位置0,对应的也有bsf指令,可以将特定的内存位置的特定位置1,那么如何使用两条指令进行模拟呢。下面直接说结论吧,。
算数右移:
rlf mem, w
rrf mem, f
算数左移/逻辑左移:
bcf flags, 3// 这里不一定是3,这里假设状态位的第三位是进位位,即这里是把进位位清零
rlf mem, f
逻辑右移:
bcf flags, 3// 这里不一定是3,这里假设状态位的第三位是进位位,即这里是把进位位清零
rrf mem, f
两种没有经过优化的方式
使用库函数的方式
就像第一部分所说的,如果使用库函数,那么是8位扩展为16位,需要7条指令,因为可以指定移位次数是7,代码如下:
movf a, w
movf srashift.atmp, f
movl 7
movf srashift.btmp, f
call srashift.i8
movf srashift.result, w
movf c, f
同样可以看成高级语言函数声明:
srashift.result = srashift(char srashift.atmp, char srashift.btmp);
用户可以调用这个函数:
srashift.result = srashift(a, 7);
c = srashift.result;
而PIC16中的最高位宽是32位,最低位宽是8位,所以这里存在三种有符号扩展,分别为i8->i16, i8 -> i32, i16 -> i32,这三种有符号扩展分别所需要的指令条数为7条,至少11条,和13条。这是统计数据,相信我,没骗你们。
直接说出方法吧,这里以8位扩展16为例,设低位保存在mem + 0,值为00000000,高位保存在mem + 1中,由于申请这个符号的时候值是未知的,所以设置为xxxxxxxx,完成有符号移位只需要五条指令:
clrf mem + 1, f
rlf mem + 0, w
rlf mem + 1, f
decf mem + 1, f
comf mem + 1, f
让我们来看看这五条指令的执行效果:
指令名称
执行效果
高位初始值
xxxxxxxx
clrf mem + 1, f
00000000
rlf mem + 0, w
00000000
rlf mem + 1, f
00000001
decf mem + 1, f
00000000
comf mem + 1, f
11111111
可以看出,最后的高位是11111111,与mem + 0的最高位相等。容易证明,对于正数来说也是如此,最后的结果是00000000