/compiler/avr/raavrgas.pas

https://github.com/slibre/freepascal · Pascal · 693 lines · 539 code · 54 blank · 100 comment · 61 complexity · af8107339f9c454558ee84ae7c44b7fe MD5 · raw file

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