RPI.CPU.Mod 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566
  1. (* Runtime support for CPU internals *)
  2. (* Copyright (C) Florian Negele *)
  3. MODULE CPU;
  4. IMPORT SYSTEM;
  5. CONST StackSize* = 4096;
  6. CONST Quantum* = 100000;
  7. CONST CacheLineSize* = 32;
  8. CONST StackDisplacement* = 0;
  9. PROCEDURE Backoff-;
  10. CODE
  11. MOV R2, #0x100
  12. loop:
  13. SUBS R2, R2, #1
  14. BNE loop
  15. END Backoff;
  16. (* cpu control *)
  17. PROCEDURE Delay- (cycles: SIZE);
  18. CODE
  19. LDR R2, [FP, #cycles]
  20. delay:
  21. SUBS R2, R2, #1
  22. BNE delay
  23. END Delay;
  24. PROCEDURE {NORETURN} Reset-;
  25. BEGIN {UNCOOPERATIVE, UNCHECKED}
  26. WriteWord (WDOG, PASSWORD + 1);
  27. WriteWord (RSTC, PASSWORD + FULLRESET);
  28. Halt;
  29. END Reset;
  30. PROCEDURE {NORETURN} Halt-;
  31. CODE
  32. MRS R2, CPSR
  33. ORR R2, R2, #0b1100000
  34. MSR CPSR_c, r2
  35. WFI
  36. END Halt;
  37. PROCEDURE -SaveResult-;
  38. CODE
  39. STMDB SP!, {R0, R1}
  40. END SaveResult;
  41. PROCEDURE -RestoreResultAndReturn-;
  42. CODE
  43. LDMIA SP!, {R0, R1}
  44. ADD SP, FP, #4
  45. LDMIA SP!, {FP, PC}
  46. END RestoreResultAndReturn;
  47. (* memory management *)
  48. VAR pageTable {ALIGNED (4000H)}: RECORD entry: ARRAY 4096 OF SIZE END;
  49. PROCEDURE IdentityMapMemory- (size: SIZE);
  50. CONST Section = 2H; Domain0 = 0H; FullAccess = 0C00H; NormalWriteBackAllocate = 100CH; StronglyOrdered = 0H; Shareable = 10000H;
  51. CONST NormalMemory = Section + Domain0 + FullAccess + NormalWriteBackAllocate + Shareable;
  52. CONST StronglyOrderedMemory = Section + Domain0 + FullAccess + StronglyOrdered;
  53. VAR index: SIZE;
  54. BEGIN {UNCOOPERATIVE, UNCHECKED}
  55. index := 0; size := size DIV 100000H;
  56. WHILE index # size DO pageTable.entry[index] := index * 100000H + NormalMemory; INC (index) END;
  57. WHILE index # LEN (pageTable.entry) DO pageTable.entry[index] := index * 100000H + StronglyOrderedMemory; INC (index) END;
  58. END IdentityMapMemory;
  59. PROCEDURE EnableMemoryManagementUnit-;
  60. CODE
  61. load:
  62. LDR R0, [PC, #page-$-8]
  63. MCR P15, 0, R0, C2, C0, 0
  64. B grant
  65. page:
  66. d32 pageTable
  67. grant:
  68. MOV R0, #0b11
  69. MCR P15, 0, R0, C3, C0, 0
  70. enable:
  71. MRC P15, 0, R0, C1, C0, 0
  72. ORR R0, R0, #0b1 ; memory protection
  73. ORR R0, R0, #0b100 ; data and unified cache
  74. ORR R0, R0, #0b100000000000 ; branch prediction
  75. ORR R0, R0, #0b1000000000000 ; instruction cache
  76. MCR P15, 0, R0, C1, C0, 0
  77. END EnableMemoryManagementUnit;
  78. PROCEDURE Invalidate- (address: ADDRESS);
  79. CODE
  80. LDR R0, [FP, #address]
  81. BIC R0, R0, #(CacheLineSize - 1)
  82. MCR P15, 0, R0, C7, C6, 1
  83. END Invalidate;
  84. PROCEDURE Clean- (address: ADDRESS);
  85. CODE
  86. LDR R0, [FP, #address]
  87. BIC R0, R0, #(CacheLineSize - 1)
  88. MCR P15, 0, R0, C7, C10, 1
  89. END Clean;
  90. (* hardware registers *)
  91. CONST WDOG* = 03F100024H; RSTC* = 03F10001CH; PASSWORD = 05A000000H; FULLRESET = 000000020H;
  92. CONST GPFSEL0* = 03F200000H; FSEL0* = 0; FSEL1* = 3; FSEL2* = 6; FSEL3* = 9; FSEL4* = 12; FSEL5* = 15; FSEL6* = 18; FSEL7* = 21; FSEL8* = 24; FSEL9* = 27;
  93. CONST GPFSEL1* = 03F200004H; FSEL10* = 0; FSEL11* = 3; FSEL12* = 6; FSEL13* = 9; FSEL14* = 12; FSEL15* = 15; FSEL16* = 18; FSEL17* = 21; FSEL18* = 24; FSEL19* = 27;
  94. GPFSEL2* = 03F200008H; GPFSEL3* = 03F20000CH; GPFSEL4* = 03F200010H; GPFSEL5* = 03F200014H;
  95. CONST GPSET0* = 03F20001CH; GPSET1* = 03F200020H;
  96. CONST GPCLR0* = 03F200028H; GPCLR1* = 03F20002CH;
  97. CONST GPPUD* = 03F200094H; PUD* = 0;
  98. CONST GPPUDCLK0* = 03F200098H; GPPUDCLK1* = 03F20009CH;
  99. CONST IRQBasicPending* = 03F00B200H; IRQPending1* = 03F00B204H; IRQPending2* = 03F00B208H;
  100. CONST IRQEnable1* = 03F00B210H; IRQEnable2* = 03F00B214H; IRQEnableBasic* = 03F00B218H;
  101. CONST IRQDisable1* = 03F00B21CH; IRQDisable2* = 03F00B220H; IRQDisableBasic* = 03F00B224H;
  102. CONST STCS* = 03F003000H; M0* = 0; M1* = 1; M2* = 2; M3* = 3;
  103. CONST STCLO* = 03F003004H; STCHI* = 03F003008H;
  104. CONST STC0* = 03F00300CH; STC1* = 03F003010H; STC2* = 03F003014H; STC3* = 03F003018H;
  105. CONST FUARTCLK* = 3000000;
  106. CONST UART_DR* = 03F201000H;
  107. CONST UART_FR* = 03F201018H; RXFE* = 4; TXFF* = 5; TXFE* = 7;
  108. CONST UART_IBRD* = 03F201024H;
  109. CONST UART_FBRD* = 03F201028H;
  110. CONST UART_LCRH* = 03F20102CH; FEN* = 4; WLEN8* = {5, 6};
  111. CONST UART_CR* = 03F201030H; UARTEN* = 0; TXE* = 8; RXE* = 9;
  112. CONST UART_IMSC* = 03F201038H; RXIM* = 4;
  113. CONST UART_ICR* = 03F201044H; RXIC* = 4;
  114. PROCEDURE ReadWord- (register: ADDRESS): WORD;
  115. CODE
  116. LDR R2, [FP, #register]
  117. LDR R0, [R2, #0]
  118. END ReadWord;
  119. PROCEDURE ReadMask- (register: ADDRESS): SET;
  120. CODE
  121. LDR R2, [FP, #register]
  122. LDR R0, [R2, #0]
  123. END ReadMask;
  124. PROCEDURE WriteWord- (register: ADDRESS; value: ADDRESS);
  125. CODE
  126. LDR R2, [FP, #register]
  127. LDR R3, [FP, #value]
  128. STR R3, [R2, #0]
  129. END WriteWord;
  130. PROCEDURE WriteMask- (register: ADDRESS; value: SET);
  131. CODE
  132. LDR R2, [FP, #register]
  133. LDR R3, [FP, #value]
  134. STR R3, [R2, #0]
  135. END WriteMask;
  136. PROCEDURE Mask- (register: ADDRESS; value: SET);
  137. CODE
  138. LDR R2, [FP, #register]
  139. LDR R3, [FP, #value]
  140. LDR R4, [R2, #0]
  141. ORR R4, R4, R3
  142. STR R4, [R2, #0]
  143. END Mask;
  144. PROCEDURE Unmask- (register: ADDRESS; value: SET);
  145. CODE
  146. LDR R2, [FP, #register]
  147. LDR R3, [FP, #value]
  148. LDR R4, [R2, #0]
  149. BIC R4, R4, R3
  150. STR R4, [R2, #0]
  151. END Unmask;
  152. (* combined mask / unmask: clear mask and set value *)
  153. PROCEDURE MaskIn-(register: ADDRESS; mask, value: SET);
  154. CODE
  155. LDR R2, [FP, #register]
  156. LDR R3, [FP, #mask]
  157. LDR R4, [FP, #value]
  158. LDR R5, [R2, #0]
  159. BIC R5, R5, R3
  160. ORR R5, R5, R4
  161. STR R5, [R2, #0]
  162. END MaskIn;
  163. (* interrupt handling *)
  164. CONST Interrupts* = 7;
  165. CONST UndefinedInstruction* = 1; SoftwareInterrupt* = 2; PrefetchAbort* = 3; DataAbort* = 4; IRQ* = 5; FIQ* = 6;
  166. TYPE InterruptHandler* = PROCEDURE (index: SIZE);
  167. VAR handlers: ARRAY Interrupts OF InterruptHandler;
  168. PROCEDURE InstallInterrupt- (handler: InterruptHandler; index: SIZE): InterruptHandler;
  169. VAR previous: InterruptHandler;
  170. BEGIN {UNCOOPERATIVE, UNCHECKED}
  171. ASSERT (handler # NIL); ASSERT (index < Interrupts);
  172. REPEAT previous := CAS (handlers[index], NIL, NIL) UNTIL CAS (handlers[index], previous, handler) = previous;
  173. RETURN previous;
  174. END InstallInterrupt;
  175. PROCEDURE HandleInterrupt (index: SIZE);
  176. BEGIN {UNCOOPERATIVE, UNCHECKED}
  177. SYSTEM.SetActivity (NIL);
  178. IF index = IRQ THEN WriteMask (IRQDisable1, ReadMask (IRQPending1)); WriteMask (IRQDisable2, ReadMask (IRQPending2)) END;
  179. IF handlers[index] # NIL THEN handlers[index] (index) ELSE HALT (1234) END;
  180. END HandleInterrupt;
  181. PROCEDURE DisableInterrupt- (index: SIZE);
  182. VAR previous: InterruptHandler;
  183. BEGIN {UNCOOPERATIVE, UNCHECKED}
  184. ASSERT (index < Interrupts);
  185. IF index = IRQ THEN WriteMask (IRQDisable1, ReadMask (IRQEnable1)); WriteMask (IRQDisable2, ReadMask (IRQEnable2)) END;
  186. REPEAT previous := CAS (handlers[index], NIL, NIL) UNTIL CAS (handlers[index], previous, NIL) = previous;
  187. END DisableInterrupt;
  188. PROCEDURE Initialize-;
  189. CODE
  190. ADD R2, PC, #vector-$-8
  191. MOV R3, #0
  192. ADD R4, R3, #vector_end - vector
  193. copy:
  194. CMP R3, R4
  195. BEQ vector_end
  196. LDR r5, [R2], #4
  197. STR r5, [R3], #4
  198. B copy
  199. vector:
  200. LDR PC, [PC, #header-$-8]
  201. LDR PC, [PC, #undefined_instruction-$-8]
  202. LDR PC, [PC, #software_interrupt-$-8]
  203. LDR PC, [PC, #prefetch_abort-$-8]
  204. LDR PC, [PC, #data_abort-$-8]
  205. MOV R0, R0
  206. LDR PC, [PC, #irq-$-8]
  207. fiq:
  208. STMDB SP!, {R0, R1, R2, R3, R4, R5, R6, R7, LR}
  209. MOV R2, #UndefinedInstruction
  210. STR R2, [SP, #-4]!
  211. LDR R2, [PC, #handle-$-8]
  212. BLX R2
  213. ADD SP, SP, #4
  214. LDMIA SP!, {R0, R1, R2, R3, R4, R5, R6, R7, LR}
  215. SUBS PC, LR, #4
  216. header:
  217. d32 0x8000
  218. undefined_instruction:
  219. d32 UndefinedInstructionHandler
  220. software_interrupt:
  221. d32 SoftwareInterruptHandler
  222. prefetch_abort:
  223. d32 PrefetchAbortHandler
  224. data_abort:
  225. d32 DataAbortHandler
  226. irq:
  227. d32 IRQHandler
  228. handle:
  229. d32 HandleInterrupt
  230. vector_end:
  231. MOV R2, #0b10001
  232. MSR CPSR_c, R2
  233. MOV SP, #0x7000
  234. MOV R2, #0b10010
  235. MSR CPSR_c, R2
  236. MOV SP, #0x6000
  237. MOV R2, #0b10111
  238. MSR CPSR_c, R2
  239. MOV SP, #0x5000
  240. MOV R2, #0b11011
  241. MSR CPSR_c, R2
  242. MOV SP, #0x4000
  243. MOV R2, #0b10011
  244. MSR CPSR_c, R2
  245. END Initialize;
  246. PROCEDURE {NOPAF} UndefinedInstructionHandler;
  247. CODE
  248. STMDB SP!, {R0, R1, R2, R3, R4, R5, R6, R7, R8, R9, R10, R11, R12, LR}
  249. MOV R2, #UndefinedInstruction
  250. STR R2, [SP, #-4]!
  251. LDR R2, [PC, #handle-$-8]
  252. BLX R2
  253. ADD SP, SP, #4
  254. LDMIA SP!, {R0, R1, R2, R3, R4, R5, R6, R7, R8, R9, R10, R11, R12, LR}
  255. MOVS PC, LR
  256. handle:
  257. d32 HandleInterrupt
  258. END UndefinedInstructionHandler;
  259. PROCEDURE {NOPAF} SoftwareInterruptHandler;
  260. CODE
  261. STMDB SP!, {R0, R1, R2, R3, R4, R5, R6, R7, R8, R9, R10, R11, R12, LR}
  262. MOV R2, #SoftwareInterrupt
  263. STR R2, [SP, #-4]!
  264. LDR R2, [PC, #handle-$-8]
  265. BLX R2
  266. ADD SP, SP, #4
  267. LDMIA SP!, {R0, R1, R2, R3, R4, R5, R6, R7, R8, R9, R10, R11, R12, LR}
  268. MOVS PC, LR
  269. handle:
  270. d32 HandleInterrupt
  271. END SoftwareInterruptHandler;
  272. PROCEDURE {NOPAF} PrefetchAbortHandler;
  273. CODE
  274. STMDB SP!, {R0, R1, R2, R3, R4, R5, R6, R7, R8, R9, R10, R11, R12, LR}
  275. MOV R2, #PrefetchAbort
  276. STR R2, [SP, #-4]!
  277. LDR R2, [PC, #handle-$-8]
  278. BLX R2
  279. ADD SP, SP, #4
  280. LDMIA SP!, {R0, R1, R2, R3, R4, R5, R6, R7, R8, R9, R10, R11, R12, LR}
  281. SUBS PC, LR, #4
  282. handle:
  283. d32 HandleInterrupt
  284. END PrefetchAbortHandler;
  285. PROCEDURE {NOPAF} DataAbortHandler;
  286. CODE
  287. STMDB SP!, {R0, R1, R2, R3, R4, R5, R6, R7, R8, R9, R10, R11, R12, LR}
  288. MOV R2, #DataAbort
  289. STR R2, [SP, #-4]!
  290. LDR R2, [PC, #handle-$-8]
  291. BLX R2
  292. ADD SP, SP, #4
  293. LDMIA SP!, {R0, R1, R2, R3, R4, R5, R6, R7, R8, R9, R10, R11, R12, LR}
  294. SUBS PC, LR, #4
  295. handle:
  296. d32 HandleInterrupt
  297. END DataAbortHandler;
  298. PROCEDURE {NOPAF} IRQHandler;
  299. CODE
  300. STMDB SP!, {R0, R1, R2, R3, R4, R5, R6, R7, R8, R9, R10, R11, R12, LR}
  301. MOV R2, #IRQ
  302. STR R2, [SP, #-4]!
  303. LDR R2, [PC, #handle-$-8]
  304. BLX R2
  305. ADD SP, SP, #4
  306. LDMIA SP!, {R0, R1, R2, R3, R4, R5, R6, R7, R8, R9, R10, R11, R12, LR}
  307. SUBS PC, LR, #4
  308. handle:
  309. d32 HandleInterrupt
  310. END IRQHandler;
  311. (* compiler intrinsics *)
  312. TYPE ULONGINT = LONGINT; (* alias to make distinction between signed and unsigned more clear *)
  313. TYPE UHUGEINT = HUGEINT;
  314. PROCEDURE DivS8*(left, right: SHORTINT): SHORTINT;
  315. VAR result, dummy: LONGINT;
  316. BEGIN {UNCOOPERATIVE, UNCHECKED} DivModS32(left, right, result, dummy); RETURN SHORTINT(result)
  317. END DivS8;
  318. PROCEDURE DivS16*(left, right: INTEGER): INTEGER;
  319. VAR result, dummy: LONGINT;
  320. BEGIN {UNCOOPERATIVE, UNCHECKED} DivModS32(left, right, result, dummy); RETURN INTEGER(result)
  321. END DivS16;
  322. PROCEDURE DivS32*(left, right: LONGINT): LONGINT;
  323. VAR result, dummy: LONGINT;
  324. BEGIN {UNCOOPERATIVE, UNCHECKED} DivModS32(left, right, result, dummy); RETURN result
  325. END DivS32;
  326. PROCEDURE DivU32*(left, right: ULONGINT): ULONGINT;
  327. VAR result, dummy: LONGINT;
  328. BEGIN {UNCOOPERATIVE, UNCHECKED} DivModU32(left, right, result, dummy); RETURN result
  329. END DivU32;
  330. PROCEDURE DivS64*(left, right: HUGEINT): HUGEINT;
  331. VAR result, dummy: HUGEINT;
  332. BEGIN {UNCOOPERATIVE, UNCHECKED} DivModS64(left, right, result, dummy); RETURN result
  333. END DivS64;
  334. PROCEDURE ModS8*(left, right: SHORTINT): SHORTINT;
  335. VAR result, dummy: LONGINT;
  336. BEGIN {UNCOOPERATIVE, UNCHECKED} DivModS32(left, right, dummy, result); RETURN SHORTINT(result)
  337. END ModS8;
  338. PROCEDURE ModS16*(left, right: INTEGER): INTEGER;
  339. VAR result, dummy: LONGINT;
  340. BEGIN {UNCOOPERATIVE, UNCHECKED} DivModS32(left, right, dummy, result); RETURN INTEGER(result)
  341. END ModS16;
  342. PROCEDURE ModS32*(left, right: LONGINT): LONGINT;
  343. VAR result, dummy: LONGINT;
  344. BEGIN {UNCOOPERATIVE, UNCHECKED} DivModS32(left, right, dummy, result); RETURN result
  345. END ModS32;
  346. PROCEDURE ModU32*(left, right: ULONGINT): ULONGINT;
  347. VAR result, dummy: LONGINT;
  348. BEGIN {UNCOOPERATIVE, UNCHECKED} DivModU32(left, right, dummy, result); RETURN result
  349. END ModU32;
  350. PROCEDURE ModS64*(left, right: HUGEINT): HUGEINT;
  351. VAR result, dummy: HUGEINT;
  352. BEGIN {UNCOOPERATIVE, UNCHECKED}
  353. DivModS64(left, right, dummy, result); RETURN result
  354. END ModS64;
  355. (* signed division and modulus
  356. - note: this implements the mathematical definition of DIV and MOD in contrast to the symmetric one
  357. *)
  358. PROCEDURE DivModS32(dividend, divisor: LONGINT; VAR quotient, remainder: LONGINT);
  359. BEGIN {UNCOOPERATIVE, UNCHECKED}
  360. ASSERT(divisor > 0);
  361. IF dividend >= 0 THEN
  362. DivModU32(dividend, divisor, quotient, remainder)
  363. ELSE
  364. dividend := -dividend;
  365. DivModU32(dividend, divisor, quotient, remainder);
  366. quotient := -quotient;
  367. IF remainder # 0 THEN
  368. DEC(quotient);
  369. remainder := divisor - remainder
  370. END
  371. END
  372. END DivModS32;
  373. (*
  374. Fast 32-bit unsigned integer division/modulo (author Alexey Morozov)
  375. *)
  376. PROCEDURE DivModU32(dividend, divisor: ULONGINT; VAR quotient, remainder: ULONGINT);
  377. CODE
  378. MOV R2, #0 ; quotient will be stored in R2
  379. LDR R0, [FP,#dividend] ; R0 := dividend
  380. LDR R1, [FP,#divisor] ; R1 := divisor
  381. ; check for the case dividend < divisor
  382. CMP R0, R1
  383. BLT Exit ; nothing to do than setting quotient to 0 and remainder to dividend (R0)
  384. CLZ R3, R0 ; R3 := clz(dividend)
  385. CLZ R4, R1 ; R4 := clz(divisor)
  386. SUB R3, R4, R3 ; R2 := clz(divisor) - clz(dividend) , R2 >= 0
  387. LSL R1, R1, R3 ; scale divisor: divisor := LSH(divisor,clz(divisor)-clz(dividend))
  388. Loop:
  389. CMP R0, R1
  390. ADC R2, R2, R2
  391. SUBCS R0, R0, R1
  392. LSR R1, R1, #1
  393. SUBS R3, R3, #1
  394. BPL Loop
  395. ; R0 holds the remainder
  396. Exit:
  397. LDR R1, [FP,#quotient] ; R1 := address of quotient
  398. LDR R3, [FP,#remainder] ; R3 := address of remainder
  399. STR R2, [R1,#0] ; quotient := R1
  400. STR R0, [R3,#0] ; remainder := R0
  401. END DivModU32;
  402. (* signed division and modulus
  403. - note: this implements the mathematical definition of DIV and MOD in contrast to the symmetric one
  404. *)
  405. PROCEDURE DivModS64*(dividend, divisor: HUGEINT; VAR quotient, remainder: HUGEINT);
  406. BEGIN {UNCOOPERATIVE, UNCHECKED}
  407. ASSERT(divisor > 0);
  408. IF dividend >= 0 THEN
  409. DivModU64(dividend, divisor, quotient, remainder)
  410. ELSE
  411. dividend := -dividend;
  412. DivModU64(dividend, divisor, quotient, remainder);
  413. quotient := -quotient;
  414. IF remainder # 0 THEN
  415. DEC(quotient);
  416. remainder := divisor - remainder
  417. END
  418. END
  419. END DivModS64;
  420. (* Count leading zeros in a binary representation of a given 64-bit integer number *)
  421. PROCEDURE Clz64*(x: UHUGEINT): LONGINT;
  422. CODE
  423. ; high-half
  424. LDR R1, [FP,#x+4]
  425. CMP R1, #0 ; if high-half is zero count leading zeros of the low-half
  426. BEQ LowHalf
  427. CLZ R0, R1
  428. B Exit
  429. ; low-half
  430. LowHalf:
  431. LDR R1, [FP,#x]
  432. CLZ R0, R1
  433. ADD R0, R0, #32 ; add 32 zeros from the high-half
  434. Exit:
  435. END Clz64;
  436. (*
  437. Fast 64-bit unsigned integer division/modulo (Alexey Morozov)
  438. *)
  439. PROCEDURE DivModU64*(dividend, divisor: UHUGEINT; VAR quotient, remainder: UHUGEINT);
  440. VAR m: LONGINT;
  441. BEGIN {UNCOOPERATIVE, UNCHECKED}
  442. quotient := 0;
  443. IF dividend = 0 THEN remainder := 0; RETURN; END;
  444. IF dividend < divisor THEN remainder := dividend; RETURN; END;
  445. m := Clz64(divisor) - Clz64(dividend);
  446. ASSERT(m >= 0);
  447. divisor := LSH(divisor,m);
  448. WHILE m >= 0 DO
  449. quotient := LSH(quotient,1);
  450. IF dividend >= divisor THEN
  451. INC(quotient);
  452. DEC(dividend,divisor);
  453. END;
  454. divisor := LSH(divisor,-1);
  455. DEC(m);
  456. END;
  457. remainder := dividend;
  458. END DivModU64;
  459. PROCEDURE MulS64*(x, y: HUGEINT): HUGEINT;
  460. CODE
  461. ldr r0, [FP,#x]
  462. ldr r1, [FP,#x+4]
  463. ldr r2, [FP,#y]
  464. ldr r3, [FP,#y+4]
  465. muls r1, r1, r2
  466. muls r3, r3, r0
  467. adds r1, r1, r3
  468. lsrs r3, r0, #16
  469. lsrs r4, r2, #16
  470. muls r3, r3, r4
  471. adds r1, r1, r3
  472. lsrs r3, r0, #16
  473. uxth r0, r0
  474. uxth r2, r2
  475. muls r3, r3, r2
  476. muls r4, r4, r0
  477. muls r0, r0, r2
  478. movs r2, #0
  479. adds r3, r3, r4
  480. adcs r2, r2, r2
  481. lsls r2, r2, #16
  482. adds r1, r1, r2
  483. lsls r2, r3, #16
  484. lsrs r3, r3, #16
  485. adds r0, r0, r2
  486. adcs r1, r1, r3
  487. END MulS64;
  488. END CPU.