raarmgas.pas 39 KB

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