agppcmpw.pas 39 KB

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