除法¶
PANCHIP RISC架构包含不支持除法指令,因此除法可以使用移位相减法进行实现。这里以32位除法为例,进行说明。
无符号除法¶
除法的目的是得到商和余数,事实上移位相减法即模拟竖式运算。
定义:
numer
: 被除数;denom
: 除数;quot
: 商;rem
: 余数;
为numer
,denom
,quot
,rem
均分配32位的空间,并将numer
,denom
,rem
按照以下方式进行对齐:
+--------------------------------+ +--------------------------------+
<===| rem |<===| numer |
+--------------------------------+ +--------------------------------+
+--------------------------------+
| denom |
+--------------------------------+
将rem
的初始值设置为0。按照以下方法进行计算:
将
rem
,numer
看做一个整体,左移一位;如果
rem >= denom
,则quot |= 1
;rem = rem - denom
;quot <<= 1
;继续步骤
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; } |