/compiler/aarch64/aasmcpu.pas
Pascal | 2178 lines | 656 code | 157 blank | 1365 comment | 24 complexity | ecb4854ef356f8e9d9ed85b01a664947 MD5 | raw file
Possible License(s): LGPL-2.0, LGPL-2.1, LGPL-3.0
1{
2 Copyright (c) 2003-2012 by Florian Klaempfl and others
3
4 Contains the assembler object for ARM64
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19
20 ****************************************************************************
21}
22unit aasmcpu;
23
24{$i fpcdefs.inc}
25
26interface
27
28uses
29 cclasses,globtype,globals,verbose,
30 aasmbase,aasmtai,aasmdata,aasmsym,
31 ogbase,
32 symtype,
33 cpubase,cpuinfo,cgbase,cgutils;
34
35 const
36 { "mov reg,reg" source operand number }
37 O_MOV_SOURCE = 1;
38 { "mov reg,reg" source operand number }
39 O_MOV_DEST = 0;
40
41 { Operand types }
42 OT_NONE = $00000000;
43
44 OT_BITS8 = $00000001; { size, and other attributes, of the operand }
45 OT_BITS16 = $00000002;
46 OT_BITS32 = $00000004;
47 OT_BITS64 = $00000008; { FPU only }
48 OT_BITS80 = $00000010;
49 OT_FAR = $00000020; { this means 16:16 or 16:32, like in CALL/JMP }
50 OT_NEAR = $00000040;
51 OT_SHORT = $00000080;
52 OT_BITSTINY = $00000100; { fpu constant }
53 OT_BITSSHIFTER =
54 $00000200;
55
56 OT_SIZE_MASK = $000003FF; { all the size attributes }
57 OT_NON_SIZE = longint(not OT_SIZE_MASK);
58
59 OT_SIGNED = $00000100; { the operand need to be signed -128-127 }
60
61 OT_TO = $00000200; { operand is followed by a colon }
62 { reverse effect in FADD, FSUB &c }
63 OT_COLON = $00000400;
64
65 OT_SHIFTEROP = $00000800;
66 OT_REGISTER = $00001000;
67 OT_IMMEDIATE = $00002000;
68 OT_REGLIST = $00008000;
69 OT_IMM8 = $00002001;
70 OT_IMM24 = $00002002;
71 OT_IMM32 = $00002004;
72 OT_IMM64 = $00002008;
73 OT_IMM80 = $00002010;
74 OT_IMMTINY = $00002100;
75 OT_IMMSHIFTER= $00002200;
76 OT_IMMEDIATE24 = OT_IMM24;
77 OT_SHIFTIMM = OT_SHIFTEROP or OT_IMMSHIFTER;
78 OT_SHIFTIMMEDIATE = OT_SHIFTIMM;
79 OT_IMMEDIATESHIFTER = OT_IMMSHIFTER;
80
81 OT_IMMEDIATEFPU = OT_IMMTINY;
82
83 OT_REGMEM = $00200000; { for r/m, ie EA, operands }
84 OT_REGNORM = $00201000; { 'normal' reg, qualifies as EA }
85 OT_REG8 = $00201001;
86 OT_REG16 = $00201002;
87 OT_REG32 = $00201004;
88 OT_REG64 = $00201008;
89 OT_VREG = $00201010; { vector register }
90 OT_REGF = $00201020; { coproc register }
91 OT_MEMORY = $00204000; { register number in 'basereg' }
92 OT_MEM8 = $00204001;
93 OT_MEM16 = $00204002;
94 OT_MEM32 = $00204004;
95 OT_MEM64 = $00204008;
96 OT_MEM80 = $00204010;
97 { word/byte load/store }
98 OT_AM2 = $00010000;
99 { misc ld/st operations }
100 OT_AM3 = $00020000;
101 { multiple ld/st operations }
102 OT_AM4 = $00040000;
103 { co proc. ld/st operations }
104 OT_AM5 = $00080000;
105 OT_AMMASK = $000f0000;
106 { IT instruction }
107 OT_CONDITION = $00100000;
108
109 OT_MEMORYAM2 = OT_MEMORY or OT_AM2;
110 OT_MEMORYAM3 = OT_MEMORY or OT_AM3;
111 OT_MEMORYAM4 = OT_MEMORY or OT_AM4;
112 OT_MEMORYAM5 = OT_MEMORY or OT_AM5;
113
114 OT_FPUREG = $01000000; { floating point stack registers }
115 OT_REG_SMASK = $00070000; { special register operands: these may be treated differently }
116 { a mask for the following }
117
118 OT_MEM_OFFS = $00604000; { special type of EA }
119 { simple [address] offset }
120 OT_ONENESS = $00800000; { special type of immediate operand }
121 { so UNITY == IMMEDIATE | ONENESS }
122 OT_UNITY = $00802000; { for shift/rotate instructions }
123
124 instabentries = {$i a64nop.inc}
125
126 maxinfolen = 5;
127
128 IF_NONE = $00000000;
129
130 IF_ARMMASK = $000F0000;
131 IF_ARM7 = $00070000;
132 IF_FPMASK = $00F00000;
133 IF_FPA = $00100000;
134
135 { if the instruction can change in a second pass }
136 IF_PASS2 = longint($80000000);
137
138 type
139 TInsTabCache=array[TasmOp] of longint;
140 PInsTabCache=^TInsTabCache;
141
142 tinsentry = record
143 opcode : tasmop;
144 ops : byte;
145 optypes : array[0..3] of longint;
146 code : array[0..maxinfolen] of char;
147 flags : longint;
148 end;
149
150 pinsentry=^tinsentry;
151
152{ const
153 InsTab : array[0..instabentries-1] of TInsEntry={$i a64tab.inc} }
154
155 var
156 InsTabCache : PInsTabCache;
157
158 type
159 taicpu = class(tai_cpu_abstract_sym)
160 oppostfix : TOpPostfix;
161 procedure loadshifterop(opidx:longint;const so:tshifterop);
162 constructor op_none(op : tasmop);
163
164 constructor op_reg(op : tasmop;_op1 : tregister);
165 constructor op_ref(op : tasmop;const _op1 : treference);
166 constructor op_const(op : tasmop;_op1 : longint);
167
168 constructor op_reg_reg(op : tasmop;_op1,_op2 : tregister);
169 constructor op_reg_ref(op : tasmop;_op1 : tregister;const _op2 : treference);
170 constructor op_reg_const(op:tasmop; _op1: tregister; _op2: aint);
171
172 constructor op_reg_reg_reg(op : tasmop;_op1,_op2,_op3 : tregister);
173 constructor op_reg_reg_reg_reg(op : tasmop;_op1,_op2,_op3,_op4 : tregister);
174 constructor op_reg_reg_const(op : tasmop;_op1,_op2 : tregister; _op3: aint);
175 constructor op_reg_reg_sym_ofs(op : tasmop;_op1,_op2 : tregister; _op3: tasmsymbol;_op3ofs: longint);
176 constructor op_reg_reg_ref(op : tasmop;_op1,_op2 : tregister; const _op3: treference);
177 constructor op_reg_reg_shifterop(op : tasmop;_op1,_op2 : tregister;_op3 : tshifterop);
178 constructor op_reg_reg_reg_shifterop(op : tasmop;_op1,_op2,_op3 : tregister;_op4 : tshifterop);
179
180 { this is for Jmp instructions }
181 constructor op_cond_sym(op : tasmop;cond:TAsmCond;_op1 : tasmsymbol);
182
183 constructor op_sym(op : tasmop;_op1 : tasmsymbol);
184 constructor op_sym_ofs(op : tasmop;_op1 : tasmsymbol;_op1ofs:longint);
185 constructor op_reg_sym_ofs(op : tasmop;_op1 : tregister;_op2:tasmsymbol;_op2ofs : longint);
186 constructor op_sym_ofs_ref(op : tasmop;_op1 : tasmsymbol;_op1ofs:longint;const _op2 : treference);
187
188 function is_same_reg_move(regtype: Tregistertype):boolean; override;
189
190 function spilling_get_operation_type(opnr: longint): topertype;override;
191
192 { assembler }
193 public
194 { the next will reset all instructions that can change in pass 2 }
195 procedure ResetPass1;override;
196 procedure ResetPass2;override;
197 function CheckIfValid:boolean;
198 function GetString:string;
199 function Pass1(objdata:TObjData):longint;override;
200 procedure Pass2(objdata:TObjData);override;
201 protected
202 procedure ppuloadoper(ppufile:tcompilerppufile;var o:toper);override;
203 procedure ppuwriteoper(ppufile:tcompilerppufile;const o:toper);override;
204 procedure ppubuildderefimploper(var o:toper);override;
205 procedure ppuderefoper(var o:toper);override;
206 private
207 { next fields are filled in pass1, so pass2 is faster }
208 inssize : shortint;
209 insoffset : longint;
210 LastInsOffset : longint; { need to be public to be reset }
211 insentry : PInsEntry;
212 function InsEnd:longint;
213 procedure create_ot(objdata:TObjData);
214 function Matches(p:PInsEntry):longint;
215 function calcsize(p:PInsEntry):shortint;
216 procedure gencode(objdata:TObjData);
217 function NeedAddrPrefix(opidx:byte):boolean;
218 procedure Swapoperands;
219 function FindInsentry(objdata:TObjData):boolean;
220 end;
221
222 tai_align = class(tai_align_abstract)
223 { nothing to add }
224 end;
225
226 function spilling_create_load(const ref:treference;r:tregister):Taicpu;
227 function spilling_create_store(r:tregister; const ref:treference):Taicpu;
228
229 function setoppostfix(i : taicpu;pf : toppostfix) : taicpu;
230 function setcondition(i : taicpu;c : tasmcond) : taicpu;
231
232 { inserts pc relative symbols at places where they are reachable
233 and transforms special instructions to valid instruction encodings }
234 procedure finalizearmcode(list,listtoinsert : TAsmList);
235 { inserts .pdata section and dummy function prolog needed for arm-wince exception handling }
236 procedure InsertPData;
237
238 procedure InitAsm;
239 procedure DoneAsm;
240
241
242implementation
243
244 uses
245 cutils,rgobj,itcpugas,aoptcpu;
246
247
248 procedure taicpu.loadshifterop(opidx:longint;const so:tshifterop);
249 begin
250 allocate_oper(opidx+1);
251 with oper[opidx]^ do
252 begin
253 if typ<>top_shifterop then
254 begin
255 clearop(opidx);
256 new(shifterop);
257 end;
258 shifterop^:=so;
259 typ:=top_shifterop;
260 end;
261 end;
262
263
264{*****************************************************************************
265 taicpu Constructors
266*****************************************************************************}
267
268 constructor taicpu.op_none(op : tasmop);
269 begin
270 inherited create(op);
271 end;
272
273
274 { for pld }
275 constructor taicpu.op_ref(op : tasmop;const _op1 : treference);
276 begin
277 inherited create(op);
278 ops:=1;
279 loadref(0,_op1);
280 end;
281
282
283 constructor taicpu.op_reg(op : tasmop;_op1 : tregister);
284 begin
285 inherited create(op);
286 ops:=1;
287 loadreg(0,_op1);
288 end;
289
290
291 constructor taicpu.op_const(op : tasmop;_op1 : longint);
292 begin
293 inherited create(op);
294 ops:=1;
295 loadconst(0,aint(_op1));
296 end;
297
298
299 constructor taicpu.op_reg_reg(op : tasmop;_op1,_op2 : tregister);
300 begin
301 inherited create(op);
302 ops:=2;
303 loadreg(0,_op1);
304 loadreg(1,_op2);
305 end;
306
307
308 constructor taicpu.op_reg_const(op:tasmop; _op1: tregister; _op2: aint);
309 begin
310 inherited create(op);
311 ops:=2;
312 loadreg(0,_op1);
313 loadconst(1,aint(_op2));
314 end;
315
316
317 constructor taicpu.op_reg_ref(op : tasmop;_op1 : tregister;const _op2 : treference);
318 begin
319 inherited create(op);
320 ops:=2;
321 loadreg(0,_op1);
322 loadref(1,_op2);
323 end;
324
325
326 constructor taicpu.op_reg_reg_reg(op : tasmop;_op1,_op2,_op3 : tregister);
327 begin
328 inherited create(op);
329 ops:=3;
330 loadreg(0,_op1);
331 loadreg(1,_op2);
332 loadreg(2,_op3);
333 end;
334
335
336 constructor taicpu.op_reg_reg_reg_reg(op : tasmop;_op1,_op2,_op3,_op4 : tregister);
337 begin
338 inherited create(op);
339 ops:=4;
340 loadreg(0,_op1);
341 loadreg(1,_op2);
342 loadreg(2,_op3);
343 loadreg(3,_op4);
344 end;
345
346
347 constructor taicpu.op_reg_reg_const(op : tasmop;_op1,_op2 : tregister; _op3: aint);
348 begin
349 inherited create(op);
350 ops:=3;
351 loadreg(0,_op1);
352 loadreg(1,_op2);
353 loadconst(2,aint(_op3));
354 end;
355
356
357 constructor taicpu.op_reg_reg_sym_ofs(op : tasmop;_op1,_op2 : tregister; _op3: tasmsymbol;_op3ofs: longint);
358 begin
359 inherited create(op);
360 ops:=3;
361 loadreg(0,_op1);
362 loadreg(1,_op2);
363 loadsymbol(0,_op3,_op3ofs);
364 end;
365
366
367 constructor taicpu.op_reg_reg_ref(op : tasmop;_op1,_op2 : tregister; const _op3: treference);
368 begin
369 inherited create(op);
370 ops:=3;
371 loadreg(0,_op1);
372 loadreg(1,_op2);
373 loadref(2,_op3);
374 end;
375
376
377 constructor taicpu.op_reg_reg_shifterop(op : tasmop;_op1,_op2 : tregister;_op3 : tshifterop);
378 begin
379 inherited create(op);
380 ops:=3;
381 loadreg(0,_op1);
382 loadreg(1,_op2);
383 loadshifterop(2,_op3);
384 end;
385
386
387 constructor taicpu.op_reg_reg_reg_shifterop(op : tasmop;_op1,_op2,_op3 : tregister;_op4 : tshifterop);
388 begin
389 inherited create(op);
390 ops:=4;
391 loadreg(0,_op1);
392 loadreg(1,_op2);
393 loadreg(2,_op3);
394 loadshifterop(3,_op4);
395 end;
396
397
398 constructor taicpu.op_cond_sym(op : tasmop;cond:TAsmCond;_op1 : tasmsymbol);
399 begin
400 inherited create(op);
401 condition:=cond;
402 ops:=1;
403 loadsymbol(0,_op1,0);
404 end;
405
406
407 constructor taicpu.op_sym(op : tasmop;_op1 : tasmsymbol);
408 begin
409 inherited create(op);
410 ops:=1;
411 loadsymbol(0,_op1,0);
412 end;
413
414
415 constructor taicpu.op_sym_ofs(op : tasmop;_op1 : tasmsymbol;_op1ofs:longint);
416 begin
417 inherited create(op);
418 ops:=1;
419 loadsymbol(0,_op1,_op1ofs);
420 end;
421
422
423 constructor taicpu.op_reg_sym_ofs(op : tasmop;_op1 : tregister;_op2:tasmsymbol;_op2ofs : longint);
424 begin
425 inherited create(op);
426 ops:=2;
427 loadreg(0,_op1);
428 loadsymbol(1,_op2,_op2ofs);
429 end;
430
431
432 constructor taicpu.op_sym_ofs_ref(op : tasmop;_op1 : tasmsymbol;_op1ofs:longint;const _op2 : treference);
433 begin
434 inherited create(op);
435 ops:=2;
436 loadsymbol(0,_op1,_op1ofs);
437 loadref(1,_op2);
438 end;
439
440
441 function taicpu.is_same_reg_move(regtype: Tregistertype):boolean;
442 begin
443 { allow the register allocator to remove unnecessary moves }
444 result:=(
445 ((opcode=A_MOV) and (regtype = R_INTREGISTER)) or
446 ((opcode=A_FMOV) and (regtype = R_MMREGISTER))
447 ) and
448 (oppostfix in [PF_None]) and
449 (condition=C_None) and
450 (ops=2) and
451 (oper[0]^.typ=top_reg) and
452 (oper[1]^.typ=top_reg) and
453 (oper[0]^.reg=oper[1]^.reg);
454 end;
455
456
457 function spilling_create_load(const ref:treference;r:tregister):Taicpu;
458 var
459 op: tasmop;
460 begin
461 case getregtype(r) of
462 R_INTREGISTER :
463 result:=taicpu.op_reg_ref(A_LDR,r,ref);
464 R_MMREGISTER :
465 begin
466 case getsubreg(r) of
467 R_SUBFD:
468 op:=A_LDR;
469 R_SUBFS:
470 op:=A_LDR;
471 else
472 internalerror(2009112905);
473 end;
474 result:=taicpu.op_reg_ref(op,r,ref);
475 end;
476 else
477 internalerror(200401041);
478 end;
479 end;
480
481
482 function spilling_create_store(r:tregister; const ref:treference):Taicpu;
483 var
484 op: tasmop;
485 begin
486 case getregtype(r) of
487 R_INTREGISTER :
488 result:=taicpu.op_reg_ref(A_STR,r,ref);
489 R_MMREGISTER :
490 begin
491 case getsubreg(r) of
492 R_SUBFD:
493 op:=A_STR;
494 R_SUBFS:
495 op:=A_STR;
496 else
497 internalerror(2009112904);
498 end;
499 result:=taicpu.op_reg_ref(op,r,ref);
500 end;
501 else
502 internalerror(200401041);
503 end;
504 end;
505
506
507 function taicpu.spilling_get_operation_type(opnr: longint): topertype;
508 begin
509 case opcode of
510 A_ADC,A_ADD,A_AND,A_BIC,
511 A_EOR,A_CLZ,A_RBIT,
512 A_LDR,
513 A_MOV,A_MVN,A_MUL,
514 A_ORR,A_SBC,A_SUB,
515 A_UXT,A_SXT:
516 if opnr=0 then
517 result:=operand_write
518 else
519 result:=operand_read;
520 A_B,A_BL,
521 A_CMN,A_CMP,A_TST:
522 result:=operand_read;
523 A_STR:
524 { important is what happens with the involved registers }
525 if opnr=0 then
526 result := operand_read
527 else
528 { check for pre/post indexed }
529 result := operand_read;
530 else
531 internalerror(200403151);
532 end;
533 end;
534
535
536 procedure BuildInsTabCache;
537 var
538 i : longint;
539 begin
540(* new(instabcache);
541 FillChar(instabcache^,sizeof(tinstabcache),$ff);
542 i:=0;
543 while (i<InsTabEntries) do
544 begin
545 if InsTabCache^[InsTab[i].Opcode]=-1 then
546 InsTabCache^[InsTab[i].Opcode]:=i;
547 inc(i);
548 end; *)
549 end;
550
551
552 procedure InitAsm;
553 begin
554 if not assigned(instabcache) then
555 BuildInsTabCache;
556 end;
557
558
559 procedure DoneAsm;
560 begin
561 if assigned(instabcache) then
562 begin
563 dispose(instabcache);
564 instabcache:=nil;
565 end;
566 end;
567
568
569 function setoppostfix(i : taicpu;pf : toppostfix) : taicpu;
570 begin
571 i.oppostfix:=pf;
572 result:=i;
573 end;
574
575
576 function setcondition(i : taicpu;c : tasmcond) : taicpu;
577 begin
578 i.condition:=c;
579 result:=i;
580 end;
581
582
583 Function SimpleGetNextInstruction(Current: tai; Var Next: tai): Boolean;
584 Begin
585 Current:=tai(Current.Next);
586 While Assigned(Current) And (Current.typ In SkipInstr) Do
587 Current:=tai(Current.Next);
588 Next:=Current;
589 If Assigned(Next) And Not(Next.typ In SkipInstr) Then
590 Result:=True
591 Else
592 Begin
593 Next:=Nil;
594 Result:=False;
595 End;
596 End;
597
598
599(*
600 function armconstequal(hp1,hp2: tai): boolean;
601 begin
602 result:=false;
603 if hp1.typ<>hp2.typ then
604 exit;
605 case hp1.typ of
606 tai_const:
607 result:=
608 (tai_const(hp2).sym=tai_const(hp).sym) and
609 (tai_const(hp2).value=tai_const(hp).value) and
610 (tai(hp2.previous).typ=ait_label);
611 tai_const:
612 result:=
613 (tai_const(hp2).sym=tai_const(hp).sym) and
614 (tai_const(hp2).value=tai_const(hp).value) and
615 (tai(hp2.previous).typ=ait_label);
616 end;
617 end;
618*)
619
620 procedure insertpcrelativedata(list,listtoinsert : TAsmList);
621 var
622 curinspos,
623 penalty,
624 lastinspos,
625 { increased for every data element > 4 bytes inserted }
626 currentsize,
627 extradataoffset,
628 limit: longint;
629 curop : longint;
630 curtai : tai;
631 curdatatai,hp,hp2 : tai;
632 curdata : TAsmList;
633 l : tasmlabel;
634 doinsert,
635 removeref : boolean;
636 begin
637(*
638 curdata:=TAsmList.create;
639 lastinspos:=-1;
640 curinspos:=0;
641 extradataoffset:=0;
642 limit:=1016;
643 curtai:=tai(list.first);
644 doinsert:=false;
645 while assigned(curtai) do
646 begin
647 { instruction? }
648 case curtai.typ of
649 ait_instruction:
650 begin
651 { walk through all operand of the instruction }
652 for curop:=0 to taicpu(curtai).ops-1 do
653 begin
654 { reference? }
655 if (taicpu(curtai).oper[curop]^.typ=top_ref) then
656 begin
657 { pc relative symbol? }
658 curdatatai:=tai(taicpu(curtai).oper[curop]^.ref^.symboldata);
659 if assigned(curdatatai) and
660 { move only if we're at the first reference of a label }
661 not(tai_label(curdatatai).moved) then
662 begin
663 tai_label(curdatatai).moved:=true;
664 { check if symbol already used. }
665 { if yes, reuse the symbol }
666 hp:=tai(curdatatai.next);
667 removeref:=false;
668 if assigned(hp) then
669 begin
670 case hp.typ of
671 ait_const:
672 begin
673 if (tai_const(hp).consttype=aitconst_64bit) then
674 inc(extradataoffset);
675 end;
676 ait_comp_64bit,
677 ait_real_64bit:
678 begin
679 inc(extradataoffset);
680 end;
681 ait_real_80bit:
682 begin
683 inc(extradataoffset,2);
684 end;
685 end;
686 if (hp.typ=ait_const) then
687 begin
688 hp2:=tai(curdata.first);
689 while assigned(hp2) do
690 begin
691 { if armconstequal(hp2,hp) then }
692 if (hp2.typ=ait_const) and (tai_const(hp2).sym=tai_const(hp).sym)
693 and (tai_const(hp2).value=tai_const(hp).value) and (tai(hp2.previous).typ=ait_label)
694 then
695 begin
696 with taicpu(curtai).oper[curop]^.ref^ do
697 begin
698 symboldata:=hp2.previous;
699 symbol:=tai_label(hp2.previous).labsym;
700 end;
701 removeref:=true;
702 break;
703 end;
704 hp2:=tai(hp2.next);
705 end;
706 end;
707 end;
708 { move or remove symbol reference }
709 repeat
710 hp:=tai(curdatatai.next);
711 listtoinsert.remove(curdatatai);
712 if removeref then
713 curdatatai.free
714 else
715 curdata.concat(curdatatai);
716 curdatatai:=hp;
717 until (curdatatai=nil) or (curdatatai.typ=ait_label);
718 if lastinspos=-1 then
719 lastinspos:=curinspos;
720 end;
721 end;
722 end;
723 inc(curinspos);
724 end;
725 ait_align:
726 begin
727 { code is always 4 byte aligned, so we don't have to take care of .align 2 which would
728 requires also incrementing curinspos by 1 }
729 inc(curinspos,(tai_align(curtai).aligntype div 4));
730 end;
731 ait_const:
732 begin
733 inc(curinspos);
734 if (tai_const(curtai).consttype=aitconst_64bit) then
735 inc(curinspos);
736 end;
737 ait_real_32bit:
738 begin
739 inc(curinspos);
740 end;
741 ait_comp_64bit,
742 ait_real_64bit:
743 begin
744 inc(curinspos,2);
745 end;
746 ait_real_80bit:
747 begin
748 inc(curinspos,3);
749 end;
750 end;
751 { special case for case jump tables }
752 if SimpleGetNextInstruction(curtai,hp) and
753 (tai(hp).typ=ait_instruction) and
754 (taicpu(hp).opcode=A_LDR) and
755 (taicpu(hp).oper[0]^.typ=top_reg) and
756 (taicpu(hp).oper[0]^.reg=NR_PC) then
757 begin
758 penalty:=1;
759 hp:=tai(hp.next);
760 { skip register allocations and comments inserted by the optimizer }
761 while assigned(hp) and (hp.typ in [ait_comment,ait_regalloc]) do
762 hp:=tai(hp.next);
763 while assigned(hp) and (hp.typ=ait_const) do
764 begin
765 inc(penalty);
766 hp:=tai(hp.next);
767 end;
768 end
769 else
770 penalty:=0;
771
772 { FLD/FST VFP instructions have a limit of +/- 1024, not 4096 }
773 if SimpleGetNextInstruction(curtai,hp) and
774 (tai(hp).typ=ait_instruction) and
775 ((taicpu(hp).opcode=A_FLDS) or
776 (taicpu(hp).opcode=A_FLDD)) then
777 limit:=254;
778
779 { don't miss an insert }
780 doinsert:=doinsert or
781 (not(curdata.empty) and
782 (curinspos-lastinspos+penalty+extradataoffset>limit));
783
784 { split only at real instructions else the test below fails }
785 if doinsert and (curtai.typ=ait_instruction) and
786 (
787 { don't split loads of pc to lr and the following move }
788 not(
789 (taicpu(curtai).opcode=A_MOV) and
790 (taicpu(curtai).oper[0]^.typ=top_reg) and
791 (taicpu(curtai).oper[0]^.reg=NR_R14) and
792 (taicpu(curtai).oper[1]^.typ=top_reg) and
793 (taicpu(curtai).oper[1]^.reg=NR_PC)
794 )
795 ) then
796 begin
797 lastinspos:=-1;
798 extradataoffset:=0;
799 limit:=1016;
800 doinsert:=false;
801 hp:=tai(curtai.next);
802 current_asmdata.getjumplabel(l);
803 curdata.insert(taicpu.op_sym(A_B,l));
804 curdata.concat(tai_label.create(l));
805 list.insertlistafter(curtai,curdata);
806 curtai:=hp;
807 end
808 else
809 curtai:=tai(curtai.next);
810 end;
811 list.concatlist(curdata);
812 curdata.free;
813*)
814 end;
815
816
817 procedure finalizearmcode(list, listtoinsert: TAsmList);
818 begin
819 insertpcrelativedata(list, listtoinsert);
820 end;
821
822 procedure InsertPData;
823 var
824 prolog: TAsmList;
825 begin
826 prolog:=TAsmList.create;
827 new_section(prolog,sec_code,'FPC_EH_PROLOG',sizeof(pint),secorder_begin);
828 prolog.concat(Tai_const.Createname('_ARM_ExceptionHandler', 0));
829 prolog.concat(Tai_const.Create_32bit(0));
830 prolog.concat(Tai_symbol.Createname_global('FPC_EH_CODE_START',AT_DATA,0));
831 { dummy function }
832 prolog.concat(taicpu.op_reg(A_BR,NR_X29));
833 current_asmdata.asmlists[al_start].insertList(prolog);
834 prolog.Free;
835 new_section(current_asmdata.asmlists[al_end],sec_pdata,'',sizeof(pint));
836 current_asmdata.asmlists[al_end].concat(Tai_const.Createname('FPC_EH_CODE_START', 0));
837 current_asmdata.asmlists[al_end].concat(Tai_const.Create_32bit(longint($ffffff01)));
838 end;
839
840(*
841 Floating point instruction format information, taken from the linux kernel
842 ARM Floating Point Instruction Classes
843 | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | |
844 |c o n d|1 1 0 P|U|u|W|L| Rn |v| Fd |0|0|0|1| o f f s e t | CPDT
845 |c o n d|1 1 0 P|U|w|W|L| Rn |x| Fd |0|0|1|0| o f f s e t | CPDT (copro 2)
846 | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | |
847 |c o n d|1 1 1 0|a|b|c|d|e| Fn |j| Fd |0|0|0|1|f|g|h|0|i| Fm | CPDO
848 |c o n d|1 1 1 0|a|b|c|L|e| Fn | Rd |0|0|0|1|f|g|h|1|i| Fm | CPRT
849 |c o n d|1 1 1 0|a|b|c|1|e| Fn |1|1|1|1|0|0|0|1|f|g|h|1|i| Fm | comparisons
850 | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | |
851
852 CPDT data transfer instructions
853 LDF, STF, LFM (copro 2), SFM (copro 2)
854
855 CPDO dyadic arithmetic instructions
856 ADF, MUF, SUF, RSF, DVF, RDF,
857 POW, RPW, RMF, FML, FDV, FRD, POL
858
859 CPDO monadic arithmetic instructions
860 MVF, MNF, ABS, RND, SQT, LOG, LGN, EXP,
861 SIN, COS, TAN, ASN, ACS, ATN, URD, NRM
862
863 CPRT joint arithmetic/data transfer instructions
864 FIX (arithmetic followed by load/store)
865 FLT (load/store followed by arithmetic)
866 CMF, CNF CMFE, CNFE (comparisons)
867 WFS, RFS (write/read floating point status register)
868 WFC, RFC (write/read floating point control register)
869
870 cond condition codes
871 P pre/post index bit: 0 = postindex, 1 = preindex
872 U up/down bit: 0 = stack grows down, 1 = stack grows up
873 W write back bit: 1 = update base register (Rn)
874 L load/store bit: 0 = store, 1 = load
875 Rn base register
876 Rd destination/source register
877 Fd floating point destination register
878 Fn floating point source register
879 Fm floating point source register or floating point constant
880
881 uv transfer length (TABLE 1)
882 wx register count (TABLE 2)
883 abcd arithmetic opcode (TABLES 3 & 4)
884 ef destination size (rounding precision) (TABLE 5)
885 gh rounding mode (TABLE 6)
886 j dyadic/monadic bit: 0 = dyadic, 1 = monadic
887 i constant bit: 1 = constant (TABLE 6)
888 */
889
890 /*
891 TABLE 1
892 +-------------------------+---+---+---------+---------+
893 | Precision | u | v | FPSR.EP | length |
894 +-------------------------+---+---+---------+---------+
895 | Single | 0 | 0 | x | 1 words |
896 | Double | 1 | 1 | x | 2 words |
897 | Extended | 1 | 1 | x | 3 words |
898 | Packed decimal | 1 | 1 | 0 | 3 words |
899 | Expanded packed decimal | 1 | 1 | 1 | 4 words |
900 +-------------------------+---+---+---------+---------+
901 Note: x = don't care
902 */
903
904 /*
905 TABLE 2
906 +---+---+---------------------------------+
907 | w | x | Number of registers to transfer |
908 +---+---+---------------------------------+
909 | 0 | 1 | 1 |
910 | 1 | 0 | 2 |
911 | 1 | 1 | 3 |
912 | 0 | 0 | 4 |
913 +---+---+---------------------------------+
914 */
915
916 /*
917 TABLE 3: Dyadic Floating Point Opcodes
918 +---+---+---+---+----------+-----------------------+-----------------------+
919 | a | b | c | d | Mnemonic | Description | Operation |
920 +---+---+---+---+----------+-----------------------+-----------------------+
921 | 0 | 0 | 0 | 0 | ADF | Add | Fd := Fn + Fm |
922 | 0 | 0 | 0 | 1 | MUF | Multiply | Fd := Fn * Fm |
923 | 0 | 0 | 1 | 0 | SUF | Subtract | Fd := Fn - Fm |
924 | 0 | 0 | 1 | 1 | RSF | Reverse subtract | Fd := Fm - Fn |
925 | 0 | 1 | 0 | 0 | DVF | Divide | Fd := Fn / Fm |
926 | 0 | 1 | 0 | 1 | RDF | Reverse divide | Fd := Fm / Fn |
927 | 0 | 1 | 1 | 0 | POW | Power | Fd := Fn ^ Fm |
928 | 0 | 1 | 1 | 1 | RPW | Reverse power | Fd := Fm ^ Fn |
929 | 1 | 0 | 0 | 0 | RMF | Remainder | Fd := IEEE rem(Fn/Fm) |
930 | 1 | 0 | 0 | 1 | FML | Fast Multiply | Fd := Fn * Fm |
931 | 1 | 0 | 1 | 0 | FDV | Fast Divide | Fd := Fn / Fm |
932 | 1 | 0 | 1 | 1 | FRD | Fast reverse divide | Fd := Fm / Fn |
933 | 1 | 1 | 0 | 0 | POL | Polar angle (ArcTan2) | Fd := arctan2(Fn,Fm) |
934 | 1 | 1 | 0 | 1 | | undefined instruction | trap |
935 | 1 | 1 | 1 | 0 | | undefined instruction | trap |
936 | 1 | 1 | 1 | 1 | | undefined instruction | trap |
937 +---+---+---+---+----------+-----------------------+-----------------------+
938 Note: POW, RPW, POL are deprecated, and are available for backwards
939 compatibility only.
940 */
941
942 /*
943 TABLE 4: Monadic Floating Point Opcodes
944 +---+---+---+---+----------+-----------------------+-----------------------+
945 | a | b | c | d | Mnemonic | Description | Operation |
946 +---+---+---+---+----------+-----------------------+-----------------------+
947 | 0 | 0 | 0 | 0 | MVF | Move | Fd := Fm |
948 | 0 | 0 | 0 | 1 | MNF | Move negated | Fd := - Fm |
949 | 0 | 0 | 1 | 0 | ABS | Absolute value | Fd := abs(Fm) |
950 | 0 | 0 | 1 | 1 | RND | Round to integer | Fd := int(Fm) |
951 | 0 | 1 | 0 | 0 | SQT | Square root | Fd := sqrt(Fm) |
952 | 0 | 1 | 0 | 1 | LOG | Log base 10 | Fd := log10(Fm) |
953 | 0 | 1 | 1 | 0 | LGN | Log base e | Fd := ln(Fm) |
954 | 0 | 1 | 1 | 1 | EXP | Exponent | Fd := e ^ Fm |
955 | 1 | 0 | 0 | 0 | SIN | Sine | Fd := sin(Fm) |
956 | 1 | 0 | 0 | 1 | COS | Cosine | Fd := cos(Fm) |
957 | 1 | 0 | 1 | 0 | TAN | Tangent | Fd := tan(Fm) |
958 | 1 | 0 | 1 | 1 | ASN | Arc Sine | Fd := arcsin(Fm) |
959 | 1 | 1 | 0 | 0 | ACS | Arc Cosine | Fd := arccos(Fm) |
960 | 1 | 1 | 0 | 1 | ATN | Arc Tangent | Fd := arctan(Fm) |
961 | 1 | 1 | 1 | 0 | URD | Unnormalized round | Fd := int(Fm) |
962 | 1 | 1 | 1 | 1 | NRM | Normalize | Fd := norm(Fm) |
963 +---+---+---+---+----------+-----------------------+-----------------------+
964 Note: LOG, LGN, EXP, SIN, COS, TAN, ASN, ACS, ATN are deprecated, and are
965 available for backwards compatibility only.
966 */
967
968 /*
969 TABLE 5
970 +-------------------------+---+---+
971 | Rounding Precision | e | f |
972 +-------------------------+---+---+
973 | IEEE Single precision | 0 | 0 |
974 | IEEE Double precision | 0 | 1 |
975 | IEEE Extended precision | 1 | 0 |
976 | undefined (trap) | 1 | 1 |
977 +-------------------------+---+---+
978 */
979
980 /*
981 TABLE 5
982 +---------------------------------+---+---+
983 | Rounding Mode | g | h |
984 +---------------------------------+---+---+
985 | Round to nearest (default) | 0 | 0 |
986 | Round toward plus infinity | 0 | 1 |
987 | Round toward negative infinity | 1 | 0 |
988 | Round toward zero | 1 | 1 |
989 +---------------------------------+---+---+
990*)
991 function taicpu.GetString:string;
992 var
993 i : longint;
994 s : string;
995 addsize : boolean;
996 begin
997 s:='['+gas_op2str[opcode];
998 for i:=0 to ops-1 do
999 begin
1000 with oper[i]^ do
1001 begin
1002 if i=0 then
1003 s:=s+' '
1004 else
1005 s:=s+',';
1006 { type }
1007 addsize:=false;
1008 if (ot and OT_VREG)=OT_VREG then
1009 s:=s+'vreg'
1010 else
1011 if (ot and OT_FPUREG)=OT_FPUREG then
1012 s:=s+'fpureg'
1013 else
1014 if (ot and OT_REGISTER)=OT_REGISTER then
1015 begin
1016 s:=s+'reg';
1017 addsize:=true;
1018 end
1019 else
1020 if (ot and OT_REGLIST)=OT_REGLIST then
1021 begin
1022 s:=s+'reglist';
1023 addsize:=false;
1024 end
1025 else
1026 if (ot and OT_IMMEDIATE)=OT_IMMEDIATE then
1027 begin
1028 s:=s+'imm';
1029 addsize:=true;
1030 end
1031 else
1032 if (ot and OT_MEMORY)=OT_MEMORY then
1033 begin
1034 s:=s+'mem';
1035 addsize:=true;
1036 if (ot and OT_AM2)<>0 then
1037 s:=s+' am2 ';
1038 end
1039 else
1040 s:=s+'???';
1041 { size }
1042 if addsize then
1043 begin
1044 if (ot and OT_BITS8)<>0 then
1045 s:=s+'8'
1046 else
1047 if (ot and OT_BITS16)<>0 then
1048 s:=s+'24'
1049 else
1050 if (ot and OT_BITS32)<>0 then
1051 s:=s+'32'
1052 else
1053 if (ot and OT_BITSSHIFTER)<>0 then
1054 s:=s+'shifter'
1055 else
1056 s:=s+'??';
1057 { signed }
1058 if (ot and OT_SIGNED)<>0 then
1059 s:=s+'s';
1060 end;
1061 end;
1062 end;
1063 GetString:=s+']';
1064 end;
1065
1066
1067 procedure taicpu.ResetPass1;
1068 begin
1069 { we need to reset everything here, because the choosen insentry
1070 can be invalid for a new situation where the previously optimized
1071 insentry is not correct }
1072 InsEntry:=nil;
1073 InsSize:=0;
1074 LastInsOffset:=-1;
1075 end;
1076
1077
1078 procedure taicpu.ResetPass2;
1079 begin
1080 { we are here in a second pass, check if the instruction can be optimized }
1081 if assigned(InsEntry) and
1082 ((InsEntry^.flags and IF_PASS2)<>0) then
1083 begin
1084 InsEntry:=nil;
1085 InsSize:=0;
1086 end;
1087 LastInsOffset:=-1;
1088 end;
1089
1090
1091 function taicpu.CheckIfValid:boolean;
1092 begin
1093 Result:=False; { unimplemented }
1094 end;
1095
1096
1097 function taicpu.Pass1(objdata:TObjData):longint;
1098 begin
1099 Pass1:=0;
1100 LastInsOffset:=-1;
1101 end;
1102
1103
1104 procedure taicpu.Pass2(objdata:TObjData);
1105 begin
1106 { error in pass1 ? }
1107 if insentry=nil then
1108 exit;
1109 current_filepos:=fileinfo;
1110 { Generate the instruction }
1111 GenCode(objdata);
1112 end;
1113
1114
1115 procedure taicpu.ppuloadoper(ppufile:tcompilerppufile;var o:toper);
1116 begin
1117 end;
1118
1119
1120 procedure taicpu.ppuwriteoper(ppufile:tcompilerppufile;const o:toper);
1121 begin
1122 end;
1123
1124
1125 procedure taicpu.ppubuildderefimploper(var o:toper);
1126 begin
1127 end;
1128
1129
1130 procedure taicpu.ppuderefoper(var o:toper);
1131 begin
1132 end;
1133
1134
1135 function taicpu.InsEnd:longint;
1136 begin
1137 Result:=0; { unimplemented }
1138 end;
1139
1140
1141 procedure taicpu.create_ot(objdata:TObjData);
1142 begin
1143 end;
1144
1145
1146 function taicpu.Matches(p:PInsEntry):longint;
1147 begin
1148 end;
1149
1150
1151 function taicpu.calcsize(p:PInsEntry):shortint;
1152 begin
1153 result:=4;
1154 end;
1155
1156
1157 function taicpu.NeedAddrPrefix(opidx:byte):boolean;
1158 begin
1159 Result:=False; { unimplemented }
1160 end;
1161
1162
1163 procedure taicpu.Swapoperands;
1164 begin
1165 end;
1166
1167
1168 function taicpu.FindInsentry(objdata:TObjData):boolean;
1169 begin
1170 end;
1171
1172
1173 procedure taicpu.gencode(objdata:TObjData);
1174 var
1175 bytes : dword;
1176 i_field : byte;
1177
1178 procedure setshifterop(op : byte);
1179 begin
1180 case oper[op]^.typ of
1181 top_const:
1182 begin
1183 i_field:=1;
1184 bytes:=bytes or dword(oper[op]^.val and $fff);
1185 end;
1186 top_reg:
1187 begin
1188 i_field:=0;
1189 bytes:=bytes or (getsupreg(oper[op]^.reg) shl 16);
1190
1191 { does a real shifter op follow? }
1192 if (op+1<=op) and (oper[op+1]^.typ=top_shifterop) then
1193 begin
1194 end;
1195 end;
1196 else
1197 internalerror(2005091103);
1198 end;
1199 end;
1200
1201 begin
1202 bytes:=$0;
1203 { evaluate and set condition code }
1204
1205 { condition code allowed? }
1206
1207 { setup rest of the instruction }
1208 case insentry^.code[0] of
1209 #$08:
1210 begin
1211 { set instruction code }
1212 bytes:=bytes or (ord(insentry^.code[1]) shl 26);
1213 bytes:=bytes or (ord(insentry^.code[2]) shl 21);
1214
1215 { set destination }
1216 bytes:=bytes or (getsupreg(oper[0]^.reg) shl 12);
1217
1218 { create shifter op }
1219 setshifterop(1);
1220
1221 { set i field }
1222 bytes:=bytes or (i_field shl 25);
1223
1224 { set s if necessary }
1225 if oppostfix=PF_S then
1226 bytes:=bytes or (1 shl 20);
1227 end;
1228 #$ff:
1229 internalerror(2005091101);
1230 else
1231 internalerror(2005091102);
1232 end;
1233 { we're finished, write code }
1234 objdata.writebytes(bytes,sizeof(bytes));
1235 end;
1236
1237
1238{$ifdef dummy}
1239(*
1240static void gencode (long segment, long offset, int bits,
1241 insn *ins, char *codes, long insn_end)
1242{
1243 int has_S_code; /* S - setflag */
1244 int has_B_code; /* B - setflag */
1245 int has_T_code; /* T - setflag */
1246 int has_W_code; /* ! => W flag */
1247 int has_F_code; /* ^ => S flag */
1248 int keep;
1249 unsigned char c;
1250 unsigned char bytes[4];
1251 long data, size;
1252 static int cc_code[] = /* bit pattern of cc */
1253 { /* order as enum in */
1254 0x0E, 0x03, 0x02, 0x00, /* nasm.h */
1255 0x0A, 0x0C, 0x08, 0x0D,
1256 0x09, 0x0B, 0x04, 0x01,
1257 0x05, 0x07, 0x06,
1258 };
1259
1260
1261#ifdef DEBUG
1262static char *CC[] =
1263 { /* condition code names */
1264 "AL", "CC", "CS", "EQ",
1265 "GE", "GT", "HI", "LE",
1266 "LS", "LT", "MI", "NE",
1267 "PL", "VC", "VS", "",
1268 "S"
1269};
1270
1271
1272 has_S_code = (ins->condition & C_SSETFLAG);
1273 has_B_code = (ins->condition & C_BSETFLAG);
1274 has_T_code = (ins->condition & C_TSETFLAG);
1275 has_W_code = (ins->condition & C_EXSETFLAG);
1276 has_F_code = (ins->condition & C_FSETFLAG);
1277 ins->condition = (ins->condition & 0x0F);
1278
1279
1280 if (rt_debug)
1281 {
1282 printf ("gencode: instruction: %s%s", insn_names[ins->opcode],
1283 CC[ins->condition & 0x0F]);
1284 if (has_S_code)
1285 printf ("S");
1286 if (has_B_code)
1287 printf ("B");
1288 if (has_T_code)
1289 printf ("T");
1290 if (has_W_code)
1291 printf ("!");
1292 if (has_F_code)
1293 printf ("^");
1294
1295 printf ("\n");
1296
1297 c = *codes;
1298
1299 printf (" (%d) decode - '0x%02X'\n", ins->operands, c);
1300
1301
1302 bytes[0] = 0xB;
1303 bytes[1] = 0xE;
1304 bytes[2] = 0xE;
1305 bytes[3] = 0xF;
1306 }
1307
1308 // First condition code in upper nibble
1309 if (ins->condition < C_NONE)
1310 {
1311 c = cc_code[ins->condition] << 4;
1312 }
1313 else
1314 {
1315 c = cc_code[C_AL] << 4; // is often ALWAYS but not always
1316 }
1317
1318
1319 switch (keep = *codes)
1320 {
1321 case 1:
1322 // B, BL
1323 ++codes;
1324 c |= *codes++;
1325 bytes[0] = c;
1326
1327 if (ins->oprs[0].segment != segment)
1328 {
1329 // fais une relocation
1330 c = 1;
1331 data = 0; // Let the linker locate ??
1332 }
1333 else
1334 {
1335 c = 0;
1336 data = ins->oprs[0].offset - (offset + 8);
1337
1338 if (data % 4)
1339 {
1340 errfunc (ERR_NONFATAL, "offset not aligned on 4 bytes");
1341 }
1342 }
1343
1344 if (data >= 0x1000)
1345 {
1346 errfunc (ERR_NONFATAL, "too long offset");
1347 }
1348
1349 data = data >> 2;
1350 bytes[1] = (data >> 16) & 0xFF;
1351 bytes[2] = (data >> 8) & 0xFF;
1352 bytes[3] = (data ) & 0xFF;
1353
1354 if (c == 1)
1355 {
1356// out (offset, segment, &bytes[0], OUT_RAWDATA+1, NO_SEG, NO_SEG);
1357 out (offset, segment, &bytes[0], OUT_REL3ADR+4, ins->oprs[0].segment, NO_SEG);
1358 }
1359 else
1360 {
1361 out (offset, segment, &bytes[0], OUT_RAWDATA+4, NO_SEG, NO_SEG);
1362 }
1363 return;
1364
1365 case 2:
1366 // SWI
1367 ++codes;
1368 c |= *codes++;
1369 bytes[0] = c;
1370 data = ins->oprs[0].offset;
1371 bytes[1] = (data >> 16) & 0xFF;
1372 bytes[2] = (data >> 8) & 0xFF;
1373 bytes[3] = (data) & 0xFF;
1374 out (offset, segment, &bytes, OUT_RAWDATA+4, NO_SEG, NO_SEG);
1375 return;
1376 case 3:
1377 // BX
1378 ++codes;
1379 c |= *codes++;
1380 bytes[0] = c;
1381 bytes[1] = *codes++;
1382 bytes[2] = *codes++;
1383 bytes[3] = *codes++;
1384 c = regval (&ins->oprs[0],1);
1385 if (c == 15) // PC
1386 {
1387 errfunc (ERR_WARNING, "'BX' with R15 has undefined behaviour");
1388 }
1389 else if (c > 15)
1390 {
1391 errfunc (ERR_NONFATAL, "Illegal register specified for 'BX'");
1392 }
1393
1394 bytes[3] |= (c & 0x0F);
1395 out (offset, segment, bytes, OUT_RAWDATA+4, NO_SEG, NO_SEG);
1396 return;
1397
1398 case 4: // AND Rd,Rn,Rm
1399 case 5: // AND Rd,Rn,Rm,<shift>Rs
1400 case 6: // AND Rd,Rn,Rm,<shift>imm
1401 case 7: // AND Rd,Rn,<shift>imm
1402 ++codes;
1403#ifdef DEBUG
1404 if (rt_debug)
1405 {
1406 printf (" decode - '0x%02X'\n", keep);
1407 printf (" code - '0x%02X'\n", (unsigned char) ( *codes));
1408 }
1409#endif
1410 bytes[0] = c | *codes;
1411 ++codes;
1412
1413 bytes[1] = *codes;
1414 if (has_S_code)
1415 bytes[1] |= 0x10;
1416 c = regval (&ins->oprs[1],1);
1417 // Rn in low nibble
1418 bytes[1] |= c;
1419
1420 // Rd in high nibble
1421 bytes[2] = regval (&ins->oprs[0],1) << 4;
1422
1423 if (keep != 7)
1424 {
1425 // Rm in low nibble
1426 bytes[3] = regval (&ins->oprs[2],1);
1427 }
1428
1429 // Shifts if any
1430 if (keep == 5 || keep == 6)
1431 {
1432 // Shift in bytes 2 and 3
1433 if (keep == 5)
1434 {
1435 // Rs
1436 c = regval (&ins->oprs[3],1);
1437 bytes[2] |= c;
1438
1439 c = 0x10; // Set bit 4 in byte[3]
1440 }
1441 if (keep == 6)
1442 {
1443 c = (ins->oprs[3].offset) & 0x1F;
1444
1445 // #imm
1446 bytes[2] |= c >> 1;
1447 if (c & 0x01)
1448 {
1449 bytes[3] |= 0x80;
1450 }
1451 c = 0; // Clr bit 4 in byte[3]
1452 }
1453 // <shift>
1454 c |= shiftval (&ins->oprs[3]) << 5;
1455
1456 bytes[3] |= c;
1457 }
1458
1459 // reg,reg,imm
1460 if (keep == 7)
1461 {
1462 int shimm;
1463
1464 shimm = imm_shift (ins->oprs[2].offset);
1465
1466 if (shimm == -1)
1467 {
1468 errfunc (ERR_NONFATAL, "cannot create that constant");
1469 }
1470 bytes[3] = shimm & 0xFF;
1471 bytes[2] |= (shimm & 0xF00) >> 8;
1472 }
1473
1474 out (offset, segment, bytes, OUT_RAWDATA+4, NO_SEG, NO_SEG);
1475 return;
1476
1477 case 8: // MOV Rd,Rm
1478 case 9: // MOV Rd,Rm,<shift>Rs
1479 case 0xA: // MOV Rd,Rm,<shift>imm
1480 case 0xB: // MOV Rd,<shift>imm
1481 ++codes;
1482#ifdef DEBUG
1483 if (rt_debug)
1484 {
1485 printf (" decode - '0x%02X'\n", keep);
1486 printf (" code - '0x%02X'\n", (unsigned char) ( *codes));
1487 }
1488#endif
1489 bytes[0] = c | *codes;
1490 ++codes;
1491
1492 bytes[1] = *codes;
1493 if (has_S_code)
1494 bytes[1] |= 0x10;
1495
1496 // Rd in high nibble
1497 bytes[2] = regval (&ins->oprs[0],1) << 4;
1498
1499 if (keep != 0x0B)
1500 {
1501 // Rm in low nibble
1502 bytes[3] = regval (&ins->oprs[1],1);
1503 }
1504
1505 // Shifts if any
1506 if (keep == 0x09 || keep == 0x0A)
1507 {
1508 // Shift in bytes 2 and 3
1509 if (keep == 0x09)
1510 {
1511 // Rs
1512 c = regval (&ins->oprs[2],1);
1513 bytes[2] |= c;
1514
1515 c = 0x10; // Set bit 4 in byte[3]
1516 }
1517 if (keep == 0x0A)
1518 {
1519 c = (ins->oprs[2].offset) & 0x1F;
1520
1521 // #imm
1522 bytes[2] |= c >> 1;
1523 if (c & 0x01)
1524 {
1525 bytes[3] |= 0x80;
1526 }
1527 c = 0; // Clr bit 4 in byte[3]
1528 }
1529 // <shift>
1530 c |= shiftval (&ins->oprs[2]) << 5;
1531
1532 bytes[3] |= c;
1533 }
1534
1535 // reg,imm
1536 if (keep == 0x0B)
1537 {
1538 int shimm;
1539
1540 shimm = imm_shift (ins->oprs[1].offset);
1541
1542 if (shimm == -1)
1543 {
1544 errfunc (ERR_NONFATAL, "cannot create that constant");
1545 }
1546 bytes[3] = shimm & 0xFF;
1547 bytes[2] |= (shimm & 0xF00) >> 8;
1548 }
1549
1550 out (offset, segment, bytes, OUT_RAWDATA+4, NO_SEG, NO_SEG);
1551 return;
1552
1553
1554 case 0xC: // CMP Rn,Rm
1555 case 0xD: // CMP Rn,Rm,<shift>Rs
1556 case 0xE: // CMP Rn,Rm,<shift>imm
1557 case 0xF: // CMP Rn,<shift>imm
1558 ++codes;
1559
1560 bytes[0] = c | *codes++;
1561
1562 bytes[1] = *codes;
1563
1564 // Implicit S code
1565 bytes[1] |= 0x10;
1566
1567 c = regval (&ins->oprs[0],1);
1568 // Rn in low nibble
1569 bytes[1] |= c;
1570
1571 // No destination
1572 bytes[2] = 0;
1573
1574 if (keep != 0x0B)
1575 {
1576 // Rm in low nibble
1577 bytes[3] = regval (&ins->oprs[1],1);
1578 }
1579
1580 // Shifts if any
1581 if (keep == 0x0D || keep == 0x0E)
1582 {
1583 // Shift in bytes 2 and 3
1584 if (keep == 0x0D)
1585 {
1586 // Rs
1587 c = regval (&ins->oprs[2],1);
1588 bytes[2] |= c;
1589
1590 c = 0x10; // Set bit 4 in byte[3]
1591 }
1592 if (keep == 0x0E)
1593 {
1594 c = (ins->oprs[2].offset) & 0x1F;
1595
1596 // #imm
1597 bytes[2] |= c >> 1;
1598 if (c & 0x01)
1599 {
1600 bytes[3] |= 0x80;
1601 }
1602 c = 0; // Clr bit 4 in byte[3]
1603 }
1604 // <shift>
1605 c |= shiftval (&ins->oprs[2]) << 5;
1606
1607 bytes[3] |= c;
1608 }
1609
1610 // reg,imm
1611 if (keep == 0x0F)
1612 {
1613 int shimm;
1614
1615 shimm = imm_shift (ins->oprs[1].offset);
1616
1617 if (shimm == -1)
1618 {
1619 errfunc (ERR_NONFATAL, "cannot create that constant");
1620 }
1621 bytes[3] = shimm & 0xFF;
1622 bytes[2] |= (shimm & 0xF00) >> 8;
1623 }
1624
1625 out (offset, segment, bytes, OUT_RAWDATA+4, NO_SEG, NO_SEG);
1626 return;
1627
1628 case 0x10: // MRS Rd,<psr>
1629 ++codes;
1630
1631 bytes[0] = c | *codes++;
1632
1633 bytes[1] = *codes++;
1634
1635 // Rd
1636 c = regval (&ins->oprs[0],1);
1637
1638 bytes[2] = c << 4;
1639
1640 bytes[3] = 0;
1641
1642 c = ins->oprs[1].basereg;
1643
1644 if (c == R_CPSR || c == R_SPSR)
1645 {
1646 if (c == R_SPSR)
1647 {
1648 bytes[1] |= 0x40;
1649 }
1650 }
1651 else
1652 {
1653 errfunc (ERR_NONFATAL, "CPSR or SPSR expected");
1654 }
1655
1656 out (offset, segment, bytes, OUT_RAWDATA+4, NO_SEG, NO_SEG);
1657
1658 return;
1659
1660 case 0x11: // MSR <psr>,Rm
1661 case 0x12: // MSR <psrf>,Rm
1662 case 0x13: // MSR <psrf>,#expression
1663 ++codes;
1664
1665 bytes[0] = c | *codes++;
1666
1667 bytes[1] = *codes++;
1668
1669 bytes[2] = *codes;
1670
1671
1672 if (keep == 0x11 || keep == 0x12)
1673 {
1674 // Rm
1675 c = regval (&ins->oprs[1],1);
1676
1677 bytes[3] = c;
1678 }
1679 else
1680 {
1681 int shimm;
1682
1683 shimm = imm_shift (ins->oprs[1].offset);
1684
1685 if (shimm == -1)
1686 {
1687 errfunc (ERR_NONFATAL, "cannot create that constant");
1688 }
1689 bytes[3] = shimm & 0xFF;
1690 bytes[2] |= (shimm & 0xF00) >> 8;
1691 }
1692
1693 c = ins->oprs[0].basereg;
1694
1695 if ( keep == 0x11)
1696 {
1697 if ( c == R_CPSR || c == R_SPSR)
1698 {
1699 if ( c== R_SPSR)
1700 {
1701 bytes[1] |= 0x40;
1702 }
1703 }
1704 else
1705 {
1706 errfunc (ERR_NONFATAL, "CPSR or SPSR expected");
1707 }
1708 }
1709 else
1710 {
1711 if ( c == R_CPSR_FLG || c == R_SPSR_FLG)
1712 {
1713 if ( c== R_SPSR_FLG)
1714 {
1715 bytes[1] |= 0x40;
1716 }
1717 }
1718 else
1719 {
1720 errfunc (ERR_NONFATAL, "CPSR_flg or SPSR_flg expected");
1721 }
1722 }
1723 break;
1724
1725 case 0x14: // MUL Rd,Rm,Rs
1726 case 0x15: // MULA Rd,Rm,Rs,Rn
1727 ++codes;
1728
1729 bytes[0] = c | *codes++;
1730
1731 bytes[1] = *codes++;
1732
1733 bytes[3] = *codes;
1734
1735 // Rd
1736 bytes[1] |= regval (&ins->oprs[0],1);
1737 if (has_S_code)
1738 bytes[1] |= 0x10;
1739
1740 // Rm
1741 bytes[3] |= regval (&ins->oprs[1],1);
1742
1743 // Rs
1744 bytes[2] = regval (&ins->oprs[2],1);
1745
1746 if (keep == 0x15)
1747 {
1748 bytes[2] |= regval (&ins->oprs[3],1) << 4;
1749 }
1750 break;
1751
1752 case 0x16: // SMLAL RdHi,RdLo,Rm,Rs
1753 ++codes;
1754
1755 bytes[0] = c | *codes++;
1756
1757 bytes[1] = *codes++;
1758
1759 bytes[3] = *codes;
1760
1761 // RdHi
1762 bytes[1] |= regval (&ins->oprs[1],1);
1763 if (has_S_code)
1764 bytes[1] |= 0x10;
1765
1766 // RdLo
1767 bytes[2] = regval (&ins->oprs[0],1) << 4;
1768 // Rm
1769 bytes[3] |= regval (&ins->oprs[2],1);
1770
1771 // Rs
1772 bytes[2] |= regval (&ins->oprs[3],1);
1773
1774 break;
1775
1776 case 0x17: // LDR Rd, expression
1777 ++codes;
1778
1779 bytes[0] = c | *codes++;
1780
1781 bytes[1] = *codes++;
1782
1783 // Rd
1784 bytes[2] = regval (&ins->oprs[0],1) << 4;
1785 if (has_B_code)
1786 bytes[1] |= 0x40;
1787 if (has_T_code)
1788 {
1789 errfunc (ERR_NONFATAL, "'T' not allowed in pre-index mode");
1790 }
1791 if (has_W_code)
1792 {
1793 errfunc (ERR_NONFATAL, "'!' not allowed");
1794 }
1795
1796 // Rn - implicit R15
1797 bytes[1] |= 0xF;
1798
1799 if (ins->oprs[1].segment != segment)
1800 {
1801 errfunc (ERR_NONFATAL, "label not in same segment");
1802 }
1803
1804 data = ins->oprs[1].offset - (offset + 8);
1805
1806 if (data < 0)
1807 {
1808 data = -data;
1809 }
1810 else
1811 {
1812 bytes[1] |= 0x80;
1813 }
1814
1815 if (data >= 0x1000)
1816 {
1817 errfunc (ERR_NONFATAL, "too long offset");
1818 }
1819
1820 bytes[2] |= ((data & 0xF00) >> 8);
1821 bytes[3] = data & 0xFF;
1822 break;
1823
1824 case 0x18: // LDR Rd, [Rn]
1825 ++codes;
1826
1827 bytes[0] = c | *codes++;
1828
1829 bytes[1] = *codes++;
1830
1831 // Rd
1832 bytes[2] = regval (&ins->oprs[0],1) << 4;
1833 if (has_B_code)
1834 bytes[1] |= 0x40;
1835 if (has_T_code)
1836 {
1837 bytes[1] |= 0x20; // write-back
1838 }
1839 else
1840 {
1841 bytes[0] |= 0x01; // implicit pre-index mode
1842 }
1843
1844 if (has_W_code)
1845 {
1846 bytes[1] |= 0x20; // write-back
1847 }
1848
1849 // Rn
1850 c = regval (&ins->oprs[1],1);
1851 bytes[1] |= c;
1852
1853 if (c == 0x15) // R15
1854 data = -8;
1855 else
1856 data = 0;
1857
1858 if (data < 0)
1859 {
1860 data = -data;
1861 }
1862 else
1863 {
1864 bytes[1] |= 0x80;
1865 }
1866
1867 bytes[2] |= ((data & 0xF00) >> 8);
1868 bytes[3] = data & 0xFF;
1869 break;
1870
1871 case 0x19: // LDR Rd, [Rn,#expression]
1872 case 0x20: // LDR Rd, [Rn,Rm]
1873 case 0x21: // LDR Rd, [Rn,Rm,shift]
1874 ++codes;
1875
1876 bytes[0] = c | *codes++;
1877
1878 bytes[1] = *codes++;
1879
1880 // Rd
1881 bytes[2] = regval (&ins->oprs[0],1) << 4;
1882 if (has_B_code)
1883 bytes[1] |= 0x40;
1884
1885 // Rn
1886 c = regval (&ins->oprs[1],1);
1887 bytes[1] |= c;
1888
1889 if (ins->oprs[ins->operands-1].bracket) // FIXME: Bracket on last operand -> pre-index <--
1890 {
1891 bytes[0] |= 0x01; // pre-index mode
1892 if (has_W_code)
1893 {
1894 bytes[1] |= 0x20;
1895 }
1896 if (has_T_code)
1897 {
1898 errfunc (ERR_NONFATAL, "'T' not allowed in pre-index mode");
1899 }
1900 }
1901 else
1902 {
1903 if (has_T_code) // Forced write-back in post-index mode
1904 {
1905 bytes[1] |= 0x20;
1906 }
1907 if (has_W_code)
1908 {
1909 errfunc (ERR_NONFATAL, "'!' not allowed in post-index mode");
1910 }
1911 }
1912
1913 if (keep == 0x19)
1914 {
1915 data = ins->oprs[2].offset;
1916
1917 if (data < 0)
1918 {
1919 data = -data;
1920 }
1921 else
1922 {
1923 bytes[1] |= 0x80;
1924 }
1925
1926 if (data >= 0x1000)
1927 {
1928 errfunc (ERR_NONFATAL, "too long offset");
1929 }
1930
1931 bytes[2] |= ((data & 0xF00) >> 8);
1932 bytes[3] = data & 0xFF;
1933 }
1934 else
1935 {
1936 if (ins->oprs[2].minus == 0)
1937 {
1938 bytes[1] |= 0x80;
1939 }
1940 c = regval (&ins->oprs[2],1);
1941 bytes[3] = c;
1942
1943 if (keep == 0x21)
1944 {
1945 c = ins->oprs[3].offset;
1946 if (c > 0x1F)
1947 {
1948 errfunc (ERR_NONFATAL, "too large shiftvalue");
1949 c = c & 0x1F;
1950 }
1951
1952 bytes[2] |= c >> 1;
1953 if (c & 0x01)
1954 {
1955 bytes[3] |= 0x80;
1956 }
1957 bytes[3] |= shiftval (&ins->oprs[3]) << 5;
1958 }
1959 }
1960
1961 break;
1962
1963 case 0x22: // LDRH Rd, expression
1964 ++codes;
1965
1966 bytes[0] = c | 0x01; // Implicit pre-index
1967
1968 bytes[1] = *codes++;
1969
1970 // Rd
1971 bytes[2] = regval (&ins->oprs[0],1) << 4;
1972
1973 // Rn - implicit R15
1974 bytes[1] |= 0xF;
1975
1976 if (ins->oprs[1].segment != segment)
1977 {
1978 errfunc (ERR_NONFATAL, "label not in same segment");
1979 }
1980
1981 data = ins->oprs[1].offset - (offset + 8);
1982
1983 if (data < 0)
1984 {
1985 data = -data;
1986 }
1987 else
1988 {
1989 bytes[1] |= 0x80;
1990 }
1991
1992 if (data >= 0x100)
1993 {
1994 errfunc (ERR_NONFATAL, "too long offset");
1995 }
1996 bytes[3] = *codes++;
1997
1998 bytes[2] |= ((data & 0xF0) >> 4);
1999 bytes[3] |= data & 0xF;
2000 break;
2001
2002 case 0x23: // LDRH Rd, Rn
2003 ++codes;
2004
2005 bytes[0] = c | 0x01; // Implicit pre-index
2006
2007 bytes[1] = *codes++;
2008
2009 // Rd
2010 bytes[2] = regval (&ins->oprs[0],1) << 4;
2011
2012 // Rn
2013 c = regval (&ins->oprs[1],1);
2014 bytes[1] |= c;
2015
2016 if (c == 0x15) // R15
2017 data = -8;
2018 else
2019 data = 0;
2020
2021 if (data < 0)
2022 {
2023 data = -data;
2024 }
2025 else
2026 {
2027 bytes[1] |= 0x80;
2028 }
2029
2030 if (data >= 0x100)
2031 {
2032 errfunc (ERR_NONFATAL, "too long offset");
2033 }
2034 bytes[3] = *codes++;
2035
2036 bytes[2] |= ((data & 0xF0) >> 4);
2037 bytes[3] |= data & 0xF;
2038 break;
2039
2040 case 0x24: // LDRH Rd, Rn, expression
2041 case 0x25: // LDRH Rd, Rn, Rm
2042 ++codes;
2043
2044 bytes[0] = c;
2045
2046 bytes[1] = *codes++;
2047
2048 // Rd
2049 bytes[2] = regval (&ins->oprs[0],1) << 4;
2050
2051 // Rn
2052 c = regval (&ins->oprs[1],1);
2053 bytes[1] |= c;
2054
2055 if (ins->oprs[ins->operands-1].bracket) // FIXME: Bracket on last operand -> pre-index <--
2056 {
2057 bytes[0] |= 0x01; // pre-index mode
2058 if (has_W_code)
2059 {
2060 bytes[1] |= 0x20;
2061 }
2062 }
2063 else
2064 {
2065 if (has_W_code)
2066 {
2067 errfunc (ERR_NONFATAL, "'!' not allowed in post-index mode");
2068 }
2069 }
2070
2071 bytes[3] = *codes++;
2072
2073 if (keep == 0x24)
2074 {
2075 data = ins->oprs[2].offset;
2076
2077 if (data < 0)
2078 {
2079 data = -data;
2080 }
2081 else
2082 {
2083 bytes[1] |= 0x80;
2084 }
2085
2086 if (data >= 0x100)
2087 {
2088 errfunc (ERR_NONFATAL, "too long offset");
2089 }
2090
2091 bytes[2] |= ((data & 0xF0) >> 4);
2092 bytes[3] |= data & 0xF;
2093 }
2094 else
2095 {
2096 if (ins->oprs[2].minus == 0)
2097 {
2098 bytes[1] |= 0x80;
2099 }
2100 c = regval (&ins->oprs[2],1);
2101 bytes[3] |= c;
2102
2103 }
2104 break;
2105
2106 case 0x26: // LDM/STM Rn, {reg-list}
2107 ++codes;
2108
2109 bytes[0] = c;
2110
2111 bytes[0] |= ( *codes >> 4) & 0xF;
2112 bytes[1] = ( *codes << 4) & 0xF0;
2113 ++codes;
2114
2115 if (has_W_code)
2116 {
2117 bytes[1] |= 0x20;
2118 }
2119 if (has_F_code)
2120 {
2121 bytes[1] |= 0x40;
2122 }
2123
2124 // Rn
2125 bytes[1] |= regval (&ins->oprs[0],1);
2126
2127 data = ins->oprs[1].basereg;
2128
2129 bytes[2] = ((data >> 8) & 0xFF);
2130 bytes[3] = (data & 0xFF);
2131
2132 break;
2133
2134 case 0x27: // SWP Rd, Rm, [Rn]
2135 ++codes;
2136
2137 bytes[0] = c;
2138
2139 bytes[0] |= *codes++;
2140
2141 bytes[1] = regval (&ins->oprs[2],1);
2142 if (has_B_code)
2143 {
2144 bytes[1] |= 0x40;
2145 }
2146 bytes[2] = regval (&ins->oprs[0],1) << 4;
2147 bytes[3] = *codes++;
2148 bytes[3] |= regval (&ins->oprs[1],1);
2149 break;
2150
2151 default:
2152 errfunc (ERR_FATAL, "unknown decoding of instruction");
2153
2154 bytes[0] = c;
2155 // And a fix nibble
2156 ++codes;
2157 bytes[0] |= *codes++;
2158
2159 if ( *codes == 0x01) // An I bit
2160 {
2161
2162 }
2163 if ( *codes == 0x02) // An I bit
2164 {
2165
2166 }
2167 ++codes;
2168 }
2169 out (offset, segment, bytes, OUT_RAWDATA+4, NO_SEG, NO_SEG);
2170}
2171
2172*)
2173{$endif dummy}
2174
2175begin
2176 cai_align:=tai_align;
2177end.
2178