Win32.Machine.Mod 32 KB

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