PageRenderTime 49ms CodeModel.GetById 16ms app.highlight 22ms RepoModel.GetById 0ms app.codeStats 1ms

/compiler/aarch64/aasmcpu.pas

https://github.com/slibre/freepascal
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
   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              shimm = imm_shift (ins->oprs[1].offset);
1541
1542              if (shimm == -1)
1543                {
1544                  errfunc (ERR_NONFATAL, "cannot create that constant");
1545                }
1546              bytes[3] = shimm & 0xFF;
1547              bytes[2] |= (shimm & 0xF00) >> 8;
1548            }
1549
1550          out (offset, segment, bytes, OUT_RAWDATA+4, NO_SEG, NO_SEG);
1551          return;
1552
1553
1554        case 0xC:       // CMP Rn,Rm
1555        case 0xD:       // CMP Rn,Rm,<shift>Rs
1556        case 0xE:       // CMP Rn,Rm,<shift>imm
1557        case 0xF:       // CMP Rn,<shift>imm
1558          ++codes;
1559
1560          bytes[0] = c | *codes++;
1561
1562          bytes[1] = *codes;
1563
1564          // Implicit S code
1565          bytes[1] |= 0x10;
1566
1567          c = regval (&ins->oprs[0],1);
1568          // Rn in low nibble
1569          bytes[1] |= c;
1570
1571          // No destination
1572          bytes[2] = 0;
1573
1574          if (keep != 0x0B)
1575            {
1576              // Rm in low nibble
1577              bytes[3] = regval (&ins->oprs[1],1);
1578            }
1579
1580          // Shifts if any
1581          if (keep == 0x0D || keep == 0x0E)
1582            {
1583              // Shift in bytes 2 and 3
1584              if (keep == 0x0D)
1585                {
1586                  // Rs
1587                  c = regval (&ins->oprs[2],1);
1588                  bytes[2] |= c;
1589
1590                  c = 0x10;             // Set bit 4 in byte[3]
1591                }
1592              if (keep == 0x0E)
1593                {
1594                  c = (ins->oprs[2].offset) & 0x1F;
1595
1596                  // #imm
1597                  bytes[2] |= c >> 1;
1598                  if (c & 0x01)
1599                    {
1600                      bytes[3] |= 0x80;
1601                    }
1602                  c = 0;                // Clr bit 4 in byte[3]
1603                }
1604              // <shift>
1605              c |= shiftval (&ins->oprs[2]) << 5;
1606
1607              bytes[3] |= c;
1608            }
1609
1610          // reg,imm
1611          if (keep == 0x0F)
1612            {
1613              int shimm;
1614
1615              shimm = imm_shift (ins->oprs[1].offset);
1616
1617              if (shimm == -1)
1618                {
1619                  errfunc (ERR_NONFATAL, "cannot create that constant");
1620                }
1621              bytes[3] = shimm & 0xFF;
1622              bytes[2] |= (shimm & 0xF00) >> 8;
1623            }
1624
1625          out (offset, segment, bytes, OUT_RAWDATA+4, NO_SEG, NO_SEG);
1626          return;
1627
1628        case 0x10:      // MRS Rd,<psr>
1629          ++codes;
1630
1631          bytes[0] = c | *codes++;
1632
1633          bytes[1] = *codes++;
1634
1635          // Rd
1636          c = regval (&ins->oprs[0],1);
1637
1638          bytes[2] = c << 4;
1639
1640          bytes[3] = 0;
1641
1642          c = ins->oprs[1].basereg;
1643
1644          if (c == R_CPSR || c == R_SPSR)
1645            {
1646              if (c == R_SPSR)
1647                {
1648                  bytes[1] |= 0x40;
1649                }
1650            }
1651          else
1652            {
1653              errfunc (ERR_NONFATAL, "CPSR or SPSR expected");
1654            }
1655
1656          out (offset, segment, bytes, OUT_RAWDATA+4, NO_SEG, NO_SEG);
1657
1658          return;
1659
1660        case 0x11:      // MSR <psr>,Rm
1661        case 0x12:      // MSR <psrf>,Rm
1662        case 0x13:      // MSR <psrf>,#expression
1663          ++codes;
1664
1665          bytes[0] = c | *codes++;
1666
1667          bytes[1] = *codes++;
1668
1669          bytes[2] = *codes;
1670
1671
1672          if (keep == 0x11 || keep == 0x12)
1673            {
1674              // Rm
1675              c = regval (&ins->oprs[1],1);
1676
1677              bytes[3] = c;
1678            }
1679          else
1680            {
1681              int shimm;
1682
1683              shimm = imm_shift (ins->oprs[1].offset);
1684
1685              if (shimm == -1)
1686                {
1687                  errfunc (ERR_NONFATAL, "cannot create that constant");
1688                }
1689              bytes[3] = shimm & 0xFF;
1690              bytes[2] |= (shimm & 0xF00) >> 8;
1691            }
1692
1693          c = ins->oprs[0].basereg;
1694
1695          if ( keep == 0x11)
1696            {
1697              if ( c == R_CPSR || c == R_SPSR)
1698                {
1699                if ( c== R_SPSR)
1700                  {
1701                    bytes[1] |= 0x40;
1702                  }
1703                }
1704            else
1705              {
1706                errfunc (ERR_NONFATAL, "CPSR or SPSR expected");
1707              }
1708            }
1709          else
1710            {
1711              if ( c == R_CPSR_FLG || c == R_SPSR_FLG)
1712                {
1713                  if ( c== R_SPSR_FLG)
1714                    {
1715                      bytes[1] |= 0x40;
1716                    }
1717                }
1718              else
1719                {
1720                  errfunc (ERR_NONFATAL, "CPSR_flg or SPSR_flg expected");
1721                }
1722            }
1723          break;
1724
1725        case 0x14:      // MUL  Rd,Rm,Rs
1726        case 0x15:      // MULA Rd,Rm,Rs,Rn
1727          ++codes;
1728
1729          bytes[0] = c | *codes++;
1730
1731          bytes[1] = *codes++;
1732
1733          bytes[3] = *codes;
1734
1735          // Rd
1736          bytes[1] |= regval (&ins->oprs[0],1);
1737          if (has_S_code)
1738            bytes[1] |= 0x10;
1739
1740          // Rm
1741          bytes[3] |= regval (&ins->oprs[1],1);
1742
1743          // Rs
1744          bytes[2] = regval (&ins->oprs[2],1);
1745
1746          if (keep == 0x15)
1747            {
1748              bytes[2] |= regval (&ins->oprs[3],1) << 4;
1749            }
1750          break;
1751
1752        case 0x16:      // SMLAL RdHi,RdLo,Rm,Rs
1753          ++codes;
1754
1755          bytes[0] = c | *codes++;
1756
1757          bytes[1] = *codes++;
1758
1759          bytes[3] = *codes;
1760
1761          // RdHi
1762          bytes[1] |= regval (&ins->oprs[1],1);
1763          if (has_S_code)
1764            bytes[1] |= 0x10;
1765
1766          // RdLo
1767          bytes[2] = regval (&ins->oprs[0],1) << 4;
1768          // Rm
1769          bytes[3] |= regval (&ins->oprs[2],1);
1770
1771          // Rs
1772          bytes[2] |= regval (&ins->oprs[3],1);
1773
1774          break;
1775
1776        case 0x17:      // LDR Rd, expression
1777          ++codes;
1778
1779          bytes[0] = c | *codes++;
1780
1781          bytes[1] = *codes++;
1782
1783          // Rd
1784          bytes[2] = regval (&ins->oprs[0],1) << 4;
1785          if (has_B_code)
1786            bytes[1] |= 0x40;
1787          if (has_T_code)
1788            {
1789              errfunc (ERR_NONFATAL, "'T' not allowed in pre-index mode");
1790            }
1791          if (has_W_code)
1792            {
1793              errfunc (ERR_NONFATAL, "'!' not allowed");
1794            }
1795
1796          // Rn - implicit R15
1797          bytes[1] |= 0xF;
1798
1799          if (ins->oprs[1].segment != segment)
1800            {
1801              errfunc (ERR_NONFATAL, "label not in same segment");
1802            }
1803
1804          data = ins->oprs[1].offset - (offset + 8);
1805
1806          if (data < 0)
1807            {
1808              data = -data;
1809            }
1810          else
1811            {
1812              bytes[1] |= 0x80;
1813            }
1814
1815          if (data >= 0x1000)
1816            {
1817              errfunc (ERR_NONFATAL, "too long offset");
1818            }
1819
1820          bytes[2] |= ((data & 0xF00) >> 8);
1821          bytes[3] = data & 0xFF;
1822          break;
1823
1824        case 0x18:      // LDR Rd, [Rn]
1825          ++codes;
1826
1827          bytes[0] = c | *codes++;
1828
1829          bytes[1] = *codes++;
1830
1831          // Rd
1832          bytes[2] = regval (&ins->oprs[0],1) << 4;
1833          if (has_B_code)
1834            bytes[1] |= 0x40;
1835          if (has_T_code)
1836            {
1837              bytes[1] |= 0x20;         // write-back
1838            }
1839          else
1840            {
1841              bytes[0] |= 0x01;         // implicit pre-index mode
1842            }
1843
1844          if (has_W_code)
1845            {
1846              bytes[1] |= 0x20;         // write-back
1847            }
1848
1849          // Rn
1850          c = regval (&ins->oprs[1],1);
1851          bytes[1] |= c;
1852
1853          if (c == 0x15)                // R15
1854            data = -8;
1855          else
1856            data = 0;
1857
1858          if (data < 0)
1859            {
1860              data = -data;
1861            }
1862          else
1863            {
1864              bytes[1] |= 0x80;
1865            }
1866
1867          bytes[2] |= ((data & 0xF00) >> 8);
1868          bytes[3] = data & 0xFF;
1869          break;
1870
1871        case 0x19:      // LDR Rd, [Rn,#expression]
1872        case 0x20:      // LDR Rd, [Rn,Rm]
1873        case 0x21:      // LDR Rd, [Rn,Rm,shift]
1874          ++codes;
1875
1876          bytes[0] = c | *codes++;
1877
1878          bytes[1] = *codes++;
1879
1880          // Rd
1881          bytes[2] = regval (&ins->oprs[0],1) << 4;
1882          if (has_B_code)
1883            bytes[1] |= 0x40;
1884
1885          // Rn
1886          c = regval (&ins->oprs[1],1);
1887          bytes[1] |= c;
1888
1889          if (ins->oprs[ins->operands-1].bracket)       // FIXME: Bracket on last operand -> pre-index  <--
1890            {
1891              bytes[0] |= 0x01;         // pre-index mode
1892              if (has_W_code)
1893                {
1894                  bytes[1] |= 0x20;
1895                }
1896              if (has_T_code)
1897                {
1898                  errfunc (ERR_NONFATAL, "'T' not allowed in pre-index mode");
1899                }
1900            }
1901          else
1902            {
1903              if (has_T_code)           // Forced write-back in post-index mode
1904                {
1905                  bytes[1] |= 0x20;
1906                }
1907              if (has_W_code)
1908                {
1909                  errfunc (ERR_NONFATAL, "'!' not allowed in post-index mode");
1910                }
1911            }
1912
1913          if (keep == 0x19)
1914            {
1915              data = ins->oprs[2].offset;
1916
1917              if (data < 0)
1918                {
1919                  data = -data;
1920                }
1921              else
1922                {
1923                  bytes[1] |= 0x80;
1924                }
1925
1926              if (data >= 0x1000)
1927                {
1928                  errfunc (ERR_NONFATAL, "too long offset");
1929                }
1930
1931              bytes[2] |= ((data & 0xF00) >> 8);
1932              bytes[3] = data & 0xFF;
1933            }
1934          else
1935            {
1936              if (ins->oprs[2].minus == 0)
1937                {
1938                  bytes[1] |= 0x80;
1939                }
1940              c = regval (&ins->oprs[2],1);
1941              bytes[3] = c;
1942
1943              if (keep == 0x21)
1944                {
1945                  c = ins->oprs[3].offset;
1946                  if (c > 0x1F)
1947                    {
1948                      errfunc (ERR_NONFATAL, "too large shiftvalue");
1949                      c = c & 0x1F;
1950                    }
1951
1952                  bytes[2] |= c >> 1;
1953                  if (c & 0x01)
1954                    {
1955                      bytes[3] |= 0x80;
1956                    }
1957                  bytes[3] |= shiftval (&ins->oprs[3]) << 5;
1958                }
1959            }
1960
1961          break;
1962
1963        case 0x22:      // LDRH Rd, expression
1964          ++codes;
1965
1966          bytes[0] = c | 0x01;          // Implicit pre-index
1967
1968          bytes[1] = *codes++;
1969
1970          // Rd
1971          bytes[2] = regval (&ins->oprs[0],1) << 4;
1972
1973          // Rn - implicit R15
1974          bytes[1] |= 0xF;
1975
1976          if (ins->oprs[1].segment != segment)
1977            {
1978              errfunc (ERR_NONFATAL, "label not in same segment");
1979            }
1980
1981          data = ins->oprs[1].offset - (offset + 8);
1982
1983          if (data < 0)
1984            {
1985              data = -data;
1986            }
1987          else
1988            {
1989              bytes[1] |= 0x80;
1990            }
1991
1992          if (data >= 0x100)
1993            {
1994              errfunc (ERR_NONFATAL, "too long offset");
1995            }
1996          bytes[3] = *codes++;
1997
1998          bytes[2] |= ((data & 0xF0) >> 4);
1999          bytes[3] |= data & 0xF;
2000          break;
2001
2002        case 0x23:      // LDRH Rd, Rn
2003          ++codes;
2004
2005          bytes[0] = c | 0x01;          // Implicit pre-index
2006
2007          bytes[1] = *codes++;
2008
2009          // Rd
2010          bytes[2] = regval (&ins->oprs[0],1) << 4;
2011
2012          // Rn
2013          c = regval (&ins->oprs[1],1);
2014          bytes[1] |= c;
2015
2016          if (c == 0x15)                // R15
2017            data = -8;
2018          else
2019            data = 0;
2020
2021          if (data < 0)
2022            {
2023              data = -data;
2024            }
2025          else
2026            {
2027              bytes[1] |= 0x80;
2028            }
2029
2030          if (data >= 0x100)
2031            {
2032              errfunc (ERR_NONFATAL, "too long offset");
2033            }
2034          bytes[3] = *codes++;
2035
2036          bytes[2] |= ((data & 0xF0) >> 4);
2037          bytes[3] |= data & 0xF;
2038          break;
2039
2040        case 0x24:      // LDRH Rd, Rn, expression
2041        case 0x25:      // LDRH Rd, Rn, Rm
2042          ++codes;
2043
2044          bytes[0] = c;
2045
2046          bytes[1] = *codes++;
2047
2048          // Rd
2049          bytes[2] = regval (&ins->oprs[0],1) << 4;
2050
2051          // Rn
2052          c = regval (&ins->oprs[1],1);
2053          bytes[1] |= c;
2054
2055          if (ins->oprs[ins->operands-1].bracket)       // FIXME: Bracket on last operand -> pre-index  <--
2056            {
2057              bytes[0] |= 0x01;         // pre-index mode
2058              if (has_W_code)
2059                {
2060                  bytes[1] |= 0x20;
2061                }
2062            }
2063          else
2064            {
2065              if (has_W_code)
2066                {
2067                  errfunc (ERR_NONFATAL, "'!' not allowed in post-index mode");
2068                }
2069            }
2070
2071          bytes[3] = *codes++;
2072
2073          if (keep == 0x24)
2074            {
2075              data = ins->oprs[2].offset;
2076
2077              if (data < 0)
2078                {
2079                  data = -data;
2080                }
2081              else
2082                {
2083                  bytes[1] |= 0x80;
2084                }
2085
2086              if (data >= 0x100)
2087                {
2088                  errfunc (ERR_NONFATAL, "too long offset");
2089                }
2090
2091              bytes[2] |= ((data & 0xF0) >> 4);
2092              bytes[3] |= data & 0xF;
2093            }
2094          else
2095            {
2096              if (ins->oprs[2].minus == 0)
2097                {
2098                  bytes[1] |= 0x80;
2099                }
2100              c = regval (&ins->oprs[2],1);
2101              bytes[3] |= c;
2102
2103            }
2104          break;
2105
2106        case 0x26:      // LDM/STM Rn, {reg-list}
2107          ++codes;
2108
2109          bytes[0] = c;
2110
2111          bytes[0] |= ( *codes >> 4) & 0xF;
2112          bytes[1] = ( *codes << 4) & 0xF0;
2113          ++codes;
2114
2115          if (has_W_code)
2116            {
2117              bytes[1] |= 0x20;
2118            }
2119          if (has_F_code)
2120            {
2121              bytes[1] |= 0x40;
2122            }
2123
2124          // Rn
2125          bytes[1] |= regval (&ins->oprs[0],1);
2126
2127          data = ins->oprs[1].basereg;
2128
2129          bytes[2] = ((data >> 8) & 0xFF);
2130          bytes[3] = (data & 0xFF);
2131
2132          break;
2133
2134        case 0x27:      // SWP Rd, Rm, [Rn]
2135          ++codes;
2136
2137          bytes[0] = c;
2138
2139          bytes[0] |= *codes++;
2140
2141          bytes[1] = regval (&ins->oprs[2],1);
2142          if (has_B_code)
2143            {
2144              bytes[1] |= 0x40;
2145            }
2146          bytes[2] = regval (&ins->oprs[0],1) << 4;
2147          bytes[3] = *codes++;
2148          bytes[3] |= regval (&ins->oprs[1],1);
2149          break;
2150
2151        default:
2152          errfunc (ERR_FATAL, "unknown decoding of instruction");
2153
2154          bytes[0] = c;
2155          // And a fix nibble
2156          ++codes;
2157          bytes[0] |= *codes++;
2158
2159         if ( *codes == 0x01)           // An I bit
2160           {
2161
2162           }
2163         if ( *codes == 0x02)           // An I bit
2164           {
2165
2166           }
2167         ++codes;
2168      }
2169    out (offset, segment, bytes, OUT_RAWDATA+4, NO_SEG, NO_SEG);
2170}
2171
2172*)
2173{$endif dummy}
2174
2175begin
2176  cai_align:=tai_align;
2177end.
2178