agppcmpw.pas 39 KB

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