Win32.Machine.Mod 32 KB

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