PageRenderTime 11ms CodeModel.GetById 6ms app.highlight 2ms RepoModel.GetById 0ms app.codeStats 0ms

/compiler/avr/raavrgas.pas

https://github.com/slibre/freepascal
Pascal | 693 lines | 539 code | 54 blank | 100 comment | 61 complexity | af8107339f9c454558ee84ae7c44b7fe MD5 | raw file
Possible License(s): LGPL-2.0, LGPL-2.1, LGPL-3.0
  1{
  2    Copyright (c) 1998-2008 by Carl Eric Codere and Peter Vreman
  3
  4    Does the parsing for the ARM GNU AS styled inline assembler.
  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 raavrgas;
 23
 24{$i fpcdefs.inc}
 25
 26  Interface
 27
 28    uses
 29      raatt,raavr,
 30      cpubase;
 31
 32    type
 33      tavrattreader = class(tattreader)
 34        function is_asmopcode(const s: string):boolean;override;
 35        function is_register(const s:string):boolean;override;
 36        procedure handleopcode;override;
 37        procedure BuildReference(oper : tavroperand);
 38        procedure BuildOperand(oper : tavroperand);
 39        procedure BuildOpCode(instr : tavrinstruction);
 40        procedure ReadSym(oper : tavroperand);
 41        procedure ConvertCalljmp(instr : tavrinstruction);
 42      end;
 43
 44
 45  Implementation
 46
 47    uses
 48      { helpers }
 49      cutils,
 50      { global }
 51      globtype,globals,verbose,
 52      systems,
 53      { aasm }
 54      cpuinfo,aasmbase,aasmtai,aasmdata,aasmcpu,
 55      { symtable }
 56      symconst,symbase,symtype,symsym,symtable,
 57      { parser }
 58      scanner,
 59      procinfo,
 60      itcpugas,
 61      rabase,rautils,
 62      cgbase,cgutils,cgobj
 63      ;
 64
 65
 66    function tavrattreader.is_register(const s:string):boolean;
 67      type
 68        treg2str = record
 69          name : string[2];
 70          reg : tregister;
 71        end;
 72{
 73      const
 74        extraregs : array[0..19] of treg2str = (
 75          (name: 'X'; reg : NR_Z),
 76          (name: 'Y'; reg : NR_R1),
 77          (name: 'Z'; reg : NR_R2),
 78        );
 79}
 80      var
 81        i : longint;
 82
 83      begin
 84        result:=inherited is_register(s);
 85        { reg found?
 86          possible aliases are always 2 char
 87        }
 88        if result or (length(s)<>2) then
 89          exit;
 90{
 91        for i:=low(extraregs) to high(extraregs) do
 92          begin
 93            if s=extraregs[i].name then
 94              begin
 95                actasmregister:=extraregs[i].reg;
 96                result:=true;
 97                actasmtoken:=AS_REGISTER;
 98                exit;
 99              end;
100          end;
101}
102      end;
103
104
105    procedure tavrattreader.ReadSym(oper : tavroperand);
106      var
107        tempstr, mangledname : string;
108        typesize,l,k : aint;
109      begin
110        tempstr:=actasmpattern;
111        Consume(AS_ID);
112        { typecasting? }
113        if (actasmtoken=AS_LPAREN) and
114           SearchType(tempstr,typesize) then
115         begin
116           oper.hastype:=true;
117           Consume(AS_LPAREN);
118           BuildOperand(oper);
119           Consume(AS_RPAREN);
120           if oper.opr.typ in [OPR_REFERENCE,OPR_LOCAL] then
121             oper.SetSize(typesize,true);
122         end
123        else
124         if not oper.SetupVar(tempstr,false) then
125          Message1(sym_e_unknown_id,tempstr);
126        { record.field ? }
127        if actasmtoken=AS_DOT then
128         begin
129           BuildRecordOffsetSize(tempstr,l,k,mangledname,false);
130           if (mangledname<>'') then
131             Message(asmr_e_invalid_reference_syntax);
132           inc(oper.opr.ref.offset,l);
133         end;
134      end;
135
136
137    Procedure tavrattreader.BuildReference(oper : tavroperand);
138
139      procedure Consume_RParen;
140        begin
141          if actasmtoken<>AS_RPAREN then
142           Begin
143             Message(asmr_e_invalid_reference_syntax);
144             RecoverConsume(true);
145           end
146          else
147           begin
148             Consume(AS_RPAREN);
149             if not (actasmtoken in [AS_COMMA,AS_SEPARATOR,AS_END]) then
150              Begin
151                Message(asmr_e_invalid_reference_syntax);
152                RecoverConsume(true);
153              end;
154           end;
155        end;
156
157
158      procedure read_index;
159        begin
160          Consume(AS_COMMA);
161          if actasmtoken=AS_REGISTER then
162            Begin
163              oper.opr.ref.index:=actasmregister;
164              Consume(AS_REGISTER);
165            end
166          else if actasmtoken=AS_HASH then
167            begin
168              Consume(AS_HASH);
169              inc(oper.opr.ref.offset,BuildConstExpression(false,true));
170            end;
171        end;
172
173
174      begin
175        Consume(AS_LPAREN);
176        if actasmtoken=AS_REGISTER then
177          begin
178            oper.opr.ref.base:=actasmregister;
179            Consume(AS_REGISTER);
180            { can either be a register or a right parenthesis }
181            { (reg)        }
182            if actasmtoken=AS_LPAREN then
183             Begin
184               Consume_RParen;
185               exit;
186             end;
187            if actasmtoken=AS_PLUS then
188              begin
189                consume(AS_PLUS);
190                oper.opr.ref.addressmode:=AM_POSTINCREMENT;
191              end;
192          end {end case }
193        else
194          Begin
195            Message(asmr_e_invalid_reference_syntax);
196            RecoverConsume(false);
197          end;
198      end;
199
200
201    Procedure tavrattreader.BuildOperand(oper : tavroperand);
202      var
203        expr : string;
204        typesize,l : aint;
205
206
207        procedure AddLabelOperand(hl:tasmlabel);
208          begin
209            if not(actasmtoken in [AS_PLUS,AS_MINUS,AS_LPAREN]) { and
210               is_calljmp(actopcode) } then
211             begin
212               oper.opr.typ:=OPR_SYMBOL;
213               oper.opr.symbol:=hl;
214             end
215            else
216             begin
217               oper.InitRef;
218               oper.opr.ref.symbol:=hl;
219             end;
220          end;
221
222
223        procedure MaybeRecordOffset;
224          var
225            mangledname: string;
226            hasdot  : boolean;
227            l,
228            toffset,
229            tsize   : aint;
230          begin
231            if not(actasmtoken in [AS_DOT,AS_PLUS,AS_MINUS]) then
232             exit;
233            l:=0;
234            hasdot:=(actasmtoken=AS_DOT);
235            if hasdot then
236              begin
237                if expr<>'' then
238                  begin
239                    BuildRecordOffsetSize(expr,toffset,tsize,mangledname,false);
240                    if (oper.opr.typ<>OPR_CONSTANT) and
241                       (mangledname<>'') then
242                      Message(asmr_e_wrong_sym_type);
243                    inc(l,toffset);
244                    oper.SetSize(tsize,true);
245                  end;
246              end;
247            if actasmtoken in [AS_PLUS,AS_MINUS] then
248              inc(l,BuildConstExpression(true,false));
249            case oper.opr.typ of
250              OPR_LOCAL :
251                begin
252                  { don't allow direct access to fields of parameters, because that
253                    will generate buggy code. Allow it only for explicit typecasting }
254                  if hasdot and
255                     (not oper.hastype) and
256                     (tabstractnormalvarsym(oper.opr.localsym).owner.symtabletype=parasymtable) and
257                     (current_procinfo.procdef.proccalloption<>pocall_register) then
258                    Message(asmr_e_cannot_access_field_directly_for_parameters);
259                  inc(oper.opr.localsymofs,l)
260                end;
261              OPR_CONSTANT :
262                inc(oper.opr.val,l);
263              OPR_REFERENCE :
264                if (mangledname<>'') then
265                  begin
266                    if (oper.opr.val<>0) then
267                      Message(asmr_e_wrong_sym_type);
268                    oper.opr.typ:=OPR_SYMBOL;
269                    oper.opr.symbol:=current_asmdata.RefAsmSymbol(mangledname);
270                  end
271                else
272                  inc(oper.opr.val,l);
273              OPR_SYMBOL:
274                Message(asmr_e_invalid_symbol_ref);
275              else
276                internalerror(200309221);
277            end;
278          end;
279
280
281        function MaybeBuildReference:boolean;
282          { Try to create a reference, if not a reference is found then false
283            is returned }
284          begin
285            MaybeBuildReference:=true;
286            case actasmtoken of
287              AS_INTNUM,
288              AS_MINUS,
289              AS_PLUS:
290                Begin
291                  oper.opr.ref.offset:=BuildConstExpression(True,False);
292                  if actasmtoken<>AS_LPAREN then
293                    Message(asmr_e_invalid_reference_syntax)
294                  else
295                    BuildReference(oper);
296                end;
297              AS_LPAREN:
298                BuildReference(oper);
299              AS_ID: { only a variable is allowed ... }
300                Begin
301                  ReadSym(oper);
302                  case actasmtoken of
303                    AS_END,
304                    AS_SEPARATOR,
305                    AS_COMMA: ;
306                    AS_LPAREN:
307                      BuildReference(oper);
308                  else
309                    Begin
310                      Message(asmr_e_invalid_reference_syntax);
311                      Consume(actasmtoken);
312                    end;
313                  end; {end case }
314                end;
315              else
316               MaybeBuildReference:=false;
317            end; { end case }
318          end;
319
320
321      var
322        tempreg : tregister;
323        ireg : tsuperregister;
324        hl : tasmlabel;
325        ofs : longint;
326        registerset : tcpuregisterset;
327        tempstr : string;
328        tempsymtyp : tasmsymtype;
329      Begin
330        expr:='';
331        case actasmtoken of
332          AS_LBRACKET: { Memory reference or constant expression }
333            Begin
334              oper.InitRef;
335              BuildReference(oper);
336            end;
337
338          AS_INTNUM,
339          AS_MINUS,
340          AS_PLUS:
341            Begin
342              { Constant memory offset }
343              { This must absolutely be followed by (  }
344              oper.InitRef;
345              oper.opr.ref.offset:=BuildConstExpression(True,False);
346
347              { absolute memory addresss? }
348              if actopcode in [A_LDS,A_STS] then
349                BuildReference(oper)
350              else
351                begin
352                  ofs:=oper.opr.ref.offset;
353                  BuildConstantOperand(oper);
354                  inc(oper.opr.val,ofs);
355                end;
356            end;
357
358          AS_ID: { A constant expression, or a Variable ref.  }
359            Begin
360              if (actasmpattern='LO8') or (actasmpattern='HI8') then
361                begin
362                  { Low or High part of a constant (or constant
363                    memory location) }
364                  oper.InitRef;
365                  if actasmpattern='LO8' then
366                    oper.opr.ref.refaddr:=addr_lo8
367                  else
368                    oper.opr.ref.refaddr:=addr_hi8;
369                  Consume(actasmtoken);
370                  Consume(AS_LPAREN);
371                  BuildConstSymbolExpression(false, true,false,l,tempstr,tempsymtyp);
372                  if not assigned(oper.opr.ref.symbol) then
373                    oper.opr.ref.symbol:=current_asmdata.RefAsmSymbol(tempstr)
374                  else
375                    Message(asmr_e_cant_have_multiple_relocatable_symbols);
376                  case oper.opr.typ of
377                    OPR_CONSTANT :
378                      inc(oper.opr.val,l);
379                    OPR_LOCAL :
380                      inc(oper.opr.localsymofs,l);
381                    OPR_REFERENCE :
382                      inc(oper.opr.ref.offset,l);
383                    else
384                      internalerror(200309202);
385                  end;
386                  Consume(AS_RPAREN);
387                end
388              { Local Label ? }
389              else if is_locallabel(actasmpattern) then
390               begin
391                 CreateLocalLabel(actasmpattern,hl,false);
392                 Consume(AS_ID);
393                 AddLabelOperand(hl);
394               end
395              { Check for label }
396              else if SearchLabel(actasmpattern,hl,false) then
397                begin
398                  Consume(AS_ID);
399                  AddLabelOperand(hl);
400                end
401              else
402               { probably a variable or normal expression }
403               { or a procedure (such as in CALL ID)      }
404               Begin
405                 { is it a constant ? }
406                 if SearchIConstant(actasmpattern,l) then
407                  Begin
408                    if not (oper.opr.typ in [OPR_NONE,OPR_CONSTANT]) then
409                     Message(asmr_e_invalid_operand_type);
410                    BuildConstantOperand(oper);
411                  end
412                 else
413                  begin
414                    expr:=actasmpattern;
415                    Consume(AS_ID);
416                    { typecasting? }
417                    if (actasmtoken=AS_LPAREN) and
418                       SearchType(expr,typesize) then
419                     begin
420                       oper.hastype:=true;
421                       Consume(AS_LPAREN);
422                       BuildOperand(oper);
423                       Consume(AS_RPAREN);
424                       if oper.opr.typ in [OPR_REFERENCE,OPR_LOCAL] then
425                         oper.SetSize(typesize,true);
426                     end
427                    else
428                     begin
429                       if not(oper.SetupVar(expr,false)) then
430                        Begin
431                          { look for special symbols ... }
432                          if expr= '__HIGH' then
433                            begin
434                              consume(AS_LPAREN);
435                              if not oper.setupvar('high'+actasmpattern,false) then
436                                Message1(sym_e_unknown_id,'high'+actasmpattern);
437                              consume(AS_ID);
438                              consume(AS_RPAREN);
439                            end
440                          else
441                           if expr = '__RESULT' then
442                            oper.SetUpResult
443                          else
444                           if expr = '__SELF' then
445                            oper.SetupSelf
446                          else
447                           if expr = '__OLDEBP' then
448                            oper.SetupOldEBP
449                          else
450                            Message1(sym_e_unknown_id,expr);
451                        end;
452                     end;
453                  end;
454                  if actasmtoken=AS_DOT then
455                    MaybeRecordOffset;
456                  { add a constant expression? }
457                  if (actasmtoken=AS_PLUS) then
458                   begin
459                     l:=BuildConstExpression(true,false);
460                     case oper.opr.typ of
461                       OPR_CONSTANT :
462                         inc(oper.opr.val,l);
463                       OPR_LOCAL :
464                         inc(oper.opr.localsymofs,l);
465                       OPR_REFERENCE :
466                         inc(oper.opr.ref.offset,l);
467                       else
468                         internalerror(200309202);
469                     end;
470                   end
471               end;
472              { Do we have a indexing reference, then parse it also }
473              if actasmtoken=AS_LPAREN then
474                BuildReference(oper);
475            end;
476
477          { Register, a variable reference or a constant reference  }
478          AS_REGISTER:
479            Begin
480              { save the type of register used. }
481              tempreg:=actasmregister;
482              Consume(AS_REGISTER);
483              if (actasmtoken in [AS_END,AS_SEPARATOR,AS_COMMA]) then
484                Begin
485                  if not (oper.opr.typ in [OPR_NONE,OPR_REGISTER]) then
486                    Message(asmr_e_invalid_operand_type);
487                  oper.opr.typ:=OPR_REGISTER;
488                  oper.opr.reg:=tempreg;
489                end
490              else
491                Message(asmr_e_syn_operand);
492            end;
493
494          AS_END,
495          AS_SEPARATOR,
496          AS_COMMA: ;
497        else
498          Begin
499            Message(asmr_e_syn_operand);
500            Consume(actasmtoken);
501          end;
502        end; { end case }
503      end;
504
505
506{*****************************************************************************
507                                tavrattreader
508*****************************************************************************}
509
510    procedure tavrattreader.BuildOpCode(instr : tavrinstruction);
511      var
512        operandnum : longint;
513      Begin
514        { opcode }
515        if (actasmtoken<>AS_OPCODE) then
516         Begin
517           Message(asmr_e_invalid_or_missing_opcode);
518           RecoverConsume(true);
519           exit;
520         end;
521        { Fill the instr object with the current state }
522        with instr do
523          begin
524            Opcode:=ActOpcode;
525            condition:=ActCondition;
526          end;
527
528        { We are reading operands, so opcode will be an AS_ID }
529        operandnum:=1;
530        Consume(AS_OPCODE);
531        { Zero operand opcode ?  }
532        if actasmtoken in [AS_SEPARATOR,AS_END] then
533         begin
534           operandnum:=0;
535           exit;
536         end;
537        { Read the operands }
538        repeat
539          case actasmtoken of
540            AS_COMMA: { Operand delimiter }
541              Begin
542                if operandnum>Max_Operands then
543                  Message(asmr_e_too_many_operands)
544                else
545                  Inc(operandnum);
546                Consume(AS_COMMA);
547              end;
548            AS_SEPARATOR,
549            AS_END : { End of asm operands for this opcode  }
550              begin
551                break;
552              end;
553          else
554            BuildOperand(instr.Operands[operandnum] as tavroperand);
555          end; { end case }
556        until false;
557        instr.Ops:=operandnum;
558      end;
559
560
561    function tavrattreader.is_asmopcode(const s: string):boolean;
562
563      const
564        { sorted by length so longer postfixes will match first }
565        postfix2strsorted : array[1..19] of string[2] = (
566          'EP','SB','BT','SH',
567          'IA','IB','DA','DB','FD','FA','ED','EA',
568          'B','D','E','P','T','H','S');
569
570      var
571        len,
572        j,
573        sufidx : longint;
574        hs : string;
575        maxlen : longint;
576        icond : tasmcond;
577      Begin
578        { making s a value parameter would break other assembler readers }
579        hs:=s;
580        is_asmopcode:=false;
581
582        { clear op code }
583        actopcode:=A_None;
584
585        actcondition:=C_None;
586
587        { first, handle B else BLS is read wrong }
588        if ((copy(hs,1,2)='BR') and (length(hs)=4)) then
589          begin
590            for icond:=low(tasmcond) to high(tasmcond) do
591              begin
592                if copy(hs,2,3)=uppercond2str[icond] then
593                  begin
594                    actopcode:=A_BRxx;
595                    actasmtoken:=AS_OPCODE;
596                    actcondition:=icond;
597                    is_asmopcode:=true;
598                    exit;
599                  end;
600              end;
601          end;
602        maxlen:=max(length(hs),5);
603        actopcode:=A_NONE;
604        for j:=maxlen downto 1 do
605          begin
606            actopcode:=tasmop(PtrInt(iasmops.Find(copy(hs,1,j))));
607            if actopcode<>A_NONE then
608              begin
609                actasmtoken:=AS_OPCODE;
610                { strip op code }
611                delete(hs,1,j);
612                break;
613              end;
614          end;
615        if actopcode=A_NONE then
616          exit;
617        { search for condition, conditions are always 2 chars }
618        if length(hs)>1 then
619          begin
620            for icond:=low(tasmcond) to high(tasmcond) do
621              begin
622                if copy(hs,1,2)=uppercond2str[icond] then
623                  begin
624                    actcondition:=icond;
625                    { strip condition }
626                    delete(hs,1,2);
627                    break;
628                  end;
629              end;
630          end;
631        { if we stripped all postfixes, it's a valid opcode }
632        is_asmopcode:=length(hs)=0;
633      end;
634
635
636    procedure tavrattreader.ConvertCalljmp(instr : tavrinstruction);
637      var
638        newopr : toprrec;
639      begin
640        if instr.Operands[1].opr.typ=OPR_REFERENCE then
641          begin
642            newopr.typ:=OPR_SYMBOL;
643            newopr.symbol:=instr.Operands[1].opr.ref.symbol;
644            newopr.symofs:=instr.Operands[1].opr.ref.offset;
645            if (instr.Operands[1].opr.ref.base<>NR_NO) or
646              (instr.Operands[1].opr.ref.index<>NR_NO) then
647              Message(asmr_e_syn_operand);
648            instr.Operands[1].opr:=newopr;
649          end;
650      end;
651
652
653    procedure tavrattreader.handleopcode;
654      var
655        instr : tavrinstruction;
656      begin
657        instr:=tavrinstruction.Create(tavroperand);
658        BuildOpcode(instr);
659{        if is_calljmp(instr.opcode) then
660          ConvertCalljmp(instr); }
661        {
662        instr.AddReferenceSizes;
663        instr.SetInstructionOpsize;
664        instr.CheckOperandSizes;
665        }
666        instr.ConcatInstruction(curlist);
667        instr.Free;
668      end;
669
670
671{*****************************************************************************
672                                     Initialize
673*****************************************************************************}
674
675const
676  asmmode_avr_att_info : tasmmodeinfo =
677          (
678            id    : asmmode_avr_gas;
679            idtxt : 'GAS';
680            casmreader : tavrattreader;
681          );
682
683  asmmode_avr_standard_info : tasmmodeinfo =
684          (
685            id    : asmmode_standard;
686            idtxt : 'STANDARD';
687            casmreader : tavrattreader;
688          );
689
690initialization
691  RegisterAsmMode(asmmode_avr_att_info);
692  RegisterAsmMode(asmmode_avr_standard_info);
693end.