Commit | Line | Data |
---|---|---|
54cc8ed4 DE |
1 | /* Instruction printing code for the TXVU |
2 | Copyright (C) 1998 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 along | |
15 | with this program; if not, write to the Free Software Foundation, Inc., | |
16 | 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ | |
17 | ||
18 | #include "dis-asm.h" | |
19 | #include "opcode/txvu.h" | |
20 | #include "elf-bfd.h" | |
21 | #include "elf/txvu.h" | |
22 | ||
23 | static void print_insn PARAMS ((bfd_vma, disassemble_info *, TXVU_INSN, int)); | |
24 | ||
25 | /* Print one instruction from PC on INFO->STREAM. | |
26 | Return the size of the instruction. */ | |
27 | ||
28 | int | |
29 | print_insn_txvu (pc, info) | |
30 | bfd_vma pc; | |
31 | disassemble_info *info; | |
32 | { | |
33 | bfd_byte buffer[8]; | |
34 | void *stream = info->stream; | |
35 | fprintf_ftype func = info->fprintf_func; | |
36 | int status; | |
37 | /* First element is upper, second is lower. */ | |
38 | TXVU_INSN upper,lower; | |
39 | static int initialized = 0; | |
40 | ||
41 | if (!initialized) | |
42 | { | |
43 | initialized = 1; | |
44 | txvu_opcode_init_tables (0); | |
45 | } | |
46 | ||
47 | status = (*info->read_memory_func) (pc, buffer, 8, info); | |
48 | if (status != 0) | |
49 | { | |
50 | (*info->memory_error_func) (status, pc, info); | |
51 | return -1; | |
52 | } | |
1a702a24 DE |
53 | /* The lower instruction has the lower address. */ |
54 | upper = bfd_getl32 (buffer + 4); | |
55 | lower = bfd_getl32 (buffer); | |
54cc8ed4 DE |
56 | |
57 | /* FIXME: This will need revisiting. */ | |
58 | print_insn (pc, info, upper, 0); | |
42639e83 | 59 | #ifdef VERTICAL_BAR_SEPARATOR |
d97f99af | 60 | (*func) (stream, " | "); |
42639e83 DE |
61 | #else |
62 | /* Not sure how much whitespace to print here. | |
63 | At least two spaces, not more than 9, and having columns line up somewhat | |
64 | seems reasonable. */ | |
65 | (*func) (stream, " \t"); | |
66 | #endif | |
54cc8ed4 DE |
67 | print_insn (pc, info, lower, 1); |
68 | ||
69 | return 8; | |
70 | } | |
71 | ||
72 | /* Print one instruction. | |
73 | LOWER_P is non-zero if disassembling a lower slot insn. */ | |
74 | ||
75 | static void | |
76 | print_insn (pc, info, insn, lower_p) | |
77 | bfd_vma pc; | |
78 | disassemble_info *info; | |
79 | TXVU_INSN insn; | |
80 | int lower_p; | |
81 | { | |
82 | const struct txvu_opcode *opcode; | |
83 | void *stream = info->stream; | |
84 | fprintf_ftype func = info->fprintf_func; | |
85 | ||
86 | /* The instructions are stored in lists hashed by the insn code | |
87 | (though we needn't care how they're hashed). */ | |
88 | ||
89 | if (lower_p) | |
90 | opcode = txvu_lower_opcode_lookup_dis (insn); | |
91 | else | |
92 | opcode = txvu_upper_opcode_lookup_dis (insn); | |
93 | for ( ; opcode != NULL; opcode = TXVU_OPCODE_NEXT_DIS (opcode)) | |
94 | { | |
95 | const unsigned char *syn; | |
96 | int mods,invalid,num_operands; | |
97 | long value; | |
98 | const struct txvu_operand *operand; | |
99 | ||
100 | /* Basic bit mask must be correct. */ | |
101 | if ((insn & opcode->mask) != opcode->value) | |
102 | continue; | |
103 | ||
104 | /* Make two passes over the operands. First see if any of them | |
105 | have extraction functions, and, if they do, make sure the | |
106 | instruction is valid. */ | |
107 | ||
108 | txvu_opcode_init_print (); | |
109 | invalid = 0; | |
110 | ||
111 | for (syn = opcode->syntax; *syn; ++syn) | |
112 | { | |
113 | int index; | |
114 | ||
115 | if (*syn < 128) | |
116 | continue; | |
117 | ||
118 | mods = 0; | |
119 | index = TXVU_OPERAND_INDEX (*syn); | |
120 | while (TXVU_MOD_P (txvu_operands[index].flags)) | |
121 | { | |
122 | mods |= txvu_operands[index].flags & TXVU_MOD_BITS; | |
123 | ++syn; | |
124 | index = TXVU_OPERAND_INDEX (*syn); | |
125 | } | |
126 | operand = txvu_operands + index; | |
127 | if (operand->extract) | |
f31e2072 | 128 | (*operand->extract) (&insn, operand, mods, &invalid); |
54cc8ed4 DE |
129 | } |
130 | if (invalid) | |
131 | continue; | |
132 | ||
133 | /* The instruction is valid. */ | |
134 | ||
135 | (*func) (stream, "%s", opcode->mnemonic); | |
136 | num_operands = 0; | |
137 | for (syn = opcode->syntax; *syn; ++syn) | |
138 | { | |
139 | int index; | |
140 | ||
141 | if (*syn < 128) | |
142 | { | |
143 | (*func) (stream, "%c", *syn); | |
144 | continue; | |
145 | } | |
146 | ||
147 | /* We have an operand. Fetch any special modifiers. */ | |
148 | mods = 0; | |
149 | index = TXVU_OPERAND_INDEX (*syn); | |
150 | while (TXVU_MOD_P (txvu_operands[index].flags)) | |
151 | { | |
152 | mods |= txvu_operands[index].flags & TXVU_MOD_BITS; | |
153 | ++syn; | |
154 | index = TXVU_OPERAND_INDEX (*syn); | |
155 | } | |
156 | operand = txvu_operands + index; | |
157 | ||
158 | /* Extract the value from the instruction. */ | |
159 | if (operand->extract) | |
160 | { | |
f31e2072 | 161 | value = (*operand->extract) (&insn, operand, mods, (int *) NULL); |
54cc8ed4 DE |
162 | } |
163 | else | |
164 | { | |
165 | value = (insn >> operand->shift) & ((1 << operand->bits) - 1); | |
97a6824d | 166 | if ((operand->flags & TXVU_OPERAND_SIGNED) != 0 |
54cc8ed4 DE |
167 | && (value & (1 << (operand->bits - 1)))) |
168 | value -= 1 << operand->bits; | |
169 | } | |
170 | ||
1a702a24 | 171 | #if 0 /* commas are part of the syntax string now */ |
54cc8ed4 DE |
172 | /* If second or later operand, print a comma. */ |
173 | if (num_operands > 0) | |
174 | (*func) (stream, ","); | |
1a702a24 | 175 | #endif |
54cc8ed4 DE |
176 | |
177 | /* Print the operand as directed by the flags. */ | |
178 | if (operand->print) | |
f31e2072 | 179 | (*operand->print) (info, &insn, value); |
54cc8ed4 DE |
180 | else if (operand->flags & TXVU_OPERAND_FAKE) |
181 | ; /* nothing to do (??? at least not yet) */ | |
182 | else if (operand->flags & TXVU_OPERAND_RELATIVE_BRANCH) | |
1a702a24 | 183 | (*info->print_address_func) (pc + (value << 3), info); |
54cc8ed4 DE |
184 | /* ??? Not all cases of this are currently caught. */ |
185 | else if (operand->flags & TXVU_OPERAND_ABSOLUTE_BRANCH) | |
186 | (*info->print_address_func) ((bfd_vma) value & 0xffffffff, info); | |
187 | else if (operand->flags & TXVU_OPERAND_ADDRESS) | |
188 | (*info->print_address_func) ((bfd_vma) value & 0xffffffff, info); | |
189 | else | |
190 | (*func) (stream, "%ld", value); | |
191 | ||
192 | if (! (operand->flags & TXVU_OPERAND_SUFFIX)) | |
193 | ++num_operands; | |
194 | } | |
195 | ||
196 | /* We have found and printed an instruction; return. */ | |
197 | return; | |
198 | } | |
199 | ||
200 | (*func) (stream, "*unknown*"); | |
201 | } |