raarmgas.pas 43 KB

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