agppcmpw.pas 38 KB

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