1 /*
2 * Copyright © 2022 Mary Guillemard
3 * SPDX-License-Identifier: MIT
4 */
5 #include "mme_fermi.h"
6
7 #include "mme_bitpack_helpers.h"
8
9 #define OP_TO_STR(OP) [MME_FERMI_OP_##OP] = #OP
10 static const char *op_to_str[] = {
11 OP_TO_STR(ALU_REG),
12 OP_TO_STR(ADD_IMM),
13 OP_TO_STR(MERGE),
14 OP_TO_STR(BFE_LSL_IMM),
15 OP_TO_STR(BFE_LSL_REG),
16 OP_TO_STR(STATE),
17 OP_TO_STR(UNK6),
18 OP_TO_STR(BRANCH),
19 };
20 #undef OP_TO_STR
21
22 const char *
mme_fermi_op_to_str(enum mme_fermi_op op)23 mme_fermi_op_to_str(enum mme_fermi_op op)
24 {
25 assert(op < ARRAY_SIZE(op_to_str));
26 return op_to_str[op];
27 }
28
29 #define ALU_OP_TO_STR(OP) [MME_FERMI_ALU_OP_##OP] = #OP
30 static const char *alu_op_to_str[] = {
31 ALU_OP_TO_STR(ADD),
32 ALU_OP_TO_STR(ADDC),
33 ALU_OP_TO_STR(SUB),
34 ALU_OP_TO_STR(SUBB),
35 ALU_OP_TO_STR(RESERVED4),
36 ALU_OP_TO_STR(RESERVED5),
37 ALU_OP_TO_STR(RESERVED6),
38 ALU_OP_TO_STR(RESERVED7),
39 ALU_OP_TO_STR(XOR),
40 ALU_OP_TO_STR(OR),
41 ALU_OP_TO_STR(AND),
42 ALU_OP_TO_STR(AND_NOT),
43 ALU_OP_TO_STR(NAND),
44 ALU_OP_TO_STR(RESERVED13),
45 ALU_OP_TO_STR(RESERVED14),
46 ALU_OP_TO_STR(RESERVED15),
47 ALU_OP_TO_STR(RESERVED16),
48 ALU_OP_TO_STR(RESERVED17),
49 ALU_OP_TO_STR(RESERVED18),
50 ALU_OP_TO_STR(RESERVED19),
51 ALU_OP_TO_STR(RESERVED20),
52 ALU_OP_TO_STR(RESERVED21),
53 ALU_OP_TO_STR(RESERVED22),
54 ALU_OP_TO_STR(RESERVED23),
55 ALU_OP_TO_STR(RESERVED24),
56 ALU_OP_TO_STR(RESERVED25),
57 ALU_OP_TO_STR(RESERVED26),
58 ALU_OP_TO_STR(RESERVED27),
59 ALU_OP_TO_STR(RESERVED28),
60 ALU_OP_TO_STR(RESERVED29),
61 ALU_OP_TO_STR(RESERVED30),
62 ALU_OP_TO_STR(RESERVED31),
63 };
64 #undef ALU_OP_TO_STR
65
66 const char *
mme_fermi_alu_op_to_str(enum mme_fermi_alu_op op)67 mme_fermi_alu_op_to_str(enum mme_fermi_alu_op op)
68 {
69 assert(op < ARRAY_SIZE(alu_op_to_str));
70 return alu_op_to_str[op];
71 }
72
73 #define ASSIGN_OP_TO_STR(OP) [MME_FERMI_ASSIGN_OP_##OP] = #OP
74 static const char *assign_op_to_str[] = {
75 ASSIGN_OP_TO_STR(LOAD),
76 ASSIGN_OP_TO_STR(MOVE),
77 ASSIGN_OP_TO_STR(MOVE_SET_MADDR),
78 ASSIGN_OP_TO_STR(LOAD_EMIT),
79 ASSIGN_OP_TO_STR(MOVE_EMIT),
80 ASSIGN_OP_TO_STR(LOAD_SET_MADDR),
81 ASSIGN_OP_TO_STR(MOVE_SET_MADDR_LOAD_EMIT),
82 ASSIGN_OP_TO_STR(MOVE_SET_MADDR_LOAD_EMIT_HIGH),
83 };
84 #undef ASSIGN_OP_TO_STR
85
86 const char *
mme_fermi_assign_op_to_str(enum mme_fermi_assign_op op)87 mme_fermi_assign_op_to_str(enum mme_fermi_assign_op op)
88 {
89 assert(op < ARRAY_SIZE(assign_op_to_str));
90 return assign_op_to_str[op];
91 }
92
mme_fermi_encode(uint32_t * out,uint32_t inst_count,const struct mme_fermi_inst * insts)93 void mme_fermi_encode(uint32_t *out, uint32_t inst_count,
94 const struct mme_fermi_inst *insts)
95 {
96 for (uint32_t i = 0; i < inst_count; i++) {
97 uint32_t *b = &out[i];
98 *b = 0;
99
100 pack_uint(b, 0, 3, insts[i].op);
101 pack_uint(b, 7, 7, insts[i].end_next);
102 pack_uint(b, 8, 10, insts[i].dst);
103
104 if (insts[i].op != MME_FERMI_OP_BRANCH) {
105 pack_uint(b, 4, 6, insts[i].assign_op);
106 }
107
108 if (insts[i].op == MME_FERMI_OP_ALU_REG) {
109 pack_uint(b, 11, 13, insts[i].src[0]);
110 pack_uint(b, 14, 16, insts[i].src[1]);
111 pack_uint(b, 17, 21, insts[i].alu_op);
112 } else if (insts[i].op == MME_FERMI_OP_ADD_IMM ||
113 insts[i].op == MME_FERMI_OP_STATE) {
114 pack_uint(b, 11, 13, insts[i].src[0]);
115 pack_sint(b, 14, 31, insts[i].imm);
116 } else if (insts[i].op == MME_FERMI_OP_MERGE ||
117 insts[i].op == MME_FERMI_OP_BFE_LSL_IMM ||
118 insts[i].op == MME_FERMI_OP_BFE_LSL_REG) {
119 pack_uint(b, 11, 13, insts[i].src[0]);
120 pack_uint(b, 14, 16, insts[i].src[1]);
121 pack_uint(b, 17, 21, insts[i].bitfield.src_bit);
122 pack_uint(b, 22, 26, insts[i].bitfield.size);
123 pack_uint(b, 27, 31, insts[i].bitfield.dst_bit);
124 } else if (insts[i].op == MME_FERMI_OP_BRANCH) {
125 pack_uint(b, 4, 4, insts[i].branch.not_zero);
126 pack_uint(b, 5, 5, insts[i].branch.no_delay);
127 pack_uint(b, 11, 13, insts[i].src[0]);
128 pack_sint(b, 14, 31, insts[i].imm);
129 }
130 }
131 }
132
mme_fermi_decode(struct mme_fermi_inst * insts,const uint32_t * in,uint32_t inst_count)133 void mme_fermi_decode(struct mme_fermi_inst *insts,
134 const uint32_t *in, uint32_t inst_count)
135 {
136 for (uint32_t i = 0; i < inst_count; i++) {
137 const uint32_t *b = &in[i];
138
139 insts[i] = (struct mme_fermi_inst) {
140 .op = unpack_uint(b, 0, 3),
141 .end_next = unpack_uint(b, 7, 7),
142 .dst = unpack_uint(b, 8, 10),
143 };
144
145 if (insts[i].op != MME_FERMI_OP_BRANCH) {
146 insts[i].assign_op = unpack_uint(b, 4, 6);
147 }
148
149 if (insts[i].op == MME_FERMI_OP_ALU_REG) {
150 insts[i].src[0] = unpack_uint(b, 11, 13);
151 insts[i].src[1] = unpack_uint(b, 14, 16);
152 insts[i].alu_op = unpack_uint(b, 17, 21);
153 } else if (insts[i].op == MME_FERMI_OP_ADD_IMM ||
154 insts[i].op == MME_FERMI_OP_STATE) {
155 insts[i].src[0] = unpack_uint(b, 11, 13);
156 insts[i].imm = unpack_sint(b, 14, 31);
157 } else if (insts[i].op == MME_FERMI_OP_MERGE ||
158 insts[i].op == MME_FERMI_OP_BFE_LSL_IMM ||
159 insts[i].op == MME_FERMI_OP_BFE_LSL_REG) {
160 insts[i].src[0] = unpack_uint(b, 11, 13);
161 insts[i].src[1] = unpack_uint(b, 14, 16);
162 insts[i].bitfield.src_bit = unpack_uint(b, 17, 21);
163 insts[i].bitfield.size = unpack_uint(b, 22, 26);
164 insts[i].bitfield.dst_bit = unpack_uint(b, 27, 31);
165 } else if (insts[i].op == MME_FERMI_OP_BRANCH) {
166 insts[i].branch.not_zero = unpack_uint(b, 4, 4);
167 insts[i].branch.no_delay = unpack_uint(b, 5, 5);
168 insts[i].src[0] = unpack_uint(b, 11, 13);
169 insts[i].imm = unpack_sint(b, 14, 31);
170 }
171 }
172 }
173
174 static void
print_indent(FILE * fp,unsigned depth)175 print_indent(FILE *fp, unsigned depth)
176 {
177 for (unsigned i = 0; i < depth; i++)
178 fprintf(fp, " ");
179 }
180
181 static void
print_reg(FILE * fp,enum mme_fermi_reg reg)182 print_reg(FILE *fp, enum mme_fermi_reg reg)
183 {
184 if (reg == MME_FERMI_REG_ZERO) {
185 fprintf(fp, " $zero");
186 } else {
187 fprintf(fp, " $r%u", (unsigned)reg);
188 }
189 }
190
191 static void
print_imm(FILE * fp,const struct mme_fermi_inst * inst)192 print_imm(FILE *fp, const struct mme_fermi_inst *inst)
193 {
194 int32_t imm = util_mask_sign_extend(inst->imm, 18);
195
196 fprintf(fp, " %d /* 0x%04x */", (int)imm, (unsigned)imm);
197 }
198
199 void
mme_fermi_print_inst(FILE * fp,unsigned indent,const struct mme_fermi_inst * inst)200 mme_fermi_print_inst(FILE *fp, unsigned indent,
201 const struct mme_fermi_inst *inst)
202 {
203 print_indent(fp, indent);
204
205 switch (inst->op) {
206 case MME_FERMI_OP_ALU_REG:
207 fprintf(fp, "%s", mme_fermi_alu_op_to_str(inst->alu_op));
208 print_reg(fp, inst->src[0]);
209 print_reg(fp, inst->src[1]);
210
211 if (inst->alu_op == MME_FERMI_ALU_OP_ADDC) {
212 fprintf(fp, " $carry");
213 } else if (inst->alu_op == MME_FERMI_ALU_OP_SUBB) {
214 fprintf(fp, " $borrow");
215 }
216 break;
217 case MME_FERMI_OP_ADD_IMM:
218 case MME_FERMI_OP_STATE:
219 fprintf(fp, "%s", mme_fermi_op_to_str(inst->op));
220 print_reg(fp, inst->src[0]);
221 print_imm(fp, inst);
222 break;
223 case MME_FERMI_OP_MERGE:
224 fprintf(fp, "%s", mme_fermi_op_to_str(inst->op));
225 print_reg(fp, inst->src[0]);
226 print_reg(fp, inst->src[1]);
227 fprintf(fp, " (%u, %u, %u)", inst->bitfield.dst_bit,
228 inst->bitfield.size,
229 inst->bitfield.src_bit);
230 break;
231 case MME_FERMI_OP_BFE_LSL_IMM:
232 fprintf(fp, "%s", mme_fermi_op_to_str(inst->op));
233 print_reg(fp, inst->src[0]);
234 print_reg(fp, inst->src[1]);
235 fprintf(fp, " (%u, %u)", inst->bitfield.dst_bit,
236 inst->bitfield.size);
237 break;
238 case MME_FERMI_OP_BFE_LSL_REG:
239 fprintf(fp, "%s", mme_fermi_op_to_str(inst->op));
240 print_reg(fp, inst->src[0]);
241 print_reg(fp, inst->src[1]);
242 fprintf(fp, " (%u, %u)", inst->bitfield.src_bit,
243 inst->bitfield.size);
244 break;
245 case MME_FERMI_OP_BRANCH:
246 if (inst->branch.not_zero) {
247 fprintf(fp, "BNZ");
248 } else {
249 fprintf(fp, "BZ");
250 }
251 print_reg(fp, inst->src[0]);
252 print_imm(fp, inst);
253
254 if (inst->branch.no_delay) {
255 fprintf(fp, " NO_DELAY");
256 }
257
258 break;
259 default:
260 fprintf(fp, "%s", mme_fermi_op_to_str(inst->op));
261 break;
262 }
263
264 if (inst->op != MME_FERMI_OP_BRANCH) {
265 fprintf(fp, "\n");
266 print_indent(fp, indent);
267
268 fprintf(fp, "%s", mme_fermi_assign_op_to_str(inst->assign_op));
269 print_reg(fp, inst->dst);
270
271 if (inst->assign_op != MME_FERMI_ASSIGN_OP_LOAD) {
272 fprintf(fp, " $scratch");
273 }
274 }
275
276 if (inst->end_next) {
277 fprintf(fp, "\n");
278 print_indent(fp, indent);
279 fprintf(fp, "END_NEXT");
280 }
281
282 fprintf(fp, "\n");
283
284 }
285
286 void
mme_fermi_print(FILE * fp,const struct mme_fermi_inst * insts,uint32_t inst_count)287 mme_fermi_print(FILE *fp, const struct mme_fermi_inst *insts,
288 uint32_t inst_count)
289 {
290 for (uint32_t i = 0; i < inst_count; i++) {
291 fprintf(fp, "%u:\n", i);
292 mme_fermi_print_inst(fp, 1, &insts[i]);
293 }
294 }
295
296 void
mme_fermi_dump(FILE * fp,uint32_t * encoded,size_t encoded_size)297 mme_fermi_dump(FILE *fp, uint32_t *encoded, size_t encoded_size)
298 {
299 uint32_t inst_count = encoded_size / 4;
300 for (uint32_t i = 0; i < inst_count; i++) {
301 struct mme_fermi_inst inst;
302 mme_fermi_decode(&inst, &encoded[i], 1);
303 mme_fermi_print_inst(fp, 1, &inst);
304 }
305 }
306