racpugas.pas 33 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043
  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. actoppostfix : TOpPostfix;
  26. actIsPrefixed: boolean;
  27. function is_asmopcode(const s: string):boolean;override;
  28. function is_register(const s:string):boolean;override;
  29. // function is_targetdirective(const s: string): boolean; override;
  30. procedure handleopcode;override;
  31. procedure BuildReference(oper : TXtensaOperand);
  32. procedure BuildOperand(oper : TXtensaOperand);
  33. procedure BuildSpecialreg(oper : TXtensaOperand);
  34. procedure BuildOpCode(instr : TXtensaInstruction);
  35. procedure ReadSym(oper : TXtensaOperand);
  36. procedure ConvertCalljmp(instr : TXtensaInstruction);
  37. procedure HandleTargetDirective; override;
  38. end;
  39. Implementation
  40. uses
  41. { helpers }
  42. cutils,
  43. { global }
  44. globtype,globals,verbose,
  45. systems,aasmbase,aasmtai,aasmdata,aasmcpu,
  46. { symtable }
  47. symconst,symsym,symdef,
  48. procinfo,
  49. rabase,rautils,
  50. cgbase,cgutils,paramgr;
  51. function txtensaattreader.is_register(const s:string):boolean;
  52. type
  53. treg2str = record
  54. name : string[3];
  55. reg : tregister;
  56. end;
  57. const
  58. extraregs : array[0..0] of treg2str = (
  59. (name: 'A1'; reg : NR_A0)
  60. );
  61. var
  62. i : longint;
  63. begin
  64. result:=inherited is_register(s);
  65. { reg found?
  66. possible aliases are always 2 char
  67. }
  68. if result or (not (length(s) in [2,3])) then
  69. exit;
  70. for i:=low(extraregs) to high(extraregs) do
  71. begin
  72. if s=extraregs[i].name then
  73. begin
  74. actasmregister:=extraregs[i].reg;
  75. result:=true;
  76. actasmtoken:=AS_REGISTER;
  77. exit;
  78. end;
  79. end;
  80. end;
  81. procedure txtensaattreader.ReadSym(oper : TXtensaOperand);
  82. var
  83. tempstr, mangledname : string;
  84. typesize,l,k : tcgint;
  85. begin
  86. tempstr:=actasmpattern;
  87. Consume(AS_ID);
  88. { typecasting? }
  89. if (actasmtoken=AS_LPAREN) and
  90. SearchType(tempstr,typesize) then
  91. begin
  92. oper.hastype:=true;
  93. Consume(AS_LPAREN);
  94. BuildOperand(oper);
  95. Consume(AS_RPAREN);
  96. if oper.opr.typ in [OPR_REFERENCE,OPR_LOCAL] then
  97. oper.SetSize(typesize,true);
  98. end
  99. else
  100. if not oper.SetupVar(tempstr,false) then
  101. Message1(sym_e_unknown_id,tempstr);
  102. { record.field ? }
  103. if actasmtoken=AS_DOT then
  104. begin
  105. BuildRecordOffsetSize(tempstr,l,k,mangledname,false);
  106. if (mangledname<>'') then
  107. Message(asmr_e_invalid_reference_syntax);
  108. inc(oper.opr.ref.offset,l);
  109. end;
  110. end;
  111. Procedure txtensaattreader.BuildReference(oper : TXtensaOperand);
  112. procedure do_error;
  113. begin
  114. Message(asmr_e_invalid_reference_syntax);
  115. RecoverConsume(false);
  116. end;
  117. procedure test_end(require_rbracket : boolean);
  118. begin
  119. if require_rbracket then begin
  120. if not(actasmtoken=AS_RBRACKET) then
  121. begin
  122. do_error;
  123. exit;
  124. end
  125. else
  126. Consume(AS_RBRACKET);
  127. end;
  128. if not(actasmtoken in [AS_SEPARATOR,AS_end]) then
  129. do_error
  130. else
  131. begin
  132. {$IFDEF debugasmreader}
  133. writeln('TEST_end_FINAL_OK. Created the following ref:');
  134. writeln('oper.opr.ref.shiftimm=',oper.opr.ref.shiftimm);
  135. writeln('oper.opr.ref.shiftmode=',ord(oper.opr.ref.shiftmode));
  136. writeln('oper.opr.ref.index=',ord(oper.opr.ref.index));
  137. writeln('oper.opr.ref.base=',ord(oper.opr.ref.base));
  138. writeln('oper.opr.ref.signindex=',ord(oper.opr.ref.signindex));
  139. writeln('oper.opr.ref.addressmode=',ord(oper.opr.ref.addressmode));
  140. writeln;
  141. {$endIF debugasmreader}
  142. end;
  143. end;
  144. procedure read_index_shift(require_rbracket : boolean);
  145. var
  146. shift : aint;
  147. begin
  148. case actasmtoken of
  149. AS_COMMA :
  150. begin
  151. Consume(AS_COMMA);
  152. if not(actasmtoken=AS_ID) then
  153. do_error;
  154. end;
  155. AS_RBRACKET :
  156. if require_rbracket then
  157. test_end(require_rbracket)
  158. else
  159. begin
  160. do_error;
  161. exit;
  162. end;
  163. AS_SEPARATOR,AS_END :
  164. if not require_rbracket then
  165. test_end(false)
  166. else
  167. do_error;
  168. else
  169. begin
  170. do_error;
  171. exit;
  172. end;
  173. end;
  174. end;
  175. procedure read_index(require_rbracket : boolean);
  176. var
  177. recname : string;
  178. o_int,s_int : tcgint;
  179. begin
  180. case actasmtoken of
  181. AS_REGISTER :
  182. begin
  183. oper.opr.ref.index:=actasmregister;
  184. Consume(AS_REGISTER);
  185. read_index_shift(require_rbracket);
  186. exit;
  187. end;
  188. AS_PLUS,AS_MINUS :
  189. begin
  190. if actasmtoken=AS_PLUS then
  191. begin
  192. Consume(AS_PLUS);
  193. end;
  194. if actasmtoken=AS_REGISTER then
  195. begin
  196. oper.opr.ref.index:=actasmregister;
  197. Consume(AS_REGISTER);
  198. read_index_shift(require_rbracket);
  199. exit;
  200. end
  201. else
  202. begin
  203. do_error;
  204. exit;
  205. end;
  206. test_end(require_rbracket);
  207. exit;
  208. end;
  209. AS_HASH : // constant
  210. begin
  211. Consume(AS_HASH);
  212. o_int := BuildConstExpression(false,true);
  213. if (o_int>4095) or (o_int<-4095) then
  214. begin
  215. Message(asmr_e_constant_out_of_bounds);
  216. RecoverConsume(false);
  217. exit;
  218. end
  219. else
  220. begin
  221. inc(oper.opr.ref.offset,o_int);
  222. test_end(require_rbracket);
  223. exit;
  224. end;
  225. end;
  226. AS_ID :
  227. begin
  228. recname := actasmpattern;
  229. Consume(AS_ID);
  230. BuildRecordOffsetSize(recname,o_int,s_int,recname,false);
  231. if (o_int>4095)or(o_int<-4095) then
  232. begin
  233. Message(asmr_e_constant_out_of_bounds);
  234. RecoverConsume(false);
  235. exit;
  236. end
  237. else
  238. begin
  239. inc(oper.opr.ref.offset,o_int);
  240. test_end(require_rbracket);
  241. exit;
  242. end;
  243. end;
  244. AS_AT:
  245. begin
  246. do_error;
  247. exit;
  248. end;
  249. AS_DOT : // local label
  250. begin
  251. BuildConstExpression(true,false);
  252. test_end(require_rbracket);
  253. exit;
  254. end;
  255. AS_RBRACKET :
  256. begin
  257. if require_rbracket then
  258. begin
  259. test_end(require_rbracket);
  260. exit;
  261. end
  262. else
  263. begin
  264. do_error; // unexpected rbracket
  265. exit;
  266. end;
  267. end;
  268. AS_SEPARATOR,AS_end :
  269. begin
  270. if not require_rbracket then
  271. begin
  272. test_end(false);
  273. exit;
  274. end
  275. else
  276. begin
  277. do_error;
  278. exit;
  279. end;
  280. end;
  281. else
  282. begin
  283. // unexpected token
  284. do_error;
  285. exit;
  286. end;
  287. end; // case
  288. end;
  289. procedure try_prepostindexed;
  290. begin
  291. Consume(AS_RBRACKET);
  292. case actasmtoken of
  293. AS_COMMA :
  294. begin // post-indexed
  295. Consume(AS_COMMA);
  296. read_index(false);
  297. exit;
  298. end;
  299. AS_NOT :
  300. begin // pre-indexed
  301. Consume(AS_NOT);
  302. test_end(false);
  303. exit;
  304. end;
  305. else
  306. begin
  307. test_end(false);
  308. exit;
  309. end;
  310. end; // case
  311. end;
  312. var
  313. lab : TASMLABEL;
  314. begin
  315. Consume(AS_LBRACKET);
  316. if actasmtoken=AS_REGISTER then
  317. begin
  318. oper.opr.ref.base:=actasmregister;
  319. Consume(AS_REGISTER);
  320. case actasmtoken of
  321. AS_RBRACKET :
  322. begin
  323. try_prepostindexed;
  324. exit;
  325. end;
  326. AS_COMMA :
  327. begin
  328. Consume(AS_COMMA);
  329. read_index(true);
  330. exit;
  331. end;
  332. else
  333. begin
  334. Message(asmr_e_invalid_reference_syntax);
  335. RecoverConsume(false);
  336. end;
  337. end;
  338. end
  339. else
  340. {
  341. if base isn't a register, r15=PC is implied base, so it must be a local label.
  342. pascal constants don't make sense, because implied r15
  343. record offsets probably don't make sense, too (a record offset of code?)
  344. TODO: However, we could make the Stackpointer implied.
  345. }
  346. Begin
  347. case actasmtoken of
  348. AS_ID :
  349. begin
  350. // TODO: Stackpointer implied,
  351. Message(asmr_e_invalid_reference_syntax);
  352. RecoverConsume(false);
  353. exit;
  354. end;
  355. else
  356. begin
  357. Message(asmr_e_invalid_reference_syntax);
  358. RecoverConsume(false);
  359. exit;
  360. end;
  361. end;
  362. end;
  363. end;
  364. Procedure txtensaattreader.BuildOperand(oper : TXtensaOperand);
  365. var
  366. expr : string;
  367. typesize,l : tcgint;
  368. procedure AddLabelOperand(hl:tasmlabel);
  369. begin
  370. oper.opr.typ:=OPR_SYMBOL;
  371. oper.opr.symbol:=hl;
  372. end;
  373. procedure MaybeRecordOffset;
  374. var
  375. mangledname: string;
  376. hasdot : boolean;
  377. l,
  378. toffset,
  379. tsize : tcgint;
  380. begin
  381. if not(actasmtoken in [AS_DOT,AS_PLUS,AS_MINUS]) then
  382. exit;
  383. l:=0;
  384. mangledname:='';
  385. hasdot:=(actasmtoken=AS_DOT);
  386. if hasdot then
  387. begin
  388. if expr<>'' then
  389. begin
  390. BuildRecordOffsetSize(expr,toffset,tsize,mangledname,false);
  391. if (oper.opr.typ<>OPR_CONSTANT) and
  392. (mangledname<>'') then
  393. Message(asmr_e_wrong_sym_type);
  394. inc(l,toffset);
  395. oper.SetSize(tsize,true);
  396. end;
  397. end;
  398. if actasmtoken in [AS_PLUS,AS_MINUS] then
  399. inc(l,BuildConstExpression(true,false));
  400. case oper.opr.typ of
  401. OPR_LOCAL :
  402. begin
  403. { don't allow direct access to fields of parameters, because that
  404. will generate buggy code. Allow it only for explicit typecasting }
  405. if hasdot and
  406. (not oper.hastype) then
  407. checklocalsubscript(oper.opr.localsym);
  408. inc(oper.opr.localsymofs,l)
  409. end;
  410. OPR_CONSTANT :
  411. inc(oper.opr.val,l);
  412. OPR_REFERENCE :
  413. if (mangledname<>'') then
  414. begin
  415. if (oper.opr.val<>0) then
  416. Message(asmr_e_wrong_sym_type);
  417. oper.opr.typ:=OPR_SYMBOL;
  418. oper.opr.symbol:=current_asmdata.RefAsmSymbol(mangledname,AT_FUNCTION);
  419. end
  420. else
  421. inc(oper.opr.val,l);
  422. OPR_SYMBOL:
  423. Message(asmr_e_invalid_symbol_ref);
  424. else
  425. internalerror(200309221);
  426. end;
  427. end;
  428. function MaybeBuildReference:boolean;
  429. { Try to create a reference, if not a reference is found then false
  430. is returned }
  431. begin
  432. MaybeBuildReference:=true;
  433. case actasmtoken of
  434. AS_INTNUM,
  435. AS_MINUS,
  436. AS_PLUS:
  437. Begin
  438. oper.opr.ref.offset:=BuildConstExpression(True,False);
  439. if actasmtoken<>AS_LPAREN then
  440. Message(asmr_e_invalid_reference_syntax)
  441. else
  442. BuildReference(oper);
  443. end;
  444. AS_LPAREN:
  445. BuildReference(oper);
  446. AS_ID: { only a variable is allowed ... }
  447. Begin
  448. ReadSym(oper);
  449. case actasmtoken of
  450. AS_end,
  451. AS_SEPARATOR,
  452. AS_COMMA: ;
  453. AS_LPAREN:
  454. BuildReference(oper);
  455. else
  456. Begin
  457. Message(asmr_e_invalid_reference_syntax);
  458. Consume(actasmtoken);
  459. end;
  460. end; {end case }
  461. end;
  462. else
  463. MaybeBuildReference:=false;
  464. end; { end case }
  465. end;
  466. procedure BuildDirectRef;
  467. function GetConstLabel(const symname: string; ofs: aint): TAsmLabel;
  468. var
  469. hp: tai;
  470. newconst: tai_const;
  471. lab: TAsmLabel;
  472. begin
  473. if symname<>'' then
  474. newconst:=tai_const.Createname(symname,ofs)
  475. else
  476. newconst:=tai_const.Create_32bit(ofs);
  477. hp:=tai(current_procinfo.aktlocaldata.First);
  478. while assigned(hp) do
  479. begin
  480. if hp.typ=ait_const then
  481. begin
  482. if (tai_const(hp).sym=newconst.sym) and
  483. (tai_const(hp).value=newconst.value) and
  484. assigned(hp.Previous) and
  485. (tai(hp.previous).typ=ait_label) then
  486. begin
  487. newconst.Free;
  488. result:=tai_label(hp.Previous).labsym;
  489. exit;
  490. end;
  491. end;
  492. hp:=tai(hp.Next);
  493. end;
  494. current_asmdata.getjumplabel(lab);
  495. current_procinfo.aktlocaldata.concat(tai_align.create(4));
  496. current_procinfo.aktlocaldata.concat(tai_label.create(lab));
  497. current_procinfo.aktlocaldata.concat(newconst);
  498. result:=lab;
  499. end;
  500. var
  501. symtype: TAsmsymtype;
  502. sym: string;
  503. val: tcgint;
  504. begin
  505. case actasmtoken of
  506. AS_INTNUM,
  507. AS_ID:
  508. begin
  509. BuildConstSymbolExpression(true,false,false,val,sym,symtype);
  510. if symtype=AT_NONE then
  511. sym:='';
  512. reference_reset(oper.opr.ref,4,[]);
  513. oper.opr.ref.symbol:=GetConstLabel(sym,val);
  514. end;
  515. else
  516. ;
  517. end;
  518. end;
  519. function getregsetindex(reg: tregister): integer;
  520. begin
  521. if getsubreg(reg)=R_SUBFS then
  522. begin
  523. result:=getsupreg(reg)*2;
  524. if result>32 then
  525. result:=result-63;
  526. end
  527. else
  528. result:=getsupreg(reg);
  529. end;
  530. var
  531. tempreg : tregister;
  532. ireg : tsuperregister;
  533. regtype: tregistertype;
  534. subreg: tsubregister;
  535. hl : tasmlabel;
  536. {ofs : longint;}
  537. registerset : tcpuregisterset;
  538. Begin
  539. expr:='';
  540. case actasmtoken of
  541. AS_LBRACKET: { Memory reference or constant expression }
  542. Begin
  543. oper.InitRef;
  544. BuildReference(oper);
  545. end;
  546. AS_MINUS,
  547. AS_PLUS,
  548. AS_INTNUM: { Constant expression }
  549. Begin
  550. BuildConstantOperand(oper);
  551. end;
  552. AS_ID: { A constant expression, or a Variable ref. }
  553. Begin
  554. if is_locallabel(actasmpattern) then
  555. begin
  556. CreateLocalLabel(actasmpattern,hl,false);
  557. Consume(AS_ID);
  558. AddLabelOperand(hl);
  559. end
  560. else
  561. { Check for label }
  562. if SearchLabel(actasmpattern,hl,false) then
  563. begin
  564. Consume(AS_ID);
  565. AddLabelOperand(hl);
  566. end
  567. else
  568. { probably a variable or normal expression }
  569. { or a procedure (such as in CALL ID) }
  570. Begin
  571. { is it a constant ? }
  572. if SearchIConstant(actasmpattern,l) then
  573. Begin
  574. if not (oper.opr.typ in [OPR_NONE,OPR_CONSTANT]) then
  575. Message(asmr_e_invalid_operand_type);
  576. BuildConstantOperand(oper);
  577. end
  578. else
  579. begin
  580. expr:=actasmpattern;
  581. Consume(AS_ID);
  582. { typecasting? }
  583. if (actasmtoken=AS_LPAREN) and
  584. SearchType(expr,typesize) then
  585. begin
  586. oper.hastype:=true;
  587. Consume(AS_LPAREN);
  588. BuildOperand(oper);
  589. Consume(AS_RPAREN);
  590. if oper.opr.typ in [OPR_REFERENCE,OPR_LOCAL] then
  591. oper.SetSize(typesize,true);
  592. end
  593. else
  594. begin
  595. if not(oper.SetupVar(expr,false)) then
  596. Begin
  597. { look for special symbols ... }
  598. if expr= '__HIGH' then
  599. begin
  600. consume(AS_LPAREN);
  601. if not oper.setupvar('high'+actasmpattern,false) then
  602. Message1(sym_e_unknown_id,'high'+actasmpattern);
  603. consume(AS_ID);
  604. consume(AS_RPAREN);
  605. end
  606. else
  607. if expr = '__RESULT' then
  608. oper.SetUpResult
  609. else
  610. if expr = '__SELF' then
  611. oper.SetupSelf
  612. else
  613. if expr = '__OLDEBP' then
  614. oper.SetupOldEBP
  615. else
  616. Message1(sym_e_unknown_id,expr);
  617. end;
  618. end;
  619. end;
  620. if actasmtoken=AS_DOT then
  621. MaybeRecordOffset;
  622. { add a constant expression? }
  623. if (actasmtoken=AS_PLUS) then
  624. begin
  625. l:=BuildConstExpression(true,false);
  626. case oper.opr.typ of
  627. OPR_CONSTANT :
  628. inc(oper.opr.val,l);
  629. OPR_LOCAL :
  630. inc(oper.opr.localsymofs,l);
  631. OPR_REFERENCE :
  632. inc(oper.opr.ref.offset,l);
  633. else
  634. internalerror(200309202);
  635. end;
  636. end
  637. end;
  638. { Do we have a indexing reference, then parse it also }
  639. if actasmtoken=AS_LPAREN then
  640. BuildReference(oper);
  641. end;
  642. { Register, a variable reference or a constant reference }
  643. AS_REGISTER:
  644. Begin
  645. { save the type of register used. }
  646. tempreg:=actasmregister;
  647. Consume(AS_REGISTER);
  648. if (actasmtoken in [AS_end,AS_SEPARATOR,AS_COMMA]) then
  649. Begin
  650. if not (oper.opr.typ in [OPR_NONE,OPR_REGISTER]) then
  651. Message(asmr_e_invalid_operand_type);
  652. oper.opr.typ:=OPR_REGISTER;
  653. oper.opr.reg:=tempreg;
  654. end
  655. else
  656. Message(asmr_e_syn_operand);
  657. end;
  658. AS_end,
  659. AS_SEPARATOR,
  660. AS_COMMA: ;
  661. else
  662. Begin
  663. Message(asmr_e_syn_operand);
  664. Consume(actasmtoken);
  665. end;
  666. end; { end case }
  667. end;
  668. procedure txtensaattreader.BuildSpecialreg(oper: TXtensaOperand);
  669. var
  670. hs, reg : String;
  671. ch : char;
  672. i, t : longint;
  673. hreg : tregister;
  674. flags : tspecialregflags;
  675. begin
  676. hreg:=NR_NO;
  677. case actasmtoken of
  678. AS_REGISTER:
  679. begin
  680. oper.opr.typ:=OPR_REGISTER;
  681. oper.opr.reg:=actasmregister;
  682. Consume(AS_REGISTER);
  683. end;
  684. else
  685. Message(asmr_e_invalid_operand_type);
  686. end;
  687. end;
  688. {*****************************************************************************
  689. tarmattreader
  690. *****************************************************************************}
  691. procedure txtensaattreader.BuildOpCode(instr : TXtensaInstruction);
  692. var
  693. operandnum : longint;
  694. Begin
  695. { opcode }
  696. if (actasmtoken<>AS_OPCODE) then
  697. Begin
  698. Message(asmr_e_invalid_or_missing_opcode);
  699. RecoverConsume(true);
  700. exit;
  701. end;
  702. { Fill the instr object with the current state }
  703. with instr do
  704. begin
  705. Opcode:=ActOpcode;
  706. condition:=ActCondition;
  707. oppostfix:=actoppostfix;
  708. opIsPrefixed:=actIsPrefixed;
  709. end;
  710. { We are reading operands, so opcode will be an AS_ID }
  711. operandnum:=1;
  712. Consume(AS_OPCODE);
  713. { Zero operand opcode ? }
  714. if actasmtoken in [AS_SEPARATOR,AS_end] then
  715. begin
  716. operandnum:=0;
  717. exit;
  718. end;
  719. { Read the operands }
  720. repeat
  721. case actasmtoken of
  722. AS_COMMA: { Operand delimiter }
  723. Begin
  724. if operandnum>Max_Operands then
  725. Message(asmr_e_too_many_operands)
  726. else
  727. Inc(operandnum);
  728. Consume(AS_COMMA);
  729. end;
  730. AS_SEPARATOR,
  731. AS_end : { End of asm operands for this opcode }
  732. begin
  733. break;
  734. end;
  735. else
  736. BuildOperand(instr.Operands[operandnum] as TXtensaOperand);
  737. end; { end case }
  738. until false;
  739. instr.Ops:=operandnum;
  740. end;
  741. function txtensaattreader.is_asmopcode(const s: string):boolean;
  742. const
  743. { sorted by length so longer postfixes will match first }
  744. postfix2strsorted : array[1..112] of string[13] = (
  745. 'IBREAKENABLE', 'DA.HH.LDDEC', 'DA.HH.LDINC', 'DA.HL.LDDEC', 'DA.HL.LDINC',
  746. 'DA.LH.LDDEC', 'DA.LH.LDINC', 'DA.LL.LDDEC', 'DA.LL.LDINC', 'DD.HH.LDDEC',
  747. 'DD.HH.LDINC', 'DD.HL.LDDEC', 'DD.HL.LDINC', 'DD.LH.LDDEC', 'DD.LH.LDINC',
  748. 'DD.LL.LDDEC', 'DD.LL.LDINC', 'ICOUNTLEVEL', 'WINDOWSTART', 'DEBUGCAUSE',
  749. 'WINDOWBASE', 'CCOMPARE0', 'CCOMPARE1', 'CCOMPARE2', 'INTENABLE',
  750. 'INTERRUPT', 'SCOMPARE1', 'CPENABLE', 'DBREAKA0', 'DBREAKA1',
  751. 'DBREAKC0', 'DBREAKC1', 'EXCCAUSE', 'EXCSAVE1', 'EXCSAVE2',
  752. 'EXCSAVE3', 'EXCSAVE4', 'EXCSAVE5', 'EXCSAVE6', 'EXCSAVE7',
  753. 'EXCVADDR', 'IBREAKA0', 'IBREAKA1', 'INTCLEAR', 'PTEVADDR',
  754. 'ATOMCTL', 'DTLBCFG', 'ITLBCFG', 'LITBASE', 'MEVADDR',
  755. 'VECBASE', 'CCOUNT', 'ICOUNT', 'INTSET', 'LCOUNT',
  756. 'MESAVE', 'AA.HH', 'AA.HL', 'AA.LH', 'AA.LL',
  757. 'ACCHI', 'ACCLO', 'AD.HH', 'AD.HL', 'AD.LH',
  758. 'AD.LL', 'DA.HH', 'DA.HL', 'DA.LH', 'DA.LL',
  759. 'DD.HH', 'DD.HL', 'DD.LH', 'DD.LL', 'MISC0',
  760. 'MISC1', 'MISC2', 'MISC3', 'RASID', 'DEPC',
  761. 'EPC1', 'EPC2', 'EPC3', 'EPC4', 'EPC5',
  762. 'EPC6', 'EPC7', 'EPS2', 'EPS3', 'EPS4',
  763. 'EPS5', 'EPS6', 'EPS7', 'LBEG', 'LEND',
  764. 'MECR', 'MEPC', 'MEPS', 'MESR', 'MMID',
  765. 'PRID', 'DDR', 'SAR', 'BR', 'M0',
  766. 'M1', 'M2', 'M3', 'PS', 'L',
  767. 'N', 'S');
  768. postfixsorted : array[1..112] of TOpPostfix = (
  769. PF_IBREAKENABLE, PF_DA_HH_LDDEC, PF_DA_HH_LDINC, PF_DA_HL_LDDEC, PF_DA_HL_LDINC,
  770. PF_DA_LH_LDDEC, PF_DA_LH_LDINC, PF_DA_LL_LDDEC, PF_DA_LL_LDINC, PF_DD_HH_LDDEC,
  771. PF_DD_HH_LDINC, PF_DD_HL_LDDEC, PF_DD_HL_LDINC, PF_DD_LH_LDDEC, PF_DD_LH_LDINC,
  772. PF_DD_LL_LDDEC, PF_DD_LL_LDINC, PF_ICOUNTLEVEL, PF_WINDOWSTART, PF_DEBUGCAUSE,
  773. PF_WINDOWBASE, PF_CCOMPARE0, PF_CCOMPARE1, PF_CCOMPARE2, PF_INTENABLE,
  774. PF_INTERRUPT, PF_SCOMPARE1, PF_CPENABLE, PF_DBREAKA0, PF_DBREAKA1,
  775. PF_DBREAKC0, PF_DBREAKC1, PF_EXCCAUSE, PF_EXCSAVE1, PF_EXCSAVE2,
  776. PF_EXCSAVE3, PF_EXCSAVE4, PF_EXCSAVE5, PF_EXCSAVE6, PF_EXCSAVE7,
  777. PF_EXCVADDR, PF_IBREAKA0, PF_IBREAKA1, PF_INTCLEAR, PF_PTEVADDR,
  778. PF_ATOMCTL, PF_DTLBCFG, PF_ITLBCFG, PF_LITBASE, PF_MEVADDR,
  779. PF_VECBASE, PF_CCOUNT, PF_ICOUNT, PF_INTSET, PF_LCOUNT,
  780. PF_MESAVE, PF_AA_HH, PF_AA_HL, PF_AA_LH, PF_AA_LL,
  781. PF_ACCHI, PF_ACCLO, PF_AD_HH, PF_AD_HL, PF_AD_LH,
  782. PF_AD_LL, PF_DA_HH, PF_DA_HL, PF_DA_LH, PF_DA_LL,
  783. PF_DD_HH, PF_DD_HL, PF_DD_LH, PF_DD_LL, PF_MISC0,
  784. PF_MISC1, PF_MISC2, PF_MISC3, PF_RASID, PF_DEPC,
  785. PF_EPC1, PF_EPC2, PF_EPC3, PF_EPC4, PF_EPC5,
  786. PF_EPC6, PF_EPC7, PF_EPS2, PF_EPS3, PF_EPS4,
  787. PF_EPS5, PF_EPS6, PF_EPS7, PF_LBEG, PF_LEND,
  788. PF_MECR, PF_MEPC, PF_MEPS, PF_MESR, PF_MMID,
  789. PF_PRID, PF_DDR, PF_SAR, PF_BR, PF_M0,
  790. PF_M1, PF_M2, PF_M3, PF_PS, PF_L,
  791. PF_N, PF_S);
  792. var
  793. j, j2 : longint;
  794. hs,hs2 : string;
  795. maxlen : longint;
  796. icond : tasmcond;
  797. Begin
  798. { making s a value parameter would break other assembler readers }
  799. hs:=s;
  800. is_asmopcode:=false;
  801. { clear op code }
  802. actopcode:=A_NONE;
  803. actcondition:=C_None;
  804. actoppostfix := PF_None;
  805. actIsPrefixed := false;
  806. if hs[1]='_' then
  807. begin
  808. actIsPrefixed := true;
  809. delete(hs, 1, 1);
  810. end;
  811. if (hs[1]='B') and not(hs='BREAK') then
  812. begin
  813. { Branch condition can be followed by a postfix, e.g. BEQZ.N or BBSI.L }
  814. j:=pos('.', hs);
  815. if j < 2 then
  816. j:=length(hs)
  817. else
  818. dec(j);
  819. hs2:=copy(hs, 2, j-1);
  820. for icond:=low(tasmcond) to high(tasmcond) do
  821. begin
  822. if hs2=uppercond2str[icond] then
  823. begin
  824. actopcode:=A_B;
  825. actasmtoken:=AS_OPCODE;
  826. actcondition:=icond;
  827. is_asmopcode:=true;
  828. delete(hs, 1, j);
  829. break;
  830. end;
  831. end;
  832. end
  833. else
  834. begin
  835. j2:=min(length(hs),7);
  836. hs2:=hs;
  837. while (j2>=1) and (actopcode=A_NONE) do
  838. begin
  839. hs:=hs2;
  840. while j2>=1 do
  841. begin
  842. actopcode:=tasmop(PtrUInt(iasmops.Find(copy(hs,1,j2))));
  843. if actopcode<>A_NONE then
  844. begin
  845. actasmtoken:=AS_OPCODE;
  846. { strip op code }
  847. delete(hs,1,j2);
  848. dec(j2);
  849. break;
  850. end;
  851. dec(j2);
  852. end;
  853. end;
  854. end;
  855. if actopcode=A_NONE then
  856. exit;
  857. { check for postfix }
  858. if (length(hs)>0) then
  859. begin
  860. for j:=low(postfixsorted) to high(postfixsorted) do
  861. begin
  862. if copy(hs,2,length(postfix2strsorted[j]))=postfix2strsorted[j] then
  863. begin
  864. actoppostfix:=postfixsorted[j];
  865. { strip postfix }
  866. delete(hs,1,length(postfix2strsorted[j])+1);
  867. break;
  868. end;
  869. end;
  870. end;
  871. { if we stripped all postfixes, it's a valid opcode }
  872. is_asmopcode:=length(hs)=0;
  873. end;
  874. procedure txtensaattreader.ConvertCalljmp(instr : TXtensaInstruction);
  875. var
  876. newopr : toprrec;
  877. begin
  878. if instr.Operands[1].opr.typ=OPR_REFERENCE then
  879. begin
  880. newopr.typ:=OPR_SYMBOL;
  881. newopr.symbol:=instr.Operands[1].opr.ref.symbol;
  882. newopr.symofs:=instr.Operands[1].opr.ref.offset;
  883. if (instr.Operands[1].opr.ref.base<>NR_NO) or
  884. (instr.Operands[1].opr.ref.index<>NR_NO) then
  885. Message(asmr_e_syn_operand);
  886. instr.Operands[1].opr:=newopr;
  887. end;
  888. end;
  889. procedure txtensaattreader.HandleTargetDirective;
  890. var
  891. symname,
  892. symval : String;
  893. val : tcgint;
  894. symtyp : TAsmsymtype;
  895. begin
  896. case actasmpattern of
  897. '.thumb_set':
  898. begin
  899. consume(AS_TARGET_DIRECTIVE);
  900. BuildConstSymbolExpression(true,false,false, val,symname,symtyp);
  901. Consume(AS_COMMA);
  902. BuildConstSymbolExpression(true,false,false, val,symval,symtyp);
  903. curList.concat(tai_symbolpair.create(spk_thumb_set,symname,symval));
  904. end;
  905. '.code':
  906. begin
  907. consume(AS_TARGET_DIRECTIVE);
  908. val:=BuildConstExpression(false,false);
  909. if not(val in [16,32]) then
  910. Message(asmr_e_invalid_code_value);
  911. curList.concat(tai_directive.create(asd_code,tostr(val)));
  912. end;
  913. '.thumb_func':
  914. begin
  915. consume(AS_TARGET_DIRECTIVE);
  916. curList.concat(tai_directive.create(asd_thumb_func,''));
  917. end
  918. else
  919. inherited HandleTargetDirective;
  920. end;
  921. end;
  922. procedure txtensaattreader.handleopcode;
  923. var
  924. instr : TXtensaInstruction;
  925. begin
  926. instr:=TXtensaInstruction.Create(TXtensaOperand);
  927. BuildOpcode(instr);
  928. if is_calljmp(instr.opcode) then
  929. ConvertCalljmp(instr);
  930. {
  931. instr.AddReferenceSizes;
  932. instr.SetInstructionOpsize;
  933. instr.CheckOperandSizes;
  934. }
  935. instr.ConcatInstruction(curlist);
  936. instr.Free;
  937. // actoppostfix:=PF_None;
  938. // actwideformat:=false;
  939. end;
  940. {*****************************************************************************
  941. Initialize
  942. *****************************************************************************}
  943. const
  944. asmmode_xtensa_att_info : tasmmodeinfo =
  945. (
  946. id : asmmode_xtensa_gas;
  947. idtxt : 'DIVIDED';
  948. casmreader : txtensaattreader;
  949. );
  950. asmmode_xtensa_standard_info : tasmmodeinfo =
  951. (
  952. id : asmmode_standard;
  953. idtxt : 'STANDARD';
  954. casmreader : txtensaattreader;
  955. );
  956. initialization
  957. RegisterAsmMode(asmmode_xtensa_att_info);
  958. RegisterAsmMode(asmmode_xtensa_standard_info);
  959. end.