]>
Commit | Line | Data |
---|---|---|
8aa13b87 JK |
1 | /* This file has been modified by Data General Corporation, November 1989. */ |
2 | ||
3 | #include <stdio.h> | |
4 | #include "m88k-opcode.h" | |
5 | #include "defs.h" | |
6 | #include "symtab.h" | |
7 | ||
8 | void sprint_address (); | |
9 | ||
10 | /* Changed hashtab to hashtable to avoid naming conflict | |
11 | with libdc.o (used for tdesc) for m88k. | |
12 | */ | |
13 | ||
14 | INSTAB *hashtable[HASHVAL] = {0}; | |
15 | ||
16 | /* | |
17 | * Disassemble an M88000 Instruction | |
18 | * | |
19 | * | |
20 | * This module decodes the first instruction in inbuf. It uses the pc | |
21 | * to display pc-relative displacements. It writes the disassembled | |
22 | * instruction in outbuf. | |
23 | * | |
24 | * Revision History | |
25 | * | |
26 | * Revision 1.0 11/08/85 Creation date by Motorola | |
27 | * 05/11/89 R. Trawick adapted to GDB interface. | |
28 | */ | |
29 | #define MAXLEN 20 | |
30 | ||
31 | print_insn (memaddr, stream) | |
32 | CORE_ADDR memaddr; | |
33 | FILE *stream; | |
34 | { | |
35 | unsigned char buffer[MAXLEN]; | |
36 | /* should be expanded if disassembler prints symbol names */ | |
37 | char outbuf[100]; | |
38 | int n; | |
39 | ||
40 | /* Instruction addresses may have low two bits set. Clear them. */ | |
41 | memaddr&= 0xfffffffc; | |
42 | read_memory (memaddr, buffer, MAXLEN); | |
43 | ||
44 | n = m88kdis ((int)memaddr, buffer, outbuf); | |
45 | ||
46 | fputs (outbuf, stream); | |
47 | ||
48 | return (n); | |
49 | } | |
50 | ||
51 | /* | |
52 | * disassemble the first instruction in 'inbuf'. | |
53 | * 'pc' should be the address of this instruction, it will | |
54 | * be used to print the target address if this is a relative jump or call | |
55 | * 'outbuf' gets filled in with the disassembled instruction. It should | |
56 | * be long enough to hold the longest disassembled instruction. | |
57 | * 100 bytes is certainly enough, unless symbol printing is added later | |
58 | * The function returns the length of this instruction in bytes. | |
59 | */ | |
60 | ||
61 | int m88kdis( pc, inbuf, outbuf ) | |
62 | ||
63 | int pc; | |
64 | int *inbuf; | |
65 | char *outbuf; | |
66 | ||
67 | { static ihashtab_initialized = 0; | |
68 | int instruction; | |
69 | unsigned int opcode; | |
70 | INSTAB *entry_ptr; | |
71 | int opmask; | |
72 | int class; | |
73 | ||
74 | instruction= *inbuf; | |
75 | ||
76 | if (!ihashtab_initialized) { | |
77 | init_disasm(); | |
78 | } | |
79 | ||
80 | /* create a the appropriate mask to isolate the opcode */ | |
81 | opmask= DEFMASK; | |
82 | class= instruction & DEFMASK; | |
83 | if ((class >= SFU0) && (class <= SFU7)) { | |
84 | if (instruction < SFU1) { | |
85 | opmask= CTRLMASK; | |
86 | } else { | |
87 | opmask= SFUMASK; | |
88 | } | |
89 | } else if (class == RRR) { | |
90 | opmask= RRRMASK; | |
91 | } else if (class == RRI10) { | |
92 | opmask= RRI10MASK; | |
93 | } | |
94 | ||
95 | /* isolate the opcode */ | |
96 | opcode= instruction & opmask; | |
97 | ||
98 | /* search the hash table with the isolated opcode */ | |
99 | for (entry_ptr= hashtable[ opcode % HASHVAL ]; | |
100 | (entry_ptr != NULL) && (entry_ptr->opcode != opcode); | |
101 | entry_ptr= entry_ptr->next) { | |
102 | } | |
103 | ||
104 | if (entry_ptr == NULL) { | |
105 | sprintf( outbuf, "word\t%08x", instruction ); | |
106 | } else { | |
107 | sprintf( outbuf, "%s\t", entry_ptr->mnemonic ); | |
108 | sprintop( &outbuf[strlen(outbuf)], &(entry_ptr->op1), instruction, pc, 1 ); | |
109 | sprintop( &outbuf[strlen(outbuf)], &(entry_ptr->op2), instruction, pc, 0 ); | |
110 | sprintop( &outbuf[strlen(outbuf)], &(entry_ptr->op3), instruction, pc, 0 ); | |
111 | } | |
112 | ||
113 | ||
114 | return 4; | |
115 | } | |
116 | \f | |
117 | ||
118 | /* | |
119 | * Decode an Operand of an Instruction | |
120 | * | |
121 | * Functional Description | |
122 | * | |
123 | * This module formats and writes an operand of an instruction to buf | |
124 | * based on the operand specification. When the first flag is set this | |
125 | * is the first operand of an instruction. Undefined operand types | |
126 | * cause a <dis error> message. | |
127 | * | |
128 | * Parameters | |
129 | * char *buf buffer where the operand may be printed | |
130 | * OPSPEC *opptr Pointer to an operand specification | |
131 | * UINT inst Instruction from which operand is extracted | |
132 | * UINT pc PC of instruction; used for pc-relative disp. | |
133 | * int first Flag which if nonzero indicates the first | |
134 | * operand of an instruction | |
135 | * | |
136 | * Output | |
137 | * | |
138 | * The operand specified is extracted from the instruction and is | |
139 | * written to buf in the format specified. The operand is preceded | |
140 | * by a comma if it is not the first operand of an instruction and it | |
141 | * is not a register indirect form. Registers are preceded by 'r' and | |
142 | * hex values by '0x'. | |
143 | * | |
144 | * Revision History | |
145 | * | |
146 | * Revision 1.0 11/08/85 Creation date | |
147 | */ | |
148 | ||
149 | sprintop( buf, opptr, inst, pc, first ) | |
150 | ||
151 | char *buf; | |
152 | OPSPEC *opptr; | |
153 | UINT inst; | |
154 | int pc; | |
155 | int first; | |
156 | ||
157 | { int extracted_field; | |
158 | char *cond_mask_sym; | |
159 | char cond_mask_sym_buf[6]; | |
160 | ||
161 | if (opptr->width == 0) | |
162 | return; | |
163 | ||
164 | switch(opptr->type) { | |
165 | case CRREG: | |
166 | if (!first) | |
167 | *buf++= ','; | |
168 | sprintf( buf, "cr%d", UEXT(inst,opptr->offset,opptr->width)); | |
169 | break; | |
170 | ||
171 | case FCRREG: | |
172 | if (!first) | |
173 | *buf++= ','; | |
174 | sprintf( buf, "fcr%d", UEXT(inst,opptr->offset,opptr->width)); | |
175 | break; | |
176 | ||
177 | case REGSC: | |
178 | sprintf( buf, "[r%d]", UEXT(inst,opptr->offset,opptr->width)); | |
179 | break; | |
180 | ||
181 | case REG: | |
182 | if (!first) | |
183 | *buf++= ','; | |
184 | sprintf( buf, "r%d", UEXT(inst,opptr->offset,opptr->width)); | |
185 | break; | |
186 | ||
187 | case HEX: | |
188 | if (!first) | |
189 | *buf++= ','; | |
190 | extracted_field= UEXT(inst, opptr->offset, opptr->width); | |
191 | if (extracted_field == 0) { | |
192 | sprintf( buf, "0" ); | |
193 | } else { | |
194 | sprintf( buf, "0x%02x", extracted_field ); | |
195 | } | |
196 | break; | |
197 | ||
198 | case CONDMASK: | |
199 | if (!first) | |
200 | *buf++= ','; | |
201 | extracted_field= UEXT(inst, opptr->offset, opptr->width); | |
202 | switch (extracted_field & 0x0f) { | |
203 | case 0x1: cond_mask_sym= "gt0"; | |
204 | break; | |
205 | case 0x2: cond_mask_sym= "eq0"; | |
206 | break; | |
207 | case 0x3: cond_mask_sym= "ge0"; | |
208 | break; | |
209 | case 0xc: cond_mask_sym= "lt0"; | |
210 | break; | |
211 | case 0xd: cond_mask_sym= "ne0"; | |
212 | break; | |
213 | case 0xe: cond_mask_sym= "le0"; | |
214 | break; | |
215 | default: cond_mask_sym= cond_mask_sym_buf; | |
216 | sprintf( cond_mask_sym_buf, | |
217 | "%x", | |
218 | extracted_field ); | |
219 | break; | |
220 | } | |
221 | strcpy( buf, cond_mask_sym ); | |
222 | break; | |
223 | ||
224 | case PCREL: | |
225 | if (!first) | |
226 | *buf++= ','; | |
227 | sprint_address( pc + 4*(SEXT(inst,opptr->offset,opptr->width)), | |
228 | buf ); | |
229 | break; | |
230 | ||
231 | case CONT: | |
232 | sprintf( buf, | |
233 | "%d,r%d", | |
234 | UEXT(inst,opptr->offset,5), | |
235 | UEXT(inst,(opptr->offset)+5,5) ); | |
236 | break; | |
237 | ||
238 | case BF: | |
239 | if (!first) | |
240 | *buf++= ','; | |
241 | sprintf( buf, | |
242 | "%d<%d>", | |
243 | UEXT(inst,(opptr->offset)+5,5), | |
244 | UEXT(inst,opptr->offset,5)); | |
245 | break; | |
246 | ||
247 | default: | |
248 | sprintf( buf, "<dis error: %08x>", inst ); | |
249 | } | |
250 | ||
251 | } | |
252 | ||
253 | /* | |
254 | * Initialize the Disassembler Instruction Table | |
255 | * | |
256 | * Initialize the hash table and instruction table for the disassembler. | |
257 | * This should be called once before the first call to disasm(). | |
258 | * | |
259 | * Parameters | |
260 | * | |
261 | * Output | |
262 | * | |
263 | * If the debug option is selected, certain statistics about the hashing | |
264 | * distribution are written to stdout. | |
265 | * | |
266 | * Revision History | |
267 | * | |
268 | * Revision 1.0 11/08/85 Creation date | |
269 | */ | |
270 | ||
271 | init_disasm() | |
272 | { | |
273 | int i,size; | |
274 | ||
275 | for (i=0 ; i < HASHVAL ; i++) | |
276 | hashtable[i] = NULL; | |
277 | ||
278 | for (i=0, size = sizeof(instructions) / sizeof(INSTAB) ; i < size ; | |
279 | install(&instructions[i++])); | |
280 | ||
281 | } | |
282 | ||
283 | /* | |
284 | * Insert an instruction into the disassembler table by hashing the | |
285 | * opcode and inserting it into the linked list for that hash value. | |
286 | * | |
287 | * Parameters | |
288 | * | |
289 | * INSTAB *instptr Pointer to the entry in the instruction table | |
290 | * to be installed | |
291 | * | |
292 | * Revision 1.0 11/08/85 Creation date | |
293 | * 05/11/89 R. TRAWICK ADAPTED FROM MOTOROLA | |
294 | */ | |
295 | ||
296 | install(instptr) | |
297 | INSTAB *instptr; | |
298 | { | |
299 | UINT i; | |
300 | ||
301 | i = (instptr->opcode) % HASHVAL; | |
302 | instptr->next = hashtable[i]; | |
303 | hashtable[i] = instptr; | |
304 | } | |
305 | \f | |
306 | ||
307 | /* adapted from print_address in printcmd by R. Trawick 5/15/89. The two should | |
308 | be combined. | |
309 | */ | |
310 | ||
311 | void sprint_address (addr, buffer) | |
312 | ||
313 | CORE_ADDR addr; | |
314 | char *buffer; | |
315 | ||
316 | { | |
317 | register int i; | |
318 | struct symbol *fs; | |
319 | char *name; | |
320 | int name_location; | |
321 | ||
322 | sprintf ( buffer, "0x%x", addr); | |
323 | ||
324 | fs = find_pc_function (addr); | |
325 | ||
326 | if (!fs) { | |
327 | i = find_pc_misc_function (addr); | |
328 | ||
329 | if (i < 0) return; /* If nothing comes through, don't | |
330 | print anything symbolic */ | |
331 | ||
332 | name = misc_function_vector[i].name; | |
333 | name_location = misc_function_vector[i].address; | |
334 | } else { | |
335 | name = fs->name; | |
336 | name_location = BLOCK_START (SYMBOL_BLOCK_VALUE (fs)); | |
337 | } | |
338 | ||
339 | if (addr - name_location) | |
340 | sprintf (buffer, " <%s+%d>", name, addr - name_location); | |
341 | else | |
342 | sprintf (buffer, " <%s>", name); | |
343 | } |