narmbas.pas 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259
  1. {
  2. Copyright (c) 2024 by J. Gareth "Kit" Moreton
  3. This unit implements the ARM and AArch64-specific assembly node
  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 narmbas;
  18. {$i fpcdefs.inc}
  19. interface
  20. uses
  21. nbas, ncgbas, aasmtai;
  22. type
  23. TArmGenAsmNode = class(TCGAsmNode)
  24. {$ifdef DEBUG_NODE_XML}
  25. procedure XMLPrintNodeData(var T: Text); override;
  26. protected
  27. function XMLFormatOp(const Oper: POper): string; override;
  28. procedure XMLProcessInstruction(var T: Text; p: tai); override;
  29. {$endif DEBUG_NODE_XML}
  30. end;
  31. implementation
  32. {$ifdef DEBUG_NODE_XML}
  33. uses
  34. cutils,
  35. cgutils,
  36. cgbase,
  37. cpubase,
  38. itcpugas,
  39. aasmcpu,
  40. {$ifdef arm}
  41. agarmgas, { Needed for gas_shiftmode2str }
  42. {$endif arm}
  43. {$ifdef aarch64}
  44. agcpugas, { Needed for gas_shiftmode2str }
  45. {$endif aarch64}
  46. verbose;
  47. {$endif DEBUG_NODE_XML}
  48. {$ifdef DEBUG_NODE_XML}
  49. function TArmGenAsmNode.XMLFormatOp(const Oper: POper): string;
  50. {$ifdef arm}
  51. var
  52. NotFirst: Boolean;
  53. ThisSupReg: TSuperRegister;
  54. {$endif arm}
  55. begin
  56. case Oper^.typ of
  57. top_const:
  58. begin
  59. case Oper^.val of
  60. -15..15:
  61. Result := '#' + tostr(Oper^.val);
  62. $10..$FF:
  63. Result := '#0x' + hexstr(Oper^.val, 2);
  64. $100..$FFFF:
  65. Result := '#0x' + hexstr(Oper^.val, 4);
  66. {$ifdef CPU32}
  67. else
  68. Result := '#0x' + hexstr(Oper^.val, 8);
  69. {$else CPU32}
  70. $10000..$FFFFFFFF:
  71. Result := '#0x' + hexstr(Oper^.val, 8);
  72. else
  73. Result := '#0x' + hexstr(Oper^.val, 16);
  74. {$endif CPU32}
  75. end;
  76. end;
  77. top_ref:
  78. with Oper^.ref^ do
  79. begin
  80. if Assigned(symbol) then
  81. begin
  82. Result := symbol.Name;
  83. if (offset <> 0) then
  84. begin
  85. if (offset < 0) then
  86. Result := Result + ' - ' + tostr(-offset)
  87. else
  88. Result := Result + ' + ' + tostr(offset);
  89. end;
  90. end
  91. else
  92. begin
  93. if (base <> NR_NO) then
  94. begin
  95. Result := '[' + gas_regname(base);
  96. if addressmode = AM_POSTINDEXED then
  97. Result := Result + '], '
  98. else if (offset <> 0) or (shiftmode <> SM_None) then
  99. Result := Result + ', ';
  100. end
  101. else { Usually a special kind of reference used by ldm/stm instructions }
  102. Result := '';
  103. if index <> NR_NO then
  104. Result := Result + gas_regname(index)
  105. else if (offset <> 0) or (shiftmode <> SM_None) or (addressmode = AM_POSTINDEXED) then
  106. Result := Result + '#' + tostr(offset);
  107. {$ifdef arm}
  108. if shiftmode = SM_RRX then
  109. Result := Result + ', rrx' { Implicit value of 1 }
  110. else
  111. {$endif arm}
  112. if shiftmode <> SM_None then
  113. Result := Result + ', ' + gas_shiftmode2str[shiftmode] + ' #' + tostr(shiftimm);
  114. if addressmode <> AM_POSTINDEXED then
  115. begin
  116. if (base <> NR_NO) then
  117. Result := Result + ']';
  118. if addressmode = AM_PREINDEXED then
  119. Result := Result + '!';
  120. end;
  121. end;
  122. end;
  123. {$ifdef arm}
  124. top_regset:
  125. begin
  126. Result := '{';
  127. NotFirst := False;
  128. for ThisSupReg in Oper^.regset^ do
  129. begin
  130. if NotFirst then
  131. Result := Result + ', ';
  132. Result := Result + gas_regname(newreg(Oper^.regtyp, ThisSupReg, Oper^.subreg));
  133. NotFirst := True;
  134. end;
  135. Result := Result + '}';
  136. end;
  137. top_specialreg:
  138. with Oper^ do
  139. begin
  140. Result := gas_regname(specialreg) + '_';
  141. if (srC in specialflags) then
  142. Result := Result + 'c';
  143. if (srX in specialflags) then
  144. Result := Result + 'x';
  145. if (srF in specialflags) then
  146. Result := Result + 'f';
  147. if (srS in specialflags) then
  148. Result := Result + 's';
  149. end;
  150. {$endif arm}
  151. {$ifdef aarch64}
  152. top_indexedreg:
  153. with Oper^ do
  154. Result := gas_regname(indexedreg)+'['+tostr(regindex)+']';
  155. {$endif aarch64}
  156. top_conditioncode:
  157. Result := cond2str[Oper^.cc];
  158. top_realconst:
  159. Result := '#' + realtostr(Oper^.val_real);
  160. top_shifterop:
  161. with Oper^.shifterop^ do
  162. begin
  163. {$ifdef arm}
  164. if shiftmode = SM_RRX then
  165. begin
  166. Result := 'rrx'; { Implicit value of 1 }
  167. Exit;
  168. end;
  169. Result := gas_shiftmode2str[shiftmode] + ' ';
  170. if rs <> NR_NO then
  171. Result := Result + gas_regname(rs)
  172. else
  173. Result := Result + '#' + tostr(shiftimm);
  174. {$endif arm}
  175. {$ifdef aarch64}
  176. Result := gas_shiftmode2str[shiftmode] + ' #' + tostr(shiftimm);
  177. {$endif aarch64}
  178. end;
  179. else
  180. Result := inherited XMLFormatOp(Oper);
  181. end;
  182. end;
  183. procedure TArmGenAsmNode.XMLProcessInstruction(var T: Text; p: tai);
  184. var
  185. ThisOp, ThisOper: string;
  186. X: Integer;
  187. begin
  188. if p.typ = ait_instruction then
  189. begin
  190. ThisOp := gas_op2str[taicpu(p).opcode] + cond2str[taicpu(p).condition] + oppostfix2str[taicpu(p).oppostfix];
  191. { Pad the opcode with spaces so the succeeding operands are aligned }
  192. XMLPadString(ThisOp, 7);
  193. Write(T, PrintNodeIndention, ' ', ThisOp); { Extra indentation to account for label formatting }
  194. for X := 0 to taicpu(p).ops - 1 do
  195. begin
  196. Write(T, ' ');
  197. ThisOper := XMLFormatOp(taicpu(p).oper[X]);
  198. if X < taicpu(p).ops - 1 then
  199. begin
  200. ThisOper := ThisOper + ',';
  201. XMLPadString(ThisOper, 4);
  202. end;
  203. Write(T, ThisOper);
  204. end;
  205. WriteLn(T);
  206. end
  207. else
  208. inherited XMLProcessInstruction(T, p);
  209. end;
  210. procedure TArmGenAsmNode.XMLPrintNodeData(var T: Text);
  211. var
  212. hp: tai;
  213. begin
  214. if not Assigned(p_asm) then
  215. Exit;
  216. hp := tai(p_asm.First);
  217. while Assigned(hp) do
  218. begin
  219. XMLProcessInstruction(T, hp);
  220. hp := tai(hp.Next);
  221. end;
  222. end;
  223. {$endif DEBUG_NODE_XML}
  224. initialization
  225. casmnode := TArmGenAsmNode;
  226. end.