RPI.Environment.Mod 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207
  1. (* Raspberry Pi environment *)
  2. (* Copyright (C) Florian Negele *)
  3. MODULE Environment;
  4. IMPORT SYSTEM, Activities, CPU, HeapManager, Interrupts, Trace, Processors, Timer;
  5. CONST Running* = 0; ShuttingDown* = 1; Rebooting* = 2;
  6. VAR memory: SIZE;
  7. VAR heap: HeapManager.Heap;
  8. VAR clock := 0: LONGINT;
  9. VAR frequency: Timer.Counter;
  10. VAR status* := Running: WORD;
  11. VAR uartInterruptInstalled := 0: SIZE;
  12. VAR timerInterruptInstalled := 0: SIZE;
  13. VAR uartInterrupt: Interrupts.Interrupt;
  14. VAR previousTimerHandler := NIL: CPU.InterruptHandler;
  15. VAR atags {UNTRACED}: POINTER {UNSAFE} TO ARRAY 1000H OF SIZE;
  16. PROCEDURE {NORETURN} Abort-;
  17. BEGIN {UNCOOPERATIVE, UNCHECKED}
  18. IF SYSTEM.GetActivity () # NIL THEN Activities.TerminateCurrentActivity END;
  19. Activities.TerminateCurrentActivity;
  20. END Abort;
  21. PROCEDURE Allocate- (size: SIZE): ADDRESS;
  22. VAR result, address: ADDRESS;
  23. BEGIN {UNCOOPERATIVE, UNCHECKED}
  24. result := HeapManager.Allocate (size, heap);
  25. IF result = NIL THEN RETURN NIL END;
  26. FOR address := result TO result + size - 1 DO SYSTEM.PUT8 (address, 0) END;
  27. RETURN result;
  28. END Allocate;
  29. PROCEDURE Deallocate- (address: ADDRESS);
  30. BEGIN {UNCOOPERATIVE, UNCHECKED}
  31. HeapManager.Deallocate (address, heap);
  32. END Deallocate;
  33. PROCEDURE Write- (character: CHAR);
  34. BEGIN {UNCOOPERATIVE, UNCHECKED}
  35. WHILE CPU.TXFF IN CPU.ReadMask (CPU.UART_FR) DO END;
  36. CPU.WriteWord (CPU.UART_DR, ORD (character));
  37. END Write;
  38. PROCEDURE Read- (VAR character: CHAR): BOOLEAN;
  39. BEGIN {UNCOOPERATIVE, UNCHECKED}
  40. WHILE CPU.RXFE IN CPU.ReadMask (CPU.UART_FR) DO
  41. IF CAS (uartInterruptInstalled, 0, 1) = 0 THEN
  42. Interrupts.Install (uartInterrupt, CPU.IRQ);
  43. END;
  44. CPU.WriteMask (CPU.IRQEnable2, {25});
  45. Interrupts.Await (uartInterrupt);
  46. IF status # Running THEN RETURN FALSE END;
  47. END;
  48. character := CHR (CPU.ReadWord (CPU.UART_DR));
  49. Write (character); RETURN TRUE;
  50. END Read;
  51. PROCEDURE Flush-;
  52. BEGIN {UNCOOPERATIVE, UNCHECKED}
  53. REPEAT UNTIL CPU.TXFE IN CPU.ReadMask (CPU.UART_FR);
  54. END Flush;
  55. PROCEDURE GetString- (CONST name: ARRAY OF CHAR; VAR result: ARRAY OF CHAR);
  56. BEGIN {UNCOOPERATIVE, UNCHECKED}
  57. result[0] := 0X
  58. END GetString;
  59. PROCEDURE Clock- (): LONGINT;
  60. BEGIN RETURN Timer.GetCounter () DIV frequency;
  61. END Clock;
  62. PROCEDURE Sleep- (milliseconds: LONGINT);
  63. VAR interrupt: Interrupts.Interrupt;
  64. BEGIN {UNCOOPERATIVE, UNCHECKED}
  65. ASSERT (milliseconds >= 0);
  66. IF CAS (timerInterruptInstalled, 0, 1) = 0 THEN
  67. previousTimerHandler := CPU.InstallInterrupt (HandleTimer, CPU.IRQ);
  68. CPU.WriteWord (CPU.STC1, CPU.ReadWord (CPU.STCLO) + 1000);
  69. CPU.WriteMask (CPU.IRQEnable1, {1});
  70. END;
  71. Interrupts.Install (interrupt, CPU.IRQ); INC (milliseconds, clock);
  72. WHILE clock - milliseconds < 0 DO Interrupts.Await (interrupt) END;
  73. END Sleep;
  74. PROCEDURE HandleTimer (index: SIZE);
  75. BEGIN {UNCOOPERATIVE, UNCHECKED}
  76. IF previousTimerHandler # NIL THEN previousTimerHandler (index) END;
  77. IF 1 IN CPU.ReadMask (CPU.STCS) THEN
  78. CPU.WriteWord (CPU.STC1, CPU.ReadWord (CPU.STCLO) + 1000);
  79. CPU.WriteMask (CPU.STCS, {1}); INC (clock);
  80. CPU.WriteMask (CPU.IRQEnable1, {1});
  81. END;
  82. END HandleTimer;
  83. PROCEDURE LED- (led: LONGINT; status: BOOLEAN);
  84. BEGIN {UNCOOPERATIVE, UNCHECKED}
  85. IF led = 0 THEN
  86. CPU.MaskIn (CPU.GPFSEL4, {21..23}, {21});
  87. IF status THEN CPU.WriteMask (CPU.GPSET1, {15}) ELSE CPU.WriteMask (CPU.GPCLR1, {15}) END;
  88. ELSE (* power led *)
  89. IF status THEN
  90. CPU.MaskIn (CPU.GPFSEL3, {15..17}, {17});
  91. ELSE
  92. CPU.MaskIn (CPU.GPFSEL3, {15..17}, {15});
  93. END;
  94. END;
  95. END LED;
  96. PROCEDURE Shutdown*;
  97. BEGIN {UNCOOPERATIVE, UNCHECKED}
  98. IF CAS (status, Running, ShuttingDown) # Running THEN RETURN END;
  99. Trace.StringLn ("system: shutting down...");
  100. IF uartInterruptInstalled # 0 THEN CPU.WriteMask (CPU.IRQDisable2, {25}); Interrupts.Cancel (uartInterrupt) END;
  101. IF timerInterruptInstalled # 0 THEN CPU.WriteMask (CPU.IRQDisable1, {1}) END;
  102. END Shutdown;
  103. PROCEDURE Reboot*;
  104. BEGIN {UNCOOPERATIVE, UNCHECKED}
  105. Shutdown;
  106. ASSERT (CAS (status, ShuttingDown, Rebooting) = ShuttingDown);
  107. END Reboot;
  108. PROCEDURE {NORETURN} Exit- (status: WORD);
  109. BEGIN {UNCOOPERATIVE, UNCHECKED}
  110. Trace.String ("system: ");
  111. IF status = Rebooting THEN Trace.StringLn ("rebooting..."); CPU.Reset END;
  112. Trace.StringLn ("ready for power off or restart"); Flush; CPU.Halt;
  113. END Exit;
  114. PROCEDURE InitTrace;
  115. CONST BaudRate = 115200;
  116. BEGIN {UNCOOPERATIVE, UNCHECKED}
  117. CPU.WriteMask (CPU.UART_CR, {CPU.UARTEN});
  118. CPU.Unmask (CPU.GPPUD, {CPU.PUD}); CPU.Delay (150);
  119. CPU.Mask (CPU.GPPUDCLK0, {14, 15}); CPU.Delay (150);
  120. CPU.WriteMask (CPU.GPPUDCLK0, {});
  121. CPU.WriteMask (CPU.UART_ICR, {1, 4..10});
  122. CPU.WriteWord (CPU.UART_IBRD, CPU.FUARTCLK DIV (16 * BaudRate));
  123. CPU.WriteWord (CPU.UART_FBRD, (CPU.FUARTCLK MOD (16 * BaudRate)) * 64 DIV (16 * BaudRate));
  124. CPU.WriteMask (CPU.UART_LCRH, CPU.WLEN8);
  125. CPU.WriteMask (CPU.UART_IMSC, {CPU.RXIM});
  126. CPU.WriteMask (CPU.UART_CR, {CPU.UARTEN, CPU.TXE, CPU.RXE});
  127. Trace.Init; Trace.Char := Write;
  128. END InitTrace;
  129. PROCEDURE InitMemory;
  130. CONST ATAG_MEM = 054410002H;
  131. VAR atag := 0: SIZE; memTag {UNTRACED}: POINTER {UNSAFE} TO RECORD size: SIZE; start: ADDRESS END;
  132. BEGIN {UNCOOPERATIVE, UNCHECKED}
  133. WHILE atags[atag + 1] # ATAG_MEM DO INC (atag, atags[atag]) END;
  134. memTag := ADDRESS OF atags[atag + 2];
  135. CPU.IdentityMapMemory (memTag.size); CPU.EnableMemoryManagementUnit;
  136. HeapManager.Initialize (heap, ADDRESS OF KernelEnd, memTag.start + memTag.size);
  137. memory := memTag.start + memTag.size - ADDRESS OF KernelEnd;
  138. END InitMemory;
  139. PROCEDURE Blink-(num, speed: LONGINT);
  140. VAR i,j: LONGINT;
  141. BEGIN {UNCOOPERATIVE, UNCHECKED}
  142. FOR j:= 1 TO num DO
  143. LED (0, TRUE); LED(1, FALSE);
  144. FOR i := 0 TO speed*1000000 DO END;
  145. LED(0, FALSE); LED(1, TRUE);
  146. FOR i := 0 TO speed*1000000 DO END;
  147. END;
  148. END Blink;
  149. PROCEDURE Initialize-;
  150. VAR i: LONGINT;
  151. BEGIN {UNCOOPERATIVE, UNCHECKED}
  152. SYSTEM.SetActivity (NIL);
  153. CPU.Initialize; InitTrace; InitMemory;
  154. frequency := Timer.GetFrequency () DIV 1000;
  155. END Initialize;
  156. PROCEDURE Terminate-;
  157. BEGIN {UNCOOPERATIVE, UNCHECKED}
  158. Interrupts.Terminate;
  159. LED (0, FALSE);
  160. END Terminate;
  161. PROCEDURE {NOPAF, INITIAL, FIXED(8000H)} KernelBegin;
  162. CODE
  163. MOV SP, #8000H
  164. LDR R0, [PC, #tags-$-8]
  165. STR R2, [R0, #0]
  166. B skip
  167. tags:
  168. d32 atags
  169. skip:
  170. END KernelBegin;
  171. PROCEDURE {NOPAF, FINAL, ALIGNED(32)} KernelEnd;
  172. CODE
  173. END KernelEnd;
  174. BEGIN {UNCHECKED}
  175. Trace.String ("Version "); Trace.String (SYSTEM.Date); Trace.String (" (");
  176. Trace.Int (memory DIV (1024 * 1024), 0); Trace.String (" MB RAM, GC, ");
  177. Trace.Int (Processors.count, 0); Trace.String (" CPU");
  178. IF Processors.count > 1 THEN Trace.Char ('s') END; Trace.Char (')'); Trace.Ln;
  179. END Environment.