ShaderDecodeAlu.cs 38 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178
  1. using System;
  2. using static Ryujinx.Graphics.Gal.Shader.ShaderDecodeHelper;
  3. namespace Ryujinx.Graphics.Gal.Shader
  4. {
  5. static partial class ShaderDecode
  6. {
  7. public static void Bfe_C(ShaderIrBlock Block, long OpCode, int Position)
  8. {
  9. EmitBfe(Block, OpCode, ShaderOper.CR);
  10. }
  11. public static void Bfe_I(ShaderIrBlock Block, long OpCode, int Position)
  12. {
  13. EmitBfe(Block, OpCode, ShaderOper.Imm);
  14. }
  15. public static void Bfe_R(ShaderIrBlock Block, long OpCode, int Position)
  16. {
  17. EmitBfe(Block, OpCode, ShaderOper.RR);
  18. }
  19. public static void Fadd_C(ShaderIrBlock Block, long OpCode, int Position)
  20. {
  21. EmitFadd(Block, OpCode, ShaderOper.CR);
  22. }
  23. public static void Fadd_I(ShaderIrBlock Block, long OpCode, int Position)
  24. {
  25. EmitFadd(Block, OpCode, ShaderOper.Immf);
  26. }
  27. public static void Fadd_I32(ShaderIrBlock Block, long OpCode, int Position)
  28. {
  29. ShaderIrNode OperA = OpCode.Gpr8();
  30. ShaderIrNode OperB = OpCode.Immf32_20();
  31. bool NegB = OpCode.Read(53);
  32. bool AbsA = OpCode.Read(54);
  33. bool NegA = OpCode.Read(56);
  34. bool AbsB = OpCode.Read(57);
  35. OperA = GetAluFabsFneg(OperA, AbsA, NegA);
  36. OperB = GetAluFabsFneg(OperB, AbsB, NegB);
  37. ShaderIrOp Op = new ShaderIrOp(ShaderIrInst.Fadd, OperA, OperB);
  38. Block.AddNode(OpCode.PredNode(new ShaderIrAsg(OpCode.Gpr0(), Op)));
  39. }
  40. public static void Fadd_R(ShaderIrBlock Block, long OpCode, int Position)
  41. {
  42. EmitFadd(Block, OpCode, ShaderOper.RR);
  43. }
  44. public static void Ffma_CR(ShaderIrBlock Block, long OpCode, int Position)
  45. {
  46. EmitFfma(Block, OpCode, ShaderOper.CR);
  47. }
  48. public static void Ffma_I(ShaderIrBlock Block, long OpCode, int Position)
  49. {
  50. EmitFfma(Block, OpCode, ShaderOper.Immf);
  51. }
  52. public static void Ffma_RC(ShaderIrBlock Block, long OpCode, int Position)
  53. {
  54. EmitFfma(Block, OpCode, ShaderOper.RC);
  55. }
  56. public static void Ffma_RR(ShaderIrBlock Block, long OpCode, int Position)
  57. {
  58. EmitFfma(Block, OpCode, ShaderOper.RR);
  59. }
  60. public static void Fmnmx_C(ShaderIrBlock Block, long OpCode, int Position)
  61. {
  62. EmitFmnmx(Block, OpCode, ShaderOper.CR);
  63. }
  64. public static void Fmnmx_I(ShaderIrBlock Block, long OpCode, int Position)
  65. {
  66. EmitFmnmx(Block, OpCode, ShaderOper.Immf);
  67. }
  68. public static void Fmnmx_R(ShaderIrBlock Block, long OpCode, int Position)
  69. {
  70. EmitFmnmx(Block, OpCode, ShaderOper.RR);
  71. }
  72. public static void Fmul_I32(ShaderIrBlock Block, long OpCode, int Position)
  73. {
  74. ShaderIrNode OperA = OpCode.Gpr8();
  75. ShaderIrNode OperB = OpCode.Immf32_20();
  76. ShaderIrOp Op = new ShaderIrOp(ShaderIrInst.Fmul, OperA, OperB);
  77. Block.AddNode(OpCode.PredNode(new ShaderIrAsg(OpCode.Gpr0(), Op)));
  78. }
  79. public static void Fmul_C(ShaderIrBlock Block, long OpCode, int Position)
  80. {
  81. EmitFmul(Block, OpCode, ShaderOper.CR);
  82. }
  83. public static void Fmul_I(ShaderIrBlock Block, long OpCode, int Position)
  84. {
  85. EmitFmul(Block, OpCode, ShaderOper.Immf);
  86. }
  87. public static void Fmul_R(ShaderIrBlock Block, long OpCode, int Position)
  88. {
  89. EmitFmul(Block, OpCode, ShaderOper.RR);
  90. }
  91. public static void Fset_C(ShaderIrBlock Block, long OpCode, int Position)
  92. {
  93. EmitFset(Block, OpCode, ShaderOper.CR);
  94. }
  95. public static void Fset_I(ShaderIrBlock Block, long OpCode, int Position)
  96. {
  97. EmitFset(Block, OpCode, ShaderOper.Immf);
  98. }
  99. public static void Fset_R(ShaderIrBlock Block, long OpCode, int Position)
  100. {
  101. EmitFset(Block, OpCode, ShaderOper.RR);
  102. }
  103. public static void Fsetp_C(ShaderIrBlock Block, long OpCode, int Position)
  104. {
  105. EmitFsetp(Block, OpCode, ShaderOper.CR);
  106. }
  107. public static void Fsetp_I(ShaderIrBlock Block, long OpCode, int Position)
  108. {
  109. EmitFsetp(Block, OpCode, ShaderOper.Immf);
  110. }
  111. public static void Fsetp_R(ShaderIrBlock Block, long OpCode, int Position)
  112. {
  113. EmitFsetp(Block, OpCode, ShaderOper.RR);
  114. }
  115. public static void Iadd_C(ShaderIrBlock Block, long OpCode, int Position)
  116. {
  117. EmitIadd(Block, OpCode, ShaderOper.CR);
  118. }
  119. public static void Iadd_I(ShaderIrBlock Block, long OpCode, int Position)
  120. {
  121. EmitIadd(Block, OpCode, ShaderOper.Imm);
  122. }
  123. public static void Iadd_I32(ShaderIrBlock Block, long OpCode, int Position)
  124. {
  125. ShaderIrNode OperA = OpCode.Gpr8();
  126. ShaderIrNode OperB = OpCode.Imm32_20();
  127. bool NegA = OpCode.Read(56);
  128. OperA = GetAluIneg(OperA, NegA);
  129. ShaderIrOp Op = new ShaderIrOp(ShaderIrInst.Add, OperA, OperB);
  130. Block.AddNode(OpCode.PredNode(new ShaderIrAsg(OpCode.Gpr0(), Op)));
  131. }
  132. public static void Iadd_R(ShaderIrBlock Block, long OpCode, int Position)
  133. {
  134. EmitIadd(Block, OpCode, ShaderOper.RR);
  135. }
  136. public static void Iadd3_C(ShaderIrBlock Block, long OpCode, int Position)
  137. {
  138. EmitIadd3(Block, OpCode, ShaderOper.CR);
  139. }
  140. public static void Iadd3_I(ShaderIrBlock Block, long OpCode, int Position)
  141. {
  142. EmitIadd3(Block, OpCode, ShaderOper.Imm);
  143. }
  144. public static void Iadd3_R(ShaderIrBlock Block, long OpCode, int Position)
  145. {
  146. EmitIadd3(Block, OpCode, ShaderOper.RR);
  147. }
  148. public static void Imnmx_C(ShaderIrBlock Block, long OpCode, int Position)
  149. {
  150. EmitImnmx(Block, OpCode, ShaderOper.CR);
  151. }
  152. public static void Imnmx_I(ShaderIrBlock Block, long OpCode, int Position)
  153. {
  154. EmitImnmx(Block, OpCode, ShaderOper.Imm);
  155. }
  156. public static void Imnmx_R(ShaderIrBlock Block, long OpCode, int Position)
  157. {
  158. EmitImnmx(Block, OpCode, ShaderOper.RR);
  159. }
  160. public static void Ipa(ShaderIrBlock Block, long OpCode, int Position)
  161. {
  162. ShaderIrNode OperA = OpCode.Abuf28();
  163. ShaderIrNode OperB = OpCode.Gpr20();
  164. ShaderIpaMode Mode = (ShaderIpaMode)(OpCode.Read(54, 3));
  165. ShaderIrMetaIpa Meta = new ShaderIrMetaIpa(Mode);
  166. ShaderIrOp Op = new ShaderIrOp(ShaderIrInst.Ipa, OperA, OperB, null, Meta);
  167. Block.AddNode(OpCode.PredNode(new ShaderIrAsg(OpCode.Gpr0(), Op)));
  168. }
  169. public static void Iscadd_C(ShaderIrBlock Block, long OpCode, int Position)
  170. {
  171. EmitIscadd(Block, OpCode, ShaderOper.CR);
  172. }
  173. public static void Iscadd_I(ShaderIrBlock Block, long OpCode, int Position)
  174. {
  175. EmitIscadd(Block, OpCode, ShaderOper.Imm);
  176. }
  177. public static void Iscadd_R(ShaderIrBlock Block, long OpCode, int Position)
  178. {
  179. EmitIscadd(Block, OpCode, ShaderOper.RR);
  180. }
  181. public static void Iset_C(ShaderIrBlock Block, long OpCode, int Position)
  182. {
  183. EmitIset(Block, OpCode, ShaderOper.CR);
  184. }
  185. public static void Iset_I(ShaderIrBlock Block, long OpCode, int Position)
  186. {
  187. EmitIset(Block, OpCode, ShaderOper.Imm);
  188. }
  189. public static void Iset_R(ShaderIrBlock Block, long OpCode, int Position)
  190. {
  191. EmitIset(Block, OpCode, ShaderOper.RR);
  192. }
  193. public static void Isetp_C(ShaderIrBlock Block, long OpCode, int Position)
  194. {
  195. EmitIsetp(Block, OpCode, ShaderOper.CR);
  196. }
  197. public static void Isetp_I(ShaderIrBlock Block, long OpCode, int Position)
  198. {
  199. EmitIsetp(Block, OpCode, ShaderOper.Imm);
  200. }
  201. public static void Isetp_R(ShaderIrBlock Block, long OpCode, int Position)
  202. {
  203. EmitIsetp(Block, OpCode, ShaderOper.RR);
  204. }
  205. public static void Lop_I32(ShaderIrBlock Block, long OpCode, int Position)
  206. {
  207. int SubOp = OpCode.Read(53, 3);
  208. bool InvA = OpCode.Read(55);
  209. bool InvB = OpCode.Read(56);
  210. ShaderIrInst Inst = 0;
  211. switch (SubOp)
  212. {
  213. case 0: Inst = ShaderIrInst.And; break;
  214. case 1: Inst = ShaderIrInst.Or; break;
  215. case 2: Inst = ShaderIrInst.Xor; break;
  216. }
  217. ShaderIrNode OperB = GetAluNot(OpCode.Imm32_20(), InvB);
  218. //SubOp == 3 is pass, used by the not instruction
  219. //which just moves the inverted register value.
  220. if (SubOp < 3)
  221. {
  222. ShaderIrNode OperA = GetAluNot(OpCode.Gpr8(), InvA);
  223. ShaderIrOp Op = new ShaderIrOp(Inst, OperA, OperB);
  224. Block.AddNode(OpCode.PredNode(new ShaderIrAsg(OpCode.Gpr0(), Op)));
  225. }
  226. else
  227. {
  228. Block.AddNode(OpCode.PredNode(new ShaderIrAsg(OpCode.Gpr0(), OperB)));
  229. }
  230. }
  231. public static void Lop_C(ShaderIrBlock Block, long OpCode, int Position)
  232. {
  233. EmitLop(Block, OpCode, ShaderOper.CR);
  234. }
  235. public static void Lop_I(ShaderIrBlock Block, long OpCode, int Position)
  236. {
  237. EmitLop(Block, OpCode, ShaderOper.Imm);
  238. }
  239. public static void Lop_R(ShaderIrBlock Block, long OpCode, int Position)
  240. {
  241. EmitLop(Block, OpCode, ShaderOper.RR);
  242. }
  243. public static void Mufu(ShaderIrBlock Block, long OpCode, int Position)
  244. {
  245. int SubOp = OpCode.Read(20, 0xf);
  246. bool AbsA = OpCode.Read(46);
  247. bool NegA = OpCode.Read(48);
  248. ShaderIrInst Inst = 0;
  249. switch (SubOp)
  250. {
  251. case 0: Inst = ShaderIrInst.Fcos; break;
  252. case 1: Inst = ShaderIrInst.Fsin; break;
  253. case 2: Inst = ShaderIrInst.Fex2; break;
  254. case 3: Inst = ShaderIrInst.Flg2; break;
  255. case 4: Inst = ShaderIrInst.Frcp; break;
  256. case 5: Inst = ShaderIrInst.Frsq; break;
  257. case 8: Inst = ShaderIrInst.Fsqrt; break;
  258. default: throw new NotImplementedException(SubOp.ToString());
  259. }
  260. ShaderIrNode OperA = OpCode.Gpr8();
  261. ShaderIrOp Op = new ShaderIrOp(Inst, GetAluFabsFneg(OperA, AbsA, NegA));
  262. Block.AddNode(OpCode.PredNode(new ShaderIrAsg(OpCode.Gpr0(), Op)));
  263. }
  264. public static void Psetp(ShaderIrBlock Block, long OpCode, int Position)
  265. {
  266. bool NegA = OpCode.Read(15);
  267. bool NegB = OpCode.Read(32);
  268. bool NegP = OpCode.Read(42);
  269. ShaderIrInst LopInst = OpCode.BLop24();
  270. ShaderIrNode OperA = OpCode.Pred12();
  271. ShaderIrNode OperB = OpCode.Pred29();
  272. if (NegA)
  273. {
  274. OperA = new ShaderIrOp(ShaderIrInst.Bnot, OperA);
  275. }
  276. if (NegB)
  277. {
  278. OperB = new ShaderIrOp(ShaderIrInst.Bnot, OperB);
  279. }
  280. ShaderIrOp Op = new ShaderIrOp(LopInst, OperA, OperB);
  281. ShaderIrOperPred P0Node = OpCode.Pred3();
  282. ShaderIrOperPred P1Node = OpCode.Pred0();
  283. ShaderIrOperPred P2Node = OpCode.Pred39();
  284. Block.AddNode(OpCode.PredNode(new ShaderIrAsg(P0Node, Op)));
  285. LopInst = OpCode.BLop45();
  286. if (LopInst == ShaderIrInst.Band && P1Node.IsConst && P2Node.IsConst)
  287. {
  288. return;
  289. }
  290. ShaderIrNode P2NNode = P2Node;
  291. if (NegP)
  292. {
  293. P2NNode = new ShaderIrOp(ShaderIrInst.Bnot, P2NNode);
  294. }
  295. Op = new ShaderIrOp(ShaderIrInst.Bnot, P0Node);
  296. Op = new ShaderIrOp(LopInst, Op, P2NNode);
  297. Block.AddNode(OpCode.PredNode(new ShaderIrAsg(P1Node, Op)));
  298. Op = new ShaderIrOp(LopInst, P0Node, P2NNode);
  299. Block.AddNode(OpCode.PredNode(new ShaderIrAsg(P0Node, Op)));
  300. }
  301. public static void Rro_C(ShaderIrBlock Block, long OpCode, int Position)
  302. {
  303. EmitRro(Block, OpCode, ShaderOper.CR);
  304. }
  305. public static void Rro_I(ShaderIrBlock Block, long OpCode, int Position)
  306. {
  307. EmitRro(Block, OpCode, ShaderOper.Immf);
  308. }
  309. public static void Rro_R(ShaderIrBlock Block, long OpCode, int Position)
  310. {
  311. EmitRro(Block, OpCode, ShaderOper.RR);
  312. }
  313. public static void Shl_C(ShaderIrBlock Block, long OpCode, int Position)
  314. {
  315. EmitAluBinary(Block, OpCode, ShaderOper.CR, ShaderIrInst.Lsl);
  316. }
  317. public static void Shl_I(ShaderIrBlock Block, long OpCode, int Position)
  318. {
  319. EmitAluBinary(Block, OpCode, ShaderOper.Imm, ShaderIrInst.Lsl);
  320. }
  321. public static void Shl_R(ShaderIrBlock Block, long OpCode, int Position)
  322. {
  323. EmitAluBinary(Block, OpCode, ShaderOper.RR, ShaderIrInst.Lsl);
  324. }
  325. public static void Shr_C(ShaderIrBlock Block, long OpCode, int Position)
  326. {
  327. EmitAluBinary(Block, OpCode, ShaderOper.CR, GetShrInst(OpCode));
  328. }
  329. public static void Shr_I(ShaderIrBlock Block, long OpCode, int Position)
  330. {
  331. EmitAluBinary(Block, OpCode, ShaderOper.Imm, GetShrInst(OpCode));
  332. }
  333. public static void Shr_R(ShaderIrBlock Block, long OpCode, int Position)
  334. {
  335. EmitAluBinary(Block, OpCode, ShaderOper.RR, GetShrInst(OpCode));
  336. }
  337. private static ShaderIrInst GetShrInst(long OpCode)
  338. {
  339. bool Signed = OpCode.Read(48);
  340. return Signed ? ShaderIrInst.Asr : ShaderIrInst.Lsr;
  341. }
  342. public static void Vmad(ShaderIrBlock Block, long OpCode, int Position)
  343. {
  344. ShaderIrNode OperA = OpCode.Gpr8();
  345. ShaderIrNode OperB;
  346. if (OpCode.Read(50))
  347. {
  348. OperB = OpCode.Gpr20();
  349. }
  350. else
  351. {
  352. OperB = OpCode.Imm19_20();
  353. }
  354. ShaderIrOperGpr OperC = OpCode.Gpr39();
  355. ShaderIrNode Tmp = new ShaderIrOp(ShaderIrInst.Mul, OperA, OperB);
  356. ShaderIrNode Final = new ShaderIrOp(ShaderIrInst.Add, Tmp, OperC);
  357. int Shr = OpCode.Read(51, 3);
  358. if (Shr != 0)
  359. {
  360. int Shift = (Shr == 2) ? 15 : 7;
  361. Final = new ShaderIrOp(ShaderIrInst.Lsr, Final, new ShaderIrOperImm(Shift));
  362. }
  363. Block.AddNode(new ShaderIrCmnt("Stubbed. Instruction is reduced to a * b + c"));
  364. Block.AddNode(OpCode.PredNode(new ShaderIrAsg(OpCode.Gpr0(), Final)));
  365. }
  366. public static void Xmad_CR(ShaderIrBlock Block, long OpCode, int Position)
  367. {
  368. EmitXmad(Block, OpCode, ShaderOper.CR);
  369. }
  370. public static void Xmad_I(ShaderIrBlock Block, long OpCode, int Position)
  371. {
  372. EmitXmad(Block, OpCode, ShaderOper.Imm);
  373. }
  374. public static void Xmad_RC(ShaderIrBlock Block, long OpCode, int Position)
  375. {
  376. EmitXmad(Block, OpCode, ShaderOper.RC);
  377. }
  378. public static void Xmad_RR(ShaderIrBlock Block, long OpCode, int Position)
  379. {
  380. EmitXmad(Block, OpCode, ShaderOper.RR);
  381. }
  382. private static void EmitAluBinary(
  383. ShaderIrBlock Block,
  384. long OpCode,
  385. ShaderOper Oper,
  386. ShaderIrInst Inst)
  387. {
  388. ShaderIrNode OperA = OpCode.Gpr8(), OperB;
  389. switch (Oper)
  390. {
  391. case ShaderOper.CR: OperB = OpCode.Cbuf34(); break;
  392. case ShaderOper.Imm: OperB = OpCode.Imm19_20(); break;
  393. case ShaderOper.RR: OperB = OpCode.Gpr20(); break;
  394. default: throw new ArgumentException(nameof(Oper));
  395. }
  396. ShaderIrNode Op = new ShaderIrOp(Inst, OperA, OperB);
  397. Block.AddNode(OpCode.PredNode(new ShaderIrAsg(OpCode.Gpr0(), Op)));
  398. }
  399. private static void EmitBfe(ShaderIrBlock Block, long OpCode, ShaderOper Oper)
  400. {
  401. //TODO: Handle the case where position + length
  402. //is greater than the word size, in this case the sign bit
  403. //needs to be replicated to fill the remaining space.
  404. bool NegB = OpCode.Read(48);
  405. bool NegA = OpCode.Read(49);
  406. ShaderIrNode OperA = OpCode.Gpr8(), OperB;
  407. switch (Oper)
  408. {
  409. case ShaderOper.CR: OperB = OpCode.Cbuf34(); break;
  410. case ShaderOper.Imm: OperB = OpCode.Imm19_20(); break;
  411. case ShaderOper.RR: OperB = OpCode.Gpr20(); break;
  412. default: throw new ArgumentException(nameof(Oper));
  413. }
  414. ShaderIrNode Op;
  415. bool Signed = OpCode.Read(48); //?
  416. if (OperB is ShaderIrOperImm PosLen)
  417. {
  418. int Position = (PosLen.Value >> 0) & 0xff;
  419. int Length = (PosLen.Value >> 8) & 0xff;
  420. int LSh = 32 - (Position + Length);
  421. ShaderIrInst RightShift = Signed
  422. ? ShaderIrInst.Asr
  423. : ShaderIrInst.Lsr;
  424. Op = new ShaderIrOp(ShaderIrInst.Lsl, OperA, new ShaderIrOperImm(LSh));
  425. Op = new ShaderIrOp(RightShift, Op, new ShaderIrOperImm(LSh + Position));
  426. }
  427. else
  428. {
  429. ShaderIrOperImm Shift = new ShaderIrOperImm(8);
  430. ShaderIrOperImm Mask = new ShaderIrOperImm(0xff);
  431. ShaderIrNode OpPos, OpLen;
  432. OpPos = new ShaderIrOp(ShaderIrInst.And, OperB, Mask);
  433. OpLen = new ShaderIrOp(ShaderIrInst.Lsr, OperB, Shift);
  434. OpLen = new ShaderIrOp(ShaderIrInst.And, OpLen, Mask);
  435. Op = new ShaderIrOp(ShaderIrInst.Lsr, OperA, OpPos);
  436. Op = ExtendTo32(Op, Signed, OpLen);
  437. }
  438. Block.AddNode(OpCode.PredNode(new ShaderIrAsg(OpCode.Gpr0(), Op)));
  439. }
  440. private static void EmitFadd(ShaderIrBlock Block, long OpCode, ShaderOper Oper)
  441. {
  442. bool NegB = OpCode.Read(45);
  443. bool AbsA = OpCode.Read(46);
  444. bool NegA = OpCode.Read(48);
  445. bool AbsB = OpCode.Read(49);
  446. ShaderIrNode OperA = OpCode.Gpr8(), OperB;
  447. OperA = GetAluFabsFneg(OperA, AbsA, NegA);
  448. switch (Oper)
  449. {
  450. case ShaderOper.CR: OperB = OpCode.Cbuf34(); break;
  451. case ShaderOper.Immf: OperB = OpCode.Immf19_20(); break;
  452. case ShaderOper.RR: OperB = OpCode.Gpr20(); break;
  453. default: throw new ArgumentException(nameof(Oper));
  454. }
  455. OperB = GetAluFabsFneg(OperB, AbsB, NegB);
  456. ShaderIrNode Op = new ShaderIrOp(ShaderIrInst.Fadd, OperA, OperB);
  457. Block.AddNode(OpCode.PredNode(new ShaderIrAsg(OpCode.Gpr0(), Op)));
  458. }
  459. private static void EmitFmul(ShaderIrBlock Block, long OpCode, ShaderOper Oper)
  460. {
  461. bool NegB = OpCode.Read(48);
  462. ShaderIrNode OperA = OpCode.Gpr8(), OperB;
  463. switch (Oper)
  464. {
  465. case ShaderOper.CR: OperB = OpCode.Cbuf34(); break;
  466. case ShaderOper.Immf: OperB = OpCode.Immf19_20(); break;
  467. case ShaderOper.RR: OperB = OpCode.Gpr20(); break;
  468. default: throw new ArgumentException(nameof(Oper));
  469. }
  470. OperB = GetAluFneg(OperB, NegB);
  471. ShaderIrNode Op = new ShaderIrOp(ShaderIrInst.Fmul, OperA, OperB);
  472. Block.AddNode(OpCode.PredNode(new ShaderIrAsg(OpCode.Gpr0(), Op)));
  473. }
  474. private static void EmitFfma(ShaderIrBlock Block, long OpCode, ShaderOper Oper)
  475. {
  476. bool NegB = OpCode.Read(48);
  477. bool NegC = OpCode.Read(49);
  478. ShaderIrNode OperA = OpCode.Gpr8(), OperB, OperC;
  479. switch (Oper)
  480. {
  481. case ShaderOper.CR: OperB = OpCode.Cbuf34(); break;
  482. case ShaderOper.Immf: OperB = OpCode.Immf19_20(); break;
  483. case ShaderOper.RC: OperB = OpCode.Gpr39(); break;
  484. case ShaderOper.RR: OperB = OpCode.Gpr20(); break;
  485. default: throw new ArgumentException(nameof(Oper));
  486. }
  487. OperB = GetAluFneg(OperB, NegB);
  488. if (Oper == ShaderOper.RC)
  489. {
  490. OperC = GetAluFneg(OpCode.Cbuf34(), NegC);
  491. }
  492. else
  493. {
  494. OperC = GetAluFneg(OpCode.Gpr39(), NegC);
  495. }
  496. ShaderIrOp Op = new ShaderIrOp(ShaderIrInst.Ffma, OperA, OperB, OperC);
  497. Block.AddNode(OpCode.PredNode(new ShaderIrAsg(OpCode.Gpr0(), Op)));
  498. }
  499. private static void EmitIadd(ShaderIrBlock Block, long OpCode, ShaderOper Oper)
  500. {
  501. ShaderIrNode OperA = OpCode.Gpr8();
  502. ShaderIrNode OperB;
  503. switch (Oper)
  504. {
  505. case ShaderOper.CR: OperB = OpCode.Cbuf34(); break;
  506. case ShaderOper.Imm: OperB = OpCode.Imm19_20(); break;
  507. case ShaderOper.RR: OperB = OpCode.Gpr20(); break;
  508. default: throw new ArgumentException(nameof(Oper));
  509. }
  510. bool NegA = OpCode.Read(49);
  511. bool NegB = OpCode.Read(48);
  512. OperA = GetAluIneg(OperA, NegA);
  513. OperB = GetAluIneg(OperB, NegB);
  514. ShaderIrOp Op = new ShaderIrOp(ShaderIrInst.Add, OperA, OperB);
  515. Block.AddNode(OpCode.PredNode(new ShaderIrAsg(OpCode.Gpr0(), Op)));
  516. }
  517. private static void EmitIadd3(ShaderIrBlock Block, long OpCode, ShaderOper Oper)
  518. {
  519. int Mode = OpCode.Read(37, 3);
  520. bool Neg1 = OpCode.Read(51);
  521. bool Neg2 = OpCode.Read(50);
  522. bool Neg3 = OpCode.Read(49);
  523. int Height1 = OpCode.Read(35, 3);
  524. int Height2 = OpCode.Read(33, 3);
  525. int Height3 = OpCode.Read(31, 3);
  526. ShaderIrNode OperB;
  527. switch (Oper)
  528. {
  529. case ShaderOper.CR: OperB = OpCode.Cbuf34(); break;
  530. case ShaderOper.Imm: OperB = OpCode.Imm19_20(); break;
  531. case ShaderOper.RR: OperB = OpCode.Gpr20(); break;
  532. default: throw new ArgumentException(nameof(Oper));
  533. }
  534. ShaderIrNode ApplyHeight(ShaderIrNode Src, int Height)
  535. {
  536. if (Oper != ShaderOper.RR)
  537. {
  538. return Src;
  539. }
  540. switch (Height)
  541. {
  542. case 0: return Src;
  543. case 1: return new ShaderIrOp(ShaderIrInst.And, Src, new ShaderIrOperImm(0xffff));
  544. case 2: return new ShaderIrOp(ShaderIrInst.Lsr, Src, new ShaderIrOperImm(16));
  545. default: throw new InvalidOperationException();
  546. }
  547. }
  548. ShaderIrNode Src1 = GetAluIneg(ApplyHeight(OpCode.Gpr8(), Height1), Neg1);
  549. ShaderIrNode Src2 = GetAluIneg(ApplyHeight(OperB, Height2), Neg2);
  550. ShaderIrNode Src3 = GetAluIneg(ApplyHeight(OpCode.Gpr39(), Height3), Neg3);
  551. ShaderIrOp Sum = new ShaderIrOp(ShaderIrInst.Add, Src1, Src2);
  552. if (Oper == ShaderOper.RR)
  553. {
  554. switch (Mode)
  555. {
  556. case 1: Sum = new ShaderIrOp(ShaderIrInst.Lsr, Sum, new ShaderIrOperImm(16)); break;
  557. case 2: Sum = new ShaderIrOp(ShaderIrInst.Lsl, Sum, new ShaderIrOperImm(16)); break;
  558. }
  559. }
  560. //Note: Here there should be a "+ 1" when carry flag is set
  561. //but since carry is mostly ignored by other instructions, it's excluded for now
  562. Block.AddNode(OpCode.PredNode(new ShaderIrAsg(OpCode.Gpr0(), new ShaderIrOp(ShaderIrInst.Add, Sum, Src3))));
  563. }
  564. private static void EmitIscadd(ShaderIrBlock Block, long OpCode, ShaderOper Oper)
  565. {
  566. bool NegB = OpCode.Read(48);
  567. bool NegA = OpCode.Read(49);
  568. ShaderIrNode OperA = OpCode.Gpr8(), OperB;
  569. ShaderIrOperImm Scale = OpCode.Imm5_39();
  570. switch (Oper)
  571. {
  572. case ShaderOper.CR: OperB = OpCode.Cbuf34(); break;
  573. case ShaderOper.Imm: OperB = OpCode.Imm19_20(); break;
  574. case ShaderOper.RR: OperB = OpCode.Gpr20(); break;
  575. default: throw new ArgumentException(nameof(Oper));
  576. }
  577. OperA = GetAluIneg(OperA, NegA);
  578. OperB = GetAluIneg(OperB, NegB);
  579. ShaderIrOp ScaleOp = new ShaderIrOp(ShaderIrInst.Lsl, OperA, Scale);
  580. ShaderIrOp AddOp = new ShaderIrOp(ShaderIrInst.Add, OperB, ScaleOp);
  581. Block.AddNode(OpCode.PredNode(new ShaderIrAsg(OpCode.Gpr0(), AddOp)));
  582. }
  583. private static void EmitFmnmx(ShaderIrBlock Block, long OpCode, ShaderOper Oper)
  584. {
  585. EmitMnmx(Block, OpCode, true, Oper);
  586. }
  587. private static void EmitImnmx(ShaderIrBlock Block, long OpCode, ShaderOper Oper)
  588. {
  589. EmitMnmx(Block, OpCode, false, Oper);
  590. }
  591. private static void EmitMnmx(ShaderIrBlock Block, long OpCode, bool IsFloat, ShaderOper Oper)
  592. {
  593. bool NegB = OpCode.Read(45);
  594. bool AbsA = OpCode.Read(46);
  595. bool NegA = OpCode.Read(48);
  596. bool AbsB = OpCode.Read(49);
  597. ShaderIrNode OperA = OpCode.Gpr8(), OperB;
  598. if (IsFloat)
  599. {
  600. OperA = GetAluFabsFneg(OperA, AbsA, NegA);
  601. }
  602. else
  603. {
  604. OperA = GetAluIabsIneg(OperA, AbsA, NegA);
  605. }
  606. switch (Oper)
  607. {
  608. case ShaderOper.CR: OperB = OpCode.Cbuf34(); break;
  609. case ShaderOper.Imm: OperB = OpCode.Imm19_20(); break;
  610. case ShaderOper.Immf: OperB = OpCode.Immf19_20(); break;
  611. case ShaderOper.RR: OperB = OpCode.Gpr20(); break;
  612. default: throw new ArgumentException(nameof(Oper));
  613. }
  614. if (IsFloat)
  615. {
  616. OperB = GetAluFabsFneg(OperB, AbsB, NegB);
  617. }
  618. else
  619. {
  620. OperB = GetAluIabsIneg(OperB, AbsB, NegB);
  621. }
  622. ShaderIrOperPred Pred = OpCode.Pred39();
  623. ShaderIrOp Op;
  624. ShaderIrInst MaxInst = IsFloat ? ShaderIrInst.Fmax : ShaderIrInst.Max;
  625. ShaderIrInst MinInst = IsFloat ? ShaderIrInst.Fmin : ShaderIrInst.Min;
  626. if (Pred.IsConst)
  627. {
  628. bool IsMax = OpCode.Read(42);
  629. Op = new ShaderIrOp(IsMax
  630. ? MaxInst
  631. : MinInst, OperA, OperB);
  632. Block.AddNode(OpCode.PredNode(new ShaderIrAsg(OpCode.Gpr0(), Op)));
  633. }
  634. else
  635. {
  636. ShaderIrNode PredN = OpCode.Pred39N();
  637. ShaderIrOp OpMax = new ShaderIrOp(MaxInst, OperA, OperB);
  638. ShaderIrOp OpMin = new ShaderIrOp(MinInst, OperA, OperB);
  639. ShaderIrAsg AsgMax = new ShaderIrAsg(OpCode.Gpr0(), OpMax);
  640. ShaderIrAsg AsgMin = new ShaderIrAsg(OpCode.Gpr0(), OpMin);
  641. Block.AddNode(OpCode.PredNode(new ShaderIrCond(PredN, AsgMax, Not: true)));
  642. Block.AddNode(OpCode.PredNode(new ShaderIrCond(PredN, AsgMin, Not: false)));
  643. }
  644. }
  645. private static void EmitRro(ShaderIrBlock Block, long OpCode, ShaderOper Oper)
  646. {
  647. //Note: this is a range reduction instruction and is supposed to
  648. //be used with Mufu, here it just moves the value and ignores the operation.
  649. bool NegA = OpCode.Read(45);
  650. bool AbsA = OpCode.Read(49);
  651. ShaderIrNode OperA;
  652. switch (Oper)
  653. {
  654. case ShaderOper.CR: OperA = OpCode.Cbuf34(); break;
  655. case ShaderOper.Immf: OperA = OpCode.Immf19_20(); break;
  656. case ShaderOper.RR: OperA = OpCode.Gpr20(); break;
  657. default: throw new ArgumentException(nameof(Oper));
  658. }
  659. OperA = GetAluFabsFneg(OperA, AbsA, NegA);
  660. Block.AddNode(new ShaderIrCmnt("Stubbed."));
  661. Block.AddNode(OpCode.PredNode(new ShaderIrAsg(OpCode.Gpr0(), OperA)));
  662. }
  663. private static void EmitFset(ShaderIrBlock Block, long OpCode, ShaderOper Oper)
  664. {
  665. EmitSet(Block, OpCode, true, Oper);
  666. }
  667. private static void EmitIset(ShaderIrBlock Block, long OpCode, ShaderOper Oper)
  668. {
  669. EmitSet(Block, OpCode, false, Oper);
  670. }
  671. private static void EmitSet(ShaderIrBlock Block, long OpCode, bool IsFloat, ShaderOper Oper)
  672. {
  673. bool NegA = OpCode.Read(43);
  674. bool AbsB = OpCode.Read(44);
  675. bool NegB = OpCode.Read(53);
  676. bool AbsA = OpCode.Read(54);
  677. bool BoolFloat = OpCode.Read(IsFloat ? 52 : 44);
  678. ShaderIrNode OperA = OpCode.Gpr8(), OperB;
  679. switch (Oper)
  680. {
  681. case ShaderOper.CR: OperB = OpCode.Cbuf34(); break;
  682. case ShaderOper.Imm: OperB = OpCode.Imm19_20(); break;
  683. case ShaderOper.Immf: OperB = OpCode.Immf19_20(); break;
  684. case ShaderOper.RR: OperB = OpCode.Gpr20(); break;
  685. default: throw new ArgumentException(nameof(Oper));
  686. }
  687. ShaderIrInst CmpInst;
  688. if (IsFloat)
  689. {
  690. OperA = GetAluFabsFneg(OperA, AbsA, NegA);
  691. OperB = GetAluFabsFneg(OperB, AbsB, NegB);
  692. CmpInst = OpCode.CmpF();
  693. }
  694. else
  695. {
  696. CmpInst = OpCode.Cmp();
  697. }
  698. ShaderIrOp Op = new ShaderIrOp(CmpInst, OperA, OperB);
  699. ShaderIrInst LopInst = OpCode.BLop45();
  700. ShaderIrOperPred PNode = OpCode.Pred39();
  701. ShaderIrNode Imm0, Imm1;
  702. if (BoolFloat)
  703. {
  704. Imm0 = new ShaderIrOperImmf(0);
  705. Imm1 = new ShaderIrOperImmf(1);
  706. }
  707. else
  708. {
  709. Imm0 = new ShaderIrOperImm(0);
  710. Imm1 = new ShaderIrOperImm(-1);
  711. }
  712. ShaderIrNode Asg0 = new ShaderIrAsg(OpCode.Gpr0(), Imm0);
  713. ShaderIrNode Asg1 = new ShaderIrAsg(OpCode.Gpr0(), Imm1);
  714. if (LopInst != ShaderIrInst.Band || !PNode.IsConst)
  715. {
  716. ShaderIrOp Op2 = new ShaderIrOp(LopInst, Op, PNode);
  717. Asg0 = new ShaderIrCond(Op2, Asg0, Not: true);
  718. Asg1 = new ShaderIrCond(Op2, Asg1, Not: false);
  719. }
  720. else
  721. {
  722. Asg0 = new ShaderIrCond(Op, Asg0, Not: true);
  723. Asg1 = new ShaderIrCond(Op, Asg1, Not: false);
  724. }
  725. Block.AddNode(OpCode.PredNode(Asg0));
  726. Block.AddNode(OpCode.PredNode(Asg1));
  727. }
  728. private static void EmitFsetp(ShaderIrBlock Block, long OpCode, ShaderOper Oper)
  729. {
  730. EmitSetp(Block, OpCode, true, Oper);
  731. }
  732. private static void EmitIsetp(ShaderIrBlock Block, long OpCode, ShaderOper Oper)
  733. {
  734. EmitSetp(Block, OpCode, false, Oper);
  735. }
  736. private static void EmitSetp(ShaderIrBlock Block, long OpCode, bool IsFloat, ShaderOper Oper)
  737. {
  738. bool AbsA = OpCode.Read(7);
  739. bool NegP = OpCode.Read(42);
  740. bool NegA = OpCode.Read(43);
  741. bool AbsB = OpCode.Read(44);
  742. ShaderIrNode OperA = OpCode.Gpr8(), OperB;
  743. switch (Oper)
  744. {
  745. case ShaderOper.CR: OperB = OpCode.Cbuf34(); break;
  746. case ShaderOper.Imm: OperB = OpCode.Imm19_20(); break;
  747. case ShaderOper.Immf: OperB = OpCode.Immf19_20(); break;
  748. case ShaderOper.RR: OperB = OpCode.Gpr20(); break;
  749. default: throw new ArgumentException(nameof(Oper));
  750. }
  751. ShaderIrInst CmpInst;
  752. if (IsFloat)
  753. {
  754. OperA = GetAluFabsFneg(OperA, AbsA, NegA);
  755. OperB = GetAluFabs (OperB, AbsB);
  756. CmpInst = OpCode.CmpF();
  757. }
  758. else
  759. {
  760. CmpInst = OpCode.Cmp();
  761. }
  762. ShaderIrOp Op = new ShaderIrOp(CmpInst, OperA, OperB);
  763. ShaderIrOperPred P0Node = OpCode.Pred3();
  764. ShaderIrOperPred P1Node = OpCode.Pred0();
  765. ShaderIrOperPred P2Node = OpCode.Pred39();
  766. Block.AddNode(OpCode.PredNode(new ShaderIrAsg(P0Node, Op)));
  767. ShaderIrInst LopInst = OpCode.BLop45();
  768. if (LopInst == ShaderIrInst.Band && P1Node.IsConst && P2Node.IsConst)
  769. {
  770. return;
  771. }
  772. ShaderIrNode P2NNode = P2Node;
  773. if (NegP)
  774. {
  775. P2NNode = new ShaderIrOp(ShaderIrInst.Bnot, P2NNode);
  776. }
  777. Op = new ShaderIrOp(ShaderIrInst.Bnot, P0Node);
  778. Op = new ShaderIrOp(LopInst, Op, P2NNode);
  779. Block.AddNode(OpCode.PredNode(new ShaderIrAsg(P1Node, Op)));
  780. Op = new ShaderIrOp(LopInst, P0Node, P2NNode);
  781. Block.AddNode(OpCode.PredNode(new ShaderIrAsg(P0Node, Op)));
  782. }
  783. private static void EmitLop(ShaderIrBlock Block, long OpCode, ShaderOper Oper)
  784. {
  785. int SubOp = OpCode.Read(41, 3);
  786. bool InvA = OpCode.Read(39);
  787. bool InvB = OpCode.Read(40);
  788. ShaderIrInst Inst = 0;
  789. switch (SubOp)
  790. {
  791. case 0: Inst = ShaderIrInst.And; break;
  792. case 1: Inst = ShaderIrInst.Or; break;
  793. case 2: Inst = ShaderIrInst.Xor; break;
  794. }
  795. ShaderIrNode OperA = GetAluNot(OpCode.Gpr8(), InvA);
  796. ShaderIrNode OperB;
  797. switch (Oper)
  798. {
  799. case ShaderOper.CR: OperB = OpCode.Cbuf34(); break;
  800. case ShaderOper.Imm: OperB = OpCode.Imm19_20(); break;
  801. case ShaderOper.RR: OperB = OpCode.Gpr20(); break;
  802. default: throw new ArgumentException(nameof(Oper));
  803. }
  804. OperB = GetAluNot(OperB, InvB);
  805. ShaderIrNode Op;
  806. if (SubOp < 3)
  807. {
  808. Op = new ShaderIrOp(Inst, OperA, OperB);
  809. }
  810. else
  811. {
  812. Op = OperB;
  813. }
  814. ShaderIrNode Compare = new ShaderIrOp(ShaderIrInst.Cne, Op, new ShaderIrOperImm(0));
  815. Block.AddNode(OpCode.PredNode(new ShaderIrAsg(OpCode.Pred48(), Compare)));
  816. Block.AddNode(OpCode.PredNode(new ShaderIrAsg(OpCode.Gpr0(), Op)));
  817. }
  818. private static void EmitXmad(ShaderIrBlock Block, long OpCode, ShaderOper Oper)
  819. {
  820. //TODO: Confirm SignAB/C, it is just a guess.
  821. //TODO: Implement Mode 3 (CSFU), what it does?
  822. bool SignAB = OpCode.Read(48);
  823. bool SignC = OpCode.Read(49);
  824. bool HighB = OpCode.Read(52);
  825. bool HighA = OpCode.Read(53);
  826. int Mode = OpCode.Read(50, 7);
  827. ShaderIrNode OperA = OpCode.Gpr8(), OperB, OperC;
  828. ShaderIrOperImm Imm16 = new ShaderIrOperImm(16);
  829. ShaderIrOperImm ImmMsk = new ShaderIrOperImm(0xffff);
  830. ShaderIrInst ShiftAB = SignAB ? ShaderIrInst.Asr : ShaderIrInst.Lsr;
  831. ShaderIrInst ShiftC = SignC ? ShaderIrInst.Asr : ShaderIrInst.Lsr;
  832. if (HighA)
  833. {
  834. OperA = new ShaderIrOp(ShiftAB, OperA, Imm16);
  835. }
  836. switch (Oper)
  837. {
  838. case ShaderOper.CR: OperB = OpCode.Cbuf34(); break;
  839. case ShaderOper.Imm: OperB = OpCode.Imm19_20(); break;
  840. case ShaderOper.RC: OperB = OpCode.Gpr39(); break;
  841. case ShaderOper.RR: OperB = OpCode.Gpr20(); break;
  842. default: throw new ArgumentException(nameof(Oper));
  843. }
  844. bool ProductShiftLeft = false, Merge = false;
  845. if (Oper == ShaderOper.RC)
  846. {
  847. OperC = OpCode.Cbuf34();
  848. }
  849. else
  850. {
  851. OperC = OpCode.Gpr39();
  852. ProductShiftLeft = OpCode.Read(36);
  853. Merge = OpCode.Read(37);
  854. }
  855. switch (Mode)
  856. {
  857. //CLO.
  858. case 1: OperC = ExtendTo32(OperC, SignC, 16); break;
  859. //CHI.
  860. case 2: OperC = new ShaderIrOp(ShiftC, OperC, Imm16); break;
  861. }
  862. ShaderIrNode OperBH = OperB;
  863. if (HighB)
  864. {
  865. OperBH = new ShaderIrOp(ShiftAB, OperBH, Imm16);
  866. }
  867. ShaderIrOp MulOp = new ShaderIrOp(ShaderIrInst.Mul, OperA, OperBH);
  868. if (ProductShiftLeft)
  869. {
  870. MulOp = new ShaderIrOp(ShaderIrInst.Lsl, MulOp, Imm16);
  871. }
  872. ShaderIrOp AddOp = new ShaderIrOp(ShaderIrInst.Add, MulOp, OperC);
  873. if (Merge)
  874. {
  875. AddOp = new ShaderIrOp(ShaderIrInst.And, AddOp, ImmMsk);
  876. OperB = new ShaderIrOp(ShaderIrInst.Lsl, OperB, Imm16);
  877. AddOp = new ShaderIrOp(ShaderIrInst.Or, AddOp, OperB);
  878. }
  879. if (Mode == 4)
  880. {
  881. OperB = new ShaderIrOp(ShaderIrInst.Lsl, OperB, Imm16);
  882. AddOp = new ShaderIrOp(ShaderIrInst.Or, AddOp, OperB);
  883. }
  884. Block.AddNode(OpCode.PredNode(new ShaderIrAsg(OpCode.Gpr0(), AddOp)));
  885. }
  886. }
  887. }