raarmgas.pas 35 KB

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