2
0

agppcmpw.pas 39 KB

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