1 // Copyright 2014 Tony Wasserka
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions are met:
6 //
7 // * Redistributions of source code must retain the above copyright
8 // notice, this list of conditions and the following disclaimer.
9 // * Redistributions in binary form must reproduce the above copyright
10 // notice, this list of conditions and the following disclaimer in the
11 // documentation and/or other materials provided with the distribution.
12 // * Neither the name of the owner nor the names of its contributors may
13 // be used to endorse or promote products derived from this software
14 // without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28 #pragma once
29
30 #include <cstdint>
31 #include <map>
32 #include <stdexcept>
33 #include <string>
34 #include <sstream>
35
36 #include "bit_field.h"
37
38 namespace nihstro {
39
40 enum class RegisterType {
41 Input,
42 Output,
43 Temporary,
44 FloatUniform,
45 IntUniform,
46 BoolUniform,
47 Address,
48 ConditionalCode,
49 Unknown
50 };
51
GetRegisterName(RegisterType type)52 static std::string GetRegisterName(RegisterType type) {
53 switch (type) {
54 case RegisterType::Input: return "v";
55 case RegisterType::Output: return "o";
56 case RegisterType::Temporary: return "r";
57 case RegisterType::FloatUniform: return "c";
58 case RegisterType::IntUniform: return "i";
59 case RegisterType::BoolUniform: return "b";
60 case RegisterType::ConditionalCode: return "cc";
61 case RegisterType::Unknown: return "u";
62 default: return "";
63 }
64 }
65
66 struct SourceRegister {
67 SourceRegister() = default;
68
SourceRegisterSourceRegister69 SourceRegister(uint32_t value) {
70 this->value = value;
71 }
72
GetRegisterTypeSourceRegister73 RegisterType GetRegisterType() const {
74 if (value < 0x10)
75 return RegisterType::Input;
76 else if (value < 0x20)
77 return RegisterType::Temporary;
78 else
79 return RegisterType::FloatUniform;
80 }
81
GetIndexSourceRegister82 int GetIndex() const {
83 if (GetRegisterType() == RegisterType::Input)
84 return value;
85 else if (GetRegisterType() == RegisterType::Temporary)
86 return value - 0x10;
87 else if (GetRegisterType() == RegisterType::FloatUniform)
88 return value - 0x20;
89 }
90
FromTypeAndIndexSourceRegister91 static const SourceRegister FromTypeAndIndex(RegisterType type, int index) {
92 SourceRegister reg;
93 if (type == RegisterType::Input)
94 reg.value = index;
95 else if (type == RegisterType::Temporary)
96 reg.value = index + 0x10;
97 else if (type == RegisterType::FloatUniform)
98 reg.value = index + 0x20;
99 else {
100 // TODO: Should throw an exception or something.
101 }
102 return reg;
103 }
104
MakeInputSourceRegister105 static const SourceRegister MakeInput(int index) {
106 return FromTypeAndIndex(RegisterType::Input, index);
107 }
108
MakeTemporarySourceRegister109 static const SourceRegister MakeTemporary(int index) {
110 return FromTypeAndIndex(RegisterType::Temporary, index);
111 }
112
MakeFloatSourceRegister113 static const SourceRegister MakeFloat(int index) {
114 return FromTypeAndIndex(RegisterType::FloatUniform, index);
115 }
116
GetNameSourceRegister117 std::string GetName() const {
118 std::stringstream ss;
119 ss << GetRegisterName(GetRegisterType()) << GetIndex();
120 return ss.str();
121 }
122
uint32_tSourceRegister123 operator uint32_t() const {
124 return value;
125 }
126
127 template<typename T>
128 decltype(uint32_t{} - T{}) operator -(const T& oth) const {
129 return value - oth;
130 }
131
132 template<typename T>
decltypeSourceRegister133 decltype(uint32_t{} & T{}) operator &(const T& oth) const {
134 return value & oth;
135 }
136
137 uint32_t operator &(const SourceRegister& oth) const {
138 return value & oth.value;
139 }
140
141 uint32_t operator ~() const {
142 return ~value;
143 }
144
145 private:
146 uint32_t value;
147 };
148
149 struct DestRegister {
150 DestRegister() = default;
151
DestRegisterDestRegister152 DestRegister(uint32_t value) {
153 this->value = value;
154 }
155
GetRegisterTypeDestRegister156 RegisterType GetRegisterType() const {
157 if (value < 0x10)
158 return RegisterType::Output;
159 else
160 return RegisterType::Temporary;
161 }
162
GetIndexDestRegister163 int GetIndex() const {
164 if (GetRegisterType() == RegisterType::Output)
165 return value;
166 else if (GetRegisterType() == RegisterType::Temporary)
167 return value - 0x10;
168 else // if (GetRegisterType() == RegisterType::FloatUniform)
169 // TODO: This will lead to negative returned values...
170 return value - 0x20;
171 }
172
FromTypeAndIndexDestRegister173 static const DestRegister FromTypeAndIndex(RegisterType type, int index) {
174 DestRegister reg;
175 if (type == RegisterType::Output)
176 reg.value = index;
177 else if (type == RegisterType::Temporary)
178 reg.value = index + 0x10;
179 else if (type == RegisterType::FloatUniform) // TODO: Wait what? These shouldn't be writable..
180 reg.value = index + 0x20;
181 else {
182 // TODO: Should throw an exception or something.
183 }
184 return reg;
185 }
186
MakeOutputDestRegister187 static const DestRegister MakeOutput(int index) {
188 return FromTypeAndIndex(RegisterType::Output, index);
189 }
190
MakeTemporaryDestRegister191 static const DestRegister MakeTemporary(int index) {
192 return FromTypeAndIndex(RegisterType::Temporary, index);
193 }
194
GetNameDestRegister195 std::string GetName() const {
196 std::stringstream ss;
197 ss << GetRegisterName(GetRegisterType()) << GetIndex();
198 return ss.str();
199 }
200
uint32_tDestRegister201 operator uint32_t() const {
202 return value;
203 }
204
205 template<typename T>
206 decltype(uint32_t{} - T{}) operator -(const T& oth) const {
207 return value - oth;
208 }
209
210 template<typename T>
decltypeDestRegister211 decltype(uint32_t{} & T{}) operator &(const T& oth) const {
212 return value & oth;
213 }
214
215 uint32_t operator &(const DestRegister& oth) const {
216 return value & oth.value;
217 }
218
219 uint32_t operator ~() const {
220 return ~value;
221 }
222
223 private:
224 uint32_t value;
225 };
226
227 struct OpCode {
228 enum class Id : uint32_t {
229 ADD = 0x00,
230 DP3 = 0x01,
231 DP4 = 0x02,
232 DPH = 0x03, // Dot product of Vec4 and Vec3; the Vec3 is made into
233 // a Vec4 by appending 1.0 as the fourth component
234 DST = 0x04, // Distance, same as in vs_3_0
235 EX2 = 0x05, // Base-2 exponential
236 LG2 = 0x06, // Base-2 logarithm
237 LIT = 0x07, // Clamp for lighting
238 MUL = 0x08,
239 SGE = 0x09, // Set to 1.0 if SRC1 is greater or equal to SRC2
240 SLT = 0x0A, // Set to 1.0 if SRC1 is less than SRC2
241 FLR = 0x0B,
242 MAX = 0x0C,
243 MIN = 0x0D,
244 RCP = 0x0E, // Reciprocal
245 RSQ = 0x0F, // Reciprocal of square root
246
247 MOVA = 0x12, // Move to Address Register
248 MOV = 0x13,
249
250 DPHI = 0x18,
251 DSTI = 0x19,
252 SGEI = 0x1A,
253 SLTI = 0x1B,
254
255 BREAK = 0x20,
256 NOP = 0x21,
257 END = 0x22,
258 BREAKC = 0x23,
259 CALL = 0x24,
260 CALLC = 0x25,
261 CALLU = 0x26,
262 IFU = 0x27,
263 IFC = 0x28,
264 LOOP = 0x29,
265 EMIT = 0x2A,
266 SETEMIT = 0x2B,
267 JMPC = 0x2C,
268 JMPU = 0x2D,
269 CMP = 0x2E, // LSB opcode bit ignored
270
271 // lower 3 opcode bits ignored for these
272 MADI = 0x30,
273 MAD = 0x38, // lower 3 opcode bits ignored
274
275 // Pseudo-instructions, used internally by the assembler
276 PSEUDO_INSTRUCTION_START = 0x40,
277
278 GEN_IF = PSEUDO_INSTRUCTION_START, // Generic IF (IFC or IFU)
279 ELSE,
280 ENDIF,
281 GEN_CALL, // Generic CALL (CALL, CALC, or CALLU)
282 GEN_JMP, // Generic JMP (JMPC or JMPU)
283 //RET, // Return from function (not supported yet)
284 ENDLOOP,
285 };
286
287 enum class Type {
288 Trivial, // 3dbrew format 0
289 Arithmetic, // 3dbrew format 1
290 Conditional, // 3dbrew format 2
291 UniformFlowControl, // 3dbrew format 3
292 SetEmit, // 3dbrew format 4
293 MultiplyAdd, // 3dbrew format 5
294 Unknown
295 };
296
297 struct Info {
298 Type type;
299
300 // Arithmetic
301 enum : uint32_t {
302 OpDesc = 1,
303 Src1 = 2,
304 Src2 = 4,
305 Idx = 8,
306 Dest = 16,
307 SrcInversed = 32,
308 CompareOps = 64,
309 MOVA = 128 | OpDesc | Src1 | Idx,
310 OneArgument = OpDesc | Src1 | Idx | Dest,
311 TwoArguments = OneArgument | Src2,
312 Compare = OpDesc | Idx | Src1 | Src2 | CompareOps,
313 };
314
315 // Flow Control
316 enum : uint32_t {
317 HasUniformIndex = 1,
318 HasCondition = 2,
319 HasExplicitDest = 4, // target code given explicitly and context-independently (contrary to e.g. BREAKC)
320 HasFinishPoint = 8, // last instruction until returning to caller
321 HasAlternative = 16, // has an "else" branch
322 LOOP = 32,
323
324 BREAKC = HasCondition,
325
326 JMP = HasExplicitDest,
327 JMPC = JMP | HasCondition,
328 JMPU = JMP | HasUniformIndex,
329
330 CALL = JMP | HasFinishPoint,
331 CALLC = CALL | HasCondition,
332 CALLU = CALL | HasUniformIndex,
333 IFU = CALLU | HasAlternative,
334 IFC = CALLC | HasAlternative,
335 };
336
337 enum : uint32_t {
338 FullAndBool,
339 SimpleAndInt,
340 };
341
342 uint32_t subtype;
343
344 const char* name;
345
346 // TODO: Deprecate.
NumArgumentsOpCode::Info347 size_t NumArguments() const {
348 if (type == Type::Arithmetic) {
349 if (subtype & Src2)
350 return 3;
351 else if (subtype & Src1)
352 return 2;
353 }
354
355 return 0;
356 }
357 };
358
359 OpCode() = default;
360
OpCodeOpCode361 OpCode(Id value) {
362 this->value = static_cast<uint32_t>(value);
363 }
364
OpCodeOpCode365 OpCode(uint32_t value) {
366 this->value = value;
367 }
368
EffectiveOpCodeOpCode369 Id EffectiveOpCode() const {
370 uint32_t op = static_cast<uint32_t>(value);
371 if (static_cast<Id>(op & ~0x7) == Id::MAD)
372 return Id::MAD;
373 else if (static_cast<Id>(op & ~0x7) == Id::MADI)
374 return Id::MADI;
375 else if (static_cast<Id>(op & ~0x1) == Id::CMP)
376 return Id::CMP;
377 else
378 return static_cast<Id>(value);
379 }
380
GetInfoOpCode381 const Info& GetInfo() const {
382 #define unknown_instruction { OpCode::Type::Unknown, 0, "UNK" }
383 static const OpCode::Info info_table[] = {
384 { OpCode::Type::Arithmetic, OpCode::Info::TwoArguments, "add" },
385 { OpCode::Type::Arithmetic, OpCode::Info::TwoArguments, "dp3" },
386 { OpCode::Type::Arithmetic, OpCode::Info::TwoArguments, "dp4" },
387 { OpCode::Type::Arithmetic, OpCode::Info::TwoArguments, "dph" },
388 { OpCode::Type::Arithmetic, OpCode::Info::TwoArguments, "dst" },
389 { OpCode::Type::Arithmetic, OpCode::Info::OneArgument, "exp" },
390 { OpCode::Type::Arithmetic, OpCode::Info::OneArgument, "log" },
391 { OpCode::Type::Arithmetic, OpCode::Info::OneArgument, "lit" },
392 { OpCode::Type::Arithmetic, OpCode::Info::TwoArguments, "mul" },
393 { OpCode::Type::Arithmetic, OpCode::Info::TwoArguments, "sge" },
394 { OpCode::Type::Arithmetic, OpCode::Info::TwoArguments, "slt" },
395 { OpCode::Type::Arithmetic, OpCode::Info::OneArgument, "flr" },
396 { OpCode::Type::Arithmetic, OpCode::Info::TwoArguments, "max" },
397 { OpCode::Type::Arithmetic, OpCode::Info::TwoArguments, "min" },
398 { OpCode::Type::Arithmetic, OpCode::Info::OneArgument, "rcp" },
399 { OpCode::Type::Arithmetic, OpCode::Info::OneArgument, "rsq" },
400 unknown_instruction,
401 unknown_instruction,
402 { OpCode::Type::Arithmetic, OpCode::Info::MOVA, "mova" },
403 { OpCode::Type::Arithmetic, OpCode::Info::OneArgument, "mov" },
404 unknown_instruction,
405 unknown_instruction,
406 unknown_instruction,
407 unknown_instruction,
408 { OpCode::Type::Arithmetic, OpCode::Info::TwoArguments | OpCode::Info::SrcInversed, "dphi" },
409 { OpCode::Type::Arithmetic, OpCode::Info::TwoArguments | OpCode::Info::SrcInversed, "dsti" },
410 { OpCode::Type::Arithmetic, OpCode::Info::TwoArguments | OpCode::Info::SrcInversed, "sgei" },
411 { OpCode::Type::Arithmetic, OpCode::Info::TwoArguments | OpCode::Info::SrcInversed, "slti" },
412 unknown_instruction,
413 unknown_instruction,
414 unknown_instruction,
415 unknown_instruction,
416 { OpCode::Type::Trivial, 0, "break" },
417 { OpCode::Type::Trivial, 0, "nop" },
418 { OpCode::Type::Trivial, 0, "end" },
419 { OpCode::Type::Conditional, OpCode::Info::BREAKC, "breakc" },
420 { OpCode::Type::Conditional, OpCode::Info::CALL, "call" },
421 { OpCode::Type::Conditional, OpCode::Info::CALLC, "callc" },
422 { OpCode::Type::UniformFlowControl, OpCode::Info::CALLU, "callu" },
423 { OpCode::Type::UniformFlowControl, OpCode::Info::IFU, "ifu" },
424 { OpCode::Type::Conditional, OpCode::Info::IFC, "ifc" },
425 { OpCode::Type::UniformFlowControl, OpCode::Info::LOOP, "loop" },
426 { OpCode::Type::Trivial, 0, "emit" },
427 { OpCode::Type::SetEmit, 0, "setemit" },
428 { OpCode::Type::Conditional, OpCode::Info::JMPC, "jmpc" },
429 { OpCode::Type::Conditional, OpCode::Info::JMPU, "jmpu" },
430 { OpCode::Type::Arithmetic, OpCode::Info::Compare, "cmp" },
431 { OpCode::Type::Arithmetic, OpCode::Info::Compare, "cmp" },
432 { OpCode::Type::MultiplyAdd, OpCode::Info::SrcInversed, "madi" },
433 { OpCode::Type::MultiplyAdd, OpCode::Info::SrcInversed, "madi" },
434 { OpCode::Type::MultiplyAdd, OpCode::Info::SrcInversed, "madi" },
435 { OpCode::Type::MultiplyAdd, OpCode::Info::SrcInversed, "madi" },
436 { OpCode::Type::MultiplyAdd, OpCode::Info::SrcInversed, "madi" },
437 { OpCode::Type::MultiplyAdd, OpCode::Info::SrcInversed, "madi" },
438 { OpCode::Type::MultiplyAdd, OpCode::Info::SrcInversed, "madi" },
439 { OpCode::Type::MultiplyAdd, OpCode::Info::SrcInversed, "madi" },
440 { OpCode::Type::MultiplyAdd, 0, "mad" },
441 { OpCode::Type::MultiplyAdd, 0, "mad" },
442 { OpCode::Type::MultiplyAdd, 0, "mad" },
443 { OpCode::Type::MultiplyAdd, 0, "mad" },
444 { OpCode::Type::MultiplyAdd, 0, "mad" },
445 { OpCode::Type::MultiplyAdd, 0, "mad" },
446 { OpCode::Type::MultiplyAdd, 0, "mad" },
447 { OpCode::Type::MultiplyAdd, 0, "mad" }
448 };
449 #undef unknown_instruction
450 return info_table[value];
451 }
452
IdOpCode453 operator Id() const {
454 return static_cast<Id>(value);
455 }
456
457 OpCode operator << (size_t bits) const {
458 return value << bits;
459 }
460
461 template<typename T>
462 decltype(uint32_t{} - T{}) operator -(const T& oth) const {
463 return value - oth;
464 }
465
466 uint32_t operator &(const OpCode& oth) const {
467 return value & oth.value;
468 }
469
470 uint32_t operator ~() const {
471 return ~value;
472 }
473
474 private:
475 uint32_t value;
476 };
477
478 } // namespace nihstro
479
480 namespace std {
481 template<>
482 struct make_unsigned<nihstro::SourceRegister> {
483 using type = nihstro::SourceRegister;
484 };
485
486 template<>
487 struct make_unsigned<nihstro::DestRegister> {
488 using type = nihstro::DestRegister;
489 };
490
491 template<>
492 struct make_unsigned<nihstro::OpCode> {
493 using type = nihstro::OpCode;
494 };
495 }
496
497 namespace nihstro {
498
499 #pragma pack(1)
500 union Instruction {
501 Instruction& operator =(const Instruction& instr) {
502 hex = instr.hex;
503 return *this;
504 }
505
506 uint32_t hex;
507
508 BitField<0x1a, 0x6, OpCode> opcode;
509
510
511 // General notes:
512 //
513 // When two input registers are used, one of them uses a 5-bit index while the other
514 // one uses a 7-bit index. This is because at most one floating point uniform may be used
515 // as an input.
516
517
518 // Format used e.g. by arithmetic instructions and comparisons
519 union Common { // TODO: Remove name
520 BitField<0x00, 0x7, uint32_t> operand_desc_id;
521
522 const SourceRegister GetSrc1(bool is_inverted) const {
523 if (!is_inverted) {
524 return src1;
525 } else {
526 return src1i;
527 }
528 }
529
530 const SourceRegister GetSrc2(bool is_inverted) const {
531 if (!is_inverted) {
532 return src2;
533 } else {
534 return src2i;
535 }
536 }
537
538 /**
539 * Source inputs may be reordered for certain instructions.
540 * Use GetSrc1 and GetSrc2 instead to access the input register indices hence.
541 */
542 BitField<0x07, 0x5, SourceRegister> src2;
543 BitField<0x0c, 0x7, SourceRegister> src1;
544 BitField<0x07, 0x7, SourceRegister> src2i;
545 BitField<0x0e, 0x5, SourceRegister> src1i;
546
547 // Address register value is used for relative addressing of src1 / src2 (inverted)
548 BitField<0x13, 0x2, uint32_t> address_register_index;
549
550 union CompareOpType { // TODO: Make nameless once MSVC supports it
551 enum Op : uint32_t {
552 Equal = 0,
553 NotEqual = 1,
554 LessThan = 2,
555 LessEqual = 3,
556 GreaterThan = 4,
557 GreaterEqual = 5,
558 Unk6 = 6,
559 Unk7 = 7
560 };
561
562 BitField<0x15, 0x3, Op> y;
563 BitField<0x18, 0x3, Op> x;
564
565 const std::string ToString(Op op) const {
566 switch (op) {
567 case Equal: return "==";
568 case NotEqual: return "!=";
569 case LessThan: return "<";
570 case LessEqual: return "<=";
571 case GreaterThan: return ">";
572 case GreaterEqual: return ">=";
573 case Unk6: return "UNK6";
574 case Unk7: return "UNK7";
575 default: return "";
576 };
577 }
578 } compare_op;
579
580 std::string AddressRegisterName() const {
581 if (address_register_index == 0) return "";
582 else if (address_register_index == 1) return "a0.x";
583 else if (address_register_index == 2) return "a0.y";
584 else /*if (address_register_index == 3)*/ return "aL";
585 }
586
587 BitField<0x15, 0x5, DestRegister> dest;
588 } common;
589
590 union FlowControlType { // TODO: Make nameless once MSVC supports it
591 enum Op : uint32_t {
592 Or = 0,
593 And = 1,
594 JustX = 2,
595 JustY = 3
596 };
597
598 BitField<0x00, 0x8, uint32_t> num_instructions;
599 BitField<0x0a, 0xc, uint32_t> dest_offset;
600
601 BitField<0x16, 0x2, Op> op;
602 BitField<0x16, 0x4, uint32_t> bool_uniform_id;
603 BitField<0x16, 0x2, uint32_t> int_uniform_id; // TODO: Verify that only this many bits are used...
604
605 BitFlag<0x18, uint32_t> refy;
606 BitFlag<0x19, uint32_t> refx;
607 } flow_control;
608
609 union {
610 const SourceRegister GetSrc1(bool is_inverted) const {
611 // The inverted form for src1 is the same, this function is just here for consistency
612 return src1;
613 }
614
615 const SourceRegister GetSrc2(bool is_inverted) const {
616 if (!is_inverted) {
617 return src2;
618 } else {
619 return src2i;
620 }
621 }
622
623 const SourceRegister GetSrc3(bool is_inverted) const {
624 if (!is_inverted) {
625 return src3;
626 } else {
627 return src3i;
628 }
629 }
630
631 BitField<0x00, 0x5, uint32_t> operand_desc_id;
632
633 BitField<0x05, 0x5, SourceRegister> src3;
634 BitField<0x0a, 0x7, SourceRegister> src2;
635 BitField<0x11, 0x5, SourceRegister> src1;
636
637 BitField<0x05, 0x7, SourceRegister> src3i;
638 BitField<0x0c, 0x5, SourceRegister> src2i;
639
640 // Address register value is used for relative addressing of src2 / src3 (inverted)
641 BitField<0x16, 0x2, uint32_t> address_register_index;
642
643 std::string AddressRegisterName() const {
644 if (address_register_index == 0) return "";
645 else if (address_register_index == 1) return "a0.x";
646 else if (address_register_index == 2) return "a0.y";
647 else /*if (address_register_index == 3)*/ return "aL";
648 }
649
650 BitField<0x18, 0x5, DestRegister> dest;
651 } mad;
652
653 union {
654 BitField<0x16, 1, uint32_t> winding;
655 BitField<0x17, 1, uint32_t> prim_emit;
656 BitField<0x18, 2, uint32_t> vertex_id;
657 } setemit;
658 };
659 static_assert(sizeof(Instruction) == 0x4, "Incorrect structure size");
660 static_assert(std::is_standard_layout<Instruction>::value, "Structure does not have standard layout");
661
662 union SwizzlePattern {
663 SwizzlePattern& operator =(const SwizzlePattern& instr) {
664 hex = instr.hex;
665 return *this;
666 }
667
668 uint32_t hex;
669
670 enum class Selector : uint32_t {
671 x = 0,
672 y = 1,
673 z = 2,
674 w = 3
675 };
676
677 /**
678 * Gets the raw 8-bit selector for the specified (1-indexed) source register.
679 */
680 unsigned GetRawSelector(unsigned src) const {
681 if (src == 0 || src > 3)
682 throw std::out_of_range("src needs to be between 1 and 3");
683
684 unsigned selectors[] = {
685 src1_selector, src2_selector, src3_selector
686 };
687 return selectors[src - 1];
688 }
689
690 Selector GetSelectorSrc1(int comp) const {
691 Selector selectors[] = {
692 src1_selector_0, src1_selector_1, src1_selector_2, src1_selector_3
693 };
694 return selectors[comp];
695 }
696
697 Selector GetSelectorSrc2(int comp) const {
698 Selector selectors[] = {
699 src2_selector_0, src2_selector_1, src2_selector_2, src2_selector_3
700 };
701 return selectors[comp];
702 }
703
704 Selector GetSelectorSrc3(int comp) const {
705 Selector selectors[] = {
706 src3_selector_0, src3_selector_1, src3_selector_2, src3_selector_3
707 };
708 return selectors[comp];
709 }
710
711 void SetSelectorSrc1(int comp, Selector value) {
712 if (comp == 0)
713 src1_selector_0 = value;
714 else if (comp == 1)
715 src1_selector_1 = value;
716 else if (comp == 2)
717 src1_selector_2 = value;
718 else if (comp == 3)
719 src1_selector_3 = value;
720 else
721 throw std::out_of_range("comp needs to be smaller than 4");
722 }
723
724 void SetSelectorSrc2(int comp, Selector value) {
725 if (comp == 0)
726 src2_selector_0 = value;
727 else if (comp == 1)
728 src2_selector_1 = value;
729 else if (comp == 2)
730 src2_selector_2 = value;
731 else if (comp == 3)
732 src2_selector_3 = value;
733 else
734 throw std::out_of_range("comp needs to be smaller than 4");
735 }
736
737 void SetSelectorSrc3(int comp, Selector value) {
738 if (comp == 0)
739 src3_selector_0 = value;
740 else if (comp == 1)
741 src3_selector_1 = value;
742 else if (comp == 2)
743 src3_selector_2 = value;
744 else if (comp == 3)
745 src3_selector_3 = value;
746 else
747 throw std::out_of_range("comp needs to be smaller than 4");
748 }
749
750 std::string SelectorToString(bool src2) const {
751 std::map<Selector, std::string> map = {
752 { Selector::x, "x" },
753 { Selector::y, "y" },
754 { Selector::z, "z" },
755 { Selector::w, "w" }
756 };
757 std::string ret;
758 for (int i = 0; i < 4; ++i) {
759 ret += map.at(src2 ? GetSelectorSrc2(i) : GetSelectorSrc1(i));
760 }
761 return ret;
762 }
763
764 bool DestComponentEnabled(unsigned int i) const {
765 return (dest_mask & (0x8 >> i)) != 0;
766 }
767
768 void SetDestComponentEnabled(unsigned int i, bool enabled) {
769 int mask = 0xffff & (0x8 >> i);
770 dest_mask = (dest_mask & ~mask) | (enabled * mask);
771 }
772
773 std::string DestMaskToString() const {
774 std::string ret;
775 for (int i = 0; i < 4; ++i) {
776 if (!DestComponentEnabled(i))
777 ret += "_";
778 else
779 ret += "xyzw"[i];
780 }
781 return ret;
782 }
783
784 // Components of "dest" that should be written to: LSB=dest.w, MSB=dest.x
785 BitField< 0, 4, uint32_t> dest_mask;
786
787 BitFlag < 4, uint32_t> negate_src1;
788 BitField< 5, 8, uint32_t> src1_selector;
789 BitField< 5, 2, Selector> src1_selector_3;
790 BitField< 7, 2, Selector> src1_selector_2;
791 BitField< 9, 2, Selector> src1_selector_1;
792 BitField<11, 2, Selector> src1_selector_0;
793
794 BitFlag <13, uint32_t> negate_src2;
795 BitField<14, 8, uint32_t> src2_selector;
796 BitField<14, 2, Selector> src2_selector_3;
797 BitField<16, 2, Selector> src2_selector_2;
798 BitField<18, 2, Selector> src2_selector_1;
799 BitField<20, 2, Selector> src2_selector_0;
800
801 BitFlag <22, uint32_t> negate_src3;
802 BitField<23, 8, uint32_t> src3_selector;
803 BitField<23, 2, Selector> src3_selector_3;
804 BitField<25, 2, Selector> src3_selector_2;
805 BitField<27, 2, Selector> src3_selector_1;
806 BitField<29, 2, Selector> src3_selector_0;
807 };
808 static_assert(sizeof(SwizzlePattern) == 0x4, "Incorrect structure size");
809
810
811 #pragma pack()
812
813 } // namespace
814