Zynq.CPU.Mod 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471
  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_CONTROL, LSH (0, CLKSEL) + LSH (0, CRV) + LSH (0248H, CKEY));
  27. WriteWord (WDOG_MODE, LSH (1, WDEN) + LSH (1, RSTEN) + LSH (0ABCH, ZKEY));
  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. (* hardware registers *)
  48. CONST PSS_RST_CTRL* = 0F8000200H; SOFT_RST* = 0;
  49. CONST UART_RST_CTRL* = 0F8000228H; UART0_CPU1X_RST* = 0; UART1_CPU1X_RST* = 1; UART0_REF_RST* = 2; UART1_REF_RST* = 3;
  50. CONST UART_REF_CLK* = 50000000;
  51. CONST UART0* = 0E0000000H; UART1* = 0E0001000H;
  52. CONST Control_reg0* = 000H; RXRST* = 0; TXRST* = 1; RXEN* = 2; RXDIS* = 3; TXEN* = 4; TXDIS* = 5;
  53. CONST mode_reg0* = 004H; CHMOD* = 8; NBSTOP* = 6; PAR* = 3; CHRL* = 1; CLKS* = 0;
  54. CONST Intrpt_dis_reg0* = 00CH;
  55. CONST Baud_rate_gen_reg0* = 018H; CD* = 0;
  56. CONST Channel_sts_reg0* = 02CH; TXEMPTY* = 3; TXFULL* = 4;
  57. CONST Baud_rate_divider_reg0* = 034H; BDIV* = 0;
  58. CONST TX_RX_FIFO0* = 030H; FIFO* = 0;
  59. CONST Global_Timer_Counter_Register0* = 0F8F00200H;
  60. CONST Global_Timer_Counter_Register1* = 0F8F00204H;
  61. CONST WDOG_MODE* = 0F8005000H; WDEN* = 0; RSTEN* = 1; ZKEY* = 12;
  62. CONST WDOG_CONTROL* = 0F8005004H; CLKSEL* = 0; CRV* = 2; CKEY* = 14;
  63. PROCEDURE ReadWord- (register: ADDRESS): WORD;
  64. CODE
  65. LDR R2, [FP, #register]
  66. LDR R0, [R2, #0]
  67. END ReadWord;
  68. PROCEDURE ReadMask- (register: ADDRESS): SET;
  69. CODE
  70. LDR R2, [FP, #register]
  71. LDR R0, [R2, #0]
  72. END ReadMask;
  73. PROCEDURE WriteWord- (register: ADDRESS; value: ADDRESS);
  74. CODE
  75. LDR R2, [FP, #register]
  76. LDR R3, [FP, #value]
  77. STR R3, [R2, #0]
  78. END WriteWord;
  79. PROCEDURE WriteMask- (register: ADDRESS; value: SET);
  80. CODE
  81. LDR R2, [FP, #register]
  82. LDR R3, [FP, #value]
  83. STR R3, [R2, #0]
  84. END WriteMask;
  85. PROCEDURE Mask- (register: ADDRESS; value: SET);
  86. CODE
  87. LDR R2, [FP, #register]
  88. LDR R3, [FP, #value]
  89. LDR R4, [R2, #0]
  90. ORR R4, R4, R3
  91. STR R4, [R2, #0]
  92. END Mask;
  93. PROCEDURE Unmask- (register: ADDRESS; value: SET);
  94. CODE
  95. LDR R2, [FP, #register]
  96. LDR R3, [FP, #value]
  97. LDR R4, [R2, #0]
  98. BIC R4, R4, R3
  99. STR R4, [R2, #0]
  100. END Unmask;
  101. (* combined mask / unmask: clear mask and set value *)
  102. PROCEDURE MaskIn-(register: ADDRESS; mask, value: SET);
  103. CODE
  104. LDR R2, [FP, #register]
  105. LDR R3, [FP, #mask]
  106. LDR R4, [FP, #value]
  107. LDR R5, [R2, #0]
  108. BIC R5, R5, R3
  109. ORR R5, R5, R4
  110. STR R5, [R2, #0]
  111. END MaskIn;
  112. (* interrupt handling *)
  113. CONST Interrupts* = 7;
  114. CONST UndefinedInstruction* = 1; SoftwareInterrupt* = 2; PrefetchAbort* = 3; DataAbort* = 4; IRQ* = 5; FIQ* = 6;
  115. TYPE InterruptHandler* = PROCEDURE (index: SIZE);
  116. VAR handlers: ARRAY Interrupts OF InterruptHandler;
  117. PROCEDURE InstallInterrupt- (handler: InterruptHandler; index: SIZE): InterruptHandler;
  118. VAR previous: InterruptHandler;
  119. BEGIN {UNCOOPERATIVE, UNCHECKED}
  120. ASSERT (handler # NIL); ASSERT (index < Interrupts);
  121. REPEAT previous := CAS (handlers[index], NIL, NIL) UNTIL CAS (handlers[index], previous, handler) = previous;
  122. RETURN previous;
  123. END InstallInterrupt;
  124. PROCEDURE HandleInterrupt (index: SIZE);
  125. BEGIN {UNCOOPERATIVE, UNCHECKED}
  126. SYSTEM.SetActivity (NIL);
  127. IF handlers[index] # NIL THEN handlers[index] (index) ELSE HALT (1234) END;
  128. END HandleInterrupt;
  129. PROCEDURE DisableInterrupt- (index: SIZE);
  130. VAR previous: InterruptHandler;
  131. BEGIN {UNCOOPERATIVE, UNCHECKED}
  132. ASSERT (index < Interrupts);
  133. REPEAT previous := CAS (handlers[index], NIL, NIL) UNTIL CAS (handlers[index], previous, NIL) = previous;
  134. END DisableInterrupt;
  135. PROCEDURE Initialize-;
  136. CODE
  137. ADD R2, PC, #vector-$-8
  138. MOV R3, #0
  139. ADD R4, R3, #vector_end - vector
  140. copy:
  141. CMP R3, R4
  142. BEQ vector_end
  143. LDR r5, [R2], #4
  144. STR r5, [R3], #4
  145. B copy
  146. vector:
  147. LDR PC, [PC, #header-$-8]
  148. LDR PC, [PC, #undefined_instruction-$-8]
  149. LDR PC, [PC, #software_interrupt-$-8]
  150. LDR PC, [PC, #prefetch_abort-$-8]
  151. LDR PC, [PC, #data_abort-$-8]
  152. MOV R0, R0
  153. LDR PC, [PC, #irq-$-8]
  154. fiq:
  155. STMDB SP!, {R0, R1, R2, R3, R4, R5, R6, R7, LR}
  156. MOV R2, #UndefinedInstruction
  157. STR R2, [SP, #-4]!
  158. LDR R2, [PC, #handle-$-8]
  159. BLX R2
  160. ADD SP, SP, #4
  161. LDMIA SP!, {R0, R1, R2, R3, R4, R5, R6, R7, LR}
  162. SUBS PC, LR, #4
  163. header:
  164. d32 0x8000
  165. undefined_instruction:
  166. d32 UndefinedInstructionHandler
  167. software_interrupt:
  168. d32 SoftwareInterruptHandler
  169. prefetch_abort:
  170. d32 PrefetchAbortHandler
  171. data_abort:
  172. d32 DataAbortHandler
  173. irq:
  174. d32 IRQHandler
  175. handle:
  176. d32 HandleInterrupt
  177. vector_end:
  178. MOV R2, #0b10001
  179. MSR CPSR_c, R2
  180. MOV SP, #0x7000
  181. MOV R2, #0b10010
  182. MSR CPSR_c, R2
  183. MOV SP, #0x6000
  184. MOV R2, #0b10111
  185. MSR CPSR_c, R2
  186. MOV SP, #0x5000
  187. MOV R2, #0b11011
  188. MSR CPSR_c, R2
  189. MOV SP, #0x4000
  190. MOV R2, #0b10011
  191. MSR CPSR_c, R2
  192. END Initialize;
  193. PROCEDURE {NOPAF} UndefinedInstructionHandler;
  194. CODE
  195. STMDB SP!, {R0, R1, R2, R3, R4, R5, R6, R7, R8, R9, R10, R11, R12, LR}
  196. MOV R2, #UndefinedInstruction
  197. STR R2, [SP, #-4]!
  198. LDR R2, [PC, #handle-$-8]
  199. BLX R2
  200. ADD SP, SP, #4
  201. LDMIA SP!, {R0, R1, R2, R3, R4, R5, R6, R7, R8, R9, R10, R11, R12, LR}
  202. MOVS PC, LR
  203. handle:
  204. d32 HandleInterrupt
  205. END UndefinedInstructionHandler;
  206. PROCEDURE {NOPAF} SoftwareInterruptHandler;
  207. CODE
  208. STMDB SP!, {R0, R1, R2, R3, R4, R5, R6, R7, R8, R9, R10, R11, R12, LR}
  209. MOV R2, #SoftwareInterrupt
  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, R8, R9, R10, R11, R12, LR}
  215. MOVS PC, LR
  216. handle:
  217. d32 HandleInterrupt
  218. END SoftwareInterruptHandler;
  219. PROCEDURE {NOPAF} PrefetchAbortHandler;
  220. CODE
  221. STMDB SP!, {R0, R1, R2, R3, R4, R5, R6, R7, R8, R9, R10, R11, R12, LR}
  222. MOV R2, #PrefetchAbort
  223. STR R2, [SP, #-4]!
  224. LDR R2, [PC, #handle-$-8]
  225. BLX R2
  226. ADD SP, SP, #4
  227. LDMIA SP!, {R0, R1, R2, R3, R4, R5, R6, R7, R8, R9, R10, R11, R12, LR}
  228. SUBS PC, LR, #4
  229. handle:
  230. d32 HandleInterrupt
  231. END PrefetchAbortHandler;
  232. PROCEDURE {NOPAF} DataAbortHandler;
  233. CODE
  234. STMDB SP!, {R0, R1, R2, R3, R4, R5, R6, R7, R8, R9, R10, R11, R12, LR}
  235. MOV R2, #DataAbort
  236. STR R2, [SP, #-4]!
  237. LDR R2, [PC, #handle-$-8]
  238. BLX R2
  239. ADD SP, SP, #4
  240. LDMIA SP!, {R0, R1, R2, R3, R4, R5, R6, R7, R8, R9, R10, R11, R12, LR}
  241. SUBS PC, LR, #4
  242. handle:
  243. d32 HandleInterrupt
  244. END DataAbortHandler;
  245. PROCEDURE {NOPAF} IRQHandler;
  246. CODE
  247. STMDB SP!, {R0, R1, R2, R3, R4, R5, R6, R7, R8, R9, R10, R11, R12, LR}
  248. MOV R2, #IRQ
  249. STR R2, [SP, #-4]!
  250. LDR R2, [PC, #handle-$-8]
  251. BLX R2
  252. ADD SP, SP, #4
  253. LDMIA SP!, {R0, R1, R2, R3, R4, R5, R6, R7, R8, R9, R10, R11, R12, LR}
  254. SUBS PC, LR, #4
  255. handle:
  256. d32 HandleInterrupt
  257. END IRQHandler;
  258. (* compiler intrinsics *)
  259. TYPE ULONGINT = LONGINT; (* alias to make distinction between signed and unsigned more clear *)
  260. TYPE UHUGEINT = HUGEINT;
  261. PROCEDURE DivS8*(left, right: SHORTINT): SHORTINT;
  262. VAR result, dummy: LONGINT;
  263. BEGIN {UNCOOPERATIVE, UNCHECKED} DivModS32(left, right, result, dummy); RETURN SHORTINT(result)
  264. END DivS8;
  265. PROCEDURE DivS16*(left, right: INTEGER): INTEGER;
  266. VAR result, dummy: LONGINT;
  267. BEGIN {UNCOOPERATIVE, UNCHECKED} DivModS32(left, right, result, dummy); RETURN INTEGER(result)
  268. END DivS16;
  269. PROCEDURE DivS32*(left, right: LONGINT): LONGINT;
  270. VAR result, dummy: LONGINT;
  271. BEGIN {UNCOOPERATIVE, UNCHECKED} DivModS32(left, right, result, dummy); RETURN result
  272. END DivS32;
  273. PROCEDURE DivU32*(left, right: ULONGINT): ULONGINT;
  274. VAR result, dummy: LONGINT;
  275. BEGIN {UNCOOPERATIVE, UNCHECKED} DivModU32(left, right, result, dummy); RETURN result
  276. END DivU32;
  277. PROCEDURE DivS64*(left, right: HUGEINT): HUGEINT;
  278. VAR result, dummy: HUGEINT;
  279. BEGIN {UNCOOPERATIVE, UNCHECKED} DivModS64(left, right, result, dummy); RETURN result
  280. END DivS64;
  281. PROCEDURE ModS8*(left, right: SHORTINT): SHORTINT;
  282. VAR result, dummy: LONGINT;
  283. BEGIN {UNCOOPERATIVE, UNCHECKED} DivModS32(left, right, dummy, result); RETURN SHORTINT(result)
  284. END ModS8;
  285. PROCEDURE ModS16*(left, right: INTEGER): INTEGER;
  286. VAR result, dummy: LONGINT;
  287. BEGIN {UNCOOPERATIVE, UNCHECKED} DivModS32(left, right, dummy, result); RETURN INTEGER(result)
  288. END ModS16;
  289. PROCEDURE ModS32*(left, right: LONGINT): LONGINT;
  290. VAR result, dummy: LONGINT;
  291. BEGIN {UNCOOPERATIVE, UNCHECKED} DivModS32(left, right, dummy, result); RETURN result
  292. END ModS32;
  293. PROCEDURE ModU32*(left, right: ULONGINT): ULONGINT;
  294. VAR result, dummy: LONGINT;
  295. BEGIN {UNCOOPERATIVE, UNCHECKED} DivModU32(left, right, dummy, result); RETURN result
  296. END ModU32;
  297. PROCEDURE ModS64*(left, right: HUGEINT): HUGEINT;
  298. VAR result, dummy: HUGEINT;
  299. BEGIN {UNCOOPERATIVE, UNCHECKED}
  300. DivModS64(left, right, dummy, result); RETURN result
  301. END ModS64;
  302. (* signed division and modulus
  303. - note: this implements the mathematical definition of DIV and MOD in contrast to the symmetric one
  304. *)
  305. PROCEDURE DivModS32(dividend, divisor: LONGINT; VAR quotient, remainder: LONGINT);
  306. BEGIN {UNCOOPERATIVE, UNCHECKED}
  307. ASSERT(divisor > 0);
  308. IF dividend >= 0 THEN
  309. DivModU32(dividend, divisor, quotient, remainder)
  310. ELSE
  311. dividend := -dividend;
  312. DivModU32(dividend, divisor, quotient, remainder);
  313. quotient := -quotient;
  314. IF remainder # 0 THEN
  315. DEC(quotient);
  316. remainder := divisor - remainder
  317. END
  318. END
  319. END DivModS32;
  320. (*
  321. Fast 32-bit unsigned integer division/modulo (author Alexey Morozov)
  322. *)
  323. PROCEDURE DivModU32(dividend, divisor: ULONGINT; VAR quotient, remainder: ULONGINT);
  324. CODE
  325. MOV R2, #0 ; quotient will be stored in R2
  326. LDR R0, [FP,#dividend] ; R0 := dividend
  327. LDR R1, [FP,#divisor] ; R1 := divisor
  328. ; check for the case dividend < divisor
  329. CMP R0, R1
  330. BLT Exit ; nothing to do than setting quotient to 0 and remainder to dividend (R0)
  331. CLZ R3, R0 ; R3 := clz(dividend)
  332. CLZ R4, R1 ; R4 := clz(divisor)
  333. SUB R3, R4, R3 ; R2 := clz(divisor) - clz(dividend) , R2 >= 0
  334. LSL R1, R1, R3 ; scale divisor: divisor := LSH(divisor,clz(divisor)-clz(dividend))
  335. Loop:
  336. CMP R0, R1
  337. ADC R2, R2, R2
  338. SUBCS R0, R0, R1
  339. LSR R1, R1, #1
  340. SUBS R3, R3, #1
  341. BPL Loop
  342. ; R0 holds the remainder
  343. Exit:
  344. LDR R1, [FP,#quotient] ; R1 := address of quotient
  345. LDR R3, [FP,#remainder] ; R3 := address of remainder
  346. STR R2, [R1,#0] ; quotient := R1
  347. STR R0, [R3,#0] ; remainder := R0
  348. END DivModU32;
  349. (* signed division and modulus
  350. - note: this implements the mathematical definition of DIV and MOD in contrast to the symmetric one
  351. *)
  352. PROCEDURE DivModS64*(dividend, divisor: HUGEINT; VAR quotient, remainder: HUGEINT);
  353. BEGIN {UNCOOPERATIVE, UNCHECKED}
  354. ASSERT(divisor > 0);
  355. IF dividend >= 0 THEN
  356. DivModU64(dividend, divisor, quotient, remainder)
  357. ELSE
  358. dividend := -dividend;
  359. DivModU64(dividend, divisor, quotient, remainder);
  360. quotient := -quotient;
  361. IF remainder # 0 THEN
  362. DEC(quotient);
  363. remainder := divisor - remainder
  364. END
  365. END
  366. END DivModS64;
  367. (* Count leading zeros in a binary representation of a given 64-bit integer number *)
  368. PROCEDURE Clz64*(x: UHUGEINT): LONGINT;
  369. CODE
  370. ; high-half
  371. LDR R1, [FP,#x+4]
  372. CMP R1, #0 ; if high-half is zero count leading zeros of the low-half
  373. BEQ LowHalf
  374. CLZ R0, R1
  375. B Exit
  376. ; low-half
  377. LowHalf:
  378. LDR R1, [FP,#x]
  379. CLZ R0, R1
  380. ADD R0, R0, #32 ; add 32 zeros from the high-half
  381. Exit:
  382. END Clz64;
  383. (*
  384. Fast 64-bit unsigned integer division/modulo (Alexey Morozov)
  385. *)
  386. PROCEDURE DivModU64*(dividend, divisor: UHUGEINT; VAR quotient, remainder: UHUGEINT);
  387. VAR m: LONGINT;
  388. BEGIN {UNCOOPERATIVE, UNCHECKED}
  389. quotient := 0;
  390. IF dividend = 0 THEN remainder := 0; RETURN; END;
  391. IF dividend < divisor THEN remainder := dividend; RETURN; END;
  392. m := Clz64(divisor) - Clz64(dividend);
  393. ASSERT(m >= 0);
  394. divisor := LSH(divisor,m);
  395. WHILE m >= 0 DO
  396. quotient := LSH(quotient,1);
  397. IF dividend >= divisor THEN
  398. INC(quotient);
  399. DEC(dividend,divisor);
  400. END;
  401. divisor := LSH(divisor,-1);
  402. DEC(m);
  403. END;
  404. remainder := dividend;
  405. END DivModU64;
  406. END CPU.