racpugas.pas 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026
  1. {
  2. Copyright (c) 1998-2002 by Carl Eric Codere and Peter Vreman
  3. Does the parsing for the Xtensa 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 racpugas;
  18. {$i fpcdefs.inc}
  19. Interface
  20. uses
  21. raatt,raxtensa,
  22. cpubase;
  23. type
  24. txtensaattreader = class(tattreader)
  25. function is_asmopcode(const s: string):boolean;override;
  26. function is_register(const s:string):boolean;override;
  27. // function is_targetdirective(const s: string): boolean; override;
  28. procedure handleopcode;override;
  29. procedure BuildReference(oper : TXtensaOperand);
  30. procedure BuildOperand(oper : TXtensaOperand);
  31. procedure BuildSpecialreg(oper : TXtensaOperand);
  32. procedure BuildOpCode(instr : TXtensaInstruction);
  33. procedure ReadSym(oper : TXtensaOperand);
  34. procedure ConvertCalljmp(instr : TXtensaInstruction);
  35. procedure HandleTargetDirective; override;
  36. end;
  37. Implementation
  38. uses
  39. { helpers }
  40. cutils,
  41. { global }
  42. globtype,globals,verbose,
  43. systems,aasmbase,aasmtai,aasmdata,aasmcpu,
  44. { symtable }
  45. symconst,symsym,symdef,
  46. procinfo,
  47. rabase,rautils,
  48. cgbase,cgutils,paramgr;
  49. function txtensaattreader.is_register(const s:string):boolean;
  50. type
  51. treg2str = record
  52. name : string[3];
  53. reg : tregister;
  54. end;
  55. const
  56. extraregs : array[0..0] of treg2str = (
  57. (name: 'A1'; reg : NR_A0)
  58. );
  59. var
  60. i : longint;
  61. begin
  62. result:=inherited is_register(s);
  63. { reg found?
  64. possible aliases are always 2 char
  65. }
  66. if result or (not (length(s) in [2,3])) then
  67. exit;
  68. for i:=low(extraregs) to high(extraregs) do
  69. begin
  70. if s=extraregs[i].name then
  71. begin
  72. actasmregister:=extraregs[i].reg;
  73. result:=true;
  74. actasmtoken:=AS_REGISTER;
  75. exit;
  76. end;
  77. end;
  78. end;
  79. procedure txtensaattreader.ReadSym(oper : TXtensaOperand);
  80. var
  81. tempstr, mangledname : string;
  82. typesize,l,k : tcgint;
  83. begin
  84. tempstr:=actasmpattern;
  85. Consume(AS_ID);
  86. { typecasting? }
  87. if (actasmtoken=AS_LPAREN) and
  88. SearchType(tempstr,typesize) then
  89. begin
  90. oper.hastype:=true;
  91. Consume(AS_LPAREN);
  92. BuildOperand(oper);
  93. Consume(AS_RPAREN);
  94. if oper.opr.typ in [OPR_REFERENCE,OPR_LOCAL] then
  95. oper.SetSize(typesize,true);
  96. end
  97. else
  98. if not oper.SetupVar(tempstr,false) then
  99. Message1(sym_e_unknown_id,tempstr);
  100. { record.field ? }
  101. if actasmtoken=AS_DOT then
  102. begin
  103. BuildRecordOffsetSize(tempstr,l,k,mangledname,false);
  104. if (mangledname<>'') then
  105. Message(asmr_e_invalid_reference_syntax);
  106. inc(oper.opr.ref.offset,l);
  107. end;
  108. end;
  109. Procedure txtensaattreader.BuildReference(oper : TXtensaOperand);
  110. procedure do_error;
  111. begin
  112. Message(asmr_e_invalid_reference_syntax);
  113. RecoverConsume(false);
  114. end;
  115. procedure test_end(require_rbracket : boolean);
  116. begin
  117. if require_rbracket then begin
  118. if not(actasmtoken=AS_RBRACKET) then
  119. begin
  120. do_error;
  121. exit;
  122. end
  123. else
  124. Consume(AS_RBRACKET);
  125. end;
  126. if not(actasmtoken in [AS_SEPARATOR,AS_end]) then
  127. do_error
  128. else
  129. begin
  130. {$IFDEF debugasmreader}
  131. writeln('TEST_end_FINAL_OK. Created the following ref:');
  132. writeln('oper.opr.ref.shiftimm=',oper.opr.ref.shiftimm);
  133. writeln('oper.opr.ref.shiftmode=',ord(oper.opr.ref.shiftmode));
  134. writeln('oper.opr.ref.index=',ord(oper.opr.ref.index));
  135. writeln('oper.opr.ref.base=',ord(oper.opr.ref.base));
  136. writeln('oper.opr.ref.signindex=',ord(oper.opr.ref.signindex));
  137. writeln('oper.opr.ref.addressmode=',ord(oper.opr.ref.addressmode));
  138. writeln;
  139. {$endIF debugasmreader}
  140. end;
  141. end;
  142. procedure read_index_shift(require_rbracket : boolean);
  143. var
  144. shift : aint;
  145. begin
  146. case actasmtoken of
  147. AS_COMMA :
  148. begin
  149. Consume(AS_COMMA);
  150. if not(actasmtoken=AS_ID) then
  151. do_error;
  152. end;
  153. AS_RBRACKET :
  154. if require_rbracket then
  155. test_end(require_rbracket)
  156. else
  157. begin
  158. do_error;
  159. exit;
  160. end;
  161. AS_SEPARATOR,AS_END :
  162. if not require_rbracket then
  163. test_end(false)
  164. else
  165. do_error;
  166. else
  167. begin
  168. do_error;
  169. exit;
  170. end;
  171. end;
  172. end;
  173. procedure read_index(require_rbracket : boolean);
  174. var
  175. recname : string;
  176. o_int,s_int : tcgint;
  177. begin
  178. case actasmtoken of
  179. AS_REGISTER :
  180. begin
  181. oper.opr.ref.index:=actasmregister;
  182. Consume(AS_REGISTER);
  183. read_index_shift(require_rbracket);
  184. exit;
  185. end;
  186. AS_PLUS,AS_MINUS :
  187. begin
  188. if actasmtoken=AS_PLUS then
  189. begin
  190. Consume(AS_PLUS);
  191. end;
  192. if actasmtoken=AS_REGISTER then
  193. begin
  194. oper.opr.ref.index:=actasmregister;
  195. Consume(AS_REGISTER);
  196. read_index_shift(require_rbracket);
  197. exit;
  198. end
  199. else
  200. begin
  201. do_error;
  202. exit;
  203. end;
  204. test_end(require_rbracket);
  205. exit;
  206. end;
  207. AS_HASH : // constant
  208. begin
  209. Consume(AS_HASH);
  210. o_int := BuildConstExpression(false,true);
  211. if (o_int>4095) or (o_int<-4095) then
  212. begin
  213. Message(asmr_e_constant_out_of_bounds);
  214. RecoverConsume(false);
  215. exit;
  216. end
  217. else
  218. begin
  219. inc(oper.opr.ref.offset,o_int);
  220. test_end(require_rbracket);
  221. exit;
  222. end;
  223. end;
  224. AS_ID :
  225. begin
  226. recname := actasmpattern;
  227. Consume(AS_ID);
  228. BuildRecordOffsetSize(recname,o_int,s_int,recname,false);
  229. if (o_int>4095)or(o_int<-4095) then
  230. begin
  231. Message(asmr_e_constant_out_of_bounds);
  232. RecoverConsume(false);
  233. exit;
  234. end
  235. else
  236. begin
  237. inc(oper.opr.ref.offset,o_int);
  238. test_end(require_rbracket);
  239. exit;
  240. end;
  241. end;
  242. AS_AT:
  243. begin
  244. do_error;
  245. exit;
  246. end;
  247. AS_DOT : // local label
  248. begin
  249. BuildConstExpression(true,false);
  250. test_end(require_rbracket);
  251. exit;
  252. end;
  253. AS_RBRACKET :
  254. begin
  255. if require_rbracket then
  256. begin
  257. test_end(require_rbracket);
  258. exit;
  259. end
  260. else
  261. begin
  262. do_error; // unexpected rbracket
  263. exit;
  264. end;
  265. end;
  266. AS_SEPARATOR,AS_end :
  267. begin
  268. if not require_rbracket then
  269. begin
  270. test_end(false);
  271. exit;
  272. end
  273. else
  274. begin
  275. do_error;
  276. exit;
  277. end;
  278. end;
  279. else
  280. begin
  281. // unexpected token
  282. do_error;
  283. exit;
  284. end;
  285. end; // case
  286. end;
  287. procedure try_prepostindexed;
  288. begin
  289. Consume(AS_RBRACKET);
  290. case actasmtoken of
  291. AS_COMMA :
  292. begin // post-indexed
  293. Consume(AS_COMMA);
  294. read_index(false);
  295. exit;
  296. end;
  297. AS_NOT :
  298. begin // pre-indexed
  299. Consume(AS_NOT);
  300. test_end(false);
  301. exit;
  302. end;
  303. else
  304. begin
  305. test_end(false);
  306. exit;
  307. end;
  308. end; // case
  309. end;
  310. var
  311. lab : TASMLABEL;
  312. begin
  313. Consume(AS_LBRACKET);
  314. if actasmtoken=AS_REGISTER then
  315. begin
  316. oper.opr.ref.base:=actasmregister;
  317. Consume(AS_REGISTER);
  318. case actasmtoken of
  319. AS_RBRACKET :
  320. begin
  321. try_prepostindexed;
  322. exit;
  323. end;
  324. AS_COMMA :
  325. begin
  326. Consume(AS_COMMA);
  327. read_index(true);
  328. exit;
  329. end;
  330. else
  331. begin
  332. Message(asmr_e_invalid_reference_syntax);
  333. RecoverConsume(false);
  334. end;
  335. end;
  336. end
  337. else
  338. {
  339. if base isn't a register, r15=PC is implied base, so it must be a local label.
  340. pascal constants don't make sense, because implied r15
  341. record offsets probably don't make sense, too (a record offset of code?)
  342. TODO: However, we could make the Stackpointer implied.
  343. }
  344. Begin
  345. case actasmtoken of
  346. AS_ID :
  347. begin
  348. // TODO: Stackpointer implied,
  349. Message(asmr_e_invalid_reference_syntax);
  350. RecoverConsume(false);
  351. exit;
  352. end;
  353. else
  354. begin
  355. Message(asmr_e_invalid_reference_syntax);
  356. RecoverConsume(false);
  357. exit;
  358. end;
  359. end;
  360. end;
  361. end;
  362. Procedure txtensaattreader.BuildOperand(oper : TXtensaOperand);
  363. var
  364. expr : string;
  365. typesize,l : tcgint;
  366. procedure AddLabelOperand(hl:tasmlabel);
  367. begin
  368. oper.opr.typ:=OPR_SYMBOL;
  369. oper.opr.symbol:=hl;
  370. end;
  371. procedure MaybeRecordOffset;
  372. var
  373. mangledname: string;
  374. hasdot : boolean;
  375. l,
  376. toffset,
  377. tsize : tcgint;
  378. begin
  379. if not(actasmtoken in [AS_DOT,AS_PLUS,AS_MINUS]) then
  380. exit;
  381. l:=0;
  382. mangledname:='';
  383. hasdot:=(actasmtoken=AS_DOT);
  384. if hasdot then
  385. begin
  386. if expr<>'' then
  387. begin
  388. BuildRecordOffsetSize(expr,toffset,tsize,mangledname,false);
  389. if (oper.opr.typ<>OPR_CONSTANT) and
  390. (mangledname<>'') then
  391. Message(asmr_e_wrong_sym_type);
  392. inc(l,toffset);
  393. oper.SetSize(tsize,true);
  394. end;
  395. end;
  396. if actasmtoken in [AS_PLUS,AS_MINUS] then
  397. inc(l,BuildConstExpression(true,false));
  398. case oper.opr.typ of
  399. OPR_LOCAL :
  400. begin
  401. { don't allow direct access to fields of parameters, because that
  402. will generate buggy code. Allow it only for explicit typecasting }
  403. if hasdot and
  404. (not oper.hastype) then
  405. checklocalsubscript(oper.opr.localsym);
  406. inc(oper.opr.localsymofs,l)
  407. end;
  408. OPR_CONSTANT :
  409. inc(oper.opr.val,l);
  410. OPR_REFERENCE :
  411. if (mangledname<>'') then
  412. begin
  413. if (oper.opr.val<>0) then
  414. Message(asmr_e_wrong_sym_type);
  415. oper.opr.typ:=OPR_SYMBOL;
  416. oper.opr.symbol:=current_asmdata.RefAsmSymbol(mangledname,AT_FUNCTION);
  417. end
  418. else
  419. inc(oper.opr.val,l);
  420. OPR_SYMBOL:
  421. Message(asmr_e_invalid_symbol_ref);
  422. else
  423. internalerror(200309221);
  424. end;
  425. end;
  426. function MaybeBuildReference:boolean;
  427. { Try to create a reference, if not a reference is found then false
  428. is returned }
  429. begin
  430. MaybeBuildReference:=true;
  431. case actasmtoken of
  432. AS_INTNUM,
  433. AS_MINUS,
  434. AS_PLUS:
  435. Begin
  436. oper.opr.ref.offset:=BuildConstExpression(True,False);
  437. if actasmtoken<>AS_LPAREN then
  438. Message(asmr_e_invalid_reference_syntax)
  439. else
  440. BuildReference(oper);
  441. end;
  442. AS_LPAREN:
  443. BuildReference(oper);
  444. AS_ID: { only a variable is allowed ... }
  445. Begin
  446. ReadSym(oper);
  447. case actasmtoken of
  448. AS_end,
  449. AS_SEPARATOR,
  450. AS_COMMA: ;
  451. AS_LPAREN:
  452. BuildReference(oper);
  453. else
  454. Begin
  455. Message(asmr_e_invalid_reference_syntax);
  456. Consume(actasmtoken);
  457. end;
  458. end; {end case }
  459. end;
  460. else
  461. MaybeBuildReference:=false;
  462. end; { end case }
  463. end;
  464. procedure BuildDirectRef;
  465. function GetConstLabel(const symname: string; ofs: aint): TAsmLabel;
  466. var
  467. hp: tai;
  468. newconst: tai_const;
  469. lab: TAsmLabel;
  470. begin
  471. if symname<>'' then
  472. newconst:=tai_const.Createname(symname,ofs)
  473. else
  474. newconst:=tai_const.Create_32bit(ofs);
  475. hp:=tai(current_procinfo.aktlocaldata.First);
  476. while assigned(hp) do
  477. begin
  478. if hp.typ=ait_const then
  479. begin
  480. if (tai_const(hp).sym=newconst.sym) and
  481. (tai_const(hp).value=newconst.value) and
  482. assigned(hp.Previous) and
  483. (tai(hp.previous).typ=ait_label) then
  484. begin
  485. newconst.Free;
  486. result:=tai_label(hp.Previous).labsym;
  487. exit;
  488. end;
  489. end;
  490. hp:=tai(hp.Next);
  491. end;
  492. current_asmdata.getjumplabel(lab);
  493. current_procinfo.aktlocaldata.concat(tai_align.create(4));
  494. current_procinfo.aktlocaldata.concat(tai_label.create(lab));
  495. current_procinfo.aktlocaldata.concat(newconst);
  496. result:=lab;
  497. end;
  498. var
  499. symtype: TAsmsymtype;
  500. sym: string;
  501. val: tcgint;
  502. begin
  503. case actasmtoken of
  504. AS_INTNUM,
  505. AS_ID:
  506. begin
  507. BuildConstSymbolExpression(true,false,false,val,sym,symtype);
  508. if symtype=AT_NONE then
  509. sym:='';
  510. reference_reset(oper.opr.ref,4,[]);
  511. oper.opr.ref.symbol:=GetConstLabel(sym,val);
  512. end;
  513. else
  514. ;
  515. end;
  516. end;
  517. function getregsetindex(reg: tregister): integer;
  518. begin
  519. if getsubreg(reg)=R_SUBFS then
  520. begin
  521. result:=getsupreg(reg)*2;
  522. if result>32 then
  523. result:=result-63;
  524. end
  525. else
  526. result:=getsupreg(reg);
  527. end;
  528. var
  529. tempreg : tregister;
  530. ireg : tsuperregister;
  531. regtype: tregistertype;
  532. subreg: tsubregister;
  533. hl : tasmlabel;
  534. {ofs : longint;}
  535. registerset : tcpuregisterset;
  536. Begin
  537. expr:='';
  538. case actasmtoken of
  539. AS_LBRACKET: { Memory reference or constant expression }
  540. Begin
  541. oper.InitRef;
  542. BuildReference(oper);
  543. end;
  544. AS_MINUS,
  545. AS_PLUS,
  546. AS_INTNUM: { Constant expression }
  547. Begin
  548. BuildConstantOperand(oper);
  549. end;
  550. AS_ID: { A constant expression, or a Variable ref. }
  551. Begin
  552. if is_locallabel(actasmpattern) then
  553. begin
  554. CreateLocalLabel(actasmpattern,hl,false);
  555. Consume(AS_ID);
  556. AddLabelOperand(hl);
  557. end
  558. else
  559. { Check for label }
  560. if SearchLabel(actasmpattern,hl,false) then
  561. begin
  562. Consume(AS_ID);
  563. AddLabelOperand(hl);
  564. end
  565. else
  566. { probably a variable or normal expression }
  567. { or a procedure (such as in CALL ID) }
  568. Begin
  569. { is it a constant ? }
  570. if SearchIConstant(actasmpattern,l) then
  571. Begin
  572. if not (oper.opr.typ in [OPR_NONE,OPR_CONSTANT]) then
  573. Message(asmr_e_invalid_operand_type);
  574. BuildConstantOperand(oper);
  575. end
  576. else
  577. begin
  578. expr:=actasmpattern;
  579. Consume(AS_ID);
  580. { typecasting? }
  581. if (actasmtoken=AS_LPAREN) and
  582. SearchType(expr,typesize) then
  583. begin
  584. oper.hastype:=true;
  585. Consume(AS_LPAREN);
  586. BuildOperand(oper);
  587. Consume(AS_RPAREN);
  588. if oper.opr.typ in [OPR_REFERENCE,OPR_LOCAL] then
  589. oper.SetSize(typesize,true);
  590. end
  591. else
  592. begin
  593. if not(oper.SetupVar(expr,false)) then
  594. Begin
  595. { look for special symbols ... }
  596. if expr= '__HIGH' then
  597. begin
  598. consume(AS_LPAREN);
  599. if not oper.setupvar('high'+actasmpattern,false) then
  600. Message1(sym_e_unknown_id,'high'+actasmpattern);
  601. consume(AS_ID);
  602. consume(AS_RPAREN);
  603. end
  604. else
  605. if expr = '__RESULT' then
  606. oper.SetUpResult
  607. else
  608. if expr = '__SELF' then
  609. oper.SetupSelf
  610. else
  611. if expr = '__OLDEBP' then
  612. oper.SetupOldEBP
  613. else
  614. Message1(sym_e_unknown_id,expr);
  615. end;
  616. end;
  617. end;
  618. if actasmtoken=AS_DOT then
  619. MaybeRecordOffset;
  620. { add a constant expression? }
  621. if (actasmtoken=AS_PLUS) then
  622. begin
  623. l:=BuildConstExpression(true,false);
  624. case oper.opr.typ of
  625. OPR_CONSTANT :
  626. inc(oper.opr.val,l);
  627. OPR_LOCAL :
  628. inc(oper.opr.localsymofs,l);
  629. OPR_REFERENCE :
  630. inc(oper.opr.ref.offset,l);
  631. else
  632. internalerror(200309202);
  633. end;
  634. end
  635. end;
  636. { Do we have a indexing reference, then parse it also }
  637. if actasmtoken=AS_LPAREN then
  638. BuildReference(oper);
  639. end;
  640. { Register, a variable reference or a constant reference }
  641. AS_REGISTER:
  642. Begin
  643. { save the type of register used. }
  644. tempreg:=actasmregister;
  645. Consume(AS_REGISTER);
  646. if (actasmtoken in [AS_end,AS_SEPARATOR,AS_COMMA]) then
  647. Begin
  648. if not (oper.opr.typ in [OPR_NONE,OPR_REGISTER]) then
  649. Message(asmr_e_invalid_operand_type);
  650. oper.opr.typ:=OPR_REGISTER;
  651. oper.opr.reg:=tempreg;
  652. end
  653. else
  654. Message(asmr_e_syn_operand);
  655. end;
  656. AS_end,
  657. AS_SEPARATOR,
  658. AS_COMMA: ;
  659. else
  660. Begin
  661. Message(asmr_e_syn_operand);
  662. Consume(actasmtoken);
  663. end;
  664. end; { end case }
  665. end;
  666. procedure txtensaattreader.BuildSpecialreg(oper: TXtensaOperand);
  667. var
  668. hs, reg : String;
  669. ch : char;
  670. i, t : longint;
  671. hreg : tregister;
  672. flags : tspecialregflags;
  673. begin
  674. hreg:=NR_NO;
  675. case actasmtoken of
  676. AS_REGISTER:
  677. begin
  678. oper.opr.typ:=OPR_REGISTER;
  679. oper.opr.reg:=actasmregister;
  680. Consume(AS_REGISTER);
  681. end;
  682. else
  683. Message(asmr_e_invalid_operand_type);
  684. end;
  685. end;
  686. {*****************************************************************************
  687. tarmattreader
  688. *****************************************************************************}
  689. procedure txtensaattreader.BuildOpCode(instr : TXtensaInstruction);
  690. var
  691. operandnum : longint;
  692. Begin
  693. { opcode }
  694. if (actasmtoken<>AS_OPCODE) then
  695. Begin
  696. Message(asmr_e_invalid_or_missing_opcode);
  697. RecoverConsume(true);
  698. exit;
  699. end;
  700. { Fill the instr object with the current state }
  701. with instr do
  702. begin
  703. Opcode:=ActOpcode;
  704. condition:=ActCondition;
  705. end;
  706. { We are reading operands, so opcode will be an AS_ID }
  707. operandnum:=1;
  708. Consume(AS_OPCODE);
  709. { Zero operand opcode ? }
  710. if actasmtoken in [AS_SEPARATOR,AS_end] then
  711. begin
  712. operandnum:=0;
  713. exit;
  714. end;
  715. { Read the operands }
  716. repeat
  717. case actasmtoken of
  718. AS_COMMA: { Operand delimiter }
  719. Begin
  720. if operandnum>Max_Operands then
  721. Message(asmr_e_too_many_operands)
  722. else
  723. Inc(operandnum);
  724. Consume(AS_COMMA);
  725. end;
  726. AS_SEPARATOR,
  727. AS_end : { End of asm operands for this opcode }
  728. begin
  729. break;
  730. end;
  731. else
  732. BuildOperand(instr.Operands[operandnum] as TXtensaOperand);
  733. end; { end case }
  734. until false;
  735. instr.Ops:=operandnum;
  736. end;
  737. function txtensaattreader.is_asmopcode(const s: string):boolean;
  738. //const
  739. // { sorted by length so longer postfixes will match first }
  740. // postfix2strsorted : array[1..70] of string[9] = (
  741. // '.F32.S32','.F32.U32','.S32.F32','.U32.F32','.F64.S32','.F64.U32','.S32.F64','.U32.F64',
  742. // '.F32.S16','.F32.U16','.S16.F32','.U16.F32','.F64.S16','.F64.U16','.S16.F64','.U16.F64',
  743. // '.F32.F64','.F64.F32',
  744. // '.I16','.I32','.I64','.S16','.S32','.S64','.U16','.U32','.U64','.F32','.F64',
  745. // 'IAD','DBD','FDD','EAD','IAS','DBS','FDS','EAS','IAX','DBX','FDX','EAX',
  746. // '.16','.32','.64','.I8','.S8','.U8','.P8',
  747. // 'EP','SB','BT','SH','IA','IB','DA','DB','FD','FA','ED','EA',
  748. // '.8','S','D','E','P','X','R','B','H','T');
  749. //
  750. // postfixsorted : array[1..70] of TOpPostfix = (
  751. // PF_F32S32,PF_F32U32,PF_S32F32,PF_U32F32,PF_F64S32,PF_F64U32,PF_S32F64,PF_U32F64,
  752. // PF_F32S16,PF_F32U16,PF_S16F32,PF_U16F32,PF_F64S16,PF_F64U16,PF_S16F64,PF_U16F64,
  753. // PF_F32F64,PF_F64F32,
  754. // PF_I16,PF_I32,
  755. // PF_I64,PF_S16,PF_S32,PF_S64,PF_U16,PF_U32,PF_U64,PF_F32,
  756. // PF_F64,PF_IAD,PF_DBD,PF_FDD,PF_EAD,
  757. // PF_IAS,PF_DBS,PF_FDS,PF_EAS,PF_IAX,
  758. // PF_DBX,PF_FDX,PF_EAX,PF_16,PF_32,
  759. // PF_64,PF_I8,PF_S8,PF_U8,PF_P8,
  760. // PF_EP,PF_SB,PF_BT,PF_SH,PF_IA,
  761. // PF_IB,PF_DA,PF_DB,PF_FD,PF_FA,
  762. // PF_ED,PF_EA,PF_8,PF_S,PF_D,PF_E,
  763. // PF_P,PF_X,PF_R,PF_B,PF_H,PF_T);
  764. var
  765. j, j2 : longint;
  766. hs,hs2 : string;
  767. maxlen : longint;
  768. icond : tasmcond;
  769. Begin
  770. { making s a value parameter would break other assembler readers }
  771. hs:=s;
  772. is_asmopcode:=false;
  773. { clear op code }
  774. actopcode:=A_None;
  775. actcondition:=C_None;
  776. if hs[1]='B' then
  777. begin
  778. for icond:=low(tasmcond) to high(tasmcond) do
  779. begin
  780. if copy(hs,2,length(hs)-1)=uppercond2str[icond] then
  781. begin
  782. actopcode:=A_Bcc;
  783. actasmtoken:=AS_OPCODE;
  784. actcondition:=icond;
  785. is_asmopcode:=true;
  786. exit;
  787. end;
  788. end;
  789. end;
  790. maxlen:=min(length(hs),7);
  791. actopcode:=A_NONE;
  792. j2:=maxlen;
  793. hs2:=hs;
  794. while j2>=1 do
  795. begin
  796. hs:=hs2;
  797. while j2>=1 do
  798. begin
  799. actopcode:=tasmop(PtrUInt(iasmops.Find(copy(hs,1,j2))));
  800. if actopcode<>A_NONE then
  801. begin
  802. actasmtoken:=AS_OPCODE;
  803. { strip op code }
  804. delete(hs,1,j2);
  805. dec(j2);
  806. break;
  807. end;
  808. dec(j2);
  809. end;
  810. if actopcode=A_NONE then
  811. exit;
  812. begin
  813. { search for condition, conditions are always 2 chars }
  814. if length(hs)>1 then
  815. begin
  816. for icond:=low(tasmcond) to high(tasmcond) do
  817. begin
  818. if copy(hs,1,2)=uppercond2str[icond] then
  819. begin
  820. actcondition:=icond;
  821. { strip condition }
  822. delete(hs,1,2);
  823. break;
  824. end;
  825. end;
  826. end;
  827. { check for postfix }
  828. //if (length(hs)>0) and (actoppostfix=PF_None) then
  829. // begin
  830. // for j:=low(postfixsorted) to high(postfixsorted) do
  831. // begin
  832. // if copy(hs,1,length(postfix2strsorted[j]))=postfix2strsorted[j] then
  833. // begin
  834. // actoppostfix:=postfixsorted[j];
  835. // { strip postfix }
  836. // delete(hs,1,length(postfix2strsorted[j]));
  837. // break;
  838. // end;
  839. // end;
  840. // end;
  841. end;
  842. { check for format postfix }
  843. //if length(hs)>0 then
  844. // begin
  845. // if copy(hs,1,2) = '.W' then
  846. // begin
  847. // actwideformat:=true;
  848. // delete(hs,1,2);
  849. // end;
  850. // end;
  851. { if we stripped all postfixes, it's a valid opcode }
  852. is_asmopcode:=length(hs)=0;
  853. if is_asmopcode = true then
  854. break;
  855. end;
  856. end;
  857. procedure txtensaattreader.ConvertCalljmp(instr : TXtensaInstruction);
  858. var
  859. newopr : toprrec;
  860. begin
  861. if instr.Operands[1].opr.typ=OPR_REFERENCE then
  862. begin
  863. newopr.typ:=OPR_SYMBOL;
  864. newopr.symbol:=instr.Operands[1].opr.ref.symbol;
  865. newopr.symofs:=instr.Operands[1].opr.ref.offset;
  866. if (instr.Operands[1].opr.ref.base<>NR_NO) or
  867. (instr.Operands[1].opr.ref.index<>NR_NO) then
  868. Message(asmr_e_syn_operand);
  869. instr.Operands[1].opr:=newopr;
  870. end;
  871. end;
  872. procedure txtensaattreader.HandleTargetDirective;
  873. var
  874. symname,
  875. symval : String;
  876. val : tcgint;
  877. symtyp : TAsmsymtype;
  878. begin
  879. case actasmpattern of
  880. '.thumb_set':
  881. begin
  882. consume(AS_TARGET_DIRECTIVE);
  883. BuildConstSymbolExpression(true,false,false, val,symname,symtyp);
  884. Consume(AS_COMMA);
  885. BuildConstSymbolExpression(true,false,false, val,symval,symtyp);
  886. curList.concat(tai_symbolpair.create(spk_thumb_set,symname,symval));
  887. end;
  888. '.code':
  889. begin
  890. consume(AS_TARGET_DIRECTIVE);
  891. val:=BuildConstExpression(false,false);
  892. if not(val in [16,32]) then
  893. Message(asmr_e_invalid_code_value);
  894. curList.concat(tai_directive.create(asd_code,tostr(val)));
  895. end;
  896. '.thumb_func':
  897. begin
  898. consume(AS_TARGET_DIRECTIVE);
  899. curList.concat(tai_directive.create(asd_thumb_func,''));
  900. end
  901. else
  902. inherited HandleTargetDirective;
  903. end;
  904. end;
  905. procedure txtensaattreader.handleopcode;
  906. var
  907. instr : TXtensaInstruction;
  908. begin
  909. instr:=TXtensaInstruction.Create(TXtensaOperand);
  910. BuildOpcode(instr);
  911. if is_calljmp(instr.opcode) then
  912. ConvertCalljmp(instr);
  913. {
  914. instr.AddReferenceSizes;
  915. instr.SetInstructionOpsize;
  916. instr.CheckOperandSizes;
  917. }
  918. instr.ConcatInstruction(curlist);
  919. instr.Free;
  920. // actoppostfix:=PF_None;
  921. // actwideformat:=false;
  922. end;
  923. {*****************************************************************************
  924. Initialize
  925. *****************************************************************************}
  926. const
  927. asmmode_xtensa_att_info : tasmmodeinfo =
  928. (
  929. id : asmmode_xtensa_gas;
  930. idtxt : 'DIVIDED';
  931. casmreader : txtensaattreader;
  932. );
  933. asmmode_xtensa_standard_info : tasmmodeinfo =
  934. (
  935. id : asmmode_standard;
  936. idtxt : 'STANDARD';
  937. casmreader : txtensaattreader;
  938. );
  939. initialization
  940. RegisterAsmMode(asmmode_xtensa_att_info);
  941. RegisterAsmMode(asmmode_xtensa_standard_info);
  942. end.