cpubase.pas 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571
  1. {
  2. $Id$
  3. Copyright (c) 1998-2002 by Florian Klaempfl and Peter Vreman
  4. Contains the base types for the i386 and x86-64 architecture
  5. * This code was inspired by the NASM sources
  6. The Netwide Assembler is Copyright (c) 1996 Simon Tatham and
  7. Julian Hall. All rights reserved.
  8. This program is free software; you can redistribute it and/or modify
  9. it under the terms of the GNU General Public License as published by
  10. the Free Software Foundation; either version 2 of the License, or
  11. (at your option) any later version.
  12. This program is distributed in the hope that it will be useful,
  13. but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. GNU General Public License for more details.
  16. You should have received a copy of the GNU General Public License
  17. along with this program; if not, write to the Free Software
  18. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  19. ****************************************************************************
  20. }
  21. {# Base unit for processor information. This unit contains
  22. enumerations of registers, opcodes, sizes, and other
  23. such things which are processor specific.
  24. }
  25. unit cpubase;
  26. {$i fpcdefs.inc}
  27. interface
  28. uses
  29. cutils,cclasses,
  30. globtype,globals,
  31. cpuinfo,
  32. aasmbase,
  33. cgbase
  34. {$ifdef delphi}
  35. ,dmisc
  36. {$endif}
  37. ;
  38. {*****************************************************************************
  39. Assembler Opcodes
  40. *****************************************************************************}
  41. type
  42. {$ifdef x86_64}
  43. TAsmOp={$i x8664op.inc}
  44. {$else x86_64}
  45. TAsmOp={$i i386op.inc}
  46. {$endif x86_64}
  47. { This should define the array of instructions as string }
  48. op2strtable=array[tasmop] of string[11];
  49. const
  50. { First value of opcode enumeration }
  51. firstop = low(tasmop);
  52. { Last value of opcode enumeration }
  53. lastop = high(tasmop);
  54. {*****************************************************************************
  55. Registers
  56. *****************************************************************************}
  57. const
  58. { Invalid register number }
  59. RS_INVALID = $ff;
  60. { Integer Super registers }
  61. RS_RAX = $00; {EAX}
  62. RS_RCX = $01; {ECX}
  63. RS_RDX = $02; {EDX}
  64. RS_RBX = $03; {EBX}
  65. RS_RSI = $04; {ESI}
  66. RS_RDI = $05; {EDI}
  67. RS_RBP = $06; {EBP}
  68. RS_RSP = $07; {ESP}
  69. RS_R8 = $08; {R8}
  70. RS_R9 = $09; {R9}
  71. RS_R10 = $0a; {R10}
  72. RS_R11 = $0b; {R11}
  73. RS_R12 = $0c; {R12}
  74. RS_R13 = $0d; {R13}
  75. RS_R14 = $0e; {R14}
  76. RS_R15 = $0f; {R15}
  77. { create aliases to allow code sharing between x86-64 and i386 }
  78. RS_EAX = RS_RAX;
  79. RS_EBX = RS_RBX;
  80. RS_ECX = RS_RCX;
  81. RS_EDX = RS_RDX;
  82. RS_ESI = RS_RSI;
  83. RS_EDI = RS_RDI;
  84. RS_EBP = RS_RBP;
  85. RS_ESP = RS_RSP;
  86. { Number of first imaginary register }
  87. first_int_imreg = $10;
  88. { Float Super registers }
  89. RS_ST0 = $00;
  90. RS_ST1 = $01;
  91. RS_ST2 = $02;
  92. RS_ST3 = $03;
  93. RS_ST4 = $04;
  94. RS_ST5 = $05;
  95. RS_ST6 = $06;
  96. RS_ST7 = $07;
  97. { Number of first imaginary register }
  98. first_fpu_imreg = $08;
  99. { MM Super registers }
  100. RS_XMM0 = $00;
  101. RS_XMM1 = $01;
  102. RS_XMM2 = $02;
  103. RS_XMM3 = $03;
  104. RS_XMM4 = $04;
  105. RS_XMM5 = $05;
  106. RS_XMM6 = $06;
  107. RS_XMM7 = $07;
  108. RS_XMM8 = $08;
  109. RS_XMM9 = $09;
  110. RS_XMM10 = $0a;
  111. RS_XMM11 = $0b;
  112. RS_XMM12 = $0c;
  113. RS_XMM13 = $0d;
  114. RS_XMM14 = $0e;
  115. RS_XMM15 = $0f;
  116. { Number of first imaginary register }
  117. {$ifdef x86_64}
  118. first_mm_imreg = $10;
  119. {$else x86_64}
  120. first_mm_imreg = $08;
  121. {$endif x86_64}
  122. { The subregister that specifies the entire register }
  123. {$ifdef x86_64}
  124. R_SUBWHOLE = R_SUBQ; {Hammer}
  125. {$else x86_64}
  126. R_SUBWHOLE = R_SUBD; {i386}
  127. {$endif x86_64}
  128. { Available Registers }
  129. {$ifdef x86_64}
  130. {$i r8664con.inc}
  131. {$else x86_64}
  132. {$i r386con.inc}
  133. {$endif x86_64}
  134. type
  135. { Number of registers used for indexing in tables }
  136. {$ifdef x86_64}
  137. tregisterindex=0..{$i r8664nor.inc}-1;
  138. {$else x86_64}
  139. tregisterindex=0..{$i r386nor.inc}-1;
  140. {$endif x86_64}
  141. const
  142. {$warning TODO Calculate bsstart}
  143. regnumber_count_bsstart = 64;
  144. regnumber_table : array[tregisterindex] of tregister = (
  145. {$ifdef x86_64}
  146. {$i r8664num.inc}
  147. {$else x86_64}
  148. {$i r386num.inc}
  149. {$endif x86_64}
  150. );
  151. regstabs_table : array[tregisterindex] of shortint = (
  152. {$ifdef x86_64}
  153. {$i r8664stab.inc}
  154. {$else x86_64}
  155. {$i r386stab.inc}
  156. {$endif x86_64}
  157. );
  158. regdwarf_table : array[tregisterindex] of shortint = (
  159. {$ifdef x86_64}
  160. {$i r8664dwrf.inc}
  161. {$else x86_64}
  162. {$i r386dwrf.inc}
  163. {$endif x86_64}
  164. );
  165. type
  166. totherregisterset = set of tregisterindex;
  167. {*****************************************************************************
  168. Conditions
  169. *****************************************************************************}
  170. type
  171. TAsmCond=(C_None,
  172. C_A,C_AE,C_B,C_BE,C_C,C_E,C_G,C_GE,C_L,C_LE,C_NA,C_NAE,
  173. C_NB,C_NBE,C_NC,C_NE,C_NG,C_NGE,C_NL,C_NLE,C_NO,C_NP,
  174. C_NS,C_NZ,C_O,C_P,C_PE,C_PO,C_S,C_Z
  175. );
  176. const
  177. cond2str:array[TAsmCond] of string[3]=('',
  178. 'a','ae','b','be','c','e','g','ge','l','le','na','nae',
  179. 'nb','nbe','nc','ne','ng','nge','nl','nle','no','np',
  180. 'ns','nz','o','p','pe','po','s','z'
  181. );
  182. inverse_cond:array[TAsmCond] of TAsmCond=(C_None,
  183. C_NA,C_NAE,C_NB,C_NBE,C_NC,C_NE,C_NG,C_NGE,C_NL,C_NLE,C_A,C_AE,
  184. C_B,C_BE,C_C,C_E,C_G,C_GE,C_L,C_LE,C_O,C_P,
  185. C_S,C_Z,C_NO,C_NP,C_NP,C_P,C_NS,C_NZ
  186. );
  187. {*****************************************************************************
  188. Flags
  189. *****************************************************************************}
  190. type
  191. TResFlags = (F_E,F_NE,F_G,F_L,F_GE,F_LE,F_C,F_NC,
  192. F_A,F_AE,F_B,F_BE,
  193. F_S,F_NS,F_O,F_NO);
  194. {*****************************************************************************
  195. Reference
  196. *****************************************************************************}
  197. type
  198. { reference record, reordered for best alignment }
  199. preference = ^treference;
  200. treference = record
  201. offset : aint;
  202. symbol,
  203. relsymbol : tasmsymbol;
  204. segment,
  205. base,
  206. index : tregister;
  207. refaddr : trefaddr;
  208. scalefactor : byte;
  209. end;
  210. { reference record }
  211. pparareference = ^tparareference;
  212. tparareference = packed record
  213. index : tregister;
  214. offset : aint;
  215. end;
  216. {*****************************************************************************
  217. Generic Location
  218. *****************************************************************************}
  219. type
  220. { tparamlocation describes where a parameter for a procedure is stored.
  221. References are given from the caller's point of view. The usual
  222. TLocation isn't used, because contains a lot of unnessary fields.
  223. }
  224. tparalocation = record
  225. size : TCGSize;
  226. loc : TCGLoc;
  227. { Location type of registerhigh, for x86_64 this can
  228. be different from loc when pushing structures of 16 bytes }
  229. lochigh : TCGLoc;
  230. alignment : byte;
  231. case TCGLoc of
  232. LOC_REFERENCE : (reference : tparareference);
  233. { segment in reference at the same place as in loc_register }
  234. LOC_REGISTER,LOC_CREGISTER : (
  235. case longint of
  236. 1 : (register,registerhigh : tregister);
  237. { overlay a registerlow }
  238. 2 : (registerlow : tregister);
  239. {$ifndef cpu64bit}
  240. { overlay a 64 Bit register type }
  241. 3 : (register64 : tregister64);
  242. {$endif cpu64bit}
  243. );
  244. { it's only for better handling }
  245. LOC_MMXREGISTER,LOC_CMMXREGISTER : (
  246. case longint of
  247. 0: (mmxreg : tregister);
  248. 1: (mmxregset : Tregistermmxset);
  249. );
  250. end;
  251. tlocation = packed record
  252. loc : TCGLoc;
  253. size : TCGSize;
  254. case TCGLoc of
  255. LOC_FLAGS : (resflags : tresflags);
  256. LOC_CONSTANT : (
  257. case longint of
  258. 1 : (value : AInt);
  259. { can't do this, this layout depends on the host cpu. Use }
  260. { lo(valueqword)/hi(valueqword) instead (JM) }
  261. { overlay a complete 64 Bit value }
  262. 2 : (value64 : Int64);
  263. );
  264. LOC_CREFERENCE,
  265. LOC_REFERENCE : (reference : treference);
  266. { segment in reference at the same place as in loc_register }
  267. LOC_REGISTER,LOC_CREGISTER : (
  268. case longint of
  269. 1 : (register,registerhigh,segment : tregister);
  270. { overlay a registerlow }
  271. 2 : (registerlow : tregister);
  272. { overlay a 64 Bit register type }
  273. 3 : (reg64 : tregister64);
  274. 4 : (register64 : tregister64);
  275. );
  276. { it's only for better handling }
  277. LOC_MMXREGISTER,LOC_CMMXREGISTER : (mmxreg : tregister);
  278. end;
  279. {*****************************************************************************
  280. Constants
  281. *****************************************************************************}
  282. const
  283. { declare aliases }
  284. LOC_SSEREGISTER = LOC_MMREGISTER;
  285. LOC_CSSEREGISTER = LOC_CMMREGISTER;
  286. max_operands = 3;
  287. maxfpuregs = 8;
  288. {*****************************************************************************
  289. CPU Dependent Constants
  290. *****************************************************************************}
  291. {$i cpubase.inc}
  292. {*****************************************************************************
  293. Helpers
  294. *****************************************************************************}
  295. function cgsize2subreg(s:Tcgsize):Tsubregister;
  296. function reg2opsize(r:Tregister):topsize;
  297. function reg_cgsize(const reg: tregister): tcgsize;
  298. function is_calljmp(o:tasmop):boolean;
  299. procedure inverse_flags(var f: TResFlags);
  300. function flags_to_cond(const f: TResFlags) : TAsmCond;
  301. function is_segment_reg(r:tregister):boolean;
  302. function findreg_by_number(r:Tregister):tregisterindex;
  303. function std_regnum_search(const s:string):Tregister;
  304. function std_regname(r:Tregister):string;
  305. implementation
  306. uses
  307. rgbase,verbose;
  308. const
  309. {$ifdef x86_64}
  310. std_regname_table : array[tregisterindex] of string[7] = (
  311. {$i r8664std.inc}
  312. );
  313. regnumber_index : array[tregisterindex] of tregisterindex = (
  314. {$i r8664rni.inc}
  315. );
  316. std_regname_index : array[tregisterindex] of tregisterindex = (
  317. {$i r8664sri.inc}
  318. );
  319. {$else x86_64}
  320. std_regname_table : array[tregisterindex] of string[7] = (
  321. {$i r386std.inc}
  322. );
  323. regnumber_index : array[tregisterindex] of tregisterindex = (
  324. {$i r386rni.inc}
  325. );
  326. std_regname_index : array[tregisterindex] of tregisterindex = (
  327. {$i r386sri.inc}
  328. );
  329. {$endif x86_64}
  330. {*****************************************************************************
  331. Helpers
  332. *****************************************************************************}
  333. function cgsize2subreg(s:Tcgsize):Tsubregister;
  334. begin
  335. case s of
  336. OS_8,OS_S8:
  337. cgsize2subreg:=R_SUBL;
  338. OS_16,OS_S16:
  339. cgsize2subreg:=R_SUBW;
  340. OS_32,OS_S32:
  341. cgsize2subreg:=R_SUBD;
  342. OS_64,OS_S64:
  343. cgsize2subreg:=R_SUBQ;
  344. OS_M64:
  345. cgsize2subreg:=R_SUBNONE;
  346. OS_F32,OS_F64,OS_C64,
  347. OS_M128,OS_MS128:
  348. cgsize2subreg:=R_SUBWHOLE;
  349. else
  350. internalerror(200301231);
  351. end;
  352. end;
  353. function reg_cgsize(const reg: tregister): tcgsize;
  354. const subreg2cgsize:array[Tsubregister] of Tcgsize =
  355. (OS_NO,OS_8,OS_8,OS_16,OS_32,OS_64,OS_NO,OS_NO,OS_NO);
  356. begin
  357. case getregtype(reg) of
  358. R_INTREGISTER :
  359. reg_cgsize:=subreg2cgsize[getsubreg(reg)];
  360. R_FPUREGISTER :
  361. reg_cgsize:=OS_F80;
  362. R_MMXREGISTER:
  363. reg_cgsize:=OS_M64;
  364. R_MMREGISTER:
  365. reg_cgsize:=OS_M128;
  366. R_SPECIALREGISTER :
  367. case reg of
  368. NR_CS,NR_DS,NR_ES,NR_SS,NR_FS,NR_GS:
  369. reg_cgsize:=OS_16
  370. else
  371. reg_cgsize:=OS_32
  372. end
  373. else
  374. internalerror(200303181);
  375. end;
  376. end;
  377. function reg2opsize(r:Tregister):topsize;
  378. const
  379. subreg2opsize : array[tsubregister] of topsize =
  380. (S_NO,S_B,S_B,S_W,S_L,S_Q,S_NO,S_NO,S_NO);
  381. begin
  382. reg2opsize:=S_L;
  383. case getregtype(r) of
  384. R_INTREGISTER :
  385. reg2opsize:=subreg2opsize[getsubreg(r)];
  386. R_FPUREGISTER :
  387. reg2opsize:=S_FL;
  388. R_MMXREGISTER,
  389. R_MMREGISTER :
  390. reg2opsize:=S_MD;
  391. R_SPECIALREGISTER :
  392. begin
  393. case r of
  394. NR_CS,NR_DS,NR_ES,
  395. NR_SS,NR_FS,NR_GS :
  396. reg2opsize:=S_W;
  397. end;
  398. end;
  399. else
  400. internalerror(200303181);
  401. end;
  402. end;
  403. function is_calljmp(o:tasmop):boolean;
  404. begin
  405. case o of
  406. A_CALL,
  407. A_JCXZ,
  408. A_JECXZ,
  409. A_JMP,
  410. A_LOOP,
  411. A_LOOPE,
  412. A_LOOPNE,
  413. A_LOOPNZ,
  414. A_LOOPZ,
  415. A_Jcc :
  416. is_calljmp:=true;
  417. else
  418. is_calljmp:=false;
  419. end;
  420. end;
  421. procedure inverse_flags(var f: TResFlags);
  422. const
  423. inv_flags: array[TResFlags] of TResFlags =
  424. (F_NE,F_E,F_LE,F_GE,F_L,F_G,F_NC,F_C,
  425. F_BE,F_B,F_AE,F_A,
  426. F_NS,F_S,F_NO,F_O);
  427. begin
  428. f:=inv_flags[f];
  429. end;
  430. function flags_to_cond(const f: TResFlags) : TAsmCond;
  431. const
  432. flags_2_cond : array[TResFlags] of TAsmCond =
  433. (C_E,C_NE,C_G,C_L,C_GE,C_LE,C_C,C_NC,C_A,C_AE,C_B,C_BE,C_S,C_NS,C_O,C_NO);
  434. begin
  435. result := flags_2_cond[f];
  436. end;
  437. function is_segment_reg(r:tregister):boolean;
  438. begin
  439. result:=false;
  440. case r of
  441. NR_CS,NR_DS,NR_ES,
  442. NR_SS,NR_FS,NR_GS :
  443. result:=true;
  444. end;
  445. end;
  446. function findreg_by_number(r:Tregister):tregisterindex;
  447. begin
  448. result:=findreg_by_number_table(r,regnumber_index);
  449. end;
  450. function std_regnum_search(const s:string):Tregister;
  451. begin
  452. result:=regnumber_table[findreg_by_name_table(s,std_regname_table,std_regname_index)];
  453. end;
  454. function std_regname(r:Tregister):string;
  455. var
  456. p : tregisterindex;
  457. begin
  458. p:=findreg_by_number_table(r,regnumber_index);
  459. if p<>0 then
  460. result:=std_regname_table[p]
  461. else
  462. result:=generic_regname(r);
  463. end;
  464. end.
  465. {
  466. $Log$
  467. Revision 1.46 2004-08-24 21:23:11 florian
  468. * fixed i386 compilation
  469. Revision 1.45 2004/07/09 23:30:13 jonas
  470. * changed first_sse_imreg to first_mm_imreg
  471. Revision 1.44 2004/06/20 08:55:32 florian
  472. * logs truncated
  473. Revision 1.43 2004/06/16 20:07:11 florian
  474. * dwarf branch merged
  475. Revision 1.42.2.5 2004/05/28 20:29:50 florian
  476. * fixed currency trouble on x86-64
  477. Revision 1.42.2.4 2004/05/01 16:02:10 peter
  478. * POINTER_SIZE replaced with sizeof(aint)
  479. * aint,aword,tconst*int moved to globtype
  480. Revision 1.42.2.3 2004/05/01 11:12:24 florian
  481. * spilling of registers with size<>4 fixed
  482. Revision 1.42.2.2 2004/04/27 18:18:26 peter
  483. * aword -> aint
  484. }