Win32.Machine.Mod 35 KB

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