agppcmpw.pas 39 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254
  1. {
  2. Copyright (c) 2002 by Florian Klaempfl
  3. This unit implements an asmoutput class for PowerPC with MPW syntax
  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. {
  18. This unit implements an asmoutput class for PowerPC with MPW syntax
  19. }
  20. unit agppcmpw;
  21. {$i fpcdefs.inc}
  22. { We know that use_PR is a const boolean
  23. but we don't care about this warning }
  24. {$WARN 6018 OFF}
  25. interface
  26. uses
  27. aasmtai,aasmdata,
  28. globals,aasmbase,aasmcpu,assemble,
  29. cpubase;
  30. type
  31. TPPCMPWAssembler = class(TExternalAssembler)
  32. procedure WriteTree(p:TAsmList);override;
  33. procedure WriteAsmList;override;
  34. Function DoAssemble:boolean;override;
  35. procedure WriteExternals;
  36. procedure WriteAsmFileHeader;
  37. private
  38. cur_CSECT_name: String;
  39. cur_CSECT_class: String;
  40. procedure WriteInstruction(hp : tai);
  41. procedure WriteProcedureHeader(var hp:tai);
  42. procedure WriteDataHeader(var s:string; isExported, isConst:boolean);
  43. end;
  44. implementation
  45. uses
  46. cutils,globtype,systems,cclasses,
  47. verbose,finput,fmodule,cscript,cpuinfo,
  48. cgbase,cgutils,
  49. itcpugas
  50. ;
  51. const
  52. line_length = 70;
  53. {Whether internal procedure references should be xxx[PR]: }
  54. use_PR = false;
  55. const_storage_class = '';
  56. var_storage_class = '';
  57. secnames : array[TAsmSectiontype] of string[10] = (
  58. '', {none}
  59. '', {user}
  60. 'csect', {code}
  61. 'csect', {data}
  62. 'csect', {read only data}
  63. 'csect', {read only data - no relocations}
  64. 'csect', {bss} 'csect', '',
  65. 'csect','csect','csect','csect','csect',
  66. 'csect','csect','csect',
  67. '','','','','','','','','','','','','','',
  68. '',
  69. '',
  70. '',
  71. '',
  72. '',
  73. '',
  74. '',
  75. '',
  76. '',
  77. '',
  78. '',
  79. '',
  80. '',
  81. '',
  82. '',
  83. '',
  84. '',
  85. '',
  86. '',
  87. '',
  88. '',
  89. '',
  90. '',
  91. '',
  92. '',
  93. '',
  94. '',
  95. '',
  96. '',
  97. '',
  98. '',
  99. '',
  100. '',
  101. '',
  102. '',
  103. '',
  104. '',
  105. '',
  106. '',
  107. ''
  108. );
  109. type
  110. t64bitarray = array[0..7] of byte;
  111. t32bitarray = array[0..3] of byte;
  112. function ReplaceForbiddenChars(var s: string):Boolean;
  113. {Returns wheater a replacement has occurred.}
  114. var
  115. i:Integer;
  116. {The dollar sign is not allowed in MPW PPCAsm}
  117. begin
  118. ReplaceForbiddenChars:=false;
  119. for i:=1 to Length(s) do
  120. if s[i]='$' then
  121. begin
  122. s[i]:='s';
  123. ReplaceForbiddenChars:=true;
  124. end;
  125. end;
  126. {*** From here is copyed from agppcgas.pp, except where marked with CHANGED.
  127. Perhaps put in a third common file. ***}
  128. function getreferencestring(var ref : treference) : string;
  129. var
  130. s : string;
  131. begin
  132. with ref do
  133. begin
  134. if (refaddr <> addr_no) then
  135. InternalError(2002110301)
  136. else if ((offset < -32768) or (offset > 32767)) then
  137. InternalError(19991);
  138. if assigned(symbol) then
  139. begin
  140. s:= symbol.name;
  141. ReplaceForbiddenChars(s);
  142. {if symbol.typ = AT_FUNCTION then
  143. ;}
  144. s:= s+'[TC]' {ref to TOC entry }
  145. end
  146. else
  147. s:= '';
  148. if offset<0 then
  149. s:=s+tostr(offset)
  150. else
  151. if (offset>0) then
  152. begin
  153. if assigned(symbol) then
  154. s:=s+'+'+tostr(offset)
  155. else
  156. s:=s+tostr(offset);
  157. end;
  158. if (index=NR_NO) and (base<>NR_NO) then
  159. begin
  160. if offset=0 then
  161. if not assigned(symbol) then
  162. s:=s+'0';
  163. s:=s+'('+gas_regname(base)+')';
  164. end
  165. else if (index<>NR_NO) and (base<>NR_NO) and (offset=0) then
  166. begin
  167. if (offset=0) then
  168. s:=s+gas_regname(base)+','+gas_regname(index)
  169. else
  170. internalerror(19992);
  171. end
  172. else if (base=NR_NO) and (offset=0) then
  173. begin
  174. {Temporary fix for inline asm, where a local var is referenced.}
  175. //if assigned(symbol) then
  176. // s:= s+'(rtoc)';
  177. end;
  178. end;
  179. getreferencestring:=s;
  180. end;
  181. function getopstr_jmp(const o:toper) : string;
  182. var
  183. hs : string;
  184. begin
  185. case o.typ of
  186. top_reg :
  187. getopstr_jmp:=gas_regname(o.reg);
  188. { no top_ref jumping for powerpc }
  189. top_const :
  190. getopstr_jmp:=tostr(o.val);
  191. top_ref :
  192. begin
  193. if o.ref^.refaddr=addr_full then
  194. begin
  195. hs:=o.ref^.symbol.name;
  196. ReplaceForbiddenChars(hs);
  197. case o.ref^.symbol.typ of
  198. AT_FUNCTION:
  199. begin
  200. if hs[1] <> '@' then {if not local label}
  201. if use_PR then
  202. hs:= '.'+hs+'[PR]'
  203. else
  204. hs:= '.'+hs
  205. end
  206. else
  207. ;
  208. end;
  209. if o.ref^.offset>0 then
  210. hs:=hs+'+'+tostr(o.ref^.offset)
  211. else
  212. if o.ref^.offset<0 then
  213. hs:=hs+tostr(o.ref^.offset);
  214. getopstr_jmp:=hs;
  215. end
  216. else
  217. internalerror(200402263);
  218. end;
  219. top_none:
  220. getopstr_jmp:='';
  221. else
  222. internalerror(2002070603);
  223. end;
  224. end;
  225. function getopstr(const o:toper) : string;
  226. var
  227. hs : string;
  228. begin
  229. case o.typ of
  230. top_reg:
  231. getopstr:=gas_regname(o.reg);
  232. top_const:
  233. getopstr:=tostr(longint(o.val));
  234. top_ref:
  235. if o.ref^.refaddr=addr_no then
  236. getopstr:=getreferencestring(o.ref^)
  237. else if o.ref^.refaddr=addr_pic_no_got then
  238. begin
  239. if (o.ref^.base<>NR_RTOC) or
  240. (o.ref^.index<>NR_NO) or
  241. (o.ref^.offset<>0) or
  242. not assigned(o.ref^.symbol) then
  243. internalerror(2011122701);
  244. hs:=o.ref^.symbol.name;
  245. ReplaceForbiddenChars(hs);
  246. hs:=hs+'[TC](RTOC)';
  247. getopstr:=hs;
  248. end
  249. else
  250. begin
  251. hs:=o.ref^.symbol.name;
  252. ReplaceForbiddenChars(hs);
  253. if o.ref^.offset>0 then
  254. hs:=hs+'+'+tostr(o.ref^.offset)
  255. else
  256. if o.ref^.offset<0 then
  257. hs:=hs+tostr(o.ref^.offset);
  258. getopstr:=hs;
  259. end;
  260. else
  261. internalerror(2002070604);
  262. end;
  263. end;
  264. type
  265. topstr = string[4];
  266. function branchmode(o: tasmop): topstr;
  267. var tempstr: topstr;
  268. begin
  269. tempstr := '';
  270. case o of
  271. A_BCCTR,A_BCCTRL: tempstr := 'ctr';
  272. A_BCLR,A_BCLRL: tempstr := 'lr';
  273. else
  274. ;
  275. end;
  276. case o of
  277. A_BL,A_BLA,A_BCL,A_BCLA,A_BCCTRL,A_BCLRL: tempstr := tempstr+'l';
  278. else
  279. ;
  280. end;
  281. case o of
  282. A_BA,A_BLA,A_BCA,A_BCLA: tempstr:=tempstr+'a';
  283. else
  284. ;
  285. end;
  286. branchmode := tempstr;
  287. end;
  288. function cond2str(op: tasmop; c: tasmcond): string;
  289. { note: no checking is performed whether the given combination of }
  290. { conditions is valid }
  291. var
  292. tempstr: string;
  293. begin
  294. tempstr:=#9;
  295. case c.simple of
  296. false:
  297. begin
  298. cond2str := tempstr+gas_op2str[op];
  299. case c.dirhint of
  300. DH_None:;
  301. DH_Minus:
  302. cond2str:=cond2str+'-';
  303. DH_Plus:
  304. cond2str:=cond2str+'+';
  305. else
  306. internalerror(2003112901);
  307. end;
  308. cond2str:=cond2str+#9+tostr(c.bo)+','+tostr(c.bi)+',';
  309. end;
  310. true:
  311. if (op >= A_B) and (op <= A_BCLRL) then
  312. case c.cond of
  313. { unconditional branch }
  314. C_NONE:
  315. cond2str := tempstr+gas_op2str[op];
  316. { bdnzt etc }
  317. else
  318. begin
  319. tempstr := tempstr+'b'+asmcondflag2str[c.cond]+
  320. branchmode(op);
  321. case c.dirhint of
  322. DH_None:
  323. tempstr:=tempstr+#9;
  324. DH_Minus:
  325. tempstr:=tempstr+('-'+#9);
  326. DH_Plus:
  327. tempstr:=tempstr+('+'+#9);
  328. else
  329. internalerror(2003112901);
  330. end;
  331. case c.cond of
  332. C_LT..C_NU:
  333. cond2str := tempstr+gas_regname(newreg(R_SPECIALREGISTER,c.cr,R_SUBWHOLE));
  334. C_T,C_F,C_DNZT,C_DNZF,C_DZT,C_DZF:
  335. cond2str := tempstr+tostr(c.crbit);
  336. else
  337. cond2str := tempstr;
  338. end;
  339. end;
  340. end
  341. { we have a trap instruction }
  342. else
  343. begin
  344. internalerror(2002070601);
  345. { not yet implemented !!!!!!!!!!!!!!!!!!!!! }
  346. { case tempstr := 'tw';}
  347. end;
  348. end;
  349. end;
  350. procedure TPPCMPWAssembler.WriteInstruction(hp : tai);
  351. var op: TAsmOp;
  352. s: string;
  353. i: byte;
  354. sep: string[3];
  355. begin
  356. op:=taicpu(hp).opcode;
  357. if is_calljmp(op) then
  358. begin
  359. { direct BO/BI in op[0] and op[1] not supported, put them in condition! }
  360. case op of
  361. A_B,A_BA:
  362. s:=#9+gas_op2str[op]+#9;
  363. A_BCTR,A_BCTRL,A_BLR,A_BLRL:
  364. s:=#9+gas_op2str[op];
  365. A_BL,A_BLA:
  366. s:=#9+gas_op2str[op]+#9;
  367. else
  368. begin
  369. s:=cond2str(op,taicpu(hp).condition);
  370. if (s[length(s)] <> #9) and
  371. (taicpu(hp).ops>0) then
  372. s := s + ',';
  373. end;
  374. end;
  375. if (taicpu(hp).ops>0) and (taicpu(hp).oper[0]^.typ<>top_none) then
  376. begin
  377. { first write the current contents of s, because the symbol }
  378. { may be 255 characters }
  379. writer.AsmWrite(s);
  380. s:=getopstr_jmp(taicpu(hp).oper[0]^);
  381. end;
  382. end
  383. else
  384. { process operands }
  385. begin
  386. s:=#9+gas_op2str[op];
  387. if taicpu(hp).ops<>0 then
  388. begin
  389. sep:=#9;
  390. for i:=0 to taicpu(hp).ops-1 do
  391. begin
  392. s:=s+sep+getopstr(taicpu(hp).oper[i]^);
  393. sep:=',';
  394. end;
  395. end;
  396. end;
  397. writer.AsmWriteLn(s);
  398. end;
  399. {*** Until here is copyed from agppcgas.pp. ***}
  400. function single2str(d : single) : string;
  401. var
  402. hs : string;
  403. p : byte;
  404. begin
  405. str(d,hs);
  406. { nasm expects a lowercase e }
  407. p:=pos('E',hs);
  408. if p>0 then
  409. hs[p]:='e';
  410. p:=pos('+',hs);
  411. if p>0 then
  412. delete(hs,p,1);
  413. single2str:=lower(hs);
  414. end;
  415. function double2str(d : double) : string;
  416. var
  417. hs : string;
  418. p : byte;
  419. begin
  420. str(d,hs);
  421. { nasm expects a lowercase e }
  422. p:=pos('E',hs);
  423. if p>0 then
  424. hs[p]:='e';
  425. p:=pos('+',hs);
  426. if p>0 then
  427. delete(hs,p,1);
  428. double2str:=lower(hs);
  429. end;
  430. { convert floating point values }
  431. { to correct endian }
  432. procedure swap64bitarray(var t: t64bitarray);
  433. var
  434. b: byte;
  435. begin
  436. b:= t[7];
  437. t[7] := t[0];
  438. t[0] := b;
  439. b := t[6];
  440. t[6] := t[1];
  441. t[1] := b;
  442. b:= t[5];
  443. t[5] := t[2];
  444. t[2] := b;
  445. b:= t[4];
  446. t[4] := t[3];
  447. t[3] := b;
  448. end;
  449. procedure swap32bitarray(var t: t32bitarray);
  450. var
  451. b: byte;
  452. begin
  453. b:= t[1];
  454. t[1]:= t[2];
  455. t[2]:= b;
  456. b:= t[0];
  457. t[0]:= t[3];
  458. t[3]:= b;
  459. end;
  460. Function PadTabs(const p:string;addch:char):string;
  461. var
  462. s : string;
  463. i : longint;
  464. begin
  465. i:=length(p);
  466. if addch<>#0 then
  467. begin
  468. inc(i);
  469. s:=p+addch;
  470. end
  471. else
  472. s:=p;
  473. if i<8 then
  474. PadTabs:=s+#9#9
  475. else
  476. PadTabs:=s+#9;
  477. end;
  478. {****************************************************************************
  479. PowerPC MPW Assembler
  480. ****************************************************************************}
  481. procedure TPPCMPWAssembler.WriteProcedureHeader(var hp:tai);
  482. {Returns the current hp where the caller should continue from}
  483. {For multiple entry procedures, only the last is exported as xxx[PR]
  484. (if use_PR is set) }
  485. procedure WriteExportHeader(hp:tai);
  486. var
  487. s: string;
  488. replaced: boolean;
  489. begin
  490. s:= tai_symbol(hp).sym.name;
  491. replaced:= ReplaceForbiddenChars(s);
  492. if not use_PR then
  493. begin
  494. writer.AsmWrite(#9'export'#9'.');
  495. writer.AsmWrite(s);
  496. if replaced then
  497. begin
  498. writer.AsmWrite(' => ''.');
  499. writer.AsmWrite(tai_symbol(hp).sym.name);
  500. writer.AsmWrite('''');
  501. end;
  502. writer.AsmLn;
  503. end;
  504. writer.AsmWrite(#9'export'#9);
  505. writer.AsmWrite(s);
  506. writer.AsmWrite('[DS]');
  507. if replaced then
  508. begin
  509. writer.AsmWrite(' => ''');
  510. writer.AsmWrite(tai_symbol(hp).sym.name);
  511. writer.AsmWrite('[DS]''');
  512. end;
  513. writer.AsmLn;
  514. {Entry in transition vector: }
  515. writer.AsmWrite(#9'csect'#9); writer.AsmWrite(s); writer.AsmWriteLn('[DS]');
  516. writer.AsmWrite(#9'dc.l'#9'.'); writer.AsmWriteLn(s);
  517. writer.AsmWriteln(#9'dc.l'#9'TOC[tc0]');
  518. {Entry in TOC: }
  519. writer.AsmWriteLn(#9'toc');
  520. writer.AsmWrite(#9'tc'#9);
  521. writer.AsmWrite(s); writer.AsmWrite('[TC],');
  522. writer.AsmWrite(s); writer.AsmWriteln('[DS]');
  523. end;
  524. function GetAdjacentTaiSymbol(var hp:tai):Boolean;
  525. begin
  526. GetAdjacentTaiSymbol:= false;
  527. while assigned(hp.next) do
  528. case tai(hp.next).typ of
  529. ait_symbol:
  530. begin
  531. hp:=tai(hp.next);
  532. GetAdjacentTaiSymbol:= true;
  533. Break;
  534. end;
  535. ait_function_name:
  536. hp:=tai(hp.next);
  537. else
  538. begin
  539. //writer.AsmWriteln(' ;#*#*# ' + tostr(Ord(tai(hp.next).typ)));
  540. Break;
  541. end;
  542. end;
  543. end;
  544. var
  545. first,last: tai;
  546. s: string;
  547. replaced: boolean;
  548. begin
  549. s:= tai_symbol(hp).sym.name;
  550. {Write all headers}
  551. first:= hp;
  552. repeat
  553. WriteExportHeader(hp);
  554. last:= hp;
  555. until not GetAdjacentTaiSymbol(hp);
  556. {Start the section of the body of the proc: }
  557. s:= tai_symbol(last).sym.name;
  558. replaced:= ReplaceForbiddenChars(s);
  559. if use_PR then
  560. begin
  561. writer.AsmWrite(#9'export'#9'.'); writer.AsmWrite(s); writer.AsmWrite('[PR]');
  562. if replaced then
  563. begin
  564. writer.AsmWrite(' => ''.');
  565. writer.AsmWrite(tai_symbol(last).sym.name);
  566. writer.AsmWrite('[PR]''');
  567. end;
  568. writer.AsmLn;
  569. end;
  570. {Starts the section: }
  571. writer.AsmWrite(#9'csect'#9'.');
  572. writer.AsmWrite(s);
  573. writer.AsmWriteLn('[PR]');
  574. {Info for the debugger: }
  575. writer.AsmWrite(#9'function'#9'.');
  576. writer.AsmWrite(s);
  577. writer.AsmWriteLn('[PR]');
  578. {Write all labels: }
  579. hp:= first;
  580. repeat
  581. s:= tai_symbol(hp).sym.name;
  582. ReplaceForbiddenChars(s);
  583. writer.AsmWrite('.'); writer.AsmWrite(s); writer.AsmWriteLn(':');
  584. until not GetAdjacentTaiSymbol(hp);
  585. end;
  586. procedure TPPCMPWAssembler.WriteDataHeader(var s:string; isExported, isConst:boolean);
  587. // Returns in s the changed string
  588. var
  589. sym: string;
  590. replaced: boolean;
  591. begin
  592. sym:= s;
  593. replaced:= ReplaceForbiddenChars(s);
  594. if isExported then
  595. begin
  596. writer.AsmWrite(#9'export'#9);
  597. writer.AsmWrite(s);
  598. if isConst then
  599. writer.AsmWrite(const_storage_class)
  600. else
  601. writer.AsmWrite(var_storage_class);
  602. if replaced then
  603. begin
  604. writer.AsmWrite(' => ''');
  605. writer.AsmWrite(sym);
  606. writer.AsmWrite('''');
  607. end;
  608. writer.AsmLn;
  609. end;
  610. if not macos_direct_globals then
  611. begin
  612. {The actual section is here interrupted, by inserting a "tc" entry}
  613. writer.AsmWriteLn(#9'toc');
  614. writer.AsmWrite(#9'tc'#9);
  615. writer.AsmWrite(s);
  616. writer.AsmWrite('[TC], ');
  617. writer.AsmWrite(s);
  618. if isConst then
  619. writer.AsmWrite(const_storage_class)
  620. else
  621. writer.AsmWrite(var_storage_class);
  622. writer.AsmLn;
  623. {The interrupted section is here continued.}
  624. writer.AsmWrite(#9'csect'#9);
  625. writer.AsmWriteln(cur_CSECT_name+cur_CSECT_class);
  626. writer.AsmWrite(PadTabs(s+':',#0));
  627. end
  628. else
  629. begin
  630. writer.AsmWrite(#9'csect'#9);
  631. writer.AsmWrite(s);
  632. writer.AsmWrite('[TC]');
  633. end;
  634. writer.AsmLn;
  635. end;
  636. const
  637. ait_const2str:array[aitconst_32bit..aitconst_8bit] of string[8]=
  638. (#9'dc.l'#9,#9'dc.w'#9,#9'dc.b'#9);
  639. procedure TPPCMPWAssembler.WriteTree(p:TAsmList);
  640. var
  641. s : string;
  642. hp : tai;
  643. counter,
  644. lines,
  645. InlineLevel : longint;
  646. i,j,l : longint;
  647. consttype : taiconst_type;
  648. do_line,DoNotSplitLine,
  649. quoted : boolean;
  650. sin : single;
  651. d : double;
  652. begin
  653. if not assigned(p) then
  654. exit;
  655. InlineLevel:=0;
  656. { lineinfo is only needed for al_procedures (PFV) }
  657. do_line:=((cs_asm_source in current_settings.globalswitches) or
  658. (cs_lineinfo in current_settings.moduleswitches))
  659. and (p=current_asmdata.asmlists[al_procedures]);
  660. DoNotSplitLine:=false;
  661. hp:=tai(p.first);
  662. while assigned(hp) do
  663. begin
  664. prefetch(pointer(hp.next)^);
  665. if not(hp.typ in SkipLineInfo) then
  666. begin
  667. current_filepos:=tailineinfo(hp).fileinfo;
  668. { no line info for inlined code }
  669. if do_line and (inlinelevel=0) and not DoNotSplitLine then
  670. WriteSourceLine(hp as tailineinfo);
  671. end;
  672. DoNotSplitLine:=false;
  673. case hp.typ of
  674. ait_comment:
  675. begin
  676. writer.AsmWrite(asminfo^.comment);
  677. writer.AsmWritePChar(tai_comment(hp).str);
  678. writer.AsmLn;
  679. end;
  680. ait_regalloc,
  681. ait_tempalloc:
  682. ;
  683. ait_section:
  684. begin
  685. {if LastSecType<>sec_none then
  686. writer.AsmWriteLn('_'+asminfo^.secnames[LastSecType]+#9#9'ENDS');}
  687. if tai_section(hp).sectype<>sec_none then
  688. begin
  689. if tai_section(hp).sectype in [sec_data,sec_rodata,sec_bss] then
  690. cur_CSECT_class:= '[RW]'
  691. else if tai_section(hp).sectype in [sec_code] then
  692. cur_CSECT_class:= ''
  693. else
  694. cur_CSECT_class:= '[RO]';
  695. s:= tai_section(hp).name^;
  696. if s = '' then
  697. InternalError(2004101001); {Nameless sections should not occur on MPW}
  698. ReplaceForbiddenChars(s);
  699. cur_CSECT_name:= s;
  700. writer.AsmLn;
  701. writer.AsmWriteLn(#9+secnames[tai_section(hp).sectype]+' '+cur_CSECT_name+cur_CSECT_class);
  702. end;
  703. LastSecType:=tai_section(hp).sectype;
  704. end;
  705. ait_align:
  706. begin
  707. case tai_align(hp).aligntype of
  708. 1:writer.AsmWriteLn(#9'align 0');
  709. 2:writer.AsmWriteLn(#9'align 1');
  710. 4:writer.AsmWriteLn(#9'align 2');
  711. otherwise internalerror(2002110302);
  712. end;
  713. end;
  714. ait_datablock: {Storage for global variables.}
  715. begin
  716. s:= tai_datablock(hp).sym.name;
  717. WriteDataHeader(s, tai_datablock(hp).is_global, false);
  718. if not macos_direct_globals then
  719. begin
  720. writer.AsmWriteLn(#9'ds.b '+tostr(tai_datablock(hp).size));
  721. end
  722. else
  723. begin
  724. writer.AsmWriteLn(PadTabs(s+':',#0)+'ds.b '+tostr(tai_datablock(hp).size));
  725. {TODO: ? PadTabs(s,#0) }
  726. end;
  727. end;
  728. ait_const:
  729. begin
  730. consttype:=tai_const(hp).consttype;
  731. case consttype of
  732. aitconst_128bit:
  733. begin
  734. internalerror(200404291);
  735. end;
  736. aitconst_64bit:
  737. begin
  738. if assigned(tai_const(hp).sym) then
  739. internalerror(200404292);
  740. writer.AsmWrite(ait_const2str[aitconst_32bit]);
  741. if target_info.endian = endian_little then
  742. begin
  743. writer.AsmWrite(tostr(longint(lo(tai_const(hp).value))));
  744. writer.AsmWrite(',');
  745. writer.AsmWrite(tostr(longint(hi(tai_const(hp).value))));
  746. end
  747. else
  748. begin
  749. writer.AsmWrite(tostr(longint(hi(tai_const(hp).value))));
  750. writer.AsmWrite(',');
  751. writer.AsmWrite(tostr(longint(lo(tai_const(hp).value))));
  752. end;
  753. writer.AsmLn;
  754. end;
  755. aitconst_uleb128bit,
  756. aitconst_sleb128bit,
  757. aitconst_32bit,
  758. aitconst_16bit,
  759. aitconst_8bit,
  760. aitconst_rva_symbol :
  761. begin
  762. writer.AsmWrite(ait_const2str[consttype]);
  763. l:=0;
  764. repeat
  765. if assigned(tai_const(hp).sym) then
  766. begin
  767. if assigned(tai_const(hp).endsym) then
  768. begin
  769. if (tai_const(hp).endsym.typ = AT_FUNCTION) and use_PR then
  770. writer.AsmWrite('.');
  771. s:=tai_const(hp).endsym.name;
  772. ReplaceForbiddenChars(s);
  773. writer.AsmWrite(s);
  774. inc(l,length(s));
  775. if tai_const(hp).endsym.typ = AT_FUNCTION then
  776. begin
  777. if use_PR then
  778. writer.AsmWrite('[PR]')
  779. else
  780. writer.AsmWrite('[DS]');
  781. end;
  782. writer.AsmWrite('-');
  783. inc(l,5); {Approx 5 extra, no need to be exactly}
  784. end;
  785. if (tai_const(hp).sym.typ = AT_FUNCTION) and use_PR then
  786. writer.AsmWrite('.');
  787. s:= tai_const(hp).sym.name;
  788. ReplaceForbiddenChars(s);
  789. writer.AsmWrite(s);
  790. inc(l,length(s));
  791. if tai_const(hp).sym.typ = AT_FUNCTION then
  792. begin
  793. if use_PR then
  794. writer.AsmWrite('[PR]')
  795. else
  796. writer.AsmWrite('[DS]');
  797. end;
  798. inc(l,5); {Approx 5 extra, no need to be exactly}
  799. if tai_const(hp).value > 0 then
  800. s:= '+'+tostr(tai_const(hp).value)
  801. else if tai_const(hp).value < 0 then
  802. s:= '-'+tostr(tai_const(hp).value)
  803. else
  804. s:= '';
  805. if s<>'' then
  806. begin
  807. writer.AsmWrite(s);
  808. inc(l,length(s));
  809. end;
  810. end
  811. else
  812. begin
  813. s:= tostr(tai_const(hp).value);
  814. writer.AsmWrite(s);
  815. inc(l,length(s));
  816. end;
  817. if (l>line_length) or
  818. (hp.next=nil) or
  819. (tai(hp.next).typ<>ait_const) or
  820. (tai_const(hp.next).consttype<>consttype) then
  821. break;
  822. hp:=tai(hp.next);
  823. writer.AsmWrite(',');
  824. until false;
  825. writer.AsmLn;
  826. end;
  827. else
  828. internalerror(2019050950);
  829. end;
  830. end;
  831. ait_realconst:
  832. begin
  833. WriteRealConstAsBytes(tai_realconst(hp),#9'dc.b'#9,do_line);
  834. end;
  835. ait_string:
  836. begin
  837. {NOTE When a single quote char is encountered, it is
  838. replaced with a numeric ascii value. It could also
  839. have been replaced with the escape seq of double quotes.
  840. Backslash seems to be used as an escape char, although
  841. this is not mentioned in the PPCAsm documentation.}
  842. counter := 0;
  843. lines := tai_string(hp).len div line_length;
  844. { separate lines in different parts }
  845. if tai_string(hp).len > 0 then
  846. begin
  847. for j := 0 to lines-1 do
  848. begin
  849. writer.AsmWrite(#9'dc.b'#9);
  850. quoted:=false;
  851. for i:=counter to counter+line_length-1 do
  852. begin
  853. { it is an ascii character. }
  854. if (ord(tai_string(hp).str[i])>31) and
  855. (ord(tai_string(hp).str[i])<128) and
  856. (tai_string(hp).str[i]<>'''') and
  857. (tai_string(hp).str[i]<>'\') then
  858. begin
  859. if not(quoted) then
  860. begin
  861. if i>counter then
  862. writer.AsmWrite(',');
  863. writer.AsmWrite('''');
  864. end;
  865. writer.AsmWrite(tai_string(hp).str[i]);
  866. quoted:=true;
  867. end { if > 31 and < 128 and ord('"') }
  868. else
  869. begin
  870. if quoted then
  871. writer.AsmWrite('''');
  872. if i>counter then
  873. writer.AsmWrite(',');
  874. quoted:=false;
  875. writer.AsmWrite(tostr(ord(tai_string(hp).str[i])));
  876. end;
  877. end; { end for i:=0 to... }
  878. if quoted then writer.AsmWrite('''');
  879. writer.AsmLn;
  880. counter := counter+line_length;
  881. end; { end for j:=0 ... }
  882. { do last line of lines }
  883. if counter < tai_string(hp).len then
  884. writer.AsmWrite(#9'dc.b'#9);
  885. quoted:=false;
  886. for i:=counter to tai_string(hp).len-1 do
  887. begin
  888. { it is an ascii character. }
  889. if (ord(tai_string(hp).str[i])>31) and
  890. (ord(tai_string(hp).str[i])<128) and
  891. (tai_string(hp).str[i]<>'''') and
  892. (tai_string(hp).str[i]<>'\') then
  893. begin
  894. if not(quoted) then
  895. begin
  896. if i>counter then
  897. writer.AsmWrite(',');
  898. writer.AsmWrite('''');
  899. end;
  900. writer.AsmWrite(tai_string(hp).str[i]);
  901. quoted:=true;
  902. end { if > 31 and < 128 and " }
  903. else
  904. begin
  905. if quoted then
  906. writer.AsmWrite('''');
  907. if i>counter then
  908. writer.AsmWrite(',');
  909. quoted:=false;
  910. writer.AsmWrite(tostr(ord(tai_string(hp).str[i])));
  911. end;
  912. end; { end for i:=0 to... }
  913. if quoted then
  914. writer.AsmWrite('''');
  915. end;
  916. writer.AsmLn;
  917. end;
  918. ait_label:
  919. begin
  920. if tai_label(hp).labsym.is_used then
  921. begin
  922. s:= tai_label(hp).labsym.name;
  923. if s[1] = '@' then
  924. begin
  925. ReplaceForbiddenChars(s);
  926. //Local labels:
  927. writer.AsmWriteLn(s+':')
  928. end
  929. else
  930. begin
  931. //Procedure entry points:
  932. if not macos_direct_globals then
  933. begin
  934. WriteDataHeader(s, tai_label(hp).labsym.bind in [AB_GLOBAL,AB_PRIVATE_EXTERN], true);
  935. end
  936. else
  937. begin
  938. ReplaceForbiddenChars(s);
  939. writer.AsmWrite(#9'csect'#9); writer.AsmWrite(s);
  940. writer.AsmWriteLn('[TC]');
  941. writer.AsmWriteLn(PadTabs(s+':',#0));
  942. end;
  943. end;
  944. end;
  945. end;
  946. ait_symbol:
  947. begin
  948. if tai_symbol(hp).sym.typ=AT_FUNCTION then
  949. WriteProcedureHeader(hp)
  950. else if tai_symbol(hp).sym.typ=AT_DATA then
  951. begin
  952. s:= tai_symbol(hp).sym.name;
  953. WriteDataHeader(s, tai_symbol(hp).is_global, true);
  954. if macos_direct_globals then
  955. begin
  956. writer.AsmWrite(s);
  957. writer.AsmWriteLn(':');
  958. end;
  959. end
  960. else
  961. InternalError(2003071301);
  962. end;
  963. ait_symbol_end:
  964. ;
  965. ait_instruction:
  966. WriteInstruction(hp);
  967. ait_stab,
  968. ait_force_line,
  969. ait_function_name : ;
  970. ait_cutobject :
  971. begin
  972. InternalError(2004101101); {Smart linking is done transparently by the MPW linker.}
  973. end;
  974. ait_marker :
  975. begin
  976. if tai_marker(hp).kind=mark_NoLineInfoStart then
  977. inc(InlineLevel)
  978. else if tai_marker(hp).kind=mark_NoLineInfoEnd then
  979. dec(InlineLevel);
  980. end;
  981. ait_directive :
  982. if tai_directive(hp).directive=asd_cpu then
  983. begin
  984. writer.AsmWrite(asminfo^.comment+' CPU ');
  985. if tai_directive(hp).name<>'' then
  986. writer.AsmWrite(tai_directive(hp).name);
  987. writer.AsmLn;
  988. end
  989. else
  990. internalerror(2016022601);
  991. else
  992. internalerror(2002110303);
  993. end;
  994. hp:=tai(hp.next);
  995. end;
  996. end;
  997. var
  998. currentasmlist : TExternalAssembler;
  999. procedure writeexternal(p:tasmsymbol);
  1000. var
  1001. s:string;
  1002. replaced: boolean;
  1003. begin
  1004. if tasmsymbol(p).bind in [AB_EXTERNAL,AB_EXTERNAL_INDIRECT] then
  1005. begin
  1006. //Writeln('ZZZ ',p.name,' ',p.typ);
  1007. s:= p.name;
  1008. replaced:= ReplaceForbiddenChars(s);
  1009. with currentasmlist do
  1010. case tasmsymbol(p).typ of
  1011. AT_FUNCTION:
  1012. begin
  1013. writer.AsmWrite(#9'import'#9'.');
  1014. writer.AsmWrite(s);
  1015. if use_PR then
  1016. writer.AsmWrite('[PR]');
  1017. if replaced then
  1018. begin
  1019. writer.AsmWrite(' <= ''.');
  1020. writer.AsmWrite(p.name);
  1021. if use_PR then
  1022. writer.AsmWrite('[PR]''')
  1023. else
  1024. writer.AsmWrite('''');
  1025. end;
  1026. writer.AsmLn;
  1027. writer.AsmWrite(#9'import'#9);
  1028. writer.AsmWrite(s);
  1029. writer.AsmWrite('[DS]');
  1030. if replaced then
  1031. begin
  1032. writer.AsmWrite(' <= ''');
  1033. writer.AsmWrite(p.name);
  1034. writer.AsmWrite('[DS]''');
  1035. end;
  1036. writer.AsmLn;
  1037. writer.AsmWriteLn(#9'toc');
  1038. writer.AsmWrite(#9'tc'#9);
  1039. writer.AsmWrite(s);
  1040. writer.AsmWrite('[TC],');
  1041. writer.AsmWrite(s);
  1042. writer.AsmWriteLn('[DS]');
  1043. end;
  1044. AT_DATA:
  1045. begin
  1046. writer.AsmWrite(#9'import'#9);
  1047. writer.AsmWrite(s);
  1048. writer.AsmWrite(var_storage_class);
  1049. if replaced then
  1050. begin
  1051. writer.AsmWrite(' <= ''');
  1052. writer.AsmWrite(p.name);
  1053. writer.AsmWrite('''');
  1054. end;
  1055. writer.AsmLn;
  1056. writer.AsmWriteLn(#9'toc');
  1057. writer.AsmWrite(#9'tc'#9);
  1058. writer.AsmWrite(s);
  1059. writer.AsmWrite('[TC],');
  1060. writer.AsmWrite(s);
  1061. writer.AsmWriteLn(var_storage_class);
  1062. end
  1063. else
  1064. InternalError(2003090901);
  1065. end;
  1066. end;
  1067. end;
  1068. procedure TPPCMPWAssembler.WriteExternals;
  1069. var
  1070. i : longint;
  1071. begin
  1072. currentasmlist:=self;
  1073. // current_asmdata.asmsymboldict.foreach_static(@writeexternal,nil);
  1074. for i:=0 to current_asmdata.AsmSymbolDict.Count-1 do
  1075. begin
  1076. writeexternal(tasmsymbol(current_asmdata.AsmSymbolDict[i]));
  1077. end;
  1078. end;
  1079. function TPPCMPWAssembler.DoAssemble : boolean;
  1080. begin
  1081. DoAssemble:=Inherited DoAssemble;
  1082. end;
  1083. procedure TPPCMPWAssembler.WriteAsmFileHeader;
  1084. begin
  1085. writer.AsmWriteLn(#9'string asis'); {Interpret strings just to be the content between the quotes.}
  1086. writer.AsmWriteLn(#9'aligning off'); {We do our own aligning.}
  1087. writer.AsmLn;
  1088. end;
  1089. procedure TPPCMPWAssembler.WriteAsmList;
  1090. var
  1091. hal : tasmlisttype;
  1092. begin
  1093. {$ifdef EXTDEBUG}
  1094. if current_module.mainsource<>'' then
  1095. comment(v_info,'Start writing MPW-styled assembler output for '+current_module.mainsource);
  1096. {$endif}
  1097. WriteAsmFileHeader;
  1098. WriteExternals;
  1099. for hal:=low(TasmlistType) to high(TasmlistType) do
  1100. begin
  1101. writer.AsmWriteLn(asminfo^.comment+'Begin asmlist '+AsmListTypeStr[hal]);
  1102. writetree(current_asmdata.asmlists[hal]);
  1103. writer.AsmWriteLn(asminfo^.comment+'End asmlist '+AsmListTypeStr[hal]);
  1104. end;
  1105. writer.AsmWriteLn(#9'end');
  1106. writer.AsmLn;
  1107. {$ifdef EXTDEBUG}
  1108. if current_module.mainsource<>'' then
  1109. comment(v_info,'Done writing MPW-styled assembler output for '+current_module.mainsource);
  1110. {$endif EXTDEBUG}
  1111. end;
  1112. {*****************************************************************************
  1113. Initialize
  1114. *****************************************************************************}
  1115. const
  1116. as_powerpc_mpw_info : tasminfo =
  1117. (
  1118. id : as_powerpc_mpw;
  1119. idtxt : 'MPW';
  1120. asmbin : 'PPCAsm';
  1121. asmcmd : '-case on $ASM $EXTRAOPT -o $OBJ';
  1122. supported_targets : [system_powerpc_macos];
  1123. flags : [af_needar,af_smartlink_sections,af_labelprefix_only_inside_procedure];
  1124. labelprefix : '@';
  1125. comment : '; ';
  1126. dollarsign: 's';
  1127. );
  1128. initialization
  1129. RegisterAssembler(as_powerpc_mpw_info,TPPCMPWAssembler);
  1130. end.