1 { 2 Copyright (c) 2003 by Florian Klaempfl 3 4 Contains the assembler object for the ARM 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 aasmcpu; 23 24 {$i fpcdefs.inc} 25 26 interface 27 28 uses 29 globtype,globals,verbose, 30 aasmbase,aasmtai,aasmdata,aasmsym, 31 ogbase, 32 symtype, 33 cpubase,cpuinfo,cgbase,cgutils, 34 sysutils; 35 36 const 37 { "mov reg,reg" source operand number } 38 O_MOV_SOURCE = 1; 39 { "mov reg,reg" source operand number } 40 O_MOV_DEST = 0; 41 42 { Operand types } 43 OT_NONE = $00000000; 44 45 OT_BITS8 = $00000001; { size, and other attributes, of the operand } 46 OT_BITS16 = $00000002; 47 OT_BITS32 = $00000004; 48 OT_BITS64 = $00000008; { FPU only } 49 OT_BITS80 = $00000010; 50 OT_FAR = $00000020; { this means 16:16 or 16:32, like in CALL/JMP } 51 OT_NEAR = $00000040; 52 OT_SHORT = $00000080; 53 OT_BITSTINY = $00000100; { fpu constant } 54 OT_BITSSHIFTER = 55 $00000200; 56 57 OT_SIZE_MASK = $000003FF; { all the size attributes } 58 OT_NON_SIZE = $0FFFF800; 59 OT_OPT_SIZE = $F0000000; 60 61 OT_SIGNED = $00000100; { the operand need to be signed -128-127 } 62 63 OT_TO = $00000200; { operand is followed by a colon } 64 { reverse effect in FADD, FSUB &c } 65 OT_COLON = $00000400; 66 67 OT_SHIFTEROP = $00000800; 68 OT_REGISTER = $00001000; 69 OT_IMMEDIATE = $00002000; 70 OT_REGLIST = $00008000; 71 OT_IMM8 = $00002001; 72 OT_IMM24 = $00002002; 73 OT_IMM32 = $00002004; 74 OT_IMM64 = $00002008; 75 OT_IMM80 = $00002010; 76 OT_IMMTINY = $00002100; 77 OT_IMMSHIFTER= $00002200; 78 OT_IMMEDIATEZERO = $10002200; 79 OT_IMMEDIATEMM = $00002400; 80 OT_IMMEDIATE24 = OT_IMM24; 81 OT_SHIFTIMM = OT_SHIFTEROP or OT_IMMSHIFTER; 82 OT_SHIFTIMMEDIATE = OT_SHIFTIMM; 83 OT_IMMEDIATESHIFTER = OT_IMMSHIFTER; 84 85 OT_IMMEDIATEFPU = OT_IMMTINY; 86 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_REGLO = $10201004; { lower reg (r0-r7) } 93 OT_REGSP = $20201004; 94 OT_REG64 = $00201008; 95 OT_VREG = $00201010; { vector register } 96 OT_REGF = $00201020; { coproc register } 97 OT_REGS = $00201040; { special register with mask } 98 OT_MEMORY = $00204000; { register number in 'basereg' } 99 OT_MEM8 = $00204001; 100 OT_MEM16 = $00204002; 101 OT_MEM32 = $00204004; 102 OT_MEM64 = $00204008; 103 OT_MEM80 = $00204010; 104 { word/byte load/store } 105 OT_AM2 = $00010000; 106 { misc ld/st operations, thumb reg indexed } 107 OT_AM3 = $00020000; 108 { multiple ld/st operations or thumb imm indexed } 109 OT_AM4 = $00040000; 110 { co proc. ld/st operations or thumb sp+imm indexed } 111 OT_AM5 = $00080000; 112 { exclusive ld/st operations or thumb pc+imm indexed } 113 OT_AM6 = $00100000; 114 OT_AMMASK = $001f0000; 115 { IT instruction } 116 OT_CONDITION = $00200000; 117 OT_MODEFLAGS = $00400000; 118 119 OT_MEMORYAM2 = OT_MEMORY or OT_AM2; 120 OT_MEMORYAM3 = OT_MEMORY or OT_AM3; 121 OT_MEMORYAM4 = OT_MEMORY or OT_AM4; 122 OT_MEMORYAM5 = OT_MEMORY or OT_AM5; 123 OT_MEMORYAM6 = OT_MEMORY or OT_AM6; 124 125 OT_FPUREG = $01000000; { floating point stack registers } 126 OT_REG_SMASK = $00070000; { special register operands: these may be treated differently } 127 { a mask for the following } 128 129 OT_MEM_OFFS = $00604000; { special type of EA } 130 { simple [address] offset } 131 OT_ONENESS = $00800000; { special type of immediate operand } 132 { so UNITY == IMMEDIATE | ONENESS } 133 OT_UNITY = $00802000; { for shift/rotate instructions } 134 135 instabentries = {$i armnop.inc} 136 137 maxinfolen = 5; 138 139 IF_NONE = $00000000; 140 141 IF_ARMMASK = $000F0000; 142 IF_ARM32 = $00010000; 143 IF_THUMB = $00020000; 144 IF_THUMB32 = $00040000; 145 IF_WIDE = $00080000; 146 147 IF_ARMvMASK = $0FF00000; 148 IF_ARMv4 = $00100000; 149 IF_ARMv4T = $00200000; 150 IF_ARMv5 = $00300000; 151 IF_ARMv5T = $00400000; 152 IF_ARMv5TE = $00500000; 153 IF_ARMv5TEJ = $00600000; 154 IF_ARMv6 = $00700000; 155 IF_ARMv6K = $00800000; 156 IF_ARMv6T2 = $00900000; 157 IF_ARMv6Z = $00A00000; 158 IF_ARMv6M = $00B00000; 159 IF_ARMv7 = $00C00000; 160 IF_ARMv7A = $00D00000; 161 IF_ARMv7R = $00E00000; 162 IF_ARMv7M = $00F00000; 163 IF_ARMv7EM = $01000000; 164 165 IF_FPMASK = $F0000000; 166 IF_FPA = $10000000; 167 IF_VFPv2 = $20000000; 168 IF_VFPv3 = $40000000; 169 IF_VFPv4 = $80000000; 170 171 { if the instruction can change in a second pass } 172 IF_PASS2 = longint($80000000); 173 174 type 175 TInsTabCache=array[TasmOp] of longint; 176 PInsTabCache=^TInsTabCache; 177 178 tinsentry = record 179 opcode : tasmop; 180 ops : byte; 181 optypes : array[0..5] of longint; 182 code : array[0..maxinfolen] of char; 183 flags : longword; 184 end; 185 186 pinsentry=^tinsentry; 187 188 const 189 InsTab : array[0..instabentries-1] of TInsEntry={$i armtab.inc} 190 191 var 192 InsTabCache : PInsTabCache; 193 194 type 195 taicpu = class(tai_cpu_abstract_sym) 196 oppostfix : TOpPostfix; 197 wideformat : boolean; 198 roundingmode : troundingmode; 199 procedure loadshifterop(opidx:longint;const so:tshifterop); 200 procedure loadregset(opidx:longint; regsetregtype: tregistertype; regsetsubregtype: tsubregister; const s:tcpuregisterset; ausermode: boolean=false); 201 procedure loadconditioncode(opidx:longint;const cond:tasmcond); 202 procedure loadmodeflags(opidx:longint;const flags:tcpumodeflags); 203 procedure loadspecialreg(opidx:longint;const areg:tregister; const aflags:tspecialregflags); 204 procedure loadrealconst(opidx:longint;const _value:bestreal); 205 206 constructor op_none(op : tasmop); 207 208 constructor op_reg(op : tasmop;_op1 : tregister); 209 constructor op_ref(op : tasmop;const _op1 : treference); 210 constructor op_const(op : tasmop;_op1 : longint); 211 212 constructor op_reg_reg(op : tasmop;_op1,_op2 : tregister); 213 constructor op_reg_ref(op : tasmop;_op1 : tregister;const _op2 : treference); 214 constructor op_reg_const(op:tasmop; _op1: tregister; _op2: aint); 215 216 constructor op_regset(op:tasmop; regtype: tregistertype; subreg: tsubregister; _op1: tcpuregisterset); 217 constructor op_ref_regset(op:tasmop; _op1: treference; regtype: tregistertype; subreg: tsubregister; _op2: tcpuregisterset); 218 219 constructor op_reg_reg_reg(op : tasmop;_op1,_op2,_op3 : tregister); 220 constructor op_reg_reg_const(op : tasmop;_op1,_op2 : tregister; _op3: aint); 221 constructor op_reg_const_const(op : tasmop;_op1 : tregister; _op2,_op3: aint); 222 constructor op_reg_reg_const_const(op : tasmop;_op1,_op2 : tregister; _op3,_op4: aint); 223 constructor op_reg_reg_sym_ofs(op : tasmop;_op1,_op2 : tregister; _op3: tasmsymbol;_op3ofs: longint); 224 constructor op_reg_reg_ref(op : tasmop;_op1,_op2 : tregister; const _op3: treference); 225 constructor op_reg_reg_shifterop(op : tasmop;_op1,_op2 : tregister;_op3 : tshifterop); 226 constructor op_reg_reg_reg_shifterop(op : tasmop;_op1,_op2,_op3 : tregister;_op4 : tshifterop); 227 { SFM/LFM } 228 constructor op_reg_const_ref(op : tasmop;_op1 : tregister;_op2 : aint;_op3 : treference); 229 230 { ITxxx } 231 constructor op_cond(op: tasmop; cond: tasmcond); 232 233 { CPSxx } 234 constructor op_modeflags(op: tasmop; flags: tcpumodeflags); 235 constructor op_modeflags_const(op: tasmop; flags: tcpumodeflags; a: aint); 236 237 { MSR } 238 constructor op_specialreg_reg(op: tasmop; specialreg: tregister; specialregflags: tspecialregflags; _op2: tregister); 239 240 { *M*LL } 241 constructor op_reg_reg_reg_reg(op : tasmop;_op1,_op2,_op3,_op4 : tregister); 242 243 constructor op_reg_realconst(op : tasmop;_op1: tregister;_op2: bestreal); 244 245 { this is for Jmp instructions } 246 constructor op_cond_sym(op : tasmop;cond:TAsmCond;_op1 : tasmsymbol); 247 248 constructor op_sym(op : tasmop;_op1 : tasmsymbol); 249 constructor op_sym_ofs(op : tasmop;_op1 : tasmsymbol;_op1ofs:longint); 250 constructor op_reg_sym_ofs(op : tasmop;_op1 : tregister;_op2:tasmsymbol;_op2ofs : longint); 251 constructor op_sym_ofs_ref(op : tasmop;_op1 : tasmsymbol;_op1ofs:longint;const _op2 : treference); 252 is_same_reg_movenull253 function is_same_reg_move(regtype: Tregistertype):boolean; override; 254 spilling_get_operation_typenull255 function spilling_get_operation_type(opnr: longint): topertype;override; spilling_get_operation_type_refnull256 function spilling_get_operation_type_ref(opnr: longint; reg: tregister): topertype;override; 257 { assembler } 258 public 259 { the next will reset all instructions that can change in pass 2 } 260 procedure ResetPass1;override; 261 procedure ResetPass2;override; CheckIfValidnull262 function CheckIfValid:boolean; GetStringnull263 function GetString:string; Pass1null264 function Pass1(objdata:TObjData):longint;override; 265 procedure Pass2(objdata:TObjData);override; 266 protected 267 procedure ppuloadoper(ppufile:tcompilerppufile;var o:toper);override; 268 procedure ppuwriteoper(ppufile:tcompilerppufile;const o:toper);override; 269 procedure ppubuildderefimploper(var o:toper);override; 270 procedure ppuderefoper(var o:toper);override; 271 private 272 { pass1 info } 273 inIT, 274 lastinIT: boolean; 275 { arm version info } 276 fArmVMask, 277 fArmMask : longint; 278 { next fields are filled in pass1, so pass2 is faster } 279 inssize : shortint; 280 insoffset : longint; 281 LastInsOffset : longint; { need to be public to be reset } 282 insentry : PInsEntry; 283 procedure BuildArmMasks(objdata:TObjData); InsEndnull284 function InsEnd:longint; 285 procedure create_ot(objdata:TObjData); Matchesnull286 function Matches(p:PInsEntry):longint; calcsizenull287 function calcsize(p:PInsEntry):shortint; 288 procedure gencode(objdata:TObjData); NeedAddrPrefixnull289 function NeedAddrPrefix(opidx:byte):boolean; 290 procedure Swapoperands; FindInsentrynull291 function FindInsentry(objdata:TObjData):boolean; 292 end; 293 294 tai_align = class(tai_align_abstract) 295 { nothing to add } 296 end; 297 spilling_create_loadnull298 function spilling_create_load(const ref:treference;r:tregister):Taicpu; spilling_create_storenull299 function spilling_create_store(r:tregister; const ref:treference):Taicpu; 300 setoppostfixnull301 function setoppostfix(i : taicpu;pf : toppostfix) : taicpu; setroundingmodenull302 function setroundingmode(i : taicpu;rm : troundingmode) : taicpu; setconditionnull303 function setcondition(i : taicpu;c : tasmcond) : taicpu; 304 305 { inserts pc relative symbols at places where they are reachable 306 and transforms special instructions to valid instruction encodings } 307 procedure finalizearmcode(list,listtoinsert : TAsmList); 308 { inserts .pdata section and dummy function prolog needed for arm-wince exception handling } 309 procedure InsertPData; 310 311 procedure InitAsm; 312 procedure DoneAsm; 313 314 315 implementation 316 317 uses 318 itcpugas,aoptcpu, 319 systems,symdef; 320 321 322 procedure taicpu.loadshifterop(opidx:longint;const so:tshifterop); 323 begin 324 allocate_oper(opidx+1); 325 with oper[opidx]^ do 326 begin 327 if typ<>top_shifterop then 328 begin 329 clearop(opidx); 330 new(shifterop); 331 end; 332 shifterop^:=so; 333 typ:=top_shifterop; 334 if assigned(add_reg_instruction_hook) then 335 add_reg_instruction_hook(self,shifterop^.rs); 336 end; 337 end; 338 339 340 procedure taicpu.loadrealconst(opidx:longint;const _value:bestreal); 341 begin 342 allocate_oper(opidx+1); 343 with oper[opidx]^ do 344 begin 345 if typ<>top_realconst then 346 clearop(opidx); 347 val_real:=_value; 348 typ:=top_realconst; 349 end; 350 end; 351 352 353 procedure taicpu.loadregset(opidx:longint; regsetregtype: tregistertype; regsetsubregtype: tsubregister; const s:tcpuregisterset; ausermode: boolean); 354 var 355 i : byte; 356 begin 357 allocate_oper(opidx+1); 358 with oper[opidx]^ do 359 begin 360 if typ<>top_regset then 361 begin 362 clearop(opidx); 363 new(regset); 364 end; 365 regset^:=s; 366 regtyp:=regsetregtype; 367 subreg:=regsetsubregtype; 368 usermode:=ausermode; 369 typ:=top_regset; 370 case regsetregtype of 371 R_INTREGISTER: 372 for i:=RS_R0 to RS_R15 do 373 begin 374 if assigned(add_reg_instruction_hook) and (i in regset^) then 375 add_reg_instruction_hook(self,newreg(R_INTREGISTER,i,regsetsubregtype)); 376 end; 377 R_MMREGISTER: 378 { both RS_S0 and RS_D0 range from 0 to 31 } 379 for i:=RS_D0 to RS_D31 do 380 begin 381 if assigned(add_reg_instruction_hook) and (i in regset^) then 382 add_reg_instruction_hook(self,newreg(R_MMREGISTER,i,regsetsubregtype)); 383 end; 384 end; 385 end; 386 end; 387 388 389 procedure taicpu.loadconditioncode(opidx:longint;const cond:tasmcond); 390 begin 391 allocate_oper(opidx+1); 392 with oper[opidx]^ do 393 begin 394 if typ<>top_conditioncode then 395 clearop(opidx); 396 cc:=cond; 397 typ:=top_conditioncode; 398 end; 399 end; 400 401 procedure taicpu.loadmodeflags(opidx: longint; const flags: tcpumodeflags); 402 begin 403 allocate_oper(opidx+1); 404 with oper[opidx]^ do 405 begin 406 if typ<>top_modeflags then 407 clearop(opidx); 408 modeflags:=flags; 409 typ:=top_modeflags; 410 end; 411 end; 412 413 procedure taicpu.loadspecialreg(opidx: longint; const areg: tregister; const aflags: tspecialregflags); 414 begin 415 allocate_oper(opidx+1); 416 with oper[opidx]^ do 417 begin 418 if typ<>top_specialreg then 419 clearop(opidx); 420 specialreg:=areg; 421 specialflags:=aflags; 422 typ:=top_specialreg; 423 end; 424 end; 425 426 {***************************************************************************** 427 taicpu Constructors 428 *****************************************************************************} 429 430 constructor taicpu.op_none(op : tasmop); 431 begin 432 inherited create(op); 433 end; 434 435 436 { for pld } 437 constructor taicpu.op_ref(op : tasmop;const _op1 : treference); 438 begin 439 inherited create(op); 440 ops:=1; 441 loadref(0,_op1); 442 end; 443 444 445 constructor taicpu.op_reg(op : tasmop;_op1 : tregister); 446 begin 447 inherited create(op); 448 ops:=1; 449 loadreg(0,_op1); 450 end; 451 452 453 constructor taicpu.op_const(op : tasmop;_op1 : longint); 454 begin 455 inherited create(op); 456 ops:=1; 457 loadconst(0,aint(_op1)); 458 end; 459 460 461 constructor taicpu.op_reg_reg(op : tasmop;_op1,_op2 : tregister); 462 begin 463 inherited create(op); 464 ops:=2; 465 loadreg(0,_op1); 466 loadreg(1,_op2); 467 end; 468 469 470 constructor taicpu.op_reg_const(op:tasmop; _op1: tregister; _op2: aint); 471 begin 472 inherited create(op); 473 ops:=2; 474 loadreg(0,_op1); 475 loadconst(1,aint(_op2)); 476 end; 477 478 constructor taicpu.op_regset(op: tasmop; regtype: tregistertype; subreg: tsubregister; _op1: tcpuregisterset); 479 begin 480 inherited create(op); 481 ops:=1; 482 loadregset(0,regtype,subreg,_op1); 483 end; 484 485 486 constructor taicpu.op_ref_regset(op:tasmop; _op1: treference; regtype: tregistertype; subreg: tsubregister; _op2: tcpuregisterset); 487 begin 488 inherited create(op); 489 ops:=2; 490 loadref(0,_op1); 491 loadregset(1,regtype,subreg,_op2); 492 end; 493 494 495 constructor taicpu.op_reg_ref(op : tasmop;_op1 : tregister;const _op2 : treference); 496 begin 497 inherited create(op); 498 ops:=2; 499 loadreg(0,_op1); 500 loadref(1,_op2); 501 end; 502 503 504 constructor taicpu.op_reg_reg_reg(op : tasmop;_op1,_op2,_op3 : tregister); 505 begin 506 inherited create(op); 507 ops:=3; 508 loadreg(0,_op1); 509 loadreg(1,_op2); 510 loadreg(2,_op3); 511 end; 512 513 514 constructor taicpu.op_reg_reg_reg_reg(op : tasmop;_op1,_op2,_op3,_op4 : tregister); 515 begin 516 inherited create(op); 517 ops:=4; 518 loadreg(0,_op1); 519 loadreg(1,_op2); 520 loadreg(2,_op3); 521 loadreg(3,_op4); 522 end; 523 524 525 constructor taicpu.op_reg_realconst(op : tasmop; _op1 : tregister; _op2 : bestreal); 526 begin 527 inherited create(op); 528 ops:=2; 529 loadreg(0,_op1); 530 loadrealconst(1,_op2); 531 end; 532 533 534 constructor taicpu.op_reg_reg_const(op : tasmop;_op1,_op2 : tregister; _op3: aint); 535 begin 536 inherited create(op); 537 ops:=3; 538 loadreg(0,_op1); 539 loadreg(1,_op2); 540 loadconst(2,aint(_op3)); 541 end; 542 543 544 constructor taicpu.op_reg_const_const(op : tasmop;_op1 : tregister; _op2,_op3: aint); 545 begin 546 inherited create(op); 547 ops:=3; 548 loadreg(0,_op1); 549 loadconst(1,aint(_op2)); 550 loadconst(2,aint(_op3)); 551 end; 552 553 554 constructor taicpu.op_reg_reg_const_const(op: tasmop; _op1, _op2: tregister; _op3, _op4: aint); 555 begin 556 inherited create(op); 557 ops:=4; 558 loadreg(0,_op1); 559 loadreg(1,_op2); 560 loadconst(2,aint(_op3)); 561 loadconst(3,aint(_op4)); 562 end; 563 564 565 constructor taicpu.op_reg_const_ref(op : tasmop;_op1 : tregister;_op2 : aint;_op3 : treference); 566 begin 567 inherited create(op); 568 ops:=3; 569 loadreg(0,_op1); 570 loadconst(1,_op2); 571 loadref(2,_op3); 572 end; 573 574 575 constructor taicpu.op_cond(op: tasmop; cond: tasmcond); 576 begin 577 inherited create(op); 578 ops:=1; 579 loadconditioncode(0, cond); 580 end; 581 582 constructor taicpu.op_modeflags(op: tasmop; flags: tcpumodeflags); 583 begin 584 inherited create(op); 585 ops := 1; 586 loadmodeflags(0,flags); 587 end; 588 589 constructor taicpu.op_modeflags_const(op: tasmop; flags: tcpumodeflags; a: aint); 590 begin 591 inherited create(op); 592 ops := 2; 593 loadmodeflags(0,flags); 594 loadconst(1,a); 595 end; 596 597 constructor taicpu.op_specialreg_reg(op: tasmop; specialreg: tregister; specialregflags: tspecialregflags; _op2: tregister); 598 begin 599 inherited create(op); 600 ops:=2; 601 loadspecialreg(0,specialreg,specialregflags); 602 loadreg(1,_op2); 603 end; 604 605 constructor taicpu.op_reg_reg_sym_ofs(op : tasmop;_op1,_op2 : tregister; _op3: tasmsymbol;_op3ofs: longint); 606 begin 607 inherited create(op); 608 ops:=3; 609 loadreg(0,_op1); 610 loadreg(1,_op2); 611 loadsymbol(0,_op3,_op3ofs); 612 end; 613 614 615 constructor taicpu.op_reg_reg_ref(op : tasmop;_op1,_op2 : tregister; const _op3: treference); 616 begin 617 inherited create(op); 618 ops:=3; 619 loadreg(0,_op1); 620 loadreg(1,_op2); 621 loadref(2,_op3); 622 end; 623 624 625 constructor taicpu.op_reg_reg_shifterop(op : tasmop;_op1,_op2 : tregister;_op3 : tshifterop); 626 begin 627 inherited create(op); 628 ops:=3; 629 loadreg(0,_op1); 630 loadreg(1,_op2); 631 loadshifterop(2,_op3); 632 end; 633 634 635 constructor taicpu.op_reg_reg_reg_shifterop(op : tasmop;_op1,_op2,_op3 : tregister;_op4 : tshifterop); 636 begin 637 inherited create(op); 638 ops:=4; 639 loadreg(0,_op1); 640 loadreg(1,_op2); 641 loadreg(2,_op3); 642 loadshifterop(3,_op4); 643 end; 644 645 646 constructor taicpu.op_cond_sym(op : tasmop;cond:TAsmCond;_op1 : tasmsymbol); 647 begin 648 inherited create(op); 649 condition:=cond; 650 ops:=1; 651 loadsymbol(0,_op1,0); 652 end; 653 654 655 constructor taicpu.op_sym(op : tasmop;_op1 : tasmsymbol); 656 begin 657 inherited create(op); 658 ops:=1; 659 loadsymbol(0,_op1,0); 660 end; 661 662 663 constructor taicpu.op_sym_ofs(op : tasmop;_op1 : tasmsymbol;_op1ofs:longint); 664 begin 665 inherited create(op); 666 ops:=1; 667 loadsymbol(0,_op1,_op1ofs); 668 end; 669 670 671 constructor taicpu.op_reg_sym_ofs(op : tasmop;_op1 : tregister;_op2:tasmsymbol;_op2ofs : longint); 672 begin 673 inherited create(op); 674 ops:=2; 675 loadreg(0,_op1); 676 loadsymbol(1,_op2,_op2ofs); 677 end; 678 679 680 constructor taicpu.op_sym_ofs_ref(op : tasmop;_op1 : tasmsymbol;_op1ofs:longint;const _op2 : treference); 681 begin 682 inherited create(op); 683 ops:=2; 684 loadsymbol(0,_op1,_op1ofs); 685 loadref(1,_op2); 686 end; 687 688 taicpu.is_same_reg_movenull689 function taicpu.is_same_reg_move(regtype: Tregistertype):boolean; 690 begin 691 { allow the register allocator to remove unnecessary moves } 692 result:=( 693 ((opcode=A_MOV) and (regtype = R_INTREGISTER)) or 694 ((opcode=A_MVF) and (regtype = R_FPUREGISTER)) or 695 ((opcode in [A_FCPYS, A_FCPYD]) and (regtype = R_MMREGISTER)) or 696 ((opcode in [A_VMOV]) and (regtype = R_MMREGISTER) and (oppostfix in [PF_F32,PF_F64])) 697 ) and 698 ((oppostfix in [PF_None,PF_D]) or (opcode = A_VMOV)) and 699 (condition=C_None) and 700 (ops=2) and 701 (oper[0]^.typ=top_reg) and 702 (oper[1]^.typ=top_reg) and 703 (oper[0]^.reg=oper[1]^.reg); 704 end; 705 706 spilling_create_loadnull707 function spilling_create_load(const ref:treference;r:tregister):Taicpu; 708 begin 709 case getregtype(r) of 710 R_INTREGISTER : 711 result:=taicpu.op_reg_ref(A_LDR,r,ref); 712 R_FPUREGISTER : 713 { use lfm because we don't know the current internal format 714 and avoid exceptions 715 } 716 result:=taicpu.op_reg_const_ref(A_LFM,r,1,ref); 717 R_MMREGISTER : 718 result:=taicpu.op_reg_ref(A_VLDR,r,ref); 719 else 720 internalerror(200401041); 721 end; 722 end; 723 724 spilling_create_storenull725 function spilling_create_store(r:tregister; const ref:treference):Taicpu; 726 begin 727 case getregtype(r) of 728 R_INTREGISTER : 729 result:=taicpu.op_reg_ref(A_STR,r,ref); 730 R_FPUREGISTER : 731 { use sfm because we don't know the current internal format 732 and avoid exceptions 733 } 734 result:=taicpu.op_reg_const_ref(A_SFM,r,1,ref); 735 R_MMREGISTER : 736 result:=taicpu.op_reg_ref(A_VSTR,r,ref); 737 else 738 internalerror(200401041); 739 end; 740 end; 741 742 taicpu.spilling_get_operation_typenull743 function taicpu.spilling_get_operation_type(opnr: longint): topertype; 744 begin 745 if GenerateThumbCode then 746 case opcode of 747 A_ADC,A_ADD,A_AND,A_BIC, 748 A_EOR,A_CLZ,A_RBIT, 749 A_LDR,A_LDRB,A_LDRBT,A_LDRH,A_LDRSB, 750 A_LDRSH,A_LDRT, 751 A_MOV,A_MVN,A_MLA,A_MUL, 752 A_ORR,A_RSB,A_RSC,A_SBC,A_SUB, 753 A_SWP,A_SWPB, 754 A_LDF,A_FLT,A_FIX, 755 A_ADF,A_DVF,A_FDV,A_FML, 756 A_RFS,A_RFC,A_RDF, 757 A_RMF,A_RPW,A_RSF,A_SUF,A_ABS,A_ACS,A_ASN,A_ATN,A_COS, 758 A_EXP,A_LOG,A_LGN,A_MVF,A_MNF,A_FRD,A_MUF,A_POL,A_RND,A_SIN,A_SQT,A_TAN, 759 A_LFM, 760 A_FLDS,A_FLDD, 761 A_FMRX,A_FMXR,A_FMSTAT, 762 A_FMSR,A_FMRS,A_FMDRR, 763 A_FCPYS,A_FCPYD,A_FCVTSD,A_FCVTDS, 764 A_FABSS,A_FABSD,A_FSQRTS,A_FSQRTD,A_FMULS,A_FMULD, 765 A_FADDS,A_FADDD,A_FSUBS,A_FSUBD,A_FDIVS,A_FDIVD, 766 A_FMACS,A_FMACD,A_FMSCS,A_FMSCD,A_FNMACS,A_FNMACD, 767 A_FNMSCS,A_FNMSCD,A_FNMULS,A_FNMULD, 768 A_FMDHR,A_FMRDH,A_FMDLR,A_FMRDL, 769 A_FNEGS,A_FNEGD, 770 A_FSITOS,A_FSITOD,A_FTOSIS,A_FTOSID, 771 A_FTOUIS,A_FTOUID,A_FUITOS,A_FUITOD, 772 A_SXTB16,A_UXTB16, 773 A_UXTB,A_UXTH,A_SXTB,A_SXTH, 774 A_NEG, 775 A_VABS,A_VADD,A_VCVT,A_VDIV,A_VLDR,A_VMOV,A_VMUL,A_VNEG,A_VSQRT,A_VSUB, 776 A_MRS,A_MSR: 777 if opnr=0 then 778 result:=operand_readwrite 779 else 780 result:=operand_read; 781 A_BKPT,A_B,A_BL,A_BLX,A_BX, 782 A_CMN,A_CMP,A_TEQ,A_TST, 783 A_CMF,A_CMFE,A_WFS,A_CNF, 784 A_FCMPS,A_FCMPD,A_FCMPES,A_FCMPED,A_FCMPEZS,A_FCMPEZD, 785 A_FCMPZS,A_FCMPZD, 786 A_VCMP,A_VCMPE: 787 result:=operand_read; 788 A_SMLAL,A_UMLAL: 789 if opnr in [0,1] then 790 result:=operand_readwrite 791 else 792 result:=operand_read; 793 A_SMULL,A_UMULL, 794 A_FMRRD: 795 if opnr in [0,1] then 796 result:=operand_readwrite 797 else 798 result:=operand_read; 799 A_STR,A_STRB,A_STRBT, 800 A_STRH,A_STRT,A_STF,A_SFM, 801 A_FSTS,A_FSTD, 802 A_VSTR: 803 { important is what happens with the involved registers } 804 if opnr=0 then 805 result := operand_read 806 else 807 { check for pre/post indexed } 808 result := operand_read; 809 //Thumb2 810 A_LSL, A_LSR, A_ROR, A_ASR, A_SDIV, A_UDIV, A_MOVW, A_MOVT, A_MLS, A_BFI, 811 A_SMMLA,A_SMMLS: 812 if opnr in [0] then 813 result:=operand_readwrite 814 else 815 result:=operand_read; 816 A_BFC: 817 if opnr in [0] then 818 result:=operand_readwrite 819 else 820 result:=operand_read; 821 A_LDREX: 822 if opnr in [0] then 823 result:=operand_readwrite 824 else 825 result:=operand_read; 826 A_STREX: 827 result:=operand_write; 828 else 829 internalerror(200403151); 830 end 831 else 832 case opcode of 833 A_ADC,A_ADD,A_AND,A_BIC,A_ORN, 834 A_EOR,A_CLZ,A_RBIT, 835 A_LDR,A_LDRB,A_LDRBT,A_LDRH,A_LDRSB, 836 A_LDRSH,A_LDRT, 837 A_MOV,A_MVN,A_MLA,A_MUL, 838 A_ORR,A_RSB,A_RSC,A_SBC,A_SUB, 839 A_SWP,A_SWPB, 840 A_LDF,A_FLT,A_FIX, 841 A_ADF,A_DVF,A_FDV,A_FML, 842 A_RFS,A_RFC,A_RDF, 843 A_RMF,A_RPW,A_RSF,A_SUF,A_ABS,A_ACS,A_ASN,A_ATN,A_COS, 844 A_EXP,A_LOG,A_LGN,A_MVF,A_MNF,A_FRD,A_MUF,A_POL,A_RND,A_SIN,A_SQT,A_TAN, 845 A_LFM, 846 A_FLDS,A_FLDD, 847 A_FMRX,A_FMXR,A_FMSTAT, 848 A_FMSR,A_FMRS,A_FMDRR, 849 A_FCPYS,A_FCPYD,A_FCVTSD,A_FCVTDS, 850 A_FABSS,A_FABSD,A_FSQRTS,A_FSQRTD,A_FMULS,A_FMULD, 851 A_FADDS,A_FADDD,A_FSUBS,A_FSUBD,A_FDIVS,A_FDIVD, 852 A_FMACS,A_FMACD,A_FMSCS,A_FMSCD,A_FNMACS,A_FNMACD, 853 A_FNMSCS,A_FNMSCD,A_FNMULS,A_FNMULD, 854 A_FMDHR,A_FMRDH,A_FMDLR,A_FMRDL, 855 A_FNEGS,A_FNEGD, 856 A_FSITOS,A_FSITOD,A_FTOSIS,A_FTOSID, 857 A_FTOUIS,A_FTOUID,A_FUITOS,A_FUITOD, 858 A_SXTB16,A_UXTB16, 859 A_UXTB,A_UXTH,A_SXTB,A_SXTH, 860 A_NEG, 861 A_VABS,A_VADD,A_VCVT,A_VDIV,A_VLDR,A_VMOV,A_VMUL,A_VNEG,A_VSQRT,A_VSUB, 862 A_MRS,A_MSR: 863 if opnr=0 then 864 result:=operand_write 865 else 866 result:=operand_read; 867 A_BKPT,A_B,A_BL,A_BLX,A_BX, 868 A_CMN,A_CMP,A_TEQ,A_TST, 869 A_CMF,A_CMFE,A_WFS,A_CNF, 870 A_FCMPS,A_FCMPD,A_FCMPES,A_FCMPED,A_FCMPEZS,A_FCMPEZD, 871 A_FCMPZS,A_FCMPZD, 872 A_VCMP,A_VCMPE: 873 result:=operand_read; 874 A_SMLAL,A_UMLAL: 875 if opnr in [0,1] then 876 result:=operand_readwrite 877 else 878 result:=operand_read; 879 A_SMULL,A_UMULL, 880 A_FMRRD: 881 if opnr in [0,1] then 882 result:=operand_write 883 else 884 result:=operand_read; 885 A_STR,A_STRB,A_STRBT, 886 A_STRH,A_STRT,A_STF,A_SFM, 887 A_FSTS,A_FSTD, 888 A_VSTR: 889 { important is what happens with the involved registers } 890 if opnr=0 then 891 result := operand_read 892 else 893 { check for pre/post indexed } 894 result := operand_read; 895 //Thumb2 896 A_LSL, A_LSR, A_ROR, A_ASR, A_SDIV, A_UDIV, A_MOVW, A_MOVT, A_MLS, A_BFI, 897 A_SMMLA,A_SMMLS: 898 if opnr in [0] then 899 result:=operand_write 900 else 901 result:=operand_read; 902 A_VFMA,A_VFMS,A_VFNMA,A_VFNMS, 903 A_BFC: 904 if opnr in [0] then 905 result:=operand_readwrite 906 else 907 result:=operand_read; 908 A_LDREX: 909 if opnr in [0] then 910 result:=operand_write 911 else 912 result:=operand_read; 913 A_STREX: 914 result:=operand_write; 915 else 916 internalerror(200403151); 917 end; 918 end; 919 920 taicpu.spilling_get_operation_type_refnull921 function taicpu.spilling_get_operation_type_ref(opnr: longint; reg: tregister): topertype; 922 begin 923 result := operand_read; 924 if (oper[opnr]^.ref^.base = reg) and 925 (oper[opnr]^.ref^.addressmode in [AM_PREINDEXED,AM_POSTINDEXED]) then 926 result := operand_readwrite; 927 end; 928 929 930 procedure BuildInsTabCache; 931 var 932 i : longint; 933 begin 934 new(instabcache); 935 FillChar(instabcache^,sizeof(tinstabcache),$ff); 936 i:=0; 937 while (i<InsTabEntries) do 938 begin 939 if InsTabCache^[InsTab[i].Opcode]=-1 then 940 InsTabCache^[InsTab[i].Opcode]:=i; 941 inc(i); 942 end; 943 end; 944 945 946 procedure InitAsm; 947 begin 948 if not assigned(instabcache) then 949 BuildInsTabCache; 950 end; 951 952 953 procedure DoneAsm; 954 begin 955 if assigned(instabcache) then 956 begin 957 dispose(instabcache); 958 instabcache:=nil; 959 end; 960 end; 961 962 setoppostfixnull963 function setoppostfix(i : taicpu;pf : toppostfix) : taicpu; 964 begin 965 i.oppostfix:=pf; 966 result:=i; 967 end; 968 969 setroundingmodenull970 function setroundingmode(i : taicpu;rm : troundingmode) : taicpu; 971 begin 972 i.roundingmode:=rm; 973 result:=i; 974 end; 975 976 setconditionnull977 function setcondition(i : taicpu;c : tasmcond) : taicpu; 978 begin 979 i.condition:=c; 980 result:=i; 981 end; 982 983 SimpleGetNextInstructionnull984 Function SimpleGetNextInstruction(Current: tai; Var Next: tai): Boolean; 985 Begin 986 Current:=tai(Current.Next); 987 While Assigned(Current) And (Current.typ In SkipInstr) Do 988 Current:=tai(Current.Next); 989 Next:=Current; 990 If Assigned(Next) And Not(Next.typ In SkipInstr) Then 991 Result:=True 992 Else 993 Begin 994 Next:=Nil; 995 Result:=False; 996 End; 997 End; 998 999 1000 (* 1001 function armconstequal(hp1,hp2: tai): boolean; 1002 begin 1003 result:=false; 1004 if hp1.typ<>hp2.typ then 1005 exit; 1006 case hp1.typ of 1007 tai_const: 1008 result:= 1009 (tai_const(hp2).sym=tai_const(hp).sym) and 1010 (tai_const(hp2).value=tai_const(hp).value) and 1011 (tai(hp2.previous).typ=ait_label); 1012 tai_const: 1013 result:= 1014 (tai_const(hp2).sym=tai_const(hp).sym) and 1015 (tai_const(hp2).value=tai_const(hp).value) and 1016 (tai(hp2.previous).typ=ait_label); 1017 end; 1018 end; 1019 *) 1020 1021 procedure insertpcrelativedata(list,listtoinsert : TAsmList); 1022 1023 var 1024 limit: longint; 1025 1026 { FLD/FST VFP instructions have a limit of +/- 1024, not 4096, this 1027 function checks the next count instructions if the limit must be 1028 decreased } 1029 procedure CheckLimit(hp : tai;count : integer); 1030 var 1031 i : Integer; 1032 begin 1033 for i:=1 to count do 1034 if SimpleGetNextInstruction(hp,hp) and 1035 (tai(hp).typ=ait_instruction) and 1036 ((taicpu(hp).opcode=A_FLDS) or 1037 (taicpu(hp).opcode=A_FLDD) or 1038 (taicpu(hp).opcode=A_VLDR) or 1039 (taicpu(hp).opcode=A_LDF) or 1040 (taicpu(hp).opcode=A_STF)) then 1041 limit:=254; 1042 end; 1043 is_case_dispatchnull1044 function is_case_dispatch(hp: taicpu): boolean; 1045 begin 1046 result:= 1047 ((taicpu(hp).opcode in [A_ADD,A_LDR]) and 1048 not(GenerateThumbCode or GenerateThumb2Code) and 1049 (taicpu(hp).oper[0]^.typ=top_reg) and 1050 (taicpu(hp).oper[0]^.reg=NR_PC)) or 1051 ((taicpu(hp).opcode=A_MOV) and (GenerateThumbCode) and 1052 (taicpu(hp).oper[0]^.typ=top_reg) and 1053 (taicpu(hp).oper[0]^.reg=NR_PC)) or 1054 (taicpu(hp).opcode=A_TBH) or 1055 (taicpu(hp).opcode=A_TBB); 1056 end; 1057 1058 var 1059 curinspos, 1060 penalty, 1061 lastinspos, 1062 { increased for every data element > 4 bytes inserted } 1063 extradataoffset, 1064 curop : longint; 1065 curtai, 1066 inserttai : tai; 1067 curdatatai,hp,hp2 : tai; 1068 curdata : TAsmList; 1069 l : tasmlabel; 1070 doinsert, 1071 removeref : boolean; 1072 multiplier : byte; 1073 begin 1074 curdata:=TAsmList.create; 1075 lastinspos:=-1; 1076 curinspos:=0; 1077 extradataoffset:=0; 1078 if GenerateThumbCode then 1079 begin 1080 multiplier:=2; 1081 limit:=504; 1082 end 1083 else 1084 begin 1085 limit:=1016; 1086 multiplier:=1; 1087 end; 1088 curtai:=tai(list.first); 1089 doinsert:=false; 1090 while assigned(curtai) do 1091 begin 1092 { instruction? } 1093 case curtai.typ of 1094 ait_instruction: 1095 begin 1096 { walk through all operand of the instruction } 1097 for curop:=0 to taicpu(curtai).ops-1 do 1098 begin 1099 { reference? } 1100 if (taicpu(curtai).oper[curop]^.typ=top_ref) then 1101 begin 1102 { pc relative symbol? } 1103 curdatatai:=tai(taicpu(curtai).oper[curop]^.ref^.symboldata); 1104 if assigned(curdatatai) then 1105 begin 1106 { create a new copy of a data entry on arm thumb if the entry has been inserted already 1107 before because arm thumb does not allow pc relative negative offsets } 1108 if (GenerateThumbCode) and 1109 tai_label(curdatatai).inserted then 1110 begin 1111 current_asmdata.getjumplabel(l); 1112 hp:=tai_label.create(l); 1113 listtoinsert.Concat(hp); 1114 hp2:=tai(curdatatai.Next.GetCopy); 1115 hp2.Next:=nil; 1116 hp2.Previous:=nil; 1117 listtoinsert.Concat(hp2); 1118 taicpu(curtai).oper[curop]^.ref^.symboldata:=hp; 1119 taicpu(curtai).oper[curop]^.ref^.symbol:=l; 1120 curdatatai:=hp; 1121 end; 1122 1123 { move only if we're at the first reference of a label } 1124 if not(tai_label(curdatatai).moved) then 1125 begin 1126 tai_label(curdatatai).moved:=true; 1127 { check if symbol already used. } 1128 1129 { if yes, reuse the symbol } 1130 hp:=tai(curdatatai.next); 1131 removeref:=false; 1132 if assigned(hp) then 1133 begin 1134 case hp.typ of 1135 ait_const: 1136 begin 1137 if (tai_const(hp).consttype=aitconst_64bit) then 1138 inc(extradataoffset,multiplier); 1139 end; 1140 ait_realconst: 1141 begin 1142 inc(extradataoffset,multiplier*(((tai_realconst(hp).savesize-4)+3) div 4)); 1143 end; 1144 end; 1145 { check if the same constant has been already inserted into the currently handled list, 1146 if yes, reuse it } 1147 if (hp.typ=ait_const) then 1148 begin 1149 hp2:=tai(curdata.first); 1150 while assigned(hp2) do 1151 begin 1152 if (hp2.typ=ait_const) and (tai_const(hp2).sym=tai_const(hp).sym) 1153 and (tai_const(hp2).value=tai_const(hp).value) and (tai(hp2.previous).typ=ait_label) 1154 then 1155 begin 1156 with taicpu(curtai).oper[curop]^.ref^ do 1157 begin 1158 symboldata:=hp2.previous; 1159 symbol:=tai_label(hp2.previous).labsym; 1160 end; 1161 removeref:=true; 1162 break; 1163 end; 1164 hp2:=tai(hp2.next); 1165 end; 1166 end; 1167 end; 1168 { move or remove symbol reference } 1169 repeat 1170 hp:=tai(curdatatai.next); 1171 listtoinsert.remove(curdatatai); 1172 if removeref then 1173 curdatatai.free 1174 else 1175 curdata.concat(curdatatai); 1176 curdatatai:=hp; 1177 until (curdatatai=nil) or (curdatatai.typ=ait_label); 1178 if lastinspos=-1 then 1179 lastinspos:=curinspos; 1180 end; 1181 end; 1182 end; 1183 end; 1184 inc(curinspos,multiplier); 1185 end; 1186 ait_align: 1187 begin 1188 { code is always 4 byte aligned, so we don't have to take care of .align 2 which would 1189 requires also incrementing curinspos by 1 } 1190 inc(curinspos,(tai_align(curtai).aligntype div 4)*multiplier); 1191 end; 1192 ait_const: 1193 begin 1194 inc(curinspos,multiplier); 1195 if (tai_const(curtai).consttype=aitconst_64bit) then 1196 inc(curinspos,multiplier); 1197 end; 1198 ait_realconst: 1199 begin 1200 inc(curinspos,multiplier*((tai_realconst(hp).savesize+3) div 4)); 1201 end; 1202 end; 1203 { special case for case jump tables } 1204 penalty:=0; 1205 if SimpleGetNextInstruction(curtai,hp) and 1206 (tai(hp).typ=ait_instruction) then 1207 begin 1208 case taicpu(hp).opcode of 1209 A_MOV, 1210 A_LDR, 1211 A_ADD, 1212 A_TBH, 1213 A_TBB: 1214 { approximation if we hit a case jump table } 1215 if is_case_dispatch(taicpu(hp)) then 1216 begin 1217 penalty:=multiplier; 1218 hp:=tai(hp.next); 1219 { skip register allocations and comments inserted by the optimizer as well as a label and align 1220 as jump tables for thumb might have } 1221 while assigned(hp) and (hp.typ in [ait_comment,ait_regalloc,ait_label,ait_align]) do 1222 hp:=tai(hp.next); 1223 while assigned(hp) and (hp.typ=ait_const) do 1224 begin 1225 inc(penalty,multiplier); 1226 hp:=tai(hp.next); 1227 end; 1228 end; 1229 A_IT: 1230 begin 1231 if GenerateThumb2Code then 1232 penalty:=multiplier; 1233 { check if the next instruction fits as well 1234 or if we splitted after the it so split before } 1235 CheckLimit(hp,1); 1236 end; 1237 A_ITE, 1238 A_ITT: 1239 begin 1240 if GenerateThumb2Code then 1241 penalty:=2*multiplier; 1242 { check if the next two instructions fit as well 1243 or if we splitted them so split before } 1244 CheckLimit(hp,2); 1245 end; 1246 A_ITEE, 1247 A_ITTE, 1248 A_ITET, 1249 A_ITTT: 1250 begin 1251 if GenerateThumb2Code then 1252 penalty:=3*multiplier; 1253 { check if the next three instructions fit as well 1254 or if we splitted them so split before } 1255 CheckLimit(hp,3); 1256 end; 1257 A_ITEEE, 1258 A_ITTEE, 1259 A_ITETE, 1260 A_ITTTE, 1261 A_ITEET, 1262 A_ITTET, 1263 A_ITETT, 1264 A_ITTTT: 1265 begin 1266 if GenerateThumb2Code then 1267 penalty:=4*multiplier; 1268 { check if the next three instructions fit as well 1269 or if we splitted them so split before } 1270 CheckLimit(hp,4); 1271 end; 1272 end; 1273 end; 1274 1275 CheckLimit(curtai,1); 1276 1277 { don't miss an insert } 1278 doinsert:=doinsert or 1279 (not(curdata.empty) and 1280 (curinspos-lastinspos+penalty+extradataoffset>limit)); 1281 1282 { split only at real instructions else the test below fails } 1283 if doinsert and (curtai.typ=ait_instruction) and 1284 ( 1285 { don't split loads of pc to lr and the following move } 1286 not( 1287 (taicpu(curtai).opcode=A_MOV) and 1288 (taicpu(curtai).oper[0]^.typ=top_reg) and 1289 (taicpu(curtai).oper[0]^.reg=NR_R14) and 1290 (taicpu(curtai).oper[1]^.typ=top_reg) and 1291 (taicpu(curtai).oper[1]^.reg=NR_PC) 1292 ) 1293 ) and 1294 ( 1295 { do not insert data after a B instruction due to their limited range } 1296 not((GenerateThumbCode) and 1297 (taicpu(curtai).opcode=A_B) 1298 ) 1299 ) then 1300 begin 1301 lastinspos:=-1; 1302 extradataoffset:=0; 1303 1304 if GenerateThumbCode then 1305 limit:=502 1306 else 1307 limit:=1016; 1308 1309 { if this is an add/tbh/tbb-based jumptable, go back to the 1310 previous instruction, because inserting data between the 1311 dispatch instruction and the table would mess up the 1312 addresses } 1313 inserttai:=curtai; 1314 if is_case_dispatch(taicpu(inserttai)) and 1315 ((taicpu(inserttai).opcode=A_ADD) or 1316 (taicpu(inserttai).opcode=A_TBH) or 1317 (taicpu(inserttai).opcode=A_TBB)) then 1318 begin 1319 repeat 1320 inserttai:=tai(inserttai.previous); 1321 until inserttai.typ=ait_instruction; 1322 { if it's an add-based jump table, then also skip the 1323 pc-relative load } 1324 if taicpu(curtai).opcode=A_ADD then 1325 repeat 1326 inserttai:=tai(inserttai.previous); 1327 until inserttai.typ=ait_instruction; 1328 end 1329 else 1330 1331 { on arm thumb, insert the data always after all labels etc. following an instruction so it 1332 is prevent that a bxx yyy; bl xxx; yyyy: sequence gets separated ( we never insert on arm thumb after 1333 bxx) and the distance of bxx gets too long } 1334 if GenerateThumbCode then 1335 while assigned(tai(inserttai.Next)) and (tai(inserttai.Next).typ in SkipInstr+[ait_label]) do 1336 inserttai:=tai(inserttai.next); 1337 1338 doinsert:=false; 1339 current_asmdata.getjumplabel(l); 1340 1341 { align jump in thumb .text section to 4 bytes } 1342 if not(curdata.empty) and (GenerateThumbCode) then 1343 curdata.Insert(tai_align.Create(4)); 1344 curdata.insert(taicpu.op_sym(A_B,l)); 1345 curdata.concat(tai_label.create(l)); 1346 1347 { mark all labels as inserted, arm thumb 1348 needs this, so data referencing an already inserted label can be 1349 duplicated because arm thumb does not allow negative pc relative offset } 1350 hp2:=tai(curdata.first); 1351 while assigned(hp2) do 1352 begin 1353 if hp2.typ=ait_label then 1354 tai_label(hp2).inserted:=true; 1355 hp2:=tai(hp2.next); 1356 end; 1357 1358 { continue with the last inserted label because we use later 1359 on SimpleGetNextInstruction, so if we used curtai.next (which 1360 is then equal curdata.last.previous) we could over see one 1361 instruction } 1362 hp:=tai(curdata.Last); 1363 list.insertlistafter(inserttai,curdata); 1364 curtai:=hp; 1365 end 1366 else 1367 curtai:=tai(curtai.next); 1368 end; 1369 { align jump in thumb .text section to 4 bytes } 1370 if not(curdata.empty) and (GenerateThumbCode or GenerateThumb2Code) then 1371 curdata.Insert(tai_align.Create(4)); 1372 list.concatlist(curdata); 1373 curdata.free; 1374 end; 1375 1376 1377 procedure ensurethumb2encodings(list: TAsmList); 1378 var 1379 curtai: tai; 1380 op2reg: TRegister; 1381 begin 1382 { Do Thumb-2 16bit -> 32bit transformations } 1383 curtai:=tai(list.first); 1384 while assigned(curtai) do 1385 begin 1386 case curtai.typ of 1387 ait_instruction: 1388 begin 1389 case taicpu(curtai).opcode of 1390 A_ADD: 1391 begin 1392 { Set wide flag for ADD Rd,Rn,Rm where registers are over R7(high register set) } 1393 if taicpu(curtai).ops = 3 then 1394 begin 1395 if taicpu(curtai).oper[2]^.typ in [top_reg,top_shifterop] then 1396 begin 1397 if taicpu(curtai).oper[2]^.typ = top_reg then 1398 op2reg := taicpu(curtai).oper[2]^.reg 1399 else if taicpu(curtai).oper[2]^.shifterop^.rs <> NR_NO then 1400 op2reg := taicpu(curtai).oper[2]^.shifterop^.rs 1401 else 1402 op2reg := NR_NO; 1403 1404 if op2reg <> NR_NO then 1405 begin 1406 if (taicpu(curtai).oper[0]^.reg >= NR_R8) or 1407 (taicpu(curtai).oper[1]^.reg >= NR_R8) or 1408 (op2reg >= NR_R8) then 1409 begin 1410 taicpu(curtai).wideformat:=true; 1411 1412 { Handle special cases where register rules are violated by optimizer/user } 1413 { if d == 13 || (d == 15 && S == ‘0’) || n == 15 || m IN [13,15] then UNPREDICTABLE; } 1414 1415 { Transform ADD.W Rx, Ry, R13 into ADD.W Rx, R13, Ry } 1416 if (op2reg = NR_R13) and (taicpu(curtai).oper[2]^.typ = top_reg) then 1417 begin 1418 taicpu(curtai).oper[2]^.reg := taicpu(curtai).oper[1]^.reg; 1419 taicpu(curtai).oper[1]^.reg := op2reg; 1420 end; 1421 end; 1422 end; 1423 end; 1424 end; 1425 end; 1426 end; 1427 end; 1428 end; 1429 1430 curtai:=tai(curtai.Next); 1431 end; 1432 end; 1433 1434 1435 procedure ensurethumbencodings(list: TAsmList); 1436 var 1437 curtai: tai; 1438 begin 1439 { Do Thumb 16bit transformations to form valid instruction forms } 1440 curtai:=tai(list.first); 1441 while assigned(curtai) do 1442 begin 1443 case curtai.typ of 1444 ait_instruction: 1445 begin 1446 case taicpu(curtai).opcode of 1447 A_STM: 1448 begin 1449 if (taicpu(curtai).ops=2) and 1450 (taicpu(curtai).oper[0]^.typ=top_ref) and 1451 (taicpu(curtai).oper[0]^.ref^.index=NR_STACK_POINTER_REG) and 1452 (taicpu(curtai).oper[0]^.ref^.addressmode=AM_PREINDEXED) and 1453 (taicpu(curtai).oppostfix in [PF_FD,PF_DB]) then 1454 begin 1455 taicpu(curtai).oppostfix:=PF_None; 1456 taicpu(curtai).loadregset(0, taicpu(curtai).oper[1]^.regtyp, taicpu(curtai).oper[1]^.subreg, taicpu(curtai).oper[1]^.regset^); 1457 taicpu(curtai).ops:=1; 1458 taicpu(curtai).opcode:=A_PUSH; 1459 end; 1460 end; 1461 1462 A_LDM: 1463 begin 1464 if (taicpu(curtai).ops=2) and 1465 (taicpu(curtai).oper[0]^.typ=top_ref) and 1466 (taicpu(curtai).oper[0]^.ref^.index=NR_STACK_POINTER_REG) and 1467 (taicpu(curtai).oper[0]^.ref^.addressmode=AM_PREINDEXED) and 1468 (taicpu(curtai).oppostfix in [PF_FD,PF_IA]) then 1469 begin 1470 taicpu(curtai).oppostfix:=PF_None; 1471 taicpu(curtai).loadregset(0, taicpu(curtai).oper[1]^.regtyp, taicpu(curtai).oper[1]^.subreg, taicpu(curtai).oper[1]^.regset^); 1472 taicpu(curtai).ops:=1; 1473 taicpu(curtai).opcode:=A_POP; 1474 end; 1475 end; 1476 1477 A_ADD, 1478 A_AND,A_EOR,A_ORR,A_BIC, 1479 A_LSL,A_LSR,A_ASR,A_ROR, 1480 A_ADC,A_SBC: 1481 begin 1482 if (taicpu(curtai).ops = 3) and 1483 (taicpu(curtai).oper[2]^.typ=top_reg) and 1484 (taicpu(curtai).oper[0]^.reg=taicpu(curtai).oper[1]^.reg) and 1485 (taicpu(curtai).oper[0]^.reg<>NR_STACK_POINTER_REG) then 1486 begin 1487 taicpu(curtai).oper[1]^.reg:=taicpu(curtai).oper[2]^.reg; 1488 taicpu(curtai).ops:=2; 1489 end; 1490 end; 1491 end; 1492 end; 1493 end; 1494 1495 curtai:=tai(curtai.Next); 1496 end; 1497 end; 1498 1499 getMergedInstructionnull1500 function getMergedInstruction(FirstOp,LastOp:TAsmOp;InvertLast:boolean) : TAsmOp; 1501 const 1502 opTable: array[A_IT..A_ITTTT] of string = 1503 ('T','TE','TT','TEE','TTE','TET','TTT', 1504 'TEEE','TTEE','TETE','TTTE', 1505 'TEET','TTET','TETT','TTTT'); 1506 invertedOpTable: array[A_IT..A_ITTTT] of string = 1507 ('E','ET','EE','ETT','EET','ETE','EEE', 1508 'ETTT','EETT','ETET','EEET', 1509 'ETTE','EETE','ETEE','EEEE'); 1510 var 1511 resStr : string; 1512 i : TAsmOp; 1513 begin 1514 if InvertLast then 1515 resStr := opTable[FirstOp]+invertedOpTable[LastOp] 1516 else 1517 resStr := opTable[FirstOp]+opTable[LastOp]; 1518 if length(resStr) > 4 then 1519 internalerror(2012100805); 1520 1521 for i := low(opTable) to high(opTable) do 1522 if opTable[i] = resStr then 1523 exit(i); 1524 1525 internalerror(2012100806); 1526 end; 1527 1528 procedure foldITInstructions(list: TAsmList); 1529 var 1530 curtai,hp1 : tai; 1531 levels,i : LongInt; 1532 begin 1533 curtai:=tai(list.First); 1534 while assigned(curtai) do 1535 begin 1536 case curtai.typ of 1537 ait_instruction: 1538 if IsIT(taicpu(curtai).opcode) then 1539 begin 1540 levels := GetITLevels(taicpu(curtai).opcode); 1541 if levels < 4 then 1542 begin 1543 i:=levels; 1544 hp1:=tai(curtai.Next); 1545 while assigned(hp1) and 1546 (i > 0) do 1547 begin 1548 if hp1.typ=ait_instruction then 1549 begin 1550 dec(i); 1551 if (i = 0) and 1552 mustbelast(hp1) then 1553 begin 1554 hp1:=nil; 1555 break; 1556 end; 1557 end; 1558 hp1:=tai(hp1.Next); 1559 end; 1560 1561 if assigned(hp1) then 1562 begin 1563 // We are pointing at the first instruction after the IT block 1564 while assigned(hp1) and 1565 (hp1.typ<>ait_instruction) do 1566 hp1:=tai(hp1.Next); 1567 1568 if assigned(hp1) and 1569 (hp1.typ=ait_instruction) and 1570 IsIT(taicpu(hp1).opcode) then 1571 begin 1572 if (levels+GetITLevels(taicpu(hp1).opcode) <= 4) and 1573 ((taicpu(curtai).oper[0]^.cc=taicpu(hp1).oper[0]^.cc) or 1574 (taicpu(curtai).oper[0]^.cc=inverse_cond(taicpu(hp1).oper[0]^.cc))) then 1575 begin 1576 taicpu(curtai).opcode:=getMergedInstruction(taicpu(curtai).opcode, 1577 taicpu(hp1).opcode, 1578 taicpu(curtai).oper[0]^.cc=inverse_cond(taicpu(hp1).oper[0]^.cc)); 1579 1580 list.Remove(hp1); 1581 hp1.Free; 1582 end; 1583 end; 1584 end; 1585 end; 1586 end; 1587 end; 1588 1589 curtai:=tai(curtai.Next); 1590 end; 1591 end; 1592 1593 procedure fix_invalid_imms(list: TAsmList); 1594 var 1595 curtai: tai; 1596 sh: byte; 1597 begin 1598 curtai:=tai(list.First); 1599 while assigned(curtai) do 1600 begin 1601 case curtai.typ of 1602 ait_instruction: 1603 begin 1604 if (taicpu(curtai).opcode in [A_AND,A_BIC]) and 1605 (taicpu(curtai).ops=3) and 1606 (taicpu(curtai).oper[2]^.typ=top_const) and 1607 (not is_shifter_const(taicpu(curtai).oper[2]^.val,sh)) and 1608 is_shifter_const((not taicpu(curtai).oper[2]^.val) and $FFFFFFFF,sh) then 1609 begin 1610 case taicpu(curtai).opcode of 1611 A_AND: taicpu(curtai).opcode:=A_BIC; 1612 A_BIC: taicpu(curtai).opcode:=A_AND; 1613 end; 1614 taicpu(curtai).oper[2]^.val:=(not taicpu(curtai).oper[2]^.val) and $FFFFFFFF; 1615 end 1616 else if (taicpu(curtai).opcode in [A_SUB,A_ADD]) and 1617 (taicpu(curtai).ops=3) and 1618 (taicpu(curtai).oper[2]^.typ=top_const) and 1619 (not is_shifter_const(taicpu(curtai).oper[2]^.val,sh)) and 1620 is_shifter_const(-taicpu(curtai).oper[2]^.val,sh) then 1621 begin 1622 case taicpu(curtai).opcode of 1623 A_ADD: taicpu(curtai).opcode:=A_SUB; 1624 A_SUB: taicpu(curtai).opcode:=A_ADD; 1625 end; 1626 taicpu(curtai).oper[2]^.val:=-taicpu(curtai).oper[2]^.val; 1627 end; 1628 end; 1629 end; 1630 1631 curtai:=tai(curtai.Next); 1632 end; 1633 end; 1634 1635 1636 procedure gather_it_info(list: TAsmList); 1637 var 1638 curtai: tai; 1639 in_it: boolean; 1640 it_count: longint; 1641 begin 1642 in_it:=false; 1643 it_count:=0; 1644 1645 curtai:=tai(list.First); 1646 while assigned(curtai) do 1647 begin 1648 case curtai.typ of 1649 ait_instruction: 1650 begin 1651 case taicpu(curtai).opcode of 1652 A_IT..A_ITTTT: 1653 begin 1654 if in_it then 1655 Message1(asmw_e_invalid_opcode_and_operands, 'ITxx instruction is inside another ITxx instruction') 1656 else 1657 begin 1658 in_it:=true; 1659 it_count:=GetITLevels(taicpu(curtai).opcode); 1660 end; 1661 end; 1662 else 1663 begin 1664 taicpu(curtai).inIT:=in_it; 1665 taicpu(curtai).lastinIT:=in_it and (it_count=1); 1666 1667 if in_it then 1668 begin 1669 dec(it_count); 1670 if it_count <= 0 then 1671 in_it:=false; 1672 end; 1673 end; 1674 end; 1675 end; 1676 end; 1677 1678 curtai:=tai(curtai.Next); 1679 end; 1680 end; 1681 1682 1683 { Expands pseudo instructions ( mov r1,r2,lsl #4 -> lsl r1,r2,#4) } 1684 procedure expand_instructions(list: TAsmList); 1685 var 1686 curtai: tai; 1687 begin 1688 curtai:=tai(list.First); 1689 while assigned(curtai) do 1690 begin 1691 case curtai.typ of 1692 ait_instruction: 1693 begin 1694 case taicpu(curtai).opcode of 1695 A_MOV: 1696 begin 1697 if (taicpu(curtai).ops=3) and 1698 (taicpu(curtai).oper[2]^.typ=top_shifterop) then 1699 begin 1700 case taicpu(curtai).oper[2]^.shifterop^.shiftmode of 1701 SM_LSL: taicpu(curtai).opcode:=A_LSL; 1702 SM_LSR: taicpu(curtai).opcode:=A_LSR; 1703 SM_ASR: taicpu(curtai).opcode:=A_ASR; 1704 SM_ROR: taicpu(curtai).opcode:=A_ROR; 1705 SM_RRX: taicpu(curtai).opcode:=A_RRX; 1706 end; 1707 1708 if taicpu(curtai).oper[2]^.shifterop^.shiftmode=SM_RRX then 1709 taicpu(curtai).ops:=2; 1710 1711 if taicpu(curtai).oper[2]^.shifterop^.rs=NR_NO then 1712 taicpu(curtai).loadconst(2, taicpu(curtai).oper[2]^.shifterop^.shiftimm) 1713 else 1714 taicpu(curtai).loadreg(2, taicpu(curtai).oper[2]^.shifterop^.rs); 1715 end; 1716 end; 1717 A_NEG: 1718 begin 1719 taicpu(curtai).opcode:=A_RSB; 1720 taicpu(curtai).oppostfix:=PF_S; // NEG should always set flags (according to documentation NEG<c> = RSBS<c>) 1721 1722 if taicpu(curtai).ops=2 then 1723 begin 1724 taicpu(curtai).loadconst(2,0); 1725 taicpu(curtai).ops:=3; 1726 end 1727 else 1728 begin 1729 taicpu(curtai).loadconst(1,0); 1730 taicpu(curtai).ops:=2; 1731 end; 1732 end; 1733 A_SWI: 1734 begin 1735 taicpu(curtai).opcode:=A_SVC; 1736 end; 1737 end; 1738 end; 1739 end; 1740 1741 curtai:=tai(curtai.Next); 1742 end; 1743 end; 1744 1745 1746 procedure finalizearmcode(list, listtoinsert: TAsmList); 1747 begin 1748 { Don't expand pseudo instructions when using GAS, it breaks on some thumb instructions } 1749 if target_asm.id<>as_gas then 1750 expand_instructions(list); 1751 1752 { Do Thumb-2 16bit -> 32bit transformations } 1753 if GenerateThumb2Code then 1754 begin 1755 ensurethumbencodings(list); 1756 ensurethumb2encodings(list); 1757 foldITInstructions(list); 1758 end 1759 else if GenerateThumbCode then 1760 ensurethumbencodings(list); 1761 1762 gather_it_info(list); 1763 1764 fix_invalid_imms(list); 1765 1766 insertpcrelativedata(list, listtoinsert); 1767 end; 1768 1769 procedure InsertPData; 1770 var 1771 prolog: TAsmList; 1772 begin 1773 prolog:=TAsmList.create; 1774 new_section(prolog,sec_code,'FPC_EH_PROLOG',sizeof(pint),secorder_begin); 1775 prolog.concat(Tai_const.Createname('_ARM_ExceptionHandler', 0)); 1776 prolog.concat(Tai_const.Create_32bit(0)); 1777 prolog.concat(Tai_symbol.Createname_global('FPC_EH_CODE_START',AT_METADATA,0,voidpointertype)); 1778 { dummy function } 1779 prolog.concat(taicpu.op_reg_reg(A_MOV,NR_R15,NR_R14)); 1780 current_asmdata.asmlists[al_start].insertList(prolog); 1781 prolog.Free; 1782 new_section(current_asmdata.asmlists[al_end],sec_pdata,'',sizeof(pint)); 1783 current_asmdata.asmlists[al_end].concat(Tai_const.Createname('FPC_EH_CODE_START', 0)); 1784 current_asmdata.asmlists[al_end].concat(Tai_const.Create_32bit(longint($ffffff01))); 1785 end; 1786 1787 (* 1788 Floating point instruction format information, taken from the linux kernel 1789 ARM Floating Point Instruction Classes 1790 | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 1791 |c o n d|1 1 0 P|U|u|W|L| Rn |v| Fd |0|0|0|1| o f f s e t | CPDT 1792 |c o n d|1 1 0 P|U|w|W|L| Rn |x| Fd |0|0|1|0| o f f s e t | CPDT (copro 2) 1793 | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 1794 |c o n d|1 1 1 0|a|b|c|d|e| Fn |j| Fd |0|0|0|1|f|g|h|0|i| Fm | CPDO 1795 |c o n d|1 1 1 0|a|b|c|L|e| Fn | Rd |0|0|0|1|f|g|h|1|i| Fm | CPRT 1796 |c o n d|1 1 1 0|a|b|c|1|e| Fn |1|1|1|1|0|0|0|1|f|g|h|1|i| Fm | comparisons 1797 | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 1798 1799 CPDT data transfer instructions 1800 LDF, STF, LFM (copro 2), SFM (copro 2) 1801 1802 CPDO dyadic arithmetic instructions 1803 ADF, MUF, SUF, RSF, DVF, RDF, 1804 POW, RPW, RMF, FML, FDV, FRD, POL 1805 1806 CPDO monadic arithmetic instructions 1807 MVF, MNF, ABS, RND, SQT, LOG, LGN, EXP, 1808 SIN, COS, TAN, ASN, ACS, ATN, URD, NRM 1809 1810 CPRT joint arithmetic/data transfer instructions 1811 FIX (arithmetic followed by load/store) 1812 FLT (load/store followed by arithmetic) 1813 CMF, CNF CMFE, CNFE (comparisons) 1814 WFS, RFS (write/read floating point status register) 1815 WFC, RFC (write/read floating point control register) 1816 1817 cond condition codes 1818 P pre/post index bit: 0 = postindex, 1 = preindex 1819 U up/down bit: 0 = stack grows down, 1 = stack grows up 1820 W write back bit: 1 = update base register (Rn) 1821 L load/store bit: 0 = store, 1 = load 1822 Rn base register 1823 Rd destination/source register 1824 Fd floating point destination register 1825 Fn floating point source register 1826 Fm floating point source register or floating point constant 1827 1828 uv transfer length (TABLE 1) 1829 wx register count (TABLE 2) 1830 abcd arithmetic opcode (TABLES 3 & 4) 1831 ef destination size (rounding precision) (TABLE 5) 1832 gh rounding mode (TABLE 6) 1833 j dyadic/monadic bit: 0 = dyadic, 1 = monadic 1834 i constant bit: 1 = constant (TABLE 6) 1835 */ 1836 1837 /* 1838 TABLE 1 1839 +-------------------------+---+---+---------+---------+ 1840 | Precision | u | v | FPSR.EP | length | 1841 +-------------------------+---+---+---------+---------+ 1842 | Single | 0 | 0 | x | 1 words | 1843 | Double | 1 | 1 | x | 2 words | 1844 | Extended | 1 | 1 | x | 3 words | 1845 | Packed decimal | 1 | 1 | 0 | 3 words | 1846 | Expanded packed decimal | 1 | 1 | 1 | 4 words | 1847 +-------------------------+---+---+---------+---------+ 1848 Note: x = don't care 1849 */ 1850 1851 /* 1852 TABLE 2 1853 +---+---+---------------------------------+ 1854 | w | x | Number of registers to transfer | 1855 +---+---+---------------------------------+ 1856 | 0 | 1 | 1 | 1857 | 1 | 0 | 2 | 1858 | 1 | 1 | 3 | 1859 | 0 | 0 | 4 | 1860 +---+---+---------------------------------+ 1861 */ 1862 1863 /* 1864 TABLE 3: Dyadic Floating Point Opcodes 1865 +---+---+---+---+----------+-----------------------+-----------------------+ 1866 | a | b | c | d | Mnemonic | Description | Operation | 1867 +---+---+---+---+----------+-----------------------+-----------------------+ 1868 | 0 | 0 | 0 | 0 | ADF | Add | Fd := Fn + Fm | 1869 | 0 | 0 | 0 | 1 | MUF | Multiply | Fd := Fn * Fm | 1870 | 0 | 0 | 1 | 0 | SUF | Subtract | Fd := Fn - Fm | 1871 | 0 | 0 | 1 | 1 | RSF | Reverse subtract | Fd := Fm - Fn | 1872 | 0 | 1 | 0 | 0 | DVF | Divide | Fd := Fn / Fm | 1873 | 0 | 1 | 0 | 1 | RDF | Reverse divide | Fd := Fm / Fn | 1874 | 0 | 1 | 1 | 0 | POW | Power | Fd := Fn ^ Fm | 1875 | 0 | 1 | 1 | 1 | RPW | Reverse power | Fd := Fm ^ Fn | 1876 | 1 | 0 | 0 | 0 | RMF | Remainder | Fd := IEEE rem(Fn/Fm) | 1877 | 1 | 0 | 0 | 1 | FML | Fast Multiply | Fd := Fn * Fm | 1878 | 1 | 0 | 1 | 0 | FDV | Fast Divide | Fd := Fn / Fm | 1879 | 1 | 0 | 1 | 1 | FRD | Fast reverse divide | Fd := Fm / Fn | 1880 | 1 | 1 | 0 | 0 | POL | Polar angle (ArcTan2) | Fd := arctan2(Fn,Fm) | 1881 | 1 | 1 | 0 | 1 | | undefined instruction | trap | 1882 | 1 | 1 | 1 | 0 | | undefined instruction | trap | 1883 | 1 | 1 | 1 | 1 | | undefined instruction | trap | 1884 +---+---+---+---+----------+-----------------------+-----------------------+ 1885 Note: POW, RPW, POL are deprecated, and are available for backwards 1886 compatibility only. 1887 */ 1888 1889 /* 1890 TABLE 4: Monadic Floating Point Opcodes 1891 +---+---+---+---+----------+-----------------------+-----------------------+ 1892 | a | b | c | d | Mnemonic | Description | Operation | 1893 +---+---+---+---+----------+-----------------------+-----------------------+ 1894 | 0 | 0 | 0 | 0 | MVF | Move | Fd := Fm | 1895 | 0 | 0 | 0 | 1 | MNF | Move negated | Fd := - Fm | 1896 | 0 | 0 | 1 | 0 | ABS | Absolute value | Fd := abs(Fm) | 1897 | 0 | 0 | 1 | 1 | RND | Round to integer | Fd := int(Fm) | 1898 | 0 | 1 | 0 | 0 | SQT | Square root | Fd := sqrt(Fm) | 1899 | 0 | 1 | 0 | 1 | LOG | Log base 10 | Fd := log10(Fm) | 1900 | 0 | 1 | 1 | 0 | LGN | Log base e | Fd := ln(Fm) | 1901 | 0 | 1 | 1 | 1 | EXP | Exponent | Fd := e ^ Fm | 1902 | 1 | 0 | 0 | 0 | SIN | Sine | Fd := sin(Fm) | 1903 | 1 | 0 | 0 | 1 | COS | Cosine | Fd := cos(Fm) | 1904 | 1 | 0 | 1 | 0 | TAN | Tangent | Fd := tan(Fm) | 1905 | 1 | 0 | 1 | 1 | ASN | Arc Sine | Fd := arcsin(Fm) | 1906 | 1 | 1 | 0 | 0 | ACS | Arc Cosine | Fd := arccos(Fm) | 1907 | 1 | 1 | 0 | 1 | ATN | Arc Tangent | Fd := arctan(Fm) | 1908 | 1 | 1 | 1 | 0 | URD | Unnormalized round | Fd := int(Fm) | 1909 | 1 | 1 | 1 | 1 | NRM | Normalize | Fd := norm(Fm) | 1910 +---+---+---+---+----------+-----------------------+-----------------------+ 1911 Note: LOG, LGN, EXP, SIN, COS, TAN, ASN, ACS, ATN are deprecated, and are 1912 available for backwards compatibility only. 1913 */ 1914 1915 /* 1916 TABLE 5 1917 +-------------------------+---+---+ 1918 | Rounding Precision | e | f | 1919 +-------------------------+---+---+ 1920 | IEEE Single precision | 0 | 0 | 1921 | IEEE Double precision | 0 | 1 | 1922 | IEEE Extended precision | 1 | 0 | 1923 | undefined (trap) | 1 | 1 | 1924 +-------------------------+---+---+ 1925 */ 1926 1927 /* 1928 TABLE 5 1929 +---------------------------------+---+---+ 1930 | Rounding Mode | g | h | 1931 +---------------------------------+---+---+ 1932 | Round to nearest (default) | 0 | 0 | 1933 | Round toward plus infinity | 0 | 1 | 1934 | Round toward negative infinity | 1 | 0 | 1935 | Round toward zero | 1 | 1 | 1936 +---------------------------------+---+---+ 1937 *) taicpu.GetStringnull1938 function taicpu.GetString:string; 1939 var 1940 i : longint; 1941 s : string; 1942 addsize : boolean; 1943 begin 1944 s:='['+gas_op2str[opcode]; 1945 for i:=0 to ops-1 do 1946 begin 1947 with oper[i]^ do 1948 begin 1949 if i=0 then 1950 s:=s+' ' 1951 else 1952 s:=s+','; 1953 { type } 1954 addsize:=false; 1955 if (ot and OT_VREG)=OT_VREG then 1956 s:=s+'vreg' 1957 else 1958 if (ot and OT_FPUREG)=OT_FPUREG then 1959 s:=s+'fpureg' 1960 else 1961 if (ot and OT_REGS)=OT_REGS then 1962 s:=s+'sreg' 1963 else 1964 if (ot and OT_REGF)=OT_REGF then 1965 s:=s+'creg' 1966 else 1967 if (ot and OT_REGISTER)=OT_REGISTER then 1968 begin 1969 s:=s+'reg'; 1970 addsize:=true; 1971 end 1972 else 1973 if (ot and OT_REGLIST)=OT_REGLIST then 1974 begin 1975 s:=s+'reglist'; 1976 addsize:=false; 1977 end 1978 else 1979 if (ot and OT_IMMEDIATE)=OT_IMMEDIATE then 1980 begin 1981 s:=s+'imm'; 1982 addsize:=true; 1983 end 1984 else 1985 if (ot and OT_MEMORY)=OT_MEMORY then 1986 begin 1987 s:=s+'mem'; 1988 addsize:=true; 1989 if (ot and OT_AM2)<>0 then 1990 s:=s+' am2 ' 1991 else if (ot and OT_AM6)<>0 then 1992 s:=s+' am2 '; 1993 end 1994 else 1995 if (ot and OT_SHIFTEROP)=OT_SHIFTEROP then 1996 begin 1997 s:=s+'shifterop'; 1998 addsize:=false; 1999 end 2000 else 2001 s:=s+'???'; 2002 { size } 2003 if addsize then 2004 begin 2005 if (ot and OT_BITS8)<>0 then 2006 s:=s+'8' 2007 else 2008 if (ot and OT_BITS16)<>0 then 2009 s:=s+'24' 2010 else 2011 if (ot and OT_BITS32)<>0 then 2012 s:=s+'32' 2013 else 2014 if (ot and OT_BITSSHIFTER)<>0 then 2015 s:=s+'shifter' 2016 else 2017 s:=s+'??'; 2018 { signed } 2019 if (ot and OT_SIGNED)<>0 then 2020 s:=s+'s'; 2021 end; 2022 end; 2023 end; 2024 GetString:=s+']'; 2025 end; 2026 2027 2028 procedure taicpu.ResetPass1; 2029 begin 2030 { we need to reset everything here, because the choosen insentry 2031 can be invalid for a new situation where the previously optimized 2032 insentry is not correct } 2033 InsEntry:=nil; 2034 InsSize:=0; 2035 LastInsOffset:=-1; 2036 end; 2037 2038 2039 procedure taicpu.ResetPass2; 2040 begin 2041 { we are here in a second pass, check if the instruction can be optimized } 2042 if assigned(InsEntry) and 2043 ((InsEntry^.flags and IF_PASS2)<>0) then 2044 begin 2045 InsEntry:=nil; 2046 InsSize:=0; 2047 end; 2048 LastInsOffset:=-1; 2049 end; 2050 2051 taicpu.CheckIfValidnull2052 function taicpu.CheckIfValid:boolean; 2053 begin 2054 Result:=False; { unimplemented } 2055 end; 2056 2057 taicpu.Pass1null2058 function taicpu.Pass1(objdata:TObjData):longint; 2059 var 2060 ldr2op : array[PF_B..PF_T] of tasmop = ( 2061 A_LDRB,A_LDRSB,A_LDRBT,A_LDRH,A_LDRSH,A_LDRT); 2062 str2op : array[PF_B..PF_T] of tasmop = ( 2063 A_STRB,A_None,A_STRBT,A_STRH,A_None,A_STRT); 2064 begin 2065 Pass1:=0; 2066 { Save the old offset and set the new offset } 2067 InsOffset:=ObjData.CurrObjSec.Size; 2068 { Error? } 2069 if (Insentry=nil) and (InsSize=-1) then 2070 exit; 2071 { set the file postion } 2072 current_filepos:=fileinfo; 2073 2074 { tranlate LDR+postfix to complete opcode } 2075 if (opcode=A_LDR) and (oppostfix=PF_D) then 2076 begin 2077 opcode:=A_LDRD; 2078 oppostfix:=PF_None; 2079 end 2080 else if (opcode=A_LDR) and (oppostfix<>PF_None) then 2081 begin 2082 if (oppostfix in [low(ldr2op)..high(ldr2op)]) then 2083 opcode:=ldr2op[oppostfix] 2084 else 2085 internalerror(2005091001); 2086 if opcode=A_None then 2087 internalerror(2005091004); 2088 { postfix has been added to opcode } 2089 oppostfix:=PF_None; 2090 end 2091 else if (opcode=A_STR) and (oppostfix=PF_D) then 2092 begin 2093 opcode:=A_STRD; 2094 oppostfix:=PF_None; 2095 end 2096 else if (opcode=A_STR) and (oppostfix<>PF_None) then 2097 begin 2098 if (oppostfix in [low(str2op)..high(str2op)]) then 2099 opcode:=str2op[oppostfix] 2100 else 2101 internalerror(2005091002); 2102 if opcode=A_None then 2103 internalerror(2005091003); 2104 { postfix has been added to opcode } 2105 oppostfix:=PF_None; 2106 end; 2107 2108 { Get InsEntry } 2109 if FindInsEntry(objdata) then 2110 begin 2111 InsSize:=4; 2112 2113 if insentry^.code[0] in [#$60..#$6C] then 2114 InsSize:=2; 2115 2116 LastInsOffset:=InsOffset; 2117 Pass1:=InsSize; 2118 exit; 2119 end; 2120 LastInsOffset:=-1; 2121 end; 2122 2123 2124 procedure taicpu.Pass2(objdata:TObjData); 2125 begin 2126 { error in pass1 ? } 2127 if insentry=nil then 2128 exit; 2129 current_filepos:=fileinfo; 2130 { Generate the instruction } 2131 GenCode(objdata); 2132 end; 2133 2134 2135 procedure taicpu.ppuloadoper(ppufile:tcompilerppufile;var o:toper); 2136 begin 2137 end; 2138 2139 2140 procedure taicpu.ppuwriteoper(ppufile:tcompilerppufile;const o:toper); 2141 begin 2142 end; 2143 2144 2145 procedure taicpu.ppubuildderefimploper(var o:toper); 2146 begin 2147 end; 2148 2149 2150 procedure taicpu.ppuderefoper(var o:toper); 2151 begin 2152 end; 2153 2154 2155 procedure taicpu.BuildArmMasks(objdata:TObjData); 2156 const 2157 Masks: array[tcputype] of longint = 2158 ( 2159 IF_NONE, 2160 IF_ARMv4, 2161 IF_ARMv4, 2162 IF_ARMv4T or IF_ARMv4, 2163 IF_ARMv4T or IF_ARMv4 or IF_ARMv5, 2164 IF_ARMv4T or IF_ARMv4 or IF_ARMv5 or IF_ARMv5T, 2165 IF_ARMv4T or IF_ARMv4 or IF_ARMv5 or IF_ARMv5T or IF_ARMv5TE, 2166 IF_ARMv4T or IF_ARMv4 or IF_ARMv5 or IF_ARMv5T or IF_ARMv5TE or IF_ARMv5TEJ, 2167 IF_ARMv4T or IF_ARMv4 or IF_ARMv5 or IF_ARMv5T or IF_ARMv5TE or IF_ARMv5TEJ or IF_armv6, 2168 IF_ARMv4T or IF_ARMv4 or IF_ARMv5 or IF_ARMv5T or IF_ARMv5TE or IF_ARMv5TEJ or IF_armv6 or IF_ARMv6K, 2169 IF_ARMv4T or IF_ARMv4 or IF_ARMv5 or IF_ARMv5T or IF_ARMv5TE or IF_ARMv5TEJ or IF_armv6 or IF_ARMv6K or IF_ARMv6T2, 2170 IF_ARMv4T or IF_ARMv4 or IF_ARMv5 or IF_ARMv5T or IF_ARMv5TE or IF_ARMv5TEJ or IF_armv6 or IF_ARMv6K or IF_ARMv6T2 or IF_ARMv6Z, 2171 IF_ARMv4T or IF_ARMv5T or IF_ARMv6M, 2172 IF_ARMv4T or IF_ARMv4 or IF_ARMv5 or IF_ARMv5T or IF_ARMv5TE or IF_ARMv5TEJ or IF_armv6 or IF_ARMv6K or IF_ARMv6T2 or IF_ARMv6Z or IF_ARMv7, 2173 IF_ARMv4T or IF_ARMv4 or IF_ARMv5 or IF_ARMv5T or IF_ARMv5TE or IF_ARMv5TEJ or IF_armv6 or IF_ARMv6K or IF_ARMv6T2 or IF_ARMv6Z or IF_ARMv7 or IF_ARMv7A, 2174 IF_ARMv4T or IF_ARMv4 or IF_ARMv5 or IF_ARMv5T or IF_ARMv5TE or IF_ARMv5TEJ or IF_armv6 or IF_ARMv6K or IF_ARMv6T2 or IF_ARMv6Z or IF_ARMv7 or IF_ARMv7A or IF_ARMv7R, 2175 IF_ARMv4T or IF_ARMv5T or IF_ARMv6T2 or IF_ARMv7M, 2176 IF_ARMv4T or IF_ARMv5T or IF_ARMv6T2 or IF_ARMv7M or IF_ARMv7EM 2177 ); 2178 2179 FPUMasks: array[tfputype] of longword = 2180 ( 2181 IF_NONE, 2182 IF_NONE, 2183 IF_NONE, 2184 IF_FPA, 2185 IF_FPA, 2186 IF_FPA, 2187 IF_VFPv2, 2188 IF_VFPv2 or IF_VFPv3, 2189 IF_VFPv2 or IF_VFPv3, 2190 IF_NONE, 2191 IF_VFPv2 or IF_VFPv3 or IF_VFPv4 2192 ); 2193 begin 2194 fArmVMask:=Masks[current_settings.cputype] or FPUMasks[current_settings.fputype]; 2195 2196 if objdata.ThumbFunc then 2197 //if current_settings.instructionset=is_thumb then 2198 begin 2199 fArmMask:=IF_THUMB; 2200 if CPUARM_HAS_THUMB2 in cpu_capabilities[current_settings.cputype] then 2201 fArmMask:=fArmMask or IF_THUMB32; 2202 end 2203 else 2204 fArmMask:=IF_ARM32; 2205 end; 2206 2207 taicpu.InsEndnull2208 function taicpu.InsEnd:longint; 2209 begin 2210 Result:=0; { unimplemented } 2211 end; 2212 2213 2214 procedure taicpu.create_ot(objdata:TObjData); 2215 var 2216 i,l,relsize : longint; 2217 dummy : byte; 2218 currsym : TObjSymbol; 2219 begin 2220 if ops=0 then 2221 exit; 2222 { update oper[].ot field } 2223 for i:=0 to ops-1 do 2224 with oper[i]^ do 2225 begin 2226 case typ of 2227 top_regset: 2228 begin 2229 ot:=OT_REGLIST; 2230 end; 2231 top_reg : 2232 begin 2233 case getregtype(reg) of 2234 R_INTREGISTER: 2235 begin 2236 ot:=OT_REG32 or OT_SHIFTEROP; 2237 if getsupreg(reg)<8 then 2238 ot:=ot or OT_REGLO 2239 else if reg=NR_STACK_POINTER_REG then 2240 ot:=ot or OT_REGSP; 2241 end; 2242 R_FPUREGISTER: 2243 ot:=OT_FPUREG; 2244 R_MMREGISTER: 2245 ot:=OT_VREG; 2246 R_SPECIALREGISTER: 2247 ot:=OT_REGF; 2248 else 2249 internalerror(2005090901); 2250 end; 2251 end; 2252 top_ref : 2253 begin 2254 if ref^.refaddr=addr_no then 2255 begin 2256 { create ot field } 2257 { we should get the size here dependend on the 2258 instruction } 2259 if (ot and OT_SIZE_MASK)=0 then 2260 ot:=OT_MEMORY or OT_BITS32 2261 else 2262 ot:=OT_MEMORY or (ot and OT_SIZE_MASK); 2263 if (ref^.base=NR_NO) and (ref^.index=NR_NO) then 2264 ot:=ot or OT_MEM_OFFS; 2265 { if we need to fix a reference, we do it here } 2266 2267 { pc relative addressing } 2268 if (ref^.base=NR_NO) and 2269 (ref^.index=NR_NO) and 2270 (ref^.shiftmode=SM_None) 2271 { at least we should check if the destination symbol 2272 is in a text section } 2273 { and 2274 (ref^.symbol^.owner="text") } then 2275 ref^.base:=NR_PC; 2276 2277 { determine possible address modes } 2278 if GenerateThumbCode or 2279 GenerateThumb2Code then 2280 begin 2281 if (ref^.addressmode<>AM_OFFSET) then 2282 ot:=ot or OT_AM2 2283 else if (ref^.base=NR_PC) then 2284 ot:=ot or OT_AM6 2285 else if (ref^.base=NR_STACK_POINTER_REG) then 2286 ot:=ot or OT_AM5 2287 else if ref^.index=NR_NO then 2288 ot:=ot or OT_AM4 2289 else 2290 ot:=ot or OT_AM3; 2291 end; 2292 2293 if (ref^.base<>NR_NO) and 2294 (opcode in [A_LDREX,A_LDREXB,A_LDREXH,A_LDREXD, 2295 A_STREX,A_STREXB,A_STREXH,A_STREXD]) and 2296 ( 2297 (ref^.addressmode=AM_OFFSET) and 2298 (ref^.index=NR_NO) and 2299 (ref^.shiftmode=SM_None) and 2300 (ref^.offset=0) 2301 ) then 2302 ot:=ot or OT_AM6 2303 else if (ref^.base<>NR_NO) and 2304 ( 2305 ( 2306 (ref^.index=NR_NO) and 2307 (ref^.shiftmode=SM_None) and 2308 (ref^.offset>=-4097) and 2309 (ref^.offset<=4097) 2310 ) or 2311 ( 2312 (ref^.shiftmode=SM_None) and 2313 (ref^.offset=0) 2314 ) or 2315 ( 2316 (ref^.index<>NR_NO) and 2317 (ref^.shiftmode<>SM_None) and 2318 (ref^.shiftimm<=32) and 2319 (ref^.offset=0) 2320 ) 2321 ) then 2322 ot:=ot or OT_AM2; 2323 2324 if (ref^.index<>NR_NO) and 2325 (oppostfix in [PF_None,PF_IA,PF_IB,PF_DA,PF_DB,PF_FD,PF_FA,PF_ED,PF_EA, 2326 PF_IAD,PF_DBD,PF_FDD,PF_EAD, 2327 PF_IAS,PF_DBS,PF_FDS,PF_EAS, 2328 PF_IAX,PF_DBX,PF_FDX,PF_EAX]) and 2329 ( 2330 (ref^.base=NR_NO) and 2331 (ref^.shiftmode=SM_None) and 2332 (ref^.offset=0) 2333 ) then 2334 ot:=ot or OT_AM4; 2335 2336 end 2337 else 2338 begin 2339 l:=ref^.offset; 2340 currsym:=ObjData.symbolref(ref^.symbol); 2341 if assigned(currsym) then 2342 inc(l,currsym.address); 2343 relsize:=(InsOffset+2)-l; 2344 if (relsize<-33554428) or (relsize>33554428) then 2345 ot:=OT_IMM32 2346 else 2347 ot:=OT_IMM24; 2348 end; 2349 end; 2350 top_local : 2351 begin 2352 { we should get the size here dependend on the 2353 instruction } 2354 if (ot and OT_SIZE_MASK)=0 then 2355 ot:=OT_MEMORY or OT_BITS32 2356 else 2357 ot:=OT_MEMORY or (ot and OT_SIZE_MASK); 2358 end; 2359 top_const : 2360 begin 2361 ot:=OT_IMMEDIATE; 2362 if (val=0) then 2363 ot:=ot_immediatezero 2364 else if is_shifter_const(val,dummy) then 2365 ot:=OT_IMMSHIFTER 2366 else if GenerateThumb2Code and is_thumb32_imm(val) then 2367 ot:=OT_IMMSHIFTER 2368 else 2369 ot:=OT_IMM32 2370 end; 2371 top_none : 2372 begin 2373 { generated when there was an error in the 2374 assembler reader. It never happends when generating 2375 assembler } 2376 end; 2377 top_shifterop: 2378 begin 2379 ot:=OT_SHIFTEROP; 2380 end; 2381 top_conditioncode: 2382 begin 2383 ot:=OT_CONDITION; 2384 end; 2385 top_specialreg: 2386 begin 2387 ot:=OT_REGS; 2388 end; 2389 top_modeflags: 2390 begin 2391 ot:=OT_MODEFLAGS; 2392 end; 2393 top_realconst: 2394 begin 2395 ot:=OT_IMMEDIATEMM; 2396 end; 2397 else 2398 internalerror(2004022623); 2399 end; 2400 end; 2401 end; 2402 2403 taicpu.Matchesnull2404 function taicpu.Matches(p:PInsEntry):longint; 2405 { * IF_SM stands for Size Match: any operand whose size is not 2406 * explicitly specified by the template is `really' intended to be 2407 * the same size as the first size-specified operand. 2408 * Non-specification is tolerated in the input instruction, but 2409 * _wrong_ specification is not. 2410 * 2411 * IF_SM2 invokes Size Match on only the first _two_ operands, for 2412 * three-operand instructions such as SHLD: it implies that the 2413 * first two operands must match in size, but that the third is 2414 * required to be _unspecified_. 2415 * 2416 * IF_SB invokes Size Byte: operands with unspecified size in the 2417 * template are really bytes, and so no non-byte specification in 2418 * the input instruction will be tolerated. IF_SW similarly invokes 2419 * Size Word, and IF_SD invokes Size Doubleword. 2420 * 2421 * (The default state if neither IF_SM nor IF_SM2 is specified is 2422 * that any operand with unspecified size in the template is 2423 * required to have unspecified size in the instruction too...) 2424 } 2425 var 2426 i{,j,asize,oprs} : longint; 2427 {siz : array[0..3] of longint;} 2428 begin 2429 Matches:=100; 2430 2431 { Check the opcode and operands } 2432 if (p^.opcode<>opcode) or (p^.ops<>ops) then 2433 begin 2434 Matches:=0; 2435 exit; 2436 end; 2437 2438 { check ARM instruction version } 2439 if (p^.flags and fArmVMask)=0 then 2440 begin 2441 Matches:=0; 2442 exit; 2443 end; 2444 2445 { check ARM instruction type } 2446 if (p^.flags and fArmMask)=0 then 2447 begin 2448 Matches:=0; 2449 exit; 2450 end; 2451 2452 { Check wideformat flag } 2453 if wideformat and ((p^.flags and IF_WIDE)=0) then 2454 begin 2455 matches:=0; 2456 exit; 2457 end; 2458 2459 { Check that no spurious colons or TOs are present } 2460 for i:=0 to p^.ops-1 do 2461 if (oper[i]^.ot and (not p^.optypes[i]) and (OT_COLON or OT_TO))<>0 then 2462 begin 2463 Matches:=0; 2464 exit; 2465 end; 2466 2467 { Check that the operand flags all match up } 2468 for i:=0 to p^.ops-1 do 2469 begin 2470 if ((p^.optypes[i] and (not oper[i]^.ot)) or 2471 ((p^.optypes[i] and OT_SIZE_MASK) and 2472 ((p^.optypes[i] xor oper[i]^.ot) and OT_SIZE_MASK)))<>0 then 2473 begin 2474 if ((p^.optypes[i] and (not oper[i]^.ot) and OT_NON_SIZE) or 2475 (oper[i]^.ot and OT_SIZE_MASK))<>0 then 2476 begin 2477 Matches:=0; 2478 exit; 2479 end 2480 else if ((p^.optypes[i] and OT_OPT_SIZE)<>0) and 2481 ((p^.optypes[i] and OT_OPT_SIZE)<>(oper[i]^.ot and OT_OPT_SIZE)) then 2482 begin 2483 Matches:=0; 2484 exit; 2485 end 2486 else 2487 Matches:=1; 2488 end; 2489 end; 2490 2491 { check postfixes: 2492 the existance of a certain postfix requires a 2493 particular code } 2494 2495 { update condition flags 2496 or floating point single } 2497 if (oppostfix=PF_S) and 2498 not(p^.code[0] in [#$04..#$0F,#$14..#$16,#$29,#$30,#$60..#$6B,#$80..#$82,#$A0..#$A2,#$44,#$94,#$42,#$92]) then 2499 begin 2500 Matches:=0; 2501 exit; 2502 end; 2503 2504 { floating point size } 2505 if (oppostfix in [PF_D,PF_E,PF_P,PF_EP]) and 2506 not(p^.code[0] in [ 2507 // FPA 2508 #$A0..#$A2, 2509 // old-school VFP 2510 #$42,#$92, 2511 // vldm/vstm 2512 #$44,#$94]) then 2513 begin 2514 Matches:=0; 2515 exit; 2516 end; 2517 2518 { multiple load/store address modes } 2519 if (oppostfix in [PF_IA,PF_IB,PF_DA,PF_DB,PF_FD,PF_FA,PF_ED,PF_EA]) and 2520 not(p^.code[0] in [ 2521 // ldr,str,ldrb,strb 2522 #$17, 2523 // stm,ldm 2524 #$26,#$69,#$8C, 2525 // vldm/vstm 2526 #$44,#$94 2527 ]) then 2528 begin 2529 Matches:=0; 2530 exit; 2531 end; 2532 2533 { we shouldn't see any opsize prefixes here } 2534 if (oppostfix in [PF_B,PF_SB,PF_BT,PF_H,PF_SH,PF_T]) then 2535 begin 2536 Matches:=0; 2537 exit; 2538 end; 2539 2540 if (roundingmode<>RM_None) and not(p^.code[0] in []) then 2541 begin 2542 Matches:=0; 2543 exit; 2544 end; 2545 2546 { Check thumb flags } 2547 if p^.code[0] in [#$60..#$61] then 2548 begin 2549 if (p^.code[0]=#$60) and 2550 (GenerateThumb2Code and 2551 ((not inIT) and (oppostfix<>PF_S)) or 2552 (inIT and (condition=C_None))) then 2553 begin 2554 Matches:=0; 2555 exit; 2556 end 2557 else if (p^.code[0]=#$61) and 2558 (oppostfix=PF_S) then 2559 begin 2560 Matches:=0; 2561 exit; 2562 end; 2563 end 2564 else if p^.code[0]=#$62 then 2565 begin 2566 if (GenerateThumb2Code and 2567 (condition<>C_None) and 2568 (not inIT) and 2569 (not lastinIT)) then 2570 begin 2571 Matches:=0; 2572 exit; 2573 end; 2574 end 2575 else if p^.code[0]=#$63 then 2576 begin 2577 if inIT then 2578 begin 2579 Matches:=0; 2580 exit; 2581 end; 2582 end 2583 else if p^.code[0]=#$64 then 2584 begin 2585 if (opcode=A_MUL) then 2586 begin 2587 if (ops=3) and 2588 ((oper[2]^.typ<>top_reg) or 2589 (oper[0]^.reg<>oper[2]^.reg)) then 2590 begin 2591 matches:=0; 2592 exit; 2593 end; 2594 end; 2595 end 2596 else if p^.code[0]=#$6B then 2597 begin 2598 if inIT or 2599 (oppostfix<>PF_S) then 2600 begin 2601 Matches:=0; 2602 exit; 2603 end; 2604 end; 2605 2606 { Check operand sizes } 2607 { as default an untyped size can get all the sizes, this is different 2608 from nasm, but else we need to do a lot checking which opcodes want 2609 size or not with the automatic size generation } 2610 (* 2611 asize:=longint($ffffffff); 2612 if (p^.flags and IF_SB)<>0 then 2613 asize:=OT_BITS8 2614 else if (p^.flags and IF_SW)<>0 then 2615 asize:=OT_BITS16 2616 else if (p^.flags and IF_SD)<>0 then 2617 asize:=OT_BITS32; 2618 if (p^.flags and IF_ARMASK)<>0 then 2619 begin 2620 siz[0]:=0; 2621 siz[1]:=0; 2622 siz[2]:=0; 2623 if (p^.flags and IF_AR0)<>0 then 2624 siz[0]:=asize 2625 else if (p^.flags and IF_AR1)<>0 then 2626 siz[1]:=asize 2627 else if (p^.flags and IF_AR2)<>0 then 2628 siz[2]:=asize; 2629 end 2630 else 2631 begin 2632 { we can leave because the size for all operands is forced to be 2633 the same 2634 but not if IF_SB IF_SW or IF_SD is set PM } 2635 if asize=-1 then 2636 exit; 2637 siz[0]:=asize; 2638 siz[1]:=asize; 2639 siz[2]:=asize; 2640 end; 2641 2642 if (p^.flags and (IF_SM or IF_SM2))<>0 then 2643 begin 2644 if (p^.flags and IF_SM2)<>0 then 2645 oprs:=2 2646 else 2647 oprs:=p^.ops; 2648 for i:=0 to oprs-1 do 2649 if ((p^.optypes[i] and OT_SIZE_MASK) <> 0) then 2650 begin 2651 for j:=0 to oprs-1 do 2652 siz[j]:=p^.optypes[i] and OT_SIZE_MASK; 2653 break; 2654 end; 2655 end 2656 else 2657 oprs:=2; 2658 2659 { Check operand sizes } 2660 for i:=0 to p^.ops-1 do 2661 begin 2662 if ((p^.optypes[i] and OT_SIZE_MASK)=0) and 2663 ((oper[i]^.ot and OT_SIZE_MASK and (not siz[i]))<>0) and 2664 { Immediates can always include smaller size } 2665 ((oper[i]^.ot and OT_IMMEDIATE)=0) and 2666 (((p^.optypes[i] and OT_SIZE_MASK) or siz[i])<(oper[i]^.ot and OT_SIZE_MASK)) then 2667 Matches:=2; 2668 end; 2669 *) 2670 end; 2671 2672 taicpu.calcsizenull2673 function taicpu.calcsize(p:PInsEntry):shortint; 2674 begin 2675 result:=4; 2676 end; 2677 2678 taicpu.NeedAddrPrefixnull2679 function taicpu.NeedAddrPrefix(opidx:byte):boolean; 2680 begin 2681 Result:=False; { unimplemented } 2682 end; 2683 2684 2685 procedure taicpu.Swapoperands; 2686 begin 2687 end; 2688 2689 taicpu.FindInsentrynull2690 function taicpu.FindInsentry(objdata:TObjData):boolean; 2691 var 2692 i : longint; 2693 begin 2694 result:=false; 2695 { Things which may only be done once, not when a second pass is done to 2696 optimize } 2697 if (Insentry=nil) or ((InsEntry^.flags and IF_PASS2)<>0) then 2698 begin 2699 { create the .ot fields } 2700 create_ot(objdata); 2701 2702 BuildArmMasks(objdata); 2703 { set the file postion } 2704 current_filepos:=fileinfo; 2705 end 2706 else 2707 begin 2708 { we've already an insentry so it's valid } 2709 result:=true; 2710 exit; 2711 end; 2712 { Lookup opcode in the table } 2713 InsSize:=-1; 2714 i:=instabcache^[opcode]; 2715 if i=-1 then 2716 begin 2717 Message1(asmw_e_opcode_not_in_table,gas_op2str[opcode]); 2718 exit; 2719 end; 2720 insentry:=@instab[i]; 2721 while (insentry^.opcode=opcode) do 2722 begin 2723 if matches(insentry)=100 then 2724 begin 2725 result:=true; 2726 exit; 2727 end; 2728 inc(i); 2729 insentry:=@instab[i]; 2730 end; 2731 Message1(asmw_e_invalid_opcode_and_operands,GetString); 2732 { No instruction found, set insentry to nil and inssize to -1 } 2733 insentry:=nil; 2734 inssize:=-1; 2735 end; 2736 2737 2738 procedure taicpu.gencode(objdata:TObjData); 2739 const 2740 CondVal : array[TAsmCond] of byte=( 2741 $E, $0, $1, $2, $3, $4, $5, $6, $7, $8, $9, $A, 2742 $B, $C, $D, $E, 0); 2743 var 2744 bytes, rd, rm, rn, d, m, n : dword; 2745 bytelen : longint; 2746 dp_operation : boolean; 2747 i_field : byte; 2748 currsym : TObjSymbol; 2749 offset : longint; 2750 refoper : poper; 2751 msb : longint; 2752 r: byte; 2753 singlerec : tcompsinglerec; 2754 doublerec : tcompdoublerec; 2755 2756 procedure setshifterop(op : byte); 2757 var 2758 r : byte; 2759 imm : dword; 2760 count : integer; 2761 begin 2762 case oper[op]^.typ of 2763 top_const: 2764 begin 2765 i_field:=1; 2766 if oper[op]^.val and $ff=oper[op]^.val then 2767 bytes:=bytes or dword(oper[op]^.val) 2768 else 2769 begin 2770 { calc rotate and adjust imm } 2771 count:=0; 2772 r:=0; 2773 imm:=dword(oper[op]^.val); 2774 repeat 2775 imm:=RolDWord(imm, 2); 2776 inc(r); 2777 inc(count); 2778 if count > 32 then 2779 begin 2780 message1(asmw_e_invalid_opcode_and_operands, 'invalid shifter imm'); 2781 exit; 2782 end; 2783 until (imm and $ff)=imm; 2784 bytes:=bytes or (r shl 8) or imm; 2785 end; 2786 end; 2787 top_reg: 2788 begin 2789 i_field:=0; 2790 bytes:=bytes or getsupreg(oper[op]^.reg); 2791 2792 { does a real shifter op follow? } 2793 if (op+1<opercnt) and (oper[op+1]^.typ=top_shifterop) then 2794 with oper[op+1]^.shifterop^ do 2795 begin 2796 bytes:=bytes or ((shiftimm and $1F) shl 7); 2797 if shiftmode<>SM_RRX then 2798 bytes:=bytes or (ord(shiftmode) - ord(SM_LSL)) shl 5 2799 else 2800 bytes:=bytes or (3 shl 5); 2801 if getregtype(rs) <> R_INVALIDREGISTER then 2802 begin 2803 bytes:=bytes or (1 shl 4); 2804 bytes:=bytes or (getsupreg(rs) shl 8); 2805 end 2806 end; 2807 end; 2808 else 2809 internalerror(2005091103); 2810 end; 2811 end; 2812 MakeRegListnull2813 function MakeRegList(reglist: tcpuregisterset): word; 2814 var 2815 i, w: integer; 2816 begin 2817 result:=0; 2818 w:=0; 2819 for i:=RS_R0 to RS_R15 do 2820 begin 2821 if i in reglist then 2822 result:=result or (1 shl w); 2823 inc(w); 2824 end; 2825 end; 2826 getcoprocnull2827 function getcoproc(reg: tregister): byte; 2828 begin 2829 if reg=NR_p15 then 2830 result:=15 2831 else 2832 begin 2833 Message1(asmw_e_invalid_opcode_and_operands,'Invalid coprocessor port'); 2834 result:=0; 2835 end; 2836 end; 2837 getcoprocregnull2838 function getcoprocreg(reg: tregister): byte; 2839 var 2840 tmpr: tregister; 2841 begin 2842 { FIXME: temp variable r is needed here to avoid Internal error 20060521 } 2843 { while compiling the compiler. } 2844 tmpr:=NR_CR0; 2845 result:=getsupreg(reg)-getsupreg(tmpr); 2846 end; 2847 getmmregnull2848 function getmmreg(reg: tregister): byte; 2849 begin 2850 case reg of 2851 NR_D0: result:=0; 2852 NR_D1: result:=1; 2853 NR_D2: result:=2; 2854 NR_D3: result:=3; 2855 NR_D4: result:=4; 2856 NR_D5: result:=5; 2857 NR_D6: result:=6; 2858 NR_D7: result:=7; 2859 NR_D8: result:=8; 2860 NR_D9: result:=9; 2861 NR_D10: result:=10; 2862 NR_D11: result:=11; 2863 NR_D12: result:=12; 2864 NR_D13: result:=13; 2865 NR_D14: result:=14; 2866 NR_D15: result:=15; 2867 NR_D16: result:=16; 2868 NR_D17: result:=17; 2869 NR_D18: result:=18; 2870 NR_D19: result:=19; 2871 NR_D20: result:=20; 2872 NR_D21: result:=21; 2873 NR_D22: result:=22; 2874 NR_D23: result:=23; 2875 NR_D24: result:=24; 2876 NR_D25: result:=25; 2877 NR_D26: result:=26; 2878 NR_D27: result:=27; 2879 NR_D28: result:=28; 2880 NR_D29: result:=29; 2881 NR_D30: result:=30; 2882 NR_D31: result:=31; 2883 2884 NR_S0: result:=0; 2885 NR_S1: result:=1; 2886 NR_S2: result:=2; 2887 NR_S3: result:=3; 2888 NR_S4: result:=4; 2889 NR_S5: result:=5; 2890 NR_S6: result:=6; 2891 NR_S7: result:=7; 2892 NR_S8: result:=8; 2893 NR_S9: result:=9; 2894 NR_S10: result:=10; 2895 NR_S11: result:=11; 2896 NR_S12: result:=12; 2897 NR_S13: result:=13; 2898 NR_S14: result:=14; 2899 NR_S15: result:=15; 2900 NR_S16: result:=16; 2901 NR_S17: result:=17; 2902 NR_S18: result:=18; 2903 NR_S19: result:=19; 2904 NR_S20: result:=20; 2905 NR_S21: result:=21; 2906 NR_S22: result:=22; 2907 NR_S23: result:=23; 2908 NR_S24: result:=24; 2909 NR_S25: result:=25; 2910 NR_S26: result:=26; 2911 NR_S27: result:=27; 2912 NR_S28: result:=28; 2913 NR_S29: result:=29; 2914 NR_S30: result:=30; 2915 NR_S31: result:=31; 2916 else 2917 result:=0; 2918 end; 2919 end; 2920 2921 procedure encodethumbimm(imm: longword); 2922 var 2923 imm12, tmp: tcgint; 2924 shift: integer; 2925 found: boolean; 2926 begin 2927 found:=true; 2928 if (imm and $FF) = imm then 2929 imm12:=imm 2930 else if ((imm shr 16)=(imm and $FFFF)) and 2931 ((imm and $FF00FF00) = 0) then 2932 imm12:=(imm and $ff) or ($1 shl 8) 2933 else if ((imm shr 16)=(imm and $FFFF)) and 2934 ((imm and $00FF00FF) = 0) then 2935 imm12:=((imm shr 8) and $ff) or ($2 shl 8) 2936 else if ((imm shr 16)=(imm and $FFFF)) and 2937 (((imm shr 8) and $FF)=(imm and $FF)) then 2938 imm12:=(imm and $ff) or ($3 shl 8) 2939 else 2940 begin 2941 found:=false; 2942 imm12:=0; 2943 for shift:=1 to 31 do 2944 begin 2945 tmp:=RolDWord(imm,shift); 2946 if ((tmp and $FF)=tmp) and 2947 ((tmp and $80)=$80) then 2948 begin 2949 imm12:=(tmp and $7F) or (shift shl 7); 2950 found:=true; 2951 break; 2952 end; 2953 end; 2954 end; 2955 2956 if found then 2957 begin 2958 bytes:=bytes or (imm12 and $FF); 2959 bytes:=bytes or (((imm12 shr 8) and $7) shl 12); 2960 bytes:=bytes or (((imm12 shr 11) and $1) shl 26); 2961 end 2962 else 2963 Message1(asmw_e_value_exceeds_bounds, IntToStr(imm)); 2964 end; 2965 2966 procedure setthumbshift(op: byte; is_sat: boolean = false); 2967 var 2968 shift,typ: byte; 2969 begin 2970 shift:=0; 2971 typ:=0; 2972 case oper[op]^.shifterop^.shiftmode of 2973 SM_LSL: begin typ:=0; shift:=oper[op]^.shifterop^.shiftimm; end; 2974 SM_LSR: begin typ:=1; shift:=oper[op]^.shifterop^.shiftimm; if shift=32 then shift:=0; end; 2975 SM_ASR: begin typ:=2; shift:=oper[op]^.shifterop^.shiftimm; if shift=32 then shift:=0; end; 2976 SM_ROR: begin typ:=3; shift:=oper[op]^.shifterop^.shiftimm; if shift=0 then message(asmw_e_invalid_opcode_and_operands); end; 2977 SM_RRX: begin typ:=3; shift:=0; end; 2978 end; 2979 2980 if is_sat then 2981 begin 2982 bytes:=bytes or ((typ and 1) shl 5); 2983 bytes:=bytes or ((typ shr 1) shl 21); 2984 end 2985 else 2986 bytes:=bytes or (typ shl 4); 2987 bytes:=bytes or (shift and $3) shl 6; 2988 bytes:=bytes or ((shift and $1C) shr 2) shl 12; 2989 end; 2990 2991 begin 2992 bytes:=$0; 2993 bytelen:=4; 2994 i_field:=0; 2995 { evaluate and set condition code } 2996 bytes:=bytes or (CondVal[condition] shl 28); 2997 2998 { condition code allowed? } 2999 3000 { setup rest of the instruction } 3001 case insentry^.code[0] of 3002 #$01: // B/BL 3003 begin 3004 { set instruction code } 3005 bytes:=bytes or (ord(insentry^.code[1]) shl 24); 3006 { set offset } 3007 if oper[0]^.typ=top_const then 3008 bytes:=bytes or ((oper[0]^.val shr 2) and $ffffff) 3009 else 3010 begin 3011 currsym:=objdata.symbolref(oper[0]^.ref^.symbol); 3012 3013 bytes:=bytes or (((oper[0]^.ref^.offset-8) shr 2) and $ffffff); 3014 3015 if (opcode<>A_BL) or (condition<>C_None) then 3016 objdata.writereloc(aint(bytes),4,currsym,RELOC_RELATIVE_24) 3017 else 3018 objdata.writereloc(aint(bytes),4,currsym,RELOC_RELATIVE_CALL); 3019 3020 exit; 3021 end; 3022 end; 3023 #$02: 3024 begin 3025 { set instruction code } 3026 bytes:=bytes or (ord(insentry^.code[1]) shl 24); 3027 { set code } 3028 bytes:=bytes or (oper[0]^.val and $FFFFFF); 3029 end; 3030 #$03: 3031 begin // BLX/BX 3032 bytes:=bytes or (ord(insentry^.code[1]) shl 24); 3033 bytes:=bytes or (ord(insentry^.code[2]) shl 16); 3034 bytes:=bytes or (ord(insentry^.code[3]) shl 8); 3035 bytes:=bytes or ord(insentry^.code[4]); 3036 3037 bytes:=bytes or getsupreg(oper[0]^.reg); 3038 end; 3039 #$04..#$07: // SUB 3040 begin 3041 { set instruction code } 3042 bytes:=bytes or (ord(insentry^.code[1]) shl 24); 3043 bytes:=bytes or (ord(insentry^.code[2]) shl 16); 3044 { set destination } 3045 bytes:=bytes or (getsupreg(oper[0]^.reg) shl 12); 3046 { set Rn } 3047 bytes:=bytes or (getsupreg(oper[1]^.reg) shl 16); 3048 { create shifter op } 3049 setshifterop(2); 3050 { set I field } 3051 bytes:=bytes or (i_field shl 25); 3052 { set S if necessary } 3053 if oppostfix=PF_S then 3054 bytes:=bytes or (1 shl 20); 3055 end; 3056 #$08,#$0A,#$0B: // MOV 3057 begin 3058 { set instruction code } 3059 bytes:=bytes or (ord(insentry^.code[1]) shl 24); 3060 bytes:=bytes or (ord(insentry^.code[2]) shl 16); 3061 { set destination } 3062 bytes:=bytes or (getsupreg(oper[0]^.reg) shl 12); 3063 { create shifter op } 3064 setshifterop(1); 3065 { set I field } 3066 bytes:=bytes or (i_field shl 25); 3067 { set S if necessary } 3068 if oppostfix=PF_S then 3069 bytes:=bytes or (1 shl 20); 3070 end; 3071 #$0C,#$0E,#$0F: // CMP 3072 begin 3073 { set instruction code } 3074 bytes:=bytes or (ord(insentry^.code[1]) shl 24); 3075 bytes:=bytes or (ord(insentry^.code[2]) shl 16); 3076 { set destination } 3077 bytes:=bytes or (getsupreg(oper[0]^.reg) shl 16); 3078 { create shifter op } 3079 setshifterop(1); 3080 { set I field } 3081 bytes:=bytes or (i_field shl 25); 3082 { always set S bit } 3083 bytes:=bytes or (1 shl 20); 3084 end; 3085 #$10: // MRS 3086 begin 3087 { set instruction code } 3088 bytes:=bytes or (ord(insentry^.code[1]) shl 24); 3089 bytes:=bytes or (ord(insentry^.code[2]) shl 16); 3090 { set destination } 3091 bytes:=bytes or (getsupreg(oper[0]^.reg) shl 12); 3092 3093 case oper[1]^.reg of 3094 NR_APSR,NR_CPSR:; 3095 NR_SPSR: 3096 begin 3097 bytes:=bytes or (1 shl 22); 3098 end; 3099 else 3100 Message(asmw_e_invalid_opcode_and_operands); 3101 end; 3102 end; 3103 #$12,#$13: // MSR 3104 begin 3105 { set instruction code } 3106 bytes:=bytes or (ord(insentry^.code[1]) shl 24); 3107 bytes:=bytes or (ord(insentry^.code[2]) shl 16); 3108 bytes:=bytes or (ord(insentry^.code[3]) shl 8); 3109 { set destination } 3110 3111 if oper[0]^.typ=top_specialreg then 3112 begin 3113 if (oper[0]^.specialreg<>NR_CPSR) and 3114 (oper[0]^.specialreg<>NR_SPSR) then 3115 Message1(asmw_e_invalid_opcode_and_operands, '"Invalid special reg"'); 3116 3117 if srC in oper[0]^.specialflags then 3118 bytes:=bytes or (1 shl 16); 3119 if srX in oper[0]^.specialflags then 3120 bytes:=bytes or (1 shl 17); 3121 if srS in oper[0]^.specialflags then 3122 bytes:=bytes or (1 shl 18); 3123 if srF in oper[0]^.specialflags then 3124 bytes:=bytes or (1 shl 19); 3125 3126 { Set R bit } 3127 if oper[0]^.specialreg=NR_SPSR then 3128 bytes:=bytes or (1 shl 22); 3129 end 3130 else 3131 case oper[0]^.reg of 3132 NR_APSR_nzcvq: bytes:=bytes or (2 shl 18); 3133 NR_APSR_g: bytes:=bytes or (1 shl 18); 3134 NR_APSR_nzcvqg: bytes:=bytes or (3 shl 18); 3135 else 3136 Message1(asmw_e_invalid_opcode_and_operands, 'Invalid combination APSR bits used'); 3137 end; 3138 3139 setshifterop(1); 3140 end; 3141 #$14: // MUL/MLA r1,r2,r3 3142 begin 3143 { set instruction code } 3144 bytes:=bytes or ord(insentry^.code[1]) shl 24; 3145 bytes:=bytes or ord(insentry^.code[2]) shl 16; 3146 bytes:=bytes or ord(insentry^.code[3]); 3147 { set regs } 3148 bytes:=bytes or getsupreg(oper[0]^.reg) shl 16; 3149 bytes:=bytes or getsupreg(oper[1]^.reg); 3150 bytes:=bytes or getsupreg(oper[2]^.reg) shl 8; 3151 3152 if oppostfix in [PF_S] then 3153 bytes:=bytes or (1 shl 20); 3154 end; 3155 #$15: // MUL/MLA r1,r2,r3,r4 3156 begin 3157 { set instruction code } 3158 bytes:=bytes or ord(insentry^.code[1]) shl 24; 3159 bytes:=bytes or ord(insentry^.code[2]) shl 16; 3160 bytes:=bytes or ord(insentry^.code[3]) shl 4; 3161 { set regs } 3162 bytes:=bytes or getsupreg(oper[0]^.reg) shl 16; 3163 bytes:=bytes or getsupreg(oper[1]^.reg); 3164 bytes:=bytes or getsupreg(oper[2]^.reg) shl 8; 3165 if ops>3 then 3166 bytes:=bytes or getsupreg(oper[3]^.reg) shl 12 3167 else 3168 bytes:=bytes or ord(insentry^.code[4]) shl 12; 3169 3170 if oppostfix in [PF_R,PF_X] then 3171 bytes:=bytes or (1 shl 5); 3172 3173 if oppostfix in [PF_S] then 3174 bytes:=bytes or (1 shl 20); 3175 end; 3176 #$16: // MULL r1,r2,r3,r4 3177 begin 3178 { set instruction code } 3179 bytes:=bytes or ord(insentry^.code[1]) shl 24; 3180 bytes:=bytes or ord(insentry^.code[2]) shl 16; 3181 bytes:=bytes or ord(insentry^.code[3]) shl 4; 3182 { set regs } 3183 bytes:=bytes or getsupreg(oper[0]^.reg) shl 12; 3184 3185 if (ops=3) and (opcode=A_PKHTB) then 3186 begin 3187 bytes:=bytes or getsupreg(oper[1]^.reg); 3188 bytes:=bytes or getsupreg(oper[2]^.reg) shl 16; 3189 end 3190 else 3191 begin 3192 bytes:=bytes or getsupreg(oper[1]^.reg) shl 16; 3193 bytes:=bytes or getsupreg(oper[2]^.reg); 3194 end; 3195 3196 if ops=4 then 3197 begin 3198 if oper[3]^.typ=top_shifterop then 3199 begin 3200 if opcode in [A_PKHBT,A_PKHTB] then 3201 begin 3202 if ((opcode=A_PKHTB) and 3203 (oper[3]^.shifterop^.shiftmode <> SM_ASR)) or 3204 ((opcode=A_PKHBT) and 3205 (oper[3]^.shifterop^.shiftmode <> SM_LSL)) or 3206 (oper[3]^.shifterop^.rs<>NR_NO) then 3207 Message1(asmw_e_invalid_opcode_and_operands,GetString); 3208 3209 bytes:=bytes or ((oper[3]^.shifterop^.shiftimm and $1F) shl 7); 3210 end 3211 else 3212 begin 3213 if (oper[3]^.shifterop^.shiftmode<>sm_ror) or 3214 (oper[3]^.shifterop^.rs<>NR_NO) or 3215 (not (oper[3]^.shifterop^.shiftimm in [0,8,16,24])) then 3216 Message1(asmw_e_invalid_opcode_and_operands,GetString); 3217 3218 bytes:=bytes or (((oper[3]^.shifterop^.shiftimm shr 3) and $3) shl 10); 3219 end; 3220 end 3221 else 3222 bytes:=bytes or getsupreg(oper[3]^.reg) shl 8; 3223 end; 3224 3225 if PF_S=oppostfix then 3226 bytes:=bytes or (1 shl 20); 3227 if PF_X=oppostfix then 3228 bytes:=bytes or (1 shl 5); 3229 end; 3230 #$17: // LDR/STR 3231 begin 3232 { set instruction code } 3233 bytes:=bytes or (ord(insentry^.code[1]) shl 24); 3234 bytes:=bytes or (ord(insentry^.code[2]) shl 16); 3235 { set Rn and Rd } 3236 bytes:=bytes or getsupreg(oper[0]^.reg) shl 12; 3237 bytes:=bytes or getsupreg(oper[1]^.ref^.base) shl 16; 3238 if getregtype(oper[1]^.ref^.index)=R_INVALIDREGISTER then 3239 begin 3240 { set offset } 3241 offset:=0; 3242 currsym:=objdata.symbolref(oper[1]^.ref^.symbol); 3243 if assigned(currsym) then 3244 offset:=currsym.offset-insoffset-8; 3245 offset:=offset+oper[1]^.ref^.offset; 3246 if offset>=0 then 3247 { set U flag } 3248 bytes:=bytes or (1 shl 23) 3249 else 3250 offset:=-offset; 3251 bytes:=bytes or (offset and $FFF); 3252 end 3253 else 3254 begin 3255 { set U flag } 3256 if oper[1]^.ref^.signindex>=0 then 3257 bytes:=bytes or (1 shl 23); 3258 { set I flag } 3259 bytes:=bytes or (1 shl 25); 3260 bytes:=bytes or getsupreg(oper[1]^.ref^.index); 3261 { set shift } 3262 with oper[1]^.ref^ do 3263 if shiftmode<>SM_None then 3264 begin 3265 bytes:=bytes or ((shiftimm and $1F) shl 7); 3266 if shiftmode<>SM_RRX then 3267 bytes:=bytes or (ord(shiftmode) - ord(SM_LSL)) shl 5 3268 else 3269 bytes:=bytes or (3 shl 5); 3270 end 3271 end; 3272 { set W bit } 3273 if oper[1]^.ref^.addressmode=AM_PREINDEXED then 3274 bytes:=bytes or (1 shl 21); 3275 { set P bit if necessary } 3276 if oper[1]^.ref^.addressmode<>AM_POSTINDEXED then 3277 bytes:=bytes or (1 shl 24); 3278 end; 3279 #$18: // LDREX/STREX 3280 begin 3281 { set instruction code } 3282 bytes:=bytes or (ord(insentry^.code[1]) shl 24); 3283 bytes:=bytes or (ord(insentry^.code[2]) shl 16); 3284 bytes:=bytes or (ord(insentry^.code[3]) shl 8); 3285 bytes:=bytes or ord(insentry^.code[4]); 3286 { set Rn and Rd } 3287 bytes:=bytes or getsupreg(oper[0]^.reg) shl 12; 3288 if (ops=3) then 3289 begin 3290 if opcode<>A_LDREXD then 3291 bytes:=bytes or getsupreg(oper[1]^.reg); 3292 3293 bytes:=bytes or (getsupreg(oper[2]^.ref^.base) shl 16); 3294 end 3295 else if (ops=4) then // STREXD 3296 begin 3297 if opcode<>A_LDREXD then 3298 bytes:=bytes or getsupreg(oper[1]^.reg); 3299 3300 bytes:=bytes or (getsupreg(oper[3]^.ref^.base) shl 16); 3301 end 3302 else 3303 bytes:=bytes or (getsupreg(oper[1]^.ref^.base) shl 16); 3304 end; 3305 #$19: // LDRD/STRD 3306 begin 3307 { set instruction code } 3308 bytes:=bytes or (ord(insentry^.code[1]) shl 24); 3309 bytes:=bytes or (ord(insentry^.code[2]) shl 16); 3310 bytes:=bytes or (ord(insentry^.code[3]) shl 8); 3311 bytes:=bytes or ord(insentry^.code[4]); 3312 { set Rn and Rd } 3313 bytes:=bytes or getsupreg(oper[0]^.reg) shl 12; 3314 3315 refoper:=oper[1]; 3316 if ops=3 then 3317 refoper:=oper[2]; 3318 3319 bytes:=bytes or getsupreg(refoper^.ref^.base) shl 16; 3320 if getregtype(refoper^.ref^.index)=R_INVALIDREGISTER then 3321 begin 3322 bytes:=bytes or (1 shl 22); 3323 { set offset } 3324 offset:=0; 3325 currsym:=objdata.symbolref(refoper^.ref^.symbol); 3326 if assigned(currsym) then 3327 offset:=currsym.offset-insoffset-8; 3328 offset:=offset+refoper^.ref^.offset; 3329 if offset>=0 then 3330 { set U flag } 3331 bytes:=bytes or (1 shl 23) 3332 else 3333 offset:=-offset; 3334 bytes:=bytes or (offset and $F); 3335 bytes:=bytes or ((offset and $F0) shl 4); 3336 end 3337 else 3338 begin 3339 { set U flag } 3340 if refoper^.ref^.signindex>=0 then 3341 bytes:=bytes or (1 shl 23); 3342 bytes:=bytes or getsupreg(refoper^.ref^.index); 3343 end; 3344 { set W bit } 3345 if refoper^.ref^.addressmode=AM_PREINDEXED then 3346 bytes:=bytes or (1 shl 21); 3347 { set P bit if necessary } 3348 if refoper^.ref^.addressmode<>AM_POSTINDEXED then 3349 bytes:=bytes or (1 shl 24); 3350 end; 3351 #$1A: // QADD/QSUB 3352 begin 3353 { set instruction code } 3354 bytes:=bytes or ord(insentry^.code[1]) shl 24; 3355 bytes:=bytes or ord(insentry^.code[2]) shl 16; 3356 bytes:=bytes or ord(insentry^.code[3]) shl 4; 3357 { set regs } 3358 bytes:=bytes or getsupreg(oper[0]^.reg) shl 12; 3359 bytes:=bytes or getsupreg(oper[1]^.reg) shl 0; 3360 bytes:=bytes or getsupreg(oper[2]^.reg) shl 16; 3361 end; 3362 #$1B: 3363 begin 3364 { set instruction code } 3365 bytes:=bytes or ord(insentry^.code[1]) shl 24; 3366 bytes:=bytes or ord(insentry^.code[2]) shl 16; 3367 bytes:=bytes or ord(insentry^.code[3]) shl 4; 3368 { set regs } 3369 bytes:=bytes or getsupreg(oper[0]^.reg) shl 12; 3370 bytes:=bytes or getsupreg(oper[1]^.reg); 3371 if ops=3 then 3372 begin 3373 if (oper[2]^.shifterop^.shiftmode<>sm_ror) or 3374 (oper[2]^.shifterop^.rs<>NR_NO) or 3375 (not (oper[2]^.shifterop^.shiftimm in [0,8,16,24])) then 3376 Message1(asmw_e_invalid_opcode_and_operands,GetString); 3377 3378 bytes:=bytes or (((oper[2]^.shifterop^.shiftimm shr 3) and $3) shl 10); 3379 end; 3380 end; 3381 #$1C: // MCR/MRC 3382 begin 3383 { set instruction code } 3384 bytes:=bytes or ord(insentry^.code[1]) shl 24; 3385 bytes:=bytes or ord(insentry^.code[2]) shl 16; 3386 bytes:=bytes or ord(insentry^.code[3]) shl 4; 3387 { set regs and operands } 3388 bytes:=bytes or getcoproc(oper[0]^.reg) shl 8; 3389 bytes:=bytes or ((oper[1]^.val and $7) shl 21); 3390 bytes:=bytes or getsupreg(oper[2]^.reg) shl 12; 3391 bytes:=bytes or getcoprocreg(oper[3]^.reg) shl 16; 3392 bytes:=bytes or getcoprocreg(oper[4]^.reg); 3393 if ops > 5 then 3394 bytes:=bytes or ((oper[5]^.val and $7) shl 5); 3395 end; 3396 #$1D: // MCRR/MRRC 3397 begin 3398 { set instruction code } 3399 bytes:=bytes or ord(insentry^.code[1]) shl 24; 3400 bytes:=bytes or ord(insentry^.code[2]) shl 16; 3401 bytes:=bytes or ord(insentry^.code[3]) shl 4; 3402 { set regs and operands } 3403 bytes:=bytes or getcoproc(oper[0]^.reg) shl 8; 3404 bytes:=bytes or ((oper[1]^.val and $7) shl 4); 3405 bytes:=bytes or getsupreg(oper[2]^.reg) shl 12; 3406 bytes:=bytes or getsupreg(oper[3]^.reg) shl 16; 3407 bytes:=bytes or getcoprocreg(oper[4]^.reg); 3408 end; 3409 #$1E: // LDRHT/STRHT 3410 begin 3411 { set instruction code } 3412 bytes:=bytes or (ord(insentry^.code[1]) shl 24); 3413 bytes:=bytes or (ord(insentry^.code[2]) shl 16); 3414 bytes:=bytes or (ord(insentry^.code[3]) shl 8); 3415 bytes:=bytes or ord(insentry^.code[4]); 3416 { set Rn and Rd } 3417 bytes:=bytes or getsupreg(oper[0]^.reg) shl 12; 3418 3419 refoper:=oper[1]; 3420 3421 bytes:=bytes or getsupreg(refoper^.ref^.base) shl 16; 3422 if getregtype(refoper^.ref^.index)=R_INVALIDREGISTER then 3423 begin 3424 bytes:=bytes or (1 shl 22); 3425 { set offset } 3426 offset:=0; 3427 currsym:=objdata.symbolref(refoper^.ref^.symbol); 3428 if assigned(currsym) then 3429 offset:=currsym.offset-insoffset-8; 3430 offset:=offset+refoper^.ref^.offset; 3431 3432 if offset>=0 then 3433 { set U flag } 3434 bytes:=bytes or (1 shl 23) 3435 else 3436 offset:=-offset; 3437 bytes:=bytes or (offset and $F); 3438 bytes:=bytes or ((offset and $F0) shl 4); 3439 end 3440 else 3441 begin 3442 { set U flag } 3443 if refoper^.ref^.signindex>=0 then 3444 bytes:=bytes or (1 shl 23); 3445 bytes:=bytes or getsupreg(refoper^.ref^.index); 3446 end; 3447 end; 3448 #$22: // LDRH/STRH 3449 begin 3450 { set instruction code } 3451 bytes:=bytes or (ord(insentry^.code[1]) shl 16); 3452 bytes:=bytes or ord(insentry^.code[2]); 3453 { src/dest register (Rd) } 3454 bytes:=bytes or getsupreg(oper[0]^.reg) shl 12; 3455 { base register (Rn) } 3456 bytes:=bytes or getsupreg(oper[1]^.ref^.base) shl 16; 3457 if getregtype(oper[1]^.ref^.index)=R_INVALIDREGISTER then 3458 begin 3459 bytes:=bytes or (1 shl 22); // with immediate offset 3460 offset:=oper[1]^.ref^.offset; 3461 if offset>=0 then 3462 { set U flag } 3463 bytes:=bytes or (1 shl 23) 3464 else 3465 offset:=-offset; 3466 bytes:=bytes or (offset and $F); 3467 bytes:=bytes or ((offset and $F0) shl 4); 3468 end 3469 else 3470 begin 3471 { set U flag } 3472 if oper[1]^.ref^.signindex>=0 then 3473 bytes:=bytes or (1 shl 23); 3474 bytes:=bytes or getsupreg(oper[1]^.ref^.index); 3475 end; 3476 { set W bit } 3477 if oper[1]^.ref^.addressmode=AM_PREINDEXED then 3478 bytes:=bytes or (1 shl 21); 3479 { set P bit if necessary } 3480 if oper[1]^.ref^.addressmode<>AM_POSTINDEXED then 3481 bytes:=bytes or (1 shl 24); 3482 end; 3483 #$25: // PLD/PLI 3484 begin 3485 { set instruction code } 3486 bytes:=bytes or (ord(insentry^.code[1]) shl 24); 3487 bytes:=bytes or (ord(insentry^.code[2]) shl 16); 3488 bytes:=bytes or (ord(insentry^.code[3]) shl 8); 3489 bytes:=bytes or ord(insentry^.code[4]); 3490 { set Rn and Rd } 3491 bytes:=bytes or getsupreg(oper[0]^.ref^.base) shl 16; 3492 if getregtype(oper[0]^.ref^.index)=R_INVALIDREGISTER then 3493 begin 3494 { set offset } 3495 offset:=0; 3496 currsym:=objdata.symbolref(oper[0]^.ref^.symbol); 3497 if assigned(currsym) then 3498 offset:=currsym.offset-insoffset-8; 3499 offset:=offset+oper[0]^.ref^.offset; 3500 if offset>=0 then 3501 begin 3502 { set U flag } 3503 bytes:=bytes or (1 shl 23); 3504 bytes:=bytes or offset 3505 end 3506 else 3507 begin 3508 offset:=-offset; 3509 bytes:=bytes or offset 3510 end; 3511 end 3512 else 3513 begin 3514 bytes:=bytes or (1 shl 25); 3515 { set U flag } 3516 if oper[0]^.ref^.signindex>=0 then 3517 bytes:=bytes or (1 shl 23); 3518 bytes:=bytes or getsupreg(oper[0]^.ref^.index); 3519 { set shift } 3520 with oper[0]^.ref^ do 3521 if shiftmode<>SM_None then 3522 begin 3523 bytes:=bytes or ((shiftimm and $1F) shl 7); 3524 if shiftmode<>SM_RRX then 3525 bytes:=bytes or (ord(shiftmode) - ord(SM_LSL)) shl 5 3526 else 3527 bytes:=bytes or (3 shl 5); 3528 end 3529 end; 3530 end; 3531 #$26: // LDM/STM 3532 begin 3533 { set instruction code } 3534 bytes:=bytes or (ord(insentry^.code[1]) shl 20); 3535 3536 if ops>1 then 3537 begin 3538 if oper[0]^.typ=top_ref then 3539 begin 3540 { set W bit } 3541 if oper[0]^.ref^.addressmode=AM_PREINDEXED then 3542 bytes:=bytes or (1 shl 21); 3543 { set Rn } 3544 bytes:=bytes or (getsupreg(oper[0]^.ref^.index) shl 16); 3545 end 3546 else { typ=top_reg } 3547 begin 3548 { set Rn } 3549 bytes:=bytes or (getsupreg(oper[0]^.reg) shl 16); 3550 end; 3551 3552 if oper[1]^.usermode then 3553 begin 3554 if (oper[0]^.typ=top_ref) then 3555 begin 3556 if (opcode=A_LDM) and 3557 (RS_PC in oper[1]^.regset^) then 3558 begin 3559 // Valid exception return 3560 end 3561 else 3562 Message(asmw_e_invalid_opcode_and_operands); 3563 end; 3564 3565 bytes:=bytes or (1 shl 22); 3566 end; 3567 { reglist } 3568 bytes:=bytes or MakeRegList(oper[1]^.regset^); 3569 end 3570 else 3571 begin 3572 { push/pop } 3573 { Set W and Rn to SP } 3574 if opcode=A_PUSH then 3575 bytes:=bytes or (1 shl 21); 3576 bytes:=bytes or ($D shl 16); 3577 { reglist } 3578 bytes:=bytes or MakeRegList(oper[0]^.regset^); 3579 end; 3580 { set P bit } 3581 if (opcode=A_LDM) and (oppostfix in [PF_ED,PF_EA,PF_IB,PF_DB]) 3582 or (opcode=A_STM) and (oppostfix in [PF_FA,PF_FD,PF_IB,PF_DB]) 3583 or (opcode=A_PUSH) then 3584 bytes:=bytes or (1 shl 24); 3585 { set U bit } 3586 if (opcode=A_LDM) and (oppostfix in [PF_None,PF_ED,PF_FD,PF_IB,PF_IA]) 3587 or (opcode=A_STM) and (oppostfix in [PF_None,PF_FA,PF_EA,PF_IB,PF_IA]) 3588 or (opcode=A_POP) then 3589 bytes:=bytes or (1 shl 23); 3590 end; 3591 #$27: // SWP/SWPB 3592 begin 3593 { set instruction code } 3594 bytes:=bytes or (ord(insentry^.code[1]) shl 20); 3595 bytes:=bytes or (ord(insentry^.code[2]) shl 4); 3596 { set regs } 3597 bytes:=bytes or (getsupreg(oper[0]^.reg) shl 12); 3598 bytes:=bytes or getsupreg(oper[1]^.reg); 3599 if ops=3 then 3600 bytes:=bytes or (getsupreg(oper[2]^.ref^.base) shl 16); 3601 end; 3602 #$28: // BX/BLX 3603 begin 3604 { set instruction code } 3605 bytes:=bytes or (ord(insentry^.code[1]) shl 24); 3606 { set offset } 3607 if oper[0]^.typ=top_const then 3608 bytes:=bytes or ((oper[0]^.val shr 2) and $ffffff) 3609 else 3610 begin 3611 currsym:=objdata.symbolref(oper[0]^.ref^.symbol); 3612 if (currsym.bind<>AB_LOCAL) and (currsym.objsection<>objdata.CurrObjSec) then 3613 begin 3614 bytes:=bytes or $fffffe; // TODO: Not sure this is right, but it matches the output of gas 3615 objdata.writereloc(oper[0]^.ref^.offset,0,currsym,RELOC_RELATIVE_24_THUMB); 3616 end 3617 else 3618 begin 3619 offset:=((currsym.offset-insoffset-8) and $3fffffe); 3620 3621 { Turn BLX into BL if the destination isn't odd, could happen with recursion } 3622 if not odd(offset shr 1) then 3623 bytes:=(bytes and $EB000000) or $EB000000; 3624 3625 bytes:=bytes or ((offset shr 2) and $ffffff); 3626 bytes:=bytes or ((offset shr 1) and $1) shl 24; 3627 end; 3628 end; 3629 end; 3630 #$29: // SUB 3631 begin 3632 { set instruction code } 3633 bytes:=bytes or (ord(insentry^.code[1]) shl 24); 3634 bytes:=bytes or (ord(insentry^.code[2]) shl 16); 3635 { set regs } 3636 bytes:=bytes or (getsupreg(oper[0]^.reg) shl 12); 3637 { set S if necessary } 3638 if oppostfix=PF_S then 3639 bytes:=bytes or (1 shl 20); 3640 end; 3641 #$2A: 3642 begin 3643 { set instruction code } 3644 bytes:=bytes or (ord(insentry^.code[1]) shl 24); 3645 bytes:=bytes or (ord(insentry^.code[2]) shl 16); 3646 bytes:=bytes or (ord(insentry^.code[3]) shl 8); 3647 bytes:=bytes or ord(insentry^.code[4]); 3648 { set opers } 3649 bytes:=bytes or (getsupreg(oper[0]^.reg) shl 12); 3650 if opcode in [A_SSAT, A_SSAT16] then 3651 bytes:=bytes or (((oper[1]^.val-1) and $1F) shl 16) 3652 else 3653 bytes:=bytes or ((oper[1]^.val and $1F) shl 16); 3654 bytes:=bytes or getsupreg(oper[2]^.reg); 3655 3656 if (ops>3) and 3657 (oper[3]^.typ=top_shifterop) and 3658 (oper[3]^.shifterop^.rs=NR_NO) then 3659 begin 3660 bytes:=bytes or ((oper[3]^.shifterop^.shiftimm and $1F) shl 7); 3661 if oper[3]^.shifterop^.shiftmode=SM_ASR then 3662 bytes:=bytes or (1 shl 6) 3663 else if oper[3]^.shifterop^.shiftmode<>SM_LSL then 3664 Message1(asmw_e_invalid_opcode_and_operands,GetString); 3665 end; 3666 end; 3667 #$2B: // SETEND 3668 begin 3669 { set instruction code } 3670 bytes:=bytes or (ord(insentry^.code[1]) shl 24); 3671 bytes:=bytes or (ord(insentry^.code[2]) shl 16); 3672 bytes:=bytes or (ord(insentry^.code[3]) shl 8); 3673 bytes:=bytes or ord(insentry^.code[4]); 3674 { set endian specifier } 3675 bytes:=bytes or ((oper[0]^.val and 1) shl 9); 3676 end; 3677 #$2C: // MOVW 3678 begin 3679 { set instruction code } 3680 bytes:=bytes or (ord(insentry^.code[1]) shl 24); 3681 bytes:=bytes or (ord(insentry^.code[2]) shl 16); 3682 { set destination } 3683 bytes:=bytes or (getsupreg(oper[0]^.reg) shl 12); 3684 { set imm } 3685 bytes:=bytes or (oper[1]^.val and $FFF); 3686 bytes:=bytes or ((oper[1]^.val and $F000) shl 4); 3687 end; 3688 #$2D: // BFX 3689 begin 3690 { set instruction code } 3691 bytes:=bytes or (ord(insentry^.code[1]) shl 24); 3692 bytes:=bytes or (ord(insentry^.code[2]) shl 16); 3693 bytes:=bytes or (ord(insentry^.code[3]) shl 8); 3694 bytes:=bytes or ord(insentry^.code[4]); 3695 3696 if ops=3 then 3697 begin 3698 msb:=(oper[1]^.val+oper[2]^.val-1); 3699 3700 { set destination } 3701 bytes:=bytes or (getsupreg(oper[0]^.reg) shl 12); 3702 { set immediates } 3703 bytes:=bytes or ((oper[1]^.val and $1F) shl 7); 3704 bytes:=bytes or ((msb and $1F) shl 16); 3705 end 3706 else 3707 begin 3708 if opcode in [A_BFC,A_BFI] then 3709 msb:=(oper[2]^.val+oper[3]^.val-1) 3710 else 3711 msb:=oper[3]^.val-1; 3712 3713 { set destination } 3714 bytes:=bytes or (getsupreg(oper[0]^.reg) shl 12); 3715 bytes:=bytes or getsupreg(oper[1]^.reg); 3716 { set immediates } 3717 bytes:=bytes or ((oper[2]^.val and $1F) shl 7); 3718 bytes:=bytes or ((msb and $1F) shl 16); 3719 end; 3720 end; 3721 #$2E: // Cache stuff 3722 begin 3723 { set instruction code } 3724 bytes:=bytes or (ord(insentry^.code[1]) shl 24); 3725 bytes:=bytes or (ord(insentry^.code[2]) shl 16); 3726 bytes:=bytes or (ord(insentry^.code[3]) shl 8); 3727 bytes:=bytes or ord(insentry^.code[4]); 3728 { set code } 3729 bytes:=bytes or (oper[0]^.val and $F); 3730 end; 3731 #$2F: // Nop 3732 begin 3733 { set instruction code } 3734 bytes:=bytes or (ord(insentry^.code[1]) shl 24); 3735 bytes:=bytes or (ord(insentry^.code[2]) shl 16); 3736 bytes:=bytes or (ord(insentry^.code[3]) shl 8); 3737 bytes:=bytes or ord(insentry^.code[4]); 3738 end; 3739 #$30: // Shifts 3740 begin 3741 { set instruction code } 3742 bytes:=bytes or (ord(insentry^.code[1]) shl 24); 3743 bytes:=bytes or (ord(insentry^.code[2]) shl 16); 3744 bytes:=bytes or (ord(insentry^.code[3]) shl 8); 3745 bytes:=bytes or ord(insentry^.code[4]); 3746 { set destination } 3747 bytes:=bytes or (getsupreg(oper[0]^.reg) shl 12); 3748 bytes:=bytes or getsupreg(oper[1]^.reg); 3749 if ops>2 then 3750 begin 3751 { set shift } 3752 if oper[2]^.typ=top_reg then 3753 bytes:=bytes or (getsupreg(oper[2]^.reg) shl 8) 3754 else 3755 bytes:=bytes or ((oper[2]^.val and $1F) shl 7); 3756 end; 3757 { set S if necessary } 3758 if oppostfix=PF_S then 3759 bytes:=bytes or (1 shl 20); 3760 end; 3761 #$31: // BKPT 3762 begin 3763 { set instruction code } 3764 bytes:=bytes or (ord(insentry^.code[1]) shl 24); 3765 bytes:=bytes or (ord(insentry^.code[2]) shl 16); 3766 bytes:=bytes or (ord(insentry^.code[3]) shl 0); 3767 { set imm } 3768 bytes:=bytes or (oper[0]^.val and $FFF0) shl 4; 3769 bytes:=bytes or (oper[0]^.val and $F); 3770 end; 3771 #$32: // CLZ/REV 3772 begin 3773 { set instruction code } 3774 bytes:=bytes or (ord(insentry^.code[1]) shl 24); 3775 bytes:=bytes or (ord(insentry^.code[2]) shl 16); 3776 bytes:=bytes or (ord(insentry^.code[3]) shl 8); 3777 bytes:=bytes or ord(insentry^.code[4]); 3778 { set regs } 3779 bytes:=bytes or (getsupreg(oper[0]^.reg) shl 12); 3780 bytes:=bytes or getsupreg(oper[1]^.reg); 3781 end; 3782 #$33: 3783 begin 3784 { set instruction code } 3785 bytes:=bytes or (ord(insentry^.code[1]) shl 24); 3786 bytes:=bytes or (ord(insentry^.code[2]) shl 16); 3787 { set regs } 3788 bytes:=bytes or (getsupreg(oper[0]^.reg) shl 12); 3789 3790 if oper[1]^.typ=top_ref then 3791 begin 3792 { set offset } 3793 offset:=0; 3794 currsym:=objdata.symbolref(oper[1]^.ref^.symbol); 3795 if assigned(currsym) then 3796 offset:=currsym.offset-insoffset-8; 3797 offset:=offset+oper[1]^.ref^.offset; 3798 if offset>=0 then 3799 begin 3800 { set U flag } 3801 bytes:=bytes or (1 shl 23); 3802 bytes:=bytes or offset 3803 end 3804 else 3805 begin 3806 bytes:=bytes or (1 shl 22); 3807 offset:=-offset; 3808 bytes:=bytes or offset 3809 end; 3810 end 3811 else 3812 begin 3813 if is_shifter_const(oper[1]^.val,r) then 3814 begin 3815 setshifterop(1); 3816 bytes:=bytes or (1 shl 23); 3817 end 3818 else 3819 begin 3820 bytes:=bytes or (1 shl 22); 3821 oper[1]^.val:=-oper[1]^.val; 3822 setshifterop(1); 3823 end; 3824 end; 3825 end; 3826 #$40,#$90: // VMOV 3827 begin 3828 { set instruction code } 3829 bytes:=bytes or (ord(insentry^.code[1]) shl 24); 3830 bytes:=bytes or (ord(insentry^.code[2]) shl 16); 3831 bytes:=bytes or (ord(insentry^.code[3]) shl 8); 3832 bytes:=bytes or ord(insentry^.code[4]); 3833 3834 { set regs } 3835 Rd:=0; 3836 Rn:=0; 3837 Rm:=0; 3838 3839 case oppostfix of 3840 PF_None: 3841 begin 3842 if ops=4 then 3843 begin 3844 if (getregtype(oper[0]^.reg)=R_MMREGISTER) and 3845 (getregtype(oper[2]^.reg)=R_INTREGISTER) then 3846 begin 3847 Rd:=getmmreg(oper[0]^.reg); 3848 Rm:=getsupreg(oper[2]^.reg); 3849 Rn:=getsupreg(oper[3]^.reg); 3850 end 3851 else if (getregtype(oper[0]^.reg)=R_INTREGISTER) and 3852 (getregtype(oper[2]^.reg)=R_MMREGISTER) then 3853 begin 3854 Rm:=getsupreg(oper[0]^.reg); 3855 Rn:=getsupreg(oper[1]^.reg); 3856 Rd:=getmmreg(oper[2]^.reg); 3857 end 3858 else 3859 message(asmw_e_invalid_opcode_and_operands); 3860 3861 bytes:=bytes or (((Rd and $1E) shr 1) shl 0); 3862 bytes:=bytes or ((Rd and $1) shl 5); 3863 3864 bytes:=bytes or (Rm shl 12); 3865 bytes:=bytes or (Rn shl 16); 3866 end 3867 else if ops=3 then 3868 begin 3869 if (getregtype(oper[0]^.reg)=R_MMREGISTER) and 3870 (getregtype(oper[1]^.reg)=R_INTREGISTER) then 3871 begin 3872 Rd:=getmmreg(oper[0]^.reg); 3873 Rm:=getsupreg(oper[1]^.reg); 3874 Rn:=getsupreg(oper[2]^.reg); 3875 end 3876 else if (getregtype(oper[0]^.reg)=R_INTREGISTER) and 3877 (getregtype(oper[2]^.reg)=R_MMREGISTER) then 3878 begin 3879 Rm:=getsupreg(oper[0]^.reg); 3880 Rn:=getsupreg(oper[1]^.reg); 3881 Rd:=getmmreg(oper[2]^.reg); 3882 end 3883 else 3884 message(asmw_e_invalid_opcode_and_operands); 3885 3886 bytes:=bytes or ((Rd and $F) shl 0); 3887 bytes:=bytes or ((Rd and $10) shl 1); 3888 3889 bytes:=bytes or (Rm shl 12); 3890 bytes:=bytes or (Rn shl 16); 3891 end 3892 else if ops=2 then 3893 begin 3894 if (getregtype(oper[0]^.reg)=R_MMREGISTER) and 3895 (getregtype(oper[1]^.reg)=R_INTREGISTER) then 3896 begin 3897 Rd:=getmmreg(oper[0]^.reg); 3898 Rm:=getsupreg(oper[1]^.reg); 3899 end 3900 else if (getregtype(oper[0]^.reg)=R_INTREGISTER) and 3901 (getregtype(oper[1]^.reg)=R_MMREGISTER) then 3902 begin 3903 Rm:=getsupreg(oper[0]^.reg); 3904 Rd:=getmmreg(oper[1]^.reg); 3905 end 3906 else 3907 message(asmw_e_invalid_opcode_and_operands); 3908 3909 bytes:=bytes or (((Rd and $1E) shr 1) shl 16); 3910 bytes:=bytes or ((Rd and $1) shl 7); 3911 3912 bytes:=bytes or (Rm shl 12); 3913 end; 3914 end; 3915 PF_F32: 3916 begin 3917 if (getregtype(oper[0]^.reg)<>R_MMREGISTER) then 3918 Message(asmw_e_invalid_opcode_and_operands); 3919 3920 case oper[1]^.typ of 3921 top_realconst: 3922 begin 3923 if not(IsVFPFloatImmediate(s32real,oper[1]^.val_real)) then 3924 Message(asmw_e_invalid_opcode_and_operands); 3925 singlerec.value:=oper[1]^.val_real; 3926 singlerec:=tcompsinglerec(NtoLE(DWord(singlerec))); 3927 3928 bytes:=bytes or ((singlerec.bytes[2] shr 3) and $f); 3929 bytes:=bytes or (DWord((singlerec.bytes[2] shr 7) and $1) shl 16) or (DWord(singlerec.bytes[3] and $3) shl 17) or (DWord((singlerec.bytes[3] shr 7) and $1) shl 19); 3930 end; 3931 top_reg: 3932 begin 3933 if getregtype(oper[1]^.reg)<>R_MMREGISTER then 3934 Message(asmw_e_invalid_opcode_and_operands); 3935 Rm:=getmmreg(oper[1]^.reg); 3936 bytes:=bytes or (((Rm and $1E) shr 1) shl 0); 3937 bytes:=bytes or ((Rm and $1) shl 5); 3938 end; 3939 else 3940 Message(asmw_e_invalid_opcode_and_operands); 3941 end; 3942 Rd:=getmmreg(oper[0]^.reg); 3943 3944 bytes:=bytes or (((Rd and $1E) shr 1) shl 12); 3945 bytes:=bytes or ((Rd and $1) shl 22); 3946 3947 end; 3948 PF_F64: 3949 begin 3950 if (getregtype(oper[0]^.reg)<>R_MMREGISTER) then 3951 Message(asmw_e_invalid_opcode_and_operands); 3952 3953 case oper[1]^.typ of 3954 top_realconst: 3955 begin 3956 if not(IsVFPFloatImmediate(s64real,oper[1]^.val_real)) then 3957 Message(asmw_e_invalid_opcode_and_operands); 3958 doublerec.value:=oper[1]^.val_real; 3959 doublerec:=tcompdoublerec(NtoLE(QWord(doublerec))); 3960 3961 // 32c: eeb41b00 vmov.f64 d1, #64 ; 0x40 3962 3963 // 32c: eeb61b00 vmov.f64 d1, #96 ; 0x60 3964 bytes:=bytes or (doublerec.bytes[6] and $f); 3965 bytes:=bytes or (DWord((doublerec.bytes[6] shr 4) and $7) shl 16) or (DWord((doublerec.bytes[7] shr 7) and $1) shl 19); 3966 end; 3967 top_reg: 3968 begin 3969 if getregtype(oper[1]^.reg)<>R_MMREGISTER then 3970 Message(asmw_e_invalid_opcode_and_operands); 3971 Rm:=getmmreg(oper[1]^.reg); 3972 bytes:=bytes or (Rm and $F); 3973 bytes:=bytes or ((Rm and $10) shl 1); 3974 end; 3975 else 3976 Message(asmw_e_invalid_opcode_and_operands); 3977 end; 3978 Rd:=getmmreg(oper[0]^.reg); 3979 3980 bytes:=bytes or (1 shl 8); 3981 3982 bytes:=bytes or ((Rd and $F) shl 12); 3983 bytes:=bytes or (((Rd and $10) shr 4) shl 22); 3984 end; 3985 end; 3986 end; 3987 #$41,#$91: // VMRS/VMSR 3988 begin 3989 { set instruction code } 3990 bytes:=bytes or (ord(insentry^.code[1]) shl 24); 3991 bytes:=bytes or (ord(insentry^.code[2]) shl 16); 3992 bytes:=bytes or (ord(insentry^.code[3]) shl 8); 3993 bytes:=bytes or ord(insentry^.code[4]); 3994 { set regs } 3995 if (opcode=A_VMRS) or 3996 (opcode=A_FMRX) then 3997 begin 3998 case oper[1]^.reg of 3999 NR_FPSID: Rn:=$0; 4000 NR_FPSCR: Rn:=$1; 4001 NR_MVFR1: Rn:=$6; 4002 NR_MVFR0: Rn:=$7; 4003 NR_FPEXC: Rn:=$8; 4004 else 4005 Rn:=0; 4006 message(asmw_e_invalid_opcode_and_operands); 4007 end; 4008 4009 bytes:=bytes or (Rn shl 16); 4010 4011 if oper[0]^.reg=NR_APSR_nzcv then 4012 bytes:=bytes or ($F shl 12) 4013 else 4014 bytes:=bytes or (getsupreg(oper[0]^.reg) shl 12); 4015 end 4016 else 4017 begin 4018 case oper[0]^.reg of 4019 NR_FPSID: Rn:=$0; 4020 NR_FPSCR: Rn:=$1; 4021 NR_FPEXC: Rn:=$8; 4022 else 4023 Rn:=0; 4024 message(asmw_e_invalid_opcode_and_operands); 4025 end; 4026 4027 bytes:=bytes or (Rn shl 16); 4028 4029 bytes:=bytes or (getsupreg(oper[1]^.reg) shl 12); 4030 end; 4031 end; 4032 #$42,#$92: // VMUL 4033 begin 4034 { set instruction code } 4035 bytes:=bytes or (ord(insentry^.code[1]) shl 24); 4036 bytes:=bytes or (ord(insentry^.code[2]) shl 16); 4037 bytes:=bytes or (ord(insentry^.code[3]) shl 8); 4038 bytes:=bytes or ord(insentry^.code[4]); 4039 { set regs } 4040 if ops=3 then 4041 begin 4042 Rd:=getmmreg(oper[0]^.reg); 4043 Rn:=getmmreg(oper[1]^.reg); 4044 Rm:=getmmreg(oper[2]^.reg); 4045 end 4046 else if ops=1 then 4047 begin 4048 Rd:=getmmreg(oper[0]^.reg); 4049 Rn:=0; 4050 Rm:=0; 4051 end 4052 else if oper[1]^.typ=top_const then 4053 begin 4054 Rd:=getmmreg(oper[0]^.reg); 4055 Rn:=0; 4056 Rm:=0; 4057 end 4058 else 4059 begin 4060 Rd:=getmmreg(oper[0]^.reg); 4061 Rn:=0; 4062 Rm:=getmmreg(oper[1]^.reg); 4063 end; 4064 4065 if (oppostfix=PF_F32) or (insentry^.code[5]=#1) then 4066 begin 4067 D:=rd and $1; Rd:=Rd shr 1; 4068 N:=rn and $1; Rn:=Rn shr 1; 4069 M:=rm and $1; Rm:=Rm shr 1; 4070 end 4071 else 4072 begin 4073 D:=(rd shr 4) and $1; Rd:=Rd and $F; 4074 N:=(rn shr 4) and $1; Rn:=Rn and $F; 4075 M:=(rm shr 4) and $1; Rm:=Rm and $F; 4076 4077 bytes:=bytes or (1 shl 8); 4078 end; 4079 4080 bytes:=bytes or (Rd shl 12); 4081 bytes:=bytes or (Rn shl 16); 4082 bytes:=bytes or (Rm shl 0); 4083 4084 bytes:=bytes or (D shl 22); 4085 bytes:=bytes or (N shl 7); 4086 bytes:=bytes or (M shl 5); 4087 end; 4088 #$43,#$93: // VCVT 4089 begin 4090 { set instruction code } 4091 bytes:=bytes or (ord(insentry^.code[1]) shl 24); 4092 bytes:=bytes or (ord(insentry^.code[2]) shl 16); 4093 bytes:=bytes or (ord(insentry^.code[3]) shl 8); 4094 bytes:=bytes or ord(insentry^.code[4]); 4095 { set regs } 4096 Rd:=getmmreg(oper[0]^.reg); 4097 Rm:=getmmreg(oper[1]^.reg); 4098 4099 if (ops=2) and 4100 (oppostfix in [PF_F32F64,PF_F64F32]) then 4101 begin 4102 if oppostfix=PF_F32F64 then 4103 begin 4104 bytes:=bytes or (1 shl 8); 4105 4106 D:=rd and $1; Rd:=Rd shr 1; 4107 M:=(rm shr 4) and $1; Rm:=Rm and $F; 4108 end 4109 else 4110 begin 4111 D:=(rd shr 4) and $1; Rd:=Rd and $F; 4112 M:=rm and $1; Rm:=Rm shr 1; 4113 end; 4114 4115 bytes:=bytes and $FFF0FFFF; 4116 bytes:=bytes or ($7 shl 16); 4117 4118 bytes:=bytes or (Rd shl 12); 4119 bytes:=bytes or (Rm shl 0); 4120 4121 bytes:=bytes or (D shl 22); 4122 bytes:=bytes or (M shl 5); 4123 end 4124 else if (ops=2) and 4125 (oppostfix=PF_None) then 4126 begin 4127 d:=0; 4128 case getsubreg(oper[0]^.reg) of 4129 R_SUBNONE: 4130 rd:=getsupreg(oper[0]^.reg); 4131 R_SUBFS: 4132 begin 4133 rd:=getmmreg(oper[0]^.reg); 4134 4135 d:=rd and 1; 4136 rd:=rd shr 1; 4137 end; 4138 R_SUBFD: 4139 begin 4140 rd:=getmmreg(oper[0]^.reg); 4141 4142 d:=(rd shr 4) and 1; 4143 rd:=rd and $F; 4144 end; 4145 end; 4146 4147 m:=0; 4148 case getsubreg(oper[1]^.reg) of 4149 R_SUBNONE: 4150 rm:=getsupreg(oper[1]^.reg); 4151 R_SUBFS: 4152 begin 4153 rm:=getmmreg(oper[1]^.reg); 4154 4155 m:=rm and 1; 4156 rm:=rm shr 1; 4157 end; 4158 R_SUBFD: 4159 begin 4160 rm:=getmmreg(oper[1]^.reg); 4161 4162 m:=(rm shr 4) and 1; 4163 rm:=rm and $F; 4164 end; 4165 end; 4166 4167 bytes:=bytes or (Rd shl 12); 4168 bytes:=bytes or (Rm shl 0); 4169 4170 bytes:=bytes or (D shl 22); 4171 bytes:=bytes or (M shl 5); 4172 end 4173 else if ops=2 then 4174 begin 4175 case oppostfix of 4176 PF_S32F64, 4177 PF_U32F64, 4178 PF_F64S32, 4179 PF_F64U32: 4180 bytes:=bytes or (1 shl 8); 4181 end; 4182 4183 if oppostfix in [PF_S32F32,PF_S32F64,PF_U32F32,PF_U32F64] then 4184 begin 4185 case oppostfix of 4186 PF_S32F64, 4187 PF_S32F32: 4188 bytes:=bytes or (1 shl 16); 4189 end; 4190 4191 bytes:=bytes or (1 shl 18); 4192 4193 D:=rd and $1; Rd:=Rd shr 1; 4194 4195 if oppostfix in [PF_S32F64,PF_U32F64] then 4196 begin 4197 M:=(rm shr 4) and $1; Rm:=Rm and $F; 4198 end 4199 else 4200 begin 4201 M:=rm and $1; Rm:=Rm shr 1; 4202 end; 4203 end 4204 else 4205 begin 4206 case oppostfix of 4207 PF_F64S32, 4208 PF_F32S32: 4209 bytes:=bytes or (1 shl 7); 4210 else 4211 bytes:=bytes and $FFFFFF7F; 4212 end; 4213 4214 M:=rm and $1; Rm:=Rm shr 1; 4215 4216 if oppostfix in [PF_F64S32,PF_F64U32] then 4217 begin 4218 D:=(rd shr 4) and $1; Rd:=Rd and $F; 4219 end 4220 else 4221 begin 4222 D:=rd and $1; Rd:=Rd shr 1; 4223 end 4224 end; 4225 4226 bytes:=bytes or (Rd shl 12); 4227 bytes:=bytes or (Rm shl 0); 4228 4229 bytes:=bytes or (D shl 22); 4230 bytes:=bytes or (M shl 5); 4231 end 4232 else 4233 begin 4234 if rd<>rm then 4235 message(asmw_e_invalid_opcode_and_operands); 4236 4237 case oppostfix of 4238 PF_S32F32,PF_U32F32, 4239 PF_F32S32,PF_F32U32, 4240 PF_S32F64,PF_U32F64, 4241 PF_F64S32,PF_F64U32: 4242 begin 4243 if not (oper[2]^.val in [1..32]) then 4244 message1(asmw_e_invalid_opcode_and_operands, 'fbits not within 1-32'); 4245 4246 bytes:=bytes or (1 shl 7); 4247 rn:=32; 4248 end; 4249 PF_S16F64,PF_U16F64, 4250 PF_F64S16,PF_F64U16, 4251 PF_S16F32,PF_U16F32, 4252 PF_F32S16,PF_F32U16: 4253 begin 4254 if not (oper[2]^.val in [0..16]) then 4255 message1(asmw_e_invalid_opcode_and_operands, 'fbits not within 0-16'); 4256 4257 rn:=16; 4258 end; 4259 else 4260 Rn:=0; 4261 message(asmw_e_invalid_opcode_and_operands); 4262 end; 4263 4264 case oppostfix of 4265 PF_S16F64,PF_U16F64, 4266 PF_S32F64,PF_U32F64, 4267 PF_F64S16,PF_F64U16, 4268 PF_F64S32,PF_F64U32: 4269 begin 4270 bytes:=bytes or (1 shl 8); 4271 D:=(rd shr 4) and $1; Rd:=Rd and $F; 4272 end; 4273 else 4274 begin 4275 D:=rd and $1; Rd:=Rd shr 1; 4276 end; 4277 end; 4278 4279 case oppostfix of 4280 PF_U16F64,PF_U16F32, 4281 PF_U32F32,PF_U32F64, 4282 PF_F64U16,PF_F32U16, 4283 PF_F32U32,PF_F64U32: 4284 bytes:=bytes or (1 shl 16); 4285 end; 4286 4287 if oppostfix in [PF_S32F32,PF_S32F64,PF_U32F32,PF_U32F64,PF_S16F32,PF_S16F64,PF_U16F32,PF_U16F64] then 4288 bytes:=bytes or (1 shl 18); 4289 4290 bytes:=bytes or (Rd shl 12); 4291 bytes:=bytes or (D shl 22); 4292 4293 rn:=rn-oper[2]^.val; 4294 4295 bytes:=bytes or ((rn and $1) shl 5); 4296 bytes:=bytes or ((rn and $1E) shr 1); 4297 end; 4298 end; 4299 #$44,#$94: // VLDM/VSTM/VPUSH/VPOP 4300 begin 4301 { set instruction code } 4302 bytes:=bytes or (ord(insentry^.code[1]) shl 24); 4303 bytes:=bytes or (ord(insentry^.code[2]) shl 16); 4304 bytes:=bytes or (ord(insentry^.code[3]) shl 8); 4305 { set regs } 4306 if ops=2 then 4307 begin 4308 if oper[0]^.typ=top_ref then 4309 begin 4310 Rn:=getsupreg(oper[0]^.ref^.index); 4311 4312 if oper[0]^.ref^.addressmode<>AM_OFFSET then 4313 begin 4314 { set W } 4315 bytes:=bytes or (1 shl 21); 4316 end 4317 else if oppostfix in [PF_DB,PF_DBS,PF_DBD,PF_DBX] then 4318 message1(asmw_e_invalid_opcode_and_operands, 'Invalid postfix without writeback'); 4319 end 4320 else 4321 begin 4322 Rn:=getsupreg(oper[0]^.reg); 4323 4324 if oppostfix in [PF_DB,PF_DBS,PF_DBD,PF_DBX] then 4325 message1(asmw_e_invalid_opcode_and_operands, 'Invalid postfix without writeback'); 4326 end; 4327 4328 bytes:=bytes or (Rn shl 16); 4329 4330 { Set PU bits } 4331 case oppostfix of 4332 PF_None, 4333 PF_IA,PF_IAS,PF_IAD,PF_IAX: 4334 bytes:=bytes or (1 shl 23); 4335 PF_DB,PF_DBS,PF_DBD,PF_DBX: 4336 bytes:=bytes or (2 shl 23); 4337 end; 4338 4339 case oppostfix of 4340 PF_IAX,PF_DBX,PF_FDX,PF_EAX: 4341 begin 4342 bytes:=bytes or (1 shl 8); 4343 bytes:=bytes or (1 shl 0); // Offset is odd 4344 end; 4345 end; 4346 4347 dp_operation:=(oper[1]^.subreg=R_SUBFD); 4348 if oper[1]^.regset^=[] then 4349 message1(asmw_e_invalid_opcode_and_operands, 'Regset cannot be empty'); 4350 4351 rd:=0; 4352 for r:=0 to 31 do 4353 if r in oper[1]^.regset^ then 4354 begin 4355 rd:=r; 4356 break; 4357 end; 4358 4359 rn:=32-rd; 4360 for r:=rd+1 to 31 do 4361 if not(r in oper[1]^.regset^) then 4362 begin 4363 rn:=r-rd; 4364 break; 4365 end; 4366 4367 if dp_operation then 4368 begin 4369 bytes:=bytes or (1 shl 8); 4370 4371 bytes:=bytes or (rn*2); 4372 4373 bytes:=bytes or ((rd and $F) shl 12); 4374 bytes:=bytes or (((rd and $10) shr 4) shl 22); 4375 end 4376 else 4377 begin 4378 bytes:=bytes or rn; 4379 4380 bytes:=bytes or ((rd and $1) shl 22); 4381 bytes:=bytes or (((rd and $1E) shr 1) shl 12); 4382 end; 4383 end 4384 else { VPUSH/VPOP } 4385 begin 4386 dp_operation:=(oper[0]^.subreg=R_SUBFD); 4387 if oper[0]^.regset^=[] then 4388 message1(asmw_e_invalid_opcode_and_operands, 'Regset cannot be empty'); 4389 4390 rd:=0; 4391 for r:=0 to 31 do 4392 if r in oper[0]^.regset^ then 4393 begin 4394 rd:=r; 4395 break; 4396 end; 4397 4398 rn:=32-rd; 4399 for r:=rd+1 to 31 do 4400 if not(r in oper[0]^.regset^) then 4401 begin 4402 rn:=r-rd; 4403 break; 4404 end; 4405 4406 if dp_operation then 4407 begin 4408 bytes:=bytes or (1 shl 8); 4409 4410 bytes:=bytes or (rn*2); 4411 4412 bytes:=bytes or ((rd and $F) shl 12); 4413 bytes:=bytes or (((rd and $10) shr 4) shl 22); 4414 end 4415 else 4416 begin 4417 bytes:=bytes or rn; 4418 4419 bytes:=bytes or ((rd and $1) shl 22); 4420 bytes:=bytes or (((rd and $1E) shr 1) shl 12); 4421 end; 4422 end; 4423 end; 4424 #$45,#$95: // VLDR/VSTR 4425 begin 4426 { set instruction code } 4427 bytes:=bytes or (ord(insentry^.code[1]) shl 24); 4428 bytes:=bytes or (ord(insentry^.code[2]) shl 16); 4429 bytes:=bytes or (ord(insentry^.code[3]) shl 8); 4430 { set regs } 4431 rd:=getmmreg(oper[0]^.reg); 4432 4433 if getsubreg(oper[0]^.reg)=R_SUBFD then 4434 begin 4435 bytes:=bytes or (1 shl 8); 4436 4437 bytes:=bytes or ((rd and $F) shl 12); 4438 bytes:=bytes or (((rd and $10) shr 4) shl 22); 4439 end 4440 else 4441 begin 4442 bytes:=bytes or (((rd and $1E) shr 1) shl 12); 4443 bytes:=bytes or ((rd and $1) shl 22); 4444 end; 4445 4446 { set ref } 4447 bytes:=bytes or getsupreg(oper[1]^.ref^.base) shl 16; 4448 if getregtype(oper[1]^.ref^.index)=R_INVALIDREGISTER then 4449 begin 4450 { set offset } 4451 offset:=0; 4452 currsym:=objdata.symbolref(oper[1]^.ref^.symbol); 4453 if assigned(currsym) then 4454 offset:=currsym.offset-insoffset-8; 4455 offset:=offset+oper[1]^.ref^.offset; 4456 4457 offset:=offset div 4; 4458 4459 if offset>=0 then 4460 begin 4461 { set U flag } 4462 bytes:=bytes or (1 shl 23); 4463 bytes:=bytes or offset 4464 end 4465 else 4466 begin 4467 offset:=-offset; 4468 bytes:=bytes or offset 4469 end; 4470 end 4471 else 4472 message(asmw_e_invalid_opcode_and_operands); 4473 end; 4474 #$46: { System instructions } 4475 begin 4476 { set instruction code } 4477 bytes:=bytes or (ord(insentry^.code[1]) shl 24); 4478 bytes:=bytes or (ord(insentry^.code[2]) shl 16); 4479 bytes:=bytes or (ord(insentry^.code[3]) shl 8); 4480 { set regs } 4481 if (oper[0]^.typ=top_modeflags) then 4482 begin 4483 if mfA in oper[0]^.modeflags then bytes:=bytes or (1 shl 8); 4484 if mfI in oper[0]^.modeflags then bytes:=bytes or (1 shl 7); 4485 if mfF in oper[0]^.modeflags then bytes:=bytes or (1 shl 6); 4486 end; 4487 4488 if (ops=2) then 4489 bytes:=bytes or (oper[1]^.val and $1F) 4490 else if (ops=1) and 4491 (oper[0]^.typ=top_const) then 4492 bytes:=bytes or (oper[0]^.val and $1F); 4493 end; 4494 #$60: { Thumb } 4495 begin 4496 bytelen:=2; 4497 bytes:=0; 4498 4499 { set opcode } 4500 bytes:=bytes or (ord(insentry^.code[1]) shl 8); 4501 bytes:=bytes or ord(insentry^.code[2]); 4502 { set regs } 4503 if ops=2 then 4504 begin 4505 bytes:=bytes or (getsupreg(oper[0]^.reg) and $7); 4506 bytes:=bytes or (getsupreg(oper[0]^.reg) shl 3); 4507 if (oper[1]^.typ=top_reg) then 4508 bytes:=bytes or ((getsupreg(oper[1]^.reg) and $7) shl 6) 4509 else 4510 bytes:=bytes or ((oper[1]^.val and $1F) shl 6); 4511 end 4512 else if ops=3 then 4513 begin 4514 bytes:=bytes or (getsupreg(oper[0]^.reg) and $7); 4515 bytes:=bytes or (getsupreg(oper[1]^.reg) shl 3); 4516 if (oper[2]^.typ=top_reg) then 4517 bytes:=bytes or ((getsupreg(oper[2]^.reg) and $7) shl 6) 4518 else 4519 bytes:=bytes or ((oper[2]^.val and $1F) shl 6); 4520 end 4521 else if ops=1 then 4522 begin 4523 if oper[0]^.typ=top_const then 4524 bytes:=bytes or (oper[0]^.val and $FF); 4525 end; 4526 end; 4527 #$61: { Thumb } 4528 begin 4529 bytelen:=2; 4530 bytes:=0; 4531 4532 { set opcode } 4533 bytes:=bytes or (ord(insentry^.code[1]) shl 8); 4534 bytes:=bytes or ord(insentry^.code[2]); 4535 { set regs } 4536 if ops=2 then 4537 begin 4538 bytes:=bytes or (getsupreg(oper[0]^.reg) and $7); 4539 bytes:=bytes or ((getsupreg(oper[0]^.reg) and $8) shr 3) shl 7; 4540 4541 bytes:=bytes or (getsupreg(oper[1]^.reg) shl 3); 4542 end 4543 else if ops=1 then 4544 begin 4545 if oper[0]^.typ=top_const then 4546 bytes:=bytes or (oper[0]^.val and $FF); 4547 end; 4548 end; 4549 #$62..#$63: { Thumb branches } 4550 begin 4551 bytelen:=2; 4552 bytes:=0; 4553 4554 { set opcode } 4555 bytes:=bytes or (ord(insentry^.code[1]) shl 8); 4556 bytes:=bytes or ord(insentry^.code[2]); 4557 4558 if insentry^.code[0]=#$63 then 4559 bytes:=bytes or (CondVal[condition] shl 8); 4560 4561 if oper[0]^.typ=top_const then 4562 begin 4563 if insentry^.code[0]=#$63 then 4564 bytes:=bytes or (((oper[0]^.val shr 1)-1) and $FF) 4565 else 4566 bytes:=bytes or (((oper[0]^.val shr 1)-1) and $3FF); 4567 end 4568 else if oper[0]^.typ=top_reg then 4569 begin 4570 bytes:=bytes or (getsupreg(oper[0]^.reg) shl 3); 4571 end 4572 else if oper[0]^.typ=top_ref then 4573 begin 4574 offset:=0; 4575 currsym:=objdata.symbolref(oper[0]^.ref^.symbol); 4576 if assigned(currsym) then 4577 offset:=currsym.offset-insoffset-8; 4578 offset:=offset+oper[0]^.ref^.offset; 4579 4580 if insentry^.code[0]=#$63 then 4581 bytes:=bytes or (((offset+4) shr 1) and $FF) 4582 else 4583 bytes:=bytes or (((offset+4) shr 1) and $7FF); 4584 end 4585 end; 4586 #$64: { Thumb: Special encodings } 4587 begin 4588 bytelen:=2; 4589 bytes:=0; 4590 4591 { set opcode } 4592 bytes:=bytes or (ord(insentry^.code[1]) shl 8); 4593 bytes:=bytes or ord(insentry^.code[2]); 4594 4595 case opcode of 4596 A_SUB: 4597 begin 4598 if (ops=3) and 4599 (oper[2]^.typ=top_const) then 4600 bytes:=bytes or ((oper[2]^.val shr 2) and $7F) 4601 else if (ops=2) and 4602 (oper[1]^.typ=top_const) then 4603 bytes:=bytes or ((oper[1]^.val shr 2) and $7F); 4604 end; 4605 A_MUL: 4606 if (ops in [2,3]) then 4607 begin 4608 bytes:=bytes or (getsupreg(oper[0]^.reg) and $7); 4609 bytes:=bytes or (getsupreg(oper[1]^.reg) shl 3); 4610 end; 4611 A_ADD: 4612 begin 4613 if ops=2 then 4614 begin 4615 bytes:=bytes or (getsupreg(oper[0]^.reg) and $7); 4616 bytes:=bytes or (getsupreg(oper[1]^.reg) shl $3); 4617 end 4618 else if (oper[0]^.reg<>NR_STACK_POINTER_REG) and 4619 (oper[2]^.typ=top_const) then 4620 begin 4621 bytes:=bytes or (getsupreg(oper[0]^.reg) and $7) shl 8; 4622 bytes:=bytes or ((oper[2]^.val shr 2) and $7F); 4623 end 4624 else if (oper[0]^.reg<>NR_STACK_POINTER_REG) and 4625 (oper[2]^.typ=top_reg) then 4626 begin 4627 bytes:=bytes or (getsupreg(oper[0]^.reg) and $7); 4628 bytes:=bytes or ((getsupreg(oper[0]^.reg) and $8) shr 3) shl 7; 4629 end 4630 else 4631 begin 4632 bytes:=bytes or (getsupreg(oper[0]^.reg) and $7); 4633 bytes:=bytes or ((oper[2]^.val shr 2) and $7F); 4634 end; 4635 end; 4636 end; 4637 end; 4638 #$65: { Thumb load/store } 4639 begin 4640 bytelen:=2; 4641 bytes:=0; 4642 4643 { set opcode } 4644 bytes:=bytes or (ord(insentry^.code[1]) shl 8); 4645 bytes:=bytes or ord(insentry^.code[2]); 4646 { set regs } 4647 bytes:=bytes or (getsupreg(oper[0]^.reg) and $7); 4648 bytes:=bytes or (getsupreg(oper[1]^.ref^.base) shl 3); 4649 bytes:=bytes or (getsupreg(oper[1]^.ref^.index) shl 6); 4650 end; 4651 #$66: { Thumb load/store } 4652 begin 4653 bytelen:=2; 4654 bytes:=0; 4655 4656 { set opcode } 4657 bytes:=bytes or (ord(insentry^.code[1]) shl 8); 4658 bytes:=bytes or ord(insentry^.code[2]); 4659 { set regs } 4660 bytes:=bytes or (getsupreg(oper[0]^.reg) and $7); 4661 bytes:=bytes or (getsupreg(oper[1]^.ref^.base) shl 3); 4662 4663 { set offset } 4664 offset:=0; 4665 currsym:=objdata.symbolref(oper[1]^.ref^.symbol); 4666 if assigned(currsym) then 4667 offset:=currsym.offset-(insoffset+4) and (not longword(3)); 4668 4669 offset:=(offset+oper[1]^.ref^.offset); 4670 4671 bytes:=bytes or (((offset shr ord(insentry^.code[3])) and $1F) shl 6); 4672 end; 4673 #$67: { Thumb load/store } 4674 begin 4675 bytelen:=2; 4676 bytes:=0; 4677 4678 { set opcode } 4679 bytes:=bytes or (ord(insentry^.code[1]) shl 8); 4680 bytes:=bytes or ord(insentry^.code[2]); 4681 { set regs } 4682 bytes:=bytes or (getsupreg(oper[0]^.reg) shl 8); 4683 4684 if oper[1]^.typ=top_ref then 4685 begin 4686 { set offset } 4687 offset:=0; 4688 currsym:=objdata.symbolref(oper[1]^.ref^.symbol); 4689 if assigned(currsym) then 4690 offset:=currsym.offset-(insoffset+4) and (not longword(3)); 4691 4692 offset:=(offset+oper[1]^.ref^.offset); 4693 4694 bytes:=bytes or ((offset shr ord(insentry^.code[3])) and $FF); 4695 end 4696 else 4697 bytes:=bytes or ((oper[1]^.val shr ord(insentry^.code[3])) and $FF); 4698 end; 4699 #$68: { Thumb CB[N]Z } 4700 begin 4701 bytelen:=2; 4702 bytes:=0; 4703 4704 { set opcode } 4705 bytes:=bytes or (ord(insentry^.code[1]) shl 8); 4706 { set opers } 4707 bytes:=bytes or (getsupreg(oper[0]^.reg) and $7); 4708 4709 if oper[1]^.typ=top_ref then 4710 begin 4711 offset:=0; 4712 currsym:=objdata.symbolref(oper[1]^.ref^.symbol); 4713 if assigned(currsym) then 4714 offset:=currsym.offset-insoffset-8; 4715 offset:=offset+oper[1]^.ref^.offset; 4716 4717 offset:=offset div 2; 4718 end 4719 else 4720 offset:=oper[1]^.val div 2; 4721 4722 bytes:=bytes or ((offset) and $1F) shl 3; 4723 bytes:=bytes or ((offset shr 5) and 1) shl 9; 4724 end; 4725 #$69: { Thumb: Push/Pop/Stm/Ldm } 4726 begin 4727 bytelen:=2; 4728 bytes:=0; 4729 4730 { set opcode } 4731 bytes:=bytes or (ord(insentry^.code[1]) shl 8); 4732 4733 case opcode of 4734 A_PUSH: 4735 begin 4736 for r:=0 to 7 do 4737 if r in oper[0]^.regset^ then 4738 bytes:=bytes or (1 shl r); 4739 if RS_R14 in oper[0]^.regset^ then 4740 bytes:=bytes or (1 shl 8); 4741 end; 4742 A_POP: 4743 begin 4744 for r:=0 to 7 do 4745 if r in oper[0]^.regset^ then 4746 bytes:=bytes or (1 shl r); 4747 if RS_R15 in oper[0]^.regset^ then 4748 bytes:=bytes or (1 shl 8); 4749 end; 4750 A_STM: 4751 begin 4752 for r:=0 to 7 do 4753 if r in oper[1]^.regset^ then 4754 bytes:=bytes or (1 shl r); 4755 4756 if oper[0]^.typ=top_ref then 4757 bytes:=bytes or (getsupreg(oper[0]^.ref^.index) shl 8) 4758 else 4759 bytes:=bytes or (getsupreg(oper[0]^.reg) shl 8); 4760 end; 4761 A_LDM: 4762 begin 4763 for r:=0 to 7 do 4764 if r in oper[1]^.regset^ then 4765 bytes:=bytes or (1 shl r); 4766 4767 if oper[0]^.typ=top_ref then 4768 bytes:=bytes or (getsupreg(oper[0]^.ref^.index) shl 8) 4769 else 4770 bytes:=bytes or (getsupreg(oper[0]^.reg) shl 8); 4771 end; 4772 end; 4773 end; 4774 #$6A: { Thumb: IT } 4775 begin 4776 bytelen:=2; 4777 bytes:=0; 4778 4779 { set opcode } 4780 bytes:=bytes or (ord(insentry^.code[1]) shl 8); 4781 bytes:=bytes or (ord(insentry^.code[2]) shl 0); 4782 4783 bytes:=bytes or (CondVal[oper[0]^.cc] shl 4); 4784 4785 i_field:=(bytes shr 4) and 1; 4786 i_field:=(i_field shl 1) or i_field; 4787 i_field:=(i_field shl 2) or i_field; 4788 4789 bytes:=bytes or ((i_field and ord(insentry^.code[3])) xor (ord(insentry^.code[3]) shr 4)); 4790 end; 4791 #$6B: { Thumb: Data processing (misc) } 4792 begin 4793 bytelen:=2; 4794 bytes:=0; 4795 4796 { set opcode } 4797 bytes:=bytes or (ord(insentry^.code[1]) shl 8); 4798 bytes:=bytes or ord(insentry^.code[2]); 4799 { set regs } 4800 if ops>=2 then 4801 begin 4802 if oper[1]^.typ=top_const then 4803 begin 4804 bytes:=bytes or ((getsupreg(oper[0]^.reg) and $7) shl 8); 4805 bytes:=bytes or (oper[1]^.val and $FF); 4806 end 4807 else if oper[1]^.typ=top_reg then 4808 begin 4809 bytes:=bytes or (getsupreg(oper[0]^.reg) and $7); 4810 bytes:=bytes or (getsupreg(oper[1]^.reg) shl 3); 4811 end; 4812 end 4813 else if ops=1 then 4814 begin 4815 if oper[0]^.typ=top_const then 4816 bytes:=bytes or (oper[0]^.val and $FF); 4817 end; 4818 end; 4819 #$6C: { Thumb: CPS } 4820 begin 4821 bytelen:=2; 4822 bytes:=0; 4823 4824 { set opcode } 4825 bytes:=bytes or (ord(insentry^.code[1]) shl 8); 4826 bytes:=bytes or ord(insentry^.code[2]); 4827 4828 if mfA in oper[0]^.modeflags then bytes:=bytes or (1 shl 2); 4829 if mfI in oper[0]^.modeflags then bytes:=bytes or (1 shl 1); 4830 if mfF in oper[0]^.modeflags then bytes:=bytes or (1 shl 0); 4831 end; 4832 #$80: { Thumb-2: Dataprocessing } 4833 begin 4834 bytes:=0; 4835 { set instruction code } 4836 bytes:=bytes or (ord(insentry^.code[1]) shl 24); 4837 bytes:=bytes or (ord(insentry^.code[2]) shl 16); 4838 bytes:=bytes or (ord(insentry^.code[3]) shl 8); 4839 bytes:=bytes or ord(insentry^.code[4]); 4840 4841 if ops=1 then 4842 begin 4843 if oper[0]^.typ=top_reg then 4844 bytes:=bytes or (getsupreg(oper[0]^.reg) shl 16) 4845 else if oper[0]^.typ=top_const then 4846 bytes:=bytes or (oper[0]^.val and $F); 4847 end 4848 else if (ops=2) and 4849 (opcode in [A_CMP,A_CMN,A_TEQ,A_TST]) then 4850 begin 4851 bytes:=bytes or (getsupreg(oper[0]^.reg) shl 16); 4852 4853 if oper[1]^.typ=top_const then 4854 encodethumbimm(oper[1]^.val) 4855 else if oper[1]^.typ=top_reg then 4856 bytes:=bytes or (getsupreg(oper[1]^.reg) shl 0); 4857 end 4858 else if (ops=3) and 4859 (opcode in [A_CMP,A_CMN,A_TEQ,A_TST]) then 4860 begin 4861 bytes:=bytes or (getsupreg(oper[0]^.reg) shl 16); 4862 bytes:=bytes or (getsupreg(oper[1]^.reg) shl 0); 4863 4864 if oper[2]^.typ=top_shifterop then 4865 setthumbshift(2) 4866 else if oper[2]^.typ=top_reg then 4867 bytes:=bytes or (getsupreg(oper[2]^.reg) shl 12); 4868 end 4869 else if (ops=2) and 4870 (opcode in [A_REV,A_RBIT,A_REV16,A_REVSH,A_CLZ]) then 4871 begin 4872 bytes:=bytes or (getsupreg(oper[0]^.reg) shl 8); 4873 bytes:=bytes or (getsupreg(oper[1]^.reg) shl 16); 4874 bytes:=bytes or (getsupreg(oper[1]^.reg) shl 0); 4875 end 4876 else if ops=2 then 4877 begin 4878 bytes:=bytes or (getsupreg(oper[0]^.reg) shl 8); 4879 bytes:=bytes or (getsupreg(oper[0]^.reg) shl 16); 4880 4881 if oper[1]^.typ=top_const then 4882 encodethumbimm(oper[1]^.val) 4883 else if oper[1]^.typ=top_reg then 4884 bytes:=bytes or (getsupreg(oper[1]^.reg) shl 0); 4885 end 4886 else if ops=3 then 4887 begin 4888 bytes:=bytes or (getsupreg(oper[0]^.reg) shl 8); 4889 bytes:=bytes or (getsupreg(oper[1]^.reg) shl 16); 4890 4891 if oper[2]^.typ=top_const then 4892 encodethumbimm(oper[2]^.val) 4893 else if oper[2]^.typ=top_reg then 4894 bytes:=bytes or (getsupreg(oper[2]^.reg) shl 0); 4895 end 4896 else if ops=4 then 4897 begin 4898 bytes:=bytes or (getsupreg(oper[0]^.reg) shl 8); 4899 bytes:=bytes or (getsupreg(oper[1]^.reg) shl 16); 4900 bytes:=bytes or (getsupreg(oper[2]^.reg) shl 0); 4901 4902 if oper[3]^.typ=top_shifterop then 4903 setthumbshift(3) 4904 else if oper[3]^.typ=top_reg then 4905 bytes:=bytes or (getsupreg(oper[3]^.reg) shl 12); 4906 end; 4907 4908 if oppostfix=PF_S then 4909 bytes:=bytes or (1 shl 20) 4910 else if oppostfix=PF_X then 4911 bytes:=bytes or (1 shl 4) 4912 else if oppostfix=PF_R then 4913 bytes:=bytes or (1 shl 4); 4914 end; 4915 #$81: { Thumb-2: Dataprocessing misc } 4916 begin 4917 bytes:=0; 4918 { set instruction code } 4919 bytes:=bytes or (ord(insentry^.code[1]) shl 24); 4920 bytes:=bytes or (ord(insentry^.code[2]) shl 16); 4921 bytes:=bytes or (ord(insentry^.code[3]) shl 8); 4922 bytes:=bytes or ord(insentry^.code[4]); 4923 4924 if ops=3 then 4925 begin 4926 bytes:=bytes or (getsupreg(oper[0]^.reg) shl 8); 4927 bytes:=bytes or (getsupreg(oper[1]^.reg) shl 16); 4928 4929 if oper[2]^.typ=top_const then 4930 begin 4931 bytes:=bytes or (oper[2]^.val and $FF); 4932 bytes:=bytes or ((oper[2]^.val and $700) shr 8) shl 12; 4933 bytes:=bytes or ((oper[2]^.val and $800) shr 11) shl 26; 4934 end; 4935 end 4936 else if ops=2 then 4937 begin 4938 bytes:=bytes or (getsupreg(oper[0]^.reg) shl 8); 4939 4940 offset:=0; 4941 if oper[1]^.typ=top_const then 4942 begin 4943 offset:=oper[1]^.val; 4944 end 4945 else if oper[1]^.typ=top_ref then 4946 begin 4947 currsym:=objdata.symbolref(oper[1]^.ref^.symbol); 4948 if assigned(currsym) then 4949 offset:=currsym.offset-insoffset-8; 4950 offset:=offset+oper[1]^.ref^.offset; 4951 4952 offset:=offset; 4953 end; 4954 4955 bytes:=bytes or (offset and $FF); 4956 bytes:=bytes or ((offset and $700) shr 8) shl 12; 4957 bytes:=bytes or ((offset and $800) shr 11) shl 26; 4958 bytes:=bytes or ((offset and $F000) shr 12) shl 16; 4959 end; 4960 4961 if oppostfix=PF_S then 4962 bytes:=bytes or (1 shl 20); 4963 end; 4964 #$82: { Thumb-2: Shifts } 4965 begin 4966 bytes:=0; 4967 { set instruction code } 4968 bytes:=bytes or (ord(insentry^.code[1]) shl 24); 4969 bytes:=bytes or (ord(insentry^.code[2]) shl 16); 4970 bytes:=bytes or (ord(insentry^.code[3]) shl 8); 4971 bytes:=bytes or ord(insentry^.code[4]); 4972 4973 bytes:=bytes or (getsupreg(oper[0]^.reg) shl 8); 4974 if oper[1]^.typ=top_reg then 4975 begin 4976 offset:=2; 4977 bytes:=bytes or (getsupreg(oper[1]^.reg) shl 0); 4978 end 4979 else 4980 begin 4981 offset:=1; 4982 bytes:=bytes or (getsupreg(oper[0]^.reg) shl 0); 4983 end; 4984 4985 if oper[offset]^.typ=top_const then 4986 begin 4987 bytes:=bytes or (oper[offset]^.val and $3) shl 6; 4988 bytes:=bytes or (oper[offset]^.val and $1C) shl 10; 4989 end 4990 else if oper[offset]^.typ=top_reg then 4991 bytes:=bytes or (getsupreg(oper[offset]^.reg) shl 16); 4992 4993 if (ops>=(offset+2)) and 4994 (oper[offset+1]^.typ=top_const) then 4995 bytes:=bytes or (oper[offset+1]^.val and $1F); 4996 4997 if oppostfix=PF_S then 4998 bytes:=bytes or (1 shl 20); 4999 end; 5000 #$84: { Thumb-2: Shifts(width-1) } 5001 begin 5002 bytes:=0; 5003 { set instruction code } 5004 bytes:=bytes or (ord(insentry^.code[1]) shl 24); 5005 bytes:=bytes or (ord(insentry^.code[2]) shl 16); 5006 bytes:=bytes or (ord(insentry^.code[3]) shl 8); 5007 bytes:=bytes or ord(insentry^.code[4]); 5008 5009 bytes:=bytes or (getsupreg(oper[0]^.reg) shl 8); 5010 if oper[1]^.typ=top_reg then 5011 begin 5012 offset:=2; 5013 bytes:=bytes or (getsupreg(oper[1]^.reg) shl 16); 5014 end 5015 else 5016 offset:=1; 5017 5018 if oper[offset]^.typ=top_const then 5019 begin 5020 bytes:=bytes or (oper[offset]^.val and $3) shl 6; 5021 bytes:=bytes or (oper[offset]^.val and $1C) shl 10; 5022 end; 5023 5024 if (ops>=(offset+2)) and 5025 (oper[offset+1]^.typ=top_const) then 5026 begin 5027 if opcode in [A_BFI,A_BFC] then 5028 i_field:=oper[offset+1]^.val+oper[offset]^.val-1 5029 else 5030 i_field:=oper[offset+1]^.val-1; 5031 5032 bytes:=bytes or (i_field and $1F); 5033 end; 5034 5035 if oppostfix=PF_S then 5036 bytes:=bytes or (1 shl 20); 5037 end; 5038 #$83: { Thumb-2: Saturation } 5039 begin 5040 bytes:=0; 5041 { set instruction code } 5042 bytes:=bytes or (ord(insentry^.code[1]) shl 24); 5043 bytes:=bytes or (ord(insentry^.code[2]) shl 16); 5044 bytes:=bytes or (ord(insentry^.code[3]) shl 8); 5045 bytes:=bytes or ord(insentry^.code[4]); 5046 5047 bytes:=bytes or (getsupreg(oper[0]^.reg) shl 8); 5048 bytes:=bytes or (oper[1]^.val and $1F); 5049 bytes:=bytes or (getsupreg(oper[2]^.reg) shl 16); 5050 5051 if ops=4 then 5052 setthumbshift(3,true); 5053 end; 5054 #$85: { Thumb-2: Long multiplications } 5055 begin 5056 bytes:=0; 5057 { set instruction code } 5058 bytes:=bytes or (ord(insentry^.code[1]) shl 24); 5059 bytes:=bytes or (ord(insentry^.code[2]) shl 16); 5060 bytes:=bytes or (ord(insentry^.code[3]) shl 8); 5061 bytes:=bytes or ord(insentry^.code[4]); 5062 5063 if ops=4 then 5064 begin 5065 bytes:=bytes or (getsupreg(oper[0]^.reg) shl 12); 5066 bytes:=bytes or (getsupreg(oper[1]^.reg) shl 8); 5067 bytes:=bytes or (getsupreg(oper[2]^.reg) shl 16); 5068 bytes:=bytes or (getsupreg(oper[3]^.reg) shl 0); 5069 end; 5070 5071 if oppostfix=PF_S then 5072 bytes:=bytes or (1 shl 20) 5073 else if oppostfix=PF_X then 5074 bytes:=bytes or (1 shl 4); 5075 end; 5076 #$86: { Thumb-2: Extension ops } 5077 begin 5078 bytes:=0; 5079 { set instruction code } 5080 bytes:=bytes or (ord(insentry^.code[1]) shl 24); 5081 bytes:=bytes or (ord(insentry^.code[2]) shl 16); 5082 bytes:=bytes or (ord(insentry^.code[3]) shl 8); 5083 bytes:=bytes or ord(insentry^.code[4]); 5084 5085 if ops=2 then 5086 begin 5087 bytes:=bytes or (getsupreg(oper[0]^.reg) shl 8); 5088 bytes:=bytes or (getsupreg(oper[1]^.reg) shl 0); 5089 end 5090 else if ops=3 then 5091 begin 5092 if oper[2]^.typ=top_shifterop then 5093 begin 5094 bytes:=bytes or (getsupreg(oper[0]^.reg) shl 8); 5095 bytes:=bytes or (getsupreg(oper[1]^.reg) shl 0); 5096 bytes:=bytes or ((oper[2]^.shifterop^.shiftimm shr 3) shl 4); 5097 end 5098 else 5099 begin 5100 bytes:=bytes or (getsupreg(oper[0]^.reg) shl 8); 5101 bytes:=bytes or (getsupreg(oper[1]^.reg) shl 16); 5102 bytes:=bytes or (getsupreg(oper[2]^.reg) shl 0); 5103 end; 5104 end 5105 else if ops=4 then 5106 begin 5107 if oper[3]^.typ=top_shifterop then 5108 begin 5109 bytes:=bytes or (getsupreg(oper[0]^.reg) shl 8); 5110 bytes:=bytes or (getsupreg(oper[1]^.reg) shl 16); 5111 bytes:=bytes or (getsupreg(oper[2]^.reg) shl 0); 5112 bytes:=bytes or ((oper[3]^.shifterop^.shiftimm shr 3) shl 4); 5113 end; 5114 end; 5115 end; 5116 #$87: { Thumb-2: PLD/PLI } 5117 begin 5118 { set instruction code } 5119 bytes:=bytes or (ord(insentry^.code[1]) shl 24); 5120 bytes:=bytes or (ord(insentry^.code[2]) shl 16); 5121 bytes:=bytes or (ord(insentry^.code[3]) shl 8); 5122 bytes:=bytes or ord(insentry^.code[4]); 5123 { set Rn and Rd } 5124 bytes:=bytes or getsupreg(oper[0]^.ref^.base) shl 16; 5125 if getregtype(oper[0]^.ref^.index)=R_INVALIDREGISTER then 5126 begin 5127 { set offset } 5128 offset:=0; 5129 currsym:=objdata.symbolref(oper[0]^.ref^.symbol); 5130 if assigned(currsym) then 5131 offset:=currsym.offset-insoffset-8; 5132 offset:=offset+oper[0]^.ref^.offset; 5133 if offset>=0 then 5134 begin 5135 { set U flag } 5136 bytes:=bytes or (1 shl 23); 5137 bytes:=bytes or (offset and $FFF); 5138 end 5139 else 5140 begin 5141 bytes:=bytes or ($3 shl 10); 5142 5143 offset:=-offset; 5144 bytes:=bytes or (offset and $FF); 5145 end; 5146 end 5147 else 5148 begin 5149 bytes:=bytes or getsupreg(oper[0]^.ref^.index); 5150 { set shift } 5151 with oper[0]^.ref^ do 5152 if shiftmode=SM_LSL then 5153 bytes:=bytes or ((shiftimm and $1F) shl 4); 5154 end; 5155 end; 5156 #$88: { Thumb-2: LDR/STR } 5157 begin 5158 { set instruction code } 5159 bytes:=bytes or (ord(insentry^.code[1]) shl 24); 5160 bytes:=bytes or (ord(insentry^.code[2]) shl 16); 5161 bytes:=bytes or (ord(insentry^.code[3]) shl 8); 5162 bytes:=bytes or (ord(insentry^.code[4]) shl 0); 5163 { set Rn and Rd } 5164 bytes:=bytes or getsupreg(oper[0]^.reg) shl 12; 5165 bytes:=bytes or getsupreg(oper[1]^.ref^.base) shl 16; 5166 if getregtype(oper[1]^.ref^.index)=R_INVALIDREGISTER then 5167 begin 5168 { set offset } 5169 offset:=0; 5170 currsym:=objdata.symbolref(oper[1]^.ref^.symbol); 5171 if assigned(currsym) then 5172 offset:=currsym.offset-insoffset-8; 5173 offset:=(offset+oper[1]^.ref^.offset) shr ord(insentry^.code[5]); 5174 if offset>=0 then 5175 begin 5176 if (offset>255) and 5177 (not (opcode in [A_LDRT,A_LDRSBT,A_LDRSHT,A_LDRBT,A_LDRHT])) then 5178 bytes:=bytes or (1 shl 23); 5179 5180 { set U flag } 5181 if (oper[1]^.ref^.addressmode<>AM_OFFSET) then 5182 begin 5183 bytes:=bytes or (1 shl 9); 5184 bytes:=bytes or (1 shl 11); 5185 end; 5186 bytes:=bytes or offset 5187 end 5188 else 5189 begin 5190 bytes:=bytes or (1 shl 11); 5191 5192 offset:=-offset; 5193 bytes:=bytes or offset 5194 end; 5195 end 5196 else 5197 begin 5198 { set I flag } 5199 bytes:=bytes or (1 shl 25); 5200 bytes:=bytes or getsupreg(oper[1]^.ref^.index); 5201 { set shift } 5202 with oper[1]^.ref^ do 5203 if shiftmode<>SM_None then 5204 bytes:=bytes or ((shiftimm and $1F) shl 4); 5205 end; 5206 5207 if not (opcode in [A_LDRT,A_LDRSBT,A_LDRSHT,A_LDRBT,A_LDRHT]) then 5208 begin 5209 { set W bit } 5210 if oper[1]^.ref^.addressmode<>AM_OFFSET then 5211 bytes:=bytes or (1 shl 8); 5212 { set P bit if necessary } 5213 if oper[1]^.ref^.addressmode<>AM_POSTINDEXED then 5214 bytes:=bytes or (1 shl 10); 5215 end; 5216 end; 5217 #$89: { Thumb-2: LDRD/STRD } 5218 begin 5219 { set instruction code } 5220 bytes:=bytes or (ord(insentry^.code[1]) shl 24); 5221 bytes:=bytes or (ord(insentry^.code[2]) shl 16); 5222 bytes:=bytes or (ord(insentry^.code[3]) shl 8); 5223 bytes:=bytes or (ord(insentry^.code[4]) shl 0); 5224 { set Rn and Rd } 5225 bytes:=bytes or getsupreg(oper[0]^.reg) shl 12; 5226 bytes:=bytes or getsupreg(oper[1]^.reg) shl 8; 5227 bytes:=bytes or getsupreg(oper[2]^.ref^.base) shl 16; 5228 if getregtype(oper[2]^.ref^.index)=R_INVALIDREGISTER then 5229 begin 5230 { set offset } 5231 offset:=0; 5232 currsym:=objdata.symbolref(oper[2]^.ref^.symbol); 5233 if assigned(currsym) then 5234 offset:=currsym.offset-insoffset-8; 5235 offset:=(offset+oper[2]^.ref^.offset) div 4; 5236 if offset>=0 then 5237 begin 5238 { set U flag } 5239 bytes:=bytes or (1 shl 23); 5240 bytes:=bytes or offset 5241 end 5242 else 5243 begin 5244 offset:=-offset; 5245 bytes:=bytes or offset 5246 end; 5247 end 5248 else 5249 begin 5250 message(asmw_e_invalid_opcode_and_operands); 5251 end; 5252 { set W bit } 5253 if oper[2]^.ref^.addressmode<>AM_OFFSET then 5254 bytes:=bytes or (1 shl 21); 5255 { set P bit if necessary } 5256 if oper[2]^.ref^.addressmode<>AM_POSTINDEXED then 5257 bytes:=bytes or (1 shl 24); 5258 end; 5259 #$8A: { Thumb-2: LDREX } 5260 begin 5261 { set instruction code } 5262 bytes:=bytes or (ord(insentry^.code[1]) shl 24); 5263 bytes:=bytes or (ord(insentry^.code[2]) shl 16); 5264 bytes:=bytes or (ord(insentry^.code[3]) shl 8); 5265 bytes:=bytes or (ord(insentry^.code[4]) shl 0); 5266 { set Rn and Rd } 5267 bytes:=bytes or getsupreg(oper[0]^.reg) shl 12; 5268 5269 if (ops=2) and (opcode in [A_LDREX]) then 5270 begin 5271 bytes:=bytes or getsupreg(oper[1]^.ref^.base) shl 16; 5272 if getregtype(oper[1]^.ref^.index)=R_INVALIDREGISTER then 5273 begin 5274 { set offset } 5275 offset:=0; 5276 currsym:=objdata.symbolref(oper[1]^.ref^.symbol); 5277 if assigned(currsym) then 5278 offset:=currsym.offset-insoffset-8; 5279 offset:=(offset+oper[1]^.ref^.offset) div 4; 5280 if offset>=0 then 5281 begin 5282 bytes:=bytes or offset 5283 end 5284 else 5285 begin 5286 message(asmw_e_invalid_opcode_and_operands); 5287 end; 5288 end 5289 else 5290 begin 5291 message(asmw_e_invalid_opcode_and_operands); 5292 end; 5293 end 5294 else if (ops=2) then 5295 begin 5296 bytes:=bytes or getsupreg(oper[1]^.ref^.base) shl 16; 5297 end 5298 else 5299 begin 5300 bytes:=bytes or getsupreg(oper[1]^.reg) shl 8; 5301 bytes:=bytes or getsupreg(oper[2]^.ref^.base) shl 16; 5302 end; 5303 end; 5304 #$8B: { Thumb-2: STREX } 5305 begin 5306 { set instruction code } 5307 bytes:=bytes or (ord(insentry^.code[1]) shl 24); 5308 bytes:=bytes or (ord(insentry^.code[2]) shl 16); 5309 bytes:=bytes or (ord(insentry^.code[3]) shl 8); 5310 bytes:=bytes or (ord(insentry^.code[4]) shl 0); 5311 { set Rn and Rd } 5312 if (ops=3) and (opcode in [A_STREX]) then 5313 begin 5314 bytes:=bytes or getsupreg(oper[0]^.reg) shl 8; 5315 bytes:=bytes or getsupreg(oper[1]^.reg) shl 12; 5316 bytes:=bytes or getsupreg(oper[2]^.ref^.base) shl 16; 5317 if getregtype(oper[2]^.ref^.index)=R_INVALIDREGISTER then 5318 begin 5319 { set offset } 5320 offset:=0; 5321 currsym:=objdata.symbolref(oper[2]^.ref^.symbol); 5322 if assigned(currsym) then 5323 offset:=currsym.offset-insoffset-8; 5324 offset:=(offset+oper[2]^.ref^.offset) div 4; 5325 if offset>=0 then 5326 begin 5327 bytes:=bytes or offset 5328 end 5329 else 5330 begin 5331 message(asmw_e_invalid_opcode_and_operands); 5332 end; 5333 end 5334 else 5335 begin 5336 message(asmw_e_invalid_opcode_and_operands); 5337 end; 5338 end 5339 else if (ops=3) then 5340 begin 5341 bytes:=bytes or getsupreg(oper[0]^.reg) shl 0; 5342 bytes:=bytes or getsupreg(oper[1]^.reg) shl 12; 5343 bytes:=bytes or getsupreg(oper[2]^.ref^.base) shl 16; 5344 end 5345 else 5346 begin 5347 bytes:=bytes or getsupreg(oper[0]^.reg) shl 0; 5348 bytes:=bytes or getsupreg(oper[1]^.reg) shl 12; 5349 bytes:=bytes or getsupreg(oper[2]^.reg) shl 8; 5350 bytes:=bytes or getsupreg(oper[3]^.ref^.base) shl 16; 5351 end; 5352 end; 5353 #$8C: { Thumb-2: LDM/STM } 5354 begin 5355 { set instruction code } 5356 bytes:=bytes or (ord(insentry^.code[1]) shl 24); 5357 bytes:=bytes or (ord(insentry^.code[2]) shl 16); 5358 bytes:=bytes or (ord(insentry^.code[3]) shl 8); 5359 bytes:=bytes or (ord(insentry^.code[4]) shl 0); 5360 5361 if oper[0]^.typ=top_reg then 5362 bytes:=bytes or (getsupreg(oper[0]^.reg) shl 16) 5363 else 5364 begin 5365 bytes:=bytes or (getsupreg(oper[0]^.ref^.base) shl 16); 5366 if oper[0]^.ref^.addressmode<>AM_OFFSET then 5367 bytes:=bytes or (1 shl 21); 5368 end; 5369 5370 for r:=0 to 15 do 5371 if r in oper[1]^.regset^ then 5372 bytes:=bytes or (1 shl r); 5373 5374 case oppostfix of 5375 PF_None,PF_IA,PF_FD: bytes:=bytes or ($1 shl 23); 5376 PF_DB,PF_EA: bytes:=bytes or ($2 shl 23); 5377 end; 5378 end; 5379 #$8D: { Thumb-2: BL/BLX } 5380 begin 5381 { set instruction code } 5382 bytes:=bytes or (ord(insentry^.code[1]) shl 24); 5383 bytes:=bytes or (ord(insentry^.code[2]) shl 8); 5384 { set offset } 5385 if oper[0]^.typ=top_const then 5386 offset:=(oper[0]^.val shr 1) and $FFFFFF 5387 else 5388 begin 5389 currsym:=objdata.symbolref(oper[0]^.ref^.symbol); 5390 if (currsym.bind<>AB_LOCAL) and (currsym.objsection<>objdata.CurrObjSec) then 5391 begin 5392 objdata.writereloc(oper[0]^.ref^.offset,0,currsym,RELOC_RELATIVE_24_THUMB); 5393 offset:=$FFFFFE 5394 end 5395 else 5396 offset:=((currsym.offset-insoffset-8) shr 1) and $FFFFFF; 5397 end; 5398 5399 bytes:=bytes or ((offset shr 00) and $7FF) shl 0; 5400 bytes:=bytes or ((offset shr 11) and $3FF) shl 16; 5401 bytes:=bytes or (((offset shr 21) xor (offset shr 23) xor 1) and $1) shl 11; 5402 bytes:=bytes or (((offset shr 22) xor (offset shr 23) xor 1) and $1) shl 13; 5403 bytes:=bytes or ((offset shr 23) and $1) shl 26; 5404 end; 5405 #$8E: { Thumb-2: TBB/TBH } 5406 begin 5407 { set instruction code } 5408 bytes:=bytes or (ord(insentry^.code[1]) shl 24); 5409 bytes:=bytes or (ord(insentry^.code[2]) shl 16); 5410 bytes:=bytes or (ord(insentry^.code[3]) shl 8); 5411 bytes:=bytes or ord(insentry^.code[4]); 5412 { set Rn and Rm } 5413 bytes:=bytes or getsupreg(oper[0]^.ref^.base) shl 16; 5414 5415 if getregtype(oper[0]^.ref^.index)=R_INVALIDREGISTER then 5416 message(asmw_e_invalid_effective_address) 5417 else 5418 begin 5419 bytes:=bytes or getsupreg(oper[0]^.ref^.index); 5420 5421 if (opcode=A_TBH) and 5422 (oper[0]^.ref^.shiftmode<>SM_LSL) and 5423 (oper[0]^.ref^.shiftimm<>1) then 5424 message(asmw_e_invalid_effective_address); 5425 end; 5426 end; 5427 #$8F: { Thumb-2: CPSxx } 5428 begin 5429 { set opcode } 5430 bytes:=bytes or (ord(insentry^.code[1]) shl 24); 5431 bytes:=bytes or (ord(insentry^.code[2]) shl 16); 5432 bytes:=bytes or (ord(insentry^.code[3]) shl 8); 5433 bytes:=bytes or ord(insentry^.code[4]); 5434 5435 if (oper[0]^.typ=top_modeflags) then 5436 begin 5437 if mfA in oper[0]^.modeflags then bytes:=bytes or (1 shl 7); 5438 if mfI in oper[0]^.modeflags then bytes:=bytes or (1 shl 6); 5439 if mfF in oper[0]^.modeflags then bytes:=bytes or (1 shl 5); 5440 end; 5441 5442 if (ops=2) then 5443 bytes:=bytes or (oper[1]^.val and $1F) 5444 else if (ops=1) and 5445 (oper[0]^.typ=top_const) then 5446 bytes:=bytes or (oper[0]^.val and $1F); 5447 end; 5448 #$96: { Thumb-2: MSR/MRS } 5449 begin 5450 { set instruction code } 5451 bytes:=bytes or (ord(insentry^.code[1]) shl 24); 5452 bytes:=bytes or (ord(insentry^.code[2]) shl 16); 5453 bytes:=bytes or (ord(insentry^.code[3]) shl 8); 5454 bytes:=bytes or ord(insentry^.code[4]); 5455 5456 if opcode=A_MRS then 5457 begin 5458 bytes:=bytes or (getsupreg(oper[0]^.reg) shl 8); 5459 5460 case oper[1]^.reg of 5461 NR_MSP: bytes:=bytes or $08; 5462 NR_PSP: bytes:=bytes or $09; 5463 5464 NR_IPSR: bytes:=bytes or $05; 5465 NR_EPSR: bytes:=bytes or $06; 5466 NR_APSR: bytes:=bytes or $00; 5467 5468 NR_PRIMASK: bytes:=bytes or $10; 5469 NR_BASEPRI: bytes:=bytes or $11; 5470 NR_BASEPRI_MAX: bytes:=bytes or $12; 5471 NR_FAULTMASK: bytes:=bytes or $13; 5472 NR_CONTROL: bytes:=bytes or $14; 5473 else 5474 Message(asmw_e_invalid_opcode_and_operands); 5475 end; 5476 end 5477 else 5478 begin 5479 bytes:=bytes or (getsupreg(oper[1]^.reg) shl 16); 5480 5481 case oper[0]^.reg of 5482 NR_APSR, 5483 NR_APSR_nzcvqg: bytes:=bytes or $C00; 5484 NR_APSR_g: bytes:=bytes or $400; 5485 NR_APSR_nzcvq: bytes:=bytes or $800; 5486 5487 NR_MSP: bytes:=bytes or $08; 5488 NR_PSP: bytes:=bytes or $09; 5489 5490 NR_PRIMASK: bytes:=bytes or $10; 5491 NR_BASEPRI: bytes:=bytes or $11; 5492 NR_BASEPRI_MAX: bytes:=bytes or $12; 5493 5494 NR_FAULTMASK: bytes:=bytes or $13; 5495 NR_CONTROL: bytes:=bytes or $14; 5496 else 5497 Message(asmw_e_invalid_opcode_and_operands); 5498 end; 5499 end; 5500 end; 5501 #$A0: { FPA: CPDT(LDF/STF) } 5502 begin 5503 { set instruction code } 5504 bytes:=bytes or (ord(insentry^.code[1]) shl 24); 5505 bytes:=bytes or (ord(insentry^.code[2]) shl 16); 5506 bytes:=bytes or (ord(insentry^.code[3]) shl 8); 5507 bytes:=bytes or ord(insentry^.code[4]); 5508 5509 if ops=2 then 5510 begin 5511 bytes:=bytes or getsupreg(oper[0]^.reg) shl 12; 5512 5513 bytes:=bytes or getsupreg(oper[1]^.ref^.base) shl 16; 5514 bytes:=bytes or ((oper[1]^.ref^.offset shr 2) and $FF); 5515 if oper[1]^.ref^.offset>=0 then 5516 bytes:=bytes or (1 shl 23); 5517 5518 if oper[1]^.ref^.addressmode<>AM_OFFSET then 5519 bytes:=bytes or (1 shl 21); 5520 if oper[1]^.ref^.addressmode=AM_PREINDEXED then 5521 bytes:=bytes or (1 shl 24); 5522 5523 case oppostfix of 5524 PF_D: bytes:=bytes or (0 shl 22) or (1 shl 15); 5525 PF_E: bytes:=bytes or (1 shl 22) or (0 shl 15); 5526 PF_P: bytes:=bytes or (1 shl 22) or (1 shl 15); 5527 end; 5528 end 5529 else 5530 begin 5531 bytes:=bytes or getsupreg(oper[0]^.reg) shl 12; 5532 5533 case oper[1]^.val of 5534 1: bytes:=bytes or (1 shl 15); 5535 2: bytes:=bytes or (1 shl 22); 5536 3: bytes:=bytes or (1 shl 22) or (1 shl 15); 5537 4: ; 5538 else 5539 message1(asmw_e_invalid_opcode_and_operands, 'Invalid count for LFM/SFM'); 5540 end; 5541 5542 bytes:=bytes or getsupreg(oper[2]^.ref^.base) shl 16; 5543 bytes:=bytes or ((oper[2]^.ref^.offset shr 2) and $FF); 5544 if oper[2]^.ref^.offset>=0 then 5545 bytes:=bytes or (1 shl 23); 5546 5547 if oper[2]^.ref^.addressmode<>AM_OFFSET then 5548 bytes:=bytes or (1 shl 21); 5549 if oper[2]^.ref^.addressmode=AM_PREINDEXED then 5550 bytes:=bytes or (1 shl 24); 5551 end; 5552 end; 5553 #$A1: { FPA: CPDO } 5554 begin 5555 { set instruction code } 5556 bytes:=bytes or ($E shl 24); 5557 bytes:=bytes or (ord(insentry^.code[1]) shl 15); 5558 bytes:=bytes or ((ord(insentry^.code[2]) shr 1) shl 20); 5559 bytes:=bytes or (1 shl 8); 5560 5561 bytes:=bytes or getsupreg(oper[0]^.reg) shl 12; 5562 if ops=2 then 5563 begin 5564 if oper[1]^.typ=top_reg then 5565 bytes:=bytes or getsupreg(oper[1]^.reg) shl 0 5566 else 5567 case oper[1]^.val of 5568 0: bytes:=bytes or $8; 5569 1: bytes:=bytes or $9; 5570 2: bytes:=bytes or $A; 5571 3: bytes:=bytes or $B; 5572 4: bytes:=bytes or $C; 5573 5: bytes:=bytes or $D; 5574 //0.5: bytes:=bytes or $E; 5575 10: bytes:=bytes or $F; 5576 else 5577 Message(asmw_e_invalid_opcode_and_operands); 5578 end; 5579 end 5580 else 5581 begin 5582 bytes:=bytes or getsupreg(oper[1]^.reg) shl 16; 5583 if oper[2]^.typ=top_reg then 5584 bytes:=bytes or getsupreg(oper[2]^.reg) shl 0 5585 else 5586 case oper[2]^.val of 5587 0: bytes:=bytes or $8; 5588 1: bytes:=bytes or $9; 5589 2: bytes:=bytes or $A; 5590 3: bytes:=bytes or $B; 5591 4: bytes:=bytes or $C; 5592 5: bytes:=bytes or $D; 5593 //0.5: bytes:=bytes or $E; 5594 10: bytes:=bytes or $F; 5595 else 5596 Message(asmw_e_invalid_opcode_and_operands); 5597 end; 5598 end; 5599 5600 case roundingmode of 5601 RM_P: bytes:=bytes or (1 shl 5); 5602 RM_M: bytes:=bytes or (2 shl 5); 5603 RM_Z: bytes:=bytes or (3 shl 5); 5604 end; 5605 5606 case oppostfix of 5607 PF_S: bytes:=bytes or (0 shl 19) or (0 shl 7); 5608 PF_D: bytes:=bytes or (0 shl 19) or (1 shl 7); 5609 PF_E: bytes:=bytes or (1 shl 19) or (0 shl 7); 5610 else 5611 message1(asmw_e_invalid_opcode_and_operands, 'Precision cannot be undefined'); 5612 end; 5613 end; 5614 #$A2: { FPA: CPDO } 5615 begin 5616 { set instruction code } 5617 bytes:=bytes or (ord(insentry^.code[1]) shl 24); 5618 bytes:=bytes or (ord(insentry^.code[2]) shl 16); 5619 bytes:=bytes or ($11 shl 4); 5620 5621 case opcode of 5622 A_FLT: 5623 begin 5624 bytes:=bytes or (getsupreg(oper[0]^.reg) shl 16); 5625 bytes:=bytes or (getsupreg(oper[1]^.reg) shl 12); 5626 5627 case roundingmode of 5628 RM_P: bytes:=bytes or (1 shl 5); 5629 RM_M: bytes:=bytes or (2 shl 5); 5630 RM_Z: bytes:=bytes or (3 shl 5); 5631 end; 5632 5633 case oppostfix of 5634 PF_S: bytes:=bytes or (0 shl 19) or (0 shl 7); 5635 PF_D: bytes:=bytes or (0 shl 19) or (1 shl 7); 5636 PF_E: bytes:=bytes or (1 shl 19) or (0 shl 7); 5637 else 5638 message1(asmw_e_invalid_opcode_and_operands, 'Precision cannot be undefined'); 5639 end; 5640 end; 5641 A_FIX: 5642 begin 5643 bytes:=bytes or (getsupreg(oper[0]^.reg) shl 12); 5644 bytes:=bytes or (getsupreg(oper[1]^.reg) shl 0); 5645 5646 case roundingmode of 5647 RM_P: bytes:=bytes or (1 shl 5); 5648 RM_M: bytes:=bytes or (2 shl 5); 5649 RM_Z: bytes:=bytes or (3 shl 5); 5650 end; 5651 end; 5652 A_WFS,A_RFS,A_WFC,A_RFC: 5653 begin 5654 bytes:=bytes or (getsupreg(oper[0]^.reg) shl 12); 5655 end; 5656 A_CMF,A_CNF,A_CMFE,A_CNFE: 5657 begin 5658 bytes:=bytes or (getsupreg(oper[0]^.reg) shl 16); 5659 5660 if oper[1]^.typ=top_reg then 5661 bytes:=bytes or getsupreg(oper[1]^.reg) shl 0 5662 else 5663 case oper[1]^.val of 5664 0: bytes:=bytes or $8; 5665 1: bytes:=bytes or $9; 5666 2: bytes:=bytes or $A; 5667 3: bytes:=bytes or $B; 5668 4: bytes:=bytes or $C; 5669 5: bytes:=bytes or $D; 5670 //0.5: bytes:=bytes or $E; 5671 10: bytes:=bytes or $F; 5672 else 5673 Message(asmw_e_invalid_opcode_and_operands); 5674 end; 5675 end; 5676 end; 5677 end; 5678 #$fe: // No written data 5679 begin 5680 exit; 5681 end; 5682 #$ff: 5683 internalerror(2005091101); 5684 else 5685 begin 5686 writeln(ord(insentry^.code[0]), ' - ', opcode); 5687 internalerror(2005091102); 5688 end; 5689 end; 5690 5691 { Todo: Decide whether the code above should take care of writing data in an order that makes senes } 5692 if (insentry^.code[0] in [#$80..#$96]) and (bytelen=4) then 5693 bytes:=((bytes shr 16) and $FFFF) or ((bytes and $FFFF) shl 16); 5694 5695 { we're finished, write code } 5696 objdata.writebytes(bytes,bytelen); 5697 end; 5698 5699 begin 5700 cai_align:=tai_align; 5701 end. 5702 5703