cpubase.pas 31 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036
  1. {
  2. $Id$
  3. Copyright (c) 1998-2000 by Florian Klaempfl and Peter Vreman
  4. Contains the base types for the i386
  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. unit cpubase;
  22. {$i defines.inc}
  23. interface
  24. uses
  25. globals,cutils,cclasses,aasm;
  26. const
  27. { Size of the instruction table converted by nasmconv.pas }
  28. instabentries = {$i i386nop.inc}
  29. maxinfolen = 8;
  30. { By default we want everything }
  31. {$define ATTOP}
  32. {$define ATTREG}
  33. {$define INTELOP}
  34. {$define ITTABLE}
  35. { We Don't need the intel style opcodes if we don't have a intel
  36. reader or generator }
  37. {$ifdef NORA386INT}
  38. {$ifdef NOAG386NSM}
  39. {$ifdef NOAG386INT}
  40. {$undef INTELOP}
  41. {$endif}
  42. {$endif}
  43. {$endif}
  44. { We Don't need the AT&T style opcodes if we don't have a AT&T
  45. reader or generator }
  46. {$ifdef NORA386ATT}
  47. {$ifdef NOAG386ATT}
  48. {$undef ATTOP}
  49. {$ifdef NOAG386DIR}
  50. {$undef ATTREG}
  51. {$endif}
  52. {$endif}
  53. {$endif}
  54. { We need the AT&T suffix table for both asm readers and AT&T writer }
  55. {$define ATTSUF}
  56. {$ifdef NORA386INT}
  57. {$ifdef NORA386ATT}
  58. {$ifdef NOAG386ATT}
  59. {$undef ATTSUF}
  60. {$endif}
  61. {$endif}
  62. {$endif}
  63. const
  64. { Operand types }
  65. OT_NONE = $00000000;
  66. OT_BITS8 = $00000001; { size, and other attributes, of the operand }
  67. OT_BITS16 = $00000002;
  68. OT_BITS32 = $00000004;
  69. OT_BITS64 = $00000008; { FPU only }
  70. OT_BITS80 = $00000010;
  71. OT_FAR = $00000020; { this means 16:16 or 16:32, like in CALL/JMP }
  72. OT_NEAR = $00000040;
  73. OT_SHORT = $00000080;
  74. OT_SIZE_MASK = $000000FF; { all the size attributes }
  75. OT_NON_SIZE = longint(not OT_SIZE_MASK);
  76. OT_SIGNED = $00000100; { the operand need to be signed -128-127 }
  77. OT_TO = $00000200; { operand is followed by a colon }
  78. { reverse effect in FADD, FSUB &c }
  79. OT_COLON = $00000400;
  80. OT_REGISTER = $00001000;
  81. OT_IMMEDIATE = $00002000;
  82. OT_IMM8 = $00002001;
  83. OT_IMM16 = $00002002;
  84. OT_IMM32 = $00002004;
  85. OT_IMM64 = $00002008;
  86. OT_IMM80 = $00002010;
  87. OT_REGMEM = $00200000; { for r/m, ie EA, operands }
  88. OT_REGNORM = $00201000; { 'normal' reg, qualifies as EA }
  89. OT_REG8 = $00201001;
  90. OT_REG16 = $00201002;
  91. OT_REG32 = $00201004;
  92. OT_MMXREG = $00201008; { MMX registers }
  93. OT_XMMREG = $00201010; { Katmai registers }
  94. OT_MEMORY = $00204000; { register number in 'basereg' }
  95. OT_MEM8 = $00204001;
  96. OT_MEM16 = $00204002;
  97. OT_MEM32 = $00204004;
  98. OT_MEM64 = $00204008;
  99. OT_MEM80 = $00204010;
  100. OT_FPUREG = $01000000; { floating point stack registers }
  101. OT_FPU0 = $01000800; { FPU stack register zero }
  102. OT_REG_SMASK = $00070000; { special register operands: these may be treated differently }
  103. { a mask for the following }
  104. OT_REG_ACCUM = $00211000; { accumulator: AL, AX or EAX }
  105. OT_REG_AL = $00211001; { REG_ACCUM | BITSxx }
  106. OT_REG_AX = $00211002; { ditto }
  107. OT_REG_EAX = $00211004; { and again }
  108. OT_REG_COUNT = $00221000; { counter: CL, CX or ECX }
  109. OT_REG_CL = $00221001; { REG_COUNT | BITSxx }
  110. OT_REG_CX = $00221002; { ditto }
  111. OT_REG_ECX = $00221004; { another one }
  112. OT_REG_DX = $00241002;
  113. OT_REG_SREG = $00081002; { any segment register }
  114. OT_REG_CS = $01081002; { CS }
  115. OT_REG_DESS = $02081002; { DS, ES, SS (non-CS 86 registers) }
  116. OT_REG_FSGS = $04081002; { FS, GS (386 extended registers) }
  117. OT_REG_CDT = $00101004; { CRn, DRn and TRn }
  118. OT_REG_CREG = $08101004; { CRn }
  119. OT_REG_CR4 = $08101404; { CR4 (Pentium only) }
  120. OT_REG_DREG = $10101004; { DRn }
  121. OT_REG_TREG = $20101004; { TRn }
  122. OT_MEM_OFFS = $00604000; { special type of EA }
  123. { simple [address] offset }
  124. OT_ONENESS = $00800000; { special type of immediate operand }
  125. { so UNITY == IMMEDIATE | ONENESS }
  126. OT_UNITY = $00802000; { for shift/rotate instructions }
  127. {Instruction flags }
  128. IF_NONE = $00000000;
  129. IF_SM = $00000001; { size match first two operands }
  130. IF_SM2 = $00000002;
  131. IF_SB = $00000004; { unsized operands can't be non-byte }
  132. IF_SW = $00000008; { unsized operands can't be non-word }
  133. IF_SD = $00000010; { unsized operands can't be nondword }
  134. IF_AR0 = $00000020; { SB, SW, SD applies to argument 0 }
  135. IF_AR1 = $00000040; { SB, SW, SD applies to argument 1 }
  136. IF_AR2 = $00000060; { SB, SW, SD applies to argument 2 }
  137. IF_ARMASK = $00000060; { mask for unsized argument spec }
  138. IF_PRIV = $00000100; { it's a privileged instruction }
  139. IF_SMM = $00000200; { it's only valid in SMM }
  140. IF_PROT = $00000400; { it's protected mode only }
  141. IF_UNDOC = $00001000; { it's an undocumented instruction }
  142. IF_FPU = $00002000; { it's an FPU instruction }
  143. IF_MMX = $00004000; { it's an MMX instruction }
  144. IF_3DNOW = $00008000; { it's a 3DNow! instruction }
  145. IF_SSE = $00010000; { it's a SSE (KNI, MMX2) instruction }
  146. IF_PMASK =
  147. longint($FF000000); { the mask for processor types }
  148. IF_PFMASK =
  149. longint($F001FF00); { the mask for disassembly "prefer" }
  150. IF_8086 = $00000000; { 8086 instruction }
  151. IF_186 = $01000000; { 186+ instruction }
  152. IF_286 = $02000000; { 286+ instruction }
  153. IF_386 = $03000000; { 386+ instruction }
  154. IF_486 = $04000000; { 486+ instruction }
  155. IF_PENT = $05000000; { Pentium instruction }
  156. IF_P6 = $06000000; { P6 instruction }
  157. IF_KATMAI = $07000000; { Katmai instructions }
  158. IF_CYRIX = $10000000; { Cyrix-specific instruction }
  159. IF_AMD = $20000000; { AMD-specific instruction }
  160. { added flags }
  161. IF_PRE = $40000000; { it's a prefix instruction }
  162. IF_PASS2 =
  163. longint($80000000); { if the instruction can change in a second pass }
  164. type
  165. TAttSuffix = (AttSufNONE,AttSufINT,AttSufFPU,AttSufFPUint);
  166. TAsmOp=
  167. {$i i386op.inc}
  168. op2strtable=array[tasmop] of string[11];
  169. tstr2opentry = class(Tnamedindexitem)
  170. op: TAsmOp;
  171. end;
  172. const
  173. firstop = low(tasmop);
  174. lastop = high(tasmop);
  175. AsmPrefixes = 6;
  176. AsmPrefix : array[0..AsmPrefixes-1] of TasmOP =(
  177. A_LOCK,A_REP,A_REPE,A_REPNE,A_REPNZ,A_REPZ
  178. );
  179. AsmOverrides = 6;
  180. AsmOverride : array[0..AsmOverrides-1] of TasmOP =(
  181. A_SEGCS,A_SEGES,A_SEGDS,A_SEGFS,A_SEGGS,A_SEGSS
  182. );
  183. {$ifdef INTELOP}
  184. int_op2str:op2strtable=
  185. {$i i386int.inc}
  186. {$endif INTELOP}
  187. {$ifdef ATTOP}
  188. att_op2str:op2strtable=
  189. {$i i386att.inc}
  190. {$endif ATTOP}
  191. {$ifdef ATTSUF}
  192. att_needsuffix:array[tasmop] of TAttSuffix=
  193. {$i i386atts.inc}
  194. {$endif ATTSUF}
  195. {*****************************************************************************
  196. Operand Sizes
  197. *****************************************************************************}
  198. type
  199. topsize = (S_NO,
  200. S_B,S_W,S_L,S_BW,S_BL,S_WL,
  201. S_IS,S_IL,S_IQ,
  202. S_FS,S_FL,S_FX,S_D,S_Q,S_FV,
  203. S_NEAR,S_FAR,S_SHORT
  204. );
  205. const
  206. { Intel style operands ! }
  207. opsize_2_type:array[0..2,topsize] of longint=(
  208. (OT_NONE,
  209. OT_BITS8,OT_BITS16,OT_BITS32,OT_BITS16,OT_BITS32,OT_BITS32,
  210. OT_BITS16,OT_BITS32,OT_BITS64,
  211. OT_BITS32,OT_BITS64,OT_BITS80,OT_BITS64,OT_BITS64,OT_BITS64,
  212. OT_NEAR,OT_FAR,OT_SHORT
  213. ),
  214. (OT_NONE,
  215. OT_BITS8,OT_BITS16,OT_BITS32,OT_BITS8,OT_BITS8,OT_BITS16,
  216. OT_BITS16,OT_BITS32,OT_BITS64,
  217. OT_BITS32,OT_BITS64,OT_BITS80,OT_BITS64,OT_BITS64,OT_BITS64,
  218. OT_NEAR,OT_FAR,OT_SHORT
  219. ),
  220. (OT_NONE,
  221. OT_BITS8,OT_BITS16,OT_BITS32,OT_NONE,OT_NONE,OT_NONE,
  222. OT_BITS16,OT_BITS32,OT_BITS64,
  223. OT_BITS32,OT_BITS64,OT_BITS80,OT_BITS64,OT_BITS64,OT_BITS64,
  224. OT_NEAR,OT_FAR,OT_SHORT
  225. )
  226. );
  227. {$ifdef ATTOP}
  228. att_opsize2str : array[topsize] of string[2] = ('',
  229. 'b','w','l','bw','bl','wl',
  230. 's','l','q',
  231. 's','l','t','d','q','v',
  232. '','',''
  233. );
  234. {$endif}
  235. {*****************************************************************************
  236. Conditions
  237. *****************************************************************************}
  238. type
  239. TAsmCond=(C_None,
  240. C_A,C_AE,C_B,C_BE,C_C,C_E,C_G,C_GE,C_L,C_LE,C_NA,C_NAE,
  241. C_NB,C_NBE,C_NC,C_NE,C_NG,C_NGE,C_NL,C_NLE,C_NO,C_NP,
  242. C_NS,C_NZ,C_O,C_P,C_PE,C_PO,C_S,C_Z
  243. );
  244. const
  245. cond2str:array[TAsmCond] of string[3]=('',
  246. 'a','ae','b','be','c','e','g','ge','l','le','na','nae',
  247. 'nb','nbe','nc','ne','ng','nge','nl','nle','no','np',
  248. 'ns','nz','o','p','pe','po','s','z'
  249. );
  250. inverse_cond:array[TAsmCond] of TAsmCond=(C_None,
  251. C_NA,C_NAE,C_NB,C_NBE,C_NC,C_NE,C_NG,C_NGE,C_NL,C_NLE,C_A,C_AE,
  252. C_B,C_BE,C_C,C_E,C_G,C_GE,C_L,C_LE,C_O,C_P,
  253. C_S,C_Z,C_NO,C_NP,C_NP,C_P,C_NS,C_NZ
  254. );
  255. const
  256. CondAsmOps=3;
  257. CondAsmOp:array[0..CondAsmOps-1] of TasmOp=(
  258. A_CMOVcc, A_Jcc, A_SETcc
  259. );
  260. CondAsmOpStr:array[0..CondAsmOps-1] of string[4]=(
  261. 'CMOV','J','SET'
  262. );
  263. {*****************************************************************************
  264. Registers
  265. *****************************************************************************}
  266. type
  267. { enumeration for registers, don't change the order }
  268. { it's used by the register size conversions }
  269. tregister = (R_NO,
  270. R_EAX,R_ECX,R_EDX,R_EBX,R_ESP,R_EBP,R_ESI,R_EDI,
  271. R_AX,R_CX,R_DX,R_BX,R_SP,R_BP,R_SI,R_DI,
  272. R_AL,R_CL,R_DL,R_BL,R_AH,R_CH,R_BH,R_DH,
  273. R_CS,R_DS,R_ES,R_SS,R_FS,R_GS,
  274. R_ST,R_ST0,R_ST1,R_ST2,R_ST3,R_ST4,R_ST5,R_ST6,R_ST7,
  275. R_DR0,R_DR1,R_DR2,R_DR3,R_DR6,R_DR7,
  276. R_CR0,R_CR2,R_CR3,R_CR4,
  277. R_TR3,R_TR4,R_TR5,R_TR6,R_TR7,
  278. R_MM0,R_MM1,R_MM2,R_MM3,R_MM4,R_MM5,R_MM6,R_MM7,
  279. R_XMM0,R_XMM1,R_XMM2,R_XMM3,R_XMM4,R_XMM5,R_XMM6,R_XMM7
  280. );
  281. tregisterset = set of tregister;
  282. reg2strtable = array[tregister] of string[6];
  283. const
  284. firstreg = low(tregister);
  285. lastreg = high(tregister);
  286. firstsreg = R_CS;
  287. lastsreg = R_GS;
  288. regset8bit : tregisterset = [R_AL..R_DH];
  289. regset16bit : tregisterset = [R_AX..R_DI,R_CS..R_SS];
  290. regset32bit : tregisterset = [R_EAX..R_EDI];
  291. { Convert reg to opsize }
  292. reg_2_opsize:array[firstreg..lastreg] of topsize = (S_NO,
  293. S_L,S_L,S_L,S_L,S_L,S_L,S_L,S_L,
  294. S_W,S_W,S_W,S_W,S_W,S_W,S_W,S_W,
  295. S_B,S_B,S_B,S_B,S_B,S_B,S_B,S_B,
  296. S_W,S_W,S_W,S_W,S_W,S_W,
  297. S_FL,S_FL,S_FL,S_FL,S_FL,S_FL,S_FL,S_FL,S_FL,
  298. S_L,S_L,S_L,S_L,S_L,S_L,
  299. S_L,S_L,S_L,S_L,
  300. S_L,S_L,S_L,S_L,S_L,
  301. S_D,S_D,S_D,S_D,S_D,S_D,S_D,S_D,
  302. S_D,S_D,S_D,S_D,S_D,S_D,S_D,S_D
  303. );
  304. { Convert reg to operand type }
  305. reg_2_type:array[firstreg..lastreg] of longint = (OT_NONE,
  306. OT_REG_EAX,OT_REG_ECX,OT_REG32,OT_REG32,OT_REG32,OT_REG32,OT_REG32,OT_REG32,
  307. OT_REG_AX,OT_REG_CX,OT_REG_DX,OT_REG16,OT_REG16,OT_REG16,OT_REG16,OT_REG16,
  308. OT_REG_AL,OT_REG_CL,OT_REG8,OT_REG8,OT_REG8,OT_REG8,OT_REG8,OT_REG8,
  309. OT_REG_CS,OT_REG_DESS,OT_REG_DESS,OT_REG_DESS,OT_REG_FSGS,OT_REG_FSGS,
  310. OT_FPU0,OT_FPU0,OT_FPUREG,OT_FPUREG,OT_FPUREG,OT_FPUREG,OT_FPUREG,OT_FPUREG,OT_FPUREG,
  311. OT_REG_DREG,OT_REG_DREG,OT_REG_DREG,OT_REG_DREG,OT_REG_DREG,OT_REG_DREG,
  312. OT_REG_CREG,OT_REG_CREG,OT_REG_CREG,OT_REG_CR4,
  313. OT_REG_TREG,OT_REG_TREG,OT_REG_TREG,OT_REG_TREG,OT_REG_TREG,
  314. OT_MMXREG,OT_MMXREG,OT_MMXREG,OT_MMXREG,OT_MMXREG,OT_MMXREG,OT_MMXREG,OT_MMXREG,
  315. OT_XMMREG,OT_XMMREG,OT_XMMREG,OT_XMMREG,OT_XMMREG,OT_XMMREG,OT_XMMREG,OT_XMMREG
  316. );
  317. {$ifdef INTELOP}
  318. int_reg2str : reg2strtable = ('',
  319. 'eax','ecx','edx','ebx','esp','ebp','esi','edi',
  320. 'ax','cx','dx','bx','sp','bp','si','di',
  321. 'al','cl','dl','bl','ah','ch','bh','dh',
  322. 'cs','ds','es','ss','fs','gs',
  323. 'st','st(0)','st(1)','st(2)','st(3)','st(4)','st(5)','st(6)','st(7)',
  324. 'dr0','dr1','dr2','dr3','dr6','dr7',
  325. 'cr0','cr2','cr3','cr4',
  326. 'tr3','tr4','tr5','tr6','tr7',
  327. 'mm0','mm1','mm2','mm3','mm4','mm5','mm6','mm7',
  328. 'xmm0','xmm1','xmm2','xmm3','xmm4','xmm5','xmm6','xmm7'
  329. );
  330. int_nasmreg2str : reg2strtable = ('',
  331. 'eax','ecx','edx','ebx','esp','ebp','esi','edi',
  332. 'ax','cx','dx','bx','sp','bp','si','di',
  333. 'al','cl','dl','bl','ah','ch','bh','dh',
  334. 'cs','ds','es','ss','fs','gs',
  335. 'st0','st0','st1','st2','st3','st4','st5','st6','st7',
  336. 'dr0','dr1','dr2','dr3','dr6','dr7',
  337. 'cr0','cr2','cr3','cr4',
  338. 'tr3','tr4','tr5','tr6','tr7',
  339. 'mm0','mm1','mm2','mm3','mm4','mm5','mm6','mm7',
  340. 'xmm0','xmm1','xmm2','xmm3','xmm4','xmm5','xmm6','xmm7'
  341. );
  342. {$endif}
  343. {$ifdef ATTREG}
  344. att_reg2str : reg2strtable = ('',
  345. '%eax','%ecx','%edx','%ebx','%esp','%ebp','%esi','%edi',
  346. '%ax','%cx','%dx','%bx','%sp','%bp','%si','%di',
  347. '%al','%cl','%dl','%bl','%ah','%ch','%bh','%dh',
  348. '%cs','%ds','%es','%ss','%fs','%gs',
  349. '%st','%st(0)','%st(1)','%st(2)','%st(3)','%st(4)','%st(5)','%st(6)','%st(7)',
  350. '%dr0','%dr1','%dr2','%dr3','%dr6','%dr7',
  351. '%cr0','%cr2','%cr3','%cr4',
  352. '%tr3','%tr4','%tr5','%tr6','%tr7',
  353. '%mm0','%mm1','%mm2','%mm3','%mm4','%mm5','%mm6','%mm7',
  354. '%xmm0','%xmm1','%xmm2','%xmm3','%xmm4','%xmm5','%xmm6','%xmm7'
  355. );
  356. {$endif ATTREG}
  357. {*****************************************************************************
  358. Flags
  359. *****************************************************************************}
  360. type
  361. TResFlags = (F_E,F_NE,F_G,F_L,F_GE,F_LE,F_C,F_NC,F_A,F_AE,F_B,F_BE);
  362. {*****************************************************************************
  363. Reference
  364. *****************************************************************************}
  365. type
  366. trefoptions=(ref_none,ref_parafixup,ref_localfixup,ref_selffixup);
  367. { immediate/reference record }
  368. preference = ^treference;
  369. treference = packed record
  370. is_immediate : boolean; { is this used as reference or immediate }
  371. segment,
  372. base,
  373. index : tregister;
  374. scalefactor : byte;
  375. offset : longint;
  376. symbol : tasmsymbol;
  377. offsetfixup : longint;
  378. options : trefoptions;
  379. {$ifdef newcg}
  380. alignment : byte;
  381. {$endif newcg}
  382. end;
  383. {*****************************************************************************
  384. Operands
  385. *****************************************************************************}
  386. { Types of operand }
  387. toptype=(top_none,top_reg,top_ref,top_const,top_symbol);
  388. toper=record
  389. ot : longint;
  390. case typ : toptype of
  391. top_none : ();
  392. top_reg : (reg:tregister);
  393. top_ref : (ref:preference);
  394. top_const : (val:longint);
  395. top_symbol : (sym:tasmsymbol;symofs:longint);
  396. end;
  397. {*****************************************************************************
  398. Argument Classification
  399. *****************************************************************************}
  400. type
  401. TArgClass = (
  402. { the following classes should be defined by all processor implemnations }
  403. AC_NOCLASS,
  404. AC_MEMORY,
  405. AC_INTEGER,
  406. AC_FPU,
  407. { the following argument classes are i386 specific }
  408. AC_FPUUP,
  409. AC_SSE,
  410. AC_SSEUP);
  411. {*****************************************************************************
  412. Generic Location
  413. *****************************************************************************}
  414. type
  415. TLoc=(
  416. LOC_INVALID, { added for tracking problems}
  417. LOC_FPU, { FPU stack }
  418. LOC_REGISTER, { in a processor register }
  419. LOC_MEM, { in memory }
  420. LOC_REFERENCE, { like LOC_MEM, but lvalue }
  421. LOC_JUMP, { boolean results only, jump to false or true label }
  422. LOC_FLAGS, { boolean results only, flags are set }
  423. LOC_CREGISTER, { Constant register which shouldn't be modified }
  424. LOC_MMXREGISTER, { MMX register }
  425. LOC_CMMXREGISTER, { MMX register variable }
  426. LOC_CFPUREGISTER, { if it is a FPU register variable on the fpu stack }
  427. LOC_SSEREGISTER,
  428. LOC_CSSEREGISTER
  429. );
  430. plocation = ^tlocation;
  431. tlocation = packed record
  432. case loc : tloc of
  433. LOC_MEM,LOC_REFERENCE : (reference : treference);
  434. LOC_FPU : ();
  435. LOC_JUMP : ();
  436. LOC_FLAGS : (resflags : tresflags);
  437. LOC_INVALID : ();
  438. { it's only for better handling }
  439. LOC_MMXREGISTER : (mmxreg : tregister);
  440. { segment in reference at the same place as in loc_register }
  441. LOC_REGISTER,LOC_CREGISTER : (
  442. case longint of
  443. 1 : (register,segment,registerhigh : tregister);
  444. { overlay a registerlow }
  445. 2 : (registerlow : tregister);
  446. );
  447. end;
  448. {*****************************************************************************
  449. Constants
  450. *****************************************************************************}
  451. const
  452. general_registers = [R_EAX,R_EBX,R_ECX,R_EDX];
  453. intregs = general_registers;
  454. fpuregs = [];
  455. mmregs = [R_MM0..R_MM7];
  456. lvaluelocations = [LOC_REFERENCE,LOC_CFPUREGISTER,
  457. LOC_CREGISTER,LOC_MMXREGISTER,LOC_CMMXREGISTER];
  458. registers_saved_on_cdecl = [R_ESI,R_EDI,R_EBX];
  459. { generic register names }
  460. stack_pointer = R_ESP;
  461. frame_pointer = R_EBP;
  462. self_pointer = R_ESI;
  463. accumulator = R_EAX;
  464. accumulatorhigh = R_EDX;
  465. { the register where the vmt offset is passed to the destructor }
  466. { helper routine }
  467. vmt_offset_reg = R_EDI;
  468. scratch_regs : array[1..1] of tregister = (R_EDI);
  469. { low and high of the available maximum width integer general purpose }
  470. { registers }
  471. LoGPReg = R_EAX;
  472. HiGPReg = R_EDI;
  473. { low and high of every possible width general purpose register (same as }
  474. { above on most architctures apart from the 80x86) }
  475. LoReg = R_EAX;
  476. HiReg = R_BL;
  477. cpuflags = [];
  478. { sizes }
  479. pointersize = 4;
  480. extended_size = 10;
  481. sizepostfix_pointer = S_L;
  482. {*****************************************************************************
  483. Instruction table
  484. *****************************************************************************}
  485. {$ifndef NOAG386BIN}
  486. type
  487. tinsentry=packed record
  488. opcode : tasmop;
  489. ops : byte;
  490. optypes : array[0..2] of longint;
  491. code : array[0..maxinfolen] of char;
  492. flags : longint;
  493. end;
  494. pinsentry=^tinsentry;
  495. TInsTabCache=array[TasmOp] of longint;
  496. PInsTabCache=^TInsTabCache;
  497. const
  498. InsTab:array[0..instabentries-1] of TInsEntry=
  499. {$i i386tab.inc}
  500. var
  501. InsTabCache : PInsTabCache;
  502. {$endif NOAG386BIN}
  503. {*****************************************************************************
  504. Opcode propeties (needed for optimizer)
  505. *****************************************************************************}
  506. {$ifndef NOOPT}
  507. Type
  508. {What an instruction can change}
  509. TInsChange = (Ch_None,
  510. {Read from a register}
  511. Ch_REAX, Ch_RECX, Ch_REDX, Ch_REBX, Ch_RESP, Ch_REBP, Ch_RESI, Ch_REDI,
  512. {write from a register}
  513. Ch_WEAX, Ch_WECX, Ch_WEDX, Ch_WEBX, Ch_WESP, Ch_WEBP, Ch_WESI, Ch_WEDI,
  514. {read and write from/to a register}
  515. Ch_RWEAX, Ch_RWECX, Ch_RWEDX, Ch_RWEBX, Ch_RWESP, Ch_RWEBP, Ch_RWESI, Ch_RWEDI,
  516. {modify the contents of a register with the purpose of using
  517. this changed content afterwards (add/sub/..., but e.g. not rep
  518. or movsd)}
  519. Ch_MEAX, Ch_MECX, Ch_MEDX, Ch_MEBX, Ch_MESP, Ch_MEBP, Ch_MESI, Ch_MEDI,
  520. Ch_CDirFlag {clear direction flag}, Ch_SDirFlag {set dir flag},
  521. Ch_RFlags, Ch_WFlags, Ch_RWFlags, Ch_FPU,
  522. Ch_Rop1, Ch_Wop1, Ch_RWop1,Ch_Mop1,
  523. Ch_Rop2, Ch_Wop2, Ch_RWop2,Ch_Mop2,
  524. Ch_Rop3, Ch_WOp3, Ch_RWOp3,Ch_Mop3,
  525. Ch_WMemEDI,
  526. Ch_All
  527. );
  528. const
  529. MaxCh = 3; { Max things a instruction can change }
  530. type
  531. TInsProp = packed record
  532. Ch : Array[1..MaxCh] of TInsChange;
  533. end;
  534. const
  535. InsProp : array[tasmop] of TInsProp =
  536. {$i i386prop.inc}
  537. {$endif NOOPT}
  538. {*****************************************************************************
  539. Init/Done
  540. *****************************************************************************}
  541. procedure InitCpu;
  542. procedure DoneCpu;
  543. {*****************************************************************************
  544. Helpers
  545. *****************************************************************************}
  546. const
  547. maxvarregs = 4;
  548. varregs : array[1..maxvarregs] of tregister =
  549. (R_EBX,R_EDX,R_ECX,R_EAX);
  550. maxfpuvarregs = 8;
  551. max_operands = 3;
  552. maxintregs = maxvarregs;
  553. maxfpuregs = maxfpuvarregs;
  554. function imm_2_type(l:longint):longint;
  555. { the following functions allow to convert registers }
  556. { for example reg8toreg32(R_AL) returns R_EAX }
  557. { for example reg16toreg32(R_AL) gives an undefined }
  558. { result }
  559. { these functions expects that the turn of }
  560. { tregister isn't changed }
  561. function reg8toreg16(reg : tregister) : tregister;
  562. function reg8toreg32(reg : tregister) : tregister;
  563. function reg16toreg8(reg : tregister) : tregister;
  564. function reg32toreg8(reg : tregister) : tregister;
  565. function reg32toreg16(reg : tregister) : tregister;
  566. function reg16toreg32(reg : tregister) : tregister;
  567. { these procedures must be defined by all target cpus }
  568. function regtoreg8(reg : tregister) : tregister;
  569. function regtoreg16(reg : tregister) : tregister;
  570. function regtoreg32(reg : tregister) : tregister;
  571. { can be ignored on 32 bit systems }
  572. function regtoreg64(reg : tregister) : tregister;
  573. { returns the operand prefix for a given register }
  574. function regsize(reg : tregister) : topsize;
  575. { resets all values of ref to defaults }
  576. procedure reset_reference(var ref : treference);
  577. { set mostly used values of a new reference }
  578. function new_reference(base : tregister;offset : longint) : preference;
  579. function newreference(const r : treference) : preference;
  580. procedure disposereference(var r : preference);
  581. function reg2str(r : tregister) : string;
  582. function is_calljmp(o:tasmop):boolean;
  583. procedure clear_location(var loc : tlocation);
  584. procedure set_location(var destloc,sourceloc : tlocation);
  585. procedure swap_location(var destloc,sourceloc : tlocation);
  586. procedure inverse_flags(var f: TResFlags);
  587. function flags_to_cond(const f: TResFlags) : TAsmCond;
  588. implementation
  589. {$ifdef heaptrc}
  590. uses
  591. ppheap;
  592. {$endif heaptrc}
  593. {*****************************************************************************
  594. Helpers
  595. *****************************************************************************}
  596. function imm_2_type(l:longint):longint;
  597. begin
  598. if (l>=-128) and (l<=127) then
  599. imm_2_type:=OT_IMM8 or OT_SIGNED
  600. else
  601. if (l>=-255) and (l<=255) then
  602. imm_2_type:=OT_IMM8
  603. else
  604. if (l>=-32768) and (l<=32767) then
  605. imm_2_type:=OT_IMM16 or OT_SIGNED
  606. else
  607. if (l>=-65536) and (l<=65535) then
  608. imm_2_type:=OT_IMM16 or OT_SIGNED
  609. else
  610. imm_2_type:=OT_IMM32;
  611. end;
  612. function reg2str(r : tregister) : string;
  613. const
  614. a : array[R_NO..R_BL] of string[3] =
  615. ('','EAX','ECX','EDX','EBX','ESP','EBP','ESI','EDI',
  616. 'AX','CX','DX','BX','SP','BP','SI','DI',
  617. 'AL','CL','DL','BL');
  618. begin
  619. if r in [R_ST0..R_ST7] then
  620. reg2str:='ST('+tostr(longint(r)-longint(R_ST0))+')'
  621. else
  622. reg2str:=a[r];
  623. end;
  624. function is_calljmp(o:tasmop):boolean;
  625. begin
  626. case o of
  627. A_CALL,
  628. A_JCXZ,
  629. A_JECXZ,
  630. A_JMP,
  631. A_LOOP,
  632. A_LOOPE,
  633. A_LOOPNE,
  634. A_LOOPNZ,
  635. A_LOOPZ,
  636. A_Jcc :
  637. is_calljmp:=true;
  638. else
  639. is_calljmp:=false;
  640. end;
  641. end;
  642. procedure disposereference(var r : preference);
  643. begin
  644. dispose(r);
  645. r:=nil;
  646. end;
  647. function newreference(const r : treference) : preference;
  648. var
  649. p : preference;
  650. begin
  651. new(p);
  652. p^:=r;
  653. newreference:=p;
  654. end;
  655. function reg8toreg16(reg : tregister) : tregister;
  656. begin
  657. reg8toreg16:=reg32toreg16(reg8toreg32(reg));
  658. end;
  659. function reg16toreg8(reg : tregister) : tregister;
  660. begin
  661. reg16toreg8:=reg32toreg8(reg16toreg32(reg));
  662. end;
  663. function reg16toreg32(reg : tregister) : tregister;
  664. begin
  665. reg16toreg32:=tregister(byte(reg)-byte(R_EDI));
  666. end;
  667. function reg32toreg16(reg : tregister) : tregister;
  668. begin
  669. reg32toreg16:=tregister(byte(reg)+byte(R_EDI));
  670. end;
  671. function reg32toreg8(reg : tregister) : tregister;
  672. begin
  673. reg32toreg8:=tregister(byte(reg)+byte(R_DI));
  674. end;
  675. function reg8toreg32(reg : tregister) : tregister;
  676. begin
  677. reg8toreg32:=tregister(byte(reg)-byte(R_DI));
  678. end;
  679. function regtoreg8(reg : tregister) : tregister;
  680. begin
  681. regtoreg8:=reg32toreg8(reg);
  682. end;
  683. function regtoreg16(reg : tregister) : tregister;
  684. begin
  685. regtoreg16:=reg32toreg16(reg);
  686. end;
  687. function regtoreg32(reg : tregister) : tregister;
  688. begin
  689. regtoreg32:=reg;
  690. end;
  691. function regtoreg64(reg : tregister) : tregister;
  692. begin
  693. { to avoid warning }
  694. regtoreg64:=R_NO;
  695. end;
  696. function regsize(reg : tregister) : topsize;
  697. begin
  698. if reg in regset8bit then
  699. regsize:=S_B
  700. else if reg in regset16bit then
  701. regsize:=S_W
  702. else if reg in regset32bit then
  703. regsize:=S_L;
  704. end;
  705. procedure reset_reference(var ref : treference);
  706. begin
  707. FillChar(ref,sizeof(treference),0);
  708. end;
  709. function new_reference(base : tregister;offset : longint) : preference;
  710. var
  711. r : preference;
  712. begin
  713. new(r);
  714. FillChar(r^,sizeof(treference),0);
  715. r^.base:=base;
  716. r^.offset:=offset;
  717. new_reference:=r;
  718. end;
  719. procedure clear_location(var loc : tlocation);
  720. begin
  721. loc.loc:=LOC_INVALID;
  722. end;
  723. {This is needed if you want to be able to delete the string with the nodes !!}
  724. procedure set_location(var destloc,sourceloc : tlocation);
  725. begin
  726. destloc:= sourceloc;
  727. end;
  728. procedure swap_location(var destloc,sourceloc : tlocation);
  729. var
  730. swapl : tlocation;
  731. begin
  732. swapl := destloc;
  733. destloc := sourceloc;
  734. sourceloc := swapl;
  735. end;
  736. {*****************************************************************************
  737. Instruction table
  738. *****************************************************************************}
  739. procedure DoneCpu;
  740. begin
  741. {exitproc:=saveexit; }
  742. {$ifndef NOAG386BIN}
  743. if assigned(instabcache) then
  744. dispose(instabcache);
  745. {$endif NOAG386BIN}
  746. end;
  747. procedure BuildInsTabCache;
  748. {$ifndef NOAG386BIN}
  749. var
  750. i : longint;
  751. {$endif}
  752. begin
  753. {$ifndef NOAG386BIN}
  754. new(instabcache);
  755. FillChar(instabcache^,sizeof(tinstabcache),$ff);
  756. i:=0;
  757. while (i<InsTabEntries) do
  758. begin
  759. if InsTabCache^[InsTab[i].OPcode]=-1 then
  760. InsTabCache^[InsTab[i].OPcode]:=i;
  761. inc(i);
  762. end;
  763. {$endif NOAG386BIN}
  764. end;
  765. procedure inverse_flags(var f: TResFlags);
  766. const
  767. flagsinvers : array[F_E..F_BE] of tresflags =
  768. (F_NE,F_E,F_LE,F_GE,F_L,F_G,F_NC,F_C,
  769. F_BE,F_B,F_AE,F_A);
  770. begin
  771. f := flagsinvers[f];
  772. end;
  773. function flags_to_cond(const f: TResFlags) : TAsmCond;
  774. const
  775. flags_2_cond : array[TResFlags] of TAsmCond =
  776. (C_E,C_NE,C_G,C_L,C_GE,C_LE,C_C,C_NC,C_A,C_AE,C_B,C_BE);
  777. begin
  778. result := flags_2_cond[f];
  779. end;
  780. procedure InitCpu;
  781. begin
  782. {$ifndef NOAG386BIN}
  783. if not assigned(instabcache) then
  784. BuildInsTabCache;
  785. {$endif NOAG386BIN}
  786. end;
  787. end.
  788. {
  789. $Log$
  790. Revision 1.10 2002-03-04 19:10:12 peter
  791. * removed compiler warnings
  792. Revision 1.9 2001/12/30 17:24:46 jonas
  793. * range checking is now processor independent (part in cgobj,
  794. part in cg64f32) and should work correctly again (it needed
  795. some changes after the changes of the low and high of
  796. tordef's to int64)
  797. * maketojumpbool() is now processor independent (in ncgutil)
  798. * getregister32 is now called getregisterint
  799. Revision 1.8 2001/12/29 15:29:59 jonas
  800. * powerpc/cgcpu.pas compiles :)
  801. * several powerpc-related fixes
  802. * cpuasm unit is now based on common tainst unit
  803. + nppcmat unit for powerpc (almost complete)
  804. Revision 1.7 2001/12/06 17:57:40 florian
  805. + parasym to tparaitem added
  806. Revision 1.6 2001/09/28 20:39:33 jonas
  807. * changed all flow control structures (except for exception handling
  808. related things) to processor independent code (in new ncgflw unit)
  809. + generic cgobj unit which contains lots of code generator helpers with
  810. global "cg" class instance variable
  811. + cgcpu unit for i386 (implements processor specific routines of the above
  812. unit)
  813. * updated cgbase and cpubase for the new code generator units
  814. * include ncgflw unit in cpunode unit
  815. Revision 1.5 2001/05/18 23:01:13 peter
  816. * portable constants
  817. Revision 1.4 2001/04/13 01:22:18 peter
  818. * symtable change to classes
  819. * range check generation and errors fixed, make cycle DEBUG=1 works
  820. * memory leaks fixed
  821. Revision 1.3 2001/02/20 21:34:04 peter
  822. * iret, lret fixes
  823. Revision 1.2 2000/12/07 17:19:45 jonas
  824. * new constant handling: from now on, hex constants >$7fffffff are
  825. parsed as unsigned constants (otherwise, $80000000 got sign extended
  826. and became $ffffffff80000000), all constants in the longint range
  827. become longints, all constants >$7fffffff and <=cardinal($ffffffff)
  828. are cardinals and the rest are int64's.
  829. * added lots of longint typecast to prevent range check errors in the
  830. compiler and rtl
  831. * type casts of symbolic ordinal constants are now preserved
  832. * fixed bug where the original resulttype wasn't restored correctly
  833. after doing a 64bit rangecheck
  834. Revision 1.1 2000/10/15 09:39:37 peter
  835. * moved cpu*.pas to i386/
  836. * renamed n386 to common cpunode
  837. Revision 1.7 2000/09/26 20:06:13 florian
  838. * hmm, still a lot of work to get things compilable
  839. Revision 1.6 2000/09/24 15:06:14 peter
  840. * use defines.inc
  841. Revision 1.5 2000/08/27 16:11:50 peter
  842. * moved some util functions from globals,cobjects to cutils
  843. * splitted files into finput,fmodule
  844. Revision 1.4 2000/08/05 13:25:06 peter
  845. * packenum 1 fixes (merged)
  846. Revision 1.3 2000/07/14 05:11:48 michael
  847. + Patch to 1.1
  848. Revision 1.2 2000/07/13 11:32:39 michael
  849. + removed logs
  850. }