racpugas.pas 32 KB

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