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