1 /* radare - LGPL - Copyright 2017 - wargio */
2 #include "libps.h"
3 #include "libps_internal.h"
4 
5 ps_operand_t ps_operands_array[] = {
6 	{ 0, 0}, // No Operand
7 	{ 5, 16}, // FA
8 	{ 5, 11}, // FB
9 	{ 5, 6}, // FC
10 	{ 5, 21}, // FD/FS
11 	{ 3, 23}, //crfD,
12 	{ 1, 16}, //WB,
13 	{ 3, 12}, //IB,
14 	{ 1, 10}, //WC,
15 	{ 3, 7}, //IC,
16 	{ 5, 16}, // RA
17 	{ 5, 11}, // RB
18 	{ 5, 16}, //DRA,
19 	{ 5, 11}, //DRB,
20 };
21 
22 
23 ps_opcode_t ps_opcodes_array[] = {
24 	{ psq_lx, "psq_lx", OPM (4, 6), OPM_MASK, { OP_FD, OP_RA, OP_RB, OP_WC, OP_IC}, "Paired Single Quantized Load Indexed"},
25 	{ psq_stx, "psq_stx", OPM (4, 7), OPM_MASK, { OP_FS, OP_RA, OP_RB, OP_WC, OP_IC}, "Paired Single Quantized Store Indexed"},
26 	{ psq_lux, "psq_lux", OPM (4, 38), OPM_MASK, { OP_FD, OP_RA, OP_RB, OP_WC, OP_IC}, "Paired Single Quantized Load with update Indexed"},
27 	{ psq_stux, "psq_stux", OPM (4, 39), OPM_MASK, { OP_FS, OP_RA, OP_RB, OP_WC, OP_IC}, "Paired Single Quantized Store with update Indexed"},
28 
29 	{ psq_l, "psq_l", OP (56), OP_MASK, { OP_FD, OP_DRA, OP_WB, OP_IB}, "Paired Single Quantized Load"},
30 	{ psq_lu, "psq_lu", OP (57), OP_MASK, { OP_FD, OP_DRA, OP_WB, OP_IB}, "Paired Single Quantized Load with Update"},
31 	{ psq_st, "psq_st", OP (60), OP_MASK, { OP_FS, OP_DRA, OP_WB, OP_IB}, "Paired Single Quantized Store"},
32 	{ psq_stu, "psq_stu", OP (61), OP_MASK, { OP_FS, OP_DRA, OP_WB, OP_IB}, "Paired Single Quantized Store with update"},
33 
34 	{ ps_div, "ps_div", OPSC (4, 18, 0), OPS_MASK, { OP_FD, OP_FA, OP_FB}, "Paired Single Divide"},
35 	{ ps_div_dot, "ps_div.", OPSC (4, 18, 1), OPS_MASK_DOT, { OP_FD, OP_FA, OP_FB}, "Paired Single Divide"},
36 	{ ps_sub, "ps_sub", OPSC (4, 20, 0), OPS_MASK, { OP_FD, OP_FA, OP_FB}, "Paired Single Subtract"},
37 	{ ps_sub_dot, "ps_sub.", OPSC (4, 20, 1), OPS_MASK_DOT, { OP_FD, OP_FA, OP_FB}, "Paired Single Subtract"},
38 	{ ps_add, "ps_add", OPSC (4, 21, 0), OPS_MASK, { OP_FD, OP_FA, OP_FB}, "Paired Single Add"},
39 	{ ps_add_dot, "ps_add.", OPSC (4, 21, 1), OPS_MASK_DOT, { OP_FD, OP_FA, OP_FB}, "Paired Single Add"},
40 	{ ps_sel, "ps_sel", OPSC (4, 23, 0), OPS_MASK, { OP_FD, OP_FA, OP_FC, OP_FB}, "Paired Single Select"},
41 	{ ps_sel_dot, "ps_sel.", OPSC (4, 23, 1), OPS_MASK_DOT, { OP_FD, OP_FA, OP_FC, OP_FB}, "Paired Single Select"},
42 	{ ps_res, "ps_res", OPSC (4, 24, 0), OPS_MASK, { OP_FD, OP_FB}, "Paired Single Reciprocal Estimate"},
43 	{ ps_res_dot, "ps_res.", OPSC (4, 24, 1), OPS_MASK_DOT, { OP_FD, OP_FB}, "Paired Single Reciprocal Estimate"},
44 	{ ps_mul, "ps_mul", OPSC (4, 25, 0), OPS_MASK, { OP_FD, OP_FA, OP_FC}, "Paired Single Multiply"},
45 	{ ps_mul_dot, "ps_mul.", OPSC (4, 25, 1), OPS_MASK_DOT, { OP_FD, OP_FA, OP_FC}, "Paired Single Multiply"},
46 	{ ps_rsqrte, "ps_rsqrte", OPSC (4, 26, 0), OPS_MASK, { OP_FD, OP_FB}, "Paired Single Reciprocal Square Root Estimate"},
47 	{ ps_rsqrte_dot, "ps_rsqrte.", OPSC (4, 26, 1), OPS_MASK_DOT, { OP_FD, OP_FB}, "Paired Single Reciprocal Square Root Estimate"},
48 	{ ps_msub, "ps_msub", OPSC (4, 28, 0), OPS_MASK, { OP_FD, OP_FA, OP_FC, OP_FB}, "Paired Single Multiply-Subtract"},
49 	{ ps_msub_dot, "ps_msub.", OPSC (4, 28, 1), OPS_MASK_DOT, { OP_FD, OP_FA, OP_FC, OP_FB}, "Paired Single Multiply-Subtract"},
50 	{ ps_madd, "ps_madd", OPSC (4, 29, 0), OPS_MASK, { OP_FD, OP_FA, OP_FC, OP_FB}, "Paired Single Multiply-Add"},
51 	{ ps_madd_dot, "ps_madd.", OPSC (4, 29, 1), OPS_MASK_DOT, { OP_FD, OP_FA, OP_FC, OP_FB}, "Paired Single Multiply-Add"},
52 	{ ps_nmsub, "ps_nmsub", OPSC (4, 30, 0), OPS_MASK, { OP_FD, OP_FA, OP_FC, OP_FB}, "Paired Single Negative Multiply-Subtract"},
53 	{ ps_nmsub_dot, "ps_nmsub.", OPSC (4, 30, 1), OPS_MASK_DOT, { OP_FD, OP_FA, OP_FC, OP_FB}, "Paired Single Negative Multiply-Subtract"},
54 	{ ps_nmadd, "ps_nmadd", OPSC (4, 31, 0), OPS_MASK, { OP_FD, OP_FA, OP_FC, OP_FB}, "Paired Single Negative Multiply-Add"},
55 	{ ps_nmadd_dot, "ps_nmadd.", OPSC (4, 31, 1), OPS_MASK_DOT, { OP_FD, OP_FA, OP_FC, OP_FB}, "Paired Single Negative Multiply-Add"},
56 
57 	{ ps_neg, "ps_neg", OPLC (4, 40, 0), OPL_MASK, { OP_FD, OP_FB}, "Paired Single Negate"},
58 	{ ps_neg_dot, "ps_neg.", OPLC (4, 40, 1), OPL_MASK_DOT, { OP_FD, OP_FB}, "Paired Single Negate"},
59 	{ ps_mr, "ps_mr", OPLC (4, 72, 0), OPL_MASK, { OP_FD, OP_FB}, "Paired Single Move Register"},
60 	{ ps_mr_dot, "ps_mr.", OPLC (4, 72, 1), OPL_MASK_DOT, { OP_FD, OP_FB}, "Paired Single Move Register"},
61 	{ ps_nabs, "ps_nabs", OPLC (4, 136, 0), OPL_MASK, { OP_FD, OP_FB}, "Paired Single Negative Absolute Value"},
62 	{ ps_nabs_dot, "ps_nabs.", OPLC (4, 136, 1), OPL_MASK_DOT, { OP_FD, OP_FB}, "Paired Single Negative Absolute Value"},
63 	{ ps_abs, "ps_abs", OPLC (4, 264, 0), OPL_MASK, { OP_FD, OP_FB}, "Paired Single Absolute Value"},
64 	{ ps_abs_dot, "ps_abs.", OPLC (4, 264, 1), OPL_MASK_DOT, { OP_FD, OP_FB}, "Paired Single Absolute Value"},
65 
66 	{ ps_sum0, "ps_sum0", OPSC (4, 10, 0), OPS_MASK, { OP_FD, OP_FA, OP_FC, OP_FB}, "Paired Single vector SUM high"},
67 	{ ps_sum0_dot, "ps_sum0.", OPSC (4, 10, 1), OPS_MASK_DOT, { OP_FD, OP_FA, OP_FC, OP_FB}, "Paired Single vector SUM high"},
68 	{ ps_sum1, "ps_sum1", OPSC (4, 11, 0), OPS_MASK, { OP_FD, OP_FA, OP_FC, OP_FB}, "Paired Single vector SUM low"},
69 	{ ps_sum1_dot, "ps_sum1.", OPSC (4, 11, 1), OPS_MASK_DOT, { OP_FD, OP_FA, OP_FC, OP_FB}, "Paired Single vector SUM low"},
70 	{ ps_muls0, "ps_muls0", OPSC (4, 12, 0), OPS_MASK, { OP_FD, OP_FA, OP_FC}, "Paired Single Multiply Scalar high"},
71 	{ ps_muls0_dot, "ps_muls0.", OPSC (4, 12, 1), OPS_MASK_DOT, { OP_FD, OP_FA, OP_FC}, "Paired Single Multiply Scalar high"},
72 	{ ps_muls1, "ps_muls1", OPSC (4, 13, 0), OPS_MASK, { OP_FD, OP_FA, OP_FC}, "Paired Single Multiply Scalar low"},
73 	{ ps_muls1_dot, "ps_muls1.", OPSC (4, 13, 1), OPS_MASK_DOT, { OP_FD, OP_FA, OP_FC}, "Paired Single Multiply Scalar low"},
74 	{ ps_madds0, "ps_madds0", OPSC (4, 14, 0), OPS_MASK, { OP_FD, OP_FA, OP_FC, OP_FB}, "Paired Single Multiply-Add Scalar high"},
75 	{ ps_madds0_dot, "ps_madds0.", OPSC (4, 14, 1), OPS_MASK_DOT, { OP_FD, OP_FA, OP_FC, OP_FB}, "Paired Single Multiply-Add Scalar high"},
76 	{ ps_madds1, "ps_madds1", OPSC (4, 15, 0), OPS_MASK, { OP_FD, OP_FA, OP_FC, OP_FB}, "Paired Single Multiply-Add Scalar low"},
77 	{ ps_madds1_dot, "ps_madds1.", OPSC (4, 15, 1), OPS_MASK_DOT, { OP_FD, OP_FA, OP_FC, OP_FB}, "Paired Single Multiply-Add Scalar low"},
78 
79 	{ ps_cmpu0, "ps_cmpu0", OPL (4, 0), OPL_MASK, { OP_crfD, OP_FA, OP_FB}, "Paired Singles Compare Unordered High"},
80 	{ ps_cmpo0, "ps_cmpo0", OPL (4, 32), OPL_MASK, { OP_crfD, OP_FA, OP_FB}, "Paired Singles Compare Ordered High"},
81 	{ ps_cmpu1, "ps_cmpu1", OPL (4, 64), OPL_MASK, { OP_crfD, OP_FA, OP_FB}, "Paired Singles Compare Unordered Low"},
82 	{ ps_cmpo1, "ps_cmpo1", OPL (4, 96), OPL_MASK, { OP_crfD, OP_FA, OP_FB}, "Paired Singles Compare Ordered Low"},
83 
84 	{ ps_merge00, "ps_merge00", OPLC (4, 528, 0), OPL_MASK, { OP_FD, OP_FA, OP_FB}, "Paired Single MERGE high"},
85 	{ ps_merge00_dot, "ps_merge00.", OPLC (4, 528, 1), OPL_MASK_DOT, { OP_FD, OP_FA, OP_FB}, "Paired Single MERGE high"},
86 	{ ps_merge01, "ps_merge01", OPLC (4, 560, 0), OPL_MASK, { OP_FD, OP_FA, OP_FB}, "Paired Single MERGE direct"},
87 	{ ps_merge01_dot, "ps_merge01.", OPLC (4, 560, 1), OPL_MASK_DOT, { OP_FD, OP_FA, OP_FB}, "Paired Single MERGE direct"},
88 	{ ps_merge10, "ps_merge10", OPLC (4, 592, 0), OPL_MASK, { OP_FD, OP_FA, OP_FB}, "Paired Single MERGE swapped"},
89 	{ ps_merge10_dot, "ps_merge10.", OPLC (4, 592, 1), OPL_MASK_DOT, { OP_FD, OP_FA, OP_FB}, "Paired Single MERGE swapped"},
90 	{ ps_merge11, "ps_merge11", OPLC (4, 624, 0), OPL_MASK, { OP_FD, OP_FA, OP_FB}, "Paired Single MERGE low"},
91 	{ ps_merge11_dot, "ps_merge11.", OPLC (4, 624, 1), OPL_MASK_DOT, { OP_FD, OP_FA, OP_FB}, "Paired Single MERGE low"},
92 
93 	{ ps_dcbz_l, "dcbz_l", OPL (4, 1014), OPL_MASK, { OP_RA, OP_RB}, "Data Cache Block Set to Zero Locked"},
94 
95 };
96 
libps_decode(ut32 data,ppcps_t * ps)97 bool libps_decode(ut32 data, ppcps_t* ps) {
98 	ut32 op = (data & OP_MASK);
99 
100 	if ((op == OP (4)) || (op == OP (56)) ||
101 		(op == OP (57)) || (op == OP (60)) ||
102 		(op == OP (61))) {
103 		ut32 size = sizeof (ps_opcodes_array) / sizeof (ps_opcode_t);
104 		ps_opcode_t* instruction = ps_opcodes_array;
105 
106 		ut32 l, j;
107 		for (l = 0; l < size; l++) {
108 			if ((data & instruction->mask) == instruction->opcode) {
109 				j = 0;
110 				for (;j < 6 && instruction->operands[j] != 0; j++) {
111 					ppcps_field_t* field = &ps->operands[j];
112 					ps_operand_t* ps_operand = &ps_operands_array[instruction->operands[j]];
113 
114 					int bits = (data >> ps_operand->shift) & ((1 << ps_operand->bits) - 1);
115 					//int ext_bits = (bits << (32 - ps_operand->bits)) >> (32 - ps_operand->bits);
116 
117 					switch (instruction->operands[j]) {
118 					case OP_FA:
119 					case OP_FB:
120 					case OP_FC:
121 					case OP_FD:
122 					{
123 						field->type = TYPE_REG;
124 						field->value = bits;
125 						break;
126 					}
127 
128 					case OP_RA:
129 					case OP_RB:
130 					{
131 						field->type = TYPE_REG;
132 						field->value = bits;
133 						break;
134 					}
135 
136 					case OP_crfD:
137 					{
138 						field->type = TYPE_CR;
139 						field->value = bits;
140 						break;
141 					}
142 					case OP_WB:
143 					case OP_IB:
144 					case OP_WC:
145 					case OP_IC:
146 					{
147 						field->type = TYPE_IMM;
148 						field->value = bits;
149 						break;
150 					}
151 
152 					case OP_DRA:
153 					{
154 						ut16 imm = (ut16) (data & 0x7FF);
155 						ut16 sign = (ut16) (data & 0x800);
156 						st16 displacement = 0;
157 						if (sign == 0) {
158 							displacement = imm;
159 						} else {
160 							displacement = -1 * imm;
161 						}
162 						field->type = TYPE_MEM;
163 						field->value = bits + displacement;
164 						break;
165 					}
166 
167 					default:
168 						break;
169 					}
170 				}
171 				ps->n = j;
172 				ps->name = instruction->name;
173 				ps->op = instruction->insn;
174 				return true;
175 			}
176 			instruction++;
177 		}
178 	}
179 	return false;
180 }
181 
libps_snprint(char * str,int size,ut64 addr,ppcps_t * instr)182 void libps_snprint(char* str, int size, ut64 addr, ppcps_t* instr) {
183 	ut32 i;
184 	int bufsize = size, add = 0;
185 	add = snprintf (str, bufsize, "%s", instr->name);
186 	for (i = 0; add > 0 && i < instr->n && add < bufsize; i++) {
187 		if (instr->operands[i].type == TYPE_REG) {
188 			add += snprintf (str + add, bufsize - add, " fr%u", instr->operands[i].value);
189 		} else if (instr->operands[i].type == TYPE_IMM) {
190 			add += snprintf (str + add, bufsize - add, " 0x%x", instr->operands[i].value);
191 		} else if (instr->operands[i].type == TYPE_MEM) {
192 			add += snprintf (str + add, bufsize - add, " 0x%x(r%d)", instr->operands[i].value, instr->operands[i + 1].value);
193 			i++;
194 		} else if (instr->operands[i].type == TYPE_CR) {
195 			add += snprintf (str + add, bufsize - add, " cr%u", instr->operands[i].value);
196 		}
197 	}
198 }
199