/compiler/aarch64/aasmcpu.pas
Pascal | 2178 lines | 656 code | 157 blank | 1365 comment | 24 complexity | ecb4854ef356f8e9d9ed85b01a664947 MD5 | raw file
Possible License(s): LGPL-2.0, LGPL-2.1, LGPL-3.0
Large files files are truncated, but you can click here to view the full file
1{ 2 Copyright (c) 2003-2012 by Florian Klaempfl and others 3 4 Contains the assembler object for ARM64 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} 22unit aasmcpu; 23 24{$i fpcdefs.inc} 25 26interface 27 28uses 29 cclasses,globtype,globals,verbose, 30 aasmbase,aasmtai,aasmdata,aasmsym, 31 ogbase, 32 symtype, 33 cpubase,cpuinfo,cgbase,cgutils; 34 35 const 36 { "mov reg,reg" source operand number } 37 O_MOV_SOURCE = 1; 38 { "mov reg,reg" source operand number } 39 O_MOV_DEST = 0; 40 41 { Operand types } 42 OT_NONE = $00000000; 43 44 OT_BITS8 = $00000001; { size, and other attributes, of the operand } 45 OT_BITS16 = $00000002; 46 OT_BITS32 = $00000004; 47 OT_BITS64 = $00000008; { FPU only } 48 OT_BITS80 = $00000010; 49 OT_FAR = $00000020; { this means 16:16 or 16:32, like in CALL/JMP } 50 OT_NEAR = $00000040; 51 OT_SHORT = $00000080; 52 OT_BITSTINY = $00000100; { fpu constant } 53 OT_BITSSHIFTER = 54 $00000200; 55 56 OT_SIZE_MASK = $000003FF; { all the size attributes } 57 OT_NON_SIZE = longint(not OT_SIZE_MASK); 58 59 OT_SIGNED = $00000100; { the operand need to be signed -128-127 } 60 61 OT_TO = $00000200; { operand is followed by a colon } 62 { reverse effect in FADD, FSUB &c } 63 OT_COLON = $00000400; 64 65 OT_SHIFTEROP = $00000800; 66 OT_REGISTER = $00001000; 67 OT_IMMEDIATE = $00002000; 68 OT_REGLIST = $00008000; 69 OT_IMM8 = $00002001; 70 OT_IMM24 = $00002002; 71 OT_IMM32 = $00002004; 72 OT_IMM64 = $00002008; 73 OT_IMM80 = $00002010; 74 OT_IMMTINY = $00002100; 75 OT_IMMSHIFTER= $00002200; 76 OT_IMMEDIATE24 = OT_IMM24; 77 OT_SHIFTIMM = OT_SHIFTEROP or OT_IMMSHIFTER; 78 OT_SHIFTIMMEDIATE = OT_SHIFTIMM; 79 OT_IMMEDIATESHIFTER = OT_IMMSHIFTER; 80 81 OT_IMMEDIATEFPU = OT_IMMTINY; 82 83 OT_REGMEM = $00200000; { for r/m, ie EA, operands } 84 OT_REGNORM = $00201000; { 'normal' reg, qualifies as EA } 85 OT_REG8 = $00201001; 86 OT_REG16 = $00201002; 87 OT_REG32 = $00201004; 88 OT_REG64 = $00201008; 89 OT_VREG = $00201010; { vector register } 90 OT_REGF = $00201020; { coproc register } 91 OT_MEMORY = $00204000; { register number in 'basereg' } 92 OT_MEM8 = $00204001; 93 OT_MEM16 = $00204002; 94 OT_MEM32 = $00204004; 95 OT_MEM64 = $00204008; 96 OT_MEM80 = $00204010; 97 { word/byte load/store } 98 OT_AM2 = $00010000; 99 { misc ld/st operations } 100 OT_AM3 = $00020000; 101 { multiple ld/st operations } 102 OT_AM4 = $00040000; 103 { co proc. ld/st operations } 104 OT_AM5 = $00080000; 105 OT_AMMASK = $000f0000; 106 { IT instruction } 107 OT_CONDITION = $00100000; 108 109 OT_MEMORYAM2 = OT_MEMORY or OT_AM2; 110 OT_MEMORYAM3 = OT_MEMORY or OT_AM3; 111 OT_MEMORYAM4 = OT_MEMORY or OT_AM4; 112 OT_MEMORYAM5 = OT_MEMORY or OT_AM5; 113 114 OT_FPUREG = $01000000; { floating point stack registers } 115 OT_REG_SMASK = $00070000; { special register operands: these may be treated differently } 116 { a mask for the following } 117 118 OT_MEM_OFFS = $00604000; { special type of EA } 119 { simple [address] offset } 120 OT_ONENESS = $00800000; { special type of immediate operand } 121 { so UNITY == IMMEDIATE | ONENESS } 122 OT_UNITY = $00802000; { for shift/rotate instructions } 123 124 instabentries = {$i a64nop.inc} 125 126 maxinfolen = 5; 127 128 IF_NONE = $00000000; 129 130 IF_ARMMASK = $000F0000; 131 IF_ARM7 = $00070000; 132 IF_FPMASK = $00F00000; 133 IF_FPA = $00100000; 134 135 { if the instruction can change in a second pass } 136 IF_PASS2 = longint($80000000); 137 138 type 139 TInsTabCache=array[TasmOp] of longint; 140 PInsTabCache=^TInsTabCache; 141 142 tinsentry = record 143 opcode : tasmop; 144 ops : byte; 145 optypes : array[0..3] of longint; 146 code : array[0..maxinfolen] of char; 147 flags : longint; 148 end; 149 150 pinsentry=^tinsentry; 151 152{ const 153 InsTab : array[0..instabentries-1] of TInsEntry={$i a64tab.inc} } 154 155 var 156 InsTabCache : PInsTabCache; 157 158 type 159 taicpu = class(tai_cpu_abstract_sym) 160 oppostfix : TOpPostfix; 161 procedure loadshifterop(opidx:longint;const so:tshifterop); 162 constructor op_none(op : tasmop); 163 164 constructor op_reg(op : tasmop;_op1 : tregister); 165 constructor op_ref(op : tasmop;const _op1 : treference); 166 constructor op_const(op : tasmop;_op1 : longint); 167 168 constructor op_reg_reg(op : tasmop;_op1,_op2 : tregister); 169 constructor op_reg_ref(op : tasmop;_op1 : tregister;const _op2 : treference); 170 constructor op_reg_const(op:tasmop; _op1: tregister; _op2: aint); 171 172 constructor op_reg_reg_reg(op : tasmop;_op1,_op2,_op3 : tregister); 173 constructor op_reg_reg_reg_reg(op : tasmop;_op1,_op2,_op3,_op4 : tregister); 174 constructor op_reg_reg_const(op : tasmop;_op1,_op2 : tregister; _op3: aint); 175 constructor op_reg_reg_sym_ofs(op : tasmop;_op1,_op2 : tregister; _op3: tasmsymbol;_op3ofs: longint); 176 constructor op_reg_reg_ref(op : tasmop;_op1,_op2 : tregister; const _op3: treference); 177 constructor op_reg_reg_shifterop(op : tasmop;_op1,_op2 : tregister;_op3 : tshifterop); 178 constructor op_reg_reg_reg_shifterop(op : tasmop;_op1,_op2,_op3 : tregister;_op4 : tshifterop); 179 180 { this is for Jmp instructions } 181 constructor op_cond_sym(op : tasmop;cond:TAsmCond;_op1 : tasmsymbol); 182 183 constructor op_sym(op : tasmop;_op1 : tasmsymbol); 184 constructor op_sym_ofs(op : tasmop;_op1 : tasmsymbol;_op1ofs:longint); 185 constructor op_reg_sym_ofs(op : tasmop;_op1 : tregister;_op2:tasmsymbol;_op2ofs : longint); 186 constructor op_sym_ofs_ref(op : tasmop;_op1 : tasmsymbol;_op1ofs:longint;const _op2 : treference); 187 188 function is_same_reg_move(regtype: Tregistertype):boolean; override; 189 190 function spilling_get_operation_type(opnr: longint): topertype;override; 191 192 { assembler } 193 public 194 { the next will reset all instructions that can change in pass 2 } 195 procedure ResetPass1;override; 196 procedure ResetPass2;override; 197 function CheckIfValid:boolean; 198 function GetString:string; 199 function Pass1(objdata:TObjData):longint;override; 200 procedure Pass2(objdata:TObjData);override; 201 protected 202 procedure ppuloadoper(ppufile:tcompilerppufile;var o:toper);override; 203 procedure ppuwriteoper(ppufile:tcompilerppufile;const o:toper);override; 204 procedure ppubuildderefimploper(var o:toper);override; 205 procedure ppuderefoper(var o:toper);override; 206 private 207 { next fields are filled in pass1, so pass2 is faster } 208 inssize : shortint; 209 insoffset : longint; 210 LastInsOffset : longint; { need to be public to be reset } 211 insentry : PInsEntry; 212 function InsEnd:longint; 213 procedure create_ot(objdata:TObjData); 214 function Matches(p:PInsEntry):longint; 215 function calcsize(p:PInsEntry):shortint; 216 procedure gencode(objdata:TObjData); 217 function NeedAddrPrefix(opidx:byte):boolean; 218 procedure Swapoperands; 219 function FindInsentry(objdata:TObjData):boolean; 220 end; 221 222 tai_align = class(tai_align_abstract) 223 { nothing to add } 224 end; 225 226 function spilling_create_load(const ref:treference;r:tregister):Taicpu; 227 function spilling_create_store(r:tregister; const ref:treference):Taicpu; 228 229 function setoppostfix(i : taicpu;pf : toppostfix) : taicpu; 230 function setcondition(i : taicpu;c : tasmcond) : taicpu; 231 232 { inserts pc relative symbols at places where they are reachable 233 and transforms special instructions to valid instruction encodings } 234 procedure finalizearmcode(list,listtoinsert : TAsmList); 235 { inserts .pdata section and dummy function prolog needed for arm-wince exception handling } 236 procedure InsertPData; 237 238 procedure InitAsm; 239 procedure DoneAsm; 240 241 242implementation 243 244 uses 245 cutils,rgobj,itcpugas,aoptcpu; 246 247 248 procedure taicpu.loadshifterop(opidx:longint;const so:tshifterop); 249 begin 250 allocate_oper(opidx+1); 251 with oper[opidx]^ do 252 begin 253 if typ<>top_shifterop then 254 begin 255 clearop(opidx); 256 new(shifterop); 257 end; 258 shifterop^:=so; 259 typ:=top_shifterop; 260 end; 261 end; 262 263 264{***************************************************************************** 265 taicpu Constructors 266*****************************************************************************} 267 268 constructor taicpu.op_none(op : tasmop); 269 begin 270 inherited create(op); 271 end; 272 273 274 { for pld } 275 constructor taicpu.op_ref(op : tasmop;const _op1 : treference); 276 begin 277 inherited create(op); 278 ops:=1; 279 loadref(0,_op1); 280 end; 281 282 283 constructor taicpu.op_reg(op : tasmop;_op1 : tregister); 284 begin 285 inherited create(op); 286 ops:=1; 287 loadreg(0,_op1); 288 end; 289 290 291 constructor taicpu.op_const(op : tasmop;_op1 : longint); 292 begin 293 inherited create(op); 294 ops:=1; 295 loadconst(0,aint(_op1)); 296 end; 297 298 299 constructor taicpu.op_reg_reg(op : tasmop;_op1,_op2 : tregister); 300 begin 301 inherited create(op); 302 ops:=2; 303 loadreg(0,_op1); 304 loadreg(1,_op2); 305 end; 306 307 308 constructor taicpu.op_reg_const(op:tasmop; _op1: tregister; _op2: aint); 309 begin 310 inherited create(op); 311 ops:=2; 312 loadreg(0,_op1); 313 loadconst(1,aint(_op2)); 314 end; 315 316 317 constructor taicpu.op_reg_ref(op : tasmop;_op1 : tregister;const _op2 : treference); 318 begin 319 inherited create(op); 320 ops:=2; 321 loadreg(0,_op1); 322 loadref(1,_op2); 323 end; 324 325 326 constructor taicpu.op_reg_reg_reg(op : tasmop;_op1,_op2,_op3 : tregister); 327 begin 328 inherited create(op); 329 ops:=3; 330 loadreg(0,_op1); 331 loadreg(1,_op2); 332 loadreg(2,_op3); 333 end; 334 335 336 constructor taicpu.op_reg_reg_reg_reg(op : tasmop;_op1,_op2,_op3,_op4 : tregister); 337 begin 338 inherited create(op); 339 ops:=4; 340 loadreg(0,_op1); 341 loadreg(1,_op2); 342 loadreg(2,_op3); 343 loadreg(3,_op4); 344 end; 345 346 347 constructor taicpu.op_reg_reg_const(op : tasmop;_op1,_op2 : tregister; _op3: aint); 348 begin 349 inherited create(op); 350 ops:=3; 351 loadreg(0,_op1); 352 loadreg(1,_op2); 353 loadconst(2,aint(_op3)); 354 end; 355 356 357 constructor taicpu.op_reg_reg_sym_ofs(op : tasmop;_op1,_op2 : tregister; _op3: tasmsymbol;_op3ofs: longint); 358 begin 359 inherited create(op); 360 ops:=3; 361 loadreg(0,_op1); 362 loadreg(1,_op2); 363 loadsymbol(0,_op3,_op3ofs); 364 end; 365 366 367 constructor taicpu.op_reg_reg_ref(op : tasmop;_op1,_op2 : tregister; const _op3: treference); 368 begin 369 inherited create(op); 370 ops:=3; 371 loadreg(0,_op1); 372 loadreg(1,_op2); 373 loadref(2,_op3); 374 end; 375 376 377 constructor taicpu.op_reg_reg_shifterop(op : tasmop;_op1,_op2 : tregister;_op3 : tshifterop); 378 begin 379 inherited create(op); 380 ops:=3; 381 loadreg(0,_op1); 382 loadreg(1,_op2); 383 loadshifterop(2,_op3); 384 end; 385 386 387 constructor taicpu.op_reg_reg_reg_shifterop(op : tasmop;_op1,_op2,_op3 : tregister;_op4 : tshifterop); 388 begin 389 inherited create(op); 390 ops:=4; 391 loadreg(0,_op1); 392 loadreg(1,_op2); 393 loadreg(2,_op3); 394 loadshifterop(3,_op4); 395 end; 396 397 398 constructor taicpu.op_cond_sym(op : tasmop;cond:TAsmCond;_op1 : tasmsymbol); 399 begin 400 inherited create(op); 401 condition:=cond; 402 ops:=1; 403 loadsymbol(0,_op1,0); 404 end; 405 406 407 constructor taicpu.op_sym(op : tasmop;_op1 : tasmsymbol); 408 begin 409 inherited create(op); 410 ops:=1; 411 loadsymbol(0,_op1,0); 412 end; 413 414 415 constructor taicpu.op_sym_ofs(op : tasmop;_op1 : tasmsymbol;_op1ofs:longint); 416 begin 417 inherited create(op); 418 ops:=1; 419 loadsymbol(0,_op1,_op1ofs); 420 end; 421 422 423 constructor taicpu.op_reg_sym_ofs(op : tasmop;_op1 : tregister;_op2:tasmsymbol;_op2ofs : longint); 424 begin 425 inherited create(op); 426 ops:=2; 427 loadreg(0,_op1); 428 loadsymbol(1,_op2,_op2ofs); 429 end; 430 431 432 constructor taicpu.op_sym_ofs_ref(op : tasmop;_op1 : tasmsymbol;_op1ofs:longint;const _op2 : treference); 433 begin 434 inherited create(op); 435 ops:=2; 436 loadsymbol(0,_op1,_op1ofs); 437 loadref(1,_op2); 438 end; 439 440 441 function taicpu.is_same_reg_move(regtype: Tregistertype):boolean; 442 begin 443 { allow the register allocator to remove unnecessary moves } 444 result:=( 445 ((opcode=A_MOV) and (regtype = R_INTREGISTER)) or 446 ((opcode=A_FMOV) and (regtype = R_MMREGISTER)) 447 ) and 448 (oppostfix in [PF_None]) and 449 (condition=C_None) and 450 (ops=2) and 451 (oper[0]^.typ=top_reg) and 452 (oper[1]^.typ=top_reg) and 453 (oper[0]^.reg=oper[1]^.reg); 454 end; 455 456 457 function spilling_create_load(const ref:treference;r:tregister):Taicpu; 458 var 459 op: tasmop; 460 begin 461 case getregtype(r) of 462 R_INTREGISTER : 463 result:=taicpu.op_reg_ref(A_LDR,r,ref); 464 R_MMREGISTER : 465 begin 466 case getsubreg(r) of 467 R_SUBFD: 468 op:=A_LDR; 469 R_SUBFS: 470 op:=A_LDR; 471 else 472 internalerror(2009112905); 473 end; 474 result:=taicpu.op_reg_ref(op,r,ref); 475 end; 476 else 477 internalerror(200401041); 478 end; 479 end; 480 481 482 function spilling_create_store(r:tregister; const ref:treference):Taicpu; 483 var 484 op: tasmop; 485 begin 486 case getregtype(r) of 487 R_INTREGISTER : 488 result:=taicpu.op_reg_ref(A_STR,r,ref); 489 R_MMREGISTER : 490 begin 491 case getsubreg(r) of 492 R_SUBFD: 493 op:=A_STR; 494 R_SUBFS: 495 op:=A_STR; 496 else 497 internalerror(2009112904); 498 end; 499 result:=taicpu.op_reg_ref(op,r,ref); 500 end; 501 else 502 internalerror(200401041); 503 end; 504 end; 505 506 507 function taicpu.spilling_get_operation_type(opnr: longint): topertype; 508 begin 509 case opcode of 510 A_ADC,A_ADD,A_AND,A_BIC, 511 A_EOR,A_CLZ,A_RBIT, 512 A_LDR, 513 A_MOV,A_MVN,A_MUL, 514 A_ORR,A_SBC,A_SUB, 515 A_UXT,A_SXT: 516 if opnr=0 then 517 result:=operand_write 518 else 519 result:=operand_read; 520 A_B,A_BL, 521 A_CMN,A_CMP,A_TST: 522 result:=operand_read; 523 A_STR: 524 { important is what happens with the involved registers } 525 if opnr=0 then 526 result := operand_read 527 else 528 { check for pre/post indexed } 529 result := operand_read; 530 else 531 internalerror(200403151); 532 end; 533 end; 534 535 536 procedure BuildInsTabCache; 537 var 538 i : longint; 539 begin 540(* new(instabcache); 541 FillChar(instabcache^,sizeof(tinstabcache),$ff); 542 i:=0; 543 while (i<InsTabEntries) do 544 begin 545 if InsTabCache^[InsTab[i].Opcode]=-1 then 546 InsTabCache^[InsTab[i].Opcode]:=i; 547 inc(i); 548 end; *) 549 end; 550 551 552 procedure InitAsm; 553 begin 554 if not assigned(instabcache) then 555 BuildInsTabCache; 556 end; 557 558 559 procedure DoneAsm; 560 begin 561 if assigned(instabcache) then 562 begin 563 dispose(instabcache); 564 instabcache:=nil; 565 end; 566 end; 567 568 569 function setoppostfix(i : taicpu;pf : toppostfix) : taicpu; 570 begin 571 i.oppostfix:=pf; 572 result:=i; 573 end; 574 575 576 function setcondition(i : taicpu;c : tasmcond) : taicpu; 577 begin 578 i.condition:=c; 579 result:=i; 580 end; 581 582 583 Function SimpleGetNextInstruction(Current: tai; Var Next: tai): Boolean; 584 Begin 585 Current:=tai(Current.Next); 586 While Assigned(Current) And (Current.typ In SkipInstr) Do 587 Current:=tai(Current.Next); 588 Next:=Current; 589 If Assigned(Next) And Not(Next.typ In SkipInstr) Then 590 Result:=True 591 Else 592 Begin 593 Next:=Nil; 594 Result:=False; 595 End; 596 End; 597 598 599(* 600 function armconstequal(hp1,hp2: tai): boolean; 601 begin 602 result:=false; 603 if hp1.typ<>hp2.typ then 604 exit; 605 case hp1.typ of 606 tai_const: 607 result:= 608 (tai_const(hp2).sym=tai_const(hp).sym) and 609 (tai_const(hp2).value=tai_const(hp).value) and 610 (tai(hp2.previous).typ=ait_label); 611 tai_const: 612 result:= 613 (tai_const(hp2).sym=tai_const(hp).sym) and 614 (tai_const(hp2).value=tai_const(hp).value) and 615 (tai(hp2.previous).typ=ait_label); 616 end; 617 end; 618*) 619 620 procedure insertpcrelativedata(list,listtoinsert : TAsmList); 621 var 622 curinspos, 623 penalty, 624 lastinspos, 625 { increased for every data element > 4 bytes inserted } 626 currentsize, 627 extradataoffset, 628 limit: longint; 629 curop : longint; 630 curtai : tai; 631 curdatatai,hp,hp2 : tai; 632 curdata : TAsmList; 633 l : tasmlabel; 634 doinsert, 635 removeref : boolean; 636 begin 637(* 638 curdata:=TAsmList.create; 639 lastinspos:=-1; 640 curinspos:=0; 641 extradataoffset:=0; 642 limit:=1016; 643 curtai:=tai(list.first); 644 doinsert:=false; 645 while assigned(curtai) do 646 begin 647 { instruction? } 648 case curtai.typ of 649 ait_instruction: 650 begin 651 { walk through all operand of the instruction } 652 for curop:=0 to taicpu(curtai).ops-1 do 653 begin 654 { reference? } 655 if (taicpu(curtai).oper[curop]^.typ=top_ref) then 656 begin 657 { pc relative symbol? } 658 curdatatai:=tai(taicpu(curtai).oper[curop]^.ref^.symboldata); 659 if assigned(curdatatai) and 660 { move only if we're at the first reference of a label } 661 not(tai_label(curdatatai).moved) then 662 begin 663 tai_label(curdatatai).moved:=true; 664 { check if symbol already used. } 665 { if yes, reuse the symbol } 666 hp:=tai(curdatatai.next); 667 removeref:=false; 668 if assigned(hp) then 669 begin 670 case hp.typ of 671 ait_const: 672 begin 673 if (tai_const(hp).consttype=aitconst_64bit) then 674 inc(extradataoffset); 675 end; 676 ait_comp_64bit, 677 ait_real_64bit: 678 begin 679 inc(extradataoffset); 680 end; 681 ait_real_80bit: 682 begin 683 inc(extradataoffset,2); 684 end; 685 end; 686 if (hp.typ=ait_const) then 687 begin 688 hp2:=tai(curdata.first); 689 while assigned(hp2) do 690 begin 691 { if armconstequal(hp2,hp) then } 692 if (hp2.typ=ait_const) and (tai_const(hp2).sym=tai_const(hp).sym) 693 and (tai_const(hp2).value=tai_const(hp).value) and (tai(hp2.previous).typ=ait_label) 694 then 695 begin 696 with taicpu(curtai).oper[curop]^.ref^ do 697 begin 698 symboldata:=hp2.previous; 699 symbol:=tai_label(hp2.previous).labsym; 700 end; 701 removeref:=true; 702 break; 703 end; 704 hp2:=tai(hp2.next); 705 end; 706 end; 707 end; 708 { move or remove symbol reference } 709 repeat 710 hp:=tai(curdatatai.next); 711 listtoinsert.remove(curdatatai); 712 if removeref then 713 curdatatai.free 714 else 715 curdata.concat(curdatatai); 716 curdatatai:=hp; 717 until (curdatatai=nil) or (curdatatai.typ=ait_label); 718 if lastinspos=-1 then 719 lastinspos:=curinspos; 720 end; 721 end; 722 end; 723 inc(curinspos); 724 end; 725 ait_align: 726 begin 727 { code is always 4 byte aligned, so we don't have to take care of .align 2 which would 728 requires also incrementing curinspos by 1 } 729 inc(curinspos,(tai_align(curtai).aligntype div 4)); 730 end; 731 ait_const: 732 begin 733 inc(curinspos); 734 if (tai_const(curtai).consttype=aitconst_64bit) then 735 inc(curinspos); 736 end; 737 ait_real_32bit: 738 begin 739 inc(curinspos); 740 end; 741 ait_comp_64bit, 742 ait_real_64bit: 743 begin 744 inc(curinspos,2); 745 end; 746 ait_real_80bit: 747 begin 748 inc(curinspos,3); 749 end; 750 end; 751 { special case for case jump tables } 752 if SimpleGetNextInstruction(curtai,hp) and 753 (tai(hp).typ=ait_instruction) and 754 (taicpu(hp).opcode=A_LDR) and 755 (taicpu(hp).oper[0]^.typ=top_reg) and 756 (taicpu(hp).oper[0]^.reg=NR_PC) then 757 begin 758 penalty:=1; 759 hp:=tai(hp.next); 760 { skip register allocations and comments inserted by the optimizer } 761 while assigned(hp) and (hp.typ in [ait_comment,ait_regalloc]) do 762 hp:=tai(hp.next); 763 while assigned(hp) and (hp.typ=ait_const) do 764 begin 765 inc(penalty); 766 hp:=tai(hp.next); 767 end; 768 end 769 else 770 penalty:=0; 771 772 { FLD/FST VFP instructions have a limit of +/- 1024, not 4096 } 773 if SimpleGetNextInstruction(curtai,hp) and 774 (tai(hp).typ=ait_instruction) and 775 ((taicpu(hp).opcode=A_FLDS) or 776 (taicpu(hp).opcode=A_FLDD)) then 777 limit:=254; 778 779 { don't miss an insert } 780 doinsert:=doinsert or 781 (not(curdata.empty) and 782 (curinspos-lastinspos+penalty+extradataoffset>limit)); 783 784 { split only at real instructions else the test below fails } 785 if doinsert and (curtai.typ=ait_instruction) and 786 ( 787 { don't split loads of pc to lr and the following move } 788 not( 789 (taicpu(curtai).opcode=A_MOV) and 790 (taicpu(curtai).oper[0]^.typ=top_reg) and 791 (taicpu(curtai).oper[0]^.reg=NR_R14) and 792 (taicpu(curtai).oper[1]^.typ=top_reg) and 793 (taicpu(curtai).oper[1]^.reg=NR_PC) 794 ) 795 ) then 796 begin 797 lastinspos:=-1; 798 extradataoffset:=0; 799 limit:=1016; 800 doinsert:=false; 801 hp:=tai(curtai.next); 802 current_asmdata.getjumplabel(l); 803 curdata.insert(taicpu.op_sym(A_B,l)); 804 curdata.concat(tai_label.create(l)); 805 list.insertlistafter(curtai,curdata); 806 curtai:=hp; 807 end 808 else 809 curtai:=tai(curtai.next); 810 end; 811 list.concatlist(curdata); 812 curdata.free; 813*) 814 end; 815 816 817 procedure finalizearmcode(list, listtoinsert: TAsmList); 818 begin 819 insertpcrelativedata(list, listtoinsert); 820 end; 821 822 procedure InsertPData; 823 var 824 prolog: TAsmList; 825 begin 826 prolog:=TAsmList.create; 827 new_section(prolog,sec_code,'FPC_EH_PROLOG',sizeof(pint),secorder_begin); 828 prolog.concat(Tai_const.Createname('_ARM_ExceptionHandler', 0)); 829 prolog.concat(Tai_const.Create_32bit(0)); 830 prolog.concat(Tai_symbol.Createname_global('FPC_EH_CODE_START',AT_DATA,0)); 831 { dummy function } 832 prolog.concat(taicpu.op_reg(A_BR,NR_X29)); 833 current_asmdata.asmlists[al_start].insertList(prolog); 834 prolog.Free; 835 new_section(current_asmdata.asmlists[al_end],sec_pdata,'',sizeof(pint)); 836 current_asmdata.asmlists[al_end].concat(Tai_const.Createname('FPC_EH_CODE_START', 0)); 837 current_asmdata.asmlists[al_end].concat(Tai_const.Create_32bit(longint($ffffff01))); 838 end; 839 840(* 841 Floating point instruction format information, taken from the linux kernel 842 ARM Floating Point Instruction Classes 843 | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 844 |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 845 |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) 846 | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 847 |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 848 |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 849 |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 850 | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 851 852 CPDT data transfer instructions 853 LDF, STF, LFM (copro 2), SFM (copro 2) 854 855 CPDO dyadic arithmetic instructions 856 ADF, MUF, SUF, RSF, DVF, RDF, 857 POW, RPW, RMF, FML, FDV, FRD, POL 858 859 CPDO monadic arithmetic instructions 860 MVF, MNF, ABS, RND, SQT, LOG, LGN, EXP, 861 SIN, COS, TAN, ASN, ACS, ATN, URD, NRM 862 863 CPRT joint arithmetic/data transfer instructions 864 FIX (arithmetic followed by load/store) 865 FLT (load/store followed by arithmetic) 866 CMF, CNF CMFE, CNFE (comparisons) 867 WFS, RFS (write/read floating point status register) 868 WFC, RFC (write/read floating point control register) 869 870 cond condition codes 871 P pre/post index bit: 0 = postindex, 1 = preindex 872 U up/down bit: 0 = stack grows down, 1 = stack grows up 873 W write back bit: 1 = update base register (Rn) 874 L load/store bit: 0 = store, 1 = load 875 Rn base register 876 Rd destination/source register 877 Fd floating point destination register 878 Fn floating point source register 879 Fm floating point source register or floating point constant 880 881 uv transfer length (TABLE 1) 882 wx register count (TABLE 2) 883 abcd arithmetic opcode (TABLES 3 & 4) 884 ef destination size (rounding precision) (TABLE 5) 885 gh rounding mode (TABLE 6) 886 j dyadic/monadic bit: 0 = dyadic, 1 = monadic 887 i constant bit: 1 = constant (TABLE 6) 888 */ 889 890 /* 891 TABLE 1 892 +-------------------------+---+---+---------+---------+ 893 | Precision | u | v | FPSR.EP | length | 894 +-------------------------+---+---+---------+---------+ 895 | Single | 0 | 0 | x | 1 words | 896 | Double | 1 | 1 | x | 2 words | 897 | Extended | 1 | 1 | x | 3 words | 898 | Packed decimal | 1 | 1 | 0 | 3 words | 899 | Expanded packed decimal | 1 | 1 | 1 | 4 words | 900 +-------------------------+---+---+---------+---------+ 901 Note: x = don't care 902 */ 903 904 /* 905 TABLE 2 906 +---+---+---------------------------------+ 907 | w | x | Number of registers to transfer | 908 +---+---+---------------------------------+ 909 | 0 | 1 | 1 | 910 | 1 | 0 | 2 | 911 | 1 | 1 | 3 | 912 | 0 | 0 | 4 | 913 +---+---+---------------------------------+ 914 */ 915 916 /* 917 TABLE 3: Dyadic Floating Point Opcodes 918 +---+---+---+---+----------+-----------------------+-----------------------+ 919 | a | b | c | d | Mnemonic | Description | Operation | 920 +---+---+---+---+----------+-----------------------+-----------------------+ 921 | 0 | 0 | 0 | 0 | ADF | Add | Fd := Fn + Fm | 922 | 0 | 0 | 0 | 1 | MUF | Multiply | Fd := Fn * Fm | 923 | 0 | 0 | 1 | 0 | SUF | Subtract | Fd := Fn - Fm | 924 | 0 | 0 | 1 | 1 | RSF | Reverse subtract | Fd := Fm - Fn | 925 | 0 | 1 | 0 | 0 | DVF | Divide | Fd := Fn / Fm | 926 | 0 | 1 | 0 | 1 | RDF | Reverse divide | Fd := Fm / Fn | 927 | 0 | 1 | 1 | 0 | POW | Power | Fd := Fn ^ Fm | 928 | 0 | 1 | 1 | 1 | RPW | Reverse power | Fd := Fm ^ Fn | 929 | 1 | 0 | 0 | 0 | RMF | Remainder | Fd := IEEE rem(Fn/Fm) | 930 | 1 | 0 | 0 | 1 | FML | Fast Multiply | Fd := Fn * Fm | 931 | 1 | 0 | 1 | 0 | FDV | Fast Divide | Fd := Fn / Fm | 932 | 1 | 0 | 1 | 1 | FRD | Fast reverse divide | Fd := Fm / Fn | 933 | 1 | 1 | 0 | 0 | POL | Polar angle (ArcTan2) | Fd := arctan2(Fn,Fm) | 934 | 1 | 1 | 0 | 1 | | undefined instruction | trap | 935 | 1 | 1 | 1 | 0 | | undefined instruction | trap | 936 | 1 | 1 | 1 | 1 | | undefined instruction | trap | 937 +---+---+---+---+----------+-----------------------+-----------------------+ 938 Note: POW, RPW, POL are deprecated, and are available for backwards 939 compatibility only. 940 */ 941 942 /* 943 TABLE 4: Monadic Floating Point Opcodes 944 +---+---+---+---+----------+-----------------------+-----------------------+ 945 | a | b | c | d | Mnemonic | Description | Operation | 946 +---+---+---+---+----------+-----------------------+-----------------------+ 947 | 0 | 0 | 0 | 0 | MVF | Move | Fd := Fm | 948 | 0 | 0 | 0 | 1 | MNF | Move negated | Fd := - Fm | 949 | 0 | 0 | 1 | 0 | ABS | Absolute value | Fd := abs(Fm) | 950 | 0 | 0 | 1 | 1 | RND | Round to integer | Fd := int(Fm) | 951 | 0 | 1 | 0 | 0 | SQT | Square root | Fd := sqrt(Fm) | 952 | 0 | 1 | 0 | 1 | LOG | Log base 10 | Fd := log10(Fm) | 953 | 0 | 1 | 1 | 0 | LGN | Log base e | Fd := ln(Fm) | 954 | 0 | 1 | 1 | 1 | EXP | Exponent | Fd := e ^ Fm | 955 | 1 | 0 | 0 | 0 | SIN | Sine | Fd := sin(Fm) | 956 | 1 | 0 | 0 | 1 | COS | Cosine | Fd := cos(Fm) | 957 | 1 | 0 | 1 | 0 | TAN | Tangent | Fd := tan(Fm) | 958 | 1 | 0 | 1 | 1 | ASN | Arc Sine | Fd := arcsin(Fm) | 959 | 1 | 1 | 0 | 0 | ACS | Arc Cosine | Fd := arccos(Fm) | 960 | 1 | 1 | 0 | 1 | ATN | Arc Tangent | Fd := arctan(Fm) | 961 | 1 | 1 | 1 | 0 | URD | Unnormalized round | Fd := int(Fm) | 962 | 1 | 1 | 1 | 1 | NRM | Normalize | Fd := norm(Fm) | 963 +---+---+---+---+----------+-----------------------+-----------------------+ 964 Note: LOG, LGN, EXP, SIN, COS, TAN, ASN, ACS, ATN are deprecated, and are 965 available for backwards compatibility only. 966 */ 967 968 /* 969 TABLE 5 970 +-------------------------+---+---+ 971 | Rounding Precision | e | f | 972 +-------------------------+---+---+ 973 | IEEE Single precision | 0 | 0 | 974 | IEEE Double precision | 0 | 1 | 975 | IEEE Extended precision | 1 | 0 | 976 | undefined (trap) | 1 | 1 | 977 +-------------------------+---+---+ 978 */ 979 980 /* 981 TABLE 5 982 +---------------------------------+---+---+ 983 | Rounding Mode | g | h | 984 +---------------------------------+---+---+ 985 | Round to nearest (default) | 0 | 0 | 986 | Round toward plus infinity | 0 | 1 | 987 | Round toward negative infinity | 1 | 0 | 988 | Round toward zero | 1 | 1 | 989 +---------------------------------+---+---+ 990*) 991 function taicpu.GetString:string; 992 var 993 i : longint; 994 s : string; 995 addsize : boolean; 996 begin 997 s:='['+gas_op2str[opcode]; 998 for i:=0 to ops-1 do 999 begin 1000 with oper[i]^ do 1001 begin 1002 if i=0 then 1003 s:=s+' ' 1004 else 1005 s:=s+','; 1006 { type } 1007 addsize:=false; 1008 if (ot and OT_VREG)=OT_VREG then 1009 s:=s+'vreg' 1010 else 1011 if (ot and OT_FPUREG)=OT_FPUREG then 1012 s:=s+'fpureg' 1013 else 1014 if (ot and OT_REGISTER)=OT_REGISTER then 1015 begin 1016 s:=s+'reg'; 1017 addsize:=true; 1018 end 1019 else 1020 if (ot and OT_REGLIST)=OT_REGLIST then 1021 begin 1022 s:=s+'reglist'; 1023 addsize:=false; 1024 end 1025 else 1026 if (ot and OT_IMMEDIATE)=OT_IMMEDIATE then 1027 begin 1028 s:=s+'imm'; 1029 addsize:=true; 1030 end 1031 else 1032 if (ot and OT_MEMORY)=OT_MEMORY then 1033 begin 1034 s:=s+'mem'; 1035 addsize:=true; 1036 if (ot and OT_AM2)<>0 then 1037 s:=s+' am2 '; 1038 end 1039 else 1040 s:=s+'???'; 1041 { size } 1042 if addsize then 1043 begin 1044 if (ot and OT_BITS8)<>0 then 1045 s:=s+'8' 1046 else 1047 if (ot and OT_BITS16)<>0 then 1048 s:=s+'24' 1049 else 1050 if (ot and OT_BITS32)<>0 then 1051 s:=s+'32' 1052 else 1053 if (ot and OT_BITSSHIFTER)<>0 then 1054 s:=s+'shifter' 1055 else 1056 s:=s+'??'; 1057 { signed } 1058 if (ot and OT_SIGNED)<>0 then 1059 s:=s+'s'; 1060 end; 1061 end; 1062 end; 1063 GetString:=s+']'; 1064 end; 1065 1066 1067 procedure taicpu.ResetPass1; 1068 begin 1069 { we need to reset everything here, because the choosen insentry 1070 can be invalid for a new situation where the previously optimized 1071 insentry is not correct } 1072 InsEntry:=nil; 1073 InsSize:=0; 1074 LastInsOffset:=-1; 1075 end; 1076 1077 1078 procedure taicpu.ResetPass2; 1079 begin 1080 { we are here in a second pass, check if the instruction can be optimized } 1081 if assigned(InsEntry) and 1082 ((InsEntry^.flags and IF_PASS2)<>0) then 1083 begin 1084 InsEntry:=nil; 1085 InsSize:=0; 1086 end; 1087 LastInsOffset:=-1; 1088 end; 1089 1090 1091 function taicpu.CheckIfValid:boolean; 1092 begin 1093 Result:=False; { unimplemented } 1094 end; 1095 1096 1097 function taicpu.Pass1(objdata:TObjData):longint; 1098 begin 1099 Pass1:=0; 1100 LastInsOffset:=-1; 1101 end; 1102 1103 1104 procedure taicpu.Pass2(objdata:TObjData); 1105 begin 1106 { error in pass1 ? } 1107 if insentry=nil then 1108 exit; 1109 current_filepos:=fileinfo; 1110 { Generate the instruction } 1111 GenCode(objdata); 1112 end; 1113 1114 1115 procedure taicpu.ppuloadoper(ppufile:tcompilerppufile;var o:toper); 1116 begin 1117 end; 1118 1119 1120 procedure taicpu.ppuwriteoper(ppufile:tcompilerppufile;const o:toper); 1121 begin 1122 end; 1123 1124 1125 procedure taicpu.ppubuildderefimploper(var o:toper); 1126 begin 1127 end; 1128 1129 1130 procedure taicpu.ppuderefoper(var o:toper); 1131 begin 1132 end; 1133 1134 1135 function taicpu.InsEnd:longint; 1136 begin 1137 Result:=0; { unimplemented } 1138 end; 1139 1140 1141 procedure taicpu.create_ot(objdata:TObjData); 1142 begin 1143 end; 1144 1145 1146 function taicpu.Matches(p:PInsEntry):longint; 1147 begin 1148 end; 1149 1150 1151 function taicpu.calcsize(p:PInsEntry):shortint; 1152 begin 1153 result:=4; 1154 end; 1155 1156 1157 function taicpu.NeedAddrPrefix(opidx:byte):boolean; 1158 begin 1159 Result:=False; { unimplemented } 1160 end; 1161 1162 1163 procedure taicpu.Swapoperands; 1164 begin 1165 end; 1166 1167 1168 function taicpu.FindInsentry(objdata:TObjData):boolean; 1169 begin 1170 end; 1171 1172 1173 procedure taicpu.gencode(objdata:TObjData); 1174 var 1175 bytes : dword; 1176 i_field : byte; 1177 1178 procedure setshifterop(op : byte); 1179 begin 1180 case oper[op]^.typ of 1181 top_const: 1182 begin 1183 i_field:=1; 1184 bytes:=bytes or dword(oper[op]^.val and $fff); 1185 end; 1186 top_reg: 1187 begin 1188 i_field:=0; 1189 bytes:=bytes or (getsupreg(oper[op]^.reg) shl 16); 1190 1191 { does a real shifter op follow? } 1192 if (op+1<=op) and (oper[op+1]^.typ=top_shifterop) then 1193 begin 1194 end; 1195 end; 1196 else 1197 internalerror(2005091103); 1198 end; 1199 end; 1200 1201 begin 1202 bytes:=$0; 1203 { evaluate and set condition code } 1204 1205 { condition code allowed? } 1206 1207 { setup rest of the instruction } 1208 case insentry^.code[0] of 1209 #$08: 1210 begin 1211 { set instruction code } 1212 bytes:=bytes or (ord(insentry^.code[1]) shl 26); 1213 bytes:=bytes or (ord(insentry^.code[2]) shl 21); 1214 1215 { set destination } 1216 bytes:=bytes or (getsupreg(oper[0]^.reg) shl 12); 1217 1218 { create shifter op } 1219 setshifterop(1); 1220 1221 { set i field } 1222 bytes:=bytes or (i_field shl 25); 1223 1224 { set s if necessary } 1225 if oppostfix=PF_S then 1226 bytes:=bytes or (1 shl 20); 1227 end; 1228 #$ff: 1229 internalerror(2005091101); 1230 else 1231 internalerror(2005091102); 1232 end; 1233 { we're finished, write code } 1234 objdata.writebytes(bytes,sizeof(bytes)); 1235 end; 1236 1237 1238{$ifdef dummy} 1239(* 1240static void gencode (long segment, long offset, int bits, 1241 insn *ins, char *codes, long insn_end) 1242{ 1243 int has_S_code; /* S - setflag */ 1244 int has_B_code; /* B - setflag */ 1245 int has_T_code; /* T - setflag */ 1246 int has_W_code; /* ! => W flag */ 1247 int has_F_code; /* ^ => S flag */ 1248 int keep; 1249 unsigned char c; 1250 unsigned char bytes[4]; 1251 long data, size; 1252 static int cc_code[] = /* bit pattern of cc */ 1253 { /* order as enum in */ 1254 0x0E, 0x03, 0x02, 0x00, /* nasm.h */ 1255 0x0A, 0x0C, 0x08, 0x0D, 1256 0x09, 0x0B, 0x04, 0x01, 1257 0x05, 0x07, 0x06, 1258 }; 1259 1260 1261#ifdef DEBUG 1262static char *CC[] = 1263 { /* condition code names */ 1264 "AL", "CC", "CS", "EQ", 1265 "GE", "GT", "HI", "LE", 1266 "LS", "LT", "MI", "NE", 1267 "PL", "VC", "VS", "", 1268 "S" 1269}; 1270 1271 1272 has_S_code = (ins->condition & C_SSETFLAG); 1273 has_B_code = (ins->condition & C_BSETFLAG); 1274 has_T_code = (ins->condition & C_TSETFLAG); 1275 has_W_code = (ins->condition & C_EXSETFLAG); 1276 has_F_code = (ins->condition & C_FSETFLAG); 1277 ins->condition = (ins->condition & 0x0F); 1278 1279 1280 if (rt_debug) 1281 { 1282 printf ("gencode: instruction: %s%s", insn_names[ins->opcode], 1283 CC[ins->condition & 0x0F]); 1284 if (has_S_code) 1285 printf ("S"); 1286 if (has_B_code) 1287 printf ("B"); 1288 if (has_T_code) 1289 printf ("T"); 1290 if (has_W_code) 1291 printf ("!"); 1292 if (has_F_code) 1293 printf ("^"); 1294 1295 printf ("\n"); 1296 1297 c = *codes; 1298 1299 printf (" (%d) decode - '0x%02X'\n", ins->operands, c); 1300 1301 1302 bytes[0] = 0xB; 1303 bytes[1] = 0xE; 1304 bytes[2] = 0xE; 1305 bytes[3] = 0xF; 1306 } 1307 1308 // First condition code in upper nibble 1309 if (ins->condition < C_NONE) 1310 { 1311 c = cc_code[ins->condition] << 4; 1312 } 1313 else 1314 { 1315 c = cc_code[C_AL] << 4; // is often ALWAYS but not always 1316 } 1317 1318 1319 switch (keep = *codes) 1320 { 1321 case 1: 1322 // B, BL 1323 ++codes; 1324 c |= *codes++; 1325 bytes[0] = c; 1326 1327 if (ins->oprs[0].segment != segment) 1328 { 1329 // fais une relocation 1330 c = 1; 1331 data = 0; // Let the linker locate ?? 1332 } 1333 else 1334 { 1335 c = 0; 1336 data = ins->oprs[0].offset - (offset + 8); 1337 1338 if (data % 4) 1339 { 1340 errfunc (ERR_NONFATAL, "offset not aligned on 4 bytes"); 1341 } 1342 } 1343 1344 if (data >= 0x1000) 1345 { 1346 errfunc (ERR_NONFATAL, "too long offset"); 1347 } 1348 1349 data = data >> 2; 1350 bytes[1] = (data >> 16) & 0xFF; 1351 bytes[2] = (data >> 8) & 0xFF; 1352 bytes[3] = (data ) & 0xFF; 1353 1354 if (c == 1) 1355 { 1356// out (offset, segment, &bytes[0], OUT_RAWDATA+1, NO_SEG, NO_SEG); 1357 out (offset, segment, &bytes[0], OUT_REL3ADR+4, ins->oprs[0].segment, NO_SEG); 1358 } 1359 else 1360 { 1361 out (offset, segment, &bytes[0], OUT_RAWDATA+4, NO_SEG, NO_SEG); 1362 } 1363 return; 1364 1365 case 2: 1366 // SWI 1367 ++codes; 1368 c |= *codes++; 1369 bytes[0] = c; 1370 data = ins->oprs[0].offset; 1371 bytes[1] = (data >> 16) & 0xFF; 1372 bytes[2] = (data >> 8) & 0xFF; 1373 bytes[3] = (data) & 0xFF; 1374 out (offset, segment, &bytes, OUT_RAWDATA+4, NO_SEG, NO_SEG); 1375 return; 1376 case 3: 1377 // BX 1378 ++codes; 1379 c |= *codes++; 1380 bytes[0] = c; 1381 bytes[1] = *codes++; 1382 bytes[2] = *codes++; 1383 bytes[3] = *codes++; 1384 c = regval (&ins->oprs[0],1); 1385 if (c == 15) // PC 1386 { 1387 errfunc (ERR_WARNING, "'BX' with R15 has undefined behaviour"); 1388 } 1389 else if (c > 15) 1390 { 1391 errfunc (ERR_NONFATAL, "Illegal register specified for 'BX'"); 1392 } 1393 1394 bytes[3] |= (c & 0x0F); 1395 out (offset, segment, bytes, OUT_RAWDATA+4, NO_SEG, NO_SEG); 1396 return; 1397 1398 case 4: // AND Rd,Rn,Rm 1399 case 5: // AND Rd,Rn,Rm,<shift>Rs 1400 case 6: // AND Rd,Rn,Rm,<shift>imm 1401 case 7: // AND Rd,Rn,<shift>imm 1402 ++codes; 1403#ifdef DEBUG 1404 if (rt_debug) 1405 { 1406 printf (" decode - '0x%02X'\n", keep); 1407 printf (" code - '0x%02X'\n", (unsigned char) ( *codes)); 1408 } 1409#endif 1410 bytes[0] = c | *codes; 1411 ++codes; 1412 1413 bytes[1] = *codes; 1414 if (has_S_code) 1415 bytes[1] |= 0x10; 1416 c = regval (&ins->oprs[1],1); 1417 // Rn in low nibble 1418 bytes[1] |= c; 1419 1420 // Rd in high nibble 1421 bytes[2] = regval (&ins->oprs[0],1) << 4; 1422 1423 if (keep != 7) 1424 { 1425 // Rm in low nibble 1426 bytes[3] = regval (&ins->oprs[2],1); 1427 } 1428 1429 // Shifts if any 1430 if (keep == 5 || keep == 6) 1431 { 1432 // Shift in bytes 2 and 3 1433 if (keep == 5) 1434 { 1435 // Rs 1436 c = regval (&ins->oprs[3],1); 1437 bytes[2] |= c; 1438 1439 c = 0x10; // Set bit 4 in byte[3] 1440 } 1441 if (keep == 6) 1442 { 1443 c = (ins->oprs[3].offset) & 0x1F; 1444 1445 // #imm 1446 bytes[2] |= c >> 1; 1447 if (c & 0x01) 1448 { 1449 bytes[3] |= 0x80; 1450 } 1451 c = 0; // Clr bit 4 in byte[3] 1452 } 1453 // <shift> 1454 c |= shiftval (&ins->oprs[3]) << 5; 1455 1456 bytes[3] |= c; 1457 } 1458 1459 // reg,reg,imm 1460 if (keep == 7) 1461 { 1462 int shimm; 1463 1464 shimm = imm_shift (ins->oprs[2].offset); 1465 1466 if (shimm == -1) 1467 { 1468 errfunc (ERR_NONFATAL, "cannot create that constant"); 1469 } 1470 bytes[3] = shimm & 0xFF; 1471 bytes[2] |= (shimm & 0xF00) >> 8; 1472 } 1473 1474 out (offset, segment, bytes, OUT_RAWDATA+4, NO_SEG, NO_SEG); 1475 return; 1476 1477 case 8: // MOV Rd,Rm 1478 case 9: // MOV Rd,Rm,<shift>Rs 1479 case 0xA: // MOV Rd,Rm,<shift>imm 1480 case 0xB: // MOV Rd,<shift>imm 1481 ++codes; 1482#ifdef DEBUG 1483 if (rt_debug) 1484 { 1485 printf (" decode - '0x%02X'\n", keep); 1486 printf (" code - '0x%02X'\n", (unsigned char) ( *codes)); 1487 } 1488#endif 1489 bytes[0] = c | *codes; 1490 ++codes; 1491 1492 bytes[1] = *codes; 1493 if (has_S_code) 1494 bytes[1] |= 0x10; 1495 1496 // Rd in high nibble 1497 bytes[2] = regval (&ins->oprs[0],1) << 4; 1498 1499 if (keep != 0x0B) 1500 { 1501 // Rm in low nibble 1502 bytes[3] = regval (&ins->oprs[1],1); 1503 } 1504 1505 // Shifts if any 1506 if (keep == 0x09 || keep == 0x0A) 1507 { 1508 // Shift in bytes 2 and 3 1509 if (keep == 0x09) 1510 { 1511 // Rs 1512 c = regval (&ins->oprs[2],1); 1513 bytes[2] |= c; 1514 1515 c = 0x10; // Set bit 4 in byte[3] 1516 } 1517 if (keep == 0x0A) 1518 { 1519 c = (ins->oprs[2].offset) & 0x1F; 1520 1521 // #imm 1522 bytes[2] |= c >> 1; 1523 if (c & 0x01) 1524 { 1525 bytes[3] |= 0x80; 1526 } 1527 c = 0; // Clr bit 4 in byte[3] 1528 } 1529 // <shift> 1530 c |= shiftval (&ins->oprs[2]) << 5; 1531 1532 bytes[3] |= c; 1533 } 1534 1535 // reg,imm 1536 if (keep == 0x0B) 1537 { 1538 int shimm; 1539 1540 …
Large files files are truncated, but you can click here to view the full file