agppcmpw.pas 39 KB

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