raarmgas.pas 36 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122
  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. function is_ConditionCode(hs: string): boolean;
  599. var icond: tasmcond;
  600. begin
  601. is_ConditionCode := false;
  602. if actopcode in [A_IT,A_ITE,A_ITT,
  603. A_ITEE,A_ITTE,A_ITET,A_ITTT,
  604. A_ITEEE,A_ITTEE,A_ITETE,A_ITTTE,A_ITEET,A_ITTET,A_ITETT,A_ITTTT] then
  605. begin
  606. { search for condition, conditions are always 2 chars }
  607. if length(hs)>1 then
  608. begin
  609. for icond:=low(tasmcond) to high(tasmcond) do
  610. begin
  611. if copy(hs,1,2)=uppercond2str[icond] then
  612. begin
  613. //actcondition:=icond;
  614. oper.opr.typ := OPR_COND;
  615. oper.opr.cc := icond;
  616. exit(true);
  617. end;
  618. end;
  619. end;
  620. end;
  621. end;
  622. var
  623. tempreg : tregister;
  624. ireg : tsuperregister;
  625. regtype: tregistertype;
  626. subreg: tsubregister;
  627. hl : tasmlabel;
  628. {ofs : longint;}
  629. registerset : tcpuregisterset;
  630. Begin
  631. expr:='';
  632. case actasmtoken of
  633. AS_LBRACKET: { Memory reference or constant expression }
  634. Begin
  635. oper.InitRef;
  636. BuildReference(oper);
  637. end;
  638. AS_HASH: { Constant expression }
  639. Begin
  640. Consume(AS_HASH);
  641. BuildConstantOperand(oper);
  642. end;
  643. (*
  644. AS_INTNUM,
  645. AS_MINUS,
  646. AS_PLUS:
  647. Begin
  648. { Constant memory offset }
  649. { This must absolutely be followed by ( }
  650. oper.InitRef;
  651. oper.opr.ref.offset:=BuildConstExpression(True,False);
  652. if actasmtoken<>AS_LPAREN then
  653. begin
  654. ofs:=oper.opr.ref.offset;
  655. BuildConstantOperand(oper);
  656. inc(oper.opr.val,ofs);
  657. end
  658. else
  659. BuildReference(oper);
  660. end;
  661. *)
  662. AS_ID: { A constant expression, or a Variable ref. }
  663. Begin
  664. { Condition code? }
  665. if is_conditioncode(actasmpattern) then
  666. begin
  667. consume(AS_ID);
  668. end
  669. else
  670. { Local Label ? }
  671. if is_locallabel(actasmpattern) then
  672. begin
  673. CreateLocalLabel(actasmpattern,hl,false);
  674. Consume(AS_ID);
  675. AddLabelOperand(hl);
  676. end
  677. else
  678. { Check for label }
  679. if SearchLabel(actasmpattern,hl,false) then
  680. begin
  681. Consume(AS_ID);
  682. AddLabelOperand(hl);
  683. end
  684. else
  685. { probably a variable or normal expression }
  686. { or a procedure (such as in CALL ID) }
  687. Begin
  688. { is it a constant ? }
  689. if SearchIConstant(actasmpattern,l) then
  690. Begin
  691. if not (oper.opr.typ in [OPR_NONE,OPR_CONSTANT]) then
  692. Message(asmr_e_invalid_operand_type);
  693. BuildConstantOperand(oper);
  694. end
  695. else
  696. begin
  697. expr:=actasmpattern;
  698. Consume(AS_ID);
  699. { typecasting? }
  700. if (actasmtoken=AS_LPAREN) and
  701. SearchType(expr,typesize) then
  702. begin
  703. oper.hastype:=true;
  704. Consume(AS_LPAREN);
  705. BuildOperand(oper);
  706. Consume(AS_RPAREN);
  707. if oper.opr.typ in [OPR_REFERENCE,OPR_LOCAL] then
  708. oper.SetSize(typesize,true);
  709. end
  710. else
  711. begin
  712. if not(oper.SetupVar(expr,false)) then
  713. Begin
  714. { look for special symbols ... }
  715. if expr= '__HIGH' then
  716. begin
  717. consume(AS_LPAREN);
  718. if not oper.setupvar('high'+actasmpattern,false) then
  719. Message1(sym_e_unknown_id,'high'+actasmpattern);
  720. consume(AS_ID);
  721. consume(AS_RPAREN);
  722. end
  723. else
  724. if expr = '__RESULT' then
  725. oper.SetUpResult
  726. else
  727. if expr = '__SELF' then
  728. oper.SetupSelf
  729. else
  730. if expr = '__OLDEBP' then
  731. oper.SetupOldEBP
  732. else
  733. Message1(sym_e_unknown_id,expr);
  734. end;
  735. end;
  736. end;
  737. if actasmtoken=AS_DOT then
  738. MaybeRecordOffset;
  739. { add a constant expression? }
  740. if (actasmtoken=AS_PLUS) then
  741. begin
  742. l:=BuildConstExpression(true,false);
  743. case oper.opr.typ of
  744. OPR_CONSTANT :
  745. inc(oper.opr.val,l);
  746. OPR_LOCAL :
  747. inc(oper.opr.localsymofs,l);
  748. OPR_REFERENCE :
  749. inc(oper.opr.ref.offset,l);
  750. else
  751. internalerror(200309202);
  752. end;
  753. end
  754. end;
  755. { Do we have a indexing reference, then parse it also }
  756. if actasmtoken=AS_LPAREN then
  757. BuildReference(oper);
  758. end;
  759. { Register, a variable reference or a constant reference }
  760. AS_REGISTER:
  761. Begin
  762. { save the type of register used. }
  763. tempreg:=actasmregister;
  764. Consume(AS_REGISTER);
  765. if (actasmtoken in [AS_end,AS_SEPARATOR,AS_COMMA]) then
  766. Begin
  767. if not (oper.opr.typ in [OPR_NONE,OPR_REGISTER]) then
  768. Message(asmr_e_invalid_operand_type);
  769. oper.opr.typ:=OPR_REGISTER;
  770. oper.opr.reg:=tempreg;
  771. end
  772. else if (actasmtoken=AS_NOT) and (actopcode in [A_LDM,A_STM,A_FLDM,A_FSTM]) then
  773. begin
  774. consume(AS_NOT);
  775. oper.opr.typ:=OPR_REFERENCE;
  776. oper.opr.ref.addressmode:=AM_PREINDEXED;
  777. oper.opr.ref.index:=tempreg;
  778. end
  779. else
  780. Message(asmr_e_syn_operand);
  781. end;
  782. { Registerset }
  783. AS_LSBRACKET:
  784. begin
  785. consume(AS_LSBRACKET);
  786. registerset:=[];
  787. regtype:=R_INVALIDREGISTER;
  788. subreg:=R_SUBNONE;
  789. while true do
  790. begin
  791. if actasmtoken=AS_REGISTER then
  792. begin
  793. include(registerset,getsupreg(actasmregister));
  794. if regtype<>R_INVALIDREGISTER then
  795. begin
  796. if (getregtype(actasmregister)<>regtype) or
  797. (getsubreg(actasmregister)<>subreg) then
  798. Message(asmr_e_mixing_regtypes);
  799. end
  800. else
  801. begin
  802. regtype:=getregtype(actasmregister);
  803. subreg:=getsubreg(actasmregister);
  804. end;
  805. tempreg:=actasmregister;
  806. consume(AS_REGISTER);
  807. if actasmtoken=AS_MINUS then
  808. begin
  809. consume(AS_MINUS);
  810. for ireg:=getsupreg(tempreg) to getsupreg(actasmregister) do
  811. include(registerset,ireg);
  812. consume(AS_REGISTER);
  813. end;
  814. end
  815. else
  816. consume(AS_REGISTER);
  817. if actasmtoken=AS_COMMA then
  818. consume(AS_COMMA)
  819. else
  820. break;
  821. end;
  822. consume(AS_RSBRACKET);
  823. oper.opr.typ:=OPR_REGSET;
  824. oper.opr.regtype:=regtype;
  825. oper.opr.subreg:=subreg;
  826. oper.opr.regset:=registerset;
  827. if (registerset=[]) then
  828. Message(asmr_e_empty_regset);
  829. end;
  830. AS_end,
  831. AS_SEPARATOR,
  832. AS_COMMA: ;
  833. else
  834. Begin
  835. Message(asmr_e_syn_operand);
  836. Consume(actasmtoken);
  837. end;
  838. end; { end case }
  839. end;
  840. {*****************************************************************************
  841. tarmattreader
  842. *****************************************************************************}
  843. procedure tarmattreader.BuildOpCode(instr : tarminstruction);
  844. var
  845. operandnum : longint;
  846. Begin
  847. { opcode }
  848. if (actasmtoken<>AS_OPCODE) then
  849. Begin
  850. Message(asmr_e_invalid_or_missing_opcode);
  851. RecoverConsume(true);
  852. exit;
  853. end;
  854. { Fill the instr object with the current state }
  855. with instr do
  856. begin
  857. Opcode:=ActOpcode;
  858. condition:=ActCondition;
  859. oppostfix:=actoppostfix;
  860. end;
  861. { We are reading operands, so opcode will be an AS_ID }
  862. operandnum:=1;
  863. Consume(AS_OPCODE);
  864. { Zero operand opcode ? }
  865. if actasmtoken in [AS_SEPARATOR,AS_end] then
  866. begin
  867. operandnum:=0;
  868. exit;
  869. end;
  870. { Read the operands }
  871. repeat
  872. case actasmtoken of
  873. AS_COMMA: { Operand delimiter }
  874. Begin
  875. if ((instr.opcode=A_MOV) and (operandnum=2)) or
  876. ((operandnum=3) and not(instr.opcode in [A_UMLAL,A_UMULL,A_SMLAL,A_SMULL,A_MLA])) then
  877. begin
  878. Consume(AS_COMMA);
  879. if not(TryBuildShifterOp(instr.Operands[operandnum+1] as tarmoperand)) then
  880. Message(asmr_e_illegal_shifterop_syntax);
  881. Inc(operandnum);
  882. end
  883. else
  884. begin
  885. if operandnum>Max_Operands then
  886. Message(asmr_e_too_many_operands)
  887. else
  888. Inc(operandnum);
  889. Consume(AS_COMMA);
  890. end;
  891. end;
  892. AS_SEPARATOR,
  893. AS_end : { End of asm operands for this opcode }
  894. begin
  895. break;
  896. end;
  897. else
  898. BuildOperand(instr.Operands[operandnum] as tarmoperand);
  899. end; { end case }
  900. until false;
  901. instr.Ops:=operandnum;
  902. end;
  903. function tarmattreader.is_asmopcode(const s: string):boolean;
  904. const
  905. { sorted by length so longer postfixes will match first }
  906. postfix2strsorted : array[1..31] of string[3] = (
  907. 'IAD','DBD','FDD','EAD',
  908. 'IAS','DBS','FDS','EAS',
  909. 'IAX','DBX','FDX','EAX',
  910. 'EP','SB','BT','SH',
  911. 'IA','IB','DA','DB','FD','FA','ED','EA',
  912. 'B','D','E','P','T','H','S');
  913. postfixsorted : array[1..31] of TOpPostfix = (
  914. PF_IAD,PF_DBD,PF_FDD,PF_EAD,
  915. PF_IAS,PF_DBS,PF_FDS,PF_EAS,
  916. PF_IAX,PF_DBX,PF_FDX,PF_EAX,
  917. PF_EP,PF_SB,PF_BT,PF_SH,
  918. PF_IA,PF_IB,PF_DA,PF_DB,PF_FD,PF_FA,PF_ED,PF_EA,
  919. PF_B,PF_D,PF_E,PF_P,PF_T,PF_H,PF_S);
  920. var
  921. j : longint;
  922. hs : string;
  923. maxlen : longint;
  924. icond : tasmcond;
  925. Begin
  926. { making s a value parameter would break other assembler readers }
  927. hs:=s;
  928. is_asmopcode:=false;
  929. { clear op code }
  930. actopcode:=A_None;
  931. actcondition:=C_None;
  932. { first, handle B else BLS is read wrong }
  933. if ((hs[1]='B') and (length(hs)=3)) then
  934. begin
  935. for icond:=low(tasmcond) to high(tasmcond) do
  936. begin
  937. if copy(hs,2,3)=uppercond2str[icond] then
  938. begin
  939. actopcode:=A_B;
  940. actasmtoken:=AS_OPCODE;
  941. actcondition:=icond;
  942. is_asmopcode:=true;
  943. exit;
  944. end;
  945. end;
  946. end;
  947. maxlen:=max(length(hs),5);
  948. actopcode:=A_NONE;
  949. for j:=maxlen downto 1 do
  950. begin
  951. actopcode:=tasmop(PtrUInt(iasmops.Find(copy(hs,1,j))));
  952. if actopcode<>A_NONE then
  953. begin
  954. actasmtoken:=AS_OPCODE;
  955. { strip op code }
  956. delete(hs,1,j);
  957. break;
  958. end;
  959. end;
  960. if actopcode=A_NONE then
  961. exit;
  962. { search for condition, conditions are always 2 chars }
  963. if length(hs)>1 then
  964. begin
  965. for icond:=low(tasmcond) to high(tasmcond) do
  966. begin
  967. if copy(hs,1,2)=uppercond2str[icond] then
  968. begin
  969. actcondition:=icond;
  970. { strip condition }
  971. delete(hs,1,2);
  972. break;
  973. end;
  974. end;
  975. end;
  976. { check for postfix }
  977. if length(hs)>0 then
  978. begin
  979. for j:=low(postfixsorted) to high(postfixsorted) do
  980. begin
  981. if copy(hs,1,length(postfix2strsorted[j]))=postfix2strsorted[j] then
  982. begin
  983. actoppostfix:=postfixsorted[j];
  984. { strip postfix }
  985. delete(hs,1,length(postfix2strsorted[j]));
  986. break;
  987. end;
  988. end;
  989. end;
  990. { if we stripped all postfixes, it's a valid opcode }
  991. is_asmopcode:=length(hs)=0;
  992. end;
  993. procedure tarmattreader.ConvertCalljmp(instr : tarminstruction);
  994. var
  995. newopr : toprrec;
  996. begin
  997. if instr.Operands[1].opr.typ=OPR_REFERENCE then
  998. begin
  999. newopr.typ:=OPR_SYMBOL;
  1000. newopr.symbol:=instr.Operands[1].opr.ref.symbol;
  1001. newopr.symofs:=instr.Operands[1].opr.ref.offset;
  1002. if (instr.Operands[1].opr.ref.base<>NR_NO) or
  1003. (instr.Operands[1].opr.ref.index<>NR_NO) then
  1004. Message(asmr_e_syn_operand);
  1005. instr.Operands[1].opr:=newopr;
  1006. end;
  1007. end;
  1008. procedure tarmattreader.handleopcode;
  1009. var
  1010. instr : tarminstruction;
  1011. begin
  1012. instr:=TarmInstruction.Create(TarmOperand);
  1013. BuildOpcode(instr);
  1014. if is_calljmp(instr.opcode) then
  1015. ConvertCalljmp(instr);
  1016. {
  1017. instr.AddReferenceSizes;
  1018. instr.SetInstructionOpsize;
  1019. instr.CheckOperandSizes;
  1020. }
  1021. instr.ConcatInstruction(curlist);
  1022. instr.Free;
  1023. actoppostfix:=PF_None;
  1024. end;
  1025. {*****************************************************************************
  1026. Initialize
  1027. *****************************************************************************}
  1028. const
  1029. asmmode_arm_att_info : tasmmodeinfo =
  1030. (
  1031. id : asmmode_arm_gas;
  1032. idtxt : 'GAS';
  1033. casmreader : tarmattreader;
  1034. );
  1035. asmmode_arm_standard_info : tasmmodeinfo =
  1036. (
  1037. id : asmmode_standard;
  1038. idtxt : 'STANDARD';
  1039. casmreader : tarmattreader;
  1040. );
  1041. initialization
  1042. RegisterAsmMode(asmmode_arm_att_info);
  1043. RegisterAsmMode(asmmode_arm_standard_info);
  1044. end.