Win32.Machine.Mod 31 KB

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