agppcmpw.pas 39 KB

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