cpugas.pas 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387
  1. {
  2. Copyright (c) 1999-2009 by Florian Klaempfl and David Zhang
  3. This unit implements an asmoutput class for MIPS assembly 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. unit cpugas;
  18. {$i fpcdefs.inc}
  19. interface
  20. uses
  21. cpubase,
  22. aasmtai, aasmcpu, assemble, aggas;
  23. type
  24. TMIPSGNUAssembler = class(TGNUassembler)
  25. constructor create(smart: boolean); override;
  26. end;
  27. TMIPSInstrWriter = class(TCPUInstrWriter)
  28. procedure WriteInstruction(hp : tai);override;
  29. end;
  30. const
  31. use_std_regnames : boolean =
  32. {$ifndef USE_MIPS_GAS_REGS}
  33. true;
  34. {$else}
  35. false;
  36. {$endif}
  37. implementation
  38. uses
  39. aasmbase, cutils, systems,
  40. verbose, itcpugas, cgbase, cgutils;
  41. function gas_std_regname(r:Tregister):string;
  42. var
  43. hr: tregister;
  44. p: longint;
  45. begin
  46. { Double uses the same table as single }
  47. hr := r;
  48. case getsubreg(hr) of
  49. R_SUBFD:
  50. setsubreg(hr, R_SUBFS);
  51. R_SUBL, R_SUBW, R_SUBD, R_SUBQ:
  52. setsubreg(hr, R_SUBD);
  53. end;
  54. result:=std_regname(hr);
  55. end;
  56. function asm_regname(reg : TRegister) : string;
  57. begin
  58. if use_std_regnames then
  59. asm_regname:='$'+gas_std_regname(reg)
  60. else
  61. asm_regname:=gas_regname(reg);
  62. end;
  63. {****************************************************************************}
  64. { GNU MIPS Assembler writer }
  65. {****************************************************************************}
  66. constructor TMIPSGNUAssembler.create(smart: boolean);
  67. begin
  68. inherited create(smart);
  69. InstrWriter := TMIPSInstrWriter.create(self);
  70. end;
  71. {****************************************************************************}
  72. { Helper routines for Instruction Writer }
  73. {****************************************************************************}
  74. function GetReferenceString(var ref: TReference): string;
  75. var
  76. hasgot : boolean;
  77. gotprefix : string;
  78. begin
  79. GetReferenceString := '';
  80. hasgot:=false;
  81. with ref do
  82. begin
  83. if (base = NR_NO) and (index = NR_NO) then
  84. begin
  85. if assigned(symbol) then
  86. begin
  87. GetReferenceString := symbol.Name;
  88. if symbol.typ=AT_FUNCTION then
  89. gotprefix:='%call16('
  90. else
  91. gotprefix:='%got(';
  92. hasgot:=true;
  93. end;
  94. if offset > 0 then
  95. GetReferenceString := GetReferenceString + '+' + ToStr(offset)
  96. else if offset < 0 then
  97. GetReferenceString := GetReferenceString + ToStr(offset);
  98. case refaddr of
  99. addr_high:
  100. GetReferenceString := '%hi(' + GetReferenceString + ')';
  101. addr_low:
  102. GetReferenceString := '%lo(' + GetReferenceString + ')';
  103. addr_pic:
  104. begin
  105. if hasgot then
  106. GetReferenceString := gotprefix + GetReferenceString + ')'
  107. else
  108. internalerror(2012070401);
  109. end;
  110. end;
  111. end
  112. else
  113. begin
  114. {$ifdef extdebug}
  115. if assigned(symbol) and
  116. not(refaddr in [addr_pic,addr_low]) then
  117. internalerror(2003052601);
  118. {$endif extdebug}
  119. if base <> NR_NO then
  120. GetReferenceString := GetReferenceString + '(' + asm_regname(base) + ')';
  121. if index = NR_NO then
  122. begin
  123. if offset <> 0 then
  124. GetReferenceString := ToStr(offset) + GetReferenceString;
  125. if assigned(symbol) then
  126. begin
  127. if refaddr = addr_low then
  128. GetReferenceString := '%lo(' + symbol.Name + ')' + GetReferenceString
  129. else if refaddr = addr_pic then
  130. begin
  131. if hasgot then
  132. GetReferenceString := gotprefix + GetReferenceString + ')'
  133. else
  134. internalerror(2012070401);
  135. end
  136. else
  137. GetReferenceString := symbol.Name + {'+' +} GetReferenceString;
  138. end;
  139. end
  140. else
  141. begin
  142. {$ifdef extdebug}
  143. if (Offset<>0) or assigned(symbol) then
  144. internalerror(2003052603);
  145. {$endif extdebug}
  146. GetReferenceString := GetReferenceString + '(' + asm_regname(index) + ')';
  147. end;
  148. end;
  149. end;
  150. end;
  151. function getopstr(const Oper: TOper): string;
  152. begin
  153. with Oper do
  154. case typ of
  155. top_reg:
  156. getopstr := asm_regname(reg);
  157. top_const:
  158. getopstr := tostr(longint(val));
  159. top_ref:
  160. if (oper.ref^.refaddr in [addr_no, addr_pic]) or ((oper.ref^.refaddr = addr_low) and ((oper.ref^.base <> NR_NO) or
  161. (oper.ref^.index <> NR_NO))) then
  162. getopstr := getreferencestring(ref^)
  163. else
  164. getopstr := getreferencestring(ref^);
  165. else
  166. internalerror(10001);
  167. end;
  168. end;
  169. function getopstr_4(const Oper: TOper): string;
  170. var
  171. tmpref: treference;
  172. begin
  173. with Oper do
  174. case typ of
  175. top_ref:
  176. begin
  177. tmpref := ref^;
  178. Inc(tmpref.offset, 4);
  179. getopstr_4 := getreferencestring(tmpref);
  180. end;
  181. else
  182. internalerror(2007050403);
  183. end;
  184. end;
  185. {
  186. function getnextfpreg(tmpfpu : shortstring) : shortstring;
  187. begin
  188. case length(tmpfpu) of
  189. 3:
  190. if (tmpfpu[3] = '9') then
  191. tmpfpu:='$f10'
  192. else
  193. tmpfpu[3] := succ(tmpfpu[3]);
  194. 4:
  195. if (tmpfpu[4] = '9') then
  196. tmpfpu:='$f20'
  197. else
  198. tmpfpu[4] := succ(tmpfpu[4]);
  199. else
  200. internalerror(20120531);
  201. end;
  202. getnextfpreg := tmpfpu;
  203. end;
  204. }
  205. procedure TMIPSInstrWriter.WriteInstruction(hp: Tai);
  206. var
  207. Op: TAsmOp;
  208. s,s1: string;
  209. i: integer;
  210. tmpfpu: string;
  211. tmpfpu_len: longint;
  212. r: TRegister;
  213. begin
  214. if hp.typ <> ait_instruction then
  215. exit;
  216. op := taicpu(hp).opcode;
  217. case op of
  218. A_P_SET_NOMIPS16:
  219. begin
  220. s := #9 + '.set' + #9 + 'nomips16';
  221. owner.AsmWriteLn(s);
  222. end;
  223. A_P_MASK,
  224. A_P_FMASK:
  225. begin
  226. s := #9 + gas_op2str[op] + #9'0x' + hexstr(taicpu(hp).oper[0]^.val,8)+ ',' + getopstr(taicpu(hp).oper[1]^) ;
  227. owner.AsmWriteLn(s);
  228. end;
  229. A_P_SET_MACRO:
  230. begin
  231. s := #9 + '.set' + #9 + 'macro';
  232. owner.AsmWriteLn(s);
  233. end;
  234. A_P_SET_REORDER:
  235. begin
  236. s := #9 + '.set' + #9 + 'reorder';
  237. owner.AsmWriteLn(s);
  238. end;
  239. A_P_SET_NOMACRO:
  240. begin
  241. s := #9 + '.set' + #9 + 'nomacro';
  242. owner.AsmWriteLn(s);
  243. end;
  244. A_P_SET_NOREORDER:
  245. begin
  246. s := #9 + '.set' + #9 + 'noreorder';
  247. owner.AsmWriteLn(s);
  248. end;
  249. A_P_SW:
  250. begin
  251. s := #9 + gas_op2str[A_SW] + #9 + getopstr(taicpu(hp).oper[0]^)+ ',' + getopstr(taicpu(hp).oper[2]^) + '(' + getopstr(taicpu(hp).oper[1]^) + ')';
  252. owner.AsmWriteLn(s);
  253. end;
  254. A_P_LW:
  255. begin
  256. s := #9 + gas_op2str[A_LW] + #9 + getopstr(taicpu(hp).oper[0]^)+ ',' + getopstr(taicpu(hp).oper[2]^) + '(' + getopstr(taicpu(hp).oper[1]^) + ')';
  257. owner.AsmWriteLn(s);
  258. end;
  259. A_LDC1:
  260. begin
  261. if (target_info.endian = endian_big) then
  262. begin
  263. s := #9 + gas_op2str[A_LDC1] + #9 + getopstr(taicpu(hp).oper[0]^)
  264. + ',' + getopstr(taicpu(hp).oper[1]^);
  265. end
  266. else
  267. begin
  268. tmpfpu := getopstr(taicpu(hp).oper[0]^);
  269. s := #9 + gas_op2str[A_LWC1] + #9 + tmpfpu + ',' + getopstr(taicpu(hp).oper[1]^); // + '(' + getopstr(taicpu(hp).oper[1]^) + ')';
  270. owner.AsmWriteLn(s);
  271. { bug if $f9/$f19
  272. tmpfpu_len := length(tmpfpu);
  273. tmpfpu[tmpfpu_len] := succ(tmpfpu[tmpfpu_len]);
  274. }
  275. r := taicpu(hp).oper[0]^.reg;
  276. setsupreg(r, getsupreg(r) + 1);
  277. tmpfpu := asm_regname(r);
  278. s := #9 + gas_op2str[A_LWC1] + #9 + tmpfpu + ',' + getopstr_4(taicpu(hp).oper[1]^); // + '(' + getopstr(taicpu(hp).oper[1]^) + ')';
  279. end;
  280. owner.AsmWriteLn(s);
  281. end;
  282. A_SDC1:
  283. begin
  284. if (target_info.endian = endian_big) then
  285. begin
  286. s := #9 + gas_op2str[A_SDC1] + #9 + getopstr(taicpu(hp).oper[0]^)
  287. + ',' + getopstr(taicpu(hp).oper[1]^);
  288. end
  289. else
  290. begin
  291. tmpfpu := getopstr(taicpu(hp).oper[0]^);
  292. s := #9 + gas_op2str[A_SWC1] + #9 + tmpfpu + ',' + getopstr(taicpu(hp).oper[1]^); //+ ',' + getopstr(taicpu(hp).oper[2]^) + '(' + getopstr(taicpu(hp).oper[1]^) + ')';
  293. owner.AsmWriteLn(s);
  294. {
  295. tmpfpu_len := length(tmpfpu);
  296. tmpfpu[tmpfpu_len] := succ(tmpfpu[tmpfpu_len]);
  297. }
  298. r := taicpu(hp).oper[0]^.reg;
  299. setsupreg(r, getsupreg(r) + 1);
  300. tmpfpu := asm_regname(r);
  301. s := #9 + gas_op2str[A_SWC1] + #9 + tmpfpu + ',' + getopstr_4(taicpu(hp).oper[1]^); //+ ',' + getopstr(taicpu(hp).oper[2]^) + '(' + getopstr(taicpu(hp).oper[1]^) + ')';
  302. end;
  303. owner.AsmWriteLn(s);
  304. end;
  305. else
  306. begin
  307. s := #9 + gas_op2str[op] + cond2str[taicpu(hp).condition];
  308. if taicpu(hp).delayslot_annulled then
  309. s := s + ',a';
  310. if taicpu(hp).ops > 0 then
  311. begin
  312. s := s + #9 + getopstr(taicpu(hp).oper[0]^);
  313. for i := 1 to taicpu(hp).ops - 1 do
  314. s := s + ',' + getopstr(taicpu(hp).oper[i]^);
  315. end;
  316. owner.AsmWriteLn(s);
  317. end;
  318. end;
  319. end;
  320. const
  321. as_MIPSEL_as_info: tasminfo =
  322. (
  323. id: as_gas;
  324. idtxt: 'AS';
  325. asmbin: 'as';
  326. asmcmd: '-mips2 $NOWARN -EL $PIC -o $OBJ $ASM';
  327. supported_targets: [system_mipsel_linux];
  328. flags: [af_allowdirect, af_needar, af_smartlink_sections];
  329. labelprefix: '.L';
  330. comment: '# ';
  331. dollarsign: '$';
  332. );
  333. as_MIPSEB_as_info: tasminfo =
  334. (
  335. id: as_gas;
  336. idtxt: 'AS';
  337. asmbin: 'as';
  338. asmcmd: '-mips2 $NOWARN -EB $PIC -o $OBJ $ASM';
  339. supported_targets: [system_mipseb_linux];
  340. flags: [af_allowdirect, af_needar, af_smartlink_sections];
  341. labelprefix: '.L';
  342. comment: '# ';
  343. dollarsign: '$';
  344. );
  345. begin
  346. {$ifdef MIPSEL}
  347. RegisterAssembler(as_MIPSEL_as_info, TMIPSGNUAssembler);
  348. {$else MIPSEL}
  349. RegisterAssembler(as_MIPSEB_as_info, TMIPSGNUAssembler);
  350. {$endif MIPSEL}
  351. end.