agppcmpw.pas 38 KB

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