raarmgas.pas 40 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282
  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. end;
  515. end;
  516. procedure MaybeRecordOffset;
  517. var
  518. mangledname: string;
  519. hasdot : boolean;
  520. l,
  521. toffset,
  522. tsize : longint;
  523. begin
  524. if not(actasmtoken in [AS_DOT,AS_PLUS,AS_MINUS]) then
  525. exit;
  526. l:=0;
  527. hasdot:=(actasmtoken=AS_DOT);
  528. if hasdot then
  529. begin
  530. if expr<>'' then
  531. begin
  532. BuildRecordOffsetSize(expr,toffset,tsize,mangledname,false);
  533. if (oper.opr.typ<>OPR_CONSTANT) and
  534. (mangledname<>'') then
  535. Message(asmr_e_wrong_sym_type);
  536. inc(l,toffset);
  537. oper.SetSize(tsize,true);
  538. end;
  539. end;
  540. if actasmtoken in [AS_PLUS,AS_MINUS] then
  541. inc(l,BuildConstExpression(true,false));
  542. case oper.opr.typ of
  543. OPR_LOCAL :
  544. begin
  545. { don't allow direct access to fields of parameters, because that
  546. will generate buggy code. Allow it only for explicit typecasting }
  547. if hasdot and
  548. (not oper.hastype) and
  549. (tabstractnormalvarsym(oper.opr.localsym).owner.symtabletype=parasymtable) and
  550. (current_procinfo.procdef.proccalloption<>pocall_register) then
  551. Message(asmr_e_cannot_access_field_directly_for_parameters);
  552. inc(oper.opr.localsymofs,l)
  553. end;
  554. OPR_CONSTANT :
  555. inc(oper.opr.val,l);
  556. OPR_REFERENCE :
  557. if (mangledname<>'') then
  558. begin
  559. if (oper.opr.val<>0) then
  560. Message(asmr_e_wrong_sym_type);
  561. oper.opr.typ:=OPR_SYMBOL;
  562. oper.opr.symbol:=current_asmdata.RefAsmSymbol(mangledname);
  563. end
  564. else
  565. inc(oper.opr.val,l);
  566. OPR_SYMBOL:
  567. Message(asmr_e_invalid_symbol_ref);
  568. else
  569. internalerror(200309221);
  570. end;
  571. end;
  572. function MaybeBuildReference:boolean;
  573. { Try to create a reference, if not a reference is found then false
  574. is returned }
  575. begin
  576. MaybeBuildReference:=true;
  577. case actasmtoken of
  578. AS_INTNUM,
  579. AS_MINUS,
  580. AS_PLUS:
  581. Begin
  582. oper.opr.ref.offset:=BuildConstExpression(True,False);
  583. if actasmtoken<>AS_LPAREN then
  584. Message(asmr_e_invalid_reference_syntax)
  585. else
  586. BuildReference(oper);
  587. end;
  588. AS_LPAREN:
  589. BuildReference(oper);
  590. AS_ID: { only a variable is allowed ... }
  591. Begin
  592. ReadSym(oper);
  593. case actasmtoken of
  594. AS_end,
  595. AS_SEPARATOR,
  596. AS_COMMA: ;
  597. AS_LPAREN:
  598. BuildReference(oper);
  599. else
  600. Begin
  601. Message(asmr_e_invalid_reference_syntax);
  602. Consume(actasmtoken);
  603. end;
  604. end; {end case }
  605. end;
  606. else
  607. MaybeBuildReference:=false;
  608. end; { end case }
  609. end;
  610. function is_ConditionCode(hs: string): boolean;
  611. var icond: tasmcond;
  612. begin
  613. is_ConditionCode := false;
  614. case actopcode of
  615. A_IT,A_ITE,A_ITT,
  616. A_ITEE,A_ITTE,A_ITET,A_ITTT,
  617. A_ITEEE,A_ITTEE,A_ITETE,A_ITTTE,A_ITEET,A_ITTET,A_ITETT,A_ITTTT:
  618. begin
  619. { search for condition, conditions are always 2 chars }
  620. if length(hs)>1 then
  621. begin
  622. for icond:=low(tasmcond) to high(tasmcond) do
  623. begin
  624. if copy(hs,1,2)=uppercond2str[icond] then
  625. begin
  626. //actcondition:=icond;
  627. oper.opr.typ := OPR_COND;
  628. oper.opr.cc := icond;
  629. exit(true);
  630. end;
  631. end;
  632. end;
  633. end;
  634. end;
  635. end;
  636. function is_modeflag(hs : string): boolean;
  637. var
  638. i: longint;
  639. flags: tcpumodeflags;
  640. begin
  641. is_modeflag := false;
  642. flags:=[];
  643. hs:=lower(hs);
  644. if (actopcode in [A_CPSID,A_CPSIE]) and (length(hs) >= 1) then
  645. begin
  646. for i:=1 to length(hs) do
  647. begin
  648. case hs[i] of
  649. 'a':
  650. Include(flags,mfA);
  651. 'f':
  652. Include(flags,mfF);
  653. 'i':
  654. Include(flags,mfI);
  655. else
  656. exit;
  657. end;
  658. end;
  659. oper.opr.typ := OPR_MODEFLAGS;
  660. oper.opr.flags := flags;
  661. exit(true);
  662. end;
  663. end;
  664. var
  665. tempreg : tregister;
  666. ireg : tsuperregister;
  667. regtype: tregistertype;
  668. subreg: tsubregister;
  669. hl : tasmlabel;
  670. {ofs : longint;}
  671. registerset : tcpuregisterset;
  672. Begin
  673. expr:='';
  674. case actasmtoken of
  675. AS_LBRACKET: { Memory reference or constant expression }
  676. Begin
  677. oper.InitRef;
  678. BuildReference(oper);
  679. end;
  680. AS_HASH: { Constant expression }
  681. Begin
  682. Consume(AS_HASH);
  683. BuildConstantOperand(oper);
  684. end;
  685. (*
  686. AS_INTNUM,
  687. AS_MINUS,
  688. AS_PLUS:
  689. Begin
  690. { Constant memory offset }
  691. { This must absolutely be followed by ( }
  692. oper.InitRef;
  693. oper.opr.ref.offset:=BuildConstExpression(True,False);
  694. if actasmtoken<>AS_LPAREN then
  695. begin
  696. ofs:=oper.opr.ref.offset;
  697. BuildConstantOperand(oper);
  698. inc(oper.opr.val,ofs);
  699. end
  700. else
  701. BuildReference(oper);
  702. end;
  703. *)
  704. AS_ID: { A constant expression, or a Variable ref. }
  705. Begin
  706. if is_modeflag(actasmpattern) then
  707. begin
  708. consume(AS_ID);
  709. end
  710. else
  711. { Condition code? }
  712. if is_conditioncode(actasmpattern) then
  713. begin
  714. consume(AS_ID);
  715. end
  716. else
  717. { Local Label ? }
  718. if is_locallabel(actasmpattern) then
  719. begin
  720. CreateLocalLabel(actasmpattern,hl,false);
  721. Consume(AS_ID);
  722. AddLabelOperand(hl);
  723. end
  724. else
  725. { Check for label }
  726. if SearchLabel(actasmpattern,hl,false) then
  727. begin
  728. Consume(AS_ID);
  729. AddLabelOperand(hl);
  730. end
  731. else
  732. { probably a variable or normal expression }
  733. { or a procedure (such as in CALL ID) }
  734. Begin
  735. { is it a constant ? }
  736. if SearchIConstant(actasmpattern,l) then
  737. Begin
  738. if not (oper.opr.typ in [OPR_NONE,OPR_CONSTANT]) then
  739. Message(asmr_e_invalid_operand_type);
  740. BuildConstantOperand(oper);
  741. end
  742. else
  743. begin
  744. expr:=actasmpattern;
  745. Consume(AS_ID);
  746. { typecasting? }
  747. if (actasmtoken=AS_LPAREN) and
  748. SearchType(expr,typesize) then
  749. begin
  750. oper.hastype:=true;
  751. Consume(AS_LPAREN);
  752. BuildOperand(oper);
  753. Consume(AS_RPAREN);
  754. if oper.opr.typ in [OPR_REFERENCE,OPR_LOCAL] then
  755. oper.SetSize(typesize,true);
  756. end
  757. else
  758. begin
  759. if not(oper.SetupVar(expr,false)) then
  760. Begin
  761. { look for special symbols ... }
  762. if expr= '__HIGH' then
  763. begin
  764. consume(AS_LPAREN);
  765. if not oper.setupvar('high'+actasmpattern,false) then
  766. Message1(sym_e_unknown_id,'high'+actasmpattern);
  767. consume(AS_ID);
  768. consume(AS_RPAREN);
  769. end
  770. else
  771. if expr = '__RESULT' then
  772. oper.SetUpResult
  773. else
  774. if expr = '__SELF' then
  775. oper.SetupSelf
  776. else
  777. if expr = '__OLDEBP' then
  778. oper.SetupOldEBP
  779. else
  780. Message1(sym_e_unknown_id,expr);
  781. end;
  782. end;
  783. end;
  784. if actasmtoken=AS_DOT then
  785. MaybeRecordOffset;
  786. { add a constant expression? }
  787. if (actasmtoken=AS_PLUS) then
  788. begin
  789. l:=BuildConstExpression(true,false);
  790. case oper.opr.typ of
  791. OPR_CONSTANT :
  792. inc(oper.opr.val,l);
  793. OPR_LOCAL :
  794. inc(oper.opr.localsymofs,l);
  795. OPR_REFERENCE :
  796. inc(oper.opr.ref.offset,l);
  797. else
  798. internalerror(200309202);
  799. end;
  800. end
  801. end;
  802. { Do we have a indexing reference, then parse it also }
  803. if actasmtoken=AS_LPAREN then
  804. BuildReference(oper);
  805. end;
  806. { Register, a variable reference or a constant reference }
  807. AS_REGISTER:
  808. Begin
  809. { save the type of register used. }
  810. tempreg:=actasmregister;
  811. Consume(AS_REGISTER);
  812. if (actasmtoken in [AS_end,AS_SEPARATOR,AS_COMMA]) then
  813. Begin
  814. if not (oper.opr.typ in [OPR_NONE,OPR_REGISTER]) then
  815. Message(asmr_e_invalid_operand_type);
  816. oper.opr.typ:=OPR_REGISTER;
  817. oper.opr.reg:=tempreg;
  818. end
  819. else if (actasmtoken=AS_NOT) and (actopcode in [A_LDM,A_STM,A_FLDM,A_FSTM]) then
  820. begin
  821. consume(AS_NOT);
  822. oper.opr.typ:=OPR_REFERENCE;
  823. oper.opr.ref.addressmode:=AM_PREINDEXED;
  824. oper.opr.ref.index:=tempreg;
  825. end
  826. else
  827. Message(asmr_e_syn_operand);
  828. end;
  829. { Registerset }
  830. AS_LSBRACKET:
  831. begin
  832. consume(AS_LSBRACKET);
  833. registerset:=[];
  834. regtype:=R_INVALIDREGISTER;
  835. subreg:=R_SUBNONE;
  836. while true do
  837. begin
  838. if actasmtoken=AS_REGISTER then
  839. begin
  840. include(registerset,getsupreg(actasmregister));
  841. if regtype<>R_INVALIDREGISTER then
  842. begin
  843. if (getregtype(actasmregister)<>regtype) or
  844. (getsubreg(actasmregister)<>subreg) then
  845. Message(asmr_e_mixing_regtypes);
  846. end
  847. else
  848. begin
  849. regtype:=getregtype(actasmregister);
  850. subreg:=getsubreg(actasmregister);
  851. end;
  852. tempreg:=actasmregister;
  853. consume(AS_REGISTER);
  854. if actasmtoken=AS_MINUS then
  855. begin
  856. consume(AS_MINUS);
  857. for ireg:=getsupreg(tempreg) to getsupreg(actasmregister) do
  858. include(registerset,ireg);
  859. consume(AS_REGISTER);
  860. end;
  861. end
  862. else
  863. consume(AS_REGISTER);
  864. if actasmtoken=AS_COMMA then
  865. consume(AS_COMMA)
  866. else
  867. break;
  868. end;
  869. consume(AS_RSBRACKET);
  870. oper.opr.typ:=OPR_REGSET;
  871. oper.opr.regtype:=regtype;
  872. oper.opr.subreg:=subreg;
  873. oper.opr.regset:=registerset;
  874. if actasmtoken=AS_XOR then
  875. begin
  876. consume(AS_XOR);
  877. oper.opr.usermode:=true;
  878. end
  879. else
  880. oper.opr.usermode:=false;
  881. if (registerset=[]) then
  882. Message(asmr_e_empty_regset);
  883. end;
  884. AS_end,
  885. AS_SEPARATOR,
  886. AS_COMMA: ;
  887. else
  888. Begin
  889. Message(asmr_e_syn_operand);
  890. Consume(actasmtoken);
  891. end;
  892. end; { end case }
  893. end;
  894. procedure tarmattreader.BuildSpecialreg(oper: tarmoperand);
  895. var
  896. hs, reg : String;
  897. ch : char;
  898. i, t : longint;
  899. hreg : tregister;
  900. flags : tspecialregflags;
  901. begin
  902. case actasmtoken of
  903. AS_REGISTER:
  904. begin
  905. oper.opr.typ:=OPR_REGISTER;
  906. oper.opr.reg:=actasmregister;
  907. Consume(AS_REGISTER);
  908. end;
  909. AS_ID:
  910. begin
  911. t := pos('_', actasmpattern);
  912. if t > 0 then
  913. begin
  914. hs:=lower(actasmpattern);
  915. reg:=copy(hs, 1, t-1);
  916. delete(hs, 1, t);
  917. if length(hs) < 1 then
  918. Message(asmr_e_invalid_operand_type);
  919. if reg = 'cpsr' then
  920. hreg:=NR_CPSR
  921. else if reg='spsr' then
  922. hreg:=NR_SPSR
  923. else
  924. Message(asmr_e_invalid_register);
  925. flags:=[];
  926. for i := 1 to length(hs) do
  927. begin
  928. ch:=hs[i];
  929. if ch='c' then
  930. include(flags, srC)
  931. else if ch='x' then
  932. include(flags, srX)
  933. else if ch='f' then
  934. include(flags, srF)
  935. else if ch='s' then
  936. include(flags, srS)
  937. else
  938. message(asmr_e_invalid_operand_type);
  939. end;
  940. oper.opr.typ:=OPR_SPECIALREG;
  941. oper.opr.specialreg:=hreg;
  942. oper.opr.specialregflags:=flags;
  943. consume(AS_ID);
  944. end
  945. else
  946. Message(asmr_e_invalid_operand_type); // Otherwise it would have been seen as a AS_REGISTER
  947. end;
  948. end;
  949. end;
  950. {*****************************************************************************
  951. tarmattreader
  952. *****************************************************************************}
  953. procedure tarmattreader.BuildOpCode(instr : tarminstruction);
  954. var
  955. operandnum : longint;
  956. Begin
  957. { opcode }
  958. if (actasmtoken<>AS_OPCODE) then
  959. Begin
  960. Message(asmr_e_invalid_or_missing_opcode);
  961. RecoverConsume(true);
  962. exit;
  963. end;
  964. { Fill the instr object with the current state }
  965. with instr do
  966. begin
  967. Opcode:=ActOpcode;
  968. condition:=ActCondition;
  969. oppostfix:=actoppostfix;
  970. wideformat:=actwideformat;
  971. end;
  972. { We are reading operands, so opcode will be an AS_ID }
  973. operandnum:=1;
  974. Consume(AS_OPCODE);
  975. { Zero operand opcode ? }
  976. if actasmtoken in [AS_SEPARATOR,AS_end] then
  977. begin
  978. operandnum:=0;
  979. exit;
  980. end;
  981. { Read the operands }
  982. repeat
  983. case actasmtoken of
  984. AS_COMMA: { Operand delimiter }
  985. Begin
  986. if ((instr.opcode in [A_MOV, A_MVN, A_CMP, A_CMN, A_TST, A_TEQ]) and (operandnum=2)) or
  987. ((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
  988. begin
  989. Consume(AS_COMMA);
  990. if not(TryBuildShifterOp(instr.Operands[operandnum+1] as tarmoperand)) then
  991. Message(asmr_e_illegal_shifterop_syntax);
  992. Inc(operandnum);
  993. end
  994. else
  995. begin
  996. if operandnum>Max_Operands then
  997. Message(asmr_e_too_many_operands)
  998. else
  999. Inc(operandnum);
  1000. Consume(AS_COMMA);
  1001. end;
  1002. end;
  1003. AS_SEPARATOR,
  1004. AS_end : { End of asm operands for this opcode }
  1005. begin
  1006. break;
  1007. end;
  1008. else
  1009. if (instr.opcode = A_MSR) and (operandnum = 1) then
  1010. BuildSpecialreg(instr.Operands[operandnum] as tarmoperand)
  1011. else
  1012. BuildOperand(instr.Operands[operandnum] as tarmoperand);
  1013. end; { end case }
  1014. until false;
  1015. instr.Ops:=operandnum;
  1016. end;
  1017. function tarmattreader.is_asmopcode(const s: string):boolean;
  1018. const
  1019. { sorted by length so longer postfixes will match first }
  1020. postfix2strsorted : array[1..31] of string[3] = (
  1021. 'IAD','DBD','FDD','EAD',
  1022. 'IAS','DBS','FDS','EAS',
  1023. 'IAX','DBX','FDX','EAX',
  1024. 'EP','SB','BT','SH',
  1025. 'IA','IB','DA','DB','FD','FA','ED','EA',
  1026. 'B','D','E','P','T','H','S');
  1027. postfixsorted : array[1..31] of TOpPostfix = (
  1028. PF_IAD,PF_DBD,PF_FDD,PF_EAD,
  1029. PF_IAS,PF_DBS,PF_FDS,PF_EAS,
  1030. PF_IAX,PF_DBX,PF_FDX,PF_EAX,
  1031. PF_EP,PF_SB,PF_BT,PF_SH,
  1032. PF_IA,PF_IB,PF_DA,PF_DB,PF_FD,PF_FA,PF_ED,PF_EA,
  1033. PF_B,PF_D,PF_E,PF_P,PF_T,PF_H,PF_S);
  1034. var
  1035. j : longint;
  1036. hs : string;
  1037. maxlen : longint;
  1038. icond : tasmcond;
  1039. Begin
  1040. { making s a value parameter would break other assembler readers }
  1041. hs:=s;
  1042. is_asmopcode:=false;
  1043. { clear op code }
  1044. actopcode:=A_None;
  1045. actcondition:=C_None;
  1046. { first, handle B else BLS is read wrong }
  1047. if ((hs[1]='B') and (length(hs)=3)) then
  1048. begin
  1049. for icond:=low(tasmcond) to high(tasmcond) do
  1050. begin
  1051. if copy(hs,2,3)=uppercond2str[icond] then
  1052. begin
  1053. actopcode:=A_B;
  1054. actasmtoken:=AS_OPCODE;
  1055. actcondition:=icond;
  1056. is_asmopcode:=true;
  1057. exit;
  1058. end;
  1059. end;
  1060. end;
  1061. maxlen:=max(length(hs),5);
  1062. actopcode:=A_NONE;
  1063. for j:=maxlen downto 1 do
  1064. begin
  1065. actopcode:=tasmop(PtrUInt(iasmops.Find(copy(hs,1,j))));
  1066. if actopcode<>A_NONE then
  1067. begin
  1068. actasmtoken:=AS_OPCODE;
  1069. { strip op code }
  1070. delete(hs,1,j);
  1071. break;
  1072. end;
  1073. end;
  1074. if actopcode=A_NONE then
  1075. exit;
  1076. { search for condition, conditions are always 2 chars }
  1077. if length(hs)>1 then
  1078. begin
  1079. for icond:=low(tasmcond) to high(tasmcond) do
  1080. begin
  1081. if copy(hs,1,2)=uppercond2str[icond] then
  1082. begin
  1083. actcondition:=icond;
  1084. { strip condition }
  1085. delete(hs,1,2);
  1086. break;
  1087. end;
  1088. end;
  1089. end;
  1090. { check for postfix }
  1091. if length(hs)>0 then
  1092. begin
  1093. for j:=low(postfixsorted) to high(postfixsorted) do
  1094. begin
  1095. if copy(hs,1,length(postfix2strsorted[j]))=postfix2strsorted[j] then
  1096. begin
  1097. actoppostfix:=postfixsorted[j];
  1098. { strip postfix }
  1099. delete(hs,1,length(postfix2strsorted[j]));
  1100. break;
  1101. end;
  1102. end;
  1103. end;
  1104. { check for format postfix }
  1105. if length(hs)>0 then
  1106. begin
  1107. if upcase(copy(hs,1,2)) = '.W' then
  1108. begin
  1109. actwideformat:=true;
  1110. delete(hs,1,2);
  1111. end;
  1112. end;
  1113. { if we stripped all postfixes, it's a valid opcode }
  1114. is_asmopcode:=length(hs)=0;
  1115. end;
  1116. procedure tarmattreader.ConvertCalljmp(instr : tarminstruction);
  1117. var
  1118. newopr : toprrec;
  1119. begin
  1120. if instr.Operands[1].opr.typ=OPR_REFERENCE then
  1121. begin
  1122. newopr.typ:=OPR_SYMBOL;
  1123. newopr.symbol:=instr.Operands[1].opr.ref.symbol;
  1124. newopr.symofs:=instr.Operands[1].opr.ref.offset;
  1125. if (instr.Operands[1].opr.ref.base<>NR_NO) or
  1126. (instr.Operands[1].opr.ref.index<>NR_NO) then
  1127. Message(asmr_e_syn_operand);
  1128. instr.Operands[1].opr:=newopr;
  1129. end;
  1130. end;
  1131. procedure tarmattreader.HandleTargetDirective;
  1132. var
  1133. symname,
  1134. symval : String;
  1135. val : aint;
  1136. symtyp : TAsmsymtype;
  1137. begin
  1138. if actasmpattern='.thumb_set' then
  1139. begin
  1140. consume(AS_TARGET_DIRECTIVE);
  1141. BuildConstSymbolExpression(true,false,false, val,symname,symtyp);
  1142. Consume(AS_COMMA);
  1143. BuildConstSymbolExpression(true,false,false, val,symval,symtyp);
  1144. curList.concat(tai_thumb_set.create(symname,symval));
  1145. end
  1146. else if actasmpattern='.thumb_func' then
  1147. begin
  1148. consume(AS_TARGET_DIRECTIVE);
  1149. curList.concat(tai_thumb_func.create);
  1150. end
  1151. else
  1152. inherited HandleTargetDirective;
  1153. end;
  1154. procedure tarmattreader.handleopcode;
  1155. var
  1156. instr : tarminstruction;
  1157. begin
  1158. instr:=TarmInstruction.Create(TarmOperand);
  1159. BuildOpcode(instr);
  1160. if is_calljmp(instr.opcode) then
  1161. ConvertCalljmp(instr);
  1162. {
  1163. instr.AddReferenceSizes;
  1164. instr.SetInstructionOpsize;
  1165. instr.CheckOperandSizes;
  1166. }
  1167. instr.ConcatInstruction(curlist);
  1168. instr.Free;
  1169. actoppostfix:=PF_None;
  1170. actwideformat:=false;
  1171. end;
  1172. {*****************************************************************************
  1173. Initialize
  1174. *****************************************************************************}
  1175. const
  1176. asmmode_arm_att_info : tasmmodeinfo =
  1177. (
  1178. id : asmmode_arm_gas;
  1179. idtxt : 'GAS';
  1180. casmreader : tarmattreader;
  1181. );
  1182. asmmode_arm_standard_info : tasmmodeinfo =
  1183. (
  1184. id : asmmode_standard;
  1185. idtxt : 'STANDARD';
  1186. casmreader : tarmattreader;
  1187. );
  1188. initialization
  1189. RegisterAsmMode(asmmode_arm_att_info);
  1190. RegisterAsmMode(asmmode_arm_standard_info);
  1191. end.