agppcmpw.pas 38 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230
  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. writer.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. writer.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. writer.AsmWrite(#9'export'#9'.');
  473. writer.AsmWrite(s);
  474. if replaced then
  475. begin
  476. writer.AsmWrite(' => ''.');
  477. writer.AsmWrite(tai_symbol(hp).sym.name);
  478. writer.AsmWrite('''');
  479. end;
  480. writer.AsmLn;
  481. end;
  482. writer.AsmWrite(#9'export'#9);
  483. writer.AsmWrite(s);
  484. writer.AsmWrite('[DS]');
  485. if replaced then
  486. begin
  487. writer.AsmWrite(' => ''');
  488. writer.AsmWrite(tai_symbol(hp).sym.name);
  489. writer.AsmWrite('[DS]''');
  490. end;
  491. writer.AsmLn;
  492. {Entry in transition vector: }
  493. writer.AsmWrite(#9'csect'#9); writer.AsmWrite(s); writer.AsmWriteLn('[DS]');
  494. writer.AsmWrite(#9'dc.l'#9'.'); writer.AsmWriteLn(s);
  495. writer.AsmWriteln(#9'dc.l'#9'TOC[tc0]');
  496. {Entry in TOC: }
  497. writer.AsmWriteLn(#9'toc');
  498. writer.AsmWrite(#9'tc'#9);
  499. writer.AsmWrite(s); writer.AsmWrite('[TC],');
  500. writer.AsmWrite(s); writer.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. //writer.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. writer.AsmWrite(#9'export'#9'.'); writer.AsmWrite(s); writer.AsmWrite('[PR]');
  540. if replaced then
  541. begin
  542. writer.AsmWrite(' => ''.');
  543. writer.AsmWrite(tai_symbol(last).sym.name);
  544. writer.AsmWrite('[PR]''');
  545. end;
  546. writer.AsmLn;
  547. end;
  548. {Starts the section: }
  549. writer.AsmWrite(#9'csect'#9'.');
  550. writer.AsmWrite(s);
  551. writer.AsmWriteLn('[PR]');
  552. {Info for the debugger: }
  553. writer.AsmWrite(#9'function'#9'.');
  554. writer.AsmWrite(s);
  555. writer.AsmWriteLn('[PR]');
  556. {Write all labels: }
  557. hp:= first;
  558. repeat
  559. s:= tai_symbol(hp).sym.name;
  560. ReplaceForbiddenChars(s);
  561. writer.AsmWrite('.'); writer.AsmWrite(s); writer.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. writer.AsmWrite(#9'export'#9);
  575. writer.AsmWrite(s);
  576. if isConst then
  577. writer.AsmWrite(const_storage_class)
  578. else
  579. writer.AsmWrite(var_storage_class);
  580. if replaced then
  581. begin
  582. writer.AsmWrite(' => ''');
  583. writer.AsmWrite(sym);
  584. writer.AsmWrite('''');
  585. end;
  586. writer.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. writer.AsmWriteLn(#9'toc');
  592. writer.AsmWrite(#9'tc'#9);
  593. writer.AsmWrite(s);
  594. writer.AsmWrite('[TC], ');
  595. writer.AsmWrite(s);
  596. if isConst then
  597. writer.AsmWrite(const_storage_class)
  598. else
  599. writer.AsmWrite(var_storage_class);
  600. writer.AsmLn;
  601. {The interrupted section is here continued.}
  602. writer.AsmWrite(#9'csect'#9);
  603. writer.AsmWriteln(cur_CSECT_name+cur_CSECT_class);
  604. writer.AsmWrite(PadTabs(s+':',#0));
  605. end
  606. else
  607. begin
  608. writer.AsmWrite(#9'csect'#9);
  609. writer.AsmWrite(s);
  610. writer.AsmWrite('[TC]');
  611. end;
  612. writer.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. writer.AsmWrite(asminfo^.comment);
  655. writer.AsmWritePChar(tai_comment(hp).str);
  656. writer.AsmLn;
  657. end;
  658. ait_regalloc,
  659. ait_tempalloc:
  660. ;
  661. ait_section:
  662. begin
  663. {if LastSecType<>sec_none then
  664. writer.AsmWriteLn('_'+asminfo^.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. writer.AsmLn;
  679. writer.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:writer.AsmWriteLn(#9'align 0');
  687. 2:writer.AsmWriteLn(#9'align 1');
  688. 4:writer.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. writer.AsmWriteLn(#9'ds.b '+tostr(tai_datablock(hp).size));
  699. end
  700. else
  701. begin
  702. writer.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. writer.AsmWrite(ait_const2str[aitconst_32bit]);
  719. if target_info.endian = endian_little then
  720. begin
  721. writer.AsmWrite(tostr(longint(lo(tai_const(hp).value))));
  722. writer.AsmWrite(',');
  723. writer.AsmWrite(tostr(longint(hi(tai_const(hp).value))));
  724. end
  725. else
  726. begin
  727. writer.AsmWrite(tostr(longint(hi(tai_const(hp).value))));
  728. writer.AsmWrite(',');
  729. writer.AsmWrite(tostr(longint(lo(tai_const(hp).value))));
  730. end;
  731. writer.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. writer.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. writer.AsmWrite('.');
  749. s:=tai_const(hp).endsym.name;
  750. ReplaceForbiddenChars(s);
  751. writer.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. writer.AsmWrite('[PR]')
  757. else
  758. writer.AsmWrite('[DS]');
  759. end;
  760. writer.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. writer.AsmWrite('.');
  765. s:= tai_const(hp).sym.name;
  766. ReplaceForbiddenChars(s);
  767. writer.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. writer.AsmWrite('[PR]')
  773. else
  774. writer.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. writer.AsmWrite(s);
  786. inc(l,length(s));
  787. end;
  788. end
  789. else
  790. begin
  791. s:= tostr(tai_const(hp).value);
  792. writer.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. writer.AsmWrite(',');
  802. until false;
  803. writer.AsmLn;
  804. end;
  805. end;
  806. end;
  807. ait_realconst:
  808. begin
  809. WriteRealConstAsBytes(tai_realconst(hp),#9'dc.b'#9,do_line);
  810. end;
  811. ait_string:
  812. begin
  813. {NOTE When a single quote char is encountered, it is
  814. replaced with a numeric ascii value. It could also
  815. have been replaced with the escape seq of double quotes.
  816. Backslash seems to be used as an escape char, although
  817. this is not mentioned in the PPCAsm documentation.}
  818. counter := 0;
  819. lines := tai_string(hp).len div line_length;
  820. { separate lines in different parts }
  821. if tai_string(hp).len > 0 then
  822. begin
  823. for j := 0 to lines-1 do
  824. begin
  825. writer.AsmWrite(#9'dc.b'#9);
  826. quoted:=false;
  827. for i:=counter to counter+line_length-1 do
  828. begin
  829. { it is an ascii character. }
  830. if (ord(tai_string(hp).str[i])>31) and
  831. (ord(tai_string(hp).str[i])<128) and
  832. (tai_string(hp).str[i]<>'''') and
  833. (tai_string(hp).str[i]<>'\') then
  834. begin
  835. if not(quoted) then
  836. begin
  837. if i>counter then
  838. writer.AsmWrite(',');
  839. writer.AsmWrite('''');
  840. end;
  841. writer.AsmWrite(tai_string(hp).str[i]);
  842. quoted:=true;
  843. end { if > 31 and < 128 and ord('"') }
  844. else
  845. begin
  846. if quoted then
  847. writer.AsmWrite('''');
  848. if i>counter then
  849. writer.AsmWrite(',');
  850. quoted:=false;
  851. writer.AsmWrite(tostr(ord(tai_string(hp).str[i])));
  852. end;
  853. end; { end for i:=0 to... }
  854. if quoted then writer.AsmWrite('''');
  855. writer.AsmLn;
  856. counter := counter+line_length;
  857. end; { end for j:=0 ... }
  858. { do last line of lines }
  859. if counter < tai_string(hp).len then
  860. writer.AsmWrite(#9'dc.b'#9);
  861. quoted:=false;
  862. for i:=counter to tai_string(hp).len-1 do
  863. begin
  864. { it is an ascii character. }
  865. if (ord(tai_string(hp).str[i])>31) and
  866. (ord(tai_string(hp).str[i])<128) and
  867. (tai_string(hp).str[i]<>'''') and
  868. (tai_string(hp).str[i]<>'\') then
  869. begin
  870. if not(quoted) then
  871. begin
  872. if i>counter then
  873. writer.AsmWrite(',');
  874. writer.AsmWrite('''');
  875. end;
  876. writer.AsmWrite(tai_string(hp).str[i]);
  877. quoted:=true;
  878. end { if > 31 and < 128 and " }
  879. else
  880. begin
  881. if quoted then
  882. writer.AsmWrite('''');
  883. if i>counter then
  884. writer.AsmWrite(',');
  885. quoted:=false;
  886. writer.AsmWrite(tostr(ord(tai_string(hp).str[i])));
  887. end;
  888. end; { end for i:=0 to... }
  889. if quoted then
  890. writer.AsmWrite('''');
  891. end;
  892. writer.AsmLn;
  893. end;
  894. ait_label:
  895. begin
  896. if tai_label(hp).labsym.is_used then
  897. begin
  898. s:= tai_label(hp).labsym.name;
  899. if s[1] = '@' then
  900. begin
  901. ReplaceForbiddenChars(s);
  902. //Local labels:
  903. writer.AsmWriteLn(s+':')
  904. end
  905. else
  906. begin
  907. //Procedure entry points:
  908. if not macos_direct_globals then
  909. begin
  910. WriteDataHeader(s, tai_label(hp).labsym.bind in [AB_GLOBAL,AB_PRIVATE_EXTERN], true);
  911. end
  912. else
  913. begin
  914. ReplaceForbiddenChars(s);
  915. writer.AsmWrite(#9'csect'#9); writer.AsmWrite(s);
  916. writer.AsmWriteLn('[TC]');
  917. writer.AsmWriteLn(PadTabs(s+':',#0));
  918. end;
  919. end;
  920. end;
  921. end;
  922. ait_symbol:
  923. begin
  924. if tai_symbol(hp).sym.typ=AT_FUNCTION then
  925. WriteProcedureHeader(hp)
  926. else if tai_symbol(hp).sym.typ=AT_DATA then
  927. begin
  928. s:= tai_symbol(hp).sym.name;
  929. WriteDataHeader(s, tai_symbol(hp).is_global, true);
  930. if macos_direct_globals then
  931. begin
  932. writer.AsmWrite(s);
  933. writer.AsmWriteLn(':');
  934. end;
  935. end
  936. else
  937. InternalError(2003071301);
  938. end;
  939. ait_symbol_end:
  940. ;
  941. ait_instruction:
  942. WriteInstruction(hp);
  943. ait_stab,
  944. ait_force_line,
  945. ait_function_name : ;
  946. ait_cutobject :
  947. begin
  948. InternalError(2004101101); {Smart linking is done transparently by the MPW linker.}
  949. end;
  950. ait_marker :
  951. begin
  952. if tai_marker(hp).kind=mark_NoLineInfoStart then
  953. inc(InlineLevel)
  954. else if tai_marker(hp).kind=mark_NoLineInfoEnd then
  955. dec(InlineLevel);
  956. end;
  957. ait_directive :
  958. if tai_directive(hp).directive=asd_cpu then
  959. begin
  960. writer.AsmWrite(asminfo^.comment+' CPU ');
  961. if tai_directive(hp).name<>'' then
  962. writer.AsmWrite(tai_directive(hp).name);
  963. writer.AsmLn;
  964. end
  965. else
  966. internalerror(2016022601);
  967. else
  968. internalerror(2002110303);
  969. end;
  970. hp:=tai(hp.next);
  971. end;
  972. end;
  973. var
  974. currentasmlist : TExternalAssembler;
  975. procedure writeexternal(p:tasmsymbol);
  976. var
  977. s:string;
  978. replaced: boolean;
  979. begin
  980. if tasmsymbol(p).bind=AB_EXTERNAL then
  981. begin
  982. //Writeln('ZZZ ',p.name,' ',p.classname,' ',Ord(tasmsymbol(p).typ));
  983. s:= p.name;
  984. replaced:= ReplaceForbiddenChars(s);
  985. with currentasmlist do
  986. case tasmsymbol(p).typ of
  987. AT_FUNCTION:
  988. begin
  989. writer.AsmWrite(#9'import'#9'.');
  990. writer.AsmWrite(s);
  991. if use_PR then
  992. writer.AsmWrite('[PR]');
  993. if replaced then
  994. begin
  995. writer.AsmWrite(' <= ''.');
  996. writer.AsmWrite(p.name);
  997. if use_PR then
  998. writer.AsmWrite('[PR]''')
  999. else
  1000. writer.AsmWrite('''');
  1001. end;
  1002. writer.AsmLn;
  1003. writer.AsmWrite(#9'import'#9);
  1004. writer.AsmWrite(s);
  1005. writer.AsmWrite('[DS]');
  1006. if replaced then
  1007. begin
  1008. writer.AsmWrite(' <= ''');
  1009. writer.AsmWrite(p.name);
  1010. writer.AsmWrite('[DS]''');
  1011. end;
  1012. writer.AsmLn;
  1013. writer.AsmWriteLn(#9'toc');
  1014. writer.AsmWrite(#9'tc'#9);
  1015. writer.AsmWrite(s);
  1016. writer.AsmWrite('[TC],');
  1017. writer.AsmWrite(s);
  1018. writer.AsmWriteLn('[DS]');
  1019. end;
  1020. AT_DATA:
  1021. begin
  1022. writer.AsmWrite(#9'import'#9);
  1023. writer.AsmWrite(s);
  1024. writer.AsmWrite(var_storage_class);
  1025. if replaced then
  1026. begin
  1027. writer.AsmWrite(' <= ''');
  1028. writer.AsmWrite(p.name);
  1029. writer.AsmWrite('''');
  1030. end;
  1031. writer.AsmLn;
  1032. writer.AsmWriteLn(#9'toc');
  1033. writer.AsmWrite(#9'tc'#9);
  1034. writer.AsmWrite(s);
  1035. writer.AsmWrite('[TC],');
  1036. writer.AsmWrite(s);
  1037. writer.AsmWriteLn(var_storage_class);
  1038. end
  1039. else
  1040. InternalError(2003090901);
  1041. end;
  1042. end;
  1043. end;
  1044. procedure TPPCMPWAssembler.WriteExternals;
  1045. var
  1046. i : longint;
  1047. begin
  1048. currentasmlist:=self;
  1049. // current_asmdata.asmsymboldict.foreach_static(@writeexternal,nil);
  1050. for i:=0 to current_asmdata.AsmSymbolDict.Count-1 do
  1051. begin
  1052. writeexternal(tasmsymbol(current_asmdata.AsmSymbolDict[i]));
  1053. end;
  1054. end;
  1055. function TPPCMPWAssembler.DoAssemble : boolean;
  1056. begin
  1057. DoAssemble:=Inherited DoAssemble;
  1058. end;
  1059. procedure TPPCMPWAssembler.WriteAsmFileHeader;
  1060. begin
  1061. writer.AsmWriteLn(#9'string asis'); {Interpret strings just to be the content between the quotes.}
  1062. writer.AsmWriteLn(#9'aligning off'); {We do our own aligning.}
  1063. writer.AsmLn;
  1064. end;
  1065. procedure TPPCMPWAssembler.WriteAsmList;
  1066. var
  1067. hal : tasmlisttype;
  1068. begin
  1069. {$ifdef EXTDEBUG}
  1070. if assigned(current_module.mainsource) then
  1071. comment(v_info,'Start writing MPW-styled assembler output for '+current_module.mainsource^);
  1072. {$endif}
  1073. WriteAsmFileHeader;
  1074. WriteExternals;
  1075. for hal:=low(TasmlistType) to high(TasmlistType) do
  1076. begin
  1077. writer.AsmWriteLn(asminfo^.comment+'Begin asmlist '+AsmListTypeStr[hal]);
  1078. writetree(current_asmdata.asmlists[hal]);
  1079. writer.AsmWriteLn(asminfo^.comment+'End asmlist '+AsmListTypeStr[hal]);
  1080. end;
  1081. writer.AsmWriteLn(#9'end');
  1082. writer.AsmLn;
  1083. {$ifdef EXTDEBUG}
  1084. if assigned(current_module.mainsource) then
  1085. comment(v_info,'Done writing MPW-styled assembler output for '+current_module.mainsource^);
  1086. {$endif EXTDEBUG}
  1087. end;
  1088. {*****************************************************************************
  1089. Initialize
  1090. *****************************************************************************}
  1091. const
  1092. as_powerpc_mpw_info : tasminfo =
  1093. (
  1094. id : as_powerpc_mpw;
  1095. idtxt : 'MPW';
  1096. asmbin : 'PPCAsm';
  1097. asmcmd : '-case on $ASM $EXTRAOPT -o $OBJ';
  1098. supported_targets : [system_powerpc_macos];
  1099. flags : [af_needar,af_smartlink_sections,af_labelprefix_only_inside_procedure];
  1100. labelprefix : '@';
  1101. comment : '; ';
  1102. dollarsign: 's';
  1103. );
  1104. initialization
  1105. RegisterAssembler(as_powerpc_mpw_info,TPPCMPWAssembler);
  1106. end.