agppcmpw.pas 38 KB

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