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',
  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. '',
  90. '',
  91. '',
  92. '',
  93. '',
  94. '',
  95. '',
  96. ''
  97. );
  98. type
  99. t64bitarray = array[0..7] of byte;
  100. t32bitarray = array[0..3] of byte;
  101. function ReplaceForbiddenChars(var s: string):Boolean;
  102. {Returns wheater a replacement has occured.}
  103. var
  104. i:Integer;
  105. {The dollar sign is not allowed in MPW PPCAsm}
  106. begin
  107. ReplaceForbiddenChars:=false;
  108. for i:=1 to Length(s) do
  109. if s[i]='$' then
  110. begin
  111. s[i]:='s';
  112. ReplaceForbiddenChars:=true;
  113. end;
  114. end;
  115. {*** From here is copyed from agppcgas.pp, except where marked with CHANGED.
  116. Perhaps put in a third common file. ***}
  117. function getreferencestring(var ref : treference) : string;
  118. var
  119. s : string;
  120. begin
  121. with ref do
  122. begin
  123. if (refaddr <> addr_no) then
  124. InternalError(2002110301)
  125. else if ((offset < -32768) or (offset > 32767)) then
  126. InternalError(19991);
  127. if assigned(symbol) then
  128. begin
  129. s:= symbol.name;
  130. ReplaceForbiddenChars(s);
  131. {if symbol.typ = AT_FUNCTION then
  132. ;}
  133. s:= s+'[TC]' {ref to TOC entry }
  134. end
  135. else
  136. s:= '';
  137. if offset<0 then
  138. s:=s+tostr(offset)
  139. else
  140. if (offset>0) then
  141. begin
  142. if assigned(symbol) then
  143. s:=s+'+'+tostr(offset)
  144. else
  145. s:=s+tostr(offset);
  146. end;
  147. if (index=NR_NO) and (base<>NR_NO) then
  148. begin
  149. if offset=0 then
  150. if not assigned(symbol) then
  151. s:=s+'0';
  152. s:=s+'('+gas_regname(base)+')';
  153. end
  154. else if (index<>NR_NO) and (base<>NR_NO) and (offset=0) then
  155. begin
  156. if (offset=0) then
  157. s:=s+gas_regname(base)+','+gas_regname(index)
  158. else
  159. internalerror(19992);
  160. end
  161. else if (base=NR_NO) and (offset=0) then
  162. begin
  163. {Temporary fix for inline asm, where a local var is referenced.}
  164. //if assigned(symbol) then
  165. // s:= s+'(rtoc)';
  166. end;
  167. end;
  168. getreferencestring:=s;
  169. end;
  170. function getopstr_jmp(const o:toper) : string;
  171. var
  172. hs : string;
  173. begin
  174. case o.typ of
  175. top_reg :
  176. getopstr_jmp:=gas_regname(o.reg);
  177. { no top_ref jumping for powerpc }
  178. top_const :
  179. getopstr_jmp:=tostr(o.val);
  180. top_ref :
  181. begin
  182. if o.ref^.refaddr=addr_full then
  183. begin
  184. hs:=o.ref^.symbol.name;
  185. ReplaceForbiddenChars(hs);
  186. case o.ref^.symbol.typ of
  187. AT_FUNCTION:
  188. begin
  189. if hs[1] <> '@' then {if not local label}
  190. if use_PR then
  191. hs:= '.'+hs+'[PR]'
  192. else
  193. hs:= '.'+hs
  194. end
  195. else
  196. ;
  197. end;
  198. if o.ref^.offset>0 then
  199. hs:=hs+'+'+tostr(o.ref^.offset)
  200. else
  201. if o.ref^.offset<0 then
  202. hs:=hs+tostr(o.ref^.offset);
  203. getopstr_jmp:=hs;
  204. end
  205. else
  206. internalerror(200402263);
  207. end;
  208. top_none:
  209. getopstr_jmp:='';
  210. else
  211. internalerror(2002070603);
  212. end;
  213. end;
  214. function getopstr(const o:toper) : string;
  215. var
  216. hs : string;
  217. begin
  218. case o.typ of
  219. top_reg:
  220. getopstr:=gas_regname(o.reg);
  221. top_const:
  222. getopstr:=tostr(longint(o.val));
  223. top_ref:
  224. if o.ref^.refaddr=addr_no then
  225. getopstr:=getreferencestring(o.ref^)
  226. else
  227. begin
  228. hs:=o.ref^.symbol.name;
  229. ReplaceForbiddenChars(hs);
  230. if o.ref^.offset>0 then
  231. hs:=hs+'+'+tostr(o.ref^.offset)
  232. else
  233. if o.ref^.offset<0 then
  234. hs:=hs+tostr(o.ref^.offset);
  235. getopstr:=hs;
  236. end;
  237. else
  238. internalerror(2002070604);
  239. end;
  240. end;
  241. type
  242. topstr = string[4];
  243. function branchmode(o: tasmop): topstr;
  244. var tempstr: topstr;
  245. begin
  246. tempstr := '';
  247. case o of
  248. A_BCCTR,A_BCCTRL: tempstr := 'ctr';
  249. A_BCLR,A_BCLRL: tempstr := 'lr';
  250. end;
  251. case o of
  252. A_BL,A_BLA,A_BCL,A_BCLA,A_BCCTRL,A_BCLRL: tempstr := tempstr+'l';
  253. end;
  254. case o of
  255. A_BA,A_BLA,A_BCA,A_BCLA: tempstr:=tempstr+'a';
  256. end;
  257. branchmode := tempstr;
  258. end;
  259. function cond2str(op: tasmop; c: tasmcond): string;
  260. { note: no checking is performed whether the given combination of }
  261. { conditions is valid }
  262. var
  263. tempstr: string;
  264. begin
  265. tempstr:=#9;
  266. case c.simple of
  267. false:
  268. begin
  269. cond2str := tempstr+gas_op2str[op];
  270. case c.dirhint of
  271. DH_None:;
  272. DH_Minus:
  273. cond2str:=cond2str+'-';
  274. DH_Plus:
  275. cond2str:=cond2str+'+';
  276. else
  277. internalerror(2003112901);
  278. end;
  279. cond2str:=cond2str+#9+tostr(c.bo)+','+tostr(c.bi)+',';
  280. end;
  281. true:
  282. if (op >= A_B) and (op <= A_BCLRL) then
  283. case c.cond of
  284. { unconditional branch }
  285. C_NONE:
  286. cond2str := tempstr+gas_op2str[op];
  287. { bdnzt etc }
  288. else
  289. begin
  290. tempstr := tempstr+'b'+asmcondflag2str[c.cond]+
  291. branchmode(op);
  292. case c.dirhint of
  293. DH_None:
  294. tempstr:=tempstr+#9;
  295. DH_Minus:
  296. tempstr:=tempstr+('-'+#9);
  297. DH_Plus:
  298. tempstr:=tempstr+('+'+#9);
  299. else
  300. internalerror(2003112901);
  301. end;
  302. case c.cond of
  303. C_LT..C_NU:
  304. cond2str := tempstr+gas_regname(newreg(R_SPECIALREGISTER,c.cr,R_SUBWHOLE));
  305. C_T,C_F,C_DNZT,C_DNZF,C_DZT,C_DZF:
  306. cond2str := tempstr+tostr(c.crbit);
  307. else
  308. cond2str := tempstr;
  309. end;
  310. end;
  311. end
  312. { we have a trap instruction }
  313. else
  314. begin
  315. internalerror(2002070601);
  316. { not yet implemented !!!!!!!!!!!!!!!!!!!!! }
  317. { case tempstr := 'tw';}
  318. end;
  319. end;
  320. end;
  321. procedure TPPCMPWAssembler.WriteInstruction(hp : tai);
  322. var op: TAsmOp;
  323. s: string;
  324. i: byte;
  325. sep: string[3];
  326. begin
  327. op:=taicpu(hp).opcode;
  328. if is_calljmp(op) then
  329. begin
  330. { direct BO/BI in op[0] and op[1] not supported, put them in condition! }
  331. case op of
  332. A_B,A_BA:
  333. s:=#9+gas_op2str[op]+#9;
  334. A_BCTR,A_BCTRL,A_BLR,A_BLRL:
  335. s:=#9+gas_op2str[op];
  336. A_BL,A_BLA:
  337. s:=#9+gas_op2str[op]+#9;
  338. else
  339. begin
  340. s:=cond2str(op,taicpu(hp).condition);
  341. if (s[length(s)] <> #9) and
  342. (taicpu(hp).ops>0) then
  343. s := s + ',';
  344. end;
  345. end;
  346. if (taicpu(hp).ops>0) and (taicpu(hp).oper[0]^.typ<>top_none) then
  347. begin
  348. { first write the current contents of s, because the symbol }
  349. { may be 255 characters }
  350. asmwrite(s);
  351. s:=getopstr_jmp(taicpu(hp).oper[0]^);
  352. end;
  353. end
  354. else
  355. { process operands }
  356. begin
  357. s:=#9+gas_op2str[op];
  358. if taicpu(hp).ops<>0 then
  359. begin
  360. sep:=#9;
  361. for i:=0 to taicpu(hp).ops-1 do
  362. begin
  363. s:=s+sep+getopstr(taicpu(hp).oper[i]^);
  364. sep:=',';
  365. end;
  366. end;
  367. end;
  368. AsmWriteLn(s);
  369. end;
  370. {*** Until here is copyed from agppcgas.pp. ***}
  371. function single2str(d : single) : string;
  372. var
  373. hs : string;
  374. p : byte;
  375. begin
  376. str(d,hs);
  377. { nasm expects a lowercase e }
  378. p:=pos('E',hs);
  379. if p>0 then
  380. hs[p]:='e';
  381. p:=pos('+',hs);
  382. if p>0 then
  383. delete(hs,p,1);
  384. single2str:=lower(hs);
  385. end;
  386. function double2str(d : double) : string;
  387. var
  388. hs : string;
  389. p : byte;
  390. begin
  391. str(d,hs);
  392. { nasm expects a lowercase e }
  393. p:=pos('E',hs);
  394. if p>0 then
  395. hs[p]:='e';
  396. p:=pos('+',hs);
  397. if p>0 then
  398. delete(hs,p,1);
  399. double2str:=lower(hs);
  400. end;
  401. { convert floating point values }
  402. { to correct endian }
  403. procedure swap64bitarray(var t: t64bitarray);
  404. var
  405. b: byte;
  406. begin
  407. b:= t[7];
  408. t[7] := t[0];
  409. t[0] := b;
  410. b := t[6];
  411. t[6] := t[1];
  412. t[1] := b;
  413. b:= t[5];
  414. t[5] := t[2];
  415. t[2] := b;
  416. b:= t[4];
  417. t[4] := t[3];
  418. t[3] := b;
  419. end;
  420. procedure swap32bitarray(var t: t32bitarray);
  421. var
  422. b: byte;
  423. begin
  424. b:= t[1];
  425. t[1]:= t[2];
  426. t[2]:= b;
  427. b:= t[0];
  428. t[0]:= t[3];
  429. t[3]:= b;
  430. end;
  431. function fixline(s:string):string;
  432. {
  433. return s with all leading and ending spaces and tabs removed
  434. }
  435. var
  436. i,j,k : longint;
  437. begin
  438. i:=length(s);
  439. while (i>0) and (s[i] in [#9,' ']) do
  440. dec(i);
  441. j:=1;
  442. while (j<i) and (s[j] in [#9,' ']) do
  443. inc(j);
  444. for k:=j to i do
  445. if s[k] in [#0..#31,#127..#255] then
  446. s[k]:='.';
  447. fixline:=Copy(s,j,i-j+1);
  448. end;
  449. Function PadTabs(const p:string;addch:char):string;
  450. var
  451. s : string;
  452. i : longint;
  453. begin
  454. i:=length(p);
  455. if addch<>#0 then
  456. begin
  457. inc(i);
  458. s:=p+addch;
  459. end
  460. else
  461. s:=p;
  462. if i<8 then
  463. PadTabs:=s+#9#9
  464. else
  465. PadTabs:=s+#9;
  466. end;
  467. {****************************************************************************
  468. PowerPC MPW Assembler
  469. ****************************************************************************}
  470. procedure TPPCMPWAssembler.WriteProcedureHeader(var hp:tai);
  471. {Returns the current hp where the caller should continue from}
  472. {For multiple entry procedures, only the last is exported as xxx[PR]
  473. (if use_PR is set) }
  474. procedure WriteExportHeader(hp:tai);
  475. var
  476. s: string;
  477. replaced: boolean;
  478. begin
  479. s:= tai_symbol(hp).sym.name;
  480. replaced:= ReplaceForbiddenChars(s);
  481. if not use_PR then
  482. begin
  483. AsmWrite(#9'export'#9'.');
  484. AsmWrite(s);
  485. if replaced then
  486. begin
  487. AsmWrite(' => ''.');
  488. AsmWrite(tai_symbol(hp).sym.name);
  489. AsmWrite('''');
  490. end;
  491. AsmLn;
  492. end;
  493. AsmWrite(#9'export'#9);
  494. AsmWrite(s);
  495. AsmWrite('[DS]');
  496. if replaced then
  497. begin
  498. AsmWrite(' => ''');
  499. AsmWrite(tai_symbol(hp).sym.name);
  500. AsmWrite('[DS]''');
  501. end;
  502. AsmLn;
  503. {Entry in transition vector: }
  504. AsmWrite(#9'csect'#9); AsmWrite(s); AsmWriteLn('[DS]');
  505. AsmWrite(#9'dc.l'#9'.'); AsmWriteLn(s);
  506. AsmWriteln(#9'dc.l'#9'TOC[tc0]');
  507. {Entry in TOC: }
  508. AsmWriteLn(#9'toc');
  509. AsmWrite(#9'tc'#9);
  510. AsmWrite(s); AsmWrite('[TC],');
  511. AsmWrite(s); AsmWriteln('[DS]');
  512. end;
  513. function GetAdjacentTaiSymbol(var hp:tai):Boolean;
  514. begin
  515. GetAdjacentTaiSymbol:= false;
  516. while assigned(hp.next) do
  517. case tai(hp.next).typ of
  518. ait_symbol:
  519. begin
  520. hp:=tai(hp.next);
  521. GetAdjacentTaiSymbol:= true;
  522. Break;
  523. end;
  524. ait_function_name:
  525. hp:=tai(hp.next);
  526. else
  527. begin
  528. //AsmWriteln(' ;#*#*# ' + tostr(Ord(tai(hp.next).typ)));
  529. Break;
  530. end;
  531. end;
  532. end;
  533. var
  534. first,last: tai;
  535. s: string;
  536. replaced: boolean;
  537. begin
  538. s:= tai_symbol(hp).sym.name;
  539. {Write all headers}
  540. first:= hp;
  541. repeat
  542. WriteExportHeader(hp);
  543. last:= hp;
  544. until not GetAdjacentTaiSymbol(hp);
  545. {Start the section of the body of the proc: }
  546. s:= tai_symbol(last).sym.name;
  547. replaced:= ReplaceForbiddenChars(s);
  548. if use_PR then
  549. begin
  550. AsmWrite(#9'export'#9'.'); AsmWrite(s); AsmWrite('[PR]');
  551. if replaced then
  552. begin
  553. AsmWrite(' => ''.');
  554. AsmWrite(tai_symbol(last).sym.name);
  555. AsmWrite('[PR]''');
  556. end;
  557. AsmLn;
  558. end;
  559. {Starts the section: }
  560. AsmWrite(#9'csect'#9'.');
  561. AsmWrite(s);
  562. AsmWriteLn('[PR]');
  563. {Info for the debugger: }
  564. AsmWrite(#9'function'#9'.');
  565. AsmWrite(s);
  566. AsmWriteLn('[PR]');
  567. {Write all labels: }
  568. hp:= first;
  569. repeat
  570. s:= tai_symbol(hp).sym.name;
  571. ReplaceForbiddenChars(s);
  572. AsmWrite('.'); AsmWrite(s); AsmWriteLn(':');
  573. until not GetAdjacentTaiSymbol(hp);
  574. end;
  575. procedure TPPCMPWAssembler.WriteDataHeader(var s:string; isExported, isConst:boolean);
  576. // Returns in s the changed string
  577. var
  578. sym: string;
  579. replaced: boolean;
  580. begin
  581. sym:= s;
  582. replaced:= ReplaceForbiddenChars(s);
  583. if isExported then
  584. begin
  585. AsmWrite(#9'export'#9);
  586. AsmWrite(s);
  587. if isConst then
  588. AsmWrite(const_storage_class)
  589. else
  590. AsmWrite(var_storage_class);
  591. if replaced then
  592. begin
  593. AsmWrite(' => ''');
  594. AsmWrite(sym);
  595. AsmWrite('''');
  596. end;
  597. AsmLn;
  598. end;
  599. if not macos_direct_globals then
  600. begin
  601. {The actual section is here interrupted, by inserting a "tc" entry}
  602. AsmWriteLn(#9'toc');
  603. AsmWrite(#9'tc'#9);
  604. AsmWrite(s);
  605. AsmWrite('[TC], ');
  606. AsmWrite(s);
  607. if isConst then
  608. AsmWrite(const_storage_class)
  609. else
  610. AsmWrite(var_storage_class);
  611. AsmLn;
  612. {The interrupted section is here continued.}
  613. AsmWrite(#9'csect'#9);
  614. AsmWriteln(cur_CSECT_name+cur_CSECT_class);
  615. AsmWrite(PadTabs(s+':',#0));
  616. end
  617. else
  618. begin
  619. AsmWrite(#9'csect'#9);
  620. AsmWrite(s);
  621. AsmWrite('[TC]');
  622. end;
  623. AsmLn;
  624. end;
  625. const
  626. ait_const2str:array[aitconst_32bit..aitconst_8bit] of string[8]=
  627. (#9'dc.l'#9,#9'dc.w'#9,#9'dc.b'#9);
  628. procedure TPPCMPWAssembler.WriteTree(p:TAsmList);
  629. var
  630. s : string;
  631. hp : tai;
  632. hp1 : tailineinfo;
  633. counter,
  634. lines,
  635. InlineLevel : longint;
  636. i,j,l : longint;
  637. consttype : taiconst_type;
  638. do_line,DoNotSplitLine,
  639. quoted : boolean;
  640. sin : single;
  641. d : double;
  642. begin
  643. if not assigned(p) then
  644. exit;
  645. InlineLevel:=0;
  646. { lineinfo is only needed for al_procedures (PFV) }
  647. do_line:=((cs_asm_source in current_settings.globalswitches) or
  648. (cs_lineinfo in current_settings.moduleswitches))
  649. and (p=current_asmdata.asmlists[al_procedures]);
  650. DoNotSplitLine:=false;
  651. hp:=tai(p.first);
  652. while assigned(hp) do
  653. begin
  654. if not(hp.typ in SkipLineInfo) and
  655. not DoNotSplitLine then
  656. begin
  657. hp1 := hp as tailineinfo;
  658. if do_line then
  659. begin
  660. { load infile }
  661. if lastfileinfo.fileindex<>hp1.fileinfo.fileindex then
  662. begin
  663. infile:=current_module.sourcefiles.get_file(hp1.fileinfo.fileindex);
  664. if assigned(infile) then
  665. begin
  666. { open only if needed !! }
  667. if (cs_asm_source in current_settings.globalswitches) then
  668. infile.open;
  669. end;
  670. { avoid unnecessary reopens of the same file !! }
  671. lastfileinfo.fileindex:=hp1.fileinfo.fileindex;
  672. { be sure to change line !! }
  673. lastfileinfo.line:=-1;
  674. end;
  675. { write source }
  676. if (cs_asm_source in current_settings.globalswitches) and
  677. assigned(infile) then
  678. begin
  679. if (infile<>lastinfile) then
  680. begin
  681. AsmWriteLn(target_asm.comment+'['+infile.name^+']');
  682. if assigned(lastinfile) then
  683. lastinfile.close;
  684. end;
  685. if (hp1.fileinfo.line<>lastfileinfo.line) and
  686. ((hp1.fileinfo.line<infile.maxlinebuf) or (InlineLevel>0)) then
  687. begin
  688. if (hp1.fileinfo.line<>0) and
  689. ((infile.linebuf^[hp1.fileinfo.line]>=0) or (InlineLevel>0)) then
  690. AsmWriteLn(target_asm.comment+'['+tostr(hp1.fileinfo.line)+'] '+
  691. fixline(infile.GetLineStr(hp1.fileinfo.line)));
  692. { set it to a negative value !
  693. to make that is has been read already !! PM }
  694. if (infile.linebuf^[hp1.fileinfo.line]>=0) then
  695. infile.linebuf^[hp1.fileinfo.line]:=-infile.linebuf^[hp1.fileinfo.line]-1;
  696. end;
  697. end;
  698. lastfileinfo:=hp1.fileinfo;
  699. lastinfile:=infile;
  700. end;
  701. end;
  702. DoNotSplitLine:=false;
  703. case hp.typ of
  704. ait_comment:
  705. begin
  706. AsmWrite(target_asm.comment);
  707. AsmWritePChar(tai_comment(hp).str);
  708. AsmLn;
  709. end;
  710. ait_regalloc,
  711. ait_tempalloc:
  712. ;
  713. ait_section:
  714. begin
  715. {if LastSecType<>sec_none then
  716. AsmWriteLn('_'+target_asm.secnames[LastSecType]+#9#9'ENDS');}
  717. if tai_section(hp).sectype<>sec_none then
  718. begin
  719. if tai_section(hp).sectype in [sec_data,sec_rodata,sec_bss] then
  720. cur_CSECT_class:= '[RW]'
  721. else if tai_section(hp).sectype in [sec_code] then
  722. cur_CSECT_class:= ''
  723. else
  724. cur_CSECT_class:= '[RO]';
  725. s:= tai_section(hp).name^;
  726. if s = '' then
  727. InternalError(2004101001); {Nameless sections should not occur on MPW}
  728. ReplaceForbiddenChars(s);
  729. cur_CSECT_name:= s;
  730. AsmLn;
  731. AsmWriteLn(#9+secnames[tai_section(hp).sectype]+' '+cur_CSECT_name+cur_CSECT_class);
  732. end;
  733. LastSecType:=tai_section(hp).sectype;
  734. end;
  735. ait_align:
  736. begin
  737. case tai_align(hp).aligntype of
  738. 1:AsmWriteLn(#9'align 0');
  739. 2:AsmWriteLn(#9'align 1');
  740. 4:AsmWriteLn(#9'align 2');
  741. otherwise internalerror(2002110302);
  742. end;
  743. end;
  744. ait_datablock: {Storage for global variables.}
  745. begin
  746. s:= tai_datablock(hp).sym.name;
  747. WriteDataHeader(s, tai_datablock(hp).is_global, false);
  748. if not macos_direct_globals then
  749. begin
  750. AsmWriteLn(#9'ds.b '+tostr(tai_datablock(hp).size));
  751. end
  752. else
  753. begin
  754. AsmWriteLn(PadTabs(s+':',#0)+'ds.b '+tostr(tai_datablock(hp).size));
  755. {TODO: ? PadTabs(s,#0) }
  756. end;
  757. end;
  758. ait_const:
  759. begin
  760. consttype:=tai_const(hp).consttype;
  761. case consttype of
  762. aitconst_128bit:
  763. begin
  764. internalerror(200404291);
  765. end;
  766. aitconst_64bit:
  767. begin
  768. if assigned(tai_const(hp).sym) then
  769. internalerror(200404292);
  770. AsmWrite(ait_const2str[aitconst_32bit]);
  771. if target_info.endian = endian_little then
  772. begin
  773. AsmWrite(tostr(longint(lo(tai_const(hp).value))));
  774. AsmWrite(',');
  775. AsmWrite(tostr(longint(hi(tai_const(hp).value))));
  776. end
  777. else
  778. begin
  779. AsmWrite(tostr(longint(hi(tai_const(hp).value))));
  780. AsmWrite(',');
  781. AsmWrite(tostr(longint(lo(tai_const(hp).value))));
  782. end;
  783. AsmLn;
  784. end;
  785. aitconst_uleb128bit,
  786. aitconst_sleb128bit,
  787. aitconst_32bit,
  788. aitconst_16bit,
  789. aitconst_8bit,
  790. aitconst_rva_symbol,
  791. aitconst_indirect_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_InlineStart then
  1036. inc(InlineLevel)
  1037. else if tai_marker(hp).kind=mark_InlineEnd 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.