raarmgas.pas 41 KB

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