int64p.inc 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567
  1. {
  2. This file is part of the Free Pascal run time library.
  3. Copyright (c) 2008 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. {$ifndef CPUAVR_16_REGS}
  12. {$define FPC_SYSTEM_HAS_SHR_QWORD}
  13. // Simplistic version with checking if whole bytes can be shifted
  14. // Doesn't change bitshift portion even if possible because of byteshift
  15. // Shorter code but not shortest execution time version
  16. function fpc_shr_qword(value: qword; shift: ALUUInt): qword; assembler; nostackframe;
  17. [public, alias: 'FPC_SHR_QWORD']; compilerproc;
  18. label
  19. byteshift, bitshift, finish;
  20. asm
  21. // value passed in R25...R18
  22. // shift passed in R16
  23. // return value in R25...R18
  24. push R16
  25. andi R16, 63 // mask 64 bit relevant value per generic routine
  26. byteshift:
  27. breq finish // shift = 0, finished
  28. cpi R16, 8 // Check if shift is at least a byte
  29. brlo bitshift
  30. mov R18, R19 // if so, then shift all bytes right by 1 position
  31. mov R19, R20
  32. mov R20, R21
  33. mov R21, R22
  34. mov R22, R23
  35. mov R23, R24
  36. mov R24, R25
  37. clr R25 // and clear the high byte
  38. subi R16, 8 // subtract 8 bits from shift
  39. rjmp byteshift // check if another byte can be shifted
  40. bitshift: // shift all 8 bytes right by 1 bit
  41. lsr R25
  42. ror R24
  43. ror R23
  44. ror R22
  45. ror R21
  46. ror R20
  47. ror R19
  48. ror R18
  49. dec R16
  50. brne bitshift // until R16 = 0
  51. finish:
  52. pop R16
  53. end;
  54. function fpc_shr_qword(value: qword; shift: ALUUInt): qword; external name 'FPC_SHR_QWORD';
  55. {$define FPC_SYSTEM_HAS_SHL_QWORD}
  56. function fpc_shl_qword(value: qword; shift: ALUUInt): qword; assembler; nostackframe;
  57. [public, alias: 'FPC_SHL_QWORD']; compilerproc;
  58. label
  59. byteshift, bitshift, finish;
  60. asm
  61. // value passed in R25...R18
  62. // shift passed in R16
  63. // return value in R25...R18
  64. push R16
  65. andi R16, 63 // mask 64 bit relevant value per generic routine
  66. byteshift:
  67. breq finish // shift = 0, finished
  68. cpi R16, 8 // Check if shift is at least a byte
  69. brlo bitshift
  70. mov R25, R24 // if so, then shift all bytes left by 1 position
  71. mov R24, R23
  72. mov R23, R22
  73. mov R22, R21
  74. mov R21, R20
  75. mov R20, R19
  76. mov R19, R18
  77. clr R18 // and clear the high byte
  78. subi R16, 8 // subtract 8 bits from shift
  79. rjmp byteshift // check if another byte can be shifted
  80. bitshift: // shift all 8 bytes left by 1 bit
  81. lsl R18
  82. rol R19
  83. rol R20
  84. rol R21
  85. rol R22
  86. rol R23
  87. rol R24
  88. rol R25
  89. dec R16
  90. brne bitshift // until R16 = 0
  91. finish:
  92. pop R16
  93. end;
  94. function fpc_shl_qword(value: qword; shift: ALUUInt): qword; external name 'FPC_SHL_QWORD';
  95. {$define FPC_SYSTEM_HAS_SHL_INT64}
  96. function fpc_shl_int64(value: int64; shift: ALUUInt): int64;
  97. [public, alias: 'FPC_SHL_INT64']; compilerproc; inline;
  98. begin
  99. Result := fpc_shl_qword(qword(value), shift);
  100. end;
  101. {$define FPC_SYSTEM_HAS_SHR_INT64}
  102. // shr of signed int is same as shr of unsigned int (logical shift right)
  103. function fpc_shr_int64(value: int64; shift: ALUUInt): int64; [public, alias: 'FPC_SHR_INT64']; compilerproc;
  104. begin
  105. Result := fpc_shr_qword(qword(value), shift);
  106. end;
  107. {$define FPC_SYSTEM_HAS_DIV_QWORD}
  108. function fpc_div_qword(n,z : qword): qword; nostackframe; assembler; [public,alias: 'FPC_DIV_QWORD']; compilerproc;
  109. label
  110. start, div1, div2, div3, finish;
  111. asm
  112. // Symbol Name Register(s)
  113. // z (A) dividend R17, R16, R15, R14, R13, R12, R11, R10
  114. // n (B) divisor R25, R24, R23, R22, R21, R20, R19, R18
  115. // r (P) remainder R9, R8, R7, R6, R5, R4, R3, R2
  116. // i counter R26
  117. // 1 R27
  118. cp R25, R1
  119. cpc R24, R1
  120. cpc R23, R1
  121. cpc R22, R1
  122. cpc R21, R1
  123. cpc R20, R1
  124. cpc R19, R1
  125. cpc R18, R1
  126. brne .LNonZero
  127. {$ifdef CPUAVR_HAS_JMP_CALL}
  128. call fpc_divbyzero
  129. {$else CPUAVR_HAS_JMP_CALL}
  130. rcall fpc_divbyzero
  131. {$endif CPUAVR_HAS_JMP_CALL}
  132. .LNonZero:
  133. push R17
  134. push R16
  135. push R15
  136. push R14
  137. push R13
  138. push R12
  139. push R11
  140. push R10
  141. push R9
  142. push R8
  143. push R7
  144. push R6
  145. push R5
  146. push R4
  147. push R3
  148. push R2
  149. ldi R27, 1 // needed below for OR instruction
  150. start: // Start of division...
  151. clr R9 // clear remainder
  152. clr R8
  153. clr R7
  154. clr R6
  155. clr R5
  156. clr R4
  157. clr R3
  158. clr R2
  159. ldi R26, 64 // iterate over 64 bits
  160. div1:
  161. lsl R10 // shift left A_L
  162. rol R11
  163. rol R12
  164. rol R13
  165. rol R14
  166. rol R15
  167. rol R16
  168. rol R17
  169. rol R2 // shift left P with carry from A shift
  170. rol R3
  171. rol R4
  172. rol R5
  173. rol R6
  174. rol R7
  175. rol R8
  176. rol R9
  177. sub R2, R18 // Subtract B from P, P <= P - B
  178. sbc R3, R19
  179. sbc R4, R20
  180. sbc R5, R21
  181. sbc R6, R22
  182. sbc R7, R23
  183. sbc R8, R24
  184. sbc R9, R25
  185. brlo div2
  186. or R10, R27 // Set A[0] = 1
  187. rjmp div3
  188. div2: // negative branch, A[0] = 0 (default after shift), restore P
  189. add R2, R18 // restore old value of P
  190. adc R3, R19
  191. adc R4, R20
  192. adc R5, R21
  193. adc R6, R22
  194. adc R7, R23
  195. adc R8, R24
  196. adc R9, R25
  197. div3:
  198. dec R26
  199. breq finish
  200. rjmp div1
  201. finish:
  202. mov R25, R17 // Move answer from R17..10 to R25..18
  203. mov R24, R16
  204. mov R23, R15
  205. mov R22, R14
  206. mov R21, R13
  207. mov R20, R12
  208. mov R19, R11
  209. mov R18, R10
  210. pop R2
  211. pop R3
  212. pop R4
  213. pop R5
  214. pop R6
  215. pop R7
  216. pop R8
  217. pop R9
  218. pop R10
  219. pop R11
  220. pop R12
  221. pop R13
  222. pop R14
  223. pop R15
  224. pop R16
  225. pop R17
  226. end;
  227. function fpc_div_qword(n,z : qword): qword; external name 'FPC_DIV_QWORD';
  228. {$define FPC_SYSTEM_HAS_MOD_QWORD}
  229. function fpc_mod_qword(n,z : qword): qword; nostackframe; assembler; [public,alias: 'FPC_MOD_QWORD']; compilerproc;
  230. label
  231. start, div1, div2, div3, finish;
  232. asm
  233. // Symbol Name Register(s)
  234. // z (A) dividend R17, R16, R15, R14, R13, R12, R11, R10
  235. // n (B) divisor R25, R24, R23, R22, R21, R20, R19, R18
  236. // r (P) remainder R9, R8, R7, R6, R5, R4, R3, R2
  237. // i counter R26
  238. // 1 R27
  239. cp R25, R1
  240. cpc R24, R1
  241. cpc R23, R1
  242. cpc R22, R1
  243. cpc R21, R1
  244. cpc R20, R1
  245. cpc R19, R1
  246. cpc R18, R1
  247. brne .LNonZero
  248. {$ifdef CPUAVR_HAS_JMP_CALL}
  249. call fpc_divbyzero
  250. {$else CPUAVR_HAS_JMP_CALL}
  251. rcall fpc_divbyzero
  252. {$endif CPUAVR_HAS_JMP_CALL}
  253. .LNonZero:
  254. push R17
  255. push R16
  256. push R15
  257. push R14
  258. push R13
  259. push R12
  260. push R11
  261. push R10
  262. push R9
  263. push R8
  264. push R7
  265. push R6
  266. push R5
  267. push R4
  268. push R3
  269. push R2
  270. ldi R27, 1
  271. start: // Start of division...
  272. clr R9 // clear remainder
  273. clr R8
  274. clr R7
  275. clr R6
  276. clr R5
  277. clr R4
  278. clr R3
  279. clr R2
  280. ldi R26, 64 // iterate over 64 bits
  281. div1:
  282. lsl R10 // shift left A_L
  283. rol R11
  284. rol R12
  285. rol R13
  286. rol R14
  287. rol R15
  288. rol R16
  289. rol R17
  290. rol R2 // shift left P with carry from A shift
  291. rol R3
  292. rol R4
  293. rol R5
  294. rol R6
  295. rol R7
  296. rol R8
  297. rol R9
  298. sub R2, R18 // Subtract B from P, P <= P - B
  299. sbc R3, R19
  300. sbc R4, R20
  301. sbc R5, R21
  302. sbc R6, R22
  303. sbc R7, R23
  304. sbc R8, R24
  305. sbc R9, R25
  306. brlo div2
  307. or R10, R27 // Set A[0] = 1
  308. rjmp div3
  309. div2: // negative branch, A[0] = 0 (default after shift), restore P
  310. add R2, R18 // restore old value of P
  311. adc R3, R19
  312. adc R4, R20
  313. adc R5, R21
  314. adc R6, R22
  315. adc R7, R23
  316. adc R8, R24
  317. adc R9, R25
  318. div3:
  319. dec R26
  320. breq finish
  321. rjmp div1
  322. finish:
  323. mov R25, R9 // Move answer from R9..2 to R25..18
  324. mov R24, R8
  325. mov R23, R7
  326. mov R22, R6
  327. mov R21, R5
  328. mov R20, R4
  329. mov R19, R3
  330. mov R18, R2
  331. pop R2
  332. pop R3
  333. pop R4
  334. pop R5
  335. pop R6
  336. pop R7
  337. pop R8
  338. pop R9
  339. pop R10
  340. pop R11
  341. pop R12
  342. pop R13
  343. pop R14
  344. pop R15
  345. pop R16
  346. pop R17
  347. end;
  348. function fpc_mod_qword(n,z : qword): qword; external name 'FPC_MOD_QWORD';
  349. {$define FPC_SYSTEM_HAS_DIV_INT64}
  350. function fpc_div_int64(n,z : int64) : int64; nostackframe; assembler; [public,alias: 'FPC_DIV_INT64']; compilerproc;
  351. label
  352. pos1, pos2, fin;
  353. asm
  354. // Convert n, z to unsigned int, then call div_qword,
  355. // Restore sign if high bits of n xor z is negative
  356. // n divisor R25, R24, R23, R22, R21, R20, R19, R18
  357. // z dividend R17, R16, R15, R14, R13, R12, R11, R10
  358. // neg_result R30
  359. // one R31
  360. mov R30, R17 // store hi8(z)
  361. eor R30, R25 // hi8(z) XOR hi8(n), answer must be negative if MSB set
  362. // convert n to absolute
  363. ldi R31, 1 // 1 in R31 used later
  364. sub R25, r1 // subtract 0, just to check sign flag
  365. brpl pos1
  366. com R25
  367. com R24
  368. com R23
  369. com R22
  370. com R21
  371. com R20
  372. com R19
  373. com R18
  374. add R18, R31 // add 1
  375. adc R19, R1 // add carry bit
  376. adc R20, R1
  377. adc R21, R1
  378. adc R22, R1
  379. adc R23, R1
  380. adc R24, R1
  381. adc R25, R1
  382. pos1:
  383. sub R17, R1
  384. brpl pos2
  385. com R17
  386. com R16
  387. com R15
  388. com R14
  389. com R13
  390. com R12
  391. com R11
  392. com R10
  393. add R10, R31
  394. adc R11, R1
  395. adc R12, R1
  396. adc R13, R1
  397. adc R14, R1
  398. adc R15, R1
  399. adc R16, R1
  400. adc R17, R1
  401. pos2:
  402. {$ifdef CPUAVR_HAS_JMP_CALL}
  403. call fpc_div_qword
  404. {$else CPUAVR_HAS_JMP_CALL}
  405. rcall fpc_div_qword
  406. {$endif CPUAVR_HAS_JMP_CALL}
  407. sbrs R30, 7 // skip if bit 7 is cleared (result should be positive)
  408. rjmp fin
  409. com R25 // result from FPC_DIV_WORD in R25 ... R22
  410. com R24
  411. com R23
  412. com R22
  413. com R21
  414. com R20
  415. com R19
  416. com R18
  417. ldi R31, 1
  418. add R18, R31 // add 1
  419. adc R19, R1 // add carry bit
  420. adc R20, R1
  421. adc R21, R1
  422. adc R22, R1
  423. adc R23, R1
  424. adc R24, R1
  425. adc R25, R1
  426. fin:
  427. end;
  428. {$define FPC_SYSTEM_HAS_MOD_INT64}
  429. function fpc_mod_int64(n,z : int64) : int64; nostackframe; assembler; [public,alias: 'FPC_MOD_INT64']; compilerproc;
  430. label
  431. pos1, pos2, fin;
  432. asm
  433. // Convert n, z to unsigned int, then call mod_qword,
  434. // Restore sign if high bits of n xor z is negative
  435. // n divisor R25, R24, R23, R22, R21, R20, R19, R18
  436. // z dividend R17, R16, R15, R14, R13, R12, R11, R10
  437. // neg_result R30
  438. // one R31
  439. mov R30, R17 // store hi8(z)
  440. // convert n to absolute
  441. ldi R31, 1
  442. sub R25, r1 // subtract 0, just to check sign flag
  443. brpl pos1
  444. com R25
  445. com R24
  446. com R23
  447. com R22
  448. com R21
  449. com R20
  450. com R19
  451. com R18
  452. add R18, R31 // add 1
  453. adc R19, R1 // add carry bit
  454. adc R20, R1
  455. adc R21, R1
  456. adc R22, R1
  457. adc R23, R1
  458. adc R24, R1
  459. adc R25, R1
  460. pos1:
  461. sub R17, R1
  462. brpl pos2
  463. com R17
  464. com R16
  465. com R15
  466. com R14
  467. com R13
  468. com R12
  469. com R11
  470. com R10
  471. add R10, R31
  472. adc R11, R1
  473. adc R12, R1
  474. adc R13, R1
  475. adc R14, R1
  476. adc R15, R1
  477. adc R16, R1
  478. adc R17, R1
  479. pos2:
  480. {$ifdef CPUAVR_HAS_JMP_CALL}
  481. call fpc_mod_qword
  482. {$else CPUAVR_HAS_JMP_CALL}
  483. rcall fpc_mod_qword
  484. {$endif CPUAVR_HAS_JMP_CALL}
  485. sbrs R30, 7 // Not finished if sign bit is set
  486. rjmp fin
  487. com R25 // Convert to 2's complement
  488. com R24 // Complement all bits...
  489. com R23
  490. com R22
  491. com R21
  492. com R20
  493. com R19
  494. com R18
  495. ldi R31, 1
  496. add R18, R31 // ...and add 1 to answer
  497. adc R19, R1
  498. adc R20, R1
  499. adc R21, R1
  500. adc R22, R1
  501. adc R23, R1
  502. adc R24, R1
  503. adc R25, R1
  504. fin:
  505. end;
  506. {$endif CPUAVR_16_REGS}