2
Copyright (c) 1998-2002 by Carl Eric Codere and Peter Vreman
4
Does the parsing for the PowerPC GNU AS styled inline assembler.
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.
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.
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.
20
****************************************************************************
32
tppcattreader = class(tattreader)
33
function is_asmopcode(const s: string):boolean;override;
34
procedure handleopcode;override;
35
procedure BuildReference(oper : tppcoperand);
36
procedure BuildOperand(oper : tppcoperand);
37
procedure BuildOpCode(instr : tppcinstruction);
38
procedure ReadAt(oper : tppcoperand);
39
procedure ReadSym(oper : tppcoperand);
40
procedure ConvertCalljmp(instr : tppcinstruction);
53
cpubase,aasmbase,aasmtai,aasmdata,aasmcpu,
62
procedure tppcattreader.ReadSym(oper : tppcoperand);
64
tempstr, mangledname : string;
67
tempstr:=actasmpattern;
70
if (actasmtoken=AS_LPAREN) and
71
SearchType(tempstr,typesize) then
77
if oper.opr.typ in [OPR_REFERENCE,OPR_LOCAL] then
78
oper.SetSize(typesize,true);
81
if not oper.SetupVar(tempstr,false) then
82
Message1(sym_e_unknown_id,tempstr);
84
if actasmtoken=AS_DOT then
86
BuildRecordOffsetSize(tempstr,l,k,mangledname,false);
87
if (mangledname<>'') then
88
Message(asmr_e_invalid_reference_syntax);
89
inc(oper.opr.ref.offset,l);
94
procedure tppcattreader.ReadAt(oper : tppcoperand);
97
if actasmtoken=AS_AT then
99
if (oper.opr.ref.symbol=nil) and
100
(oper.opr.ref.offset = 0) then
101
Message(asmr_e_invalid_reference_syntax);
103
if actasmtoken=AS_ID then
105
if upper(actasmpattern)='L' then
106
oper.opr.ref.refaddr:=addr_lo
107
else if upper(actasmpattern)='HA' then
108
oper.opr.ref.refaddr:=addr_hi
110
Message(asmr_e_invalid_reference_syntax);
114
Message(asmr_e_invalid_reference_syntax);
119
Procedure tppcattreader.BuildReference(oper : tppcoperand);
121
procedure Consume_RParen;
123
if actasmtoken <> AS_RPAREN then
125
Message(asmr_e_invalid_reference_syntax);
126
RecoverConsume(true);
131
if not (actasmtoken in [AS_COMMA,AS_SEPARATOR,AS_END]) then
133
Message(asmr_e_invalid_reference_syntax);
134
RecoverConsume(true);
149
{ offset(offset) is invalid }
150
If oper.opr.Ref.Offset <> 0 Then
152
Message(asmr_e_invalid_reference_syntax);
153
RecoverConsume(true);
157
oper.opr.Ref.Offset:=BuildConstExpression(false,true);
159
if actasmtoken=AS_AT then
164
AS_REGISTER: { (reg ... }
166
if ((oper.opr.typ=OPR_REFERENCE) and (oper.opr.ref.base<>NR_NO)) or
167
((oper.opr.typ=OPR_LOCAL) and (oper.opr.localsym.localloc.loc<>LOC_REGISTER)) then
168
message(asmr_e_cannot_index_relative_var);
169
oper.opr.ref.base:=actasmregister;
170
Consume(AS_REGISTER);
171
{ can either be a register or a right parenthesis }
173
if actasmtoken=AS_RPAREN then
180
if (actasmtoken=AS_REGISTER) and
181
(oper.opr.Ref.Offset = 0) then
183
oper.opr.ref.index:=actasmregister;
184
Consume(AS_REGISTER);
189
Message(asmr_e_invalid_reference_syntax);
190
RecoverConsume(false);
196
{ add a constant expression? }
197
if (actasmtoken=AS_PLUS) then
199
l:=BuildConstExpression(true,true);
204
inc(oper.opr.localsymofs,l);
206
inc(oper.opr.ref.offset,l);
208
internalerror(200309202);
212
if actasmtoken=AS_AT then
215
AS_COMMA: { (, ... can either be scaling, or index }
219
if (actasmtoken=AS_REGISTER) then
221
oper.opr.ref.index:=actasmregister;
222
Consume(AS_REGISTER);
223
{ check for scaling ... }
228
Message(asmr_e_invalid_reference_syntax);
229
RecoverConsume(false);
234
Message(asmr_e_invalid_reference_syntax);
235
RecoverConsume(false);
241
Procedure tppcattreader.BuildOperand(oper : tppcoperand);
247
procedure AddLabelOperand(hl:tasmlabel);
249
if not(actasmtoken in [AS_PLUS,AS_MINUS,AS_LPAREN]) and
250
is_calljmp(actopcode) then
252
oper.opr.typ:=OPR_SYMBOL;
258
oper.opr.ref.symbol:=hl;
263
procedure MaybeRecordOffset;
271
if not(actasmtoken in [AS_DOT,AS_PLUS,AS_MINUS]) then
274
hasdot:=(actasmtoken=AS_DOT);
279
BuildRecordOffsetSize(expr,toffset,tsize,mangledname,false);
280
if (oper.opr.typ<>OPR_CONSTANT) and
281
(mangledname<>'') then
282
Message(asmr_e_wrong_sym_type);
284
oper.SetSize(tsize,true);
287
if actasmtoken in [AS_PLUS,AS_MINUS] then
288
inc(l,BuildConstExpression(true,false));
292
{ don't allow direct access to fields of parameters, because that
293
will generate buggy code. Allow it only for explicit typecasting }
295
(not oper.hastype) and
296
(tabstractvarsym(oper.opr.localsym).owner.symtabletype=parasymtable) and
297
(current_procinfo.procdef.proccalloption<>pocall_register) then
298
Message(asmr_e_cannot_access_field_directly_for_parameters);
299
inc(oper.opr.localsymofs,l)
302
if (mangledname<>'') then
304
if (oper.opr.val<>0) then
305
Message(asmr_e_wrong_sym_type);
306
oper.opr.typ:=OPR_SYMBOL;
307
oper.opr.symbol:=current_asmdata.RefAsmSymbol(mangledname);
312
inc(oper.opr.ref.offset,l);
314
Message(asmr_e_invalid_symbol_ref);
316
internalerror(200309221);
321
function MaybeBuildReference:boolean;
322
{ Try to create a reference, if not a reference is found then false
325
MaybeBuildReference:=true;
331
oper.opr.ref.offset:=BuildConstExpression(True,False);
332
if actasmtoken<>AS_LPAREN then
333
Message(asmr_e_invalid_reference_syntax)
335
BuildReference(oper);
338
BuildReference(oper);
339
AS_ID: { only a variable is allowed ... }
347
BuildReference(oper);
350
Message(asmr_e_invalid_reference_syntax);
351
Consume(actasmtoken);
356
MaybeBuildReference:=false;
368
AS_LPAREN: { Memory reference or constant expression }
371
BuildReference(oper);
378
{ Constant memory offset }
379
{ This must absolutely be followed by ( }
381
oper.opr.ref.offset:=BuildConstExpression(True,False);
382
if actasmtoken<>AS_LPAREN then
384
ofs:=oper.opr.ref.offset;
385
BuildConstantOperand(oper);
386
inc(oper.opr.val,ofs);
389
BuildReference(oper);
392
AS_ID: { A constant expression, or a Variable ref. }
395
if is_locallabel(actasmpattern) then
397
CreateLocalLabel(actasmpattern,hl,false);
403
if SearchLabel(actasmpattern,hl,false) then
409
{ probably a variable or normal expression }
410
{ or a procedure (such as in CALL ID) }
412
{ is it a constant ? }
413
if SearchIConstant(actasmpattern,l) then
415
if not (oper.opr.typ in [OPR_NONE,OPR_CONSTANT]) then
416
Message(asmr_e_invalid_operand_type);
417
BuildConstantOperand(oper);
424
if (actasmtoken=AS_LPAREN) and
425
SearchType(expr,typesize) then
431
if oper.opr.typ in [OPR_REFERENCE,OPR_LOCAL] then
432
oper.SetSize(typesize,true);
436
if oper.SetupVar(expr,false) then
440
{ look for special symbols ... }
441
if expr= '__HIGH' then
444
if not oper.setupvar('high'+actasmpattern,false) then
445
Message1(sym_e_unknown_id,'high'+actasmpattern);
450
if expr = '__RESULT' then
453
if expr = '__SELF' then
456
if expr = '__OLDEBP' then
459
Message1(sym_e_unknown_id,expr);
463
if actasmtoken=AS_DOT then
465
{ add a constant expression? }
466
if (actasmtoken=AS_PLUS) then
468
l:=BuildConstExpression(true,false);
473
inc(oper.opr.localsymofs,l);
475
inc(oper.opr.ref.offset,l);
477
internalerror(200309202);
481
{ Do we have a indexing reference, then parse it also }
482
if actasmtoken=AS_LPAREN then
483
BuildReference(oper);
486
AS_REGISTER: { Register, a variable reference or a constant reference }
488
{ save the type of register used. }
489
tempreg:=actasmregister;
490
Consume(AS_REGISTER);
491
if (actasmtoken in [AS_END,AS_SEPARATOR,AS_COMMA]) then
492
if is_condreg(tempreg) and
493
((actopcode = A_BC) or
494
(actopcode = A_BCCTR) or
495
(actopcode = A_BCLR) or
496
(actopcode = A_TW) or
497
(actopcode = A_TWI)) then
499
{ it isn't a real operand, everything is stored in the condition }
500
oper.opr.typ:=OPR_NONE;
501
actcondition.cr := getsupreg(tempreg);
505
if not (oper.opr.typ in [OPR_NONE,OPR_REGISTER]) then
506
Message(asmr_e_invalid_operand_type);
507
oper.opr.typ:=OPR_REGISTER;
508
oper.opr.reg:=tempreg;
510
else if is_condreg(tempreg) then
512
if not(actcondition.cond in [C_T..C_DZF]) then
513
Message(asmr_e_syn_operand);
514
if actasmtoken=AS_STAR then
517
if (actasmtoken=AS_INTNUM) then
520
if actasmtoken=AS_PLUS then
523
if (actasmtoken=AS_ID) then
525
oper.opr.typ:=OPR_NONE;
526
if actasmpattern='LT' then
527
actcondition.crbit:=(getsupreg(tempreg)-(RS_CR0))*4
528
else if actasmpattern='GT' then
529
actcondition.crbit:=(getsupreg(tempreg)-(RS_CR0))*4+1
530
else if actasmpattern='EQ' then
531
actcondition.crbit:=(getsupreg(tempreg)-(RS_CR0))*4+2
532
else if actasmpattern='SO' then
533
actcondition.crbit:=(getsupreg(tempreg)-(RS_CR0))*4+3
535
Message(asmr_e_syn_operand);
539
Message(asmr_e_syn_operand);
542
Message(asmr_e_syn_operand);
545
Message(asmr_e_syn_operand);
548
Message(asmr_e_syn_operand);
551
Message(asmr_e_syn_operand);
558
Message(asmr_e_syn_operand);
559
Consume(actasmtoken);
565
{*****************************************************************************
567
*****************************************************************************}
569
procedure tppcattreader.BuildOpCode(instr : tppcinstruction);
571
operandnum : longint;
574
if (actasmtoken<>AS_OPCODE) then
576
Message(asmr_e_invalid_or_missing_opcode);
577
RecoverConsume(true);
580
{ Fill the instr object with the current state }
584
condition:=ActCondition;
587
{ We are reading operands, so opcode will be an AS_ID }
590
{ Zero operand opcode ? }
591
if actasmtoken in [AS_SEPARATOR,AS_END] then
596
{ Read the operands }
599
AS_COMMA: { Operand delimiter }
601
if operandnum>Max_Operands then
602
Message(asmr_e_too_many_operands)
605
{ condition operands doesn't set the operand but write to the
606
condition field of the instruction
608
if instr.Operands[operandnum].opr.typ<>OPR_NONE then
614
AS_END : { End of asm operands for this opcode }
619
BuildOperand(instr.Operands[operandnum] as tppcoperand);
622
if (operandnum=1) and (instr.Operands[operandnum].opr.typ=OPR_NONE) then
624
instr.Ops:=operandnum;
628
function tppcattreader.is_asmopcode(const s: string):boolean;
634
{ making s a value parameter would break other assembler readers }
641
fillchar(actcondition,sizeof(actcondition),0);
643
{ check for direction hint }
644
if hs[length(s)]='-' then
647
actcondition.dirhint:=DH_Minus;
649
else if hs[length(s)]='+' then
652
actcondition.dirhint:=DH_Plus;
654
actopcode := tasmop(ptrint(iasmops.find(hs)));
655
if actopcode <> A_NONE then
657
if actcondition.dirhint<>DH_None then
658
message1(asmr_e_unknown_opcode,actasmpattern);
659
actasmtoken:=AS_OPCODE;
663
{ not found, check branch instructions }
666
{ we can search here without an extra table which is sorted by string length
667
because we take the whole remaining string without the leading B }
668
if copy(hs,length(s)-1,2)='LR' then
671
setlength(hs,length(hs)-2)
673
else if copy(hs,length(s)-2,3)='CTR' then
675
actopcode := A_BCCTR;
676
setlength(hs,length(hs)-3)
680
for cond:=low(TAsmCondFlag) to high(TAsmCondFlag) do
681
if copy(hs,2,length(s)-1)=UpperAsmCondFlag2Str[cond] then
683
actcondition.simple:=true;
684
actcondition.cond:=cond;
685
if (cond in [C_LT,C_LE,C_EQ,C_GE,C_GT,C_NL,C_NE,C_NG,C_SO,C_NS,C_UN,C_NU]) then
686
actcondition.cr := RS_CR0;
687
actasmtoken:=AS_OPCODE;
694
procedure tppcattreader.ConvertCalljmp(instr : tppcinstruction);
696
if instr.Operands[1].opr.typ = OPR_CONSTANT then
698
if (instr.operands[1].opr.val > 31) or
699
(instr.operands[2].opr.typ <> OPR_CONSTANT) or
700
(instr.operands[2].opr.val > 31) or
701
not(instr.operands[3].opr.typ in [OPR_REFERENCE,OPR_SYMBOL]) then
702
Message(asmr_e_syn_operand);
704
instr.condition.simple := false;
705
instr.condition.bo := instr.operands[1].opr.val;
706
instr.condition.bi := instr.operands[2].opr.val;
707
instr.operands[1].free;
708
instr.operands[2].free;
709
instr.operands[2] := nil;
710
instr.operands[1] := instr.operands[3];
711
instr.operands[3] := nil;
714
if instr.Operands[1].opr.typ = OPR_REFERENCE then
716
instr.Operands[1].opr.ref.refaddr:=addr_full;
717
if (instr.Operands[1].opr.ref.base<>NR_NO) or
718
(instr.Operands[1].opr.ref.index<>NR_NO) then
719
Message(asmr_e_syn_operand);
724
procedure tppcattreader.handleopcode;
726
instr : tppcinstruction;
728
instr:=TPPCInstruction.Create(TPPCOperand);
730
instr.condition := actcondition;
731
if is_calljmp(instr.opcode) then
732
ConvertCalljmp(instr);
734
instr.AddReferenceSizes;
735
instr.SetInstructionOpsize;
736
instr.CheckOperandSizes;
738
instr.ConcatInstruction(curlist);
743
{*****************************************************************************
745
*****************************************************************************}
748
asmmode_ppc_att_info : tasmmodeinfo =
750
id : asmmode_ppc_gas;
752
casmreader : tppcattreader;
755
asmmode_ppc_standard_info : tasmmodeinfo =
757
id : asmmode_standard;
759
casmreader : tppcattreader;
763
RegisterAsmMode(asmmode_ppc_att_info);
764
RegisterAsmMode(asmmode_ppc_standard_info);