opcodes/
[deliverable/binutils-gdb.git] / opcodes / dlx-dis.c
CommitLineData
d172d4ba 1/* Instruction printing code for the DLX Microprocessor
9b201bb5 2 Copyright 2002, 2005, 2007 Free Software Foundation, Inc.
d172d4ba
NC
3 Contributed by Kuang Hwa Lin. Written by Kuang Hwa Lin, 03/2002.
4
9b201bb5
NC
5 This file is part of the GNU opcodes library.
6
7 This library is free software; you can redistribute it and/or modify
d172d4ba 8 it under the terms of the GNU General Public License as published by
9b201bb5
NC
9 the Free Software Foundation; either version 3, or (at your option)
10 any later version.
d172d4ba 11
9b201bb5
NC
12 It is distributed in the hope that it will be useful, but WITHOUT
13 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
15 License for more details.
d172d4ba
NC
16
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
47b0e7ad
NC
19 Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
20 MA 02110-1301, USA. */
d172d4ba
NC
21
22#include "sysdep.h"
23#include "dis-asm.h"
24#include "opcode/dlx.h"
25
26#define R_ERROR 0x1
27#define R_TYPE 0x2
28#define ILD_TYPE 0x3
29#define IST_TYPE 0x4
30#define IAL_TYPE 0x5
31#define IBR_TYPE 0x6
32#define IJ_TYPE 0x7
33#define IJR_TYPE 0x8
34#define NIL 0x9
35
36#define OPC(x) ((x >> 26) & 0x3F)
37#define FUNC(x) (x & 0x7FF)
38
39unsigned char opc, rs1, rs2, rd;
40unsigned long imm26, imm16, func, current_insn_addr;
41
d172d4ba
NC
42/* Print one instruction from MEMADDR on INFO->STREAM.
43 Return the size of the instruction (always 4 on dlx). */
44
45static unsigned char
47b0e7ad 46dlx_get_opcode (unsigned long opcode)
d172d4ba
NC
47{
48 return (unsigned char) ((opcode >> 26) & 0x3F);
49}
50
51static unsigned char
47b0e7ad 52dlx_get_rs1 (unsigned long opcode)
d172d4ba
NC
53{
54 return (unsigned char) ((opcode >> 21) & 0x1F);
55}
56
57static unsigned char
47b0e7ad 58dlx_get_rs2 (unsigned long opcode)
d172d4ba
NC
59{
60 return (unsigned char) ((opcode >> 16) & 0x1F);
61}
62
63static unsigned char
47b0e7ad 64dlx_get_rdR (unsigned long opcode)
d172d4ba
NC
65{
66 return (unsigned char) ((opcode >> 11) & 0x1F);
67}
68
69static unsigned long
47b0e7ad 70dlx_get_func (unsigned long opcode)
d172d4ba
NC
71{
72 return (unsigned char) (opcode & 0x7FF);
73}
74
75static unsigned long
47b0e7ad 76dlx_get_imm16 (unsigned long opcode)
d172d4ba
NC
77{
78 return (unsigned long) (opcode & 0xFFFF);
79}
80
81static unsigned long
47b0e7ad 82dlx_get_imm26 (unsigned long opcode)
d172d4ba
NC
83{
84 return (unsigned long) (opcode & 0x03FFFFFF);
85}
86
87/* Fill the opcode to the max length. */
47b0e7ad 88
d172d4ba 89static void
47b0e7ad 90operand_deliminator (struct disassemble_info *info, char *ptr)
d172d4ba
NC
91{
92 int difft = 8 - (int) strlen (ptr);
93
94 while (difft > 0)
95 {
96 (*info->fprintf_func) (info->stream, "%c", ' ');
97 difft -= 1;
98 }
99}
100
101/* Process the R-type opcode. */
47b0e7ad 102
d172d4ba 103static unsigned char
47b0e7ad 104dlx_r_type (struct disassemble_info *info)
d172d4ba
NC
105{
106 unsigned char r_opc[] = { OPC(ALUOP) }; /* Fix ME */
107 int r_opc_num = (sizeof r_opc) / (sizeof (char));
108 struct _r_opcode
109 {
110 unsigned long func;
111 char *name;
112 }
113 dlx_r_opcode[] =
47b0e7ad 114 {
d172d4ba
NC
115 { NOPF, "nop" }, /* NOP */
116 { ADDF, "add" }, /* Add */
117 { ADDUF, "addu" }, /* Add Unsigned */
118 { SUBF, "sub" }, /* SUB */
119 { SUBUF, "subu" }, /* Sub Unsigned */
120 { MULTF, "mult" }, /* MULTIPLY */
121 { MULTUF, "multu" }, /* MULTIPLY Unsigned */
122 { DIVF, "div" }, /* DIVIDE */
123 { DIVUF, "divu" }, /* DIVIDE Unsigned */
124 { ANDF, "and" }, /* AND */
125 { ORF, "or" }, /* OR */
126 { XORF, "xor" }, /* Exclusive OR */
127 { SLLF, "sll" }, /* SHIFT LEFT LOGICAL */
128 { SRAF, "sra" }, /* SHIFT RIGHT ARITHMETIC */
129 { SRLF, "srl" }, /* SHIFT RIGHT LOGICAL */
130 { SEQF, "seq" }, /* Set if equal */
131 { SNEF, "sne" }, /* Set if not equal */
132 { SLTF, "slt" }, /* Set if less */
133 { SGTF, "sgt" }, /* Set if greater */
134 { SLEF, "sle" }, /* Set if less or equal */
135 { SGEF, "sge" }, /* Set if greater or equal */
136 { SEQUF, "sequ" }, /* Set if equal */
137 { SNEUF, "sneu" }, /* Set if not equal */
138 { SLTUF, "sltu" }, /* Set if less */
139 { SGTUF, "sgtu" }, /* Set if greater */
140 { SLEUF, "sleu" }, /* Set if less or equal */
141 { SGEUF, "sgeu" }, /* Set if greater or equal */
142 { MVTSF, "mvts" }, /* Move to special register */
143 { MVFSF, "mvfs" }, /* Move from special register */
144 { BSWAPF, "bswap" }, /* Byte swap ?? */
145 { LUTF, "lut" } /* ????????? ?? */
146 };
147 int dlx_r_opcode_num = (sizeof dlx_r_opcode) / (sizeof dlx_r_opcode[0]);
148 int idx;
149
150 for (idx = 0; idx < r_opc_num; idx++)
151 {
152 if (r_opc[idx] != opc)
153 continue;
154 else
155 break;
47b0e7ad 156 }
d172d4ba
NC
157
158 if (idx == r_opc_num)
159 return NIL;
160
161 for (idx = 0 ; idx < dlx_r_opcode_num; idx++)
162 if (dlx_r_opcode[idx].func == func)
163 {
164 (*info->fprintf_func) (info->stream, "%s", dlx_r_opcode[idx].name);
165
166 if (func != NOPF)
167 {
168 /* This is not a nop. */
169 operand_deliminator (info, dlx_r_opcode[idx].name);
170 (*info->fprintf_func) (info->stream, "r%d,", (int)rd);
171 (*info->fprintf_func) (info->stream, "r%d", (int)rs1);
172 if (func != MVTSF && func != MVFSF)
173 (*info->fprintf_func) (info->stream, ",r%d", (int)rs2);
174 }
175 return (unsigned char) R_TYPE;
176 }
177
178 return (unsigned char) R_ERROR;
179}
180
181/* Process the memory read opcode. */
182
183static unsigned char
47b0e7ad 184dlx_load_type (struct disassemble_info* info)
d172d4ba
NC
185{
186 struct _load_opcode
187 {
188 unsigned long opcode;
189 char *name;
190 }
191 dlx_load_opcode[] =
47b0e7ad
NC
192 {
193 { OPC(LHIOP), "lhi" }, /* Load HI to register. */
194 { OPC(LBOP), "lb" }, /* load byte sign extended. */
195 { OPC(LBUOP), "lbu" }, /* load byte unsigned. */
196 { OPC(LSBUOP),"ldstbu"}, /* load store byte unsigned. */
197 { OPC(LHOP), "lh" }, /* load halfword sign extended. */
198 { OPC(LHUOP), "lhu" }, /* load halfword unsigned. */
199 { OPC(LSHUOP),"ldsthu"}, /* load store halfword unsigned. */
200 { OPC(LWOP), "lw" }, /* load word. */
201 { OPC(LSWOP), "ldstw" } /* load store word. */
202 };
d172d4ba
NC
203 int dlx_load_opcode_num =
204 (sizeof dlx_load_opcode) / (sizeof dlx_load_opcode[0]);
205 int idx;
206
207 for (idx = 0 ; idx < dlx_load_opcode_num; idx++)
208 if (dlx_load_opcode[idx].opcode == opc)
209 {
210 if (opc == OPC (LHIOP))
211 {
212 (*info->fprintf_func) (info->stream, "%s", dlx_load_opcode[idx].name);
213 operand_deliminator (info, dlx_load_opcode[idx].name);
214 (*info->fprintf_func) (info->stream, "r%d,", (int)rs2);
215 (*info->fprintf_func) (info->stream, "0x%04x", (int)imm16);
216 }
217 else
218 {
219 (*info->fprintf_func) (info->stream, "%s", dlx_load_opcode[idx].name);
220 operand_deliminator (info, dlx_load_opcode[idx].name);
221 (*info->fprintf_func) (info->stream, "r%d,", (int)rs2);
222 (*info->fprintf_func) (info->stream, "0x%04x[r%d]", (int)imm16, (int)rs1);
223 }
224
225 return (unsigned char) ILD_TYPE;
226 }
227
228 return (unsigned char) NIL;
229}
230
231/* Process the memory store opcode. */
232
233static unsigned char
47b0e7ad 234dlx_store_type (struct disassemble_info* info)
d172d4ba
NC
235{
236 struct _store_opcode
237 {
238 unsigned long opcode;
239 char *name;
240 }
241 dlx_store_opcode[] =
47b0e7ad
NC
242 {
243 { OPC(SBOP), "sb" }, /* Store byte. */
244 { OPC(SHOP), "sh" }, /* Store halfword. */
245 { OPC(SWOP), "sw" }, /* Store word. */
246 };
d172d4ba
NC
247 int dlx_store_opcode_num =
248 (sizeof dlx_store_opcode) / (sizeof dlx_store_opcode[0]);
249 int idx;
250
251 for (idx = 0 ; idx < dlx_store_opcode_num; idx++)
252 if (dlx_store_opcode[idx].opcode == opc)
253 {
254 (*info->fprintf_func) (info->stream, "%s", dlx_store_opcode[idx].name);
255 operand_deliminator (info, dlx_store_opcode[idx].name);
256 (*info->fprintf_func) (info->stream, "0x%04x[r%d],", (int)imm16, (int)rs1);
257 (*info->fprintf_func) (info->stream, "r%d", (int)rs2);
258 return (unsigned char) IST_TYPE;
259 }
260
261 return (unsigned char) NIL;
262}
263
264/* Process the Arithmetic and Logical I-TYPE opcode. */
265
266static unsigned char
47b0e7ad 267dlx_aluI_type (struct disassemble_info* info)
d172d4ba
NC
268{
269 struct _aluI_opcode
270 {
271 unsigned long opcode;
272 char *name;
273 }
274 dlx_aluI_opcode[] =
47b0e7ad
NC
275 {
276 { OPC(ADDIOP), "addi" }, /* Store byte. */
277 { OPC(ADDUIOP), "addui" }, /* Store halfword. */
278 { OPC(SUBIOP), "subi" }, /* Store word. */
279 { OPC(SUBUIOP), "subui" }, /* Store word. */
280 { OPC(ANDIOP), "andi" }, /* Store word. */
281 { OPC(ORIOP), "ori" }, /* Store word. */
282 { OPC(XORIOP), "xori" }, /* Store word. */
283 { OPC(SLLIOP), "slli" }, /* Store word. */
284 { OPC(SRAIOP), "srai" }, /* Store word. */
285 { OPC(SRLIOP), "srli" }, /* Store word. */
286 { OPC(SEQIOP), "seqi" }, /* Store word. */
287 { OPC(SNEIOP), "snei" }, /* Store word. */
288 { OPC(SLTIOP), "slti" }, /* Store word. */
289 { OPC(SGTIOP), "sgti" }, /* Store word. */
290 { OPC(SLEIOP), "slei" }, /* Store word. */
291 { OPC(SGEIOP), "sgei" }, /* Store word. */
292 { OPC(SEQUIOP), "sequi" }, /* Store word. */
293 { OPC(SNEUIOP), "sneui" }, /* Store word. */
294 { OPC(SLTUIOP), "sltui" }, /* Store word. */
295 { OPC(SGTUIOP), "sgtui" }, /* Store word. */
296 { OPC(SLEUIOP), "sleui" }, /* Store word. */
297 { OPC(SGEUIOP), "sgeui" }, /* Store word. */
d172d4ba 298#if 0
47b0e7ad
NC
299 { OPC(MVTSOP), "mvts" }, /* Store word. */
300 { OPC(MVFSOP), "mvfs" }, /* Store word. */
d172d4ba 301#endif
47b0e7ad 302 };
d172d4ba
NC
303 int dlx_aluI_opcode_num =
304 (sizeof dlx_aluI_opcode) / (sizeof dlx_aluI_opcode[0]);
305 int idx;
306
307 for (idx = 0 ; idx < dlx_aluI_opcode_num; idx++)
308 if (dlx_aluI_opcode[idx].opcode == opc)
309 {
310 (*info->fprintf_func) (info->stream, "%s", dlx_aluI_opcode[idx].name);
311 operand_deliminator (info, dlx_aluI_opcode[idx].name);
312 (*info->fprintf_func) (info->stream, "r%d,", (int)rs2);
313 (*info->fprintf_func) (info->stream, "r%d,", (int)rs1);
314 (*info->fprintf_func) (info->stream, "0x%04x", (int)imm16);
315
316 return (unsigned char) IAL_TYPE;
317 }
318
319 return (unsigned char) NIL;
320}
321
322/* Process the branch instruction. */
323
324static unsigned char
47b0e7ad 325dlx_br_type (struct disassemble_info* info)
d172d4ba
NC
326{
327 struct _br_opcode
328 {
329 unsigned long opcode;
330 char *name;
331 }
332 dlx_br_opcode[] =
47b0e7ad
NC
333 {
334 { OPC(BEQOP), "beqz" }, /* Store byte. */
335 { OPC(BNEOP), "bnez" } /* Store halfword. */
336 };
d172d4ba
NC
337 int dlx_br_opcode_num =
338 (sizeof dlx_br_opcode) / (sizeof dlx_br_opcode[0]);
339 int idx;
340
341 for (idx = 0 ; idx < dlx_br_opcode_num; idx++)
342 if (dlx_br_opcode[idx].opcode == opc)
343 {
344 if (imm16 & 0x00008000)
345 imm16 |= 0xFFFF0000;
346
347 imm16 += (current_insn_addr + 4);
348 (*info->fprintf_func) (info->stream, "%s", dlx_br_opcode[idx].name);
349 operand_deliminator (info, dlx_br_opcode[idx].name);
47b0e7ad
NC
350 (*info->fprintf_func) (info->stream, "r%d,", (int) rs1);
351 (*info->fprintf_func) (info->stream, "0x%08x", (int) imm16);
d172d4ba
NC
352
353 return (unsigned char) IBR_TYPE;
354 }
355
356 return (unsigned char) NIL;
357}
358
359/* Process the jump instruction. */
360
361static unsigned char
47b0e7ad 362dlx_jmp_type (struct disassemble_info* info)
d172d4ba
NC
363{
364 struct _jmp_opcode
365 {
366 unsigned long opcode;
367 char *name;
368 }
369 dlx_jmp_opcode[] =
47b0e7ad
NC
370 {
371 { OPC(JOP), "j" }, /* Store byte. */
372 { OPC(JALOP), "jal" }, /* Store halfword. */
373 { OPC(BREAKOP), "break" }, /* Store halfword. */
374 { OPC(TRAPOP), "trap" }, /* Store halfword. */
375 { OPC(RFEOP), "rfe" } /* Store halfword. */
376 };
d172d4ba
NC
377 int dlx_jmp_opcode_num =
378 (sizeof dlx_jmp_opcode) / (sizeof dlx_jmp_opcode[0]);
379 int idx;
380
381 for (idx = 0 ; idx < dlx_jmp_opcode_num; idx++)
382 if (dlx_jmp_opcode[idx].opcode == opc)
383 {
384 if (imm26 & 0x02000000)
385 imm26 |= 0xFC000000;
386
387 imm26 += (current_insn_addr + 4);
388
389 (*info->fprintf_func) (info->stream, "%s", dlx_jmp_opcode[idx].name);
390 operand_deliminator (info, dlx_jmp_opcode[idx].name);
391 (*info->fprintf_func) (info->stream, "0x%08x", (int)imm26);
392
393 return (unsigned char) IJ_TYPE;
394 }
395
396 return (unsigned char) NIL;
397}
398
399/* Process the jump register instruction. */
400
401static unsigned char
47b0e7ad 402dlx_jr_type (struct disassemble_info* info)
d172d4ba
NC
403{
404 struct _jr_opcode
405 {
406 unsigned long opcode;
407 char *name;
408 }
47b0e7ad
NC
409 dlx_jr_opcode[] =
410 {
d172d4ba
NC
411 { OPC(JROP), "jr" }, /* Store byte. */
412 { OPC(JALROP), "jalr" } /* Store halfword. */
413 };
414 int dlx_jr_opcode_num =
415 (sizeof dlx_jr_opcode) / (sizeof dlx_jr_opcode[0]);
416 int idx;
417
418 for (idx = 0 ; idx < dlx_jr_opcode_num; idx++)
419 if (dlx_jr_opcode[idx].opcode == opc)
420 {
421 (*info->fprintf_func) (info->stream, "%s", dlx_jr_opcode[idx].name);
422 operand_deliminator (info, dlx_jr_opcode[idx].name);
423 (*info->fprintf_func) (info->stream, "r%d", (int)rs1);
424 return (unsigned char) IJR_TYPE;
425 }
426
427 return (unsigned char) NIL;
428}
429
47b0e7ad 430typedef unsigned char (* dlx_insn) (struct disassemble_info *);
d172d4ba
NC
431
432/* This is the main DLX insn handling routine. */
433
434int
47b0e7ad 435print_insn_dlx (bfd_vma memaddr, struct disassemble_info* info)
d172d4ba
NC
436{
437 bfd_byte buffer[4];
438 int insn_idx;
439 unsigned long insn_word;
440 unsigned char rtn_code;
441 unsigned long dlx_insn_type[] =
47b0e7ad
NC
442 {
443 (unsigned long) dlx_r_type,
444 (unsigned long) dlx_load_type,
445 (unsigned long) dlx_store_type,
446 (unsigned long) dlx_aluI_type,
447 (unsigned long) dlx_br_type,
448 (unsigned long) dlx_jmp_type,
449 (unsigned long) dlx_jr_type,
450 (unsigned long) NULL
d172d4ba
NC
451 };
452 int dlx_insn_type_num = ((sizeof dlx_insn_type) / (sizeof (unsigned long))) - 1;
453 int status =
454 (*info->read_memory_func) (memaddr, (bfd_byte *) &buffer[0], 4, info);
455
456 if (status != 0)
457 {
458 (*info->memory_error_func) (status, memaddr, info);
459 return -1;
460 }
461
462 /* Now decode the insn */
463 insn_word = bfd_getb32 (buffer);
464 opc = dlx_get_opcode (insn_word);
465 rs1 = dlx_get_rs1 (insn_word);
466 rs2 = dlx_get_rs2 (insn_word);
467 rd = dlx_get_rdR (insn_word);
468 func = dlx_get_func (insn_word);
469 imm16= dlx_get_imm16 (insn_word);
470 imm26= dlx_get_imm26 (insn_word);
471
472#if 0
473 printf ("print_insn_big_dlx: opc = 0x%02x\n"
474 " rs1 = 0x%02x\n"
475 " rs2 = 0x%02x\n"
476 " rd = 0x%02x\n"
477 " func = 0x%08x\n"
478 " imm16 = 0x%08x\n"
479 " imm26 = 0x%08x\n",
480 opc, rs1, rs2, rd, func, imm16, imm26);
481#endif
482
483 /* Scan through all the insn type and print the insn out. */
484 rtn_code = 0;
485 current_insn_addr = (unsigned long) memaddr;
486
487 for (insn_idx = 0; dlx_insn_type[insn_idx] != 0x0; insn_idx++)
488 switch (((dlx_insn) (dlx_insn_type[insn_idx])) (info))
489 {
490 /* Found the correct opcode */
491 case R_TYPE:
492 case ILD_TYPE:
493 case IST_TYPE:
494 case IAL_TYPE:
495 case IBR_TYPE:
496 case IJ_TYPE:
497 case IJR_TYPE:
498 return 4;
499
500 /* Wrong insn type check next one. */
501 default:
502 case NIL:
503 continue;
504
505 /* All rest of the return code are not recongnized, treat it as error */
506 /* we should never get here, I hope! */
507 case R_ERROR:
508 return -1;
509 }
510
511 if (insn_idx == dlx_insn_type_num)
512 /* Well, does not recoganize this opcode. */
513 (*info->fprintf_func) (info->stream, "<%s>", "Unrecognized Opcode");
514
515 return 4;
516}
This page took 0.31688 seconds and 4 git commands to generate.