Win32.Machine.Mod 35 KB

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