乘法¶
PANCHIP RISC架构包含乘法指令,但不是每个芯片都支持乘法指令,比如PAN221x
就不支持乘法指令。
这里的示例即不使用乘法指令,而是使用二进制乘法分配律来实现,也可以使用二进制竖式运算来解释。
首先描述二进制乘法分配律,以x * y
来描述,以x0, x1, x2 ... x31
来表示x
的32
个比特的值,以y0, y1, y2 ... y31
来表示y
的32
个比特的值。
x * y = x * {y31,y30,y29...y0}
= x * (y0 + (y1<<1) + (y2<<2) + ... + (y31<<31)) --- 将y按比特位分解成32个数相加
= x * y0
+ x * (y1<<1) ------------------------------------ 如果y1为1则 x * (y1<<1) = x << 1
+ x * (y2<<2) ------------------------------------ 如果y2为1则 x * (y2<<2) = x << 2
+ ...
+ x * (y31<<31) ---------------------------------- 如果y31为1则 x * (y31<<31) = x << 31
= (y0 ? x : 0)
+ (y1 ? (x << 1) : 0)
+ (y2 ? (x << 2) : 0)
+ ...
+ (y31 ? (x << 31) : 0)
从上面的推导可以总结出,完成x * y
的32
位乘法,只需要循环32次,每次查看y
对应的比特位是否为1
,如果为1
则将x
的值加到结果中,然后将x
的值左移一位。
这里对于查看y
对应的比特位,为了编程方便,可以处理为查看y
的比特0
,然后将y
右移一位。
再次使用二进制竖式运算来解释乘法算法,同样以x0, x1, x2 ... x31
来表示x
的32
个比特的值,以y0, y1, y2 ... y31
来表示y
的32
个比特的值。
x {x31,x30,x29...x2,x1,x0}
* y * {y31,y30,y29...y2,y1,y0}
------ => ------------------------------------------------
{x31,x30,x29...x2,x1,x0} --- x : 如果y0为1,加到结果中
{x31,x30,x29...x2,x1,x0} ------- x << 1 : 如果y1为1,加到结果中
{x31,x30,x29...x2,x1,x0} ----------- x << 2 : 如果y2为1,加到结果中
...
{x31,x30,x29...x2,x1,x0} ----------------------- x << 31: 如果y31为1,加到结果中
从生面的竖式推导可以得到与二进制乘法分配律推导一样的结果。
小技巧
乘法两个因数位宽相等时,该算法不区分有符号数和无符号数,总是能得到正确结果(如果没有溢出)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 | #define X_VAL 1234 #define Y_VAL 4567 dseg byte x[4] byte y[4] byte z[4] byte n cseg main: mov A, #X_VAL & 0xff mov x + 0, A mov A, #(X_VAL >> 8) & 0xff mov x + 1, A mov A, #(X_VAL >> 16) & 0xff mov x + 2, A mov A, #(X_VAL >> 24) & 0xff mov x + 3, A mov A, #Y_VAL & 0xff mov y + 0, A mov A, #(Y_VAL >> 8) & 0xff mov y + 1, A mov A, #(Y_VAL >> 16) & 0xff mov y + 2, A mov A, #(Y_VAL >> 24) & 0xff mov y + 3, A //执行乘法 z = x * y mov A, #32 //设置循环次数 mov n, A clr z + 0 //清零结果变量 clr z + 1 clr z + 2 clr z + 3 loop: sbnz y + 0, 0 //判断y.0 jmp next mov A, x + 0 //执行一次加 add z + 0, A mov A, x + 1 addc z + 1, A mov A, x + 2 addc z + 2, A mov A, x + 3 addc z + 3, A next: bclr STATUS_BIT_C //x左移一位 rolc x + 0 rolc x + 1 rolc x + 2 rolc x + 3 bclr STATUS_BIT_C //y右移一位 rorc y + 3 rorc y + 2 rorc y + 1 rorc y + 0 dsz n //判断循环次数 jmp loop //z = 5635678 |