Coop.ARM.Machine.Mod 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352
  1. MODULE Machine;
  2. IMPORT CPU, Environment, Trace, Mutexes, Processors, Timer;
  3. CONST
  4. Version = "A2 Cooperative Revision 5791";
  5. MaxCPU* = Processors.Maximum; (* dummy definition to make GC for both Win32 and I386 work *)
  6. DefaultObjectFileExtension* = ".Obw";
  7. (** bits in features variable *)
  8. MTTR* = 12; MMX* = 23;
  9. debug* = FALSE; (** display more debug output during booting *)
  10. IsCooperative*= TRUE;
  11. CONST
  12. (** standard lock levels (in order) *) (* also refer to Traps.Show *)
  13. TraceOutput* = 0; (* Trace output *)
  14. Memory* = 1; (* Virtual memory management, stack and page allocation *)
  15. Heaps* = 2; (* Storage allocation and Garbage collection *)
  16. Interrupts* = 3; (* Interrupt handling. *)
  17. Modules* = 4; (* Module list *)
  18. Objects* = 5; (* Ready queue *)
  19. KernelLog* = 7; (* Atomic output *)
  20. GC* = 8;
  21. MaxLocks = 9; (* { <= 32 } *)
  22. (* error codes *)
  23. Ok* = 0;
  24. NilAdr* = -1; (* nil value for addresses (not same as pointer NIL value) *)
  25. TYPE
  26. Vendor* = ARRAY 13 OF CHAR;
  27. IDMap* = ARRAY 16 OF SHORTINT;
  28. Range* = RECORD
  29. adr*, size*: LONGINT
  30. END;
  31. MemoryBlock* = POINTER TO MemoryBlockDesc;
  32. MemoryBlockDesc* = RECORD
  33. next- {UNTRACED}: MemoryBlock;
  34. startAdr-: ADDRESS; (* sort key in linked list of memory blocks *)
  35. size-: SIZE;
  36. beginBlockAdr-, endBlockAdr-: ADDRESS
  37. END;
  38. (* dummy definition to make GC work for both I386 and Win32 - copied from I386.Machine.Mod, but not really used *)
  39. Stack* = RECORD (** values are read-only *)
  40. low: ADDRESS; (* lowest virtual address that may be allocated for stack *)
  41. adr*: ADDRESS; (* lowest address on allocated stack *) (* exported for Objects only *)
  42. high*: ADDRESS; (* next virtual address after stack *) (* exported for Objects only *)
  43. END;
  44. Address32* = LONGINT;
  45. VAR
  46. MMXSupport*: BOOLEAN;
  47. SSESupport*: BOOLEAN;
  48. SSE2Support*: BOOLEAN;
  49. SSE3Support-: BOOLEAN; (* PH 04/11*)
  50. SSSE3Support-: BOOLEAN;
  51. SSE41Support-: BOOLEAN;
  52. SSE42Support-: BOOLEAN;
  53. SSE5Support-: BOOLEAN;
  54. AVXSupport-: BOOLEAN;
  55. version*: ARRAY 64 OF CHAR; (** Aos version *)
  56. features*,features2*: SET; (** processor features *)
  57. fcr*: SET; (** default floating-point control register value (default rounding mode is towards -infinity, for ENTIER) *)
  58. mhz*: HUGEINT; (** clock rate of GetTimer() in MHz, or 0 if not known *)
  59. boottime-: HUGEINT; (** in timer units *)
  60. VAR
  61. lock-: ARRAY MaxLocks OF CHAR; (* not implemented as SET because of shared access *)
  62. mutex: ARRAY MaxLocks OF Mutexes.Mutex;
  63. memBlockHead-{UNTRACED}, memBlockTail-{UNTRACED}: MemoryBlock; (* head and tail of sorted list of memory blocks *)
  64. (** Convert a string to an integer. Parameter i specifies where in the string scanning should begin (usually 0 in the first call). Scanning stops at the first non-valid character, and i returns the updated position. Parameter s is the string to be scanned. The value is returned as result, or 0 if not valid. Syntax: number = ["-"] digit {digit} ["H" | "h"] . digit = "0" | ... "9" | "A" .. "F" | "a" .. "f" . If the number contains any hexdecimal letter, or if it ends in "H" or "h", it is interpreted as hexadecimal. *)
  65. PROCEDURE StrToInt*( VAR i: LONGINT; CONST s: ARRAY OF CHAR ): LONGINT;
  66. VAR vd, vh, sgn, d: LONGINT; hex: BOOLEAN;
  67. BEGIN
  68. vd := 0; vh := 0; hex := FALSE;
  69. IF s[i] = "-" THEN sgn := -1; INC( i ) ELSE sgn := 1 END;
  70. LOOP
  71. IF (s[i] >= "0") & (s[i] <= "9") THEN d := ORD( s[i] ) - ORD( "0" )
  72. ELSIF (CAP( s[i] ) >= "A") & (CAP( s[i] ) <= "F") THEN d := ORD( CAP( s[i] ) ) - ORD( "A" ) + 10; hex := TRUE
  73. ELSE EXIT
  74. END;
  75. vd := 10 * vd + d; vh := 16 * vh + d; INC( i )
  76. END;
  77. IF CAP( s[i] ) = "H" THEN hex := TRUE; INC( i ) END; (* optional H *)
  78. IF hex THEN vd := vh END;
  79. RETURN sgn * vd
  80. END StrToInt;
  81. (** -- Atomic operations -- *)
  82. (** This procedure should be called in all spin loops as a hint to the processor (e.g. Pentium 4). *)
  83. PROCEDURE -SpinHint*;
  84. CODE
  85. END SpinHint;
  86. (* Return current instruction pointer *)
  87. PROCEDURE CurrentPC* (): ADDRESS;
  88. CODE
  89. MOV R0, PC
  90. END CurrentPC;
  91. (* Return current frame pointer *)
  92. PROCEDURE -CurrentBP* (): ADDRESS;
  93. CODE
  94. MOV R0, FP
  95. END CurrentBP;
  96. (* Return current stack pointer *)
  97. PROCEDURE -CurrentSP* (): ADDRESS;
  98. CODE
  99. MOV R0, SP
  100. END CurrentSP;
  101. PROCEDURE MapPhysical*(physAdr: ADDRESS; size: SIZE; VAR virtAdr: ADDRESS);
  102. BEGIN
  103. virtAdr := physAdr;
  104. END MapPhysical;
  105. (** Unmap an area previously mapped with MapPhysical. *)
  106. PROCEDURE UnmapPhysical*(virtAdr: ADDRESS; size: SIZE);
  107. END UnmapPhysical;
  108. (** Translate a virtual address range to num ranges of physical address. num returns 0 on error. *)
  109. PROCEDURE TranslateVirtual*(virtAdr: ADDRESS; size: SIZE; VAR num: LONGINT; VAR physAdr: ARRAY OF Range);
  110. CONST PS = 4096;
  111. VAR ofs, phys1: ADDRESS; size1: SIZE;
  112. BEGIN
  113. num := 0;
  114. LOOP
  115. IF size = 0 THEN EXIT END;
  116. IF num = LEN(physAdr) THEN num := 0; EXIT END; (* index check *)
  117. ofs := virtAdr MOD PS; (* offset in page *)
  118. size1 := PS - ofs; (* distance to next page boundary *)
  119. IF size1 > size THEN size1 := size END;
  120. phys1 := virtAdr - ofs;
  121. physAdr[num].adr := phys1 - phys1 MOD PS + ofs;
  122. physAdr[num].size := size1; INC(num);
  123. INC(virtAdr, size1); DEC(size, size1)
  124. END;
  125. IF num = 0 THEN physAdr[0].adr := NilAdr; physAdr[0].size := 0 END;
  126. END TranslateVirtual;
  127. PROCEDURE Ensure32BitAddress*(adr: ADDRESS): Address32;
  128. BEGIN
  129. ASSERT (Address32 (adr) = adr);
  130. RETURN Address32 (adr);
  131. END Ensure32BitAddress;
  132. PROCEDURE Is32BitAddress*(adr: ADDRESS): BOOLEAN;
  133. BEGIN RETURN Address32 (adr) = adr;
  134. END Is32BitAddress;
  135. (** Fill "size" bytes at "destAdr" with "filler". "size" must be multiple of 4. *)
  136. PROCEDURE Fill32*(destAdr: ADDRESS; size: SIZE; filler: LONGINT);
  137. CODE
  138. LDR R0, [FP, #filler]
  139. LDR R1, [FP, #size]
  140. LDR R3, [FP, #destAdr]
  141. MOV R4, #0; counter
  142. (* Check size MOD 4 = 0 *)
  143. LSR R5, R1, #2
  144. LSL R5, R5, #2
  145. CMP R5, R1
  146. BEQ Loop
  147. SWI #8
  148. Loop:
  149. CMP R4, R1
  150. BGE Exit
  151. ADD R5, R3, R4
  152. STR R0, [R5, #0]; put(destAdr + counter, filler)
  153. ADD R4, R4, #4; INC(counter, 4)
  154. B Loop
  155. Exit:
  156. END Fill32;
  157. PROCEDURE GetConfig* ( CONST name: ARRAY OF CHAR; VAR val: ARRAY OF CHAR );
  158. PROCEDURE GetString EXTERN "Environment.GetString" ( CONST name: ARRAY OF CHAR; VAR val: ARRAY OF CHAR );
  159. BEGIN GetString (name, val);
  160. END GetConfig;
  161. PROCEDURE Shutdown*( restart: BOOLEAN );
  162. BEGIN
  163. IF restart THEN Environment.Reboot ELSE Environment.Shutdown END;
  164. END Shutdown;
  165. PROCEDURE Cli*;
  166. BEGIN HALT (1234);
  167. END Cli;
  168. PROCEDURE Sti*;
  169. BEGIN HALT (1234);
  170. END Sti;
  171. (* Dan: from new Machine *)
  172. PROCEDURE GetTimer*(): HUGEINT;
  173. BEGIN RETURN Timer.GetCounter ();
  174. END GetTimer;
  175. PROCEDURE ID*(): LONGINT;
  176. BEGIN
  177. RETURN Processors.GetCurrentIndex ();
  178. END ID;
  179. (** Acquire a spin-lock. *)
  180. PROCEDURE Acquire*( level: LONGINT ); (* non reentrant lock (non reentrance "ensured" by ASSERT statement ), CriticalSections are reentrant *)
  181. BEGIN
  182. Mutexes.Acquire (mutex[level]);
  183. END Acquire;
  184. (** Release a spin-lock. *)
  185. PROCEDURE Release*( level: LONGINT ); (* release lock *)
  186. BEGIN
  187. Mutexes.Release (mutex[level]);
  188. END Release;
  189. (* returns if an address is a currently allocated heap address *)
  190. PROCEDURE ValidHeapAddress*(p: ADDRESS): BOOLEAN;
  191. BEGIN
  192. RETURN p # NIL;
  193. END ValidHeapAddress;
  194. PROCEDURE GetFreeK* (VAR total, lowFree, highFree: SIZE);
  195. BEGIN
  196. total := 0; lowFree := 0; highFree := 0;
  197. END GetFreeK;
  198. PROCEDURE PhysicalAdr*(adr: ADDRESS; size: SIZE): ADDRESS;
  199. BEGIN RETURN adr;
  200. END PhysicalAdr;
  201. (** -- Atomic operations -- *)
  202. (** Atomic INC(x). *)
  203. PROCEDURE -AtomicInc*( VAR x: LONGINT );
  204. CODE
  205. LDR R0, [SP], #4
  206. loop:
  207. LDREX R1, R0
  208. ADD R1, R1, #1
  209. STREX R2, R1, R0
  210. CMP R2, #0
  211. BNE loop
  212. END AtomicInc;
  213. (** Atomic DEC(x). *)
  214. PROCEDURE -AtomicDec*( VAR x: LONGINT );
  215. CODE
  216. LDR R0, [SP], #4
  217. loop:
  218. LDREX R1, R0
  219. SUB R1, R1, #1
  220. STREX R2, R1, R0
  221. CMP R2, #0
  222. BNE loop
  223. END AtomicDec;
  224. (** Atomic INC(x, y). *)
  225. PROCEDURE -AtomicAdd*( VAR x: LONGINT; y: LONGINT );
  226. CODE
  227. LDR R3, [SP], #4 ; R3 := y
  228. LDR R0, [SP], #4 ; R0 := ADR(x)
  229. loop:
  230. LDREX R1, R0 ; R1 := x
  231. ADD R1, R1, R3 ; increment x
  232. STREX R2, R1, R0
  233. CMP R2, #0
  234. BNE loop ; if store failed, try again, else exit
  235. END AtomicAdd;
  236. (** Atomic test-and-set. Set x = TRUE and return old value of x. *)
  237. PROCEDURE AtomicTestSet*( VAR x: BOOLEAN ): BOOLEAN;
  238. CODE
  239. MOV R2, #1 ; R2 := TRUE
  240. MOV R1, #0 ; R1 := FALSE
  241. LDR R3, [SP], #4 ; R3 := ADDRESSOF(x)
  242. loop:
  243. LDREX R0, R3 ; load excl x
  244. CMP R0, R1
  245. BNE exit ; x # old -> exit
  246. STREX R4, R2, R3 ; x = old -> store excl new -> x
  247. CMP R4, #0
  248. BNE loop ; store exclusive failed: retry
  249. exit:
  250. END AtomicTestSet;
  251. (* Atomic compare-and-swap. Set x = new if x = old and return old value of x *)
  252. PROCEDURE -AtomicCAS* (VAR x: LONGINT; old, new: LONGINT): LONGINT;
  253. CODE
  254. LDR R2, [SP], #4 ; R2 := new
  255. LDR R1, [SP], #4 ; R1 := old
  256. LDR R3, [SP], #4 ; R3 := ADDRESSOF(x)
  257. loop:
  258. LDREX R0, R3 ; load excl x
  259. CMP R0, R1
  260. BNE exit ; x # old -> exit
  261. STREX R4, R2, R3 ; x = old -> store excl new -> x
  262. CMP R4, #0
  263. BNE loop ; store exclusive failed: retry
  264. exit:
  265. END AtomicCAS;
  266. (* function returning the number of processors that are available to Aos *)
  267. PROCEDURE NumberOfProcessors*( ): LONGINT;
  268. BEGIN
  269. RETURN Processors.count;
  270. END NumberOfProcessors;
  271. PROCEDURE InvalidateDCacheRange*(a: ADDRESS; s: SIZE);
  272. BEGIN
  273. END InvalidateDCacheRange;
  274. PROCEDURE FlushDCacheRange*(a: ADDRESS; s: SIZE);
  275. BEGIN
  276. END FlushDCacheRange;
  277. BEGIN
  278. Trace.String("Machine: "); Trace.Blue; Trace.StringLn (Version); Trace.Default;
  279. boottime:=GetTimer();
  280. COPY( Version, version );
  281. END Machine.