当前页面为 开发中 版本,查看特定版本的文档,请在页面左下角的下拉菜单中进行选择。

乘法

PANCHIP RISC架构包含乘法指令,但不是每个芯片都支持乘法指令,比如PAN221x就不支持乘法指令。 这里的示例即不使用乘法指令,而是使用二进制乘法分配律来实现,也可以使用二进制竖式运算来解释。

首先描述二进制乘法分配律,以x * y来描述,以x0, x1, x2 ... x31来表示x32个比特的值,以y0, y1, y2 ... y31来表示y32个比特的值。

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 * y32位乘法,只需要循环32次,每次查看y对应的比特位是否为1,如果为1则将x的值加到结果中,然后将x的值左移一位。

这里对于查看y对应的比特位,为了编程方便,可以处理为查看y的比特0,然后将y右移一位。

再次使用二进制竖式运算来解释乘法算法,同样以x0, x1, x2 ... x31来表示x32个比特的值,以y0, y1, y2 ... y31来表示y32个比特的值。

    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