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

除法

PANCHIP RISC架构包含不支持除法指令,因此除法可以使用移位相减法进行实现。这里以32位除法为例,进行说明。

无符号除法

除法的目的是得到商和余数,事实上移位相减法即模拟竖式运算。

定义:

  • numer: 被除数;

  • denom: 除数;

  • quot: 商;

  • rem: 余数;

numerdenomquotrem均分配32位的空间,并将numerdenomrem按照以下方式进行对齐:

      +--------------------------------+    +--------------------------------+
  <===|              rem               |<===|             numer              |
      +--------------------------------+    +--------------------------------+
      +--------------------------------+
      |             denom              |
      +--------------------------------+

rem的初始值设置为0。按照以下方法进行计算:

  1. rem, numer看做一个整体,左移一位;

  2. 如果rem >= denom,则quot |= 1

  3. rem = rem - denom

  4. quot <<= 1

  5. 继续步骤1 ~ 4,直到number全部移位到rem,即循环32次;

最终quot为商,rem为余数。

 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
//__lib_div_numer: numer
//__lib_div_denom: denom
//__lib_div_quot : quot
//__lib_div_rem  : rem
        cseg
export  __udiv32
__udiv32:                                   //| void __udiv32(){
        clr     __lib_div_rem + 0           //| __lib_div_rem = 0;
        clr     __lib_div_rem + 1           //| 
        clr     __lib_div_rem + 2           //| 
        clr     __lib_div_rem + 3           //| 
        mov     A, #32                      //| __lib_div_loop = 32;
        mov     __lib_div_loop, A           //| 
loop:                                       //| loop:
        rolc    __lib_div_numer + 0         //| uint8_t c = __lib_div_numer >> 31;
        rolc    __lib_div_numer + 1         //| __lib_div_numer <<= 1;
        rolc    __lib_div_numer + 2         //| 
        rolc    __lib_div_numer + 3         //|
        rolc    __lib_div_rem + 0           //| __lib_div_rem = (__lib_div_rem << 1) | c;
        rolc    __lib_div_rem + 1           //| 
        rolc    __lib_div_rem + 2           //| 
        rolc    __lib_div_rem + 3           //| 
        mov     A, __lib_div_rem + 0        //| 
        sub     A, __lib_div_denom + 0      //| 
        mov     A, __lib_div_rem + 1        //| 
        subc    A, __lib_div_denom + 1      //| 
        mov     A, __lib_div_rem + 2        //| 
        subc    A, __lib_div_denom + 2      //| 
        mov     A, __lib_div_rem + 3        //| 
        subc    A, __lib_div_denom + 3      //| if(__lib_div_rem >= __lib_div_denom)
        rolc    __lib_div_quot + 0          //|     __lib_div_quot = (__lib_div_quot << 1) | 1;
        rolc    __lib_div_quot + 1          //| else
        rolc    __lib_div_quot + 2          //|     __lib_div_quot = __lib_div_quot << 1;
        rolc    __lib_div_quot + 3          //| 
        sbnz    __lib_div_quot, 0           //| if(__lib_div_rem < __lib_div_denom)
        jmp     next                        //|     goto next;
        mov     __lib_div_rem + 3, A        //| __lib_div_rem -= __lib_div_denom;
        mov     A, __lib_div_rem + 0        //| 
        sub     A, __lib_div_denom + 0      //| 
        mov     __lib_div_rem + 0, A        //| 
        mov     A, __lib_div_rem + 1        //| 
        subc    A, __lib_div_denom + 1      //| 
        mov     __lib_div_rem + 1, A        //| 
        mov     A, __lib_div_rem + 2        //| 
        subc    A, __lib_div_denom + 2      //| 
        mov     __lib_div_rem + 2, A        //| 
next:                                       //| next:
        dsz     __lib_div_loop              //| if(--__lib_div_loop)
        jmp     loop                        //|     goto loop;
        ret                                 //| return; }

有符号除法

有符号除法需要先对被除数和除数取绝对值后进行运算,最终再进行符号处理:

  • 商:同号为正,异号为负;

  • 余数:与被除数同号。

 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
//__lib_div_numer: numer
//__lib_div_denom: denom
//__lib_div_quot : quot
//__lib_div_rem  : rem
//__lib_div_numer_f: 标记numer的符号
//__lib_div_ndxor_f: 标记被除数与除数是否异号
        cseg
export  __idiv32
__idiv32:                                   //| void __idiv32(){
        bclr    __lib_div_numer_f           //| __lib_div_numer_f = 0;
        bclr    __lib_div_ndxor_f           //| __lib_div_ndxor_f = 0;
        sbnz    __lib_div_numer + 3, 7      //| if(__lib_div_numer < 0)
        jmp     next1                       //| {
        bset    __lib_div_numer_f           //|     __lib_div_numer_f = 1;
        bset    __lib_div_ndxor_f           //|     __lib_div_ndxor_f = 1;
        mov     A, #0                       //|     __lib_div_numer = -__lib_div_numer;
        rsub    __lib_div_numer + 0         //|
        rsubc   __lib_div_numer + 1         //|
        rsubc   __lib_div_numer + 2         //|
        rsubc   __lib_div_numer + 3         //|
next1:                                      //| }
        sbnz    __lib_div_denom + 3, 7      //| if(__lib_div_denom < 0)
        jmp     next2                       //| {
        bcpl    __lib_div_ndxor_f           //|     __lib_div_ndxor_f = ~__lib_div_ndxor_f;
        mov     A, #0                       //|     __lib_div_denom = -__lib_div_denom;
        rsub    __lib_div_denom + 0         //|
        rsubc   __lib_div_denom + 1         //|
        rsubc   __lib_div_denom + 2         //|
        rsubc   __lib_div_denom + 3         //|
next2:                                      //| }
        call    __udiv32                    //| __udiv32();
        sbnz     __lib_div_ndxor_f          //| if(__lib_div_ndxor_f)
        jmp     next3                       //| {
        mov     A, #0                       //|     __lib_div_quot = -__lib_div_quot;
        rsub    __lib_div_quot + 0, A       //|
        rsubc   __lib_div_quot + 1, A       //|
        rsubc   __lib_div_quot + 2, A       //|
        rsubc   __lib_div_quot + 3, A       //|
next3:                                      //| }
        sbnz    __lib_div_numer_f           //| if(__lib_div_numer_f)
        jmp     next4                       //| {
        mov     A, #0                       //|     __lib_div_rem = -__lib_div_rem;
        rsub    __lib_div_rem + 0           //|
        rsubc   __lib_div_rem + 1           //|
        rsubc   __lib_div_rem + 2           //|
        rsubc   __lib_div_rem + 3           //| }
next4:  ret                                 //| return; }