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