1 /*
2  *	HT Editor
3  *	avrdis.cc
4  *
5  *	Copyright (C) 2008 Sebastian Biallas (sb@biallas.net)
6  *
7  *	This program is free software; you can redistribute it and/or modify
8  *	it under the terms of the GNU General Public License version 2 as
9  *	published by the Free Software Foundation.
10  *
11  *	This program is distributed in the hope that it will be useful,
12  *	but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *	GNU General Public License for more details.
15  *
16  *	You should have received a copy of the GNU General Public License
17  *	along with this program; if not, write to the Free Software
18  *	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19  */
20 
21 #include "endianess.h"
22 #include "avrdis.h"
23 #include "avropc.h"
24 #include "snprintf.h"
25 #include "tools.h"
26 
AVRDisassembler()27 AVRDisassembler::AVRDisassembler()
28 {
29 }
30 
decode(byte * code,int maxlen,CPU_ADDR addr)31 dis_insn *AVRDisassembler::decode(byte *code, int maxlen, CPU_ADDR addr)
32 {
33 	const struct avr_opcode *opcode;
34 	const struct avr_opcode *opcode_end;
35 	uint32 op;
36 
37 	if (maxlen < 2) {
38 		insn.valid = false;
39 		insn.size = maxlen;
40 		return &insn;
41 	}
42 
43 	insn.data = createHostInt(code, 2, little_endian);
44 
45 	if ((insn.data & 0xfe0c) == 0x940c || (insn.data & 0xfc0f) == 0x9000) {
46 		insn.size = 4;
47 		if (maxlen < 4) {
48 			insn.valid = false;
49 			insn.size = maxlen;
50 			return &insn;
51 		}
52 		insn.data |= createHostInt(code+2, 2, little_endian) << 16;
53 	} else {
54 		insn.size = 2;
55 	}
56 
57 	op = insn.data;
58 
59 	opcode_end = avr_opcodes + avr_num_opcodes;
60 
61 	for (opcode = avr_opcodes; opcode < opcode_end; opcode++) {
62 		const byte *opindex;
63 		const struct avr_operand *operand;
64 		bool invalid;
65 
66 		if ((insn.data & opcode->mask) != opcode->opcode) {
67 			continue;
68 		}
69 
70 		/* Make two passes over the operands.  First see if any of them
71 		   have extraction functions, and, if they do, make sure the
72 		   instruction is valid.  */
73 		invalid = false;
74 		for (opindex = opcode->operands; *opindex != 0; opindex++) {
75 			operand = avr_operands + *opindex;
76 			if (operand->extract) (*operand->extract)(insn.data, &invalid);
77 		}
78 		if (invalid) continue;
79 
80 		/* The instruction is valid.  */
81 		insn.name = opcode->name;
82 
83 		/* Now extract and print the operands.  */
84 		int opidx = 0;
85 		for (opindex = opcode->operands; *opindex != 0; opindex++) {
86 			sint32 value;
87 
88 			operand = avr_operands + *opindex;
89 
90 			/* Operands that are marked FAKE are simply ignored.  We
91 			   already made sure that the extract function considered
92 			   the instruction to be valid.  */
93 			if ((operand->flags & AVR_OPERAND_FAKE) != 0) continue;
94 
95 			insn.op[opidx].op = operand;
96 			insn.op[opidx].flags = operand->flags;
97 			/* Extract the value from the instruction.  */
98 			if (operand->extract) {
99 				value = (*operand->extract)(insn.data, NULL);
100 			} else {
101 				value = (insn.data >> operand->shift) & ((1 << operand->bits) - 1);
102 				value <<= operand->scale;
103 				value += operand->add;
104 				if ((operand->flags & AVR_OPERAND_SIGNED) != 0 && (value & (1 << (operand->bits + operand->scale - 1))) != 0) {
105 					value |= -1 << (operand->bits + operand->scale);
106 				}
107 			}
108 
109 			if (operand->flags & (AVR_OPERAND_GPR | AVR_OPERAND_GPR_2)) {
110 				insn.op[opidx++].reg = value;
111 			} else if (operand->flags & (AVR_OPERAND_IMM | AVR_OPERAND_ABS)) {
112 				insn.op[opidx++].imm = value;
113 			} else if (operand->flags & AVR_OPERAND_REL) {
114 				insn.op[opidx++].imm = addr.addr32.offset + value + 2;
115 			} else if (operand->flags & AVR_OPERAND_Yq) {
116 				insn.op[opidx++].mem.disp = value;
117 			} else if (operand->flags & AVR_OPERAND_Zq) {
118 				insn.op[opidx++].mem.disp = value;
119 			}
120 
121 		}
122 		insn.ops = opidx;
123 
124 		/* We have found and printed an instruction; return.  */
125 		insn.valid = true;
126 		return &insn;
127 	}
128 
129 	insn.valid = false;
130 	return &insn;
131 }
132 
duplicateInsn(dis_insn * disasm_insn)133 dis_insn *AVRDisassembler::duplicateInsn(dis_insn *disasm_insn)
134 {
135 	avrdis_insn *insn = ht_malloc(sizeof (avrdis_insn));
136 	*insn = *(avrdis_insn *)disasm_insn;
137 	return insn;
138 }
139 
getOpcodeMetrics(int & min_length,int & max_length,int & min_look_ahead,int & avg_look_ahead,int & addr_align)140 void AVRDisassembler::getOpcodeMetrics(int &min_length, int &max_length, int &min_look_ahead, int &avg_look_ahead, int &addr_align)
141 {
142 	min_length = 2;
143 	max_length = 4;
144 	min_look_ahead = 4;
145 	avg_look_ahead = 4;
146 	addr_align = 2;
147 }
148 
getSize(dis_insn * disasm_insn)149 byte AVRDisassembler::getSize(dis_insn *disasm_insn)
150 {
151 	return ((avrdis_insn*)disasm_insn)->size;
152 }
153 
getName()154 const char *AVRDisassembler::getName()
155 {
156 	return "AVR/Disassembler";
157 }
158 
str(dis_insn * disasm_insn,int style)159 const char *AVRDisassembler::str(dis_insn *disasm_insn, int style)
160 {
161 	return strf(disasm_insn, style, "");
162 }
163 
strf(dis_insn * disasm_insn,int style,const char * format)164 const char *AVRDisassembler::strf(dis_insn *disasm_insn, int style, const char *format)
165 {
166 	if (style & DIS_STYLE_HIGHLIGHT) enable_highlighting();
167 
168 	const char *cs_default = get_cs(e_cs_default);
169 	const char *cs_number = get_cs(e_cs_number);
170 	const char *cs_symbol = get_cs(e_cs_symbol);
171 
172 	avrdis_insn *avr_insn = (avrdis_insn *) disasm_insn;
173 	if (!avr_insn->valid) {
174 		switch (avr_insn->size) {
175 		case 1:
176 			strcpy(insnstr, "db            ?");
177 			break;
178 		case 2:
179 			sprintf(insnstr, "dw           %s0x%04x", cs_number, avr_insn->data);
180 			break;
181 		case 3:
182 			strcpy(insnstr, "db            ? * 3");
183 			break;
184 		case 4:
185 			sprintf(insnstr, "dd           %s0x%08x", cs_number, avr_insn->data);
186 			break;
187 		default: { /* braces for empty assert */
188 			strcpy(insnstr, "?");
189 //			assert(0);
190 		}
191 		}
192 	} else {
193 		char *is = insnstr+sprintf(insnstr, "%-13s", avr_insn->name);
194 
195 		bool need_comma = false;
196 		bool need_paren = false;
197 		for (int opidx = 0; opidx < avr_insn->ops; opidx++) {
198 			int flags = avr_insn->op[opidx].flags;
199 			if (need_comma) {
200 				is += sprintf(is, "%s, ", cs_symbol);
201 				need_comma = false;
202 			} else {
203 				need_comma = true;
204 			}
205 			if (flags & AVR_OPERAND_GPR) {
206 				is += sprintf(is, "%sr%d", cs_default, avr_insn->op[opidx].reg);
207 			} else if (flags & AVR_OPERAND_GPR_2) {
208 				is += sprintf(is, "%sr%d%s:%sr%d", cs_default, avr_insn->op[opidx].reg, cs_symbol, cs_default, avr_insn->op[opidx].reg+1);
209 			} else if (flags & AVR_OPERAND_XYZ_MASK) {
210 				int xyz = (flags & AVR_OPERAND_XYZ_MASK) - 1;
211 				const char *r[] = {"X", "X+", "-X", "Y", "Y+", "-Y", "Y%s%c%s%d", "Z", "Z+", "-Z", "Z%s%c%s%d"};
212 				char buf[100];
213 				ht_snprintf(buf, sizeof buf, "%s%s", cs_default, r[xyz]);
214 				unsigned q = avr_insn->op[opidx].mem.disp;
215 				char c;
216 				if (q < 0) {
217 					q = -q;
218 					c = '-';
219 				} else {
220 					c = '+';
221 				}
222 				is += sprintf(is, buf, cs_symbol, c, cs_number, q);
223 			} else if (flags & (AVR_OPERAND_ABS | AVR_OPERAND_REL)) {
224 				CPU_ADDR caddr;
225 				caddr.addr32.offset = uint32(avr_insn->op[opidx].imm);
226 				int slen;
227 				char *s = (addr_sym_func) ? addr_sym_func(caddr, &slen, addr_sym_func_context) : 0;
228 				if (s) {
229 					is += sprintf(is, "%s", cs_default);
230 					memcpy(is, s, slen);
231 					is[slen] = 0;
232 					is += slen;
233 				} else {
234 					is += ht_snprintf(is, 100, "%s0x%x", cs_number, avr_insn->op[opidx].imm);
235 				}
236 			} else if ((flags & AVR_OPERAND_IMM) != 0) {
237 				is += sprintf(is, "%s%d", cs_number, (int)avr_insn->op[opidx].imm);
238 			}
239 #if 0
240 			} else if (flags & (PPC_OPERAND_RELATIVE | )) {
241 				CPU_ADDR caddr;
242 				if (mode == PPC_MODE_32) {
243 					caddr.addr32.offset = (uint32)ppc_insn->op[opidx].mem.disp;
244 				} else {
245 					caddr.flat64.addr = ppc_insn->op[opidx].mem.disp;
246 				}
247 				int slen;
248 				char *s = (addr_sym_func) ? addr_sym_func(caddr, &slen, addr_sym_func_context) : 0;
249 				if (s) {
250 					is += sprintf(is, "%s", cs_default);
251 					memcpy(is, s, slen);
252 					is[slen] = 0;
253 					is += slen;
254 				} else {
255 					is += ht_snprintf(is, 100, "%s0x%qx", cs_number, ppc_insn->op[opidx].rel.mem);
256 				}
257 			} else if ((flags & PPC_OPERAND_ABSOLUTE) != 0) {
258 				is += ht_snprintf(is, 100, "%s0x%qx", cs_number, ppc_insn->op[opidx].abs.mem);
259 			} else if ((flags & PPC_OPERAND_CR) == 0 || (dialect & PPC_OPCODE_PPC) == 0) {
260 				is += ht_snprintf(is, 100, "%s%qd", cs_number, ppc_insn->op[opidx].imm);
261 			} else if (ppc_insn->op[opidx].op->bits == 3) {
262 				is += sprintf(is, "%scr%d", cs_default, ppc_insn->op[opidx].creg);
263 			} else {
264 				static const char *cbnames[4] = { "lt", "gt", "eq", "so" };
265 				int cr;
266 				int cc;
267 				cr = ppc_insn->op[opidx].creg >> 2;
268 				if (cr != 0) is += sprintf(is, "%s4%s*%scr%d", cs_number, cs_symbol, cs_default, cr);
269 				cc = ppc_insn->op[opidx].creg & 3;
270 				if (cc != 0) {
271 					if (cr != 0) is += sprintf(is, "%s+", cs_symbol);
272 					is += sprintf(is, "%s%s", cs_default, cbnames[cc]);
273 				}
274 			}
275 #endif
276 		}
277 	}
278 	disable_highlighting();
279 	return insnstr;
280 }
281 
getObjectID() const282 ObjectID AVRDisassembler::getObjectID() const
283 {
284 	return ATOM_DISASM_AVR;
285 }
286 
validInsn(dis_insn * disasm_insn)287 bool AVRDisassembler::validInsn(dis_insn *disasm_insn)
288 {
289 	return ((avrdis_insn*)disasm_insn)->valid;
290 }
291