1 { 2 Copyright (c) 1998-2002 by Florian Klaempfl 3 4 Contains the base types for the SPARC 5 6 This program is free software; you can redistribute it and/or modify 7 it under the terms of the GNU General Public License as published by 8 the Free Software Foundation; either version 2 of the License, or 9 (at your option) any later version. 10 11 This program is distributed in the hope that it will be useful, 12 but WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 GNU General Public License for more details. 15 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 } 22 unit cpubase; 23 24 {$i fpcdefs.inc} 25 26 {$ModeSwitch advancedrecords} 27 28 interface 29 30 uses 31 globtype,strings,cutils,cclasses,aasmbase,cpuinfo,cgbase; 32 33 34 {***************************************************************************** 35 Assembler Opcodes 36 *****************************************************************************} 37 38 type 39 { TODO: CPU32 opcodes do not fully include the Ultra SPRAC instruction set.} 40 { don't change the order of these opcodes! } 41 TAsmOp=({$i opcode.inc}); 42 43 {# This should define the array of instructions as string } 44 op2strtable=array[tasmop] of string[11]; 45 46 Const 47 {# First value of opcode enumeration } 48 firstop = low(tasmop); 49 {# Last value of opcode enumeration } 50 lastop = high(tasmop); 51 52 std_op2str:op2strtable=({$i strinst.inc}); 53 54 {***************************************************************************** 55 Registers 56 *****************************************************************************} 57 58 {$ifdef SPARC} 59 type 60 { Number of registers used for indexing in tables } 61 tregisterindex=0..{$i rspnor.inc}-1; 62 totherregisterset = set of tregisterindex; 63 64 const 65 { Available Superregisters } 66 {$i rspsup.inc} 67 68 { No Subregisters } 69 R_SUBWHOLE = R_SUBNONE; 70 71 { Available Registers } 72 {$i rspcon.inc} 73 74 first_int_imreg = $20; 75 first_fpu_imreg = $20; 76 77 { MM Super register first and last } 78 first_mm_supreg = 0; 79 first_mm_imreg = 1; 80 81 { TODO: Calculate bsstart} 82 regnumber_count_bsstart = 128; 83 84 regnumber_table : array[tregisterindex] of tregister = ( 85 {$i rspnum.inc} 86 ); 87 88 regstabs_table : array[tregisterindex] of ShortInt = ( 89 {$i rspstab.inc} 90 ); 91 92 regdwarf_table : array[tregisterindex] of ShortInt = ( 93 {$i rspdwrf.inc} 94 ); 95 96 { Aliases for full register LoadStore instructions } 97 A_ST_R = A_ST; 98 A_LD_R = A_LD; 99 {$endif SPARC} 100 101 {$ifdef SPARC64} 102 type 103 { Number of registers used for indexing in tables } 104 tregisterindex=0..{$i rsp64nor.inc}-1; 105 totherregisterset = set of tregisterindex; 106 107 const 108 { Available Superregisters } 109 {$i rsp64sup.inc} 110 111 { No Subregisters } 112 R_SUBWHOLE = R_SUBNONE; 113 114 { Available Registers } 115 {$i rsp64con.inc} 116 117 first_int_imreg = $20; 118 first_fpu_imreg = $20; 119 120 { MM Super register first and last } 121 first_mm_supreg = 0; 122 first_mm_imreg = 1; 123 124 { TODO: Calculate bsstart} 125 regnumber_count_bsstart = 128; 126 127 regnumber_table : array[tregisterindex] of tregister = ( 128 {$i rsp64num.inc} 129 ); 130 131 regstabs_table : array[tregisterindex] of ShortInt = ( 132 {$i rsp64stab.inc} 133 ); 134 135 regdwarf_table : array[tregisterindex] of ShortInt = ( 136 {$i rsp64dwrf.inc} 137 ); 138 { Aliases for full register LoadStore instructions } 139 A_ST_R = A_STX; 140 A_LD_R = A_LDX; 141 {$endif SPARC64} 142 143 {***************************************************************************** 144 Conditions 145 *****************************************************************************} 146 147 type 148 TAsmCond=(C_None, 149 C_A,C_AE,C_B,C_BE, 150 C_G,C_GE,C_L,C_LE, 151 C_E,C_NE, 152 C_POS,C_NEG,C_VC,C_VS, 153 C_FE,C_FG,C_FL,C_FGE,C_FLE,C_FNE, 154 C_FU,C_FUG,C_FUL,C_FUGE,C_FULE,C_FO,C_FUE,C_FLG 155 ); 156 157 const 158 firstIntCond=C_A; 159 lastIntCond=C_VS; 160 firstFloatCond=C_FE; 161 lastFloatCond=C_FNE; 162 floatAsmConds=[C_FE..C_FLG]; 163 164 cond2str:array[TAsmCond] of string[3]=('', 165 'gu','cc','cs','leu', 166 'g','ge','l','le', 167 'e','ne', 168 'pos','neg','vc','vs', 169 'e','g','l','ge','le','ne', 170 'u','ug','ul','uge','ule','o','ue','lg' 171 ); 172 173 174 {***************************************************************************** 175 Flags 176 *****************************************************************************} 177 178 type 179 TSparcFlags = ( 180 { Integer results } 181 F_E, {Equal} 182 F_NE, {Not Equal} 183 F_G, {Greater} 184 F_L, {Less} 185 F_GE, {Greater or Equal} 186 F_LE, {Less or Equal} 187 F_A, {Above} 188 F_AE, {Above or Equal, synonym: Carry Clear} 189 F_B, {Below, synonym: Carry Set} 190 F_BE, {Below or Equal} 191 { Floating point results } 192 F_FE, {Equal} 193 F_FNE, {Not Equal} 194 F_FG, {Greater} 195 F_FL, {Less} 196 F_FGE, {Greater or Equal} 197 F_FLE {Less or Equal} 198 ); 199 TResFlags = record 200 { either icc or xcc (64 bit } 201 FlagReg : TRegister; 202 Flags : TSparcFlags; 203 procedure Init(r : TRegister;f : TSparcFlags); 204 end; 205 206 {***************************************************************************** 207 Operand Sizes 208 *****************************************************************************} 209 210 211 {***************************************************************************** 212 Constants 213 *****************************************************************************} 214 215 const 216 max_operands = 3; 217 218 maxintregs = 8; 219 maxfpuregs = 8; 220 maxaddrregs = 0; 221 222 maxvarregs = 8; 223 varregs : Array [1..maxvarregs] of Tsuperregister = 224 (RS_L0,RS_L1,RS_L2,RS_L3,RS_L4,RS_L5,RS_L6,RS_L7); 225 226 maxfpuvarregs = 1; 227 fpuvarregs : Array [1..maxfpuvarregs] of TsuperRegister = 228 (RS_F2); 229 230 {***************************************************************************** 231 Default generic sizes 232 *****************************************************************************} 233 234 {$ifdef SPARC64} 235 {# Defines the default address size for a processor, } 236 OS_ADDR = OS_64; 237 {# the natural int size for a processor, 238 has to match osuinttype/ossinttype as initialized in psystem } 239 OS_INT = OS_64; 240 OS_SINT = OS_S64; 241 {$else SPARC64} 242 {# Defines the default address size for a processor, } 243 OS_ADDR = OS_32; 244 {# the natural int size for a processor, 245 has to match osuinttype/ossinttype as initialized in psystem } 246 OS_INT = OS_32; 247 OS_SINT = OS_S32; 248 {$endif SPARC64} 249 {# the maximum float size for a processor, } 250 OS_FLOAT = OS_F64; 251 {# the size of a vector register for a processor } 252 OS_VECTOR = OS_M64; 253 254 {***************************************************************************** 255 Generic Register names 256 *****************************************************************************} 257 258 {# Stack pointer register } 259 NR_STACK_POINTER_REG = NR_O6; 260 RS_STACK_POINTER_REG = RS_O6; 261 {# Frame pointer register } 262 NR_FRAME_POINTER_REG = NR_I6; 263 RS_FRAME_POINTER_REG = RS_I6; 264 {# Register for addressing absolute data in a position independant way, 265 such as in PIC code. The exact meaning is ABI specific. For 266 further information look at GCC source : PIC_OFFSET_TABLE_REGNUM 267 268 Taken from GCC rs6000.h 269 } 270 { TODO: As indicated in rs6000.h, but can't find it anywhere else!} 271 {PIC_OFFSET_REG = R_30;} 272 { Return address for DWARF } 273 NR_RETURN_ADDRESS_REG = NR_I7; 274 { the return_result_reg, is used inside the called function to store its return 275 value when that is a scalar value otherwise a pointer to the address of the 276 result is placed inside it } 277 { Results are returned in this register (32-bit values) } 278 NR_FUNCTION_RETURN_REG = NR_I0; 279 RS_FUNCTION_RETURN_REG = RS_I0; 280 { Low part of 64bit return value } 281 NR_FUNCTION_RETURN64_LOW_REG = NR_I1; 282 RS_FUNCTION_RETURN64_LOW_REG = RS_I1; 283 { High part of 64bit return value } 284 NR_FUNCTION_RETURN64_HIGH_REG = NR_I0; 285 RS_FUNCTION_RETURN64_HIGH_REG = RS_I0; 286 { The value returned from a function is available in this register } 287 NR_FUNCTION_RESULT_REG = NR_O0; 288 RS_FUNCTION_RESULT_REG = RS_O0; 289 { The lowh part of 64bit value returned from a function } 290 NR_FUNCTION_RESULT64_LOW_REG = NR_O1; 291 RS_FUNCTION_RESULT64_LOW_REG = RS_O1; 292 { The high part of 64bit value returned from a function } 293 NR_FUNCTION_RESULT64_HIGH_REG = NR_O0; 294 RS_FUNCTION_RESULT64_HIGH_REG = RS_O0; 295 296 NR_FPU_RESULT_REG = NR_F0; 297 NR_MM_RESULT_REG = NR_NO; 298 299 PARENT_FRAMEPOINTER_OFFSET = 68; { o0 } 300 301 NR_DEFAULTFLAGS = NR_PSR; 302 RS_DEFAULTFLAGS = RS_PSR; 303 304 {***************************************************************************** 305 GCC /ABI linking information 306 *****************************************************************************} 307 308 {# Required parameter alignment when calling a routine declared as 309 stdcall and cdecl. The alignment value should be the one defined 310 by GCC or the target ABI. 311 312 The value of this constant is equal to the constant 313 PARM_BOUNDARY / BITS_PER_UNIT in the GCC source. 314 } 315 std_param_align = sizeof(AWord); 316 317 {$ifdef SPARC64} 318 STACK_BIAS = 2047; 319 {$endif SPARC64} 320 321 322 {***************************************************************************** 323 CPU Dependent Constants 324 *****************************************************************************} 325 326 const 327 simm13lo=-4096; 328 simm13hi=4095; 329 330 {***************************************************************************** 331 Helpers 332 *****************************************************************************} 333 is_calljmpnull334 function is_calljmp(o:tasmop):boolean; 335 336 procedure inverse_flags(var f: TResFlags); inverse_condnull337 function inverse_cond(const c: TAsmCond): TAsmCond; {$ifdef USEINLINE}inline;{$endif USEINLINE} conditions_equalnull338 function conditions_equal(const c1, c2: TAsmCond): boolean; {$ifdef USEINLINE}inline;{$endif USEINLINE} 339 flags_to_condnull340 function flags_to_cond(const f: TResFlags) : TAsmCond; cgsize2subregnull341 function cgsize2subreg(regtype: tregistertype; s:Tcgsize):Tsubregister; reg_cgsizenull342 function reg_cgsize(const reg: tregister): tcgsize; std_regnamenull343 function std_regname(r:Tregister):string; std_regnum_searchnull344 function std_regnum_search(const s:string):Tregister; findreg_by_numbernull345 function findreg_by_number(r:Tregister):tregisterindex; dwarf_regnull346 function dwarf_reg(r:tregister):shortint; dwarf_reg_no_errornull347 function dwarf_reg_no_error(r:tregister):shortint; 348 349 350 implementation 351 352 uses 353 rgBase,verbose; 354 355 {$ifdef SPARC} 356 const 357 std_regname_table : TRegNameTAble = ( 358 {$i rspstd.inc} 359 ); 360 361 regnumber_index : TRegisterIndexTable = ( 362 {$i rsprni.inc} 363 ); 364 365 std_regname_index : TRegisterIndexTable = ( 366 {$i rspsri.inc} 367 ); 368 {$endif SPARC} 369 370 {$ifdef SPARC64} 371 const 372 std_regname_table : TRegNameTAble = ( 373 {$i rsp64std.inc} 374 ); 375 376 regnumber_index : TRegisterIndexTable = ( 377 {$i rsp64rni.inc} 378 ); 379 380 std_regname_index : TRegisterIndexTable = ( 381 {$i rsp64sri.inc} 382 ); 383 {$endif SPARC64} 384 385 {***************************************************************************** 386 Helpers 387 *****************************************************************************} 388 is_calljmpnull389 function is_calljmp(o:tasmop):boolean; 390 const 391 CallJmpOp=[A_JMPL..A_CBccc]; 392 begin 393 is_calljmp:=(o in CallJmpOp); 394 end; 395 396 397 procedure inverse_flags(var f: TResFlags); 398 const 399 inv_flags: array[TSparcFlags] of TSparcFlags = 400 (F_NE,F_E,F_LE,F_GE,F_L,F_G,F_BE,F_B,F_AE,F_A, 401 F_FNE,F_FE,F_FLE,F_FGE,F_FL,F_FG); 402 begin 403 f.Flags:=inv_flags[f.Flags]; 404 end; 405 406 flags_to_condnull407 function flags_to_cond(const f:TResFlags):TAsmCond; 408 const 409 flags_2_cond:array[TSparcFlags] of TAsmCond= 410 (C_E,C_NE,C_G,C_L,C_GE,C_LE,C_A,C_AE,C_B,C_BE, 411 C_FE,C_FNE,C_FG,C_FL,C_FGE,C_FLE); 412 begin 413 result:=flags_2_cond[f.Flags]; 414 end; 415 416 cgsize2subregnull417 function cgsize2subreg(regtype: tregistertype; s:Tcgsize):Tsubregister; 418 begin 419 case regtype of 420 R_FPUREGISTER: 421 case s of 422 OS_F32: 423 cgsize2subreg:=R_SUBFS; 424 OS_F64: 425 cgsize2subreg:=R_SUBFD; 426 OS_F128: 427 cgsize2subreg:=R_SUBFQ; 428 else 429 internalerror(2009071903); 430 end; 431 else 432 begin 433 {$ifdef SPARC32} 434 if s in [OS_64,OS_S64] then 435 cgsize2subreg:=R_SUBQ 436 else 437 {$endif SPARC32} 438 cgsize2subreg:=R_SUBWHOLE; 439 end; 440 end; 441 end; 442 443 reg_cgsizenull444 function reg_cgsize(const reg: tregister): tcgsize; 445 begin 446 case getregtype(reg) of 447 R_INTREGISTER : 448 result:=OS_INT; 449 R_FPUREGISTER : 450 begin 451 if getsubreg(reg)=R_SUBFD then 452 result:=OS_F64 453 else 454 result:=OS_F32; 455 end; 456 else 457 internalerror(200303181); 458 end; 459 end; 460 461 findreg_by_numbernull462 function findreg_by_number(r:Tregister):tregisterindex; 463 begin 464 result:=findreg_by_number_table(r,regnumber_index); 465 end; 466 467 std_regnamenull468 function std_regname(r:Tregister):string; 469 var 470 p : tregisterindex; 471 begin 472 { For double floats show a pair like %f0:%f1 } 473 if (getsubreg(r)=R_SUBFD) and 474 (getsupreg(r)<first_fpu_imreg) then 475 begin 476 setsubreg(r,R_SUBFS); 477 p:=findreg_by_number(r); 478 if p<>0 then 479 result:=std_regname_table[p] 480 else 481 result:=generic_regname(r); 482 setsupreg(r,getsupreg(r)+1); 483 p:=findreg_by_number(r); 484 if p<>0 then 485 result:=result+':'+std_regname_table[p] 486 else 487 result:=result+':'+generic_regname(r); 488 end 489 else 490 begin 491 p:=findreg_by_number(r); 492 if p<>0 then 493 result:=std_regname_table[p] 494 else 495 result:=generic_regname(r); 496 end; 497 end; 498 499 std_regnum_searchnull500 function std_regnum_search(const s:string):Tregister; 501 begin 502 result:=regnumber_table[findreg_by_name_table(s,std_regname_table,std_regname_index)]; 503 end; 504 505 inverse_condnull506 function inverse_cond(const c: TAsmCond): TAsmCond; {$ifdef USEINLINE}inline;{$endif USEINLINE} 507 const 508 inverse: array[TAsmCond] of TAsmCond=(C_None, 509 C_BE,C_B,C_AE,C_A, 510 C_LE,C_L,C_GE,C_G, 511 C_NE,C_E, 512 C_NEG,C_POS,C_VS,C_VC, 513 C_FNE,C_FULE,C_FUGE,C_FUL,C_FUG,C_FE, 514 C_FO,C_FLE,C_FGE,C_FL,C_FG,C_FU,C_FLG,C_FUE 515 ); 516 begin 517 result := inverse[c]; 518 end; 519 520 conditions_equalnull521 function conditions_equal(const c1, c2: TAsmCond): boolean; {$ifdef USEINLINE}inline;{$endif USEINLINE} 522 begin 523 result := c1 = c2; 524 end; 525 526 dwarf_regnull527 function dwarf_reg(r:tregister):shortint; 528 begin 529 result:=regdwarf_table[findreg_by_number(r)]; 530 if result=-1 then 531 internalerror(200603251); 532 end; 533 dwarf_reg_no_errornull534 function dwarf_reg_no_error(r:tregister):shortint; 535 begin 536 result:=regdwarf_table[findreg_by_number(r)]; 537 end; 538 539 procedure TResFlags.Init(r : TRegister; f : TSparcFlags); 540 begin 541 FlagReg:=r; 542 Flags:=f; 543 end; 544 545 end. 546