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; | ... | ... |