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