123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514 |
- /* Instruction printing code for the DLX Microprocessor
- Copyright (C) 2002-2022 Free Software Foundation, Inc.
- Contributed by Kuang Hwa Lin. Written by Kuang Hwa Lin, 03/2002.
- This file is part of the GNU opcodes library.
- This library is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3, or (at your option)
- any later version.
- It is distributed in the hope that it will be useful, but WITHOUT
- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
- License for more details.
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
- MA 02110-1301, USA. */
- #include "sysdep.h"
- #include "disassemble.h"
- #include "opcode/dlx.h"
- #define R_ERROR 0x1
- #define R_TYPE 0x2
- #define ILD_TYPE 0x3
- #define IST_TYPE 0x4
- #define IAL_TYPE 0x5
- #define IBR_TYPE 0x6
- #define IJ_TYPE 0x7
- #define IJR_TYPE 0x8
- #define NIL 0x9
- #define OPC(x) ((x >> 26) & 0x3F)
- #define FUNC(x) (x & 0x7FF)
- unsigned char opc, rs1, rs2, rd;
- unsigned long imm26, imm16, func, current_insn_addr;
- /* Print one instruction from MEMADDR on INFO->STREAM.
- Return the size of the instruction (always 4 on dlx). */
- static unsigned char
- dlx_get_opcode (unsigned long opcode)
- {
- return (unsigned char) ((opcode >> 26) & 0x3F);
- }
- static unsigned char
- dlx_get_rs1 (unsigned long opcode)
- {
- return (unsigned char) ((opcode >> 21) & 0x1F);
- }
- static unsigned char
- dlx_get_rs2 (unsigned long opcode)
- {
- return (unsigned char) ((opcode >> 16) & 0x1F);
- }
- static unsigned char
- dlx_get_rdR (unsigned long opcode)
- {
- return (unsigned char) ((opcode >> 11) & 0x1F);
- }
- static unsigned long
- dlx_get_func (unsigned long opcode)
- {
- return (unsigned char) (opcode & 0x7FF);
- }
- static unsigned long
- dlx_get_imm16 (unsigned long opcode)
- {
- return (unsigned long) (opcode & 0xFFFF);
- }
- static unsigned long
- dlx_get_imm26 (unsigned long opcode)
- {
- return (unsigned long) (opcode & 0x03FFFFFF);
- }
- /* Fill the opcode to the max length. */
- static void
- operand_deliminator (struct disassemble_info *info, char *ptr)
- {
- int difft = 8 - (int) strlen (ptr);
- while (difft > 0)
- {
- (*info->fprintf_func) (info->stream, "%c", ' ');
- difft -= 1;
- }
- }
- /* Process the R-type opcode. */
- static unsigned char
- dlx_r_type (struct disassemble_info *info)
- {
- unsigned char r_opc[] = { OPC(ALUOP) }; /* Fix ME */
- int r_opc_num = (sizeof r_opc) / (sizeof (char));
- struct _r_opcode
- {
- unsigned long func;
- char *name;
- }
- dlx_r_opcode[] =
- {
- { NOPF, "nop" }, /* NOP */
- { ADDF, "add" }, /* Add */
- { ADDUF, "addu" }, /* Add Unsigned */
- { SUBF, "sub" }, /* SUB */
- { SUBUF, "subu" }, /* Sub Unsigned */
- { MULTF, "mult" }, /* MULTIPLY */
- { MULTUF, "multu" }, /* MULTIPLY Unsigned */
- { DIVF, "div" }, /* DIVIDE */
- { DIVUF, "divu" }, /* DIVIDE Unsigned */
- { ANDF, "and" }, /* AND */
- { ORF, "or" }, /* OR */
- { XORF, "xor" }, /* Exclusive OR */
- { SLLF, "sll" }, /* SHIFT LEFT LOGICAL */
- { SRAF, "sra" }, /* SHIFT RIGHT ARITHMETIC */
- { SRLF, "srl" }, /* SHIFT RIGHT LOGICAL */
- { SEQF, "seq" }, /* Set if equal */
- { SNEF, "sne" }, /* Set if not equal */
- { SLTF, "slt" }, /* Set if less */
- { SGTF, "sgt" }, /* Set if greater */
- { SLEF, "sle" }, /* Set if less or equal */
- { SGEF, "sge" }, /* Set if greater or equal */
- { SEQUF, "sequ" }, /* Set if equal */
- { SNEUF, "sneu" }, /* Set if not equal */
- { SLTUF, "sltu" }, /* Set if less */
- { SGTUF, "sgtu" }, /* Set if greater */
- { SLEUF, "sleu" }, /* Set if less or equal */
- { SGEUF, "sgeu" }, /* Set if greater or equal */
- { MVTSF, "mvts" }, /* Move to special register */
- { MVFSF, "mvfs" }, /* Move from special register */
- { BSWAPF, "bswap" }, /* Byte swap ?? */
- { LUTF, "lut" } /* ????????? ?? */
- };
- int dlx_r_opcode_num = (sizeof dlx_r_opcode) / (sizeof dlx_r_opcode[0]);
- int idx;
- for (idx = 0; idx < r_opc_num; idx++)
- {
- if (r_opc[idx] != opc)
- continue;
- else
- break;
- }
- if (idx == r_opc_num)
- return NIL;
- for (idx = 0 ; idx < dlx_r_opcode_num; idx++)
- if (dlx_r_opcode[idx].func == func)
- {
- (*info->fprintf_func) (info->stream, "%s", dlx_r_opcode[idx].name);
- if (func != NOPF)
- {
- /* This is not a nop. */
- operand_deliminator (info, dlx_r_opcode[idx].name);
- (*info->fprintf_func) (info->stream, "r%d,", (int)rd);
- (*info->fprintf_func) (info->stream, "r%d", (int)rs1);
- if (func != MVTSF && func != MVFSF)
- (*info->fprintf_func) (info->stream, ",r%d", (int)rs2);
- }
- return (unsigned char) R_TYPE;
- }
- return (unsigned char) R_ERROR;
- }
- /* Process the memory read opcode. */
- static unsigned char
- dlx_load_type (struct disassemble_info* info)
- {
- struct _load_opcode
- {
- unsigned long opcode;
- char *name;
- }
- dlx_load_opcode[] =
- {
- { OPC(LHIOP), "lhi" }, /* Load HI to register. */
- { OPC(LBOP), "lb" }, /* load byte sign extended. */
- { OPC(LBUOP), "lbu" }, /* load byte unsigned. */
- { OPC(LSBUOP),"ldstbu"}, /* load store byte unsigned. */
- { OPC(LHOP), "lh" }, /* load halfword sign extended. */
- { OPC(LHUOP), "lhu" }, /* load halfword unsigned. */
- { OPC(LSHUOP),"ldsthu"}, /* load store halfword unsigned. */
- { OPC(LWOP), "lw" }, /* load word. */
- { OPC(LSWOP), "ldstw" } /* load store word. */
- };
- int dlx_load_opcode_num =
- (sizeof dlx_load_opcode) / (sizeof dlx_load_opcode[0]);
- int idx;
- for (idx = 0 ; idx < dlx_load_opcode_num; idx++)
- if (dlx_load_opcode[idx].opcode == opc)
- {
- if (opc == OPC (LHIOP))
- {
- (*info->fprintf_func) (info->stream, "%s", dlx_load_opcode[idx].name);
- operand_deliminator (info, dlx_load_opcode[idx].name);
- (*info->fprintf_func) (info->stream, "r%d,", (int)rs2);
- (*info->fprintf_func) (info->stream, "0x%04x", (int)imm16);
- }
- else
- {
- (*info->fprintf_func) (info->stream, "%s", dlx_load_opcode[idx].name);
- operand_deliminator (info, dlx_load_opcode[idx].name);
- (*info->fprintf_func) (info->stream, "r%d,", (int)rs2);
- (*info->fprintf_func) (info->stream, "0x%04x[r%d]", (int)imm16, (int)rs1);
- }
- return (unsigned char) ILD_TYPE;
- }
- return (unsigned char) NIL;
- }
- /* Process the memory store opcode. */
- static unsigned char
- dlx_store_type (struct disassemble_info* info)
- {
- struct _store_opcode
- {
- unsigned long opcode;
- char *name;
- }
- dlx_store_opcode[] =
- {
- { OPC(SBOP), "sb" }, /* Store byte. */
- { OPC(SHOP), "sh" }, /* Store halfword. */
- { OPC(SWOP), "sw" }, /* Store word. */
- };
- int dlx_store_opcode_num =
- (sizeof dlx_store_opcode) / (sizeof dlx_store_opcode[0]);
- int idx;
- for (idx = 0 ; idx < dlx_store_opcode_num; idx++)
- if (dlx_store_opcode[idx].opcode == opc)
- {
- (*info->fprintf_func) (info->stream, "%s", dlx_store_opcode[idx].name);
- operand_deliminator (info, dlx_store_opcode[idx].name);
- (*info->fprintf_func) (info->stream, "0x%04x[r%d],", (int)imm16, (int)rs1);
- (*info->fprintf_func) (info->stream, "r%d", (int)rs2);
- return (unsigned char) IST_TYPE;
- }
- return (unsigned char) NIL;
- }
- /* Process the Arithmetic and Logical I-TYPE opcode. */
- static unsigned char
- dlx_aluI_type (struct disassemble_info* info)
- {
- struct _aluI_opcode
- {
- unsigned long opcode;
- char *name;
- }
- dlx_aluI_opcode[] =
- {
- { OPC(ADDIOP), "addi" }, /* Store byte. */
- { OPC(ADDUIOP), "addui" }, /* Store halfword. */
- { OPC(SUBIOP), "subi" }, /* Store word. */
- { OPC(SUBUIOP), "subui" }, /* Store word. */
- { OPC(ANDIOP), "andi" }, /* Store word. */
- { OPC(ORIOP), "ori" }, /* Store word. */
- { OPC(XORIOP), "xori" }, /* Store word. */
- { OPC(SLLIOP), "slli" }, /* Store word. */
- { OPC(SRAIOP), "srai" }, /* Store word. */
- { OPC(SRLIOP), "srli" }, /* Store word. */
- { OPC(SEQIOP), "seqi" }, /* Store word. */
- { OPC(SNEIOP), "snei" }, /* Store word. */
- { OPC(SLTIOP), "slti" }, /* Store word. */
- { OPC(SGTIOP), "sgti" }, /* Store word. */
- { OPC(SLEIOP), "slei" }, /* Store word. */
- { OPC(SGEIOP), "sgei" }, /* Store word. */
- { OPC(SEQUIOP), "sequi" }, /* Store word. */
- { OPC(SNEUIOP), "sneui" }, /* Store word. */
- { OPC(SLTUIOP), "sltui" }, /* Store word. */
- { OPC(SGTUIOP), "sgtui" }, /* Store word. */
- { OPC(SLEUIOP), "sleui" }, /* Store word. */
- { OPC(SGEUIOP), "sgeui" }, /* Store word. */
- #if 0
- { OPC(MVTSOP), "mvts" }, /* Store word. */
- { OPC(MVFSOP), "mvfs" }, /* Store word. */
- #endif
- };
- int dlx_aluI_opcode_num =
- (sizeof dlx_aluI_opcode) / (sizeof dlx_aluI_opcode[0]);
- int idx;
- for (idx = 0 ; idx < dlx_aluI_opcode_num; idx++)
- if (dlx_aluI_opcode[idx].opcode == opc)
- {
- (*info->fprintf_func) (info->stream, "%s", dlx_aluI_opcode[idx].name);
- operand_deliminator (info, dlx_aluI_opcode[idx].name);
- (*info->fprintf_func) (info->stream, "r%d,", (int)rs2);
- (*info->fprintf_func) (info->stream, "r%d,", (int)rs1);
- (*info->fprintf_func) (info->stream, "0x%04x", (int)imm16);
- return (unsigned char) IAL_TYPE;
- }
- return (unsigned char) NIL;
- }
- /* Process the branch instruction. */
- static unsigned char
- dlx_br_type (struct disassemble_info* info)
- {
- struct _br_opcode
- {
- unsigned long opcode;
- char *name;
- }
- dlx_br_opcode[] =
- {
- { OPC(BEQOP), "beqz" }, /* Store byte. */
- { OPC(BNEOP), "bnez" } /* Store halfword. */
- };
- int dlx_br_opcode_num =
- (sizeof dlx_br_opcode) / (sizeof dlx_br_opcode[0]);
- int idx;
- for (idx = 0 ; idx < dlx_br_opcode_num; idx++)
- if (dlx_br_opcode[idx].opcode == opc)
- {
- if (imm16 & 0x00008000)
- imm16 |= 0xFFFF0000;
- imm16 += (current_insn_addr + 4);
- (*info->fprintf_func) (info->stream, "%s", dlx_br_opcode[idx].name);
- operand_deliminator (info, dlx_br_opcode[idx].name);
- (*info->fprintf_func) (info->stream, "r%d,", (int) rs1);
- (*info->fprintf_func) (info->stream, "0x%08x", (int) imm16);
- return (unsigned char) IBR_TYPE;
- }
- return (unsigned char) NIL;
- }
- /* Process the jump instruction. */
- static unsigned char
- dlx_jmp_type (struct disassemble_info* info)
- {
- struct _jmp_opcode
- {
- unsigned long opcode;
- char *name;
- }
- dlx_jmp_opcode[] =
- {
- { OPC(JOP), "j" }, /* Store byte. */
- { OPC(JALOP), "jal" }, /* Store halfword. */
- { OPC(BREAKOP), "break" }, /* Store halfword. */
- { OPC(TRAPOP), "trap" }, /* Store halfword. */
- { OPC(RFEOP), "rfe" } /* Store halfword. */
- };
- int dlx_jmp_opcode_num =
- (sizeof dlx_jmp_opcode) / (sizeof dlx_jmp_opcode[0]);
- int idx;
- for (idx = 0 ; idx < dlx_jmp_opcode_num; idx++)
- if (dlx_jmp_opcode[idx].opcode == opc)
- {
- if (imm26 & 0x02000000)
- imm26 |= 0xFC000000;
- imm26 += (current_insn_addr + 4);
- (*info->fprintf_func) (info->stream, "%s", dlx_jmp_opcode[idx].name);
- operand_deliminator (info, dlx_jmp_opcode[idx].name);
- (*info->fprintf_func) (info->stream, "0x%08x", (int)imm26);
- return (unsigned char) IJ_TYPE;
- }
- return (unsigned char) NIL;
- }
- /* Process the jump register instruction. */
- static unsigned char
- dlx_jr_type (struct disassemble_info* info)
- {
- struct _jr_opcode
- {
- unsigned long opcode;
- char *name;
- }
- dlx_jr_opcode[] =
- {
- { OPC(JROP), "jr" }, /* Store byte. */
- { OPC(JALROP), "jalr" } /* Store halfword. */
- };
- int dlx_jr_opcode_num =
- (sizeof dlx_jr_opcode) / (sizeof dlx_jr_opcode[0]);
- int idx;
- for (idx = 0 ; idx < dlx_jr_opcode_num; idx++)
- if (dlx_jr_opcode[idx].opcode == opc)
- {
- (*info->fprintf_func) (info->stream, "%s", dlx_jr_opcode[idx].name);
- operand_deliminator (info, dlx_jr_opcode[idx].name);
- (*info->fprintf_func) (info->stream, "r%d", (int)rs1);
- return (unsigned char) IJR_TYPE;
- }
- return (unsigned char) NIL;
- }
- typedef unsigned char (* dlx_insn) (struct disassemble_info *);
- /* This is the main DLX insn handling routine. */
- int
- print_insn_dlx (bfd_vma memaddr, struct disassemble_info* info)
- {
- bfd_byte buffer[4];
- int insn_idx;
- unsigned long insn_word;
- dlx_insn dlx_insn_type[] =
- {
- dlx_r_type,
- dlx_load_type,
- dlx_store_type,
- dlx_aluI_type,
- dlx_br_type,
- dlx_jmp_type,
- dlx_jr_type,
- (dlx_insn) NULL
- };
- int dlx_insn_type_num = ((sizeof dlx_insn_type) / (sizeof (dlx_insn))) - 1;
- int status =
- (*info->read_memory_func) (memaddr, (bfd_byte *) &buffer[0], 4, info);
- if (status != 0)
- {
- (*info->memory_error_func) (status, memaddr, info);
- return -1;
- }
- /* Now decode the insn */
- insn_word = bfd_getb32 (buffer);
- opc = dlx_get_opcode (insn_word);
- rs1 = dlx_get_rs1 (insn_word);
- rs2 = dlx_get_rs2 (insn_word);
- rd = dlx_get_rdR (insn_word);
- func = dlx_get_func (insn_word);
- imm16= dlx_get_imm16 (insn_word);
- imm26= dlx_get_imm26 (insn_word);
- #if 0
- printf ("print_insn_big_dlx: opc = 0x%02x\n"
- " rs1 = 0x%02x\n"
- " rs2 = 0x%02x\n"
- " rd = 0x%02x\n"
- " func = 0x%08x\n"
- " imm16 = 0x%08x\n"
- " imm26 = 0x%08x\n",
- opc, rs1, rs2, rd, func, imm16, imm26);
- #endif
- /* Scan through all the insn type and print the insn out. */
- current_insn_addr = (unsigned long) memaddr;
- for (insn_idx = 0; dlx_insn_type[insn_idx] != 0x0; insn_idx++)
- switch ((dlx_insn_type[insn_idx]) (info))
- {
- /* Found the correct opcode */
- case R_TYPE:
- case ILD_TYPE:
- case IST_TYPE:
- case IAL_TYPE:
- case IBR_TYPE:
- case IJ_TYPE:
- case IJR_TYPE:
- return 4;
- /* Wrong insn type check next one. */
- default:
- case NIL:
- continue;
- /* All rest of the return code are not recongnized, treat it as error */
- /* we should never get here, I hope! */
- case R_ERROR:
- return -1;
- }
- if (insn_idx == dlx_insn_type_num)
- /* Well, does not recoganize this opcode. */
- (*info->fprintf_func) (info->stream, "<%s>", "Unrecognized Opcode");
- return 4;
- }
|