agppcmpw.pas 40 KB

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