agppcmpw.pas 40 KB

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