RPI.Environment.Mod 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186
  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- (status: BOOLEAN);
  84. BEGIN {UNCOOPERATIVE, UNCHECKED}
  85. CPU.MaskIn (CPU.GPFSEL4, {21..23}, {21});
  86. IF status THEN CPU.WriteMask (CPU.GPSET1, {15}) ELSE CPU.WriteMask (CPU.GPCLR1, {15}) END;
  87. END LED;
  88. PROCEDURE Shutdown*;
  89. BEGIN {UNCOOPERATIVE, UNCHECKED}
  90. IF CAS (status, Running, ShuttingDown) # Running THEN RETURN END;
  91. Trace.StringLn ("system: shutting down...");
  92. IF uartInterruptInstalled # 0 THEN CPU.WriteMask (CPU.IRQDisable2, {25}); Interrupts.Cancel (uartInterrupt) END;
  93. IF timerInterruptInstalled # 0 THEN CPU.WriteMask (CPU.IRQDisable1, {1}) END;
  94. END Shutdown;
  95. PROCEDURE Reboot*;
  96. BEGIN {UNCOOPERATIVE, UNCHECKED}
  97. Shutdown;
  98. ASSERT (CAS (status, ShuttingDown, Rebooting) = ShuttingDown);
  99. END Reboot;
  100. PROCEDURE {NORETURN} Exit- (status: WORD);
  101. BEGIN {UNCOOPERATIVE, UNCHECKED}
  102. Trace.String ("system: ");
  103. IF status = Rebooting THEN Trace.StringLn ("rebooting..."); CPU.Reset END;
  104. Trace.StringLn ("ready for power off or restart"); Flush; CPU.Halt;
  105. END Exit;
  106. PROCEDURE InitTrace;
  107. CONST BaudRate = 115200;
  108. BEGIN {UNCOOPERATIVE, UNCHECKED}
  109. CPU.WriteMask (CPU.UART_CR, {CPU.UARTEN});
  110. CPU.Unmask (CPU.GPPUD, {CPU.PUD}); CPU.Delay (150);
  111. CPU.Mask (CPU.GPPUDCLK0, {14, 15}); CPU.Delay (150);
  112. CPU.WriteMask (CPU.GPPUDCLK0, {});
  113. CPU.WriteMask (CPU.UART_ICR, {1, 4..10});
  114. CPU.WriteWord (CPU.UART_IBRD, CPU.FUARTCLK DIV (16 * BaudRate));
  115. CPU.WriteWord (CPU.UART_FBRD, (CPU.FUARTCLK MOD (16 * BaudRate)) * 64 DIV (16 * BaudRate));
  116. CPU.WriteMask (CPU.UART_LCRH, CPU.WLEN8);
  117. CPU.WriteMask (CPU.UART_IMSC, {CPU.RXIM});
  118. CPU.WriteMask (CPU.UART_CR, {CPU.UARTEN, CPU.TXE, CPU.RXE});
  119. Trace.Init; Trace.Char := Write;
  120. END InitTrace;
  121. PROCEDURE InitMemory;
  122. CONST ATAG_MEM = 054410002H;
  123. VAR atag := 0: SIZE; memTag {UNTRACED}: POINTER {UNSAFE} TO RECORD size: SIZE; start: ADDRESS END;
  124. BEGIN {UNCOOPERATIVE, UNCHECKED}
  125. WHILE atags[atag + 1] # ATAG_MEM DO INC (atag, atags[atag]) END;
  126. memTag := ADDRESS OF atags[atag + 2];
  127. CPU.IdentityMapMemory (memTag.size); CPU.EnableMemoryManagementUnit;
  128. HeapManager.Initialize (heap, ADDRESS OF KernelEnd, memTag.start + memTag.size);
  129. memory := memTag.start + memTag.size - ADDRESS OF KernelEnd;
  130. END InitMemory;
  131. PROCEDURE Initialize-;
  132. BEGIN {UNCOOPERATIVE, UNCHECKED}
  133. SYSTEM.SetActivity (NIL); LED (TRUE);
  134. CPU.Initialize; InitTrace; InitMemory;
  135. frequency := Timer.GetFrequency () DIV 1000;
  136. END Initialize;
  137. PROCEDURE Terminate-;
  138. BEGIN {UNCOOPERATIVE, UNCHECKED}
  139. Interrupts.Terminate;
  140. LED (FALSE);
  141. END Terminate;
  142. PROCEDURE {NOPAF, INITIAL, FIXED(8000H)} KernelBegin;
  143. CODE
  144. MOV SP, #8000H
  145. LDR R0, [PC, #tags-$-8]
  146. STR R2, [R0, #0]
  147. B skip
  148. tags:
  149. d32 atags
  150. skip:
  151. END KernelBegin;
  152. PROCEDURE {NOPAF, FINAL, ALIGNED(32)} KernelEnd;
  153. CODE
  154. END KernelEnd;
  155. BEGIN {UNCHECKED}
  156. Trace.String ("Version "); Trace.String (SYSTEM.Date); Trace.String (" (");
  157. Trace.Int (memory DIV (1024 * 1024), 0); Trace.String (" MB RAM, GC, ");
  158. Trace.String ("GC, ");
  159. Trace.Int (Processors.count, 0); Trace.String (" CPU");
  160. IF Processors.count > 1 THEN Trace.Char ('s') END; Trace.Char (')'); Trace.Ln;
  161. END Environment.