agppcmpw.pas 39 KB

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