int64p.inc 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766
  1. {
  2. This file is part of the Free Pascal run time library.
  3. Copyright (c) 2013 by the Free Pascal development team
  4. This file contains some helper routines for int64 and qword
  5. See the file COPYING.FPC, included in this distribution,
  6. for details about the copyright.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  10. **********************************************************************}
  11. {$define FPC_SYSTEM_HAS_MUL_QWORD}
  12. function fpc_mul_qword( f1, f2: qword; checkoverflow: longbool ): qword; [public,alias: 'FPC_MUL_QWORD']; compilerproc;
  13. begin
  14. { routine contributed by Max Nazhalov
  15. 64-bit multiplication via 16-bit digits: (A3:A2:A1:A0)*(B3:B2:B1:B0)
  16. //////// STEP 1; break-down to 32-bit multiplications, each of them generates 64-bit result:
  17. (A3:A2*B3:B2)<<64 + (A3:A2*B1:B0)<<32 + (A1:A0*B3:B2)<<32 + (A1:A0*B1:B0)
  18. (A1:A0*B1:B0) = (A1*B1)<<32 + (A1*B0)<<16 + (A0*B1)<<16 + (A0:B0)
  19. -- never overflows, forms the base of the final result, name it as "R64"
  20. (A3:A2*B3:B2) is not required for the 64-bit result if overflow is not checked, since it is completely beyond the resulting width.
  21. -- always overflows if "<>0", so can be checked as "((A2|A3)<>0)&&(B2|B3)<>0)"
  22. (A3:A2*B1:B0) and (A1:A0*B3:B2) are partially required for the final result
  23. -- to be calculated on steps 2 and 3 as a correction for the "R64"
  24. //////// STEP 2; calculate "R64+=(A3:A2*B1:B0)<<32" (16-bit multiplications, each of them generates 32-bit result):
  25. (A3*B1)<<32 + (A3*B0)<<16 + (A2*B1)<<16 + (A2*B0)
  26. ((A3*B1)<<32)<<32 is not required for the 64-bit result if overflow is not checked, since it is completely beyond the resulting width.
  27. -- always overflows if "<>0", so can be checked as "(A3<>0)&&(B1<>0)"
  28. ((A3*B0)<<16)<<32: only low word of "A3*B0" contributes to the final result if overflow is not checked.
  29. -- overflows if the hi_word "<>0"
  30. -- overflows if R64+(lo_word<<48) produces C-flag
  31. ((A2*B1)<<16)<<32: only low word of "A2*B1" contributes to the final result if overflow is not checked.
  32. -- overflows if the hi_word "<>0"
  33. -- overflows if R64+(lo_word<<48) produces C-flag
  34. (A2*B0)<<32: the whole dword is significand, name it as "X"
  35. -- overflows if R64+(X<<32) produces C-flag
  36. //////// STEP 3; calculate "R64+=(A1:A0*B3:B2)<<32" (16-bit multiplications, each of them generates 32-bit result):
  37. (A1*B3)<<32 + (A1*B2)<<16 + (A0*B3)<<16 + (A0*B2)
  38. ((A1*B3)<<32)<<32 is not required for the 64-bit result if overflow is not checked, since it is completely beyond the resulting width.
  39. -- always overflows if "<>0", so can be checked as "(A1<>0)&&(B3<>0)"
  40. ((A1*B2)<<16)<<32: only low word of "A1*B2" contributes to the final result if overflow is not checked.
  41. -- overflows if the hi_word "<>0"
  42. -- overflows if R64+(lo_word<<48) produces C-flag
  43. ((A0*B3)<<16)<<32: only low word "A0*B3" contributes to the final result if overflow is not checked.
  44. -- overflows if the hi_word "<>0"
  45. -- overflows if R64+(lo_word<<48) produces C-flag
  46. (A0*B2)<<32: the whole dword is significand, name it as "Y"
  47. -- overflows if R64+(Y<<32) produces C-flag
  48. }
  49. asm
  50. mov di,word[f1]
  51. mov bx,word[f1+2]
  52. mov si,word[f2]
  53. mov ax,word[f2+2]
  54. push bp
  55. mov cx,ax
  56. mul bx
  57. xchg ax,bx
  58. mov bp,dx
  59. mul si
  60. xchg ax,cx
  61. add bx,dx
  62. adc bp,0
  63. mul di
  64. add cx,ax
  65. adc bx,dx
  66. adc bp,0
  67. mov ax,di
  68. mul si
  69. add cx,dx
  70. adc bx,0
  71. adc bp,0
  72. mov dx,bp
  73. pop bp
  74. mov word[result],ax
  75. mov word[result+2],cx
  76. mov word[result+4],bx
  77. mov word[result+6],dx
  78. mov si,word[f1+4]
  79. mov ax,word[f1+6]
  80. mov bx,word[checkoverflow]
  81. or bx,word[checkoverflow+2]
  82. jnz @@checked
  83. mov di,word[f2]
  84. mul di
  85. mov cx,ax
  86. mov ax,word[f2+2]
  87. mul si
  88. add cx,ax
  89. mov ax,di
  90. mul si
  91. mov bx,ax
  92. add cx,dx
  93. mov si,word[f2+4]
  94. mov ax,word[f2+6]
  95. mov di,word[f1]
  96. mul di
  97. add cx,ax
  98. mov ax,word[f1+2]
  99. mul si
  100. add cx,ax
  101. mov ax,di
  102. mul si
  103. add bx,ax
  104. adc cx,dx
  105. add word[result+4],bx
  106. adc word[result+6],cx
  107. jmp @@done
  108. @@checked:
  109. mov bx,word[f2+6]
  110. mov cx,ax
  111. or cx,si
  112. jz @@nover1
  113. mov cx,word[f2+4]
  114. or cx,bx
  115. jnz @@done
  116. @@nover1:
  117. test bx,bx
  118. jz @@nover2
  119. mov bx,word[f1+2]
  120. test bx,bx
  121. jnz @@done
  122. @@nover2:
  123. test ax,ax
  124. jz @@nover3
  125. or bx,word[f2+2]
  126. jnz @@done
  127. @@nover3:
  128. mov di,word[f2]
  129. mul di
  130. test dx,dx
  131. jnz @@done
  132. mov cx,ax
  133. mov ax,word[f2+2]
  134. mul si
  135. test dx,dx
  136. jnz @@done
  137. add cx,ax
  138. jc @@done
  139. mov ax,di
  140. mul si
  141. mov bx,ax
  142. add cx,dx
  143. jc @@done
  144. mov si,word[f2+4]
  145. mov ax,word[f2+6]
  146. mov di,word[f1]
  147. mul di
  148. test dx,dx
  149. jnz @@done
  150. add cx,ax
  151. jc @@done
  152. mov ax,word[f1+2]
  153. mul si
  154. test dx,dx
  155. jnz @@done
  156. add cx,ax
  157. jc @@done
  158. mov ax,di
  159. mul si
  160. add bx,ax
  161. adc cx,dx
  162. jc @@done
  163. add word[result+4],bx
  164. adc word[result+6],cx
  165. jc @@done
  166. // checked and succeed
  167. xor ax,ax
  168. mov word[checkoverflow],ax
  169. mov word[checkoverflow+2],ax
  170. @@done:
  171. end [ 'ax','bx','cx','dx','si','di' ];
  172. if checkoverflow then
  173. HandleErrorAddrFrameInd(215,get_pc_addr,get_frame);
  174. end;
  175. {$define FPC_SYSTEM_HAS_MUL_DWORD_TO_QWORD}
  176. function fpc_mul_dword_to_qword(f1,f2 : dword) : qword;[public,alias: 'FPC_MUL_DWORD_TO_QWORD']; compilerproc; assembler; nostackframe;
  177. asm
  178. push bp
  179. mov bp, sp
  180. mov di,word[bp + 8 + extra_param_offset] // word[f1]
  181. mov bx,word[bp + 10 + extra_param_offset] // word[f1+2]
  182. mov si,word[bp + 4 + extra_param_offset] // word[f2]
  183. mov ax,word[bp + 6 + extra_param_offset] // word[f2+2]
  184. mov cx,ax
  185. mul bx
  186. xchg ax,bx
  187. mov bp,dx
  188. mul si
  189. xchg ax,cx
  190. add bx,dx
  191. adc bp,0
  192. mul di
  193. add cx,ax
  194. adc bx,dx
  195. adc bp,0
  196. mov ax,di
  197. mul si
  198. add cx,dx
  199. adc bx,0
  200. adc bp,0
  201. mov dx,ax
  202. mov ax,bp
  203. pop bp
  204. end;
  205. {$define FPC_SYSTEM_HAS_DIV_QWORD}
  206. function fpc_div_qword( n, z: qword ): qword; [public, alias:'FPC_DIV_QWORD']; compilerproc;
  207. // Generic "schoolbook" division algorithm
  208. // see [D.Knuth, TAOCP, vol.2, sect.4.3.1] for explanation
  209. var
  210. dig: byte;
  211. u: array [0..7] of word;
  212. begin
  213. asm
  214. mov dig,4
  215. // Check parameters
  216. mov dx,word [n]
  217. mov cx,word [n+2]
  218. mov bx,word [n+4]
  219. mov ax,word [n+6]
  220. mov di,ax
  221. or di,bx
  222. or di,cx
  223. jnz @@s1
  224. or di,dx
  225. jz @@q // div by 0
  226. // Short division
  227. mov dig,al
  228. mov dx,word [z+6]
  229. cmp dx,di
  230. jc @@s0
  231. xchg ax,dx
  232. div di
  233. @@s0: mov word [result+6],ax
  234. mov ax,word [z+4]
  235. div di
  236. mov word [result+4],ax
  237. mov ax,word [z+2]
  238. div di
  239. mov word [result+2],ax
  240. mov ax,word [z]
  241. div di
  242. mov word [result],ax
  243. jmp @@q
  244. @@s1: // Long division
  245. xor si,si
  246. cmp word [z],dx
  247. mov di,word [z+2]
  248. sbb di,cx
  249. mov di,word [z+4]
  250. sbb di,bx
  251. mov di,word [z+6]
  252. sbb di,ax
  253. jnc @@n0
  254. // underflow: return 0
  255. mov dig,0
  256. mov word [result],si
  257. mov word [result+2],si
  258. mov word [result+4],si
  259. mov word [result+6],si
  260. jmp @@q
  261. @@n0: // D1. Normalize divisor:
  262. // n := n shl lzv, so that 2^63<=n<2^64
  263. mov di,si
  264. test ax,ax
  265. jnz @@n2
  266. @@n1: add si,16
  267. or ax,bx
  268. mov bx,cx
  269. mov cx,dx
  270. mov dx,di
  271. jz @@n1
  272. @@n2: test ah,ah
  273. jnz @@n4
  274. add si,8
  275. or ah,al
  276. mov al,bh
  277. mov bh,bl
  278. mov bl,ch
  279. mov ch,cl
  280. mov cl,dh
  281. mov dh,dl
  282. mov dl,0
  283. js @@n5
  284. @@n3: inc si
  285. shl dx,1
  286. rcl cx,1
  287. rcl bx,1
  288. adc ax,ax
  289. @@n4: jns @@n3
  290. @@n5: mov word [n],dx
  291. mov word [n+2],cx
  292. mov word [n+4],bx
  293. mov word [n+6],ax
  294. // Adjust divident accordingly:
  295. // u := uint128(z) shl lzv; lzv=si=0..63; di=0
  296. mov dx,word [z]
  297. mov cx,word [z+2]
  298. mov bx,word [z+4]
  299. mov ax,word [z+6]
  300. push bp
  301. mov bp,si // save lzv
  302. test si,8
  303. jz @@m0
  304. // << by odd-8
  305. xchg al,ah
  306. mov di,ax
  307. and di,0FFh
  308. mov al,bh
  309. mov bh,bl
  310. mov bl,ch
  311. mov ch,cl
  312. mov cl,dh
  313. mov dh,dl
  314. xor dl,dl
  315. @@m0: and si,7
  316. jz @@m2
  317. // << 1..7
  318. @@m1: shl dx,1
  319. rcl cx,1
  320. rcl bx,1
  321. rcl ax,1
  322. rcl di,1
  323. dec si
  324. jnz @@m1
  325. @@m2: // si=0, bp=lzv
  326. // di:ax:bx:cx:dx shifted by 0..15; 0|16|32|48 shifts remain
  327. sub bp,16
  328. jc @@m5
  329. sub bp,16
  330. jc @@m4
  331. sub bp,16
  332. jc @@m3
  333. // << 48
  334. pop bp
  335. mov word [u],si
  336. mov word [u+2],si
  337. mov word [u+4],si
  338. mov word [u+6],dx
  339. mov word [u+8],cx
  340. mov word [u+10],bx
  341. mov word [u+12],ax
  342. mov word [u+14],di
  343. jmp @@m6
  344. @@m3: // << 32
  345. pop bp
  346. mov word [u],si
  347. mov word [u+2],si
  348. mov word [u+4],dx
  349. mov word [u+6],cx
  350. mov word [u+8],bx
  351. mov word [u+10],ax
  352. mov word [u+12],di
  353. mov word [u+14],si
  354. jmp @@m6
  355. @@m4: // << 16
  356. pop bp
  357. mov word [u],si
  358. mov word [u+2],dx
  359. mov word [u+4],cx
  360. mov word [u+6],bx
  361. mov word [u+8],ax
  362. mov word [u+10],di
  363. mov word [u+12],si
  364. mov word [u+14],si
  365. jmp @@m6
  366. @@m5: // << 0
  367. pop bp
  368. mov word [u],dx
  369. mov word [u+2],cx
  370. mov word [u+4],bx
  371. mov word [u+6],ax
  372. mov word [u+8],di
  373. mov word [u+10],si
  374. mov word [u+12],si
  375. mov word [u+14],si
  376. @@m6: // D2. Start from j:=3, si:=@u[j], bx:=@q[j]
  377. lea si,word [u+6]
  378. lea bx,word [result+6]
  379. @@d0: push bx
  380. // D3. Estimate the next quotient digit:
  381. // q_hat := [u(j+4):u(j+3)]/[n3]
  382. // use max.possible q_hat if division overflows
  383. mov ax,-1
  384. mov dx,ss:[si+8]
  385. mov di,word [n+6]
  386. cmp dx,di
  387. jnc @@d1
  388. mov ax,ss:[si+6]
  389. div di
  390. @@d1: // D4. Multiply & subtract calculating partial reminder:
  391. // r := [u(j+4):u(j+3):u(j+2):u(j+1):u(j)]-q_hat*[n3:n2:n1:n0]
  392. push ax // q_hat
  393. push si // @u[j]
  394. mov si,ax
  395. mul word [n]
  396. mov bx,ax
  397. mov cx,dx
  398. mov ax,word [n+2]
  399. mul si
  400. add cx,ax
  401. adc dx,0
  402. mov di,dx
  403. mov ax,word [n+4]
  404. mul si
  405. add di,ax
  406. adc dx,0
  407. xchg dx,si
  408. mov ax,word [n+6]
  409. mul dx
  410. add ax,si
  411. pop si // @u[j]
  412. adc dx,0
  413. sub ss:[si],bx
  414. sbb ss:[si+2],cx
  415. sbb ss:[si+4],di
  416. sbb ss:[si+6],ax
  417. sbb ss:[si+8],dx
  418. pop di // q_hat
  419. // D5. Test reminder
  420. jnc @@d3 // 0<=r<n
  421. // D6. Add back once or twice correcting the quotient and remainder:
  422. // while (r<0) do { q_hat--; r+=n; }
  423. mov dx,word [n]
  424. mov cx,word [n+2]
  425. mov bx,word [n+4]
  426. mov ax,word [n+6]
  427. @@d2: dec di
  428. add ss:[si],dx
  429. adc ss:[si+2],cx
  430. adc ss:[si+4],bx
  431. adc ss:[si+6],ax
  432. adc word ss:[si+8],0
  433. jnc @@d2
  434. @@d3: // D7. Store q[j], loop on j--
  435. pop bx // @q[j]
  436. dec si
  437. dec si
  438. mov ss:[bx],di
  439. dec bx
  440. dec bx
  441. dec dig
  442. jnz @@d0
  443. @@q:
  444. end;
  445. if dig<>0 then
  446. HandleErrorAddrFrameInd(200,get_pc_addr,get_frame);
  447. end;
  448. {$define FPC_SYSTEM_HAS_MOD_QWORD}
  449. function fpc_mod_qword( n, z: qword ): qword; [public, alias:'FPC_MOD_QWORD']; compilerproc;
  450. // Generic "schoolbook" division algorithm
  451. // see [D.Knuth, TAOCP, vol.2, sect.4.3.1] for explanation
  452. var
  453. dig: byte;
  454. lzv: word;
  455. u: array [0..7] of word;
  456. begin
  457. asm
  458. mov dig,4
  459. // Check parameters
  460. mov dx,word [n]
  461. mov cx,word [n+2]
  462. mov bx,word [n+4]
  463. mov ax,word [n+6]
  464. mov di,ax
  465. or di,bx
  466. or di,cx
  467. jnz @@s1
  468. or di,dx
  469. jz @@q // div by 0
  470. // Short division
  471. mov dig,al
  472. mov dx,word [z+6]
  473. cmp dx,di
  474. jc @@s0
  475. xchg ax,dx
  476. div di
  477. @@s0: mov ax,word [z+4]
  478. div di
  479. mov ax,word [z+2]
  480. div di
  481. mov ax,word [z]
  482. div di
  483. mov word [result],dx
  484. mov word [result+2],cx
  485. mov word [result+4],cx
  486. mov word [result+6],cx
  487. jmp @@q
  488. @@s1: // Long division
  489. xor si,si
  490. cmp word [z],dx
  491. mov di,word [z+2]
  492. sbb di,cx
  493. mov di,word [z+4]
  494. sbb di,bx
  495. mov di,word [z+6]
  496. sbb di,ax
  497. jnc @@n0
  498. // underflow: return z
  499. mov dig,0
  500. mov dx,word [z]
  501. mov cx,word [z+2]
  502. mov bx,word [z+4]
  503. mov ax,word [z+6]
  504. jmp @@r6
  505. @@n0: // D1. Normalize divisor:
  506. // n := n shl lzv, so that 2^63<=n<2^64
  507. mov di,si
  508. test ax,ax
  509. jnz @@n2
  510. @@n1: add si,16
  511. or ax,bx
  512. mov bx,cx
  513. mov cx,dx
  514. mov dx,di
  515. jz @@n1
  516. @@n2: test ah,ah
  517. jnz @@n4
  518. add si,8
  519. or ah,al
  520. mov al,bh
  521. mov bh,bl
  522. mov bl,ch
  523. mov ch,cl
  524. mov cl,dh
  525. mov dh,dl
  526. mov dl,0
  527. js @@n5
  528. @@n3: inc si
  529. shl dx,1
  530. rcl cx,1
  531. rcl bx,1
  532. adc ax,ax
  533. @@n4: jns @@n3
  534. @@n5: mov word [n],dx
  535. mov word [n+2],cx
  536. mov word [n+4],bx
  537. mov word [n+6],ax
  538. mov lzv,si
  539. // Adjust divident accordingly:
  540. // u := uint128(z) shl lzv; lzv=si=0..63; di=0
  541. mov dx,word [z]
  542. mov cx,word [z+2]
  543. mov bx,word [z+4]
  544. mov ax,word [z+6]
  545. push bp
  546. mov bp,si // save lzv
  547. test si,8
  548. jz @@m0
  549. // << by odd-8
  550. xchg al,ah
  551. mov di,ax
  552. and di,0FFh
  553. mov al,bh
  554. mov bh,bl
  555. mov bl,ch
  556. mov ch,cl
  557. mov cl,dh
  558. mov dh,dl
  559. xor dl,dl
  560. @@m0: and si,7
  561. jz @@m2
  562. // << 1..7
  563. @@m1: shl dx,1
  564. rcl cx,1
  565. rcl bx,1
  566. rcl ax,1
  567. rcl di,1
  568. dec si
  569. jnz @@m1
  570. @@m2: // si=0, bp=lzv
  571. // di:ax:bx:cx:dx shifted by 0..15; 0|16|32|48 shifts remain
  572. sub bp,16
  573. jc @@m5
  574. sub bp,16
  575. jc @@m4
  576. sub bp,16
  577. jc @@m3
  578. // << 48
  579. pop bp
  580. mov word [u],si
  581. mov word [u+2],si
  582. mov word [u+4],si
  583. mov word [u+6],dx
  584. mov word [u+8],cx
  585. mov word [u+10],bx
  586. mov word [u+12],ax
  587. mov word [u+14],di
  588. jmp @@m6
  589. @@m3: // << 32
  590. pop bp
  591. mov word [u],si
  592. mov word [u+2],si
  593. mov word [u+4],dx
  594. mov word [u+6],cx
  595. mov word [u+8],bx
  596. mov word [u+10],ax
  597. mov word [u+12],di
  598. mov word [u+14],si
  599. jmp @@m6
  600. @@m4: // << 16
  601. pop bp
  602. mov word [u],si
  603. mov word [u+2],dx
  604. mov word [u+4],cx
  605. mov word [u+6],bx
  606. mov word [u+8],ax
  607. mov word [u+10],di
  608. mov word [u+12],si
  609. mov word [u+14],si
  610. jmp @@m6
  611. @@m5: // << 0
  612. pop bp
  613. mov word [u],dx
  614. mov word [u+2],cx
  615. mov word [u+4],bx
  616. mov word [u+6],ax
  617. mov word [u+8],di
  618. mov word [u+10],si
  619. mov word [u+12],si
  620. mov word [u+14],si
  621. @@m6: // D2. Start from j:=3, si:=@u[j]
  622. lea si,word [u+6]
  623. @@d0: // D3. Estimate the next quotient digit:
  624. // q_hat := [u(j+4):u(j+3)]/[n3]
  625. // use max.possible q_hat if division overflows
  626. mov ax,-1
  627. mov dx,ss:[si+8]
  628. mov di,word [n+6]
  629. cmp dx,di
  630. jnc @@d1
  631. mov ax,ss:[si+6]
  632. div di
  633. @@d1: // D4. Multiply & subtract calculating partial reminder:
  634. // r := [u(j+4):u(j+3):u(j+2):u(j+1):u(j)]-q_hat*[n3:n2:n1:n0]
  635. push si // @u[j]
  636. mov si,ax // q_hat
  637. mul word [n]
  638. mov bx,ax
  639. mov cx,dx
  640. mov ax,word [n+2]
  641. mul si
  642. add cx,ax
  643. adc dx,0
  644. mov di,dx
  645. mov ax,word [n+4]
  646. mul si
  647. add di,ax
  648. adc dx,0
  649. xchg dx,si
  650. mov ax,word [n+6]
  651. mul dx
  652. add ax,si
  653. pop si // @u[j]
  654. adc dx,0
  655. sub ss:[si],bx
  656. sbb ss:[si+2],cx
  657. sbb ss:[si+4],di
  658. sbb ss:[si+6],ax
  659. mov di,ss:[si+8]
  660. sbb di,dx
  661. // D5. Test reminder
  662. jnc @@d3 // 0<=r<n
  663. // D6. Add back once or twice correcting the remainder:
  664. // while (r<0) do { r+=n; }
  665. mov dx,word [n]
  666. mov cx,word [n+2]
  667. mov bx,word [n+4]
  668. mov ax,word [n+6]
  669. @@d2: add ss:[si],dx
  670. adc ss:[si+2],cx
  671. adc ss:[si+4],bx
  672. adc ss:[si+6],ax
  673. adc di,0
  674. jnc @@d2
  675. @@d3: // D7. Loop on j--
  676. dec si
  677. dec si
  678. dec dig
  679. jnz @@d0
  680. // D8. "Unnormalize" and return reminder:
  681. // result := [u3:u2:u1:u0] shr lzv
  682. xor ax,ax
  683. mov si,lzv
  684. sub si,16
  685. jc @@r2
  686. sub si,16
  687. jc @@r1
  688. sub si,16
  689. jc @@r0
  690. // >> 48..63
  691. mov bx,ax
  692. mov cx,ax
  693. mov dx,word [u+6]
  694. jmp @@r3
  695. @@r0: // >> 32..47
  696. mov bx,ax
  697. mov cx,word [u+6]
  698. mov dx,word [u+4]
  699. jmp @@r3
  700. @@r1: // >> 16..31
  701. mov bx,word [u+6]
  702. mov cx,word [u+4]
  703. mov dx,word [u+2]
  704. jmp @@r3
  705. @@r2: // >> 0..15
  706. mov ax,word [u+6]
  707. mov bx,word [u+4]
  708. mov cx,word [u+2]
  709. mov dx,word [u]
  710. @@r3: and si,15
  711. sub si,8
  712. jc @@r4
  713. // >> 8..15
  714. mov dl,dh
  715. mov dh,cl
  716. mov cl,ch
  717. mov ch,bl
  718. mov bl,bh
  719. mov bh,al
  720. mov al,ah
  721. xor ah,ah
  722. @@r4: and si,7
  723. jz @@r6
  724. // >> 1..7
  725. @@r5: shr ax,1
  726. rcr bx,1
  727. rcr cx,1
  728. rcr dx,1
  729. dec si
  730. jnz @@r5
  731. @@r6: mov word [result],dx
  732. mov word [result+2],cx
  733. mov word [result+4],bx
  734. mov word [result+6],ax
  735. @@q:
  736. end;
  737. if dig<>0 then
  738. HandleErrorAddrFrameInd(200,get_pc_addr,get_frame);
  739. end;