i8086.inc 27 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160
  1. {
  2. This file is part of the Free Pascal run time library.
  3. Copyright (c) 2013 by the Free Pascal development team.
  4. Processor dependent implementation for the system unit for
  5. intel i8086+
  6. See the file COPYING.FPC, included in this distribution,
  7. for details about the copyright.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  11. **********************************************************************}
  12. procedure fpc_cpuinit;
  13. begin
  14. end;
  15. {$ifndef FPC_SYSTEM_HAS_FILLCHAR}
  16. {$define FPC_SYSTEM_HAS_FILLCHAR}
  17. procedure FillChar(var x;count:SizeUInt;value:byte);assembler;nostackframe;
  18. asm
  19. mov bx, sp
  20. mov cx, ss:[bx + 4 + extra_param_offset] // count
  21. jcxz @@Done
  22. {$ifdef FPC_X86_DATA_NEAR}
  23. mov di, ss:[bx + 6 + extra_param_offset] // @x
  24. mov ax, ds
  25. mov es, ax
  26. {$else FPC_X86_DATA_NEAR}
  27. les di, ss:[bx + 6 + extra_param_offset] // @x
  28. {$endif FPC_X86_DATA_NEAR}
  29. mov al, ss:[bx + 2 + extra_param_offset] // value
  30. mov ah, al
  31. shr cx, 1
  32. {$ifdef FPC_ENABLED_CLD}
  33. cld
  34. {$endif FPC_ENABLED_CLD}
  35. rep stosw
  36. adc cx, cx
  37. rep stosb
  38. @@Done:
  39. end;
  40. {$endif FPC_SYSTEM_HAS_FILLCHAR}
  41. {$ifndef FPC_SYSTEM_HAS_FILLWORD}
  42. {$define FPC_SYSTEM_HAS_FILLWORD}
  43. procedure FillWord(var x;count : SizeInt;value : word);assembler;nostackframe;
  44. asm
  45. mov bx, sp
  46. mov cx, ss:[bx + 4 + extra_param_offset] // count
  47. or cx, cx
  48. jle @@Done
  49. {$ifdef FPC_X86_DATA_NEAR}
  50. mov di, ss:[bx + 6 + extra_param_offset] // @x
  51. mov ax, ds
  52. mov es, ax
  53. {$else FPC_X86_DATA_NEAR}
  54. les di, ss:[bx + 6 + extra_param_offset] // @x
  55. {$endif FPC_X86_DATA_NEAR}
  56. mov ax, ss:[bx + 2 + extra_param_offset] // value
  57. {$ifdef FPC_ENABLED_CLD}
  58. cld
  59. {$endif FPC_ENABLED_CLD}
  60. rep stosw
  61. @@Done:
  62. end;
  63. {$endif FPC_SYSTEM_HAS_FILLWORD}
  64. {$ifndef FPC_SYSTEM_HAS_FILLDWORD}
  65. {$define FPC_SYSTEM_HAS_FILLDWORD}
  66. procedure FillDWord(var x;count : SizeInt;value : dword);assembler;nostackframe;
  67. asm
  68. mov bx, sp
  69. mov cx, ss:[bx + 6 + extra_param_offset] // count
  70. or cx, cx
  71. jle @@Done
  72. {$ifdef FPC_X86_DATA_NEAR}
  73. mov di, ss:[bx + 8 + extra_param_offset] // @x
  74. mov ax, ds
  75. mov es, ax
  76. {$else FPC_X86_DATA_NEAR}
  77. les di, ss:[bx + 8 + extra_param_offset] // @x
  78. {$endif FPC_X86_DATA_NEAR}
  79. mov ax, ss:[bx + 2 + extra_param_offset] // lo(value)
  80. mov bx, ss:[bx + 4 + extra_param_offset] // hi(value)
  81. {$ifdef FPC_ENABLED_CLD}
  82. cld
  83. {$endif FPC_ENABLED_CLD}
  84. cmp ax, bx
  85. jne @@lo_hi_different
  86. shl cx, 1
  87. rep stosw
  88. jmp @@Done
  89. @@lo_hi_different:
  90. stosw
  91. xchg ax, bx
  92. stosw
  93. xchg ax, bx
  94. loop @@lo_hi_different
  95. @@Done:
  96. end;
  97. {$endif FPC_SYSTEM_HAS_FILLDWORD}
  98. {$ifndef FPC_SYSTEM_HAS_MOVE}
  99. {$define FPC_SYSTEM_HAS_MOVE}
  100. procedure Move(const source;var dest;count:SizeUInt);[public, alias: 'FPC_MOVE'];assembler;nostackframe;
  101. asm
  102. mov bx, sp
  103. mov cx, ss:[bx + 2 + extra_param_offset] // count
  104. jcxz @@Done
  105. mov ax, ds // for far data models, backup ds; for near data models, use to initialize es
  106. {$ifdef FPC_X86_DATA_NEAR}
  107. mov es, ax
  108. mov si, ss:[bx + 6 + extra_param_offset] // @source
  109. mov di, ss:[bx + 4 + extra_param_offset] // @dest
  110. {$else FPC_X86_DATA_NEAR}
  111. lds si, ss:[bx + 8 + extra_param_offset] // @source
  112. les di, ss:[bx + 4 + extra_param_offset] // @dest
  113. {$endif FPC_X86_DATA_NEAR}
  114. cmp si, di
  115. jb @@BackwardsMove
  116. {$ifdef FPC_ENABLED_CLD}
  117. cld
  118. {$endif FPC_ENABLED_CLD}
  119. shr cx, 1
  120. rep movsw
  121. adc cx, cx
  122. rep movsb
  123. jmp @@AfterMove // todo, add mov ds,ax & ret here for performance reasons
  124. @@BackwardsMove:
  125. std
  126. add si, cx
  127. add di, cx
  128. dec si
  129. dec di
  130. rep movsb // todo: movsw
  131. cld
  132. @@AfterMove:
  133. {$if defined(FPC_X86_DATA_FAR) or defined(FPC_X86_DATA_HUGE)}
  134. mov ds, ax
  135. {$endif}
  136. @@Done:
  137. end;
  138. {$endif FPC_SYSTEM_HAS_MOVE}
  139. {$ifndef FPC_SYSTEM_HAS_INDEXBYTE}
  140. {$define FPC_SYSTEM_HAS_INDEXBYTE}
  141. function IndexByte(Const buf;len:SizeInt;b:byte):SizeInt; assembler; nostackframe;
  142. asm
  143. mov bx, sp
  144. mov cx, ss:[bx + 4 + extra_param_offset] // len
  145. jcxz @@NotFound
  146. {$ifdef FPC_X86_DATA_NEAR}
  147. mov di, ss:[bx + 6 + extra_param_offset] // @buf
  148. mov ax, ds
  149. mov es, ax
  150. {$else FPC_X86_DATA_NEAR}
  151. les di, ss:[bx + 6 + extra_param_offset] // @buf
  152. {$endif FPC_X86_DATA_NEAR}
  153. mov si, di // save the start of the buffer in si
  154. mov al, ss:[bx + 2 + extra_param_offset] // b
  155. {$ifdef FPC_ENABLED_CLD}
  156. cld
  157. {$endif FPC_ENABLED_CLD}
  158. repne scasb
  159. je @@Found
  160. @@NotFound:
  161. mov ax, 0FFFFh // return -1
  162. jmp @@Done
  163. @@Found:
  164. sub di, si
  165. xchg ax, di
  166. dec ax
  167. @@Done:
  168. end;
  169. {$endif FPC_SYSTEM_HAS_INDEXBYTE}
  170. {$ifndef FPC_SYSTEM_HAS_INDEXWORD}
  171. {$define FPC_SYSTEM_HAS_INDEXWORD}
  172. function IndexWord(Const buf;len:SizeInt;b:word):SizeInt; assembler; nostackframe;
  173. asm
  174. mov bx, sp
  175. mov cx, ss:[bx + 4 + extra_param_offset] // len
  176. jcxz @@NotFound
  177. {$ifdef FPC_X86_DATA_NEAR}
  178. mov di, ss:[bx + 6 + extra_param_offset] // @buf
  179. mov ax, ds
  180. mov es, ax
  181. {$else FPC_X86_DATA_NEAR}
  182. les di, ss:[bx + 6 + extra_param_offset] // @buf
  183. {$endif FPC_X86_DATA_NEAR}
  184. mov si, cx // save the length of the buffer in si
  185. mov ax, ss:[bx + 2 + extra_param_offset] // b
  186. {$ifdef FPC_ENABLED_CLD}
  187. cld
  188. {$endif FPC_ENABLED_CLD}
  189. repne scasw
  190. je @@Found
  191. @@NotFound:
  192. mov ax, 0FFFFh // return -1
  193. jmp @@Done
  194. @@Found:
  195. sub si, cx
  196. xchg ax, si
  197. dec ax
  198. @@Done:
  199. end;
  200. {$endif FPC_SYSTEM_HAS_INDEXWORD}
  201. {$ifndef FPC_SYSTEM_HAS_INDEXDWORD}
  202. {$define FPC_SYSTEM_HAS_INDEXDWORD}
  203. function IndexDWord(Const buf;len:SizeInt;b:DWord):SizeInt; assembler; nostackframe;
  204. asm
  205. mov bx, sp
  206. mov cx, ss:[bx + 6 + extra_param_offset] // len
  207. jcxz @@NotFound
  208. {$ifdef FPC_X86_DATA_NEAR}
  209. mov di, ss:[bx + 8 + extra_param_offset] // @buf
  210. mov ax, ds
  211. mov es, ax
  212. {$else FPC_X86_DATA_NEAR}
  213. les di, ss:[bx + 8 + extra_param_offset] // @buf
  214. {$endif FPC_X86_DATA_NEAR}
  215. mov si, cx // save the length of the buffer in si
  216. mov ax, ss:[bx + 2 + extra_param_offset] // b
  217. mov bx, ss:[bx + 4 + extra_param_offset]
  218. {$ifdef FPC_ENABLED_CLD}
  219. cld
  220. {$endif FPC_ENABLED_CLD}
  221. jmp @@LoopStart
  222. @@SkipWord:
  223. scasw
  224. @@LoopStart:
  225. scasw
  226. loopne @@SkipWord
  227. jne @@NotFound
  228. xchg ax, bx
  229. scasw
  230. je @@Found
  231. jcxz @@NotFound
  232. xchg ax, bx
  233. jmp @@LoopStart
  234. @@Found:
  235. sub si, cx
  236. xchg ax, si
  237. dec ax
  238. jmp @@Done
  239. @@NotFound:
  240. mov ax, 0FFFFh // return -1
  241. @@Done:
  242. end;
  243. {$endif FPC_SYSTEM_HAS_INDEXDWORD}
  244. {$ifndef FPC_SYSTEM_HAS_COMPAREBYTE}
  245. {$define FPC_SYSTEM_HAS_COMPAREBYTE}
  246. function CompareByte(Const buf1,buf2;len:SizeInt):SizeInt; assembler; nostackframe;
  247. asm
  248. xor ax, ax // initialize ax=0 (it's the result register, we never use it for anything else in this function)
  249. mov bx, sp
  250. mov cx, ss:[bx + 2 + extra_param_offset] // len
  251. jcxz @@Done
  252. mov dx, ds // for far data models, backup ds; for near data models, use to initialize es
  253. {$ifdef FPC_X86_DATA_NEAR}
  254. mov es, dx
  255. mov si, ss:[bx + 6 + extra_param_offset] // @buf1
  256. mov di, ss:[bx + 4 + extra_param_offset] // @buf2
  257. {$else FPC_X86_DATA_NEAR}
  258. lds si, ss:[bx + 8 + extra_param_offset] // @buf1
  259. les di, ss:[bx + 4 + extra_param_offset] // @buf2
  260. {$endif FPC_X86_DATA_NEAR}
  261. {$ifdef FPC_ENABLED_CLD}
  262. cld
  263. {$endif FPC_ENABLED_CLD}
  264. xor bx, bx
  265. shr cx, 1
  266. adc bx, bx // remainder goes to bx
  267. jcxz @@BytewiseComparison
  268. repe cmpsw
  269. je @@BytewiseComparison
  270. // we found an unequal word
  271. // let's go back and compare it bytewise
  272. mov bl, 2
  273. dec si
  274. dec si
  275. dec di
  276. dec di
  277. @@BytewiseComparison:
  278. mov cx, bx
  279. jcxz @@Equal
  280. repe cmpsb
  281. je @@Equal
  282. // ax is 0
  283. sbb ax, ax
  284. shl ax, 1
  285. inc ax
  286. @@Equal:
  287. // ax is 0
  288. {$if defined(FPC_X86_DATA_FAR) or defined(FPC_X86_DATA_HUGE)}
  289. mov ds, dx
  290. {$endif}
  291. @@Done:
  292. end;
  293. {$endif FPC_SYSTEM_HAS_COMPAREBYTE}
  294. {$ifndef FPC_SYSTEM_HAS_COMPAREWORD}
  295. {$define FPC_SYSTEM_HAS_COMPAREWORD}
  296. function CompareWord(Const buf1,buf2;len:SizeInt):SizeInt; assembler; nostackframe;
  297. asm
  298. xor ax, ax // initialize ax=0 (it's the result register, we never use it for anything else in this function)
  299. mov bx, sp
  300. mov cx, ss:[bx + 2 + extra_param_offset] // len
  301. jcxz @@Done
  302. mov dx, ds // for far data models, backup ds; for near data models, use to initialize es
  303. {$ifdef FPC_X86_DATA_NEAR}
  304. mov es, dx
  305. mov si, ss:[bx + 6 + extra_param_offset] // @buf1
  306. mov di, ss:[bx + 4 + extra_param_offset] // @buf2
  307. {$else FPC_X86_DATA_NEAR}
  308. lds si, ss:[bx + 8 + extra_param_offset] // @buf1
  309. les di, ss:[bx + 4 + extra_param_offset] // @buf2
  310. {$endif FPC_X86_DATA_NEAR}
  311. {$ifdef FPC_ENABLED_CLD}
  312. cld
  313. {$endif FPC_ENABLED_CLD}
  314. repe cmpsw
  315. je @@Equal
  316. // ax is 0
  317. sbb ax, ax
  318. shl ax, 1
  319. inc ax
  320. @@Equal:
  321. // ax is 0
  322. {$if defined(FPC_X86_DATA_FAR) or defined(FPC_X86_DATA_HUGE)}
  323. mov ds, dx
  324. {$endif}
  325. @@Done:
  326. end;
  327. {$endif FPC_SYSTEM_HAS_COMPAREWORD}
  328. {$ifndef FPC_SYSTEM_HAS_COMPAREDWORD}
  329. {$define FPC_SYSTEM_HAS_COMPAREDWORD}
  330. function CompareDWord(Const buf1,buf2;len:SizeInt):SizeInt; assembler; nostackframe;
  331. asm
  332. xor ax, ax // initialize ax=0 (it's the result register, we never use it for anything else in this function)
  333. mov bx, sp
  334. mov cx, ss:[bx + 2 + extra_param_offset] // len
  335. jcxz @@Done
  336. cmp cx, 4000h
  337. jb @@NotTooBig
  338. mov cx, 4000h
  339. @@NotTooBig:
  340. shl cx, 1
  341. mov dx, ds // for far data models, backup ds; for near data models, use to initialize es
  342. {$ifdef FPC_X86_DATA_NEAR}
  343. mov es, dx
  344. mov si, ss:[bx + 6 + extra_param_offset] // @buf1
  345. mov di, ss:[bx + 4 + extra_param_offset] // @buf2
  346. {$else FPC_X86_DATA_NEAR}
  347. lds si, ss:[bx + 8 + extra_param_offset] // @buf1
  348. les di, ss:[bx + 4 + extra_param_offset] // @buf2
  349. {$endif FPC_X86_DATA_NEAR}
  350. {$ifdef FPC_ENABLED_CLD}
  351. cld
  352. {$endif FPC_ENABLED_CLD}
  353. repe cmpsw
  354. je @@Equal
  355. // ax is 0
  356. sbb ax, ax
  357. shl ax, 1
  358. inc ax
  359. shr cx, 1
  360. jnc @@Skip
  361. xchg ax, bx
  362. xor ax, ax
  363. cmpsw
  364. je @@hi_equal
  365. // ax is 0
  366. sbb ax, ax
  367. shl ax, 1
  368. inc ax
  369. jmp @@Skip
  370. @@hi_equal:
  371. xchg ax, bx
  372. @@Equal:
  373. // ax is 0
  374. @@Skip:
  375. {$if defined(FPC_X86_DATA_FAR) or defined(FPC_X86_DATA_HUGE)}
  376. mov ds, dx
  377. {$endif}
  378. @@Done:
  379. end;
  380. {$endif FPC_SYSTEM_HAS_COMPAREDWORD}
  381. {$ifndef FPC_SYSTEM_HAS_FPC_PCHAR_LENGTH}
  382. {$define FPC_SYSTEM_HAS_FPC_PCHAR_LENGTH}
  383. function fpc_pchar_length(p:pchar):sizeint;assembler;nostackframe;[public,alias:'FPC_PCHAR_LENGTH']; compilerproc;
  384. asm
  385. mov bx, sp
  386. {$ifdef FPC_X86_DATA_NEAR}
  387. mov ax, ss:[bx + 2 + extra_param_offset] // p
  388. test ax, ax
  389. jz @@Done
  390. xchg ax, di
  391. mov ax, ds
  392. mov es, ax
  393. {$else FPC_X86_DATA_NEAR}
  394. les di, ss:[bx + 2 + extra_param_offset] // p
  395. mov ax, es
  396. or ax, di
  397. jz @@Done
  398. {$endif FPC_X86_DATA_NEAR}
  399. mov cx, 0FFFFh
  400. xor ax, ax
  401. {$ifdef FPC_ENABLED_CLD}
  402. cld
  403. {$endif FPC_ENABLED_CLD}
  404. repne scasb
  405. dec ax
  406. dec ax
  407. sub ax, cx
  408. @@Done:
  409. end;
  410. {$endif FPC_SYSTEM_HAS_FPC_PCHAR_LENGTH}
  411. {$define FPC_SYSTEM_HAS_SPTR}
  412. Function Sptr : Pointer;assembler;nostackframe;
  413. asm
  414. mov ax, sp
  415. {$if defined(FPC_X86_DATA_FAR) or defined(FPC_X86_DATA_HUGE)}
  416. mov dx, ss
  417. {$endif}
  418. end;
  419. {$define FPC_SYSTEM_HAS_PTR}
  420. function Ptr(sel,off: Word):farpointer;{$ifdef SYSTEMINLINE}inline;{$endif}assembler;nostackframe;
  421. asm
  422. mov si, sp
  423. mov ax, ss:[si + 2 + extra_param_offset] // off
  424. mov dx, ss:[si + 4 + extra_param_offset] // sel
  425. end;
  426. {$define FPC_SYSTEM_HAS_CSEG}
  427. function CSeg: Word;{$ifdef SYSTEMINLINE}inline;{$endif}assembler;nostackframe;
  428. asm
  429. mov ax, cs
  430. end;
  431. {$define FPC_SYSTEM_HAS_DSEG}
  432. function DSeg: Word;{$ifdef SYSTEMINLINE}inline;{$endif}assembler;nostackframe;
  433. asm
  434. mov ax, ds
  435. end;
  436. {$define FPC_SYSTEM_HAS_SSEG}
  437. function SSeg: Word;{$ifdef SYSTEMINLINE}inline;{$endif}assembler;nostackframe;
  438. asm
  439. mov ax, ss
  440. end;
  441. {$IFNDEF INTERNAL_BACKTRACE}
  442. {$define FPC_SYSTEM_HAS_GET_FRAME}
  443. function get_frame:pointer;assembler;nostackframe;{$ifdef SYSTEMINLINE}inline;{$endif}
  444. asm
  445. mov ax, bp
  446. {$if defined(FPC_X86_DATA_FAR) or defined(FPC_X86_DATA_HUGE)}
  447. mov dx, ss
  448. {$endif}
  449. end;
  450. {$ENDIF not INTERNAL_BACKTRACE}
  451. {$define FPC_SYSTEM_HAS_GET_PC_ADDR}
  452. Function Get_pc_addr : CodePointer;assembler;nostackframe;
  453. asm
  454. mov bx, sp
  455. mov ax, ss:[bx]
  456. {$ifdef FPC_X86_CODE_FAR}
  457. mov dx, ss:[bx+2]
  458. {$endif FPC_X86_CODE_FAR}
  459. end;
  460. {$define FPC_SYSTEM_HAS_GET_CALLER_ADDR}
  461. function get_caller_addr(framebp:pointer;addr:codepointer=nil):codepointer;nostackframe;assembler;
  462. asm
  463. mov si, sp
  464. {$ifdef FPC_X86_CODE_FAR}
  465. xor dx, dx
  466. {$endif FPC_X86_CODE_FAR}
  467. {$ifdef FPC_X86_DATA_NEAR}
  468. mov ax, ss:[si + 4 + extra_param_offset + extra_param_offset] // framebp
  469. {$ifdef WIN16}
  470. mov cx, ax
  471. and al, $FE
  472. {$endif WIN16}
  473. or ax, ax
  474. jz @@Lg_a_null
  475. xchg ax, bx // 1 byte shorter than a mov
  476. mov ax, [bx+2]
  477. {$ifdef FPC_X86_CODE_FAR}
  478. {$ifdef WIN16}
  479. test cl, 1
  480. jnz @@farretaddr
  481. mov dx, ss:[si + 2 + extra_param_offset + extra_param_offset] // Seg(addr^)
  482. jmp @@retsegdone
  483. @@farretaddr:
  484. mov dx, [bx+4]
  485. @@retsegdone:
  486. {$else WIN16}
  487. mov dx, [bx+4]
  488. {$endif WIN16}
  489. {$endif FPC_X86_CODE_FAR}
  490. {$else FPC_X86_DATA_NEAR}
  491. les ax, ss:[si + 4 + extra_param_offset + extra_param_offset] // framebp
  492. {$ifdef WIN16}
  493. mov cx, ax
  494. and al, $FE
  495. {$endif WIN16}
  496. mov dx, es
  497. or dx, ax
  498. jz @@Lg_a_null
  499. xchg ax, bx // 1 byte shorter than a mov
  500. mov ax, es:[bx+2]
  501. {$ifdef FPC_X86_CODE_FAR}
  502. {$ifdef WIN16}
  503. test cl, 1
  504. jnz @@farretaddr
  505. mov dx, ss:[si + 2 + extra_param_offset + extra_param_offset] // Seg(addr^)
  506. jmp @@retsegdone
  507. @@farretaddr:
  508. mov dx, es:[bx+4]
  509. @@retsegdone:
  510. {$else WIN16}
  511. mov dx, es:[bx+4]
  512. {$endif WIN16}
  513. {$endif FPC_X86_CODE_FAR}
  514. {$endif FPC_X86_DATA_NEAR}
  515. @@Lg_a_null:
  516. end;
  517. {$define FPC_SYSTEM_HAS_GET_CALLER_FRAME}
  518. function get_caller_frame(framebp:pointer;addr:codepointer=nil):pointer;nostackframe;assembler;
  519. asm
  520. {$ifdef FPC_X86_DATA_NEAR}
  521. mov si, sp
  522. mov ax, ss:[si + 4 + extra_param_offset + extra_param_offset] // framebp
  523. {$ifdef WIN16}
  524. and al, $FE
  525. {$endif WIN16}
  526. or ax, ax
  527. jz @@Lgnf_null
  528. xchg ax, si // 1 byte shorter than a mov
  529. lodsw
  530. @@Lgnf_null:
  531. {$else FPC_X86_DATA_NEAR}
  532. mov si, sp
  533. les ax, ss:[si + 4 + extra_param_offset + extra_param_offset] // framebp
  534. {$ifdef WIN16}
  535. and al, $FE
  536. {$endif WIN16}
  537. mov dx, es
  538. or dx, ax
  539. jz @@Lgnf_null
  540. xchg ax, si // 1 byte shorter than a mov
  541. seges lodsw
  542. mov dx, es
  543. @@Lgnf_null:
  544. {$endif FPC_X86_DATA_NEAR}
  545. end;
  546. function InterLockedDecrement (var Target: smallint) : smallint;nostackframe;assembler;
  547. asm
  548. mov si, sp
  549. {$ifdef FPC_X86_DATA_NEAR}
  550. mov bx, ss:[si + 2 + extra_param_offset] // Target
  551. {$else FPC_X86_DATA_NEAR}
  552. mov cx, ds
  553. lds bx, ss:[si + 2 + extra_param_offset] // Target
  554. {$endif FPC_X86_DATA_NEAR}
  555. pushf
  556. cli
  557. sub word [bx], 1
  558. mov ax, [bx]
  559. popf
  560. {$if defined(FPC_X86_DATA_FAR) or defined(FPC_X86_DATA_HUGE)}
  561. mov ds, cx
  562. {$endif}
  563. end;
  564. function InterLockedDecrement (var Target: longint) : longint;nostackframe;assembler;
  565. asm
  566. mov si, sp
  567. {$ifdef FPC_X86_DATA_NEAR}
  568. mov bx, ss:[si + 2 + extra_param_offset] // Target
  569. {$else FPC_X86_DATA_NEAR}
  570. mov cx, ds
  571. lds bx, ss:[si + 2 + extra_param_offset] // Target
  572. {$endif FPC_X86_DATA_NEAR}
  573. pushf
  574. cli
  575. sub word [bx], 1
  576. sbb word [bx+2], 0
  577. mov ax, [bx]
  578. mov dx, [bx+2]
  579. popf
  580. {$if defined(FPC_X86_DATA_FAR) or defined(FPC_X86_DATA_HUGE)}
  581. mov ds, cx
  582. {$endif}
  583. end;
  584. function InterLockedIncrement (var Target: smallint) : smallint;nostackframe;assembler;
  585. asm
  586. mov si, sp
  587. {$ifdef FPC_X86_DATA_NEAR}
  588. mov bx, ss:[si + 2 + extra_param_offset] // Target
  589. {$else FPC_X86_DATA_NEAR}
  590. mov cx, ds
  591. lds bx, ss:[si + 2 + extra_param_offset] // Target
  592. {$endif FPC_X86_DATA_NEAR}
  593. pushf
  594. cli
  595. add word [bx], 1
  596. mov ax, [bx]
  597. popf
  598. {$if defined(FPC_X86_DATA_FAR) or defined(FPC_X86_DATA_HUGE)}
  599. mov ds, cx
  600. {$endif}
  601. end;
  602. function InterLockedIncrement (var Target: longint) : longint;nostackframe;assembler;
  603. asm
  604. mov si, sp
  605. {$ifdef FPC_X86_DATA_NEAR}
  606. mov bx, ss:[si + 2 + extra_param_offset] // Target
  607. {$else FPC_X86_DATA_NEAR}
  608. mov cx, ds
  609. lds bx, ss:[si + 2 + extra_param_offset] // Target
  610. {$endif FPC_X86_DATA_NEAR}
  611. pushf
  612. cli
  613. add word [bx], 1
  614. adc word [bx+2], 0
  615. mov ax, [bx]
  616. mov dx, [bx+2]
  617. popf
  618. {$if defined(FPC_X86_DATA_FAR) or defined(FPC_X86_DATA_HUGE)}
  619. mov ds, cx
  620. {$endif}
  621. end;
  622. function InterLockedExchange (var Target: smallint;Source : smallint) : smallint;nostackframe;assembler;
  623. asm
  624. mov si, sp
  625. {$ifdef FPC_X86_DATA_NEAR}
  626. mov bx, ss:[si + 4 + extra_param_offset] // Target
  627. {$else FPC_X86_DATA_NEAR}
  628. mov cx, ds
  629. lds bx, ss:[si + 4 + extra_param_offset] // Target
  630. {$endif FPC_X86_DATA_NEAR}
  631. mov ax, ss:[si + 2 + extra_param_offset] // Source
  632. xchg word [bx], ax
  633. {$if defined(FPC_X86_DATA_FAR) or defined(FPC_X86_DATA_HUGE)}
  634. mov ds, cx
  635. {$endif}
  636. end;
  637. function InterLockedExchange (var Target: longint;Source : longint) : longint;nostackframe;assembler;
  638. asm
  639. mov si, sp
  640. {$ifdef FPC_X86_DATA_NEAR}
  641. mov bx, ss:[si + 6 + extra_param_offset] // Target
  642. {$else FPC_X86_DATA_NEAR}
  643. mov cx, ds
  644. lds bx, ss:[si + 6 + extra_param_offset] // Target
  645. {$endif FPC_X86_DATA_NEAR}
  646. mov ax, ss:[si + 2 + extra_param_offset] // Lo(Source)
  647. mov dx, ss:[si + 4 + extra_param_offset] // Hi(Source)
  648. pushf
  649. cli
  650. xchg word [bx], ax
  651. xchg word [bx+2], dx
  652. popf
  653. {$if defined(FPC_X86_DATA_FAR) or defined(FPC_X86_DATA_HUGE)}
  654. mov ds, cx
  655. {$endif}
  656. end;
  657. function InterLockedExchangeAdd (var Target: smallint;Source : smallint) : smallint;nostackframe;assembler;
  658. asm
  659. mov si, sp
  660. {$ifdef FPC_X86_DATA_NEAR}
  661. mov bx, ss:[si + 4 + extra_param_offset] // Target
  662. {$else FPC_X86_DATA_NEAR}
  663. mov cx, ds
  664. lds bx, ss:[si + 4 + extra_param_offset] // Target
  665. {$endif FPC_X86_DATA_NEAR}
  666. mov di, ss:[si + 2 + extra_param_offset] // Source
  667. pushf
  668. cli
  669. mov ax, [bx]
  670. add word [bx], di
  671. popf
  672. {$if defined(FPC_X86_DATA_FAR) or defined(FPC_X86_DATA_HUGE)}
  673. mov ds, cx
  674. {$endif}
  675. end;
  676. function InterLockedExchangeAdd (var Target: longint;Source : longint) : longint;nostackframe;assembler;
  677. asm
  678. mov si, sp
  679. {$ifdef FPC_X86_DATA_NEAR}
  680. mov bx, ss:[si + 6 + extra_param_offset] // Target
  681. {$else FPC_X86_DATA_NEAR}
  682. mov cx, ds
  683. lds bx, ss:[si + 6 + extra_param_offset] // Target
  684. {$endif FPC_X86_DATA_NEAR}
  685. mov di, ss:[si + 2 + extra_param_offset] // Lo(Source)
  686. mov si, ss:[si + 4 + extra_param_offset] // Hi(Source)
  687. pushf
  688. cli
  689. mov ax, [bx]
  690. mov dx, [bx+2]
  691. add word [bx], di
  692. adc word [bx+2], si
  693. popf
  694. {$if defined(FPC_X86_DATA_FAR) or defined(FPC_X86_DATA_HUGE)}
  695. mov ds, cx
  696. {$endif}
  697. end;
  698. function InterlockedCompareExchange(var Target: smallint; NewValue: smallint; Comperand: smallint): smallint;assembler;
  699. asm
  700. {$ifdef FPC_X86_DATA_NEAR}
  701. mov bx, [Target] // Target
  702. {$else FPC_X86_DATA_NEAR}
  703. mov cx, ds
  704. lds bx, [Target] // Target
  705. {$endif FPC_X86_DATA_NEAR}
  706. mov di, [Comperand]
  707. pushf
  708. cli
  709. mov ax, [bx]
  710. cmp ax, di
  711. jne @@not_equal
  712. mov di, [NewValue]
  713. mov [bx], di
  714. @@not_equal:
  715. popf
  716. {$if defined(FPC_X86_DATA_FAR) or defined(FPC_X86_DATA_HUGE)}
  717. mov ds, cx
  718. {$endif}
  719. end;
  720. function InterlockedCompareExchange(var Target: longint; NewValue: longint; Comperand: longint): longint;assembler;
  721. asm
  722. {$ifdef FPC_X86_DATA_NEAR}
  723. mov bx, [Target] // Target
  724. {$else FPC_X86_DATA_NEAR}
  725. mov cx, ds
  726. lds bx, [Target] // Target
  727. {$endif FPC_X86_DATA_NEAR}
  728. mov di, word [Comperand]
  729. mov si, word [Comperand+2]
  730. pushf
  731. cli
  732. mov ax, [bx]
  733. mov dx, [bx+2]
  734. cmp ax, di
  735. jne @@not_equal
  736. cmp dx, si
  737. jne @@not_equal
  738. mov di, word [NewValue]
  739. mov si, word [NewValue+2]
  740. mov [bx], di
  741. mov [bx+2], si
  742. @@not_equal:
  743. popf
  744. {$if defined(FPC_X86_DATA_FAR) or defined(FPC_X86_DATA_HUGE)}
  745. mov ds, cx
  746. {$endif}
  747. end;
  748. {****************************************************************************
  749. Stack checking
  750. ****************************************************************************}
  751. procedure fpc_stackcheck_i8086;[public,alias:'FPC_STACKCHECK_I8086'];compilerproc;assembler;nostackframe;
  752. const
  753. STACK_MARGIN=512;
  754. asm
  755. { on entry: AX = required stack size to check if available
  756. (function is called before stack allocation) }
  757. {$ifdef FPC_MM_HUGE}
  758. push ds
  759. push ax
  760. mov ax, SEG @DATA
  761. mov ds, ax
  762. pop ax
  763. {$endif FPC_MM_HUGE}
  764. add ax, STACK_MARGIN
  765. jc @@stack_overflow
  766. add ax, word ptr [__stkbottom]
  767. jc @@stack_overflow
  768. cmp ax, sp
  769. ja @@stack_overflow
  770. @@no_overflow:
  771. {$ifdef FPC_MM_HUGE}
  772. pop ds
  773. {$endif FPC_MM_HUGE}
  774. ret
  775. @@stack_overflow:
  776. { check StackError flag, to avoid recursive calls from the exit routines }
  777. cmp byte ptr [StackError], 1
  778. je @@no_overflow
  779. mov byte ptr [StackError], 1
  780. { cleanup return address (and maybe saved ds) from call to this function }
  781. {$if defined(FPC_MM_HUGE)}
  782. add sp, 6
  783. {$elseif defined(FPC_X86_CODE_FAR)}
  784. pop ax
  785. pop ax
  786. {$else}
  787. pop ax
  788. {$endif}
  789. { call HandleError(202) }
  790. {$ifdef CPU8086}
  791. xor ax, ax
  792. push ax
  793. mov al, 202
  794. push ax
  795. {$else}
  796. push 0
  797. push 202
  798. {$endif}
  799. call HandleError
  800. end;
  801. {****************************************************************************
  802. BSR/BSF
  803. ****************************************************************************}
  804. const
  805. bsr8bit: array [Byte] of Byte = (
  806. $ff,0,1,1,2,2,2,2,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
  807. 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
  808. 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
  809. 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
  810. 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
  811. 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
  812. 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
  813. 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7
  814. );
  815. bsf8bit: array [Byte] of Byte = (
  816. $ff,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
  817. 5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
  818. 6,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
  819. 5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
  820. 7,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
  821. 5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
  822. 6,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
  823. 5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0
  824. );
  825. {$define FPC_SYSTEM_HAS_BSR_BYTE}
  826. function BsrByte(const AValue: Byte): Byte;
  827. begin
  828. BsrByte := bsr8bit[AValue];
  829. end;
  830. {$define FPC_SYSTEM_HAS_BSF_BYTE}
  831. function BsfByte(const AValue: Byte): Byte;
  832. begin
  833. BsfByte := bsf8bit[AValue];
  834. end;
  835. {$define FPC_SYSTEM_HAS_BSR_WORD}
  836. function BsrWord(const AValue: Word): Byte; assembler;
  837. asm
  838. lea bx, bsr8bit
  839. xor cl, cl
  840. mov ax, word [AValue]
  841. test ah, ah
  842. jz @@0
  843. mov cl, 8
  844. mov al, ah
  845. @@0: xlatb
  846. add al, cl
  847. end;
  848. {$define FPC_SYSTEM_HAS_BSF_WORD}
  849. function BsfWord(const AValue: Word): Byte; assembler;
  850. asm
  851. lea bx, bsf8bit
  852. xor cl, cl
  853. mov ax, word [AValue]
  854. test al, al
  855. jnz @@0
  856. or al, ah
  857. jz @@0
  858. add cl, 8
  859. @@0: xlatb
  860. add al, cl
  861. end;
  862. {$define FPC_SYSTEM_HAS_BSR_DWORD}
  863. function BsrDword(const AValue: DWord): Byte; assembler;
  864. asm
  865. lea bx, bsr8bit
  866. mov cl, 16
  867. mov ax, word [AValue+2]
  868. test ax, ax
  869. jnz @@0
  870. xor cl, cl
  871. mov ax, word [AValue]
  872. @@0: test ah, ah
  873. jz @@1
  874. add cl, 8
  875. mov al, ah
  876. @@1: xlatb
  877. add al, cl
  878. end;
  879. {$define FPC_SYSTEM_HAS_BSF_DWORD}
  880. function BsfDword(const AValue: DWord): Byte; assembler;
  881. asm
  882. lea bx, bsf8bit
  883. xor cl, cl
  884. mov ax, word [AValue]
  885. test ax, ax
  886. jnz @@0
  887. or ax, word [AValue+2]
  888. jz @@1
  889. mov cl, 16
  890. @@0: test al, al
  891. jnz @@1
  892. add cl, 8
  893. mov al, ah
  894. @@1: xlatb
  895. add al, cl
  896. end;
  897. {$define FPC_SYSTEM_HAS_BSR_QWORD}
  898. function BsrQword(const AValue: QWord): Byte; assembler;
  899. asm
  900. lea bx, bsr8bit
  901. mov cl, 48
  902. mov ax, word [AValue+6]
  903. test ax, ax
  904. jnz @@0
  905. mov cl, 32
  906. or ax, word [AValue+4]
  907. jnz @@0
  908. mov cl, 16
  909. or ax, word [AValue+2]
  910. jnz @@0
  911. xor cl, cl
  912. mov ax, word [AValue]
  913. @@0: test ah, ah
  914. jz @@1
  915. add cl, 8
  916. mov al, ah
  917. @@1: xlatb
  918. add al, cl
  919. end;
  920. {$define FPC_SYSTEM_HAS_BSF_QWORD}
  921. function BsfQword(const AValue: QWord): Byte; assembler;
  922. asm
  923. lea bx, bsf8bit
  924. xor cl, cl
  925. mov ax, word [AValue]
  926. test ax, ax
  927. jnz @@0
  928. mov cl, 16
  929. or ax, word [AValue+2]
  930. jnz @@0
  931. mov cl, 32
  932. or ax, word [AValue+4]
  933. jnz @@0
  934. xor cl, cl
  935. or ax, word [AValue+6]
  936. jz @@1
  937. mov cl, 48
  938. @@0: test al, al
  939. jnz @@1
  940. add cl, 8
  941. mov al, ah
  942. @@1: xlatb
  943. add al, cl
  944. end;
  945. {****************************************************************************
  946. HexStr
  947. ****************************************************************************}
  948. {$define FPC_HAS_HEXSTR_POINTER_SHORTSTR}
  949. function HexStr(Val: NearPointer): ShortString;
  950. begin
  951. HexStr:=HexStr(Word(Val),4);
  952. end;
  953. function HexStr(Val: FarPointer): ShortString;
  954. type
  955. TFarPointerRec = record
  956. Offset, Segment: Word;
  957. end;
  958. begin
  959. HexStr:=HexStr(TFarPointerRec(Val).Segment,4)+':'+HexStr(TFarPointerRec(Val).Offset,4);
  960. end;
  961. function HexStr(Val: HugePointer): ShortString;{$ifdef SYSTEMINLINE}inline;{$endif}
  962. begin
  963. HexStr:=HexStr(FarPointer(Val));
  964. end;
  965. {****************************************************************************
  966. FPU
  967. ****************************************************************************}
  968. const
  969. { Internal constants for use in system unit }
  970. FPU_Invalid = 1;
  971. FPU_Denormal = 2;
  972. FPU_DivisionByZero = 4;
  973. FPU_Overflow = 8;
  974. FPU_Underflow = $10;
  975. FPU_StackUnderflow = $20;
  976. FPU_StackOverflow = $40;
  977. FPU_ExceptionMask = $ff;
  978. { Detects the FPU and initializes the Test8087 variable (and Default8087CW):
  979. 0 = NO FPU
  980. 1 = 8087
  981. 2 = 80287
  982. 3 = 80387+ }
  983. procedure DetectFPU;
  984. var
  985. localfpucw: word;
  986. begin
  987. asm
  988. xor bx, bx { initialization, 0=NO FPU }
  989. { FPU presence detection }
  990. fninit
  991. mov byte [localfpucw + 1], 0
  992. nop
  993. fnstcw localfpucw
  994. cmp byte [localfpucw + 1], 3
  995. jne @@Done { No FPU? }
  996. inc bx
  997. { FPU found; now test if it's a 8087 }
  998. and byte [localfpucw], $7F { clear the interrupt enable mask (IEM) }
  999. fldcw localfpucw
  1000. fdisi { try to set the interrupt enable mask }
  1001. fstcw localfpucw
  1002. test byte [localfpucw], $80 { IEM set? }
  1003. jnz @@Done { if yes, we have an 8087 }
  1004. inc bx
  1005. { we have a 287+; now test if it's a 80287 }
  1006. finit
  1007. fld1
  1008. fldz
  1009. fdiv { calculate 1/0 }
  1010. fld st { copy the value }
  1011. fchs { change the sign }
  1012. fcompp { compare. if the FPU distinguishes +inf from -inf, it's a 387+ }
  1013. fstsw localfpucw
  1014. mov ah, byte [localfpucw + 1]
  1015. sahf
  1016. je @@Done
  1017. inc bx { 387+ }
  1018. @@Done:
  1019. mov Test8087, bl
  1020. end ['AX','BX'];
  1021. if Test8087<=2 then
  1022. Default8087CW:=$1330
  1023. else
  1024. Default8087CW:=$1332;
  1025. end;
  1026. {$ifndef FPC_SYSTEM_HAS_SYSINITFPU}
  1027. {$define FPC_SYSTEM_HAS_SYSINITFPU}
  1028. Procedure SysInitFPU;
  1029. var
  1030. { these locals are so we don't have to hack pic code in the assembler }
  1031. localfpucw: word;
  1032. begin
  1033. localfpucw:=Default8087CW;
  1034. asm
  1035. fninit
  1036. fldcw localfpucw
  1037. fwait
  1038. end;
  1039. end;
  1040. {$endif ndef FPC_SYSTEM_HAS_SYSINITFPU}
  1041. {$define FPC_SYSTEM_HAS_SYSRESETFPU}
  1042. Procedure SysResetFPU;
  1043. var
  1044. { these locals are so we don't have to hack pic code in the assembler }
  1045. localfpucw: word;
  1046. begin
  1047. localfpucw:=Default8087CW;
  1048. asm
  1049. fninit
  1050. fwait
  1051. fldcw localfpucw
  1052. end;
  1053. end;
  1054. {$I int32p.inc}
  1055. {$I hugeptr.inc}