agppcmpw.pas 39 KB

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