fix typo in configure --help
[qemu.git] / microblaze-dis.c
blob6144334e6c3a2c72bfc746ad2edcb2691c961276
1 /* Disassemble Xilinx microblaze instructions.
2 Copyright (C) 1993, 1999, 2000 Free Software Foundation, Inc.
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, see <http://www.gnu.org/licenses/>. */
18 * Copyright (c) 2001 Xilinx, Inc. All rights reserved.
20 * Redistribution and use in source and binary forms are permitted
21 * provided that the above copyright notice and this paragraph are
22 * duplicated in all such forms and that any documentation,
23 * advertising materials, and other materials related to such
24 * distribution and use acknowledge that the software was developed
25 * by Xilinx, Inc. The name of the Company may not be used to endorse
26 * or promote products derived from this software without specific prior
27 * written permission.
28 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
29 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
30 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
32 * Xilinx, Inc.
36 #include <stdio.h>
37 #define STATIC_TABLE
38 #define DEFINE_TABLE
40 #ifndef MICROBLAZE_OPC
41 #define MICROBLAZE_OPC
42 /* Assembler instructions for Xilinx's microblaze processor
43 Copyright (C) 1999, 2000 Free Software Foundation, Inc.
46 This program is free software; you can redistribute it and/or modify
47 it under the terms of the GNU General Public License as published by
48 the Free Software Foundation; either version 2 of the License, or
49 (at your option) any later version.
51 This program is distributed in the hope that it will be useful,
52 but WITHOUT ANY WARRANTY; without even the implied warranty of
53 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
54 GNU General Public License for more details.
56 You should have received a copy of the GNU General Public License
57 along with this program; if not, see <http://www.gnu.org/licenses/>. */
60 * Copyright (c) 2001 Xilinx, Inc. All rights reserved.
62 * Redistribution and use in source and binary forms are permitted
63 * provided that the above copyright notice and this paragraph are
64 * duplicated in all such forms and that any documentation,
65 * advertising materials, and other materials related to such
66 * distribution and use acknowledge that the software was developed
67 * by Xilinx, Inc. The name of the Company may not be used to endorse
68 * or promote products derived from this software without specific prior
69 * written permission.
70 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
71 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
72 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
74 * Xilinx, Inc.
78 #ifndef MICROBLAZE_OPCM
79 #define MICROBLAZE_OPCM
82 * Copyright (c) 2001 Xilinx, Inc. All rights reserved.
84 * Redistribution and use in source and binary forms are permitted
85 * provided that the above copyright notice and this paragraph are
86 * duplicated in all such forms and that any documentation,
87 * advertising materials, and other materials related to such
88 * distribution and use acknowledge that the software was developed
89 * by Xilinx, Inc. The name of the Company may not be used to endorse
90 * or promote products derived from this software without specific prior
91 * written permission.
92 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
93 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
94 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
96 * Xilinx, Inc.
97 * $Header:
100 enum microblaze_instr {
101 add, rsub, addc, rsubc, addk, rsubk, addkc, rsubkc, cmp, cmpu,
102 addi, rsubi, addic, rsubic, addik, rsubik, addikc, rsubikc, mul,
103 idiv, idivu, bsll, bsra, bsrl, get, put, nget, nput, cget, cput,
104 ncget, ncput, muli, bslli, bsrai, bsrli, mului, or, and, xor,
105 andn, pcmpbf, pcmpbc, pcmpeq, pcmpne, sra, src, srl, sext8, sext16, wic, wdc, mts, mfs, br, brd,
106 brld, bra, brad, brald, microblaze_brk, beq, beqd, bne, bned, blt,
107 bltd, ble, bled, bgt, bgtd, bge, bged, ori, andi, xori, andni,
108 imm, rtsd, rtid, rtbd, rted, bri, brid, brlid, brai, braid, bralid,
109 brki, beqi, beqid, bnei, bneid, blti, bltid, blei, bleid, bgti,
110 bgtid, bgei, bgeid, lbu, lhu, lw, sb, sh, sw, lbui, lhui, lwi,
111 sbi, shi, swi, msrset, msrclr, tuqula, fadd, frsub, fmul, fdiv,
112 fcmp_lt, fcmp_eq, fcmp_le, fcmp_gt, fcmp_ne, fcmp_ge, fcmp_un, invalid_inst } ;
114 enum microblaze_instr_type {
115 arithmetic_inst, logical_inst, mult_inst, div_inst, branch_inst,
116 return_inst, immediate_inst, special_inst, memory_load_inst,
117 memory_store_inst, barrel_shift_inst, anyware_inst };
119 #define INST_WORD_SIZE 4
121 /* gen purpose regs go from 0 to 31 */
122 /* mask is reg num - max_reg_num, ie reg_num - 32 in this case */
124 #define REG_PC_MASK 0x8000
125 #define REG_MSR_MASK 0x8001
126 #define REG_EAR_MASK 0x8003
127 #define REG_ESR_MASK 0x8005
128 #define REG_FSR_MASK 0x8007
130 #define MIN_REGNUM 0
131 #define MAX_REGNUM 31
133 #define REG_PC 32 /* PC */
134 #define REG_MSR 33 /* machine status reg */
135 #define REG_EAR 35 /* Exception reg */
136 #define REG_ESR 37 /* Exception reg */
137 #define REG_FSR 39 /* FPU Status reg */
139 /* alternate names for gen purpose regs */
140 #define REG_SP 1 /* stack pointer */
141 #define REG_ROSDP 2 /* read-only small data pointer */
142 #define REG_RWSDP 13 /* read-write small data pointer */
144 /* Assembler Register - Used in Delay Slot Optimization */
145 #define REG_AS 18
146 #define REG_ZERO 0
148 #define RD_LOW 21 /* low bit for RD */
149 #define RA_LOW 16 /* low bit for RA */
150 #define RB_LOW 11 /* low bit for RB */
151 #define IMM_LOW 0 /* low bit for immediate */
153 #define RD_MASK 0x03E00000
154 #define RA_MASK 0x001F0000
155 #define RB_MASK 0x0000F800
156 #define IMM_MASK 0x0000FFFF
158 // imm mask for barrel shifts
159 #define IMM5_MASK 0x0000001F
162 // imm mask for get, put instructions
163 #define IMM12_MASK 0x00000FFF
165 // imm mask for msrset, msrclr instructions
166 #define IMM14_MASK 0x00003FFF
168 #endif /* MICROBLAZE-OPCM */
170 #define INST_TYPE_RD_R1_R2 0
171 #define INST_TYPE_RD_R1_IMM 1
172 #define INST_TYPE_RD_R1_UNSIGNED_IMM 2
173 #define INST_TYPE_RD_R1 3
174 #define INST_TYPE_RD_R2 4
175 #define INST_TYPE_RD_IMM 5
176 #define INST_TYPE_R2 6
177 #define INST_TYPE_R1_R2 7
178 #define INST_TYPE_R1_IMM 8
179 #define INST_TYPE_IMM 9
180 #define INST_TYPE_SPECIAL_R1 10
181 #define INST_TYPE_RD_SPECIAL 11
182 #define INST_TYPE_R1 12
183 // new instn type for barrel shift imms
184 #define INST_TYPE_RD_R1_IMM5 13
185 #define INST_TYPE_RD_IMM12 14
186 #define INST_TYPE_R1_IMM12 15
188 // new insn type for insn cache
189 #define INST_TYPE_RD_R1_SPECIAL 16
191 // new insn type for msrclr, msrset insns.
192 #define INST_TYPE_RD_IMM14 17
194 // new insn type for tuqula rd - addik rd, r0, 42
195 #define INST_TYPE_RD 18
197 #define INST_TYPE_NONE 25
201 #define INST_PC_OFFSET 1 /* instructions where the label address is resolved as a PC offset (for branch label)*/
202 #define INST_NO_OFFSET 0 /* instructions where the label address is resolved as an absolute value (for data mem or abs address)*/
204 #define IMMVAL_MASK_NON_SPECIAL 0x0000
205 #define IMMVAL_MASK_MTS 0x4000
206 #define IMMVAL_MASK_MFS 0x0000
208 #define OPCODE_MASK_H 0xFC000000 /* High 6 bits only */
209 #define OPCODE_MASK_H1 0xFFE00000 /* High 11 bits */
210 #define OPCODE_MASK_H2 0xFC1F0000 /* High 6 and bits 20-16 */
211 #define OPCODE_MASK_H12 0xFFFF0000 /* High 16 */
212 #define OPCODE_MASK_H4 0xFC0007FF /* High 6 and low 11 bits */
213 #define OPCODE_MASK_H13S 0xFFE0FFF0 /* High 11 and 15:1 bits and last nibble of last byte for spr */
214 #define OPCODE_MASK_H23S 0xFC1FFFF0 /* High 6, 20-16 and 15:1 bits and last nibble of last byte for spr */
215 #define OPCODE_MASK_H34 0xFC00FFFF /* High 6 and low 16 bits */
216 #define OPCODE_MASK_H14 0xFFE007FF /* High 11 and low 11 bits */
217 #define OPCODE_MASK_H24 0xFC1F07FF /* High 6, bits 20-16 and low 11 bits */
218 #define OPCODE_MASK_H124 0xFFFF07FF /* High 16, and low 11 bits */
219 #define OPCODE_MASK_H1234 0xFFFFFFFF /* All 32 bits */
220 #define OPCODE_MASK_H3 0xFC000600 /* High 6 bits and bits 21, 22 */
221 #define OPCODE_MASK_H32 0xFC00F000 /* High 6 bits and bit 16, 17, 18 and 19*/
222 #define OPCODE_MASK_H34B 0xFC0000FF /* High 6 bits and low 8 bits */
224 // New Mask for msrset, msrclr insns.
225 #define OPCODE_MASK_H23N 0xFC1FC000 /* High 6 and bits 12 - 18 */
227 #define DELAY_SLOT 1
228 #define NO_DELAY_SLOT 0
230 #define MAX_OPCODES 149
232 struct op_code_struct {
233 const char *name;
234 short inst_type; /* registers and immediate values involved */
235 short inst_offset_type; /* immediate vals offset from PC? (= 1 for branches) */
236 short delay_slots; /* info about delay slots needed after this instr. */
237 short immval_mask;
238 unsigned long bit_sequence; /* all the fixed bits for the op are set and all the variable bits (reg names, imm vals) are set to 0 */
239 unsigned long opcode_mask; /* which bits define the opcode */
240 enum microblaze_instr instr;
241 enum microblaze_instr_type instr_type;
242 /* more info about output format here */
243 } opcodes[MAX_OPCODES] =
246 {"add", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x00000000, OPCODE_MASK_H4, add, arithmetic_inst },
247 {"rsub", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x04000000, OPCODE_MASK_H4, rsub, arithmetic_inst },
248 {"addc", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x08000000, OPCODE_MASK_H4, addc, arithmetic_inst },
249 {"rsubc", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x0C000000, OPCODE_MASK_H4, rsubc, arithmetic_inst },
250 {"addk", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x10000000, OPCODE_MASK_H4, addk, arithmetic_inst },
251 {"rsubk", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x14000000, OPCODE_MASK_H4, rsubk, arithmetic_inst },
252 {"cmp", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x14000001, OPCODE_MASK_H4, cmp, arithmetic_inst },
253 {"cmpu", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x14000003, OPCODE_MASK_H4, cmpu, arithmetic_inst },
254 {"addkc", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x18000000, OPCODE_MASK_H4, addkc, arithmetic_inst },
255 {"rsubkc",INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x1C000000, OPCODE_MASK_H4, rsubkc, arithmetic_inst },
256 {"addi", INST_TYPE_RD_R1_IMM, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x20000000, OPCODE_MASK_H, addi, arithmetic_inst },
257 {"rsubi", INST_TYPE_RD_R1_IMM, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x24000000, OPCODE_MASK_H, rsubi, arithmetic_inst },
258 {"addic", INST_TYPE_RD_R1_IMM, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x28000000, OPCODE_MASK_H, addic, arithmetic_inst },
259 {"rsubic",INST_TYPE_RD_R1_IMM, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x2C000000, OPCODE_MASK_H, rsubic, arithmetic_inst },
260 {"addik", INST_TYPE_RD_R1_IMM, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x30000000, OPCODE_MASK_H, addik, arithmetic_inst },
261 {"rsubik",INST_TYPE_RD_R1_IMM, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x34000000, OPCODE_MASK_H, rsubik, arithmetic_inst },
262 {"addikc",INST_TYPE_RD_R1_IMM, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x38000000, OPCODE_MASK_H, addikc, arithmetic_inst },
263 {"rsubikc",INST_TYPE_RD_R1_IMM, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x3C000000, OPCODE_MASK_H, rsubikc, arithmetic_inst },
264 {"mul", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x40000000, OPCODE_MASK_H4, mul, mult_inst },
265 {"idiv", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x48000000, OPCODE_MASK_H4, idiv, div_inst },
266 {"idivu", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x48000002, OPCODE_MASK_H4, idivu, div_inst },
267 {"bsll", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x44000400, OPCODE_MASK_H3, bsll, barrel_shift_inst },
268 {"bsra", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x44000200, OPCODE_MASK_H3, bsra, barrel_shift_inst },
269 {"bsrl", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x44000000, OPCODE_MASK_H3, bsrl, barrel_shift_inst },
270 {"get", INST_TYPE_RD_IMM12, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C000000, OPCODE_MASK_H32, get, anyware_inst },
271 {"put", INST_TYPE_R1_IMM12, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C008000, OPCODE_MASK_H32, put, anyware_inst },
272 {"nget", INST_TYPE_RD_IMM12, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C004000, OPCODE_MASK_H32, nget, anyware_inst },
273 {"nput", INST_TYPE_R1_IMM12, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C00C000, OPCODE_MASK_H32, nput, anyware_inst },
274 {"cget", INST_TYPE_RD_IMM12, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C002000, OPCODE_MASK_H32, cget, anyware_inst },
275 {"cput", INST_TYPE_R1_IMM12, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C00A000, OPCODE_MASK_H32, cput, anyware_inst },
276 {"ncget", INST_TYPE_RD_IMM12, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C006000, OPCODE_MASK_H32, ncget, anyware_inst },
277 {"ncput", INST_TYPE_R1_IMM12, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C00E000, OPCODE_MASK_H32, ncput, anyware_inst },
278 {"muli", INST_TYPE_RD_R1_IMM, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x60000000, OPCODE_MASK_H, muli, mult_inst },
279 {"bslli", INST_TYPE_RD_R1_IMM5, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x64000400, OPCODE_MASK_H3, bslli, barrel_shift_inst },
280 {"bsrai", INST_TYPE_RD_R1_IMM5, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x64000200, OPCODE_MASK_H3, bsrai, barrel_shift_inst },
281 {"bsrli", INST_TYPE_RD_R1_IMM5, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x64000000, OPCODE_MASK_H3, bsrli, barrel_shift_inst },
282 {"or", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x80000000, OPCODE_MASK_H4, or, logical_inst },
283 {"and", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x84000000, OPCODE_MASK_H4, and, logical_inst },
284 {"xor", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x88000000, OPCODE_MASK_H4, xor, logical_inst },
285 {"andn", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x8C000000, OPCODE_MASK_H4, andn, logical_inst },
286 {"pcmpbf",INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x80000400, OPCODE_MASK_H4, pcmpbf, logical_inst },
287 {"pcmpbc",INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x84000400, OPCODE_MASK_H4, pcmpbc, logical_inst },
288 {"pcmpeq",INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x88000400, OPCODE_MASK_H4, pcmpeq, logical_inst },
289 {"pcmpne",INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x8C000400, OPCODE_MASK_H4, pcmpne, logical_inst },
290 {"sra", INST_TYPE_RD_R1, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x90000001, OPCODE_MASK_H34, sra, logical_inst },
291 {"src", INST_TYPE_RD_R1, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x90000021, OPCODE_MASK_H34, src, logical_inst },
292 {"srl", INST_TYPE_RD_R1, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x90000041, OPCODE_MASK_H34, srl, logical_inst },
293 {"sext8", INST_TYPE_RD_R1, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x90000060, OPCODE_MASK_H34, sext8, logical_inst },
294 {"sext16",INST_TYPE_RD_R1, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x90000061, OPCODE_MASK_H34, sext16, logical_inst },
295 {"wic", INST_TYPE_RD_R1_SPECIAL, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x90000068, OPCODE_MASK_H34B, wic, special_inst },
296 {"wdc", INST_TYPE_RD_R1_SPECIAL, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x90000064, OPCODE_MASK_H34B, wdc, special_inst },
297 {"mts", INST_TYPE_SPECIAL_R1, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_MTS, 0x9400C000, OPCODE_MASK_H13S, mts, special_inst },
298 {"mfs", INST_TYPE_RD_SPECIAL, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_MFS, 0x94008000, OPCODE_MASK_H23S, mfs, special_inst },
299 {"br", INST_TYPE_R2, INST_PC_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x98000000, OPCODE_MASK_H124, br, branch_inst },
300 {"brd", INST_TYPE_R2, INST_PC_OFFSET, DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x98100000, OPCODE_MASK_H124, brd, branch_inst },
301 {"brld", INST_TYPE_RD_R2, INST_PC_OFFSET, DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x98140000, OPCODE_MASK_H24, brld, branch_inst },
302 {"bra", INST_TYPE_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x98080000, OPCODE_MASK_H124, bra, branch_inst },
303 {"brad", INST_TYPE_R2, INST_NO_OFFSET, DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x98180000, OPCODE_MASK_H124, brad, branch_inst },
304 {"brald", INST_TYPE_RD_R2, INST_NO_OFFSET, DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x981C0000, OPCODE_MASK_H24, brald, branch_inst },
305 {"brk", INST_TYPE_RD_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x980C0000, OPCODE_MASK_H24, microblaze_brk, branch_inst },
306 {"beq", INST_TYPE_R1_R2, INST_PC_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x9C000000, OPCODE_MASK_H14, beq, branch_inst },
307 {"beqd", INST_TYPE_R1_R2, INST_PC_OFFSET, DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x9E000000, OPCODE_MASK_H14, beqd, branch_inst },
308 {"bne", INST_TYPE_R1_R2, INST_PC_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x9C200000, OPCODE_MASK_H14, bne, branch_inst },
309 {"bned", INST_TYPE_R1_R2, INST_PC_OFFSET, DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x9E200000, OPCODE_MASK_H14, bned, branch_inst },
310 {"blt", INST_TYPE_R1_R2, INST_PC_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x9C400000, OPCODE_MASK_H14, blt, branch_inst },
311 {"bltd", INST_TYPE_R1_R2, INST_PC_OFFSET, DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x9E400000, OPCODE_MASK_H14, bltd, branch_inst },
312 {"ble", INST_TYPE_R1_R2, INST_PC_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x9C600000, OPCODE_MASK_H14, ble, branch_inst },
313 {"bled", INST_TYPE_R1_R2, INST_PC_OFFSET, DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x9E600000, OPCODE_MASK_H14, bled, branch_inst },
314 {"bgt", INST_TYPE_R1_R2, INST_PC_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x9C800000, OPCODE_MASK_H14, bgt, branch_inst },
315 {"bgtd", INST_TYPE_R1_R2, INST_PC_OFFSET, DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x9E800000, OPCODE_MASK_H14, bgtd, branch_inst },
316 {"bge", INST_TYPE_R1_R2, INST_PC_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x9CA00000, OPCODE_MASK_H14, bge, branch_inst },
317 {"bged", INST_TYPE_R1_R2, INST_PC_OFFSET, DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x9EA00000, OPCODE_MASK_H14, bged, branch_inst },
318 {"ori", INST_TYPE_RD_R1_IMM, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xA0000000, OPCODE_MASK_H, ori, logical_inst },
319 {"andi", INST_TYPE_RD_R1_IMM, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xA4000000, OPCODE_MASK_H, andi, logical_inst },
320 {"xori", INST_TYPE_RD_R1_IMM, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xA8000000, OPCODE_MASK_H, xori, logical_inst },
321 {"andni", INST_TYPE_RD_R1_IMM, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xAC000000, OPCODE_MASK_H, andni, logical_inst },
322 {"imm", INST_TYPE_IMM, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xB0000000, OPCODE_MASK_H12, imm, immediate_inst },
323 {"rtsd", INST_TYPE_R1_IMM, INST_NO_OFFSET, DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xB6000000, OPCODE_MASK_H1, rtsd, return_inst },
324 {"rtid", INST_TYPE_R1_IMM, INST_NO_OFFSET, DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xB6200000, OPCODE_MASK_H1, rtid, return_inst },
325 {"rtbd", INST_TYPE_R1_IMM, INST_NO_OFFSET, DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xB6400000, OPCODE_MASK_H1, rtbd, return_inst },
326 {"rted", INST_TYPE_R1_IMM, INST_NO_OFFSET, DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xB6800000, OPCODE_MASK_H1, rted, return_inst },
327 {"bri", INST_TYPE_IMM, INST_PC_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xB8000000, OPCODE_MASK_H12, bri, branch_inst },
328 {"brid", INST_TYPE_IMM, INST_PC_OFFSET, DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xB8100000, OPCODE_MASK_H12, brid, branch_inst },
329 {"brlid", INST_TYPE_RD_IMM, INST_PC_OFFSET, DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xB8140000, OPCODE_MASK_H2, brlid, branch_inst },
330 {"brai", INST_TYPE_IMM, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xB8080000, OPCODE_MASK_H12, brai, branch_inst },
331 {"braid", INST_TYPE_IMM, INST_NO_OFFSET, DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xB8180000, OPCODE_MASK_H12, braid, branch_inst },
332 {"bralid",INST_TYPE_RD_IMM, INST_NO_OFFSET, DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xB81C0000, OPCODE_MASK_H2, bralid, branch_inst },
333 {"brki", INST_TYPE_RD_IMM, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xB80C0000, OPCODE_MASK_H2, brki, branch_inst },
334 {"beqi", INST_TYPE_R1_IMM, INST_PC_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xBC000000, OPCODE_MASK_H1, beqi, branch_inst },
335 {"beqid", INST_TYPE_R1_IMM, INST_PC_OFFSET, DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xBE000000, OPCODE_MASK_H1, beqid, branch_inst },
336 {"bnei", INST_TYPE_R1_IMM, INST_PC_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xBC200000, OPCODE_MASK_H1, bnei, branch_inst },
337 {"bneid", INST_TYPE_R1_IMM, INST_PC_OFFSET, DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xBE200000, OPCODE_MASK_H1, bneid, branch_inst },
338 {"blti", INST_TYPE_R1_IMM, INST_PC_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xBC400000, OPCODE_MASK_H1, blti, branch_inst },
339 {"bltid", INST_TYPE_R1_IMM, INST_PC_OFFSET, DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xBE400000, OPCODE_MASK_H1, bltid, branch_inst },
340 {"blei", INST_TYPE_R1_IMM, INST_PC_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xBC600000, OPCODE_MASK_H1, blei, branch_inst },
341 {"bleid", INST_TYPE_R1_IMM, INST_PC_OFFSET, DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xBE600000, OPCODE_MASK_H1, bleid, branch_inst },
342 {"bgti", INST_TYPE_R1_IMM, INST_PC_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xBC800000, OPCODE_MASK_H1, bgti, branch_inst },
343 {"bgtid", INST_TYPE_R1_IMM, INST_PC_OFFSET, DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xBE800000, OPCODE_MASK_H1, bgtid, branch_inst },
344 {"bgei", INST_TYPE_R1_IMM, INST_PC_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xBCA00000, OPCODE_MASK_H1, bgei, branch_inst },
345 {"bgeid", INST_TYPE_R1_IMM, INST_PC_OFFSET, DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xBEA00000, OPCODE_MASK_H1, bgeid, branch_inst },
346 {"lbu", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xC0000000, OPCODE_MASK_H4, lbu, memory_load_inst },
347 {"lhu", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xC4000000, OPCODE_MASK_H4, lhu, memory_load_inst },
348 {"lw", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xC8000000, OPCODE_MASK_H4, lw, memory_load_inst },
349 {"sb", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xD0000000, OPCODE_MASK_H4, sb, memory_store_inst },
350 {"sh", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xD4000000, OPCODE_MASK_H4, sh, memory_store_inst },
351 {"sw", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xD8000000, OPCODE_MASK_H4, sw, memory_store_inst },
352 {"lbui", INST_TYPE_RD_R1_IMM, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xE0000000, OPCODE_MASK_H, lbui, memory_load_inst },
353 {"lhui", INST_TYPE_RD_R1_IMM, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xE4000000, OPCODE_MASK_H, lhui, memory_load_inst },
354 {"lwi", INST_TYPE_RD_R1_IMM, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xE8000000, OPCODE_MASK_H, lwi, memory_load_inst },
355 {"sbi", INST_TYPE_RD_R1_IMM, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xF0000000, OPCODE_MASK_H, sbi, memory_store_inst },
356 {"shi", INST_TYPE_RD_R1_IMM, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xF4000000, OPCODE_MASK_H, shi, memory_store_inst },
357 {"swi", INST_TYPE_RD_R1_IMM, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xF8000000, OPCODE_MASK_H, swi, memory_store_inst },
358 {"nop", INST_TYPE_NONE, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x80000000, OPCODE_MASK_H1234, invalid_inst, logical_inst }, /* translates to or r0, r0, r0 */
359 {"la", INST_TYPE_RD_R1_IMM, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x30000000, OPCODE_MASK_H, invalid_inst, arithmetic_inst }, /* la translates to addik */
360 {"tuqula",INST_TYPE_RD, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x3000002A, OPCODE_MASK_H, invalid_inst, arithmetic_inst }, /* tuqula rd translates to addik rd, r0, 42 */
361 {"not", INST_TYPE_RD_R1, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xA800FFFF, OPCODE_MASK_H34, invalid_inst, logical_inst }, /* not translates to xori rd,ra,-1 */
362 {"neg", INST_TYPE_RD_R1, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x04000000, OPCODE_MASK_H, invalid_inst, arithmetic_inst }, /* neg translates to rsub rd, ra, r0 */
363 {"rtb", INST_TYPE_R1, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xB6000004, OPCODE_MASK_H1, invalid_inst, return_inst }, /* rtb translates to rts rd, 4 */
364 {"sub", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x04000000, OPCODE_MASK_H, invalid_inst, arithmetic_inst }, /* sub translates to rsub rd, rb, ra */
365 {"lmi", INST_TYPE_RD_R1_IMM, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xE8000000, OPCODE_MASK_H, invalid_inst, memory_load_inst },
366 {"smi", INST_TYPE_RD_R1_IMM, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xF8000000, OPCODE_MASK_H, invalid_inst, memory_store_inst },
367 {"msrset",INST_TYPE_RD_IMM14, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x94100000, OPCODE_MASK_H23N, msrset, special_inst },
368 {"msrclr",INST_TYPE_RD_IMM14, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x94110000, OPCODE_MASK_H23N, msrclr, special_inst },
369 {"fadd", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x58000000, OPCODE_MASK_H4, fadd, arithmetic_inst },
370 {"frsub", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x58000080, OPCODE_MASK_H4, frsub, arithmetic_inst },
371 {"fmul", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x58000100, OPCODE_MASK_H4, fmul, arithmetic_inst },
372 {"fdiv", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x58000180, OPCODE_MASK_H4, fdiv, arithmetic_inst },
373 {"fcmp.lt", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x58000210, OPCODE_MASK_H4, fcmp_lt, arithmetic_inst },
374 {"fcmp.eq", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x58000220, OPCODE_MASK_H4, fcmp_eq, arithmetic_inst },
375 {"fcmp.le", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x58000230, OPCODE_MASK_H4, fcmp_le, arithmetic_inst },
376 {"fcmp.gt", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x58000240, OPCODE_MASK_H4, fcmp_gt, arithmetic_inst },
377 {"fcmp.ne", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x58000250, OPCODE_MASK_H4, fcmp_ne, arithmetic_inst },
378 {"fcmp.ge", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x58000260, OPCODE_MASK_H4, fcmp_ge, arithmetic_inst },
379 {"fcmp.un", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x58000200, OPCODE_MASK_H4, fcmp_un, arithmetic_inst },
380 {""}
383 /* prefix for register names */
384 char register_prefix[] = "r";
385 char special_register_prefix[] = "spr";
386 char fsl_register_prefix[] = "rfsl";
389 /* #defines for valid immediate range */
390 #define MIN_IMM 0x80000000
391 #define MAX_IMM 0x7fffffff
393 #define MIN_IMM12 0x000
394 #define MAX_IMM12 0x7ff
396 #define MIN_IMM14 0x0000
397 #define MAX_IMM14 0x1fff
399 #endif /* MICROBLAZE_OPC */
401 #include "dis-asm.h"
402 #include <strings.h>
404 #define get_field_rd(instr) get_field(instr, RD_MASK, RD_LOW)
405 #define get_field_r1(instr) get_field(instr, RA_MASK, RA_LOW)
406 #define get_field_r2(instr) get_field(instr, RB_MASK, RB_LOW)
407 #define get_int_field_imm(instr) ((instr & IMM_MASK) >> IMM_LOW)
408 #define get_int_field_r1(instr) ((instr & RA_MASK) >> RA_LOW)
410 static char *
411 get_field (long instr, long mask, unsigned short low)
413 char tmpstr[25];
414 sprintf(tmpstr, "%s%d", register_prefix, (int)((instr & mask) >> low));
415 return(strdup(tmpstr));
418 static char *
419 get_field_imm (long instr)
421 char tmpstr[25];
422 sprintf(tmpstr, "%d", (short)((instr & IMM_MASK) >> IMM_LOW));
423 return(strdup(tmpstr));
426 static char *
427 get_field_imm5 (long instr)
429 char tmpstr[25];
430 sprintf(tmpstr, "%d", (short)((instr & IMM5_MASK) >> IMM_LOW));
431 return(strdup(tmpstr));
434 static char *
435 get_field_imm12 (long instr)
437 char tmpstr[25];
438 sprintf(tmpstr, "%s%d", fsl_register_prefix, (short)((instr & IMM12_MASK) >> IMM_LOW));
439 return(strdup(tmpstr));
442 static char *
443 get_field_imm14 (long instr)
445 char tmpstr[25];
446 sprintf(tmpstr, "%d", (short)((instr & IMM14_MASK) >> IMM_LOW));
447 return(strdup(tmpstr));
450 #if 0
451 static char *
452 get_field_unsigned_imm (long instr)
454 char tmpstr[25];
455 sprintf(tmpstr, "%d", (int)((instr & IMM_MASK) >> IMM_LOW));
456 return(strdup(tmpstr));
458 #endif
461 char *
462 get_field_special (instr)
463 long instr;
465 char tmpstr[25];
467 sprintf(tmpstr, "%s%s", register_prefix, (((instr & IMM_MASK) >> IMM_LOW) & REG_MSR_MASK) == 0 ? "pc" : "msr");
469 return(strdup(tmpstr));
473 static char *
474 get_field_special (long instr, struct op_code_struct * op)
476 char tmpstr[25];
477 char spr[5];
479 switch ( (((instr & IMM_MASK) >> IMM_LOW) ^ op->immval_mask) ) {
480 case REG_MSR_MASK :
481 strcpy(spr, "msr");
482 break;
483 case REG_PC_MASK :
484 strcpy(spr, "pc");
485 break;
486 case REG_EAR_MASK :
487 strcpy(spr, "ear");
488 break;
489 case REG_ESR_MASK :
490 strcpy(spr, "esr");
491 break;
492 case REG_FSR_MASK :
493 strcpy(spr, "fsr");
494 break;
495 default :
496 strcpy(spr, "pc");
497 break;
500 sprintf(tmpstr, "%s%s", register_prefix, spr);
501 return(strdup(tmpstr));
504 static unsigned long
505 read_insn_microblaze(bfd_vma memaddr, struct disassemble_info *info,
506 struct op_code_struct ** opr)
508 unsigned char ibytes[4];
509 int status;
510 struct op_code_struct * op;
511 unsigned long inst;
513 status = info->read_memory_func (memaddr, ibytes, 4, info);
515 if (status != 0)
517 info->memory_error_func (status, memaddr, info);
518 return 0;
521 if (info->endian == BFD_ENDIAN_BIG)
522 inst = (ibytes[0] << 24) | (ibytes[1] << 16) | (ibytes[2] << 8) | ibytes[3];
523 else if (info->endian == BFD_ENDIAN_LITTLE)
524 inst = (ibytes[3] << 24) | (ibytes[2] << 16) | (ibytes[1] << 8) | ibytes[0];
525 else
526 abort ();
528 /* Just a linear search of the table. */
529 for (op = opcodes; op->name != 0; op ++)
530 if (op->bit_sequence == (inst & op->opcode_mask))
531 break;
533 *opr = op;
534 return inst;
538 int
539 print_insn_microblaze (bfd_vma memaddr, struct disassemble_info * info)
541 fprintf_ftype fprintf = info->fprintf_func;
542 void * stream = info->stream;
543 unsigned long inst, prev_inst;
544 struct op_code_struct * op, *pop;
545 int immval = 0;
546 boolean immfound = false;
547 static bfd_vma prev_insn_addr = -1; /*init the prev insn addr */
548 static int prev_insn_vma = -1; /*init the prev insn vma */
549 int curr_insn_vma = info->buffer_vma;
551 info->bytes_per_chunk = 4;
553 inst = read_insn_microblaze (memaddr, info, &op);
554 if (inst == 0)
555 return -1;
557 if (prev_insn_vma == curr_insn_vma) {
558 if (memaddr-(info->bytes_per_chunk) == prev_insn_addr) {
559 prev_inst = read_insn_microblaze (prev_insn_addr, info, &pop);
560 if (prev_inst == 0)
561 return -1;
562 if (pop->instr == imm) {
563 immval = (get_int_field_imm(prev_inst) << 16) & 0xffff0000;
564 immfound = true;
566 else {
567 immval = 0;
568 immfound = false;
572 /* make curr insn as prev insn */
573 prev_insn_addr = memaddr;
574 prev_insn_vma = curr_insn_vma;
576 if (op->name == 0)
577 fprintf (stream, ".short 0x%04x", inst);
578 else
580 fprintf (stream, "%s", op->name);
582 switch (op->inst_type)
584 case INST_TYPE_RD_R1_R2:
585 fprintf(stream, "\t%s, %s, %s", get_field_rd(inst), get_field_r1(inst), get_field_r2(inst));
586 break;
587 case INST_TYPE_RD_R1_IMM:
588 fprintf(stream, "\t%s, %s, %s", get_field_rd(inst), get_field_r1(inst), get_field_imm(inst));
589 if (info->print_address_func && get_int_field_r1(inst) == 0 && info->symbol_at_address_func) {
590 if (immfound)
591 immval |= (get_int_field_imm(inst) & 0x0000ffff);
592 else {
593 immval = get_int_field_imm(inst);
594 if (immval & 0x8000)
595 immval |= 0xFFFF0000;
597 if (immval > 0 && info->symbol_at_address_func(immval, info)) {
598 fprintf (stream, "\t// ");
599 info->print_address_func (immval, info);
602 break;
603 case INST_TYPE_RD_R1_IMM5:
604 fprintf(stream, "\t%s, %s, %s", get_field_rd(inst), get_field_r1(inst), get_field_imm5(inst));
605 break;
606 case INST_TYPE_RD_IMM12:
607 fprintf(stream, "\t%s, %s", get_field_rd(inst), get_field_imm12(inst));
608 break;
609 case INST_TYPE_R1_IMM12:
610 fprintf(stream, "\t%s, %s", get_field_r1(inst), get_field_imm12(inst));
611 break;
612 case INST_TYPE_RD_SPECIAL:
613 fprintf(stream, "\t%s, %s", get_field_rd(inst), get_field_special(inst, op));
614 break;
615 case INST_TYPE_SPECIAL_R1:
616 fprintf(stream, "\t%s, %s", get_field_special(inst, op), get_field_r1(inst));
617 break;
618 case INST_TYPE_RD_R1:
619 fprintf(stream, "\t%s, %s", get_field_rd(inst), get_field_r1(inst));
620 break;
621 case INST_TYPE_R1_R2:
622 fprintf(stream, "\t%s, %s", get_field_r1(inst), get_field_r2(inst));
623 break;
624 case INST_TYPE_R1_IMM:
625 fprintf(stream, "\t%s, %s", get_field_r1(inst), get_field_imm(inst));
626 /* The non-pc relative instructions are returns, which shouldn't
627 have a label printed */
628 if (info->print_address_func && op->inst_offset_type == INST_PC_OFFSET && info->symbol_at_address_func) {
629 if (immfound)
630 immval |= (get_int_field_imm(inst) & 0x0000ffff);
631 else {
632 immval = get_int_field_imm(inst);
633 if (immval & 0x8000)
634 immval |= 0xFFFF0000;
636 immval += memaddr;
637 if (immval > 0 && info->symbol_at_address_func(immval, info)) {
638 fprintf (stream, "\t// ");
639 info->print_address_func (immval, info);
640 } else {
641 fprintf (stream, "\t\t// ");
642 fprintf (stream, "%x", immval);
645 break;
646 case INST_TYPE_RD_IMM:
647 fprintf(stream, "\t%s, %s", get_field_rd(inst), get_field_imm(inst));
648 if (info->print_address_func && info->symbol_at_address_func) {
649 if (immfound)
650 immval |= (get_int_field_imm(inst) & 0x0000ffff);
651 else {
652 immval = get_int_field_imm(inst);
653 if (immval & 0x8000)
654 immval |= 0xFFFF0000;
656 if (op->inst_offset_type == INST_PC_OFFSET)
657 immval += (int) memaddr;
658 if (info->symbol_at_address_func(immval, info)) {
659 fprintf (stream, "\t// ");
660 info->print_address_func (immval, info);
663 break;
664 case INST_TYPE_IMM:
665 fprintf(stream, "\t%s", get_field_imm(inst));
666 if (info->print_address_func && info->symbol_at_address_func && op->instr != imm) {
667 if (immfound)
668 immval |= (get_int_field_imm(inst) & 0x0000ffff);
669 else {
670 immval = get_int_field_imm(inst);
671 if (immval & 0x8000)
672 immval |= 0xFFFF0000;
674 if (op->inst_offset_type == INST_PC_OFFSET)
675 immval += (int) memaddr;
676 if (immval > 0 && info->symbol_at_address_func(immval, info)) {
677 fprintf (stream, "\t// ");
678 info->print_address_func (immval, info);
679 } else if (op->inst_offset_type == INST_PC_OFFSET) {
680 fprintf (stream, "\t\t// ");
681 fprintf (stream, "%x", immval);
684 break;
685 case INST_TYPE_RD_R2:
686 fprintf(stream, "\t%s, %s", get_field_rd(inst), get_field_r2(inst));
687 break;
688 case INST_TYPE_R2:
689 fprintf(stream, "\t%s", get_field_r2(inst));
690 break;
691 case INST_TYPE_R1:
692 fprintf(stream, "\t%s", get_field_r1(inst));
693 break;
694 case INST_TYPE_RD_R1_SPECIAL:
695 fprintf(stream, "\t%s, %s", get_field_rd(inst), get_field_r2(inst));
696 break;
697 case INST_TYPE_RD_IMM14:
698 fprintf(stream, "\t%s, %s", get_field_rd(inst), get_field_imm14(inst));
699 break;
700 /* For tuqula instruction */
701 case INST_TYPE_RD:
702 fprintf(stream, "\t%s", get_field_rd(inst));
703 break;
705 default:
706 /* if the disassembler lags the instruction set */
707 fprintf (stream, "\tundecoded operands, inst is 0x%04x", inst);
708 break;
712 /* Say how many bytes we consumed? */
713 return 4;
716 #if 0
717 static enum microblaze_instr
718 get_insn_microblaze (long inst, boolean *isunsignedimm,
719 enum microblaze_instr_type *insn_type,
720 short *delay_slots )
722 struct op_code_struct * op;
723 *isunsignedimm = false;
725 /* Just a linear search of the table. */
726 for (op = opcodes; op->name != 0; op ++)
727 if (op->bit_sequence == (inst & op->opcode_mask))
728 break;
730 if (op->name == 0)
731 return invalid_inst;
732 else {
733 *isunsignedimm = (op->inst_type == INST_TYPE_RD_R1_UNSIGNED_IMM);
734 *insn_type = op->instr_type;
735 *delay_slots = op->delay_slots;
736 return op->instr;
739 #endif
741 #if 0
742 static short
743 get_delay_slots_microblaze ( long inst )
745 boolean isunsignedimm;
746 enum microblaze_instr_type insn_type;
747 enum microblaze_instr op;
748 short delay_slots;
750 op = get_insn_microblaze( inst, &isunsignedimm, &insn_type, &delay_slots);
751 if (op == invalid_inst)
752 return 0;
753 else
754 return delay_slots;
756 #endif
758 #if 0
759 static enum microblaze_instr
760 microblaze_decode_insn (long insn, int *rd, int *ra, int *rb, int *imm)
762 enum microblaze_instr op;
763 boolean t1;
764 enum microblaze_instr_type t2;
765 short t3;
767 op = get_insn_microblaze(insn, &t1, &t2, &t3);
768 *rd = (insn & RD_MASK) >> RD_LOW;
769 *ra = (insn & RA_MASK) >> RA_LOW;
770 *rb = (insn & RB_MASK) >> RB_LOW;
771 t3 = (insn & IMM_MASK) >> IMM_LOW;
772 *imm = (int) t3;
773 return (op);
775 #endif
777 #if 0
778 static unsigned long
779 microblaze_get_target_address (long inst, boolean immfound, int immval,
780 long pcval, long r1val, long r2val,
781 boolean *targetvalid,
782 boolean *unconditionalbranch)
784 struct op_code_struct * op;
785 long targetaddr = 0;
787 *unconditionalbranch = false;
788 /* Just a linear search of the table. */
789 for (op = opcodes; op->name != 0; op ++)
790 if (op->bit_sequence == (inst & op->opcode_mask))
791 break;
793 if (op->name == 0) {
794 *targetvalid = false;
795 } else if (op->instr_type == branch_inst) {
796 switch (op->inst_type) {
797 case INST_TYPE_R2:
798 *unconditionalbranch = true;
799 /* fallthru */
800 case INST_TYPE_RD_R2:
801 case INST_TYPE_R1_R2:
802 targetaddr = r2val;
803 *targetvalid = true;
804 if (op->inst_offset_type == INST_PC_OFFSET)
805 targetaddr += pcval;
806 break;
807 case INST_TYPE_IMM:
808 *unconditionalbranch = true;
809 /* fallthru */
810 case INST_TYPE_RD_IMM:
811 case INST_TYPE_R1_IMM:
812 if (immfound) {
813 targetaddr = (immval << 16) & 0xffff0000;
814 targetaddr |= (get_int_field_imm(inst) & 0x0000ffff);
815 } else {
816 targetaddr = get_int_field_imm(inst);
817 if (targetaddr & 0x8000)
818 targetaddr |= 0xFFFF0000;
820 if (op->inst_offset_type == INST_PC_OFFSET)
821 targetaddr += pcval;
822 *targetvalid = true;
823 break;
824 default:
825 *targetvalid = false;
826 break;
828 } else if (op->instr_type == return_inst) {
829 if (immfound) {
830 targetaddr = (immval << 16) & 0xffff0000;
831 targetaddr |= (get_int_field_imm(inst) & 0x0000ffff);
832 } else {
833 targetaddr = get_int_field_imm(inst);
834 if (targetaddr & 0x8000)
835 targetaddr |= 0xFFFF0000;
837 targetaddr += r1val;
838 *targetvalid = true;
839 } else {
840 *targetvalid = false;
842 return targetaddr;
844 #endif