raz80asm.pas 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670
  1. {
  2. Copyright (c) 1998-2008 by Carl Eric Codere and Peter Vreman
  3. Does the parsing for the Z80 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 raz80asm;
  18. {$i fpcdefs.inc}
  19. Interface
  20. uses
  21. rasm,
  22. raz80,
  23. cpubase;
  24. type
  25. tasmtoken = (
  26. AS_NONE,AS_LABEL,AS_LLABEL,AS_STRING,AS_INTNUM,
  27. AS_COMMA,AS_LPAREN,
  28. AS_RPAREN,AS_COLON,AS_DOT,AS_PLUS,AS_MINUS,AS_STAR,
  29. AS_SEPARATOR,AS_ID,AS_REGISTER,AS_OPCODE,AS_SLASH,AS_DOLLAR,
  30. AS_HASH,AS_LSBRACKET,AS_RSBRACKET,AS_LBRACKET,AS_RBRACKET,
  31. AS_EQUAL,
  32. {------------------ Assembler directives --------------------}
  33. AS_DEFB,AS_DEFW,AS_END
  34. );
  35. tasmkeyword = string[10];
  36. const
  37. { These tokens should be modified accordingly to the modifications }
  38. { in the different enumerations. }
  39. firstdirective = AS_DEFB;
  40. lastdirective = AS_END;
  41. token2str : array[tasmtoken] of tasmkeyword=(
  42. '','Label','LLabel','string','integer',
  43. ',','(',
  44. ')',':','.','+','-','*',
  45. ';','identifier','register','opcode','/','$',
  46. '#','{','}','[',']',
  47. '=',
  48. 'defb','defw','END');
  49. type
  50. { tz80reader }
  51. tz80reader = class(tasmreader)
  52. actasmtoken : tasmtoken;
  53. function is_asmopcode(const s: string):boolean;
  54. function is_register(const s:string):boolean;
  55. //procedure handleopcode;override;
  56. //procedure BuildReference(oper : tz80operand);
  57. //procedure BuildOperand(oper : tz80operand);
  58. //procedure BuildOpCode(instr : tz80instruction);
  59. //procedure ReadSym(oper : tz80operand);
  60. procedure ConvertCalljmp(instr : tz80instruction);
  61. end;
  62. Implementation
  63. uses
  64. { helpers }
  65. cutils,
  66. { global }
  67. globtype,globals,verbose,
  68. systems,
  69. { aasm }
  70. cpuinfo,aasmbase,aasmtai,aasmdata,aasmcpu,
  71. { symtable }
  72. symconst,symbase,symtype,symsym,symtable,
  73. { parser }
  74. scanner,
  75. procinfo,
  76. rabase,rautils,
  77. cgbase,cgutils,cgobj
  78. ;
  79. {*****************************************************************************
  80. tz80reader
  81. *****************************************************************************}
  82. function tz80reader.is_asmopcode(const s: string):boolean;
  83. begin
  84. actcondition:=C_None;
  85. actopcode:=tasmop(PtrUInt(iasmops.Find(s)));
  86. if actopcode<>A_NONE then
  87. begin
  88. actasmtoken:=AS_OPCODE;
  89. is_asmopcode:=true;
  90. end
  91. else
  92. is_asmopcode:=false;
  93. end;
  94. function tz80reader.is_register(const s:string):boolean;
  95. begin
  96. is_register:=false;
  97. actasmregister:=std_regnum_search(lower(s));
  98. if actasmregister<>NR_NO then
  99. begin
  100. is_register:=true;
  101. actasmtoken:=AS_REGISTER;
  102. end;
  103. end;
  104. //procedure tz80reader.ReadSym(oper : tz80operand);
  105. // var
  106. // tempstr, mangledname : string;
  107. // typesize,l,k : aint;
  108. // begin
  109. // tempstr:=actasmpattern;
  110. // Consume(AS_ID);
  111. // { typecasting? }
  112. // if (actasmtoken=AS_LPAREN) and
  113. // SearchType(tempstr,typesize) then
  114. // begin
  115. // oper.hastype:=true;
  116. // Consume(AS_LPAREN);
  117. // BuildOperand(oper);
  118. // Consume(AS_RPAREN);
  119. // if oper.opr.typ in [OPR_REFERENCE,OPR_LOCAL] then
  120. // oper.SetSize(typesize,true);
  121. // end
  122. // else
  123. // if not oper.SetupVar(tempstr,false) then
  124. // Message1(sym_e_unknown_id,tempstr);
  125. // { record.field ? }
  126. // if actasmtoken=AS_DOT then
  127. // begin
  128. // BuildRecordOffsetSize(tempstr,l,k,mangledname,false);
  129. // if (mangledname<>'') then
  130. // Message(asmr_e_invalid_reference_syntax);
  131. // inc(oper.opr.ref.offset,l);
  132. // end;
  133. // end;
  134. //Procedure tz80attreader.BuildReference(oper : tz80operand);
  135. //
  136. // procedure Consume_RParen;
  137. // begin
  138. // if actasmtoken<>AS_RPAREN then
  139. // Begin
  140. // Message(asmr_e_invalid_reference_syntax);
  141. // RecoverConsume(true);
  142. // end
  143. // else
  144. // begin
  145. // Consume(AS_RPAREN);
  146. // if not (actasmtoken in [AS_COMMA,AS_SEPARATOR,AS_END]) then
  147. // Begin
  148. // Message(asmr_e_invalid_reference_syntax);
  149. // RecoverConsume(true);
  150. // end;
  151. // end;
  152. // end;
  153. //procedure read_index;
  154. // begin
  155. // Consume(AS_COMMA);
  156. // if actasmtoken=AS_REGISTER then
  157. // Begin
  158. // oper.opr.ref.index:=actasmregister;
  159. // Consume(AS_REGISTER);
  160. // end
  161. // else if actasmtoken=AS_HASH then
  162. // begin
  163. // Consume(AS_HASH);
  164. // inc(oper.opr.ref.offset,BuildConstExpression(false,true));
  165. // end;
  166. // end;
  167. //begin
  168. // Consume(AS_LPAREN);
  169. // if actasmtoken=AS_REGISTER then
  170. // begin
  171. // oper.opr.ref.base:=actasmregister;
  172. // Consume(AS_REGISTER);
  173. // { can either be a register or a right parenthesis }
  174. // { (reg) }
  175. // if actasmtoken=AS_LPAREN then
  176. // Begin
  177. // Consume_RParen;
  178. // exit;
  179. // end;
  180. // if actasmtoken=AS_PLUS then
  181. // begin
  182. // consume(AS_PLUS);
  183. // oper.opr.ref.addressmode:=AM_POSTINCREMENT;
  184. // end;
  185. // end {end case }
  186. // else
  187. // Begin
  188. // Message(asmr_e_invalid_reference_syntax);
  189. // RecoverConsume(false);
  190. // end;
  191. //end;
  192. //Procedure tz80reader.BuildOperand(oper : tz80operand);
  193. // var
  194. // expr : string;
  195. // typesize,l : aint;
  196. //
  197. //
  198. // procedure AddLabelOperand(hl:tasmlabel);
  199. // begin
  200. // if not(actasmtoken in [AS_PLUS,AS_MINUS,AS_LPAREN]) { and
  201. // is_calljmp(actopcode) } then
  202. // begin
  203. // oper.opr.typ:=OPR_SYMBOL;
  204. // oper.opr.symbol:=hl;
  205. // end
  206. // else
  207. // begin
  208. // oper.InitRef;
  209. // oper.opr.ref.symbol:=hl;
  210. // end;
  211. // end;
  212. //
  213. //
  214. // procedure MaybeRecordOffset;
  215. // var
  216. // mangledname: string;
  217. // hasdot : boolean;
  218. // l,
  219. // toffset,
  220. // tsize : aint;
  221. // begin
  222. // if not(actasmtoken in [AS_DOT,AS_PLUS,AS_MINUS]) then
  223. // exit;
  224. // l:=0;
  225. // mangledname:='';
  226. // hasdot:=(actasmtoken=AS_DOT);
  227. // if hasdot then
  228. // begin
  229. // if expr<>'' then
  230. // begin
  231. // BuildRecordOffsetSize(expr,toffset,tsize,mangledname,false);
  232. // if (oper.opr.typ<>OPR_CONSTANT) and
  233. // (mangledname<>'') then
  234. // Message(asmr_e_wrong_sym_type);
  235. // inc(l,toffset);
  236. // oper.SetSize(tsize,true);
  237. // end;
  238. // end;
  239. // if actasmtoken in [AS_PLUS,AS_MINUS] then
  240. // inc(l,BuildConstExpression(true,false));
  241. // case oper.opr.typ of
  242. // OPR_LOCAL :
  243. // begin
  244. // { don't allow direct access to fields of parameters, because that
  245. // will generate buggy code. Allow it only for explicit typecasting }
  246. // if hasdot and
  247. // (not oper.hastype) and
  248. // (tabstractnormalvarsym(oper.opr.localsym).owner.symtabletype=parasymtable) and
  249. // (current_procinfo.procdef.proccalloption<>pocall_register) then
  250. // Message(asmr_e_cannot_access_field_directly_for_parameters);
  251. // inc(oper.opr.localsymofs,l)
  252. // end;
  253. // OPR_CONSTANT :
  254. // inc(oper.opr.val,l);
  255. // OPR_REFERENCE :
  256. // if (mangledname<>'') then
  257. // begin
  258. // if (oper.opr.val<>0) then
  259. // Message(asmr_e_wrong_sym_type);
  260. // oper.opr.typ:=OPR_SYMBOL;
  261. // oper.opr.symbol:=current_asmdata.RefAsmSymbol(mangledname,AT_FUNCTION);
  262. // end
  263. // else
  264. // inc(oper.opr.val,l);
  265. // OPR_SYMBOL:
  266. // Message(asmr_e_invalid_symbol_ref);
  267. // else
  268. // internalerror(200309221);
  269. // end;
  270. // end;
  271. //
  272. //
  273. // function MaybeBuildReference:boolean;
  274. // { Try to create a reference, if not a reference is found then false
  275. // is returned }
  276. // begin
  277. // MaybeBuildReference:=true;
  278. // case actasmtoken of
  279. // AS_INTNUM,
  280. // AS_MINUS,
  281. // AS_PLUS:
  282. // Begin
  283. // oper.opr.ref.offset:=BuildConstExpression(True,False);
  284. // if actasmtoken<>AS_LPAREN then
  285. // Message(asmr_e_invalid_reference_syntax)
  286. // else
  287. // BuildReference(oper);
  288. // end;
  289. // AS_LPAREN:
  290. // BuildReference(oper);
  291. // AS_ID: { only a variable is allowed ... }
  292. // Begin
  293. // ReadSym(oper);
  294. // case actasmtoken of
  295. // AS_END,
  296. // AS_SEPARATOR,
  297. // AS_COMMA: ;
  298. // AS_LPAREN:
  299. // BuildReference(oper);
  300. // else
  301. // Begin
  302. // Message(asmr_e_invalid_reference_syntax);
  303. // Consume(actasmtoken);
  304. // end;
  305. // end; {end case }
  306. // end;
  307. // else
  308. // MaybeBuildReference:=false;
  309. // end; { end case }
  310. // end;
  311. //
  312. //
  313. // var
  314. // tempreg : tregister;
  315. // ireg : tsuperregister;
  316. // hl : tasmlabel;
  317. // ofs : longint;
  318. // registerset : tcpuregisterset;
  319. // tempstr : string;
  320. // tempsymtyp : tasmsymtype;
  321. // Begin
  322. // expr:='';
  323. // case actasmtoken of
  324. // AS_LBRACKET: { Memory reference or constant expression }
  325. // Begin
  326. // oper.InitRef;
  327. // BuildReference(oper);
  328. // end;
  329. //
  330. // AS_INTNUM,
  331. // AS_MINUS,
  332. // AS_PLUS:
  333. // Begin
  334. // if (actasmtoken=AS_MINUS) and
  335. // (actopcode in [A_LD,A_ST]) then
  336. // begin
  337. // { Special handling of predecrement addressing }
  338. // oper.InitRef;
  339. // oper.opr.ref.addressmode:=AM_PREDRECEMENT;
  340. //
  341. // consume(AS_MINUS);
  342. //
  343. // if actasmtoken=AS_REGISTER then
  344. // begin
  345. // oper.opr.ref.base:=actasmregister;
  346. // consume(AS_REGISTER);
  347. // end
  348. // else
  349. // begin
  350. // Message(asmr_e_invalid_reference_syntax);
  351. // RecoverConsume(false);
  352. // end;
  353. // end
  354. // else
  355. // begin
  356. // { Constant memory offset }
  357. // { This must absolutely be followed by ( }
  358. // oper.InitRef;
  359. // oper.opr.ref.offset:=BuildConstExpression(True,False);
  360. //
  361. // { absolute memory addresss? }
  362. // if actopcode in [A_LDS,A_STS] then
  363. // BuildReference(oper)
  364. // else
  365. // begin
  366. // ofs:=oper.opr.ref.offset;
  367. // BuildConstantOperand(oper);
  368. // inc(oper.opr.val,ofs);
  369. // end;
  370. // end;
  371. // end;
  372. //
  373. // AS_ID: { A constant expression, or a Variable ref. }
  374. // Begin
  375. // if (actasmpattern='LO8') or (actasmpattern='HI8') then
  376. // begin
  377. // { Low or High part of a constant (or constant
  378. // memory location) }
  379. // oper.InitRef;
  380. // if actasmpattern='LO8' then
  381. // oper.opr.ref.refaddr:=addr_lo8
  382. // else
  383. // oper.opr.ref.refaddr:=addr_hi8;
  384. // Consume(actasmtoken);
  385. // Consume(AS_LPAREN);
  386. // BuildConstSymbolExpression(false, true,false,l,tempstr,tempsymtyp);
  387. // if not assigned(oper.opr.ref.symbol) then
  388. // oper.opr.ref.symbol:=current_asmdata.RefAsmSymbol(tempstr,tempsymtyp)
  389. // else
  390. // Message(asmr_e_cant_have_multiple_relocatable_symbols);
  391. // case oper.opr.typ of
  392. // OPR_CONSTANT :
  393. // inc(oper.opr.val,l);
  394. // OPR_LOCAL :
  395. // inc(oper.opr.localsymofs,l);
  396. // OPR_REFERENCE :
  397. // inc(oper.opr.ref.offset,l);
  398. // else
  399. // internalerror(200309202);
  400. // end;
  401. // Consume(AS_RPAREN);
  402. // end
  403. // { Local Label ? }
  404. // else if is_locallabel(actasmpattern) then
  405. // begin
  406. // CreateLocalLabel(actasmpattern,hl,false);
  407. // Consume(AS_ID);
  408. // AddLabelOperand(hl);
  409. // end
  410. // { Check for label }
  411. // else if SearchLabel(actasmpattern,hl,false) then
  412. // begin
  413. // Consume(AS_ID);
  414. // AddLabelOperand(hl);
  415. // end
  416. // else
  417. // { probably a variable or normal expression }
  418. // { or a procedure (such as in CALL ID) }
  419. // Begin
  420. // { is it a constant ? }
  421. // if SearchIConstant(actasmpattern,l) then
  422. // Begin
  423. // if not (oper.opr.typ in [OPR_NONE,OPR_CONSTANT]) then
  424. // Message(asmr_e_invalid_operand_type);
  425. // BuildConstantOperand(oper);
  426. // end
  427. // else
  428. // begin
  429. // expr:=actasmpattern;
  430. // Consume(AS_ID);
  431. // { typecasting? }
  432. // if (actasmtoken=AS_LPAREN) and
  433. // SearchType(expr,typesize) then
  434. // begin
  435. // oper.hastype:=true;
  436. // Consume(AS_LPAREN);
  437. // BuildOperand(oper);
  438. // Consume(AS_RPAREN);
  439. // if oper.opr.typ in [OPR_REFERENCE,OPR_LOCAL] then
  440. // oper.SetSize(typesize,true);
  441. // end
  442. // else
  443. // begin
  444. // if not(oper.SetupVar(expr,false)) then
  445. // Begin
  446. // { look for special symbols ... }
  447. // if expr= '__HIGH' then
  448. // begin
  449. // consume(AS_LPAREN);
  450. // if not oper.setupvar('high'+actasmpattern,false) then
  451. // Message1(sym_e_unknown_id,'high'+actasmpattern);
  452. // consume(AS_ID);
  453. // consume(AS_RPAREN);
  454. // end
  455. // else
  456. // if expr = '__RESULT' then
  457. // oper.SetUpResult
  458. // else
  459. // if expr = '__SELF' then
  460. // oper.SetupSelf
  461. // else
  462. // if expr = '__OLDEBP' then
  463. // oper.SetupOldEBP
  464. // else
  465. // Message1(sym_e_unknown_id,expr);
  466. // end;
  467. // end;
  468. // end;
  469. // if actasmtoken=AS_DOT then
  470. // MaybeRecordOffset;
  471. // { add a constant expression? }
  472. // if (actasmtoken=AS_PLUS) then
  473. // begin
  474. // l:=BuildConstExpression(true,false);
  475. // case oper.opr.typ of
  476. // OPR_CONSTANT :
  477. // inc(oper.opr.val,l);
  478. // OPR_LOCAL :
  479. // inc(oper.opr.localsymofs,l);
  480. // OPR_REFERENCE :
  481. // inc(oper.opr.ref.offset,l);
  482. // else
  483. // internalerror(200309202);
  484. // end;
  485. // end
  486. // end;
  487. // { Do we have a indexing reference, then parse it also }
  488. // if actasmtoken=AS_LPAREN then
  489. // BuildReference(oper);
  490. // end;
  491. //
  492. // { Register, a variable reference or a constant reference }
  493. // AS_REGISTER:
  494. // Begin
  495. // { save the type of register used. }
  496. // tempreg:=actasmregister;
  497. // Consume(AS_REGISTER);
  498. // if (actasmtoken=AS_PLUS) then
  499. // begin
  500. // oper.opr.typ:=OPR_REFERENCE;
  501. //
  502. // reference_reset_base(oper.opr.ref,tempreg,0,1,[]);
  503. // oper.opr.ref.addressmode:=AM_POSTINCREMENT;
  504. //
  505. // consume(AS_PLUS);
  506. // end
  507. // else if (actasmtoken in [AS_END,AS_SEPARATOR,AS_COMMA]) then
  508. // Begin
  509. // if not (oper.opr.typ in [OPR_NONE,OPR_REGISTER]) then
  510. // Message(asmr_e_invalid_operand_type);
  511. // oper.opr.typ:=OPR_REGISTER;
  512. // oper.opr.reg:=tempreg;
  513. // end
  514. // else
  515. // Message(asmr_e_syn_operand);
  516. // end;
  517. //
  518. // AS_END,
  519. // AS_SEPARATOR,
  520. // AS_COMMA: ;
  521. // else
  522. // Begin
  523. // Message(asmr_e_syn_operand);
  524. // Consume(actasmtoken);
  525. // end;
  526. // end; { end case }
  527. // end;
  528. //procedure tz80reader.BuildOpCode(instr : tz80instruction);
  529. // var
  530. // operandnum : longint;
  531. // Begin
  532. // { opcode }
  533. // if (actasmtoken<>AS_OPCODE) then
  534. // Begin
  535. // Message(asmr_e_invalid_or_missing_opcode);
  536. // RecoverConsume(true);
  537. // exit;
  538. // end;
  539. // { Fill the instr object with the current state }
  540. // with instr do
  541. // begin
  542. // Opcode:=ActOpcode;
  543. // condition:=ActCondition;
  544. // end;
  545. //
  546. // { We are reading operands, so opcode will be an AS_ID }
  547. // operandnum:=1;
  548. // Consume(AS_OPCODE);
  549. // { Zero operand opcode ? }
  550. // if actasmtoken in [AS_SEPARATOR,AS_END] then
  551. // begin
  552. // operandnum:=0;
  553. // exit;
  554. // end;
  555. // { Read the operands }
  556. // repeat
  557. // case actasmtoken of
  558. // AS_COMMA: { Operand delimiter }
  559. // Begin
  560. // if operandnum>Max_Operands then
  561. // Message(asmr_e_too_many_operands)
  562. // else
  563. // Inc(operandnum);
  564. // Consume(AS_COMMA);
  565. // end;
  566. // AS_SEPARATOR,
  567. // AS_END : { End of asm operands for this opcode }
  568. // begin
  569. // break;
  570. // end;
  571. // else
  572. // BuildOperand(instr.Operands[operandnum] as tz80operand);
  573. // end; { end case }
  574. // until false;
  575. // instr.Ops:=operandnum;
  576. // end;
  577. procedure tz80reader.ConvertCalljmp(instr : tz80instruction);
  578. var
  579. newopr : toprrec;
  580. begin
  581. if instr.Operands[1].opr.typ=OPR_REFERENCE then
  582. begin
  583. newopr.typ:=OPR_SYMBOL;
  584. newopr.symbol:=instr.Operands[1].opr.ref.symbol;
  585. newopr.symofs:=instr.Operands[1].opr.ref.offset;
  586. if (instr.Operands[1].opr.ref.base<>NR_NO) or
  587. (instr.Operands[1].opr.ref.index<>NR_NO) then
  588. Message(asmr_e_syn_operand);
  589. instr.Operands[1].opr:=newopr;
  590. end;
  591. end;
  592. //procedure tz80reader.handleopcode;
  593. // var
  594. // instr : tz80instruction;
  595. // begin
  596. // instr:=tz80instruction.Create(tz80operand);
  597. // BuildOpcode(instr);
  598. { // if is_calljmp(instr.opcode) then
  599. // ConvertCalljmp(instr); }
  600. // {
  601. // instr.AddReferenceSizes;
  602. // instr.SetInstructionOpsize;
  603. // instr.CheckOperandSizes;
  604. // }
  605. // instr.ConcatInstruction(curlist);
  606. // instr.Free;
  607. // end;
  608. {*****************************************************************************
  609. Initialize
  610. *****************************************************************************}
  611. const
  612. { asmmode_z80_att_info : tasmmodeinfo =
  613. (
  614. id : asmmode_z80_gas;
  615. idtxt : 'GAS';
  616. casmreader : tz80attreader;
  617. );}
  618. asmmode_z80_standard_info : tasmmodeinfo =
  619. (
  620. id : asmmode_standard;
  621. idtxt : 'STANDARD';
  622. casmreader : tz80reader;
  623. );
  624. initialization
  625. // RegisterAsmMode(asmmode_z80_att_info);
  626. RegisterAsmMode(asmmode_z80_standard_info);
  627. end.