Win64.Machine.Mod 32 KB

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