agppcmpw.pas 39 KB

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