Win64.Machine.Mod 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116
  1. MODULE Machine;
  2. (** AUTHOR "pjm,fof"; PURPOSE "Bootstrapping, configuration and machine interface, adaption to windows fof"; *)
  3. (* red marked parts are WinAos specific *)
  4. IMPORT SYSTEM, Trace, Kernel32;
  5. CONST
  6. Version = "WinAos (32bit) ";
  7. DefaultConfigFile = "aos.ini";
  8. DefaultGenericConfigFile = "aosg.ini";
  9. UserConfigFile = "myaos.ini";
  10. MaxCPU* = 8; (* dummy definition to make GC for both Win32 and I386 work *)
  11. DefaultObjectFileExtension* = ".Obw";
  12. (** bits in features variable *)
  13. MTTR* = 12; MMX* = 23;
  14. debug* = FALSE; (** display more debug output during booting *)
  15. CONST
  16. AddressSize = SIZEOF(ADDRESS);
  17. StaticBlockSize = 32; (* static heap block size *)
  18. BlockHeaderSize = 2 * AddressSize;
  19. (* change this when Heaps.HeapBlock is modified *)
  20. RecordDescSize = 4 * AddressSize; (* needs to be adapted in case Heaps.RecordBlockDesc is changed *)
  21. (** standard lock levels (in order) *) (* also refer to Traps.Show *)
  22. TraceOutput* = 0; (* Trace output *)
  23. Memory* = 1; (* Virtual memory management, stack and page allocation *)
  24. Heaps* = 2; (* Storage allocation and Garbage collection *)
  25. Interrupts* = 3; (* Interrupt handling. *)
  26. Modules* = 4; (* Module list *)
  27. Objects* = 5; (* Ready queue *)
  28. Processors* = 6; (* Interprocessor interrupts *)
  29. KernelLog* = 7; (* Atomic output *)
  30. GC* = 8;
  31. MaxLocks = 9; (* { <= 32 } *)
  32. StrongChecks = FALSE;
  33. MemoryBlockOfs = BlockHeaderSize + RecordDescSize + BlockHeaderSize; (* memory block (including header) starts at offset HeaderSize *)
  34. MemBlockSize = 32*1024*1024; (* must be multiple of StaticBlockSize *)
  35. MinMemBlockSize = 4*1024*1024;
  36. NilVal = 0;
  37. Second* = 1000; (* frequency of ticks increments in Hz *)
  38. CONST
  39. (* error codes *)
  40. Ok* = 0;
  41. NilAdr* = -1; (* nil value for addresses (not same as pointer NIL value) *)
  42. IsCooperative* = FALSE;
  43. TYPE
  44. Vendor* = ARRAY 13 OF CHAR;
  45. IDMap* = ARRAY 16 OF SHORTINT;
  46. Range* = RECORD
  47. adr*, size*: LONGINT
  48. END;
  49. MemoryBlock* = POINTER TO MemoryBlockDesc;
  50. MemoryBlockDesc* = RECORD
  51. next- {UNTRACED}: MemoryBlock;
  52. startAdr-: ADDRESS; (* sort key in linked list of memory blocks *)
  53. size-: SIZE;
  54. beginBlockAdr-, endBlockAdr-: ADDRESS
  55. END;
  56. (* dummy definition to make GC work for both I386 and Win32 - copied from I386.Machine.Mod, but not really used *)
  57. Stack* = RECORD (** values are read-only *)
  58. low: ADDRESS; (* lowest virtual address that may be allocated for stack *)
  59. adr*: ADDRESS; (* lowest address on allocated stack *) (* exported for Objects only *)
  60. high*: ADDRESS; (* next virtual address after stack *) (* exported for Objects only *)
  61. END;
  62. VAR
  63. LastAddress: RECORD END;
  64. stackBottom-: ADDRESS;
  65. MMXSupport*: BOOLEAN;
  66. SSESupport*: BOOLEAN;
  67. SSE2Support*: BOOLEAN;
  68. SSE3Support-: BOOLEAN; (* PH 04/11*)
  69. SSSE3Support-: BOOLEAN;
  70. SSE41Support-: BOOLEAN;
  71. SSE42Support-: BOOLEAN;
  72. SSE5Support-: BOOLEAN;
  73. AVXSupport-: BOOLEAN;
  74. version*: ARRAY 64 OF CHAR; (** Aos version *)
  75. features*,features2*: SET; (** processor features *)
  76. fcr*: SET; (** default floating-point control register value (default rounding mode is towards -infinity, for ENTIER) *)
  77. mhz*: HUGEINT; (** clock rate of GetTimer() in MHz, or 0 if not known *)
  78. boottime-: HUGEINT; (** in timer units *)
  79. commandLine-: ARRAY 256 OF CHAR;
  80. hin, hout: Kernel32.HANDLE;
  81. VAR
  82. lock-: ARRAY MaxLocks OF CHAR; (* not implemented as SET because of shared access *)
  83. cs: ARRAY MaxLocks OF Kernel32.CriticalSection;
  84. trace: ARRAY 2 OF CHAR;
  85. defaultConfigFile, userConfigFile, traceName: ARRAY Kernel32.MaxPath OF CHAR;
  86. gcThreshold-: SIZE;
  87. bootHeapAdr: ADDRESS; (* initialized by linker, variable name must not be changed, see Win32.Aos.Link *)
  88. bootHeapSize: SIZE; (* initialized by linker, variable name must not be changed, see Win32.Aos.Link *)
  89. memBlockHead-{UNTRACED}, memBlockTail-{UNTRACED}: MemoryBlock; (* head and tail of sorted list of memory blocks *)
  90. (** 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. *)
  91. PROCEDURE StrToInt*( VAR i: LONGINT; CONST s: ARRAY OF CHAR ): LONGINT;
  92. VAR vd, vh, sgn, d: LONGINT; hex: BOOLEAN;
  93. BEGIN
  94. vd := 0; vh := 0; hex := FALSE;
  95. IF s[i] = "-" THEN sgn := -1; INC( i ) ELSE sgn := 1 END;
  96. LOOP
  97. IF (s[i] >= "0") & (s[i] <= "9") THEN d := ORD( s[i] ) - ORD( "0" )
  98. ELSIF (CAP( s[i] ) >= "A") & (CAP( s[i] ) <= "F") THEN d := ORD( CAP( s[i] ) ) - ORD( "A" ) + 10; hex := TRUE
  99. ELSE EXIT
  100. END;
  101. vd := 10 * vd + d; vh := 16 * vh + d; INC( i )
  102. END;
  103. IF CAP( s[i] ) = "H" THEN hex := TRUE; INC( i ) END; (* optional H *)
  104. IF hex THEN vd := vh END;
  105. RETURN sgn * vd
  106. END StrToInt;
  107. (** -- Atomic operations -- *)
  108. (** Atomic INC(x). *)
  109. PROCEDURE -AtomicInc*(VAR x: LONGINT);
  110. CODE {SYSTEM.AMD64}
  111. POP RAX
  112. LOCK
  113. INC DWORD [RAX]
  114. END AtomicInc;
  115. (** Atomic DEC(x). *)
  116. PROCEDURE -AtomicDec*(VAR x: LONGINT);
  117. CODE {SYSTEM.AMD64}
  118. POP RAX
  119. LOCK
  120. DEC DWORD [RAX]
  121. END AtomicDec;
  122. (** Atomic EXCL. *)
  123. PROCEDURE AtomicExcl* (VAR s: SET; bit: LONGINT);
  124. CODE {SYSTEM.AMD64}
  125. MOV EAX, [RBP + bit]
  126. MOV RBX, [RBP + s]
  127. LOCK
  128. BTR [RBX], EAX
  129. END AtomicExcl;
  130. (** Atomic INC(x, y). *)
  131. PROCEDURE -AtomicAdd*(VAR x: LONGINT; y: LONGINT);
  132. CODE {SYSTEM.AMD64}
  133. POP EBX
  134. POP RAX
  135. LOCK
  136. ADD DWORD [RAX], EBX
  137. END AtomicAdd;
  138. (** Atomic test-and-set. Set x = TRUE and return old value of x. *)
  139. PROCEDURE -AtomicTestSet*(VAR x: BOOLEAN): BOOLEAN;
  140. CODE {SYSTEM.AMD64}
  141. POP RBX
  142. MOV AL, 1
  143. XCHG [RBX], AL
  144. END AtomicTestSet;
  145. (* Atomic compare-and-swap. Set x = new if x = old and return old value of x *)
  146. PROCEDURE -AtomicCAS* (VAR x: LONGINT; old, new: LONGINT): LONGINT;
  147. CODE {SYSTEM.AMD64}
  148. POP EBX ; new
  149. POP EAX ; old
  150. POP RCX ; address of x
  151. LOCK CMPXCHG [RCX], EBX ; atomicly compare x with old and set it to new if equal
  152. END AtomicCAS;
  153. (** -- Miscellaneous -- *)
  154. (* Return current instruction pointer *)
  155. PROCEDURE CurrentPC* (): ADDRESS;
  156. CODE {SYSTEM.AMD64}
  157. MOV RAX, [RBP + 8]
  158. END CurrentPC;
  159. (* Return current frame pointer *)
  160. PROCEDURE -CurrentBP* (): ADDRESS;
  161. CODE {SYSTEM.AMD64}
  162. MOV RAX, RBP
  163. END CurrentBP;
  164. (* Set current frame pointer *)
  165. PROCEDURE -SetBP* (bp: ADDRESS);
  166. CODE {SYSTEM.AMD64}
  167. POP RBP
  168. END SetBP;
  169. (* Return current stack pointer *)
  170. PROCEDURE -CurrentSP* (): ADDRESS;
  171. CODE {SYSTEM.AMD64}
  172. MOV RAX, RSP
  173. END CurrentSP;
  174. (* Set current stack pointer *)
  175. PROCEDURE -SetSP* (sp: ADDRESS);
  176. CODE {SYSTEM.AMD64}
  177. POP RSP
  178. END SetSP;
  179. (** This procedure should be called in all spin loops as a hint to the processor (e.g. Pentium 4). *)
  180. PROCEDURE -SpinHint*;
  181. CODE {SYSTEM.AMD64}
  182. PAUSE
  183. END SpinHint;
  184. (** Fill "size" bytes at "destAdr" with "filler". "size" must be multiple of 4. *)
  185. PROCEDURE Fill32* (destAdr: ADDRESS; size: SIZE; filler: LONGINT);
  186. CODE {SYSTEM.AMD64}
  187. MOV RDI, [RBP + destAdr]
  188. MOV RCX, [RBP + size]
  189. MOV EAX, [RBP + filler]
  190. TEST RCX, 3
  191. JZ ok
  192. PUSH 8 ; ASSERT failure
  193. INT 3
  194. ok:
  195. SHR RCX, 2
  196. CLD
  197. REP STOSD
  198. END Fill32;
  199. (** -- Processor initialization -- *)
  200. PROCEDURE -SetFCR( s: SET );
  201. CODE {SYSTEM.i386, SYSTEM.FPU}
  202. FLDCW [ESP] ; parameter s
  203. POP EAX
  204. END SetFCR;
  205. PROCEDURE -FCR( ): SET;
  206. CODE {SYSTEM.i386, SYSTEM.FPU}
  207. PUSH 0
  208. FNSTCW [ESP]
  209. FWAIT
  210. POP EAX
  211. END FCR;
  212. PROCEDURE -InitFPU;
  213. CODE {SYSTEM.i386, SYSTEM.FPU}
  214. FNINIT
  215. END InitFPU;
  216. (** Setup FPU control word of current processor. *)
  217. PROCEDURE SetupFPU*;
  218. BEGIN
  219. InitFPU; SetFCR( fcr )
  220. END SetupFPU;
  221. (** CPU identification. *)
  222. PROCEDURE CPUID*( VAR vendor: Vendor; VAR version: LONGINT; VAR features1,features2: SET );
  223. CODE {SYSTEM.i386, SYSTEM.Pentium}
  224. MOV EAX, 0
  225. CPUID
  226. CMP EAX, 0
  227. JNE ok
  228. MOV ESI, [EBP+vendor]
  229. MOV [ESI], AL ; AL = 0
  230. MOV ESI, [EBP+version]
  231. MOV [ESI], EAX ; EAX = 0
  232. MOV ESI, [EBP+features1]
  233. MOV [ESI], EAX
  234. MOV ESI, [EBP+features2]
  235. MOV [ESI], EAX
  236. JMP end
  237. ok:
  238. MOV ESI, [EBP+vendor]
  239. MOV [ESI], EBX
  240. MOV [ESI+4], EDX
  241. MOV [ESI+8], ECX
  242. MOV BYTE [ESI+12], 0
  243. MOV EAX, 1
  244. CPUID
  245. MOV ESI, [EBP+version]
  246. MOV [ESI], EAX
  247. MOV ESI, [EBP+features1]
  248. MOV [ESI], EDX
  249. MOV ESI, [EBP+features2]
  250. MOV [ESI], ECX
  251. end:
  252. END CPUID;
  253. PROCEDURE GetConfig*( CONST name: ARRAY OF CHAR; VAR val: ARRAY OF CHAR );
  254. CONST ConfigKey = "Configuration";
  255. BEGIN
  256. COPY ("", val);
  257. IF Kernel32.GetPrivateProfileString (ConfigKey, name, "", val, LEN (val), userConfigFile) # 0 THEN
  258. ELSIF Kernel32.GetPrivateProfileString (ConfigKey, name, "", val, LEN (val), defaultConfigFile) # 0 THEN
  259. END;
  260. IF (name = "ObjectFileExtension") & (val = "") THEN
  261. IF Kernel32.Generic THEN
  262. val := ".GofWw";
  263. ELSE
  264. val := ".Obww"
  265. END;
  266. END;
  267. END GetConfig;
  268. PROCEDURE Shutdown*( restart: BOOLEAN );
  269. BEGIN
  270. RemoveTraceFile;
  271. Kernel32.Shutdown( 0 ); (* calls the finalizer of Heaps *)
  272. END Shutdown;
  273. (* Dan: from new Machine *)
  274. PROCEDURE -GetTimer*(): HUGEINT;
  275. CODE {SYSTEM.Pentium}
  276. RDTSC ; set EDX:EAX
  277. END GetTimer;
  278. (* Dan: mono CPU PCs *)
  279. PROCEDURE ID*(): LONGINT;
  280. BEGIN
  281. RETURN 0
  282. END ID;
  283. (**
  284. * Flush Data Cache for the specified virtual address range. If len is negative, flushes the whole cache.
  285. * This is used on some architecture to interact with DMA hardware (e.g. Ethernet and USB. It can be
  286. * left empty on Intel architecture.
  287. *)
  288. PROCEDURE FlushDCacheRange * (adr: ADDRESS; len: LONGINT);
  289. END FlushDCacheRange;
  290. (**
  291. * Invalidate Data Cache for the specified virtual address range. If len is negative, flushes the whole cache.
  292. * This is used on some architecture to interact with DMA hardware (e.g. Ethernet and USB. It can be
  293. * left empty on Intel architecture.
  294. *)
  295. PROCEDURE InvalidateDCacheRange * (adr: ADDRESS; len: LONGINT);
  296. END InvalidateDCacheRange;
  297. (**
  298. * Invalidate Instruction Cache for the specified virtual address range. If len is negative, flushes the whole cache.
  299. * This is used on some architecture to interact with DMA hardware (e.g. Ethernet and USB. It can be
  300. * left empty on Intel architecture.
  301. *)
  302. PROCEDURE InvalidateICacheRange * (adr: ADDRESS; len: LONGINT);
  303. END InvalidateICacheRange;
  304. (* setup MMX, SSE and SSE2..SSE5 and AVX extension *)
  305. PROCEDURE SetupSSE2Ext;
  306. CONST
  307. MMXFlag=23;(*IN features from EBX*)
  308. FXSRFlag = 24;
  309. SSEFlag = 25;
  310. SSE2Flag = 26;
  311. SSE3Flag = 0; (*IN features2 from ECX*) (*PH 04/11*)
  312. SSSE3Flag =9;
  313. SSE41Flag =19;
  314. SSE42Flag =20;
  315. SSE5Flag = 11;
  316. AVXFlag = 28;
  317. BEGIN
  318. MMXSupport := MMXFlag IN features;
  319. SSESupport := SSEFlag IN features;
  320. SSE2Support := SSESupport & (SSE2Flag IN features);
  321. SSE3Support := SSE2Support & (SSE3Flag IN features2);
  322. SSSE3Support := SSE3Support & (SSSE3Flag IN features2); (* PH 04/11*)
  323. SSE41Support := SSE3Support & (SSE41Flag IN features2);
  324. SSE42Support := SSE3Support & (SSE42Flag IN features2);
  325. SSE5Support := SSE3Support & (SSE5Flag IN features2);
  326. AVXSupport := SSE3Support & (AVXFlag IN features2);
  327. IF SSESupport & (FXSRFlag IN features) THEN
  328. (* InitSSE(); *) (*! not privileged mode in Windows not allowed *)
  329. END;
  330. END SetupSSE2Ext;
  331. PROCEDURE ReadCommandLine(VAR commandLine: ARRAY OF CHAR);
  332. VAR adr: ADDRESS; i: LONGINT; ch: CHAR;
  333. BEGIN
  334. adr := Kernel32.GetCommandLine();
  335. SYSTEM.GET(adr,ch);
  336. i := 0;
  337. WHILE (i<LEN(commandLine)-1) & (ch # 0X) DO
  338. commandLine[i] := ch;
  339. INC(adr); INC(i);
  340. SYSTEM.GET(adr,ch);
  341. END;
  342. END ReadCommandLine;
  343. PROCEDURE ParseLine(VAR c: ARRAY OF CHAR; VAR iniFile: ARRAY OF CHAR);
  344. VAR i: LONGINT;
  345. PROCEDURE SkipSpaces;
  346. BEGIN
  347. WHILE (c[i] <= " ") & (c[i] # 0X) DO INC(i) END;
  348. END SkipSpaces;
  349. PROCEDURE SkipName;
  350. BEGIN
  351. WHILE (c[i] > " ") DO INC(i) END;
  352. END SkipName;
  353. PROCEDURE CheckName(CONST name: ARRAY OF CHAR): BOOLEAN;
  354. VAR j: LONGINT;
  355. BEGIN
  356. j := 0;
  357. WHILE (c[i] = name[j]) & (c[i] # 0X) & (name[j] # 0X) DO
  358. INC(i); INC(j);
  359. END;
  360. RETURN (name[j] = 0X);
  361. END CheckName;
  362. PROCEDURE ReadName(VAR name: ARRAY OF CHAR);
  363. VAR j: LONGINT;
  364. BEGIN
  365. SkipSpaces;
  366. j := 0;
  367. WHILE (c[i] > " ") & (j < LEN(name)-1) DO
  368. name[j] := c[i];
  369. INC(i); INC(j);
  370. END;
  371. name[j] := 0X;
  372. END ReadName;
  373. BEGIN
  374. c[LEN(c)-1] := 0X;
  375. i := 0;
  376. SkipSpaces;
  377. SkipName;
  378. SkipSpaces;
  379. IF c[i] = "-" THEN (* option *)
  380. INC(i);
  381. IF CheckName("ini") THEN SkipSpaces; ReadName(iniFile) END;
  382. END;
  383. END ParseLine;
  384. PROCEDURE TraceChar(c: CHAR);
  385. VAR len: LONGINT; b: Kernel32.BOOL;
  386. BEGIN
  387. len := 1;
  388. b := Kernel32.WriteFile(hout,c,len,len,NIL);
  389. END TraceChar;
  390. PROCEDURE SetTraceFile*;
  391. BEGIN
  392. traceName := "SystemTrace.txt";
  393. SetupTraceName(traceName);
  394. Trace.String("trace -> file "); Trace.String(traceName); Trace.Ln;
  395. hout := Kernel32.CreateFile(traceName, SetToDW({Kernel32.GenericWrite}), SetToDW({Kernel32.FileShareRead}), NIL, Kernel32.CreateAlways, SetToDW({Kernel32.FileAttributeNormal}), Kernel32.NULL);
  396. Kernel32.GetFullPathName(traceName, LEN(traceName),traceName, NIL);
  397. Trace.Char := TraceChar;
  398. END SetTraceFile;
  399. PROCEDURE SetTraceConsole*;
  400. VAR res: LONGINT;
  401. BEGIN
  402. Trace.String("trace -> console"); Trace.Ln;
  403. res := Kernel32.AllocConsole ();
  404. hin := Kernel32.GetStdHandle (Kernel32.STDInput);
  405. hout := Kernel32.GetStdHandle (Kernel32.STDOutput);
  406. Trace.Char := TraceChar;
  407. END SetTraceConsole;
  408. PROCEDURE SetupTraceName(VAR traceName: ARRAY OF CHAR);
  409. VAR
  410. ext: ARRAY 256 OF CHAR;
  411. extPos,i,j: LONGINT;
  412. systemTime: Kernel32.SystemTime;
  413. ch: CHAR;
  414. PROCEDURE AppendDecimals(int: LONGINT; from, to: LONGINT);
  415. VAR ten: LONGINT;
  416. BEGIN
  417. WHILE to >= from DO
  418. traceName[i] := CHR(ORD("0")+ int DIV to MOD 10); INC(i);
  419. to := to DIV 10;
  420. END;
  421. END AppendDecimals;
  422. BEGIN
  423. Kernel32.GetLocalTime(systemTime);
  424. extPos := 0;
  425. REPEAT
  426. ch := traceName[i];
  427. IF ch = "." THEN j := 0; extPos := i END;
  428. ext[j] := ch;
  429. INC(j); INC(i);
  430. UNTIL ch = 0X;
  431. IF extPos > 0 THEN i := extPos END;
  432. ext[j] := 0X;
  433. AppendDecimals(systemTime.wYear,1,1000);
  434. AppendDecimals(systemTime.wMonth,1,10);
  435. AppendDecimals(systemTime.wDay,1,10);
  436. traceName[i] := "_"; INC(i);
  437. AppendDecimals(systemTime.wHour,1,10);
  438. AppendDecimals(systemTime.wMinute,1,10);
  439. AppendDecimals(systemTime.wSecond,1,10);
  440. traceName[i] := "_"; INC(i);
  441. AppendDecimals(systemTime.wMilliseconds,10,100);
  442. j := 0;
  443. REPEAT
  444. ch := ext[j];
  445. traceName[i] := ch;
  446. INC(i); INC(j);
  447. UNTIL ch = 0X;
  448. END SetupTraceName;
  449. PROCEDURE RemoveTraceFile;
  450. VAR res: LONGINT;
  451. BEGIN
  452. IF (traceName # "") & (traceName # "Console") THEN
  453. Trace.String("removing "); Trace.String(traceName); Trace.Ln;
  454. (*Trace.Char := LogChar;*)
  455. res := Kernel32.CloseHandle(hout);
  456. IF res = 0 THEN
  457. res := Kernel32.GetLastError();
  458. Trace.String("could not close "); Trace.String("; res = "); Trace.Int(res,1); Trace.Ln;
  459. END;
  460. res := Kernel32.DeleteFile(traceName);
  461. IF res = 0 THEN
  462. res := Kernel32.GetLastError();
  463. Trace.String("could not delete "); Trace.String(traceName); Trace.String("; res = "); Trace.Int(res,1); Trace.Ln;
  464. END;
  465. END;
  466. END RemoveTraceFile;
  467. PROCEDURE ToExecutablePath(CONST name: ARRAY OF CHAR; VAR fullName: ARRAY OF CHAR);
  468. VAR i,j: LONGINT;
  469. BEGIN
  470. Kernel32.GetModuleFileName(Kernel32.hInstance, fullName, LEN( fullName ) );
  471. j := -1; i := 0;
  472. WHILE fullName[i] # 0X DO
  473. IF fullName[i] = '\' THEN j := i END;
  474. INC( i )
  475. END;
  476. i := 0; INC(j);
  477. WHILE name[i] # 0X DO
  478. fullName[j] := name[i]; INC(i); INC(j);
  479. END;
  480. fullName[j] := 0X;
  481. END ToExecutablePath;
  482. PROCEDURE Append(VAR s: ARRAY OF CHAR; CONST t: ARRAY OF CHAR);
  483. VAR i,j: LONGINT;
  484. BEGIN
  485. i := 0;
  486. WHILE(s[i] # 0X) DO INC(i) END;
  487. j := 0;
  488. WHILE (t[j] # 0X) DO
  489. s[i] := t[j];
  490. INC(i); INC(j);
  491. END;
  492. s[i] := 0X;
  493. END Append;
  494. PROCEDURE Init*;
  495. VAR vendor: Vendor; ver: LONGINT; hfile: Kernel32.HANDLE;
  496. BEGIN
  497. Kernel32.Init;
  498. Trace.String("Machine 1"); Trace.Ln;
  499. (* trace[1] := 0X; Trace.Char := LogChar; Trace.Color := TraceColor; *)
  500. InitLocks();
  501. boottime:=GetTimer();
  502. COPY( Version, version );
  503. Append(version, SYSTEM.Date);
  504. CPUID(vendor, ver, features,features2); SetupSSE2Ext;
  505. fcr := (FCR() - {0,2,3,10,11}) + {0..5,8,9}; (* default FCR RC=00B *)
  506. ReadCommandLine(commandLine);
  507. IF Kernel32.Generic THEN
  508. ToExecutablePath(DefaultGenericConfigFile, defaultConfigFile);
  509. ELSE
  510. ToExecutablePath(DefaultConfigFile, defaultConfigFile);
  511. END;
  512. COPY(UserConfigFile, userConfigFile);
  513. hfile := Kernel32.CreateFile( userConfigFile, SetToDW({Kernel32.GenericRead}), SetToDW({Kernel32.FileShareRead}), NIL , Kernel32.OpenExisting, SetToDW({Kernel32.FileAttributeNormal}), 0 );
  514. IF hfile = Kernel32.InvalidHandleValue THEN
  515. ToExecutablePath(UserConfigFile, userConfigFile);
  516. ELSE
  517. Kernel32.CloseHandle(hfile)
  518. END;
  519. (* ever used ? *)
  520. ParseLine(commandLine, userConfigFile);
  521. userConfigFile[Kernel32.GetFullPathName (userConfigFile, Kernel32.MaxPath, userConfigFile, 0)] := 0X;
  522. Trace.String("config file = "); Trace.String(defaultConfigFile); Trace.Ln;
  523. Trace.String("user config file = "); Trace.String(userConfigFile); Trace.Ln;
  524. traceName[0] := 0X;
  525. GetConfig("Trace",traceName);
  526. Trace.String("traceName "); Trace.String(traceName); Trace.Ln;
  527. IF traceName = "File" THEN SetTraceFile;
  528. ELSIF traceName = "Console" THEN SetTraceConsole
  529. (* else trace is on kernel log *)
  530. END;
  531. Trace.String("Machine init done"); Trace.Ln;
  532. END Init;
  533. PROCEDURE {INITIAL, NOPAF} Start;
  534. BEGIN
  535. stackBottom := CurrentSP();
  536. Init; (* cannot allocate variables in here *)
  537. END Start;
  538. (* Initialize locks. *)
  539. PROCEDURE InitLocks;
  540. VAR i: LONGINT;
  541. BEGIN
  542. i := 0;
  543. WHILE i < MaxLocks DO Kernel32.InitializeCriticalSection( cs[i] ); lock[i] := "N"; INC( i ) END;
  544. END InitLocks;
  545. PROCEDURE CleanupLocks*;
  546. VAR i: LONGINT;
  547. BEGIN
  548. i := 0;
  549. WHILE i < MaxLocks DO Kernel32.DeleteCriticalSection( cs[i] ); INC( i ) END;
  550. END CleanupLocks;
  551. (** Acquire a spin-lock. *)
  552. PROCEDURE Acquire*( level: LONGINT ); (* non reentrant lock (non reentrance "ensured" by ASSERT statement ), CriticalSections are reentrant *)
  553. BEGIN
  554. Kernel32.EnterCriticalSection( cs[level] );
  555. IF StrongChecks THEN
  556. ASSERT ( lock[level] = "N", 1001 );
  557. ELSIF lock[level] # "N" THEN
  558. Trace.String("warning: reentered non-reentrant lock"); Trace.Ln;
  559. END;
  560. lock[level] := "Y";
  561. END Acquire;
  562. (** Release a spin-lock. *)
  563. PROCEDURE Release*( level: LONGINT ); (* release lock *)
  564. BEGIN
  565. IF StrongChecks THEN
  566. ASSERT ( lock[level] ="Y", 1002 );
  567. ELSIF lock[level] # "Y" THEN
  568. Trace.String("warning: reentered non-reentrant lock"); Trace.Ln;
  569. END;
  570. lock[level] := "N";
  571. Kernel32.LeaveCriticalSection( cs[level] )
  572. END Release;
  573. (* added by Alexey *)
  574. PROCEDURE GetMemStatus(VAR stat: Kernel32.MemoryStatusEx): BOOLEAN;
  575. BEGIN
  576. stat.dwLength := 64;
  577. IF Kernel32.GlobalMemoryStatusEx(stat) = 1 THEN
  578. RETURN TRUE;
  579. ELSE
  580. RETURN FALSE;
  581. END;
  582. END GetMemStatus;
  583. (** dummy procedure to make GC work for both I386 and Win32 *)
  584. PROCEDURE GetKernelStacks*(VAR stack: ARRAY OF Stack);
  585. VAR i: LONGINT;
  586. BEGIN
  587. FOR i := 0 TO MaxCPU-1 DO
  588. stack[i].adr := NilVal;
  589. stack[i].high := NilVal
  590. END
  591. END GetKernelStacks;
  592. (* Set machine-dependent parameter gcThreshold *)
  593. PROCEDURE SetGCParams*;
  594. BEGIN
  595. gcThreshold := 10*1024*1024; (* 10 MB *)
  596. END SetGCParams;
  597. (* expand heap by allocating a new memory block - called during GC *)
  598. PROCEDURE InitHeap(VAR memoryBlock: MemoryBlock; VAR beginBlockAdr, endBlockAdr: ADDRESS);
  599. CONST MemBlockHeaderSize = BlockHeaderSize + RecordDescSize + BlockHeaderSize;
  600. TypeDescOffset = -AddressSize; (* see Heaps.Mod *)
  601. HeapBlockOffset = - 2 * AddressSize; (* see Heaps.Mod *)
  602. DataAdrOffset = AddressSize; (* offset of dataAdr field in Heaps.HeapBlockDesc *)
  603. VAR memDescSize, memBlkSize, alignOffset: SIZE; adr, memHeaderAdr, memBlockAdr, memBlockHeadAdr: ADDRESS;
  604. memBlock {UNTRACED}: MemoryBlock; i: LONGINT; ch: CHAR; h: HUGEINT; size: LONGINT;
  605. initVal: LONGINT;
  606. BEGIN
  607. (*
  608. HeapBlockPtr -- bootHeapAdr
  609. 4 Type
  610. 8 Mark
  611. 12 DataAdr
  612. 16 Size
  613. 20 HeapBlockPtr
  614. 24 Type
  615. 28 next -- MemoryBlock
  616. 32 startAdr
  617. 36 size
  618. 40 beginBlockAdr
  619. 44 endBlockAdr
  620. 48 --beginBlockAdr
  621. ....
  622. --endBlockAdr
  623. *)
  624. size := 1;
  625. memDescSize := MemBlockHeaderSize + SIZEOF(MemoryBlockDesc);
  626. INC(memDescSize, (-memDescSize) MOD StaticBlockSize); (* round up to multiple of StaticBlockSize *)
  627. INC(size, (-size) MOD StaticBlockSize); (* round up to multiple of StaticBlockSize *)
  628. memBlkSize := memDescSize + size + StaticBlockSize; (* add StaticBlockSize to account for alignments different from multiples of StaticBlockSize *)
  629. IF memBlkSize < MemBlockSize THEN memBlkSize := MemBlockSize END; (* MemBlockSize implicitly multiple of StaticBlockSize *)
  630. initVal := 8*1024*1024;
  631. adr := Kernel32.VirtualAlloc(initVal, memBlkSize, SetToDW({Kernel32.MEMCommit, Kernel32.MEMReserve}), SetToDW({Kernel32.PageExecuteReadWrite}));
  632. IF adr = NilVal THEN (* allocation failed *)
  633. adr := Kernel32.VirtualAlloc(NilVal, memBlkSize, SetToDW({Kernel32.MEMCommit}), SetToDW({Kernel32.PageExecuteReadWrite}));
  634. END;
  635. Trace.String("first heap block intVal "); Trace.Int(initVal,1); Trace.Ln;
  636. Trace.String("first heap block memBlkSize "); Trace.Int(memBlkSize,1); Trace.Ln;
  637. Trace.String("first heap block adr "); Trace.Int(adr,1); Trace.Ln;
  638. ASSERT(adr # 0);
  639. alignOffset := (-adr) MOD StaticBlockSize;
  640. memHeaderAdr := adr + alignOffset; (* force alignment of memory block start *)
  641. memBlockAdr := memHeaderAdr + MemBlockHeaderSize;
  642. memBlock := SYSTEM.VAL(MemoryBlock, memBlockAdr);
  643. beginBlockAdr := memHeaderAdr + memDescSize;
  644. memBlock.next := NIL;
  645. memBlock.startAdr := adr;
  646. memBlock.size := memBlkSize;
  647. beginBlockAdr := memHeaderAdr + memDescSize;
  648. endBlockAdr := adr + memBlkSize - alignOffset;
  649. memBlock.beginBlockAdr := beginBlockAdr;
  650. memBlock.endBlockAdr := endBlockAdr;
  651. (* correct fields *)
  652. SYSTEM.PUT(memBlockAdr + HeapBlockOffset, memHeaderAdr + BlockHeaderSize); (* set reference to header part of memory block correctly *)
  653. SYSTEM.PUT(memBlockAdr + TypeDescOffset, 0); (* set type descriptor field of memory block to default value, memory blocks are not traced by GC *)
  654. SYSTEM.PUT(memHeaderAdr + BlockHeaderSize + DataAdrOffset, memBlockAdr); (* set dataAdr of RecordBlockDesc to correct value *)
  655. SYSTEM.PUT(memHeaderAdr + BlockHeaderSize + 2*AddressSize , memBlkSize);
  656. (* fill first heap block *)
  657. SYSTEM.PUT(beginBlockAdr,0);
  658. SYSTEM.PUT(beginBlockAdr+AddressSize,0);
  659. SYSTEM.PUT(beginBlockAdr+2*AddressSize,0);
  660. (* change this when Heaps.HeapBlock is modified *)
  661. SYSTEM.PUT(beginBlockAdr+3*AddressSize,beginBlockAdr+7*AddressSize);
  662. SYSTEM.PUT(beginBlockAdr+4*AddressSize,endBlockAdr-beginBlockAdr);
  663. SYSTEM.PUT(beginBlockAdr+5*AddressSize,beginBlockAdr+2*AddressSize);
  664. SYSTEM.PUT(beginBlockAdr+6*AddressSize,0);
  665. memoryBlock := memBlock;
  666. END InitHeap;
  667. (** Get first memory block and first free address, the first free address is identical to memBlockHead.endBlockAdr *)
  668. PROCEDURE GetStaticHeap*(VAR beginBlockAdr, endBlockAdr, freeBlockAdr: ADDRESS);
  669. VAR memBlockAdr: ADDRESS;
  670. BEGIN
  671. InitHeap(memBlockHead,beginBlockAdr, endBlockAdr);
  672. memBlockTail := memBlockHead;
  673. (*
  674. SYSTEM.GET(bootHeapAdr + EndBlockOfs, freeBlockAdr);
  675. ASSERT(freeBlockAdr MOD StaticBlockSize = 0);
  676. memBlockAdr := bootHeapAdr + HeaderSize + MemoryBlockOfs;
  677. memBlockHead := SYSTEM.VAL(MemoryBlock, memBlockAdr); (* this block will never be freed since there is a global reference (initBlock in Heaps.Mod) to it *)
  678. memBlockHead.startAdr := bootHeapAdr;
  679. memBlockHead.size := bootHeapSize;
  680. ASSERT(memBlockHead.beginBlockAdr MOD StaticBlockSize = 0);
  681. ASSERT((memBlockHead.endBlockAdr - memBlockHead.beginBlockAdr) MOD StaticBlockSize = 0);
  682. memBlockTail := memBlockHead;
  683. *)
  684. beginBlockAdr := memBlockHead.beginBlockAdr;
  685. endBlockAdr := memBlockHead.endBlockAdr;
  686. freeBlockAdr := beginBlockAdr;
  687. END GetStaticHeap;
  688. (* returns if an address is a currently allocated heap address *)
  689. PROCEDURE ValidHeapAddress*(p: ADDRESS): BOOLEAN;
  690. BEGIN
  691. RETURN (p >= memBlockHead.beginBlockAdr) & (p <= memBlockTail.endBlockAdr)
  692. OR (p>=401000H) & (p<=ADDRESSOF(LastAddress))
  693. END ValidHeapAddress;
  694. PROCEDURE GetFreeK* (VAR total, lowFree, highFree: SIZE);
  695. VAR
  696. stat: Kernel32.MemoryStatusEx;
  697. BEGIN
  698. total := MAX(LONGINT); lowFree := 0; highFree := total;
  699. (*<< added by Alexey *)
  700. IF GetMemStatus(stat) THEN
  701. total := SHORT(stat.ullTotalVirtual DIV 1024);
  702. lowFree := 0;
  703. highFree := SHORT(stat.ullAvailVirtual DIV 1024);
  704. END;
  705. (* added by Alexey >>*)
  706. END GetFreeK;
  707. (* ug *)
  708. PROCEDURE TraceMemBlocks*;
  709. VAR memBlock {UNTRACED}: MemoryBlock; i : LONGINT;
  710. BEGIN
  711. memBlock := memBlockHead;
  712. i := 0;
  713. WHILE memBlock # NIL DO
  714. Trace.String("block "); Trace.Int(i, 0); Trace.String(": startAdr = "); Trace.Hex(memBlock.startAdr, 0);
  715. Trace.String(" size = "); Trace.Hex(memBlock.size, 0);
  716. Trace.String(" beginBlockAdr = "); Trace.Hex(memBlock.beginBlockAdr, 0);
  717. Trace.String(" endBlockAdr = "); Trace.Hex(memBlock.endBlockAdr, 0); Trace.Ln;
  718. memBlock := memBlock.next;
  719. INC(i)
  720. END
  721. END TraceMemBlocks;
  722. (* insert given memory block in sorted list of memory blocks, sort key is startAdr field - called during GC *)
  723. PROCEDURE InsertMemoryBlock(memBlock: MemoryBlock);
  724. VAR cur {UNTRACED}, prev {UNTRACED}: MemoryBlock;
  725. BEGIN
  726. cur := memBlockHead;
  727. prev := NIL;
  728. WHILE (cur # NIL) & (cur.startAdr < memBlock.startAdr) DO
  729. prev := cur;
  730. cur := cur.next
  731. END;
  732. IF prev = NIL THEN (* insert at head of list *)
  733. memBlock.next := memBlockHead;
  734. memBlockHead := memBlock
  735. ELSE (* insert in middle or at end of list *)
  736. memBlock.next := cur;
  737. prev.next := memBlock;
  738. IF cur = NIL THEN
  739. memBlockTail := memBlock
  740. END
  741. END
  742. END InsertMemoryBlock;
  743. PROCEDURE SetToDW(set: SET): Kernel32.DWORD;
  744. BEGIN
  745. RETURN SYSTEM.VAL(Kernel32.DWORD,set);
  746. END SetToDW;
  747. (* expand heap by allocating a new memory block - called during GC *)
  748. PROCEDURE ExpandHeap*(dummy: LONGINT; size: SIZE; VAR memoryBlock: MemoryBlock; VAR beginBlockAdr, endBlockAdr: ADDRESS);
  749. CONST MemBlockHeaderSize = BlockHeaderSize + RecordDescSize + BlockHeaderSize;
  750. TypeDescOffset = -AddressSize; (* see Heaps.Mod *)
  751. HeapBlockOffset = - 2 * AddressSize; (* see Heaps.Mod *)
  752. DataAdrOffset = AddressSize; (* offset of dataAdr field in Heaps.HeapBlockDesc *)
  753. VAR memDescSize, memBlkSize, alignOffset: SIZE; adr, memHeaderAdr, memBlockAdr, memBlockHeadAdr: ADDRESS;
  754. memBlock {UNTRACED}: MemoryBlock; i: LONGINT; ch: CHAR; h: HUGEINT; initVal: SIZE;
  755. continue: BOOLEAN;
  756. BEGIN
  757. memDescSize := MemBlockHeaderSize + SIZEOF(MemoryBlockDesc);
  758. INC(memDescSize, (-memDescSize) MOD StaticBlockSize); (* round up to multiple of StaticBlockSize *)
  759. INC(size, (-size) MOD StaticBlockSize); (* round up to multiple of StaticBlockSize *)
  760. memBlkSize := memDescSize + size + StaticBlockSize; (* add StaticBlockSize to account for alignments different from multiples of StaticBlockSize *)
  761. INC(memBlkSize, (-memBlkSize) MOD MemBlockSize);
  762. initVal := memBlockTail.startAdr + memBlockTail.size;
  763. adr := Kernel32.VirtualAlloc(initVal, memBlkSize, SetToDW({Kernel32.MEMCommit, Kernel32.MEMReserve}), SetToDW({Kernel32.PageExecuteReadWrite}));
  764. IF adr = NilVal THEN (* allocation failed *)
  765. adr := Kernel32.VirtualAlloc(NilVal, memBlkSize, SetToDW({Kernel32.MEMCommit}), SetToDW({Kernel32.PageExecuteReadWrite}));
  766. END;
  767. continue := adr = initVal;
  768. Trace.String("expand heap block intVal "); Trace.Int(initVal,1); Trace.Ln;
  769. Trace.String("expand heap block memBlkSize "); Trace.Int(memBlkSize,1); Trace.Ln;
  770. Trace.String("expand heap block adr "); Trace.Int(adr,1); Trace.Ln;
  771. ASSERT(adr # 0);
  772. IF adr # 0 THEN
  773. alignOffset := (-adr) MOD StaticBlockSize;
  774. IF continue THEN
  775. memBlock := memBlockTail;
  776. memBlock.size := memBlock.size + memBlkSize;
  777. beginBlockAdr := memBlockTail.endBlockAdr;
  778. endBlockAdr := beginBlockAdr;
  779. INC(endBlockAdr, memBlkSize);
  780. ELSE
  781. memHeaderAdr := adr + alignOffset; (* force alignment of memory block start *)
  782. memBlockAdr := memHeaderAdr + MemBlockHeaderSize;
  783. memBlock := SYSTEM.VAL(MemoryBlock, memBlockAdr);
  784. memBlock.next := NIL;
  785. memBlock.startAdr := adr;
  786. memBlock.size := memBlkSize;
  787. beginBlockAdr := memHeaderAdr + memDescSize;
  788. endBlockAdr := adr + memBlkSize - alignOffset;
  789. memBlock.beginBlockAdr := beginBlockAdr;
  790. memBlock.endBlockAdr := beginBlockAdr;
  791. (* upon memory block insertion memBlock.beginBlockAdr = memBlock.endBlockAdr to denote that the memory block has no valid heap blocks yet
  792. - necessary for real-time GC. Memory block end address is set by caller by using SetMemBlockEndAddress after fitting free block in. *)
  793. (* copy header of memBlockHead to header of memBlock - byte by byte *)
  794. memBlockHeadAdr := SYSTEM.VAL(ADDRESS, memBlockHead);
  795. FOR i := 0 TO MemBlockHeaderSize - 1 DO
  796. SYSTEM.GET(memBlockHeadAdr - MemBlockHeaderSize + i, ch);
  797. SYSTEM.PUT(memBlockAdr - MemBlockHeaderSize + i, ch)
  798. END;
  799. (* correct fields *)
  800. SYSTEM.PUT(memBlockAdr + HeapBlockOffset, memHeaderAdr + BlockHeaderSize); (* set reference to header part of memory block correctly *)
  801. SYSTEM.PUT(memBlockAdr + TypeDescOffset, 0); (* set type descriptor field of memory block to default value, memory blocks are not traced by GC *)
  802. SYSTEM.PUT(memHeaderAdr + BlockHeaderSize + DataAdrOffset, memBlockAdr); (* set dataAdr of RecordBlockDesc to correct value *)
  803. InsertMemoryBlock(memBlock);
  804. END;
  805. memoryBlock := memBlock;
  806. ELSE
  807. beginBlockAdr := 0; endBlockAdr := 0;
  808. END;
  809. END ExpandHeap;
  810. (* Set memory block end address *)
  811. PROCEDURE SetMemoryBlockEndAddress*(memBlock: MemoryBlock; endBlockAdr: ADDRESS);
  812. BEGIN
  813. ASSERT(endBlockAdr >= memBlock.beginBlockAdr);
  814. memBlock.endBlockAdr := endBlockAdr
  815. END SetMemoryBlockEndAddress;
  816. (* Free unused memory block - called during GC *)
  817. PROCEDURE FreeMemBlock*(memBlock: MemoryBlock);
  818. VAR cur {UNTRACED}, prev {UNTRACED}: MemoryBlock;
  819. startAdr: ADDRESS;
  820. BEGIN
  821. cur := memBlockHead;
  822. prev := NIL;
  823. WHILE (cur # NIL) & (cur # memBlock) DO
  824. prev := cur;
  825. cur := cur.next
  826. END;
  827. IF cur = memBlock THEN
  828. IF prev = NIL THEN
  829. memBlockHead := cur.next;
  830. ELSE
  831. prev.next := cur.next;
  832. IF prev.next = NIL THEN
  833. memBlockTail := prev
  834. END
  835. END;
  836. memBlock.next := NIL;
  837. startAdr := memBlock.startAdr; (* this value must be cached for the second call of Kernel32.VirtualFree *)
  838. Kernel32.VirtualFree(SYSTEM.VAL(LONGINT, memBlock.startAdr), memBlock.size, SetToDW({Kernel32.MEMDecommit}));
  839. Kernel32.VirtualFree(SYSTEM.VAL(LONGINT, startAdr ), 0, SetToDW({Kernel32.MEMRelease}));
  840. ELSE
  841. HALT(535) (* error in memory block management *)
  842. END;
  843. END FreeMemBlock;
  844. PROCEDURE PhysicalAdr*(adr: ADDRESS; size: SIZE): ADDRESS;
  845. END PhysicalAdr;
  846. (* function returning the number of processors that are available to Aos *)
  847. PROCEDURE NumberOfProcessors*( ): LONGINT;
  848. VAR info: Kernel32.SystemInfo;
  849. BEGIN
  850. Kernel32.GetSystemInfo( info );
  851. RETURN info.dwNumberOfProcessors
  852. END NumberOfProcessors;
  853. (* function for changing byte order *)
  854. PROCEDURE ChangeByteOrder* (n: LONGINT): LONGINT;
  855. CODE { SYSTEM.Pentium }
  856. MOV EAX, [EBP+n] ; load n in eax
  857. BSWAP EAX ; swap byte order
  858. END ChangeByteOrder;
  859. PROCEDURE TraceColor (c: SHORTINT);
  860. END TraceColor;
  861. PROCEDURE LogChar (c: CHAR);
  862. VAR trace: ARRAY 2 OF CHAR;
  863. BEGIN trace[0] := c; trace[1] := 0X; Kernel32.OutputString (trace);
  864. END LogChar;
  865. PROCEDURE -GetRAX*(): HUGEINT;
  866. CODE{SYSTEM.AMD64}
  867. END GetRAX;
  868. PROCEDURE -GetRCX*(): HUGEINT;
  869. CODE{SYSTEM.AMD64}
  870. MOV RAX,RCX
  871. END GetRCX;
  872. PROCEDURE -GetRSI*(): HUGEINT;
  873. CODE{SYSTEM.AMD64}
  874. MOV RAX,RSI
  875. END GetRSI;
  876. PROCEDURE -GetRDI*(): HUGEINT;
  877. CODE{SYSTEM.AMD64}
  878. MOV RAX,RDI
  879. END GetRDI;
  880. PROCEDURE -SetRAX*(n: HUGEINT);
  881. CODE{SYSTEM.AMD64}
  882. NOP
  883. POP RAX
  884. END SetRAX;
  885. PROCEDURE -SetRBX*(n: HUGEINT);
  886. CODE{SYSTEM.AMD64}
  887. NOP
  888. POP RBX
  889. END SetRBX;
  890. PROCEDURE -SetRCX*(n: HUGEINT);
  891. CODE{SYSTEM.AMD64}
  892. POP RCX
  893. END SetRCX;
  894. PROCEDURE -SetRDX*(n: HUGEINT);
  895. CODE{SYSTEM.AMD64}
  896. POP RDX
  897. END SetRDX;
  898. PROCEDURE -SetRSI*(n: HUGEINT);
  899. CODE{SYSTEM.AMD64}
  900. POP RSI
  901. END SetRSI;
  902. PROCEDURE -SetRDI*(n: HUGEINT);
  903. CODE{SYSTEM.AMD64}
  904. POP RDI
  905. END SetRDI;
  906. PROCEDURE Portin8*(port: LONGINT; VAR val: CHAR);
  907. CODE{SYSTEM.AMD64}
  908. MOV EDX,[RBP+port]
  909. IN AL, DX
  910. MOV RCX, [RBP+val]
  911. MOV [RCX], AL
  912. END Portin8;
  913. PROCEDURE Portin16*(port: LONGINT; VAR val: INTEGER);
  914. CODE{SYSTEM.AMD64}
  915. MOV EDX,[RBP+port]
  916. IN AX, DX
  917. MOV RCX, [RBP+val]
  918. MOV [RCX], AX
  919. END Portin16;
  920. PROCEDURE Portin32*(port: LONGINT; VAR val: LONGINT);
  921. CODE{SYSTEM.AMD64}
  922. MOV EDX,[RBP+port]
  923. IN EAX, DX
  924. MOV RCX, [RBP+val]
  925. MOV [RCX], EAX
  926. END Portin32;
  927. PROCEDURE Portout8*(port: LONGINT; val: CHAR);
  928. CODE{SYSTEM.AMD64}
  929. MOV AL,[RBP+val]
  930. MOV EDX,[RBP+port]
  931. OUT DX,AL
  932. END Portout8;
  933. PROCEDURE Portout16*(port: LONGINT; val: INTEGER);
  934. CODE{SYSTEM.AMD64}
  935. MOV AX,[RBP+val]
  936. MOV EDX,[RBP+port]
  937. OUT DX,AX
  938. END Portout16;
  939. PROCEDURE Portout32*(port: LONGINT; val: LONGINT);
  940. CODE{SYSTEM.AMD64}
  941. MOV EAX,[RBP+val]
  942. MOV EDX,[RBP+port]
  943. OUT DX,EAX
  944. END Portout32;
  945. BEGIN
  946. IF ~Kernel32.Generic THEN
  947. Init
  948. END;
  949. Trace.String("Machine (64 bit)"); Trace.Ln;
  950. END Machine.