Commit e6dbd3b3f08318196cbdb1f0c23a7eefd9b38cb7
1 parent
5aca8c3b
M68k extended addressing modes.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2870 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
2 changed files
with
121 additions
and
29 deletions
target-m68k/cpu.h
... | ... | @@ -160,7 +160,8 @@ enum m68k_features { |
160 | 160 | M68K_FEATURE_CF_FPU, |
161 | 161 | M68K_FEATURE_CF_MAC, |
162 | 162 | M68K_FEATURE_CF_EMAC, |
163 | - M68K_FEATURE_EXT_FULL /* 68020+ full extension word. */ | |
163 | + M68K_FEATURE_EXT_FULL, /* 68020+ full extension word. */ | |
164 | + M68K_FEATURE_WORD_INDEX /* word sized address index registers. */ | |
164 | 165 | }; |
165 | 166 | |
166 | 167 | static inline int m68k_feature(CPUM68KState *env, int feature) | ... | ... |
target-m68k/translate.c
... | ... | @@ -42,6 +42,7 @@ static inline void qemu_assert(int cond, const char *msg) |
42 | 42 | |
43 | 43 | /* internal defines */ |
44 | 44 | typedef struct DisasContext { |
45 | + CPUM68KState *env; | |
45 | 46 | target_ulong pc; |
46 | 47 | int is_jmp; |
47 | 48 | int cc_op; |
... | ... | @@ -198,50 +199,139 @@ static int gen_ldst(DisasContext *s, int opsize, int addr, int val) |
198 | 199 | } |
199 | 200 | } |
200 | 201 | |
202 | +/* Read a 32-bit immediate constant. */ | |
203 | +static inline uint32_t read_im32(DisasContext *s) | |
204 | +{ | |
205 | + uint32_t im; | |
206 | + im = ((uint32_t)lduw_code(s->pc)) << 16; | |
207 | + s->pc += 2; | |
208 | + im |= lduw_code(s->pc); | |
209 | + s->pc += 2; | |
210 | + return im; | |
211 | +} | |
212 | + | |
213 | +/* Calculate and address index. */ | |
214 | +static int gen_addr_index(uint16_t ext, int tmp) | |
215 | +{ | |
216 | + int add; | |
217 | + int scale; | |
218 | + | |
219 | + add = (ext & 0x8000) ? AREG(ext, 12) : DREG(ext, 12); | |
220 | + if ((ext & 0x800) == 0) { | |
221 | + gen_op_ext16s32(tmp, add); | |
222 | + add = tmp; | |
223 | + } | |
224 | + scale = (ext >> 9) & 3; | |
225 | + if (scale != 0) { | |
226 | + gen_op_shl32(tmp, add, gen_im32(scale)); | |
227 | + add = tmp; | |
228 | + } | |
229 | + return add; | |
230 | +} | |
231 | + | |
201 | 232 | /* Handle a base + index + displacement effective addresss. A base of |
202 | 233 | -1 means pc-relative. */ |
203 | 234 | static int gen_lea_indexed(DisasContext *s, int opsize, int base) |
204 | 235 | { |
205 | - int scale; | |
206 | 236 | uint32_t offset; |
207 | 237 | uint16_t ext; |
208 | 238 | int add; |
209 | 239 | int tmp; |
240 | + uint32_t bd, od; | |
210 | 241 | |
211 | 242 | offset = s->pc; |
212 | 243 | ext = lduw_code(s->pc); |
213 | 244 | s->pc += 2; |
214 | - tmp = ((ext >> 12) & 7) + ((ext & 0x8000) ? QREG_A0 : QREG_D0); | |
215 | - /* ??? Check W/L bit. */ | |
216 | - scale = (ext >> 9) & 3; | |
217 | - if (scale == 0) { | |
218 | - add = tmp; | |
219 | - } else { | |
220 | - add = gen_new_qreg(QMODE_I32); | |
221 | - gen_op_shl32(add, tmp, gen_im32(scale)); | |
222 | - } | |
223 | - tmp = gen_new_qreg(QMODE_I32); | |
224 | - if (base != -1) { | |
225 | - gen_op_add32(tmp, base, gen_im32((int8_t)ext)); | |
226 | - gen_op_add32(tmp, tmp, add); | |
245 | + | |
246 | + if ((ext & 0x800) == 0 && !m68k_feature(s->env, M68K_FEATURE_WORD_INDEX)) | |
247 | + return -1; | |
248 | + | |
249 | + if (ext & 0x100) { | |
250 | + /* full extension word format */ | |
251 | + if (!m68k_feature(s->env, M68K_FEATURE_EXT_FULL)) | |
252 | + return -1; | |
253 | + | |
254 | + if ((ext & 0x30) > 0x10) { | |
255 | + /* base displacement */ | |
256 | + if ((ext & 0x30) == 0x20) { | |
257 | + bd = (int16_t)lduw_code(s->pc); | |
258 | + s->pc += 2; | |
259 | + } else { | |
260 | + bd = read_im32(s); | |
261 | + } | |
262 | + } else { | |
263 | + bd = 0; | |
264 | + } | |
265 | + tmp = gen_new_qreg(QMODE_I32); | |
266 | + if ((ext & 0x44) == 0) { | |
267 | + /* pre-index */ | |
268 | + add = gen_addr_index(ext, tmp); | |
269 | + } else { | |
270 | + add = QREG_NULL; | |
271 | + } | |
272 | + if ((ext & 0x80) == 0) { | |
273 | + /* base not suppressed */ | |
274 | + if (base == -1) { | |
275 | + base = gen_im32(offset + bd); | |
276 | + bd = 0; | |
277 | + } | |
278 | + if (add) { | |
279 | + gen_op_add32(tmp, add, base); | |
280 | + add = tmp; | |
281 | + } else { | |
282 | + add = base; | |
283 | + } | |
284 | + } | |
285 | + if (add) { | |
286 | + if (bd != 0) { | |
287 | + gen_op_add32(tmp, add, gen_im32(bd)); | |
288 | + add = tmp; | |
289 | + } | |
290 | + } else { | |
291 | + add = gen_im32(bd); | |
292 | + } | |
293 | + if ((ext & 3) != 0) { | |
294 | + /* memory indirect */ | |
295 | + base = gen_load(s, OS_LONG, add, 0); | |
296 | + if ((ext & 0x44) == 4) { | |
297 | + add = gen_addr_index(ext, tmp); | |
298 | + gen_op_add32(tmp, add, base); | |
299 | + add = tmp; | |
300 | + } else { | |
301 | + add = base; | |
302 | + } | |
303 | + if ((ext & 3) > 1) { | |
304 | + /* outer displacement */ | |
305 | + if ((ext & 3) == 2) { | |
306 | + od = (int16_t)lduw_code(s->pc); | |
307 | + s->pc += 2; | |
308 | + } else { | |
309 | + od = read_im32(s); | |
310 | + } | |
311 | + } else { | |
312 | + od = 0; | |
313 | + } | |
314 | + if (od != 0) { | |
315 | + gen_op_add32(add, tmp, gen_im32(od)); | |
316 | + add = tmp; | |
317 | + } | |
318 | + } | |
227 | 319 | } else { |
228 | - gen_op_add32(tmp, add, gen_im32(offset + (int8_t)ext)); | |
320 | + /* brief extension word format */ | |
321 | + tmp = gen_new_qreg(QMODE_I32); | |
322 | + add = gen_addr_index(ext, tmp); | |
323 | + if (base != -1) { | |
324 | + gen_op_add32(tmp, add, base); | |
325 | + if ((int8_t)ext) | |
326 | + gen_op_add32(tmp, tmp, gen_im32((int8_t)ext)); | |
327 | + } else { | |
328 | + gen_op_add32(tmp, add, gen_im32(offset + (int8_t)ext)); | |
329 | + } | |
330 | + add = tmp; | |
229 | 331 | } |
230 | - return tmp; | |
231 | -} | |
232 | - | |
233 | -/* Read a 32-bit immediate constant. */ | |
234 | -static inline uint32_t read_im32(DisasContext *s) | |
235 | -{ | |
236 | - uint32_t im; | |
237 | - im = ((uint32_t)lduw_code(s->pc)) << 16; | |
238 | - s->pc += 2; | |
239 | - im |= lduw_code(s->pc); | |
240 | - s->pc += 2; | |
241 | - return im; | |
332 | + return add; | |
242 | 333 | } |
243 | 334 | |
244 | - | |
245 | 335 | /* Update the CPU env CC_OP state. */ |
246 | 336 | static inline void gen_flush_cc_op(DisasContext *s) |
247 | 337 | { |
... | ... | @@ -2721,6 +2811,7 @@ gen_intermediate_code_internal(CPUState *env, TranslationBlock *tb, |
2721 | 2811 | gen_opc_end = gen_opc_buf + OPC_MAX_SIZE; |
2722 | 2812 | gen_opparam_ptr = gen_opparam_buf; |
2723 | 2813 | |
2814 | + dc->env = env; | |
2724 | 2815 | dc->is_jmp = DISAS_NEXT; |
2725 | 2816 | dc->pc = pc_start; |
2726 | 2817 | dc->cc_op = CC_OP_DYNAMIC; | ... | ... |