rappcgas.pas 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747
  1. {
  2. $Id: rappcgas.pas,v 1.19 2005/02/14 17:13:10 peter Exp $
  3. Copyright (c) 1998-2002 by Carl Eric Codere and Peter Vreman
  4. Does the parsing for the PowerPC GNU AS styled inline assembler.
  5. This program is free software; you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License as published by
  7. the Free Software Foundation; either version 2 of the License, or
  8. (at your option) any later version.
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with this program; if not, write to the Free Software
  15. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  16. ****************************************************************************
  17. }
  18. unit rappcgas;
  19. {$I fpcdefs.inc}
  20. interface
  21. uses
  22. raatt, rappc;
  23. type
  24. tppcattreader = class(tattreader)
  25. function is_asmopcode(const s: string): boolean; override;
  26. procedure handleopcode; override;
  27. procedure BuildReference(oper: tppcoperand);
  28. procedure BuildOperand(oper: tppcoperand);
  29. procedure BuildOpCode(instr: tppcinstruction);
  30. procedure ReadAt(oper: tppcoperand);
  31. procedure ReadSym(oper: tppcoperand);
  32. procedure ConvertCalljmp(instr: tppcinstruction);
  33. end;
  34. implementation
  35. uses
  36. { helpers }
  37. cutils,
  38. { global }
  39. globtype, verbose,
  40. systems,
  41. { aasm }
  42. cpubase, aasmbase, aasmtai, aasmcpu,
  43. { symtable }
  44. symconst, symsym,
  45. { parser }
  46. procinfo,
  47. rabase, rautils,
  48. cgbase, cgobj
  49. ;
  50. procedure tppcattreader.ReadSym(oper: tppcoperand);
  51. var
  52. tempstr: string;
  53. typesize, l, k: aint;
  54. begin
  55. tempstr := actasmpattern;
  56. Consume(AS_ID);
  57. { typecasting? }
  58. if (actasmtoken = AS_LPAREN) and
  59. SearchType(tempstr, typesize) then
  60. begin
  61. oper.hastype := true;
  62. Consume(AS_LPAREN);
  63. BuildOperand(oper);
  64. Consume(AS_RPAREN);
  65. if oper.opr.typ in [OPR_REFERENCE, OPR_LOCAL] then
  66. oper.SetSize(typesize, true);
  67. end
  68. else if not oper.SetupVar(tempstr, false) then
  69. Message1(sym_e_unknown_id, tempstr);
  70. { record.field ? }
  71. if actasmtoken = AS_DOT then
  72. begin
  73. BuildRecordOffsetSize(tempstr, l, k);
  74. inc(oper.opr.ref.offset, l);
  75. end;
  76. end;
  77. procedure tppcattreader.ReadAt(oper: tppcoperand);
  78. begin
  79. { check for ...@ }
  80. if actasmtoken = AS_AT then
  81. begin
  82. if (oper.opr.ref.symbol = nil) and
  83. (oper.opr.ref.offset = 0) then
  84. Message(asmr_e_invalid_reference_syntax);
  85. Consume(AS_AT);
  86. if actasmtoken = AS_ID then
  87. begin
  88. if upper(actasmpattern) = 'L' then
  89. oper.opr.ref.refaddr := addr_low
  90. else if upper(actasmpattern) = 'HA' then
  91. oper.opr.ref.refaddr := addr_higha
  92. else if upper(actasmpattern) = 'H' then
  93. oper.opr.ref.refaddr := addr_high
  94. else if upper(actasmpattern) = 'HIGHERA' then
  95. oper.opr.ref.refaddr := addr_highera
  96. else if upper(actasmpattern) = 'HIGHESTA' then
  97. oper.opr.ref.refaddr := addr_highesta
  98. else if upper(actasmpattern) = 'HIGHER' then
  99. oper.opr.ref.refaddr := addr_higher
  100. else if upper(actasmpattern) = 'HIGHEST' then
  101. oper.opr.ref.refaddr := addr_highest
  102. else
  103. Message(asmr_e_invalid_reference_syntax);
  104. Consume(AS_ID);
  105. end
  106. else
  107. Message(asmr_e_invalid_reference_syntax);
  108. end;
  109. end;
  110. procedure tppcattreader.BuildReference(oper: tppcoperand);
  111. procedure Consume_RParen;
  112. begin
  113. if actasmtoken <> AS_RPAREN then
  114. begin
  115. Message(asmr_e_invalid_reference_syntax);
  116. RecoverConsume(true);
  117. end
  118. else
  119. begin
  120. Consume(AS_RPAREN);
  121. if not (actasmtoken in [AS_COMMA, AS_SEPARATOR, AS_END]) then
  122. begin
  123. Message(asmr_e_invalid_reference_syntax);
  124. RecoverConsume(true);
  125. end;
  126. end;
  127. end;
  128. var
  129. l: aint;
  130. begin
  131. Consume(AS_LPAREN);
  132. case actasmtoken of
  133. AS_INTNUM,
  134. AS_MINUS,
  135. AS_PLUS:
  136. begin
  137. { offset(offset) is invalid }
  138. if oper.opr.Ref.Offset <> 0 then
  139. begin
  140. Message(asmr_e_invalid_reference_syntax);
  141. RecoverConsume(true);
  142. end
  143. else
  144. begin
  145. oper.opr.Ref.Offset := BuildConstExpression(false, true);
  146. Consume(AS_RPAREN);
  147. if actasmtoken = AS_AT then
  148. ReadAt(oper);
  149. end;
  150. exit;
  151. end;
  152. AS_REGISTER: { (reg ... }
  153. begin
  154. if ((oper.opr.typ = OPR_REFERENCE) and (oper.opr.ref.base <> NR_NO)) or
  155. ((oper.opr.typ = OPR_LOCAL) and (oper.opr.localsym.localloc.loc <>
  156. LOC_REGISTER)) then
  157. message(asmr_e_cannot_index_relative_var);
  158. oper.opr.ref.base := actasmregister;
  159. Consume(AS_REGISTER);
  160. { can either be a register or a right parenthesis }
  161. { (reg) }
  162. if actasmtoken = AS_RPAREN then
  163. begin
  164. Consume_RParen;
  165. exit;
  166. end;
  167. { (reg,reg .. }
  168. Consume(AS_COMMA);
  169. if (actasmtoken = AS_REGISTER) and
  170. (oper.opr.Ref.Offset = 0) then
  171. begin
  172. oper.opr.ref.index := actasmregister;
  173. Consume(AS_REGISTER);
  174. Consume_RParen;
  175. end
  176. else
  177. begin
  178. Message(asmr_e_invalid_reference_syntax);
  179. RecoverConsume(false);
  180. end;
  181. end; {end case }
  182. AS_ID:
  183. begin
  184. ReadSym(oper);
  185. { add a constant expression? }
  186. if (actasmtoken = AS_PLUS) then
  187. begin
  188. l := BuildConstExpression(true, true);
  189. case oper.opr.typ of
  190. OPR_CONSTANT:
  191. inc(oper.opr.val, l);
  192. OPR_LOCAL:
  193. inc(oper.opr.localsymofs, l);
  194. OPR_REFERENCE:
  195. inc(oper.opr.ref.offset, l);
  196. else
  197. internalerror(200309202);
  198. end;
  199. end;
  200. Consume(AS_RPAREN);
  201. if actasmtoken = AS_AT then
  202. ReadAt(oper);
  203. end;
  204. AS_COMMA: { (, ... can either be scaling, or index }
  205. begin
  206. Consume(AS_COMMA);
  207. { Index }
  208. if (actasmtoken = AS_REGISTER) then
  209. begin
  210. oper.opr.ref.index := actasmregister;
  211. Consume(AS_REGISTER);
  212. { check for scaling ... }
  213. Consume_RParen;
  214. end
  215. else
  216. begin
  217. Message(asmr_e_invalid_reference_syntax);
  218. RecoverConsume(false);
  219. end;
  220. end;
  221. else
  222. begin
  223. Message(asmr_e_invalid_reference_syntax);
  224. RecoverConsume(false);
  225. end;
  226. end;
  227. end;
  228. procedure tppcattreader.BuildOperand(oper: tppcoperand);
  229. var
  230. expr: string;
  231. typesize, l: aint;
  232. procedure AddLabelOperand(hl: tasmlabel);
  233. begin
  234. if not (actasmtoken in [AS_PLUS, AS_MINUS, AS_LPAREN]) and
  235. is_calljmp(actopcode) then
  236. begin
  237. oper.opr.typ := OPR_SYMBOL;
  238. oper.opr.symbol := hl;
  239. end
  240. else
  241. begin
  242. oper.InitRef;
  243. oper.opr.ref.symbol := hl;
  244. end;
  245. end;
  246. procedure MaybeRecordOffset;
  247. var
  248. hasdot: boolean;
  249. l,
  250. toffset,
  251. tsize: aint;
  252. begin
  253. if not (actasmtoken in [AS_DOT, AS_PLUS, AS_MINUS]) then
  254. exit;
  255. l := 0;
  256. hasdot := (actasmtoken = AS_DOT);
  257. if hasdot then
  258. begin
  259. if expr <> '' then
  260. begin
  261. BuildRecordOffsetSize(expr, toffset, tsize);
  262. inc(l, toffset);
  263. oper.SetSize(tsize, true);
  264. end;
  265. end;
  266. if actasmtoken in [AS_PLUS, AS_MINUS] then
  267. inc(l, BuildConstExpression(true, false));
  268. case oper.opr.typ of
  269. OPR_LOCAL:
  270. begin
  271. { don't allow direct access to fields of parameters, because that
  272. will generate buggy code. Allow it only for explicit typecasting }
  273. if hasdot and
  274. (not oper.hastype) and
  275. (tabstractvarsym(oper.opr.localsym).owner.symtabletype =
  276. parasymtable) and
  277. (current_procinfo.procdef.proccalloption <> pocall_register) then
  278. Message(asmr_e_cannot_access_field_directly_for_parameters);
  279. inc(oper.opr.localsymofs, l)
  280. end;
  281. OPR_CONSTANT:
  282. inc(oper.opr.val, l);
  283. OPR_REFERENCE:
  284. inc(oper.opr.ref.offset, l);
  285. else
  286. internalerror(200309221);
  287. end;
  288. end;
  289. function MaybeBuildReference: boolean;
  290. { Try to create a reference, if not a reference is found then false
  291. is returned }
  292. begin
  293. MaybeBuildReference := true;
  294. case actasmtoken of
  295. AS_INTNUM,
  296. AS_MINUS,
  297. AS_PLUS:
  298. begin
  299. oper.opr.ref.offset := BuildConstExpression(True, False);
  300. if actasmtoken <> AS_LPAREN then
  301. Message(asmr_e_invalid_reference_syntax)
  302. else
  303. BuildReference(oper);
  304. end;
  305. AS_LPAREN:
  306. BuildReference(oper);
  307. AS_ID: { only a variable is allowed ... }
  308. begin
  309. ReadSym(oper);
  310. case actasmtoken of
  311. AS_END,
  312. AS_SEPARATOR,
  313. AS_COMMA: ;
  314. AS_LPAREN:
  315. BuildReference(oper);
  316. else
  317. begin
  318. Message(asmr_e_invalid_reference_syntax);
  319. Consume(actasmtoken);
  320. end;
  321. end; {end case }
  322. end;
  323. else
  324. MaybeBuildReference := false;
  325. end; { end case }
  326. end;
  327. var
  328. tempreg: tregister;
  329. hl: tasmlabel;
  330. ofs: aint;
  331. begin
  332. expr := '';
  333. case actasmtoken of
  334. AS_LPAREN: { Memory reference or constant expression }
  335. begin
  336. oper.InitRef;
  337. BuildReference(oper);
  338. end;
  339. AS_INTNUM,
  340. AS_MINUS,
  341. AS_PLUS:
  342. begin
  343. { Constant memory offset }
  344. { This must absolutely be followed by ( }
  345. oper.InitRef;
  346. oper.opr.ref.offset := BuildConstExpression(True, False);
  347. if actasmtoken <> AS_LPAREN then
  348. begin
  349. ofs := oper.opr.ref.offset;
  350. BuildConstantOperand(oper);
  351. inc(oper.opr.val, ofs);
  352. end
  353. else
  354. BuildReference(oper);
  355. end;
  356. AS_ID: { A constant expression, or a Variable ref. }
  357. begin
  358. { Local Label ? }
  359. if is_locallabel(actasmpattern) then
  360. begin
  361. CreateLocalLabel(actasmpattern, hl, false);
  362. Consume(AS_ID);
  363. AddLabelOperand(hl);
  364. end
  365. else
  366. { Check for label } if SearchLabel(actasmpattern, hl, false) then
  367. begin
  368. Consume(AS_ID);
  369. AddLabelOperand(hl);
  370. end
  371. else
  372. { probably a variable or normal expression }
  373. { or a procedure (such as in CALL ID) }
  374. begin
  375. { is it a constant ? }
  376. if SearchIConstant(actasmpattern, l) then
  377. begin
  378. if not (oper.opr.typ in [OPR_NONE, OPR_CONSTANT]) then
  379. Message(asmr_e_invalid_operand_type);
  380. BuildConstantOperand(oper);
  381. end
  382. else
  383. begin
  384. expr := actasmpattern;
  385. Consume(AS_ID);
  386. { typecasting? }
  387. if (actasmtoken = AS_LPAREN) and
  388. SearchType(expr, typesize) then
  389. begin
  390. oper.hastype := true;
  391. Consume(AS_LPAREN);
  392. BuildOperand(oper);
  393. Consume(AS_RPAREN);
  394. if oper.opr.typ in [OPR_REFERENCE, OPR_LOCAL] then
  395. oper.SetSize(typesize, true);
  396. end
  397. else
  398. begin
  399. if oper.SetupVar(expr, false) then
  400. ReadAt(oper)
  401. else
  402. begin
  403. { look for special symbols ... }
  404. if expr = '__HIGH' then
  405. begin
  406. consume(AS_LPAREN);
  407. if not oper.setupvar('high' + actasmpattern, false) then
  408. Message1(sym_e_unknown_id, 'high' + actasmpattern);
  409. consume(AS_ID);
  410. consume(AS_RPAREN);
  411. end
  412. else if expr = '__RESULT' then
  413. oper.SetUpResult
  414. else if expr = '__SELF' then
  415. oper.SetupSelf
  416. else if expr = '__OLDEBP' then
  417. oper.SetupOldEBP
  418. else
  419. Message1(sym_e_unknown_id, expr);
  420. end;
  421. end;
  422. end;
  423. if actasmtoken = AS_DOT then
  424. MaybeRecordOffset;
  425. { add a constant expression? }
  426. if (actasmtoken = AS_PLUS) then
  427. begin
  428. l := BuildConstExpression(true, false);
  429. case oper.opr.typ of
  430. OPR_CONSTANT:
  431. inc(oper.opr.val, l);
  432. OPR_LOCAL:
  433. inc(oper.opr.localsymofs, l);
  434. OPR_REFERENCE:
  435. inc(oper.opr.ref.offset, l);
  436. else
  437. internalerror(200309202);
  438. end;
  439. end
  440. end;
  441. { Do we have a indexing reference, then parse it also }
  442. if actasmtoken = AS_LPAREN then
  443. BuildReference(oper);
  444. end;
  445. AS_REGISTER: { Register, a variable reference or a constant reference }
  446. begin
  447. { save the type of register used. }
  448. tempreg := actasmregister;
  449. Consume(AS_REGISTER);
  450. if (actasmtoken in [AS_END, AS_SEPARATOR, AS_COMMA]) then
  451. if is_condreg(tempreg) and
  452. ((actopcode = A_BC) or
  453. (actopcode = A_BCCTR) or
  454. (actopcode = A_BCLR) or
  455. (actopcode = A_TW) or
  456. (actopcode = A_TWI)) then
  457. begin
  458. { it isn't a real operand, everything is stored in the condition }
  459. oper.opr.typ := OPR_NONE;
  460. actcondition.cr := getsupreg(tempreg);
  461. end
  462. else
  463. begin
  464. if not (oper.opr.typ in [OPR_NONE, OPR_REGISTER]) then
  465. Message(asmr_e_invalid_operand_type);
  466. oper.opr.typ := OPR_REGISTER;
  467. oper.opr.reg := tempreg;
  468. end
  469. else if is_condreg(tempreg) then
  470. begin
  471. if not (actcondition.cond in [C_T..C_DZF]) then
  472. Message(asmr_e_syn_operand);
  473. if actasmtoken = AS_STAR then
  474. begin
  475. consume(AS_STAR);
  476. if (actasmtoken = AS_INTNUM) then
  477. begin
  478. consume(AS_INTNUM);
  479. if actasmtoken = AS_PLUS then
  480. begin
  481. consume(AS_PLUS);
  482. if (actasmtoken = AS_ID) then
  483. begin
  484. oper.opr.typ := OPR_NONE;
  485. if actasmpattern = 'LT' then
  486. actcondition.crbit := (getsupreg(tempreg) - (RS_CR0)) * 4
  487. else if actasmpattern = 'GT' then
  488. actcondition.crbit := (getsupreg(tempreg) - (RS_CR0)) * 4 + 1
  489. else if actasmpattern = 'EQ' then
  490. actcondition.crbit := (getsupreg(tempreg) - (RS_CR0)) * 4 + 2
  491. else if actasmpattern = 'SO' then
  492. actcondition.crbit := (getsupreg(tempreg) - (RS_CR0)) * 4 + 3
  493. else
  494. Message(asmr_e_syn_operand);
  495. consume(AS_ID);
  496. end
  497. else
  498. Message(asmr_e_syn_operand);
  499. end
  500. else
  501. Message(asmr_e_syn_operand);
  502. end
  503. else
  504. Message(asmr_e_syn_operand);
  505. end
  506. else
  507. Message(asmr_e_syn_operand);
  508. end
  509. else
  510. Message(asmr_e_syn_operand);
  511. end;
  512. AS_END,
  513. AS_SEPARATOR,
  514. AS_COMMA: ;
  515. else
  516. begin
  517. Message(asmr_e_syn_operand);
  518. Consume(actasmtoken);
  519. end;
  520. end; { end case }
  521. end;
  522. {*****************************************************************************
  523. tppcattreader
  524. *****************************************************************************}
  525. procedure tppcattreader.BuildOpCode(instr: tppcinstruction);
  526. var
  527. operandnum: longint;
  528. begin
  529. { opcode }
  530. if (actasmtoken <> AS_OPCODE) then
  531. begin
  532. Message(asmr_e_invalid_or_missing_opcode);
  533. RecoverConsume(true);
  534. exit;
  535. end;
  536. { Fill the instr object with the current state }
  537. with instr do
  538. begin
  539. Opcode := ActOpcode;
  540. condition := ActCondition;
  541. end;
  542. { We are reading operands, so opcode will be an AS_ID }
  543. operandnum := 1;
  544. Consume(AS_OPCODE);
  545. { Zero operand opcode ? }
  546. if actasmtoken in [AS_SEPARATOR, AS_END] then
  547. begin
  548. operandnum := 0;
  549. exit;
  550. end;
  551. { Read the operands }
  552. repeat
  553. case actasmtoken of
  554. AS_COMMA: { Operand delimiter }
  555. begin
  556. if operandnum > Max_Operands then
  557. Message(asmr_e_too_many_operands)
  558. else
  559. begin
  560. { condition operands doesn't set the operand but write to the
  561. condition field of the instruction
  562. }
  563. if instr.Operands[operandnum].opr.typ <> OPR_NONE then
  564. Inc(operandnum);
  565. end;
  566. Consume(AS_COMMA);
  567. end;
  568. AS_SEPARATOR,
  569. AS_END: { End of asm operands for this opcode }
  570. begin
  571. break;
  572. end;
  573. else
  574. BuildOperand(instr.Operands[operandnum] as tppcoperand);
  575. end; { end case }
  576. until false;
  577. if (operandnum = 1) and (instr.Operands[operandnum].opr.typ = OPR_NONE) then
  578. dec(operandnum);
  579. instr.Ops := operandnum;
  580. end;
  581. function tppcattreader.is_asmopcode(const s: string): boolean;
  582. var
  583. str2opentry: tstr2opentry;
  584. cond: tasmcondflag;
  585. hs: string;
  586. begin
  587. { making s a value parameter would break other assembler readers }
  588. hs := s;
  589. is_asmopcode := false;
  590. { clear op code }
  591. actopcode := A_None;
  592. { clear condition }
  593. fillchar(actcondition, sizeof(actcondition), 0);
  594. { check for direction hint }
  595. if hs[length(s)] = '-' then
  596. begin
  597. dec(ord(hs[0]));
  598. actcondition.dirhint := DH_Minus;
  599. end
  600. else if hs[length(s)] = '+' then
  601. begin
  602. dec(ord(hs[0]));
  603. actcondition.dirhint := DH_Plus;
  604. end;
  605. str2opentry := tstr2opentry(iasmops.search(hs));
  606. if assigned(str2opentry) then
  607. begin
  608. if actcondition.dirhint <> DH_None then
  609. message1(asmr_e_unknown_opcode, actasmpattern);
  610. actopcode := str2opentry.op;
  611. actasmtoken := AS_OPCODE;
  612. is_asmopcode := true;
  613. exit;
  614. end;
  615. { not found, check branch instructions }
  616. if hs[1] = 'B' then
  617. begin
  618. { we can search here without an extra table which is sorted by string length
  619. because we take the whole remaining string without the leading B }
  620. if copy(hs, length(s) - 1, 2) = 'LR' then
  621. begin
  622. actopcode := A_BCLR;
  623. setlength(hs, length(hs) - 2)
  624. end
  625. else if copy(hs, length(s) - 2, 3) = 'CTR' then
  626. begin
  627. actopcode := A_BCCTR;
  628. setlength(hs, length(hs) - 3)
  629. end
  630. else
  631. actopcode := A_BC;
  632. for cond := low(TAsmCondFlag) to high(TAsmCondFlag) do
  633. if copy(hs, 2, length(s) - 1) = UpperAsmCondFlag2Str[cond] then
  634. begin
  635. actcondition.simple := true;
  636. actcondition.cond := cond;
  637. if (cond in [C_LT, C_LE, C_EQ, C_GE, C_GT, C_NL, C_NE, C_NG, C_SO, C_NS,
  638. C_UN, C_NU]) then
  639. actcondition.cr := RS_CR0;
  640. actasmtoken := AS_OPCODE;
  641. is_asmopcode := true;
  642. exit;
  643. end;
  644. end;
  645. end;
  646. procedure tppcattreader.ConvertCalljmp(instr: tppcinstruction);
  647. begin
  648. if instr.Operands[1].opr.typ = OPR_CONSTANT then begin
  649. if (instr.operands[1].opr.val > 31) or
  650. (instr.operands[2].opr.typ <> OPR_CONSTANT) or
  651. (instr.operands[2].opr.val > 31) or
  652. not(instr.operands[3].opr.typ in [OPR_REFERENCE,OPR_SYMBOL]) then
  653. Message(asmr_e_syn_operand);
  654. { BO/BI notation }
  655. instr.condition.simple := false;
  656. instr.condition.bo := instr.operands[1].opr.val;
  657. instr.condition.bi := instr.operands[2].opr.val;
  658. instr.operands[1].free;
  659. instr.operands[2].free;
  660. instr.operands[2] := nil;
  661. instr.operands[1] := instr.operands[3];
  662. instr.operands[3] := nil;
  663. instr.ops := 1;
  664. end;
  665. if instr.Operands[1].opr.typ = OPR_REFERENCE then begin
  666. instr.Operands[1].opr.ref.refaddr:=addr_full;
  667. if (instr.Operands[1].opr.ref.base<>NR_NO) or
  668. (instr.Operands[1].opr.ref.index<>NR_NO) then
  669. Message(asmr_e_syn_operand);
  670. end;
  671. end;
  672. procedure tppcattreader.handleopcode;
  673. var
  674. instr: tppcinstruction;
  675. begin
  676. instr := TPPCInstruction.Create(TPPCOperand);
  677. BuildOpcode(instr);
  678. instr.condition := actcondition;
  679. if is_calljmp(instr.opcode) then
  680. ConvertCalljmp(instr);
  681. {
  682. instr.AddReferenceSizes;
  683. instr.SetInstructionOpsize;
  684. instr.CheckOperandSizes;
  685. }
  686. instr.ConcatInstruction(curlist);
  687. instr.Free;
  688. end;
  689. {*****************************************************************************
  690. Initialize
  691. *****************************************************************************}
  692. const
  693. asmmode_ppc_att_info: tasmmodeinfo =
  694. (
  695. id: asmmode_ppc_gas;
  696. idtxt: 'GAS';
  697. casmreader: tppcattreader;
  698. );
  699. asmmode_ppc_standard_info: tasmmodeinfo =
  700. (
  701. id: asmmode_standard;
  702. idtxt: 'STANDARD';
  703. casmreader: tppcattreader;
  704. );
  705. initialization
  706. RegisterAsmMode(asmmode_ppc_att_info);
  707. RegisterAsmMode(asmmode_ppc_standard_info);
  708. end.