agppcmpw.pas 40 KB

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