agppcmpw.pas 39 KB

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