agppcmpw.pas 40 KB

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