2
0

agppcmpw.pas 39 KB

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