agppcmpw.pas 40 KB

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