/compiler/avr/raavrgas.pas
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.