raarmgas.pas 33 KB

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