ShaderDecodeAlu.cs 38 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181
  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. bool Sat = OpCode.Read(50);
  447. ShaderIrNode OperA = OpCode.Gpr8(), OperB;
  448. OperA = GetAluFabsFneg(OperA, AbsA, NegA);
  449. switch (Oper)
  450. {
  451. case ShaderOper.CR: OperB = OpCode.Cbuf34(); break;
  452. case ShaderOper.Immf: OperB = OpCode.Immf19_20(); break;
  453. case ShaderOper.RR: OperB = OpCode.Gpr20(); break;
  454. default: throw new ArgumentException(nameof(Oper));
  455. }
  456. OperB = GetAluFabsFneg(OperB, AbsB, NegB);
  457. ShaderIrNode Op = new ShaderIrOp(ShaderIrInst.Fadd, OperA, OperB);
  458. Block.AddNode(OpCode.PredNode(new ShaderIrAsg(OpCode.Gpr0(), GetAluFsat(Op, Sat))));
  459. }
  460. private static void EmitFmul(ShaderIrBlock Block, long OpCode, ShaderOper Oper)
  461. {
  462. bool NegB = OpCode.Read(48);
  463. bool Sat = OpCode.Read(50);
  464. ShaderIrNode OperA = OpCode.Gpr8(), OperB;
  465. switch (Oper)
  466. {
  467. case ShaderOper.CR: OperB = OpCode.Cbuf34(); break;
  468. case ShaderOper.Immf: OperB = OpCode.Immf19_20(); break;
  469. case ShaderOper.RR: OperB = OpCode.Gpr20(); break;
  470. default: throw new ArgumentException(nameof(Oper));
  471. }
  472. OperB = GetAluFneg(OperB, NegB);
  473. ShaderIrNode Op = new ShaderIrOp(ShaderIrInst.Fmul, OperA, OperB);
  474. Block.AddNode(OpCode.PredNode(new ShaderIrAsg(OpCode.Gpr0(), GetAluFsat(Op, Sat))));
  475. }
  476. private static void EmitFfma(ShaderIrBlock Block, long OpCode, ShaderOper Oper)
  477. {
  478. bool NegB = OpCode.Read(48);
  479. bool NegC = OpCode.Read(49);
  480. bool Sat = OpCode.Read(50);
  481. ShaderIrNode OperA = OpCode.Gpr8(), OperB, OperC;
  482. switch (Oper)
  483. {
  484. case ShaderOper.CR: OperB = OpCode.Cbuf34(); break;
  485. case ShaderOper.Immf: OperB = OpCode.Immf19_20(); break;
  486. case ShaderOper.RC: OperB = OpCode.Gpr39(); break;
  487. case ShaderOper.RR: OperB = OpCode.Gpr20(); break;
  488. default: throw new ArgumentException(nameof(Oper));
  489. }
  490. OperB = GetAluFneg(OperB, NegB);
  491. if (Oper == ShaderOper.RC)
  492. {
  493. OperC = GetAluFneg(OpCode.Cbuf34(), NegC);
  494. }
  495. else
  496. {
  497. OperC = GetAluFneg(OpCode.Gpr39(), NegC);
  498. }
  499. ShaderIrOp Op = new ShaderIrOp(ShaderIrInst.Ffma, OperA, OperB, OperC);
  500. Block.AddNode(OpCode.PredNode(new ShaderIrAsg(OpCode.Gpr0(), GetAluFsat(Op, Sat))));
  501. }
  502. private static void EmitIadd(ShaderIrBlock Block, long OpCode, ShaderOper Oper)
  503. {
  504. ShaderIrNode OperA = OpCode.Gpr8();
  505. ShaderIrNode OperB;
  506. switch (Oper)
  507. {
  508. case ShaderOper.CR: OperB = OpCode.Cbuf34(); break;
  509. case ShaderOper.Imm: OperB = OpCode.Imm19_20(); break;
  510. case ShaderOper.RR: OperB = OpCode.Gpr20(); break;
  511. default: throw new ArgumentException(nameof(Oper));
  512. }
  513. bool NegA = OpCode.Read(49);
  514. bool NegB = OpCode.Read(48);
  515. OperA = GetAluIneg(OperA, NegA);
  516. OperB = GetAluIneg(OperB, NegB);
  517. ShaderIrOp Op = new ShaderIrOp(ShaderIrInst.Add, OperA, OperB);
  518. Block.AddNode(OpCode.PredNode(new ShaderIrAsg(OpCode.Gpr0(), Op)));
  519. }
  520. private static void EmitIadd3(ShaderIrBlock Block, long OpCode, ShaderOper Oper)
  521. {
  522. int Mode = OpCode.Read(37, 3);
  523. bool Neg1 = OpCode.Read(51);
  524. bool Neg2 = OpCode.Read(50);
  525. bool Neg3 = OpCode.Read(49);
  526. int Height1 = OpCode.Read(35, 3);
  527. int Height2 = OpCode.Read(33, 3);
  528. int Height3 = OpCode.Read(31, 3);
  529. ShaderIrNode OperB;
  530. switch (Oper)
  531. {
  532. case ShaderOper.CR: OperB = OpCode.Cbuf34(); break;
  533. case ShaderOper.Imm: OperB = OpCode.Imm19_20(); break;
  534. case ShaderOper.RR: OperB = OpCode.Gpr20(); break;
  535. default: throw new ArgumentException(nameof(Oper));
  536. }
  537. ShaderIrNode ApplyHeight(ShaderIrNode Src, int Height)
  538. {
  539. if (Oper != ShaderOper.RR)
  540. {
  541. return Src;
  542. }
  543. switch (Height)
  544. {
  545. case 0: return Src;
  546. case 1: return new ShaderIrOp(ShaderIrInst.And, Src, new ShaderIrOperImm(0xffff));
  547. case 2: return new ShaderIrOp(ShaderIrInst.Lsr, Src, new ShaderIrOperImm(16));
  548. default: throw new InvalidOperationException();
  549. }
  550. }
  551. ShaderIrNode Src1 = GetAluIneg(ApplyHeight(OpCode.Gpr8(), Height1), Neg1);
  552. ShaderIrNode Src2 = GetAluIneg(ApplyHeight(OperB, Height2), Neg2);
  553. ShaderIrNode Src3 = GetAluIneg(ApplyHeight(OpCode.Gpr39(), Height3), Neg3);
  554. ShaderIrOp Sum = new ShaderIrOp(ShaderIrInst.Add, Src1, Src2);
  555. if (Oper == ShaderOper.RR)
  556. {
  557. switch (Mode)
  558. {
  559. case 1: Sum = new ShaderIrOp(ShaderIrInst.Lsr, Sum, new ShaderIrOperImm(16)); break;
  560. case 2: Sum = new ShaderIrOp(ShaderIrInst.Lsl, Sum, new ShaderIrOperImm(16)); break;
  561. }
  562. }
  563. //Note: Here there should be a "+ 1" when carry flag is set
  564. //but since carry is mostly ignored by other instructions, it's excluded for now
  565. Block.AddNode(OpCode.PredNode(new ShaderIrAsg(OpCode.Gpr0(), new ShaderIrOp(ShaderIrInst.Add, Sum, Src3))));
  566. }
  567. private static void EmitIscadd(ShaderIrBlock Block, long OpCode, ShaderOper Oper)
  568. {
  569. bool NegB = OpCode.Read(48);
  570. bool NegA = OpCode.Read(49);
  571. ShaderIrNode OperA = OpCode.Gpr8(), OperB;
  572. ShaderIrOperImm Scale = OpCode.Imm5_39();
  573. switch (Oper)
  574. {
  575. case ShaderOper.CR: OperB = OpCode.Cbuf34(); break;
  576. case ShaderOper.Imm: OperB = OpCode.Imm19_20(); break;
  577. case ShaderOper.RR: OperB = OpCode.Gpr20(); break;
  578. default: throw new ArgumentException(nameof(Oper));
  579. }
  580. OperA = GetAluIneg(OperA, NegA);
  581. OperB = GetAluIneg(OperB, NegB);
  582. ShaderIrOp ScaleOp = new ShaderIrOp(ShaderIrInst.Lsl, OperA, Scale);
  583. ShaderIrOp AddOp = new ShaderIrOp(ShaderIrInst.Add, OperB, ScaleOp);
  584. Block.AddNode(OpCode.PredNode(new ShaderIrAsg(OpCode.Gpr0(), AddOp)));
  585. }
  586. private static void EmitFmnmx(ShaderIrBlock Block, long OpCode, ShaderOper Oper)
  587. {
  588. EmitMnmx(Block, OpCode, true, Oper);
  589. }
  590. private static void EmitImnmx(ShaderIrBlock Block, long OpCode, ShaderOper Oper)
  591. {
  592. EmitMnmx(Block, OpCode, false, Oper);
  593. }
  594. private static void EmitMnmx(ShaderIrBlock Block, long OpCode, bool IsFloat, ShaderOper Oper)
  595. {
  596. bool NegB = OpCode.Read(45);
  597. bool AbsA = OpCode.Read(46);
  598. bool NegA = OpCode.Read(48);
  599. bool AbsB = OpCode.Read(49);
  600. ShaderIrNode OperA = OpCode.Gpr8(), OperB;
  601. if (IsFloat)
  602. {
  603. OperA = GetAluFabsFneg(OperA, AbsA, NegA);
  604. }
  605. else
  606. {
  607. OperA = GetAluIabsIneg(OperA, AbsA, NegA);
  608. }
  609. switch (Oper)
  610. {
  611. case ShaderOper.CR: OperB = OpCode.Cbuf34(); break;
  612. case ShaderOper.Imm: OperB = OpCode.Imm19_20(); break;
  613. case ShaderOper.Immf: OperB = OpCode.Immf19_20(); break;
  614. case ShaderOper.RR: OperB = OpCode.Gpr20(); break;
  615. default: throw new ArgumentException(nameof(Oper));
  616. }
  617. if (IsFloat)
  618. {
  619. OperB = GetAluFabsFneg(OperB, AbsB, NegB);
  620. }
  621. else
  622. {
  623. OperB = GetAluIabsIneg(OperB, AbsB, NegB);
  624. }
  625. ShaderIrOperPred Pred = OpCode.Pred39();
  626. ShaderIrOp Op;
  627. ShaderIrInst MaxInst = IsFloat ? ShaderIrInst.Fmax : ShaderIrInst.Max;
  628. ShaderIrInst MinInst = IsFloat ? ShaderIrInst.Fmin : ShaderIrInst.Min;
  629. if (Pred.IsConst)
  630. {
  631. bool IsMax = OpCode.Read(42);
  632. Op = new ShaderIrOp(IsMax
  633. ? MaxInst
  634. : MinInst, OperA, OperB);
  635. Block.AddNode(OpCode.PredNode(new ShaderIrAsg(OpCode.Gpr0(), Op)));
  636. }
  637. else
  638. {
  639. ShaderIrNode PredN = OpCode.Pred39N();
  640. ShaderIrOp OpMax = new ShaderIrOp(MaxInst, OperA, OperB);
  641. ShaderIrOp OpMin = new ShaderIrOp(MinInst, OperA, OperB);
  642. ShaderIrAsg AsgMax = new ShaderIrAsg(OpCode.Gpr0(), OpMax);
  643. ShaderIrAsg AsgMin = new ShaderIrAsg(OpCode.Gpr0(), OpMin);
  644. Block.AddNode(OpCode.PredNode(new ShaderIrCond(PredN, AsgMax, Not: true)));
  645. Block.AddNode(OpCode.PredNode(new ShaderIrCond(PredN, AsgMin, Not: false)));
  646. }
  647. }
  648. private static void EmitRro(ShaderIrBlock Block, long OpCode, ShaderOper Oper)
  649. {
  650. //Note: this is a range reduction instruction and is supposed to
  651. //be used with Mufu, here it just moves the value and ignores the operation.
  652. bool NegA = OpCode.Read(45);
  653. bool AbsA = OpCode.Read(49);
  654. ShaderIrNode OperA;
  655. switch (Oper)
  656. {
  657. case ShaderOper.CR: OperA = OpCode.Cbuf34(); break;
  658. case ShaderOper.Immf: OperA = OpCode.Immf19_20(); break;
  659. case ShaderOper.RR: OperA = OpCode.Gpr20(); break;
  660. default: throw new ArgumentException(nameof(Oper));
  661. }
  662. OperA = GetAluFabsFneg(OperA, AbsA, NegA);
  663. Block.AddNode(new ShaderIrCmnt("Stubbed."));
  664. Block.AddNode(OpCode.PredNode(new ShaderIrAsg(OpCode.Gpr0(), OperA)));
  665. }
  666. private static void EmitFset(ShaderIrBlock Block, long OpCode, ShaderOper Oper)
  667. {
  668. EmitSet(Block, OpCode, true, Oper);
  669. }
  670. private static void EmitIset(ShaderIrBlock Block, long OpCode, ShaderOper Oper)
  671. {
  672. EmitSet(Block, OpCode, false, Oper);
  673. }
  674. private static void EmitSet(ShaderIrBlock Block, long OpCode, bool IsFloat, ShaderOper Oper)
  675. {
  676. bool NegA = OpCode.Read(43);
  677. bool AbsB = OpCode.Read(44);
  678. bool NegB = OpCode.Read(53);
  679. bool AbsA = OpCode.Read(54);
  680. bool BoolFloat = OpCode.Read(IsFloat ? 52 : 44);
  681. ShaderIrNode OperA = OpCode.Gpr8(), OperB;
  682. switch (Oper)
  683. {
  684. case ShaderOper.CR: OperB = OpCode.Cbuf34(); break;
  685. case ShaderOper.Imm: OperB = OpCode.Imm19_20(); break;
  686. case ShaderOper.Immf: OperB = OpCode.Immf19_20(); break;
  687. case ShaderOper.RR: OperB = OpCode.Gpr20(); break;
  688. default: throw new ArgumentException(nameof(Oper));
  689. }
  690. ShaderIrInst CmpInst;
  691. if (IsFloat)
  692. {
  693. OperA = GetAluFabsFneg(OperA, AbsA, NegA);
  694. OperB = GetAluFabsFneg(OperB, AbsB, NegB);
  695. CmpInst = OpCode.CmpF();
  696. }
  697. else
  698. {
  699. CmpInst = OpCode.Cmp();
  700. }
  701. ShaderIrOp Op = new ShaderIrOp(CmpInst, OperA, OperB);
  702. ShaderIrInst LopInst = OpCode.BLop45();
  703. ShaderIrOperPred PNode = OpCode.Pred39();
  704. ShaderIrNode Imm0, Imm1;
  705. if (BoolFloat)
  706. {
  707. Imm0 = new ShaderIrOperImmf(0);
  708. Imm1 = new ShaderIrOperImmf(1);
  709. }
  710. else
  711. {
  712. Imm0 = new ShaderIrOperImm(0);
  713. Imm1 = new ShaderIrOperImm(-1);
  714. }
  715. ShaderIrNode Asg0 = new ShaderIrAsg(OpCode.Gpr0(), Imm0);
  716. ShaderIrNode Asg1 = new ShaderIrAsg(OpCode.Gpr0(), Imm1);
  717. if (LopInst != ShaderIrInst.Band || !PNode.IsConst)
  718. {
  719. ShaderIrOp Op2 = new ShaderIrOp(LopInst, Op, PNode);
  720. Asg0 = new ShaderIrCond(Op2, Asg0, Not: true);
  721. Asg1 = new ShaderIrCond(Op2, Asg1, Not: false);
  722. }
  723. else
  724. {
  725. Asg0 = new ShaderIrCond(Op, Asg0, Not: true);
  726. Asg1 = new ShaderIrCond(Op, Asg1, Not: false);
  727. }
  728. Block.AddNode(OpCode.PredNode(Asg0));
  729. Block.AddNode(OpCode.PredNode(Asg1));
  730. }
  731. private static void EmitFsetp(ShaderIrBlock Block, long OpCode, ShaderOper Oper)
  732. {
  733. EmitSetp(Block, OpCode, true, Oper);
  734. }
  735. private static void EmitIsetp(ShaderIrBlock Block, long OpCode, ShaderOper Oper)
  736. {
  737. EmitSetp(Block, OpCode, false, Oper);
  738. }
  739. private static void EmitSetp(ShaderIrBlock Block, long OpCode, bool IsFloat, ShaderOper Oper)
  740. {
  741. bool AbsA = OpCode.Read(7);
  742. bool NegP = OpCode.Read(42);
  743. bool NegA = OpCode.Read(43);
  744. bool AbsB = OpCode.Read(44);
  745. ShaderIrNode OperA = OpCode.Gpr8(), OperB;
  746. switch (Oper)
  747. {
  748. case ShaderOper.CR: OperB = OpCode.Cbuf34(); break;
  749. case ShaderOper.Imm: OperB = OpCode.Imm19_20(); break;
  750. case ShaderOper.Immf: OperB = OpCode.Immf19_20(); break;
  751. case ShaderOper.RR: OperB = OpCode.Gpr20(); break;
  752. default: throw new ArgumentException(nameof(Oper));
  753. }
  754. ShaderIrInst CmpInst;
  755. if (IsFloat)
  756. {
  757. OperA = GetAluFabsFneg(OperA, AbsA, NegA);
  758. OperB = GetAluFabs (OperB, AbsB);
  759. CmpInst = OpCode.CmpF();
  760. }
  761. else
  762. {
  763. CmpInst = OpCode.Cmp();
  764. }
  765. ShaderIrOp Op = new ShaderIrOp(CmpInst, OperA, OperB);
  766. ShaderIrOperPred P0Node = OpCode.Pred3();
  767. ShaderIrOperPred P1Node = OpCode.Pred0();
  768. ShaderIrOperPred P2Node = OpCode.Pred39();
  769. Block.AddNode(OpCode.PredNode(new ShaderIrAsg(P0Node, Op)));
  770. ShaderIrInst LopInst = OpCode.BLop45();
  771. if (LopInst == ShaderIrInst.Band && P1Node.IsConst && P2Node.IsConst)
  772. {
  773. return;
  774. }
  775. ShaderIrNode P2NNode = P2Node;
  776. if (NegP)
  777. {
  778. P2NNode = new ShaderIrOp(ShaderIrInst.Bnot, P2NNode);
  779. }
  780. Op = new ShaderIrOp(ShaderIrInst.Bnot, P0Node);
  781. Op = new ShaderIrOp(LopInst, Op, P2NNode);
  782. Block.AddNode(OpCode.PredNode(new ShaderIrAsg(P1Node, Op)));
  783. Op = new ShaderIrOp(LopInst, P0Node, P2NNode);
  784. Block.AddNode(OpCode.PredNode(new ShaderIrAsg(P0Node, Op)));
  785. }
  786. private static void EmitLop(ShaderIrBlock Block, long OpCode, ShaderOper Oper)
  787. {
  788. int SubOp = OpCode.Read(41, 3);
  789. bool InvA = OpCode.Read(39);
  790. bool InvB = OpCode.Read(40);
  791. ShaderIrInst Inst = 0;
  792. switch (SubOp)
  793. {
  794. case 0: Inst = ShaderIrInst.And; break;
  795. case 1: Inst = ShaderIrInst.Or; break;
  796. case 2: Inst = ShaderIrInst.Xor; break;
  797. }
  798. ShaderIrNode OperA = GetAluNot(OpCode.Gpr8(), InvA);
  799. ShaderIrNode OperB;
  800. switch (Oper)
  801. {
  802. case ShaderOper.CR: OperB = OpCode.Cbuf34(); break;
  803. case ShaderOper.Imm: OperB = OpCode.Imm19_20(); break;
  804. case ShaderOper.RR: OperB = OpCode.Gpr20(); break;
  805. default: throw new ArgumentException(nameof(Oper));
  806. }
  807. OperB = GetAluNot(OperB, InvB);
  808. ShaderIrNode Op;
  809. if (SubOp < 3)
  810. {
  811. Op = new ShaderIrOp(Inst, OperA, OperB);
  812. }
  813. else
  814. {
  815. Op = OperB;
  816. }
  817. ShaderIrNode Compare = new ShaderIrOp(ShaderIrInst.Cne, Op, new ShaderIrOperImm(0));
  818. Block.AddNode(OpCode.PredNode(new ShaderIrAsg(OpCode.Pred48(), Compare)));
  819. Block.AddNode(OpCode.PredNode(new ShaderIrAsg(OpCode.Gpr0(), Op)));
  820. }
  821. private static void EmitXmad(ShaderIrBlock Block, long OpCode, ShaderOper Oper)
  822. {
  823. //TODO: Confirm SignAB/C, it is just a guess.
  824. //TODO: Implement Mode 3 (CSFU), what it does?
  825. bool SignAB = OpCode.Read(48);
  826. bool SignC = OpCode.Read(49);
  827. bool HighB = OpCode.Read(52);
  828. bool HighA = OpCode.Read(53);
  829. int Mode = OpCode.Read(50, 7);
  830. ShaderIrNode OperA = OpCode.Gpr8(), OperB, OperC;
  831. ShaderIrOperImm Imm16 = new ShaderIrOperImm(16);
  832. ShaderIrOperImm ImmMsk = new ShaderIrOperImm(0xffff);
  833. ShaderIrInst ShiftAB = SignAB ? ShaderIrInst.Asr : ShaderIrInst.Lsr;
  834. ShaderIrInst ShiftC = SignC ? ShaderIrInst.Asr : ShaderIrInst.Lsr;
  835. if (HighA)
  836. {
  837. OperA = new ShaderIrOp(ShiftAB, OperA, Imm16);
  838. }
  839. switch (Oper)
  840. {
  841. case ShaderOper.CR: OperB = OpCode.Cbuf34(); break;
  842. case ShaderOper.Imm: OperB = OpCode.Imm19_20(); break;
  843. case ShaderOper.RC: OperB = OpCode.Gpr39(); break;
  844. case ShaderOper.RR: OperB = OpCode.Gpr20(); break;
  845. default: throw new ArgumentException(nameof(Oper));
  846. }
  847. bool ProductShiftLeft = false, Merge = false;
  848. if (Oper == ShaderOper.RC)
  849. {
  850. OperC = OpCode.Cbuf34();
  851. }
  852. else
  853. {
  854. OperC = OpCode.Gpr39();
  855. ProductShiftLeft = OpCode.Read(36);
  856. Merge = OpCode.Read(37);
  857. }
  858. switch (Mode)
  859. {
  860. //CLO.
  861. case 1: OperC = ExtendTo32(OperC, SignC, 16); break;
  862. //CHI.
  863. case 2: OperC = new ShaderIrOp(ShiftC, OperC, Imm16); break;
  864. }
  865. ShaderIrNode OperBH = OperB;
  866. if (HighB)
  867. {
  868. OperBH = new ShaderIrOp(ShiftAB, OperBH, Imm16);
  869. }
  870. ShaderIrOp MulOp = new ShaderIrOp(ShaderIrInst.Mul, OperA, OperBH);
  871. if (ProductShiftLeft)
  872. {
  873. MulOp = new ShaderIrOp(ShaderIrInst.Lsl, MulOp, Imm16);
  874. }
  875. ShaderIrOp AddOp = new ShaderIrOp(ShaderIrInst.Add, MulOp, OperC);
  876. if (Merge)
  877. {
  878. AddOp = new ShaderIrOp(ShaderIrInst.And, AddOp, ImmMsk);
  879. OperB = new ShaderIrOp(ShaderIrInst.Lsl, OperB, Imm16);
  880. AddOp = new ShaderIrOp(ShaderIrInst.Or, AddOp, OperB);
  881. }
  882. if (Mode == 4)
  883. {
  884. OperB = new ShaderIrOp(ShaderIrInst.Lsl, OperB, Imm16);
  885. AddOp = new ShaderIrOp(ShaderIrInst.Or, AddOp, OperB);
  886. }
  887. Block.AddNode(OpCode.PredNode(new ShaderIrAsg(OpCode.Gpr0(), AddOp)));
  888. }
  889. }
  890. }