diff options
Diffstat (limited to 'compiler/x86/cpubase.pas')
| -rw-r--r-- | compiler/x86/cpubase.pas | 471 |
1 files changed, 471 insertions, 0 deletions
diff --git a/compiler/x86/cpubase.pas b/compiler/x86/cpubase.pas new file mode 100644 index 0000000000..78d0ea11d6 --- /dev/null +++ b/compiler/x86/cpubase.pas @@ -0,0 +1,471 @@ +{ + Copyright (c) 1998-2002 by Florian Klaempfl and Peter Vreman + + Contains the base types for the i386 and x86-64 architecture + + * This code was inspired by the NASM sources + The Netwide Assembler is Copyright (c) 1996 Simon Tatham and + Julian Hall. All rights reserved. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + **************************************************************************** +} +{# Base unit for processor information. This unit contains + enumerations of registers, opcodes, sizes, and other + such things which are processor specific. +} +unit cpubase; + +{$i fpcdefs.inc} + +interface + +uses + cutils,cclasses, + globtype, + cgbase + ; + + +{***************************************************************************** + Assembler Opcodes +*****************************************************************************} + + type +{$ifdef x86_64} + TAsmOp={$i x8664op.inc} +{$else x86_64} + TAsmOp={$i i386op.inc} +{$endif x86_64} + + { This should define the array of instructions as string } + op2strtable=array[tasmop] of string[11]; + + const + { First value of opcode enumeration } + firstop = low(tasmop); + { Last value of opcode enumeration } + lastop = high(tasmop); + +{***************************************************************************** + Registers +*****************************************************************************} + + const + { Invalid register number } + RS_INVALID = $ff; + + { Integer Super registers } + RS_RAX = $00; {EAX} + RS_RCX = $01; {ECX} + RS_RDX = $02; {EDX} + RS_RBX = $03; {EBX} + RS_RSI = $04; {ESI} + RS_RDI = $05; {EDI} + RS_RBP = $06; {EBP} + RS_RSP = $07; {ESP} + RS_R8 = $08; {R8} + RS_R9 = $09; {R9} + RS_R10 = $0a; {R10} + RS_R11 = $0b; {R11} + RS_R12 = $0c; {R12} + RS_R13 = $0d; {R13} + RS_R14 = $0e; {R14} + RS_R15 = $0f; {R15} + { create aliases to allow code sharing between x86-64 and i386 } + RS_EAX = RS_RAX; + RS_EBX = RS_RBX; + RS_ECX = RS_RCX; + RS_EDX = RS_RDX; + RS_ESI = RS_RSI; + RS_EDI = RS_RDI; + RS_EBP = RS_RBP; + RS_ESP = RS_RSP; + + { Number of first imaginary register } + first_int_imreg = $10; + + { Float Super registers } + RS_ST0 = $00; + RS_ST1 = $01; + RS_ST2 = $02; + RS_ST3 = $03; + RS_ST4 = $04; + RS_ST5 = $05; + RS_ST6 = $06; + RS_ST7 = $07; + + { Number of first imaginary register } + first_fpu_imreg = $08; + + { MM Super registers } + RS_XMM0 = $00; + RS_XMM1 = $01; + RS_XMM2 = $02; + RS_XMM3 = $03; + RS_XMM4 = $04; + RS_XMM5 = $05; + RS_XMM6 = $06; + RS_XMM7 = $07; + RS_XMM8 = $08; + RS_XMM9 = $09; + RS_XMM10 = $0a; + RS_XMM11 = $0b; + RS_XMM12 = $0c; + RS_XMM13 = $0d; + RS_XMM14 = $0e; + RS_XMM15 = $0f; + + { Number of first imaginary register } +{$ifdef x86_64} + first_mm_imreg = $10; +{$else x86_64} + first_mm_imreg = $08; +{$endif x86_64} + + { The subregister that specifies the entire register } +{$ifdef x86_64} + R_SUBWHOLE = R_SUBQ; {Hammer} +{$else x86_64} + R_SUBWHOLE = R_SUBD; {i386} +{$endif x86_64} + + { Available Registers } +{$ifdef x86_64} + {$i r8664con.inc} +{$else x86_64} + {$i r386con.inc} +{$endif x86_64} + + type + { Number of registers used for indexing in tables } +{$ifdef x86_64} + tregisterindex=0..{$i r8664nor.inc}-1; +{$else x86_64} + tregisterindex=0..{$i r386nor.inc}-1; +{$endif x86_64} + + const +{$warning TODO Calculate bsstart} + regnumber_count_bsstart = 64; + + regnumber_table : array[tregisterindex] of tregister = ( +{$ifdef x86_64} + {$i r8664num.inc} +{$else x86_64} + {$i r386num.inc} +{$endif x86_64} + ); + + regstabs_table : array[tregisterindex] of shortint = ( +{$ifdef x86_64} + {$i r8664stab.inc} +{$else x86_64} + {$i r386stab.inc} +{$endif x86_64} + ); + + regdwarf_table : array[tregisterindex] of shortint = ( +{$ifdef x86_64} + {$i r8664dwrf.inc} +{$else x86_64} + {$i r386dwrf.inc} +{$endif x86_64} + ); + + type + totherregisterset = set of tregisterindex; + + +{***************************************************************************** + Conditions +*****************************************************************************} + + type + TAsmCond=(C_None, + C_A,C_AE,C_B,C_BE,C_C,C_E,C_G,C_GE,C_L,C_LE,C_NA,C_NAE, + C_NB,C_NBE,C_NC,C_NE,C_NG,C_NGE,C_NL,C_NLE,C_NO,C_NP, + C_NS,C_NZ,C_O,C_P,C_PE,C_PO,C_S,C_Z + ); + + const + cond2str:array[TAsmCond] of string[3]=('', + 'a','ae','b','be','c','e','g','ge','l','le','na','nae', + 'nb','nbe','nc','ne','ng','nge','nl','nle','no','np', + 'ns','nz','o','p','pe','po','s','z' + ); + +{***************************************************************************** + Flags +*****************************************************************************} + + type + 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, + F_S,F_NS,F_O,F_NO); + + +{***************************************************************************** + Constants +*****************************************************************************} + + const + { declare aliases } + LOC_SSEREGISTER = LOC_MMREGISTER; + LOC_CSSEREGISTER = LOC_CMMREGISTER; + + max_operands = 3; + maxfpuregs = 8; + +{***************************************************************************** + CPU Dependent Constants +*****************************************************************************} + + {$i cpubase.inc} + +{***************************************************************************** + Helpers +*****************************************************************************} + + function cgsize2subreg(s:Tcgsize):Tsubregister; + function reg2opsize(r:Tregister):topsize; + function reg_cgsize(const reg: tregister): tcgsize; + function is_calljmp(o:tasmop):boolean; + procedure inverse_flags(var f: TResFlags); + function flags_to_cond(const f: TResFlags) : TAsmCond; + function is_segment_reg(r:tregister):boolean; + function findreg_by_number(r:Tregister):tregisterindex; + function std_regnum_search(const s:string):Tregister; + function std_regname(r:Tregister):string; + + function inverse_cond(const c: TAsmCond): TAsmCond; {$ifdef USEINLINE}inline;{$endif USEINLINE} + function conditions_equal(const c1, c2: TAsmCond): boolean; {$ifdef USEINLINE}inline;{$endif USEINLINE} + +implementation + + uses + rgbase,verbose; + + const + {$ifdef x86_64} + std_regname_table : array[tregisterindex] of string[7] = ( + {$i r8664std.inc} + ); + + regnumber_index : array[tregisterindex] of tregisterindex = ( + {$i r8664rni.inc} + ); + std_regname_index : array[tregisterindex] of tregisterindex = ( + {$i r8664sri.inc} + ); + {$else x86_64} + std_regname_table : array[tregisterindex] of string[7] = ( + {$i r386std.inc} + ); + + regnumber_index : array[tregisterindex] of tregisterindex = ( + {$i r386rni.inc} + ); + + std_regname_index : array[tregisterindex] of tregisterindex = ( + {$i r386sri.inc} + ); + {$endif x86_64} + + +{***************************************************************************** + Helpers +*****************************************************************************} + + function cgsize2subreg(s:Tcgsize):Tsubregister; + begin + case s of + OS_8,OS_S8: + cgsize2subreg:=R_SUBL; + OS_16,OS_S16: + cgsize2subreg:=R_SUBW; + OS_32,OS_S32: + cgsize2subreg:=R_SUBD; + OS_64,OS_S64: + cgsize2subreg:=R_SUBQ; + OS_M64: + cgsize2subreg:=R_SUBNONE; + OS_F32,OS_F64,OS_C64, + OS_M128,OS_MS128: + cgsize2subreg:=R_SUBWHOLE; + else + internalerror(200301231); + end; + end; + + + function reg_cgsize(const reg: tregister): tcgsize; + const subreg2cgsize:array[Tsubregister] of Tcgsize = + (OS_NO,OS_8,OS_8,OS_16,OS_32,OS_64,OS_NO,OS_NO,OS_NO,OS_F32,OS_F64); + begin + case getregtype(reg) of + R_INTREGISTER : + reg_cgsize:=subreg2cgsize[getsubreg(reg)]; + R_FPUREGISTER : + reg_cgsize:=OS_F80; + R_MMXREGISTER: + reg_cgsize:=OS_M64; + R_MMREGISTER: + reg_cgsize:=subreg2cgsize[getsubreg(reg)]; + R_SPECIALREGISTER : + case reg of + NR_CS,NR_DS,NR_ES,NR_SS,NR_FS,NR_GS: + reg_cgsize:=OS_16 + else + reg_cgsize:=OS_32 + end + else + internalerror(200303181); + end; + end; + + + function reg2opsize(r:Tregister):topsize; + const + subreg2opsize : array[tsubregister] of topsize = + (S_NO,S_B,S_B,S_W,S_L,S_Q,S_NO,S_NO,S_NO,S_NO,S_NO); + begin + reg2opsize:=S_L; + case getregtype(r) of + R_INTREGISTER : + reg2opsize:=subreg2opsize[getsubreg(r)]; + R_FPUREGISTER : + reg2opsize:=S_FL; + R_MMXREGISTER, + R_MMREGISTER : + reg2opsize:=S_MD; + R_SPECIALREGISTER : + begin + case r of + NR_CS,NR_DS,NR_ES, + NR_SS,NR_FS,NR_GS : + reg2opsize:=S_W; + end; + end; + else + internalerror(200303181); + end; + end; + + + function is_calljmp(o:tasmop):boolean; + begin + case o of + A_CALL, + A_JCXZ, + A_JECXZ, + A_JMP, + A_LOOP, + A_LOOPE, + A_LOOPNE, + A_LOOPNZ, + A_LOOPZ, + A_Jcc : + is_calljmp:=true; + else + is_calljmp:=false; + end; + end; + + + procedure inverse_flags(var f: TResFlags); + const + inv_flags: array[TResFlags] of TResFlags = + (F_NE,F_E,F_LE,F_GE,F_L,F_G,F_NC,F_C, + F_BE,F_B,F_AE,F_A, + F_NS,F_S,F_NO,F_O); + begin + f:=inv_flags[f]; + end; + + + function flags_to_cond(const f: TResFlags) : TAsmCond; + const + flags_2_cond : array[TResFlags] of TAsmCond = + (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); + begin + result := flags_2_cond[f]; + end; + + + function is_segment_reg(r:tregister):boolean; + begin + result:=false; + case r of + NR_CS,NR_DS,NR_ES, + NR_SS,NR_FS,NR_GS : + result:=true; + end; + end; + + + function findreg_by_number(r:Tregister):tregisterindex; + var + hr : tregister; + begin + { for the name the sub reg doesn't matter } + hr:=r; + case getsubreg(hr) of + R_SUBMMS,R_SUBMMD: + setsubreg(hr,R_SUBNONE); + end; + result:=findreg_by_number_table(hr,regnumber_index); + end; + + + function std_regnum_search(const s:string):Tregister; + begin + result:=regnumber_table[findreg_by_name_table(s,std_regname_table,std_regname_index)]; + end; + + + function std_regname(r:Tregister):string; + var + p : tregisterindex; + begin + p:=findreg_by_number_table(r,regnumber_index); + if p<>0 then + result:=std_regname_table[p] + else + result:=generic_regname(r); + end; + + + function inverse_cond(const c: TAsmCond): TAsmCond; {$ifdef USEINLINE}inline;{$endif USEINLINE} + const + inverse: array[TAsmCond] of TAsmCond=(C_None, + C_NA,C_NAE,C_NB,C_NBE,C_NC,C_NE,C_NG,C_NGE,C_NL,C_NLE,C_A,C_AE, + C_B,C_BE,C_C,C_E,C_G,C_GE,C_L,C_LE,C_O,C_P, + C_S,C_Z,C_NO,C_NP,C_NP,C_P,C_NS,C_NZ + ); + begin + result := inverse[c]; + end; + + + function conditions_equal(const c1, c2: TAsmCond): boolean; {$ifdef USEINLINE}inline;{$endif USEINLINE} + begin + result := c1 = c2; + end; + + + +end. |
