RPI.CPU.Mod 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407
  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. CONST MemorySize* = 964 * MB; MB = 1024 * 1024;
  49. VAR pageTable {ALIGNED (4000H)}: RECORD entry: ARRAY 4096 OF SIZE END;
  50. PROCEDURE IdentityMapMemory-;
  51. CONST Section = 2H; Domain0 = 0H; FullAccess = 0C00H; NormalWriteBackAllocate = 100CH; StronglyOrdered = 0H; Shareable = 10000H;
  52. CONST NormalMemory = Section + Domain0 + FullAccess + NormalWriteBackAllocate + Shareable;
  53. CONST StronglyOrderedMemory = Section + Domain0 + FullAccess + StronglyOrdered;
  54. VAR index: SIZE;
  55. BEGIN {UNCOOPERATIVE, UNCHECKED}
  56. FOR index := 0 TO MemorySize DIV MB - 1 DO pageTable.entry[index] := index * MB + NormalMemory END;
  57. FOR index := MemorySize DIV MB TO LEN (pageTable.entry) - 1 DO pageTable.entry[index] := index * MB + StronglyOrderedMemory 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. MCR 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. (* hardware registers *)
  79. CONST WDOG* = 03F100024H; RSTC* = 03F10001CH; PASSWORD = 05A000000H; FULLRESET = 000000020H;
  80. CONST GPFSEL0* = 03F200004H; FSEL0* = 0; FSEL1* = 3; FSEL2* = 6; FSEL3* = 9; FSEL4* = 12; FSEL5* = 15; FSEL6* = 18; FSEL7* = 21; FSEL8* = 24; FSEL9* = 27;
  81. CONST GPFSEL1* = 03F200008H; FSEL10* = 0; FSEL11* = 3; FSEL12* = 6; FSEL13* = 9; FSEL14* = 12; FSEL15* = 15; FSEL16* = 18; FSEL17* = 21; FSEL18* = 24; FSEL19* = 27;
  82. CONST GPSET0* = 03F20001CH; GPSET1* = 03F200020H;
  83. CONST GPCLR0* = 03F200028H; GPCLR1* = 03F20002CH;
  84. CONST GPPUD* = 03F200094H; PUD* = 0;
  85. CONST GPPUDCLK0* = 03F200098H; GPPUDCLK1* = 03F20009CH;
  86. CONST IRQBasicPending* = 03F00B200H; IRQPending1* = 03F00B204H; IRQPending2* = 03F00B208H;
  87. CONST IRQEnable1* = 03F00B210H; IRQEnable2* = 03F00B214H; IRQEnableBasic* = 03F00B218H;
  88. CONST IRQDisable1* = 03F00B21CH; IRQDisable2* = 03F00B220H; IRQDisableBasic* = 03F00B224H;
  89. CONST STCS* = 03F003000H; M0* = 0; M1* = 1; M2* = 2; M3* = 3;
  90. CONST STCLO* = 03F003004H; STCHI* = 03F003008H;
  91. CONST STC0* = 03F00300CH; STC1* = 03F003010H; STC2* = 03F003014H; STC3* = 03F003018H;
  92. CONST FUARTCLK* = 3000000;
  93. CONST UART_DR* = 03F201000H;
  94. CONST UART_FR* = 03F201018H; RXFE* = 4; TXFF* = 5; TXFE* = 7;
  95. CONST UART_IBRD* = 03F201024H;
  96. CONST UART_FBRD* = 03F201028H;
  97. CONST UART_LCRH* = 03F20102CH; FEN* = 4; WLEN8* = {5, 6};
  98. CONST UART_CR* = 03F201030H; UARTEN* = 0; TXE* = 8; RXE* = 9;
  99. CONST UART_IMSC* = 03F201038H; RXIM* = 4;
  100. CONST UART_ICR* = 03F201044H; RXIC* = 4;
  101. PROCEDURE ReadWord- (register: ADDRESS): WORD;
  102. CODE
  103. LDR R2, [FP, #register]
  104. LDR R0, [R2, #0]
  105. END ReadWord;
  106. PROCEDURE ReadMask- (register: ADDRESS): SET;
  107. CODE
  108. LDR R2, [FP, #register]
  109. LDR R0, [R2, #0]
  110. END ReadMask;
  111. PROCEDURE WriteWord- (register: ADDRESS; value: ADDRESS);
  112. CODE
  113. LDR R2, [FP, #register]
  114. LDR R3, [FP, #value]
  115. STR R3, [R2, #0]
  116. END WriteWord;
  117. PROCEDURE WriteMask- (register: ADDRESS; value: SET);
  118. CODE
  119. LDR R2, [FP, #register]
  120. LDR R3, [FP, #value]
  121. STR R3, [R2, #0]
  122. END WriteMask;
  123. PROCEDURE Mask- (register: ADDRESS; value: SET);
  124. CODE
  125. LDR R2, [FP, #register]
  126. LDR R3, [FP, #value]
  127. LDR R4, [R2, #0]
  128. ORR R4, R4, R3
  129. STR R4, [R2, #0]
  130. END Mask;
  131. PROCEDURE Unmask- (register: ADDRESS; value: SET);
  132. CODE
  133. LDR R2, [FP, #register]
  134. LDR R3, [FP, #value]
  135. LDR R4, [R2, #0]
  136. BIC R4, R4, R3
  137. STR R4, [R2, #0]
  138. END Unmask;
  139. (* interrupt handling *)
  140. CONST Interrupts* = 7;
  141. CONST UndefinedInstruction* = 1; SoftwareInterrupt* = 2; PrefetchAbort* = 3; DataAbort* = 4; IRQ* = 5; FIQ* = 6;
  142. TYPE InterruptHandler* = PROCEDURE (index: SIZE);
  143. VAR handlers: ARRAY Interrupts OF InterruptHandler;
  144. PROCEDURE InstallInterrupt- (handler: InterruptHandler; index: SIZE): InterruptHandler;
  145. VAR previous: InterruptHandler;
  146. BEGIN {UNCOOPERATIVE, UNCHECKED}
  147. ASSERT (handler # NIL); ASSERT (index < Interrupts);
  148. REPEAT previous := CAS (handlers[index], NIL, NIL) UNTIL CAS (handlers[index], previous, handler) = previous;
  149. RETURN previous;
  150. END InstallInterrupt;
  151. PROCEDURE HandleInterrupt (index: SIZE);
  152. BEGIN {UNCOOPERATIVE, UNCHECKED}
  153. SYSTEM.SetActivity (NIL);
  154. IF index = IRQ THEN WriteMask (IRQDisable1, ReadMask (IRQPending1)); WriteMask (IRQDisable2, ReadMask (IRQPending2)) END;
  155. IF handlers[index] # NIL THEN handlers[index] (index) ELSE HALT (1234) END;
  156. END HandleInterrupt;
  157. PROCEDURE DisableInterrupt- (index: SIZE);
  158. VAR previous: InterruptHandler;
  159. BEGIN {UNCOOPERATIVE, UNCHECKED}
  160. ASSERT (index < Interrupts);
  161. IF index = IRQ THEN WriteMask (IRQDisable1, ReadMask (IRQEnable1)); WriteMask (IRQDisable2, ReadMask (IRQEnable2)) END;
  162. REPEAT previous := CAS (handlers[index], NIL, NIL) UNTIL CAS (handlers[index], previous, NIL) = previous;
  163. END DisableInterrupt;
  164. PROCEDURE Initialize-;
  165. CODE
  166. ADD R2, PC, #vector
  167. MOV R3, #0
  168. ADD R4, R3, #vector_end - vector
  169. copy:
  170. CMP R3, R4
  171. BEQ vector_end
  172. LDR r5, [R2], #4
  173. STR r5, [R3], #4
  174. B copy
  175. vector:
  176. LDR PC, [PC, #header-$-8]
  177. LDR PC, [PC, #undefined_instruction-$-8]
  178. LDR PC, [PC, #software_interrupt-$-8]
  179. LDR PC, [PC, #prefetch_abort-$-8]
  180. LDR PC, [PC, #data_abort-$-8]
  181. MOV R0, R0
  182. LDR PC, [PC, #irq-$-8]
  183. fiq:
  184. STMDB SP!, {R0, R1, R2, R3, R4, R5, R6, R7, LR}
  185. MOV R2, #UndefinedInstruction
  186. STR R2, [SP, #-4]!
  187. LDR R2, [PC, #handle-$-8]
  188. BLX R2
  189. ADD SP, SP, #4
  190. LDMIA SP!, {R0, R1, R2, R3, R4, R5, R6, R7, LR}
  191. SUBS PC, LR, #4
  192. header:
  193. d32 0x8000
  194. undefined_instruction:
  195. d32 UndefinedInstructionHandler
  196. software_interrupt:
  197. d32 SoftwareInterruptHandler
  198. prefetch_abort:
  199. d32 PrefetchAbortHandler
  200. data_abort:
  201. d32 DataAbortHandler
  202. irq:
  203. d32 IRQHandler
  204. handle:
  205. d32 HandleInterrupt
  206. vector_end:
  207. MOV R2, #0b10001
  208. MSR CPSR_c, R2
  209. MOV SP, #0x7000
  210. MOV R2, #0b10010
  211. MSR CPSR_c, R2
  212. MOV SP, #0x6000
  213. MOV R2, #0b10111
  214. MSR CPSR_c, R2
  215. MOV SP, #0x5000
  216. MOV R2, #0b11011
  217. MSR CPSR_c, R2
  218. MOV SP, #0x4000
  219. MOV R2, #0b10011
  220. MSR CPSR_c, R2
  221. END Initialize;
  222. PROCEDURE {NOPAF} UndefinedInstructionHandler;
  223. CODE
  224. STMDB SP!, {R0, R1, R2, R3, R4, R5, R6, R7, R8, R9, R10, R11, R12, LR}
  225. MOV R2, #UndefinedInstruction
  226. STR R2, [SP, #-4]!
  227. LDR R2, [PC, #handle-$-8]
  228. BLX R2
  229. ADD SP, SP, #4
  230. LDMIA SP!, {R0, R1, R2, R3, R4, R5, R6, R7, R8, R9, R10, R11, R12, LR}
  231. MOVS PC, LR
  232. handle:
  233. d32 HandleInterrupt
  234. END UndefinedInstructionHandler;
  235. PROCEDURE {NOPAF} SoftwareInterruptHandler;
  236. CODE
  237. STMDB SP!, {R0, R1, R2, R3, R4, R5, R6, R7, R8, R9, R10, R11, R12, LR}
  238. MOV R2, #SoftwareInterrupt
  239. STR R2, [SP, #-4]!
  240. LDR R2, [PC, #handle-$-8]
  241. BLX R2
  242. ADD SP, SP, #4
  243. LDMIA SP!, {R0, R1, R2, R3, R4, R5, R6, R7, R8, R9, R10, R11, R12, LR}
  244. MOVS PC, LR
  245. handle:
  246. d32 HandleInterrupt
  247. END SoftwareInterruptHandler;
  248. PROCEDURE {NOPAF} PrefetchAbortHandler;
  249. CODE
  250. STMDB SP!, {R0, R1, R2, R3, R4, R5, R6, R7, R8, R9, R10, R11, R12, LR}
  251. MOV R2, #PrefetchAbort
  252. STR R2, [SP, #-4]!
  253. LDR R2, [PC, #handle-$-8]
  254. BLX R2
  255. ADD SP, SP, #4
  256. LDMIA SP!, {R0, R1, R2, R3, R4, R5, R6, R7, R8, R9, R10, R11, R12, LR}
  257. SUBS PC, LR, #4
  258. handle:
  259. d32 HandleInterrupt
  260. END PrefetchAbortHandler;
  261. PROCEDURE {NOPAF} DataAbortHandler;
  262. CODE
  263. STMDB SP!, {R0, R1, R2, R3, R4, R5, R6, R7, R8, R9, R10, R11, R12, LR}
  264. MOV R2, #DataAbort
  265. STR R2, [SP, #-4]!
  266. LDR R2, [PC, #handle-$-8]
  267. BLX R2
  268. ADD SP, SP, #4
  269. LDMIA SP!, {R0, R1, R2, R3, R4, R5, R6, R7, R8, R9, R10, R11, R12, LR}
  270. SUBS PC, LR, #4
  271. handle:
  272. d32 HandleInterrupt
  273. END DataAbortHandler;
  274. PROCEDURE {NOPAF} IRQHandler;
  275. CODE
  276. STMDB SP!, {R0, R1, R2, R3, R4, R5, R6, R7, R8, R9, R10, R11, R12, LR}
  277. MOV R2, #IRQ
  278. STR R2, [SP, #-4]!
  279. LDR R2, [PC, #handle-$-8]
  280. BLX R2
  281. ADD SP, SP, #4
  282. LDMIA SP!, {R0, R1, R2, R3, R4, R5, R6, R7, R8, R9, R10, R11, R12, LR}
  283. SUBS PC, LR, #4
  284. handle:
  285. d32 HandleInterrupt
  286. END IRQHandler;
  287. (* compiler intrinsics *)
  288. TYPE ULONGINT = LONGINT; (* alias to make distinction between signed and unsigned more clear *)
  289. TYPE UHUGEINT = HUGEINT;
  290. PROCEDURE DivS64*(left, right: HUGEINT): HUGEINT;
  291. VAR result, dummy: HUGEINT;
  292. BEGIN
  293. DivModS64(left, right, result, dummy); RETURN result
  294. END DivS64;
  295. PROCEDURE ModS64*(left, right: HUGEINT): HUGEINT;
  296. VAR result, dummy: HUGEINT;
  297. BEGIN
  298. DivModS64(left, right, dummy, result); RETURN result
  299. END ModS64;
  300. (* signed division and modulus
  301. - note: this implements the mathematical definition of DIV and MOD in contrast to the symmetric one
  302. *)
  303. PROCEDURE DivModS64*(dividend, divisor: HUGEINT; VAR quotient, remainder: HUGEINT);
  304. BEGIN
  305. ASSERT(divisor > 0);
  306. IF dividend >= 0 THEN
  307. DivModU64(dividend, divisor, quotient, remainder)
  308. ELSE
  309. dividend := -dividend;
  310. DivModU64(dividend, divisor, quotient, remainder);
  311. quotient := -quotient;
  312. IF remainder # 0 THEN
  313. DEC(quotient);
  314. remainder := divisor - remainder
  315. END
  316. END
  317. END DivModS64;
  318. (* Count leading zeros in a binary representation of a given 64-bit integer number *)
  319. PROCEDURE Clz64*(x: UHUGEINT): LONGINT;
  320. CODE
  321. ; high-half
  322. LDR R1, [FP,#x+4]
  323. CMP R1, #0 ; if high-half is zero count leading zeros of the low-half
  324. BEQ LowHalf
  325. CLZ R0, R1
  326. B Exit
  327. ; low-half
  328. LowHalf:
  329. LDR R1, [FP,#x]
  330. CLZ R0, R1
  331. ADD R0, R0, #32 ; add 32 zeros from the high-half
  332. Exit:
  333. END Clz64;
  334. (*
  335. Fast 64-bit unsigned integer division/modulo (Alexey Morozov)
  336. *)
  337. PROCEDURE DivModU64*(dividend, divisor: UHUGEINT; VAR quotient, remainder: UHUGEINT);
  338. VAR m: LONGINT;
  339. BEGIN
  340. quotient := 0;
  341. IF dividend = 0 THEN remainder := 0; RETURN; END;
  342. IF dividend < divisor THEN remainder := dividend; RETURN; END;
  343. m := Clz64(divisor) - Clz64(dividend);
  344. ASSERT(m >= 0);
  345. divisor := LSH(divisor,m);
  346. WHILE m >= 0 DO
  347. quotient := LSH(quotient,1);
  348. IF dividend >= divisor THEN
  349. INC(quotient);
  350. DEC(dividend,divisor);
  351. END;
  352. divisor := LSH(divisor,-1);
  353. DEC(m);
  354. END;
  355. remainder := dividend;
  356. END DivModU64;
  357. END CPU.