1 1.28 isaki /* $NetBSD: fpu_calcea.c,v 1.28 2024/12/28 03:11:09 isaki Exp $ */ 2 1.1 briggs 3 1.1 briggs /* 4 1.1 briggs * Copyright (c) 1995 Gordon W. Ross 5 1.1 briggs * portion Copyright (c) 1995 Ken Nakata 6 1.1 briggs * All rights reserved. 7 1.1 briggs * 8 1.1 briggs * Redistribution and use in source and binary forms, with or without 9 1.1 briggs * modification, are permitted provided that the following conditions 10 1.1 briggs * are met: 11 1.1 briggs * 1. Redistributions of source code must retain the above copyright 12 1.1 briggs * notice, this list of conditions and the following disclaimer. 13 1.1 briggs * 2. Redistributions in binary form must reproduce the above copyright 14 1.1 briggs * notice, this list of conditions and the following disclaimer in the 15 1.1 briggs * documentation and/or other materials provided with the distribution. 16 1.1 briggs * 3. The name of the author may not be used to endorse or promote products 17 1.1 briggs * derived from this software without specific prior written permission. 18 1.1 briggs * 4. All advertising materials mentioning features or use of this software 19 1.1 briggs * must display the following acknowledgement: 20 1.1 briggs * This product includes software developed by Gordon Ross 21 1.1 briggs * 22 1.1 briggs * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 23 1.1 briggs * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 24 1.1 briggs * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 25 1.1 briggs * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 26 1.1 briggs * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 27 1.1 briggs * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 28 1.1 briggs * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 29 1.1 briggs * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 30 1.1 briggs * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 31 1.1 briggs * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 1.1 briggs */ 33 1.15 lukem 34 1.22 mrg #include "opt_m68k_arch.h" 35 1.22 mrg 36 1.15 lukem #include <sys/cdefs.h> 37 1.28 isaki __KERNEL_RCSID(0, "$NetBSD: fpu_calcea.c,v 1.28 2024/12/28 03:11:09 isaki Exp $"); 38 1.1 briggs 39 1.3 briggs #include <sys/param.h> 40 1.1 briggs #include <sys/signal.h> 41 1.4 briggs #include <sys/systm.h> 42 1.1 briggs #include <machine/frame.h> 43 1.10 is #include <m68k/m68k.h> 44 1.1 briggs 45 1.1 briggs #include "fpu_emulate.h" 46 1.1 briggs 47 1.24 tsutsui #ifdef DEBUG_FPE 48 1.24 tsutsui #define DPRINTF(x) printf x 49 1.24 tsutsui #else 50 1.24 tsutsui #define DPRINTF(x) do {} while (/* CONSTCOND */ 0) 51 1.24 tsutsui #endif 52 1.24 tsutsui 53 1.1 briggs /* 54 1.1 briggs * Prototypes of static functions 55 1.1 briggs */ 56 1.23 tsutsui static int decode_ea6(struct frame *, struct instruction *, 57 1.25 isaki struct insn_ea *, int); 58 1.23 tsutsui static int fetch_immed(struct frame *, struct instruction *, int *); 59 1.23 tsutsui static int fetch_disp(struct frame *, struct instruction *, int, int *); 60 1.23 tsutsui static int calc_ea(struct insn_ea *, char *, char **); 61 1.4 briggs 62 1.1 briggs /* 63 1.1 briggs * Helper routines for dealing with "effective address" values. 64 1.1 briggs */ 65 1.1 briggs 66 1.1 briggs /* 67 1.1 briggs * Decode an effective address into internal form. 68 1.1 briggs * Returns zero on success, else signal number. 69 1.1 briggs */ 70 1.1 briggs int 71 1.23 tsutsui fpu_decode_ea(struct frame *frame, struct instruction *insn, 72 1.25 isaki struct insn_ea *ea, int modreg) 73 1.1 briggs { 74 1.23 tsutsui int sig; 75 1.1 briggs 76 1.24 tsutsui #ifdef DIAGNOSTIC 77 1.23 tsutsui if (insn->is_datasize < 0) 78 1.24 tsutsui panic("%s: called with uninitialized datasize", __func__); 79 1.1 briggs #endif 80 1.1 briggs 81 1.23 tsutsui sig = 0; 82 1.1 briggs 83 1.23 tsutsui /* Set the most common value here. */ 84 1.23 tsutsui ea->ea_regnum = 8 + (modreg & 7); 85 1.1 briggs 86 1.23 tsutsui if ((modreg & 060) == 0) { 87 1.23 tsutsui /* register direct */ 88 1.23 tsutsui ea->ea_regnum = modreg & 0xf; 89 1.23 tsutsui ea->ea_flags = EA_DIRECT; 90 1.24 tsutsui DPRINTF(("%s: register direct reg=%d\n", 91 1.26 isaki __func__, ea->ea_regnum)); 92 1.23 tsutsui } else if ((modreg & 077) == 074) { 93 1.23 tsutsui /* immediate */ 94 1.23 tsutsui ea->ea_flags = EA_IMMED; 95 1.23 tsutsui sig = fetch_immed(frame, insn, &ea->ea_immed[0]); 96 1.24 tsutsui DPRINTF(("%s: immediate size=%d\n", 97 1.26 isaki __func__, insn->is_datasize)); 98 1.23 tsutsui } 99 1.23 tsutsui /* 100 1.23 tsutsui * rest of the address modes need to be separately 101 1.23 tsutsui * handled for the LC040 and the others. 102 1.23 tsutsui */ 103 1.10 is #if 0 /* XXX */ 104 1.23 tsutsui else if (frame->f_format == 4 && frame->f_fmt4.f_fa) { 105 1.23 tsutsui /* LC040 */ 106 1.23 tsutsui ea->ea_flags = EA_FRAME_EA; 107 1.23 tsutsui ea->ea_fea = frame->f_fmt4.f_fa; 108 1.24 tsutsui DPRINTF(("%s: 68LC040 - in-frame EA (%p) size %d\n", 109 1.26 isaki __func__, (void *)ea->ea_fea, insn->is_datasize)); 110 1.23 tsutsui if ((modreg & 070) == 030) { 111 1.23 tsutsui /* postincrement mode */ 112 1.23 tsutsui ea->ea_flags |= EA_POSTINCR; 113 1.23 tsutsui } else if ((modreg & 070) == 040) { 114 1.23 tsutsui /* predecrement mode */ 115 1.23 tsutsui ea->ea_flags |= EA_PREDECR; 116 1.10 is #ifdef M68060 117 1.10 is #if defined(M68020) || defined(M68030) || defined(M68040) 118 1.23 tsutsui if (cputype == CPU_68060) 119 1.10 is #endif 120 1.23 tsutsui if (insn->is_datasize == 12) 121 1.23 tsutsui ea->ea_fea -= 8; 122 1.10 is #endif 123 1.23 tsutsui } 124 1.1 briggs } 125 1.10 is #endif /* XXX */ 126 1.23 tsutsui else { 127 1.23 tsutsui /* 020/030 */ 128 1.23 tsutsui switch (modreg & 070) { 129 1.1 briggs 130 1.23 tsutsui case 020: /* (An) */ 131 1.23 tsutsui ea->ea_flags = 0; 132 1.24 tsutsui DPRINTF(("%s: register indirect reg=%d\n", 133 1.26 isaki __func__, ea->ea_regnum)); 134 1.23 tsutsui break; 135 1.1 briggs 136 1.23 tsutsui case 030: /* (An)+ */ 137 1.23 tsutsui ea->ea_flags = EA_POSTINCR; 138 1.24 tsutsui DPRINTF(("%s: reg indirect postincrement reg=%d\n", 139 1.26 isaki __func__, ea->ea_regnum)); 140 1.23 tsutsui break; 141 1.1 briggs 142 1.23 tsutsui case 040: /* -(An) */ 143 1.23 tsutsui ea->ea_flags = EA_PREDECR; 144 1.24 tsutsui DPRINTF(("%s: reg indirect predecrement reg=%d\n", 145 1.26 isaki __func__, ea->ea_regnum)); 146 1.23 tsutsui break; 147 1.1 briggs 148 1.23 tsutsui case 050: /* (d16,An) */ 149 1.23 tsutsui ea->ea_flags = EA_OFFSET; 150 1.23 tsutsui sig = fetch_disp(frame, insn, 1, &ea->ea_offset); 151 1.24 tsutsui DPRINTF(("%s: reg indirect with displacement reg=%d\n", 152 1.26 isaki __func__, ea->ea_regnum)); 153 1.28 isaki break; 154 1.1 briggs 155 1.23 tsutsui case 060: /* (d8,An,Xn) */ 156 1.23 tsutsui ea->ea_flags = EA_INDEXED; 157 1.23 tsutsui sig = decode_ea6(frame, insn, ea, modreg); 158 1.23 tsutsui break; 159 1.1 briggs 160 1.23 tsutsui case 070: /* misc. */ 161 1.23 tsutsui ea->ea_regnum = (modreg & 7); 162 1.23 tsutsui switch (modreg & 7) { 163 1.8 briggs 164 1.23 tsutsui case 0: /* (xxxx).W */ 165 1.23 tsutsui ea->ea_flags = EA_ABS; 166 1.23 tsutsui sig = fetch_disp(frame, insn, 1, 167 1.26 isaki &ea->ea_absaddr); 168 1.24 tsutsui DPRINTF(("%s: absolute address (word)\n", 169 1.26 isaki __func__)); 170 1.23 tsutsui break; 171 1.1 briggs 172 1.23 tsutsui case 1: /* (xxxxxxxx).L */ 173 1.23 tsutsui ea->ea_flags = EA_ABS; 174 1.23 tsutsui sig = fetch_disp(frame, insn, 2, 175 1.26 isaki &ea->ea_absaddr); 176 1.24 tsutsui DPRINTF(("%s: absolute address (long)\n", 177 1.26 isaki __func__)); 178 1.23 tsutsui break; 179 1.1 briggs 180 1.23 tsutsui case 2: /* (d16,PC) */ 181 1.23 tsutsui ea->ea_flags = EA_PC_REL | EA_OFFSET; 182 1.23 tsutsui sig = fetch_disp(frame, insn, 1, 183 1.26 isaki &ea->ea_absaddr); 184 1.24 tsutsui DPRINTF(("%s: pc relative word displacement\n", 185 1.26 isaki __func__)); 186 1.23 tsutsui break; 187 1.1 briggs 188 1.23 tsutsui case 3: /* (d8,PC,Xn) */ 189 1.23 tsutsui ea->ea_flags = EA_PC_REL | EA_INDEXED; 190 1.23 tsutsui sig = decode_ea6(frame, insn, ea, modreg); 191 1.23 tsutsui break; 192 1.8 briggs 193 1.23 tsutsui case 4: /* #data */ 194 1.23 tsutsui /* it should have been taken care of earlier */ 195 1.23 tsutsui default: 196 1.24 tsutsui DPRINTF(("%s: invalid addr mode (7,%d)\n", 197 1.26 isaki __func__, modreg & 7)); 198 1.23 tsutsui return SIGILL; 199 1.23 tsutsui } 200 1.23 tsutsui break; 201 1.23 tsutsui } 202 1.23 tsutsui } 203 1.23 tsutsui ea->ea_moffs = 0; 204 1.1 briggs 205 1.23 tsutsui return sig; 206 1.1 briggs } 207 1.1 briggs 208 1.1 briggs /* 209 1.1 briggs * Decode Mode=6 address modes 210 1.1 briggs */ 211 1.1 briggs static int 212 1.23 tsutsui decode_ea6(struct frame *frame, struct instruction *insn, struct insn_ea *ea, 213 1.25 isaki int modreg) 214 1.1 briggs { 215 1.27 thorpej int idx; 216 1.23 tsutsui int basedisp, outerdisp; 217 1.23 tsutsui int bd_size, od_size; 218 1.23 tsutsui int sig; 219 1.27 thorpej unsigned short extword; 220 1.23 tsutsui 221 1.27 thorpej if (ufetch_short((void *)(insn->is_pc + insn->is_advance), &extword)) 222 1.23 tsutsui return SIGSEGV; 223 1.23 tsutsui insn->is_advance += 2; 224 1.1 briggs 225 1.23 tsutsui /* get register index */ 226 1.23 tsutsui ea->ea_idxreg = (extword >> 12) & 0xf; 227 1.23 tsutsui idx = frame->f_regs[ea->ea_idxreg]; 228 1.23 tsutsui if ((extword & 0x0800) == 0) { 229 1.23 tsutsui /* if word sized index, sign-extend */ 230 1.23 tsutsui idx &= 0xffff; 231 1.23 tsutsui if (idx & 0x8000) { 232 1.23 tsutsui idx |= 0xffff0000; 233 1.23 tsutsui } 234 1.23 tsutsui } 235 1.23 tsutsui /* scale register index */ 236 1.23 tsutsui idx <<= ((extword >> 9) & 3); 237 1.23 tsutsui 238 1.23 tsutsui if ((extword & 0x100) == 0) { 239 1.23 tsutsui /* brief extension word - sign-extend the displacement */ 240 1.23 tsutsui basedisp = (extword & 0xff); 241 1.23 tsutsui if (basedisp & 0x80) { 242 1.23 tsutsui basedisp |= 0xffffff00; 243 1.23 tsutsui } 244 1.23 tsutsui 245 1.23 tsutsui ea->ea_basedisp = idx + basedisp; 246 1.23 tsutsui ea->ea_outerdisp = 0; 247 1.24 tsutsui DPRINTF(("%s: brief ext word idxreg=%d, basedisp=%08x\n", 248 1.26 isaki __func__, ea->ea_idxreg, ea->ea_basedisp)); 249 1.23 tsutsui } else { 250 1.23 tsutsui /* full extension word */ 251 1.23 tsutsui if (extword & 0x80) { 252 1.23 tsutsui ea->ea_flags |= EA_BASE_SUPPRSS; 253 1.23 tsutsui } 254 1.23 tsutsui bd_size = ((extword >> 4) & 3) - 1; 255 1.23 tsutsui od_size = (extword & 3) - 1; 256 1.23 tsutsui sig = fetch_disp(frame, insn, bd_size, &basedisp); 257 1.23 tsutsui if (sig) 258 1.23 tsutsui return sig; 259 1.23 tsutsui if (od_size >= 0) 260 1.23 tsutsui ea->ea_flags |= EA_MEM_INDIR; 261 1.23 tsutsui sig = fetch_disp(frame, insn, od_size, &outerdisp); 262 1.23 tsutsui if (sig) 263 1.23 tsutsui return sig; 264 1.23 tsutsui 265 1.23 tsutsui switch (extword & 0x44) { 266 1.23 tsutsui case 0: /* preindexed */ 267 1.23 tsutsui ea->ea_basedisp = basedisp + idx; 268 1.23 tsutsui ea->ea_outerdisp = outerdisp; 269 1.23 tsutsui break; 270 1.23 tsutsui case 4: /* postindexed */ 271 1.23 tsutsui ea->ea_basedisp = basedisp; 272 1.23 tsutsui ea->ea_outerdisp = outerdisp + idx; 273 1.23 tsutsui break; 274 1.23 tsutsui case 0x40: /* no index */ 275 1.23 tsutsui ea->ea_basedisp = basedisp; 276 1.23 tsutsui ea->ea_outerdisp = outerdisp; 277 1.23 tsutsui break; 278 1.23 tsutsui default: 279 1.24 tsutsui DPRINTF(("%s: invalid indirect mode: ext word %04x\n", 280 1.26 isaki __func__, extword)); 281 1.23 tsutsui return SIGILL; 282 1.23 tsutsui break; 283 1.23 tsutsui } 284 1.24 tsutsui DPRINTF(("%s: full ext idxreg=%d, basedisp=%x, outerdisp=%x\n", 285 1.26 isaki __func__, 286 1.26 isaki ea->ea_idxreg, ea->ea_basedisp, ea->ea_outerdisp)); 287 1.23 tsutsui } 288 1.24 tsutsui DPRINTF(("%s: regnum=%d, flags=%x\n", 289 1.26 isaki __func__, ea->ea_regnum, ea->ea_flags)); 290 1.23 tsutsui return 0; 291 1.1 briggs } 292 1.1 briggs 293 1.1 briggs /* 294 1.1 briggs * Load a value from an effective address. 295 1.1 briggs * Returns zero on success, else signal number. 296 1.1 briggs */ 297 1.1 briggs int 298 1.23 tsutsui fpu_load_ea(struct frame *frame, struct instruction *insn, struct insn_ea *ea, 299 1.25 isaki char *dst) 300 1.1 briggs { 301 1.23 tsutsui int *reg; 302 1.23 tsutsui char *src; 303 1.23 tsutsui int len, step; 304 1.23 tsutsui int sig; 305 1.1 briggs 306 1.8 briggs #ifdef DIAGNOSTIC 307 1.23 tsutsui if (ea->ea_regnum & ~0xF) 308 1.24 tsutsui panic("%s: bad regnum", __func__); 309 1.1 briggs #endif 310 1.1 briggs 311 1.24 tsutsui DPRINTF(("%s: frame at %p\n", __func__, frame)); 312 1.23 tsutsui /* dst is always int or larger. */ 313 1.23 tsutsui len = insn->is_datasize; 314 1.23 tsutsui if (len < 4) 315 1.23 tsutsui dst += (4 - len); 316 1.23 tsutsui step = (len == 1 && ea->ea_regnum == 15 /* sp */) ? 2 : len; 317 1.1 briggs 318 1.11 is #if 0 319 1.23 tsutsui if (ea->ea_flags & EA_FRAME_EA) { 320 1.23 tsutsui /* Using LC040 frame EA */ 321 1.8 briggs #ifdef DEBUG_FPE 322 1.23 tsutsui if (ea->ea_flags & (EA_PREDECR|EA_POSTINCR)) { 323 1.24 tsutsui printf("%s: frame ea %08x w/r%d\n", 324 1.26 isaki __func__, ea->ea_fea, ea->ea_regnum); 325 1.23 tsutsui } else { 326 1.24 tsutsui printf("%s: frame ea %08x\n", __func__, ea->ea_fea); 327 1.23 tsutsui } 328 1.23 tsutsui #endif 329 1.23 tsutsui src = (char *)ea->ea_fea; 330 1.23 tsutsui copyin(src + ea->ea_moffs, dst, len); 331 1.23 tsutsui if (ea->ea_flags & EA_PREDECR) { 332 1.23 tsutsui frame->f_regs[ea->ea_regnum] = ea->ea_fea; 333 1.23 tsutsui ea->ea_fea -= step; 334 1.23 tsutsui ea->ea_moffs = 0; 335 1.23 tsutsui } else if (ea->ea_flags & EA_POSTINCR) { 336 1.23 tsutsui ea->ea_fea += step; 337 1.23 tsutsui frame->f_regs[ea->ea_regnum] = ea->ea_fea; 338 1.23 tsutsui ea->ea_moffs = 0; 339 1.23 tsutsui } else { 340 1.23 tsutsui ea->ea_moffs += step; 341 1.23 tsutsui } 342 1.23 tsutsui /* That's it, folks */ 343 1.23 tsutsui } else 344 1.8 briggs #endif 345 1.23 tsutsui if (ea->ea_flags & EA_DIRECT) { 346 1.23 tsutsui if (len > 4) { 347 1.24 tsutsui DPRINTF(("%s: operand doesn't fit CPU reg\n", 348 1.26 isaki __func__)); 349 1.23 tsutsui return SIGILL; 350 1.23 tsutsui } 351 1.23 tsutsui if (ea->ea_moffs > 0) { 352 1.24 tsutsui DPRINTF(("%s: more than one move from CPU reg\n", 353 1.26 isaki __func__)); 354 1.23 tsutsui return SIGILL; 355 1.23 tsutsui } 356 1.23 tsutsui src = (char *)&frame->f_regs[ea->ea_regnum]; 357 1.23 tsutsui /* The source is an int. */ 358 1.23 tsutsui if (len < 4) { 359 1.23 tsutsui src += (4 - len); 360 1.24 tsutsui DPRINTF(("%s: short/byte opr - addr adjusted\n", 361 1.26 isaki __func__)); 362 1.23 tsutsui } 363 1.24 tsutsui DPRINTF(("%s: src %p\n", __func__, src)); 364 1.23 tsutsui memcpy(dst, src, len); 365 1.23 tsutsui } else if (ea->ea_flags & EA_IMMED) { 366 1.24 tsutsui DPRINTF(("%s: immed %08x%08x%08x size %d\n", __func__, 367 1.26 isaki ea->ea_immed[0], ea->ea_immed[1], ea->ea_immed[2], len)); 368 1.23 tsutsui src = (char *)&ea->ea_immed[0]; 369 1.23 tsutsui if (len < 4) { 370 1.23 tsutsui src += (4 - len); 371 1.25 isaki DPRINTF(("%s: short/byte immed opr - addr adjusted\n", 372 1.26 isaki __func__)); 373 1.23 tsutsui } 374 1.23 tsutsui memcpy(dst, src, len); 375 1.23 tsutsui } else if (ea->ea_flags & EA_ABS) { 376 1.24 tsutsui DPRINTF(("%s: abs addr %08x\n", __func__, ea->ea_absaddr)); 377 1.23 tsutsui src = (char *)ea->ea_absaddr; 378 1.23 tsutsui copyin(src, dst, len); 379 1.25 isaki } else /* register indirect */ { 380 1.23 tsutsui if (ea->ea_flags & EA_PC_REL) { 381 1.24 tsutsui DPRINTF(("%s: using PC\n", __func__)); 382 1.23 tsutsui reg = NULL; 383 1.23 tsutsui /* 384 1.23 tsutsui * Grab the register contents. 4 is offset to the first 385 1.23 tsutsui * extension word from the opcode 386 1.23 tsutsui */ 387 1.23 tsutsui src = (char *)insn->is_pc + 4; 388 1.24 tsutsui DPRINTF(("%s: pc relative pc+4 = %p\n", __func__, src)); 389 1.23 tsutsui } else /* not PC relative */ { 390 1.26 isaki DPRINTF(("%s: using register %c%d\n", 391 1.26 isaki __func__, 392 1.26 isaki (ea->ea_regnum >= 8) ? 'a' : 'd', 393 1.26 isaki ea->ea_regnum & 7)); 394 1.23 tsutsui /* point to the register */ 395 1.23 tsutsui reg = &frame->f_regs[ea->ea_regnum]; 396 1.1 briggs 397 1.23 tsutsui if (ea->ea_flags & EA_PREDECR) { 398 1.24 tsutsui DPRINTF(("%s: predecr mode - " 399 1.26 isaki "reg decremented\n", __func__)); 400 1.23 tsutsui *reg -= step; 401 1.23 tsutsui ea->ea_moffs = 0; 402 1.23 tsutsui } 403 1.1 briggs 404 1.23 tsutsui /* Grab the register contents. */ 405 1.23 tsutsui src = (char *)*reg; 406 1.24 tsutsui DPRINTF(("%s: reg indirect reg = %p\n", __func__, src)); 407 1.23 tsutsui } 408 1.1 briggs 409 1.23 tsutsui sig = calc_ea(ea, src, &src); 410 1.23 tsutsui if (sig) 411 1.23 tsutsui return sig; 412 1.1 briggs 413 1.23 tsutsui copyin(src + ea->ea_moffs, dst, len); 414 1.1 briggs 415 1.23 tsutsui /* do post-increment */ 416 1.23 tsutsui if (ea->ea_flags & EA_POSTINCR) { 417 1.23 tsutsui if (ea->ea_flags & EA_PC_REL) { 418 1.24 tsutsui DPRINTF(("%s: tried to postincrement PC\n", 419 1.26 isaki __func__)); 420 1.23 tsutsui return SIGILL; 421 1.23 tsutsui } 422 1.23 tsutsui *reg += step; 423 1.23 tsutsui ea->ea_moffs = 0; 424 1.24 tsutsui DPRINTF(("%s: postinc mode - reg incremented\n", 425 1.26 isaki __func__)); 426 1.23 tsutsui } else { 427 1.23 tsutsui ea->ea_moffs += len; 428 1.23 tsutsui } 429 1.1 briggs } 430 1.1 briggs 431 1.23 tsutsui return 0; 432 1.1 briggs } 433 1.1 briggs 434 1.1 briggs /* 435 1.1 briggs * Store a value at the effective address. 436 1.1 briggs * Returns zero on success, else signal number. 437 1.1 briggs */ 438 1.1 briggs int 439 1.23 tsutsui fpu_store_ea(struct frame *frame, struct instruction *insn, struct insn_ea *ea, 440 1.25 isaki char *src) 441 1.1 briggs { 442 1.23 tsutsui int *reg; 443 1.23 tsutsui char *dst; 444 1.23 tsutsui int len, step; 445 1.23 tsutsui int sig; 446 1.1 briggs 447 1.24 tsutsui #ifdef DIAGNOSTIC 448 1.23 tsutsui if (ea->ea_regnum & ~0xf) 449 1.24 tsutsui panic("%s: bad regnum", __func__); 450 1.1 briggs #endif 451 1.1 briggs 452 1.23 tsutsui if (ea->ea_flags & (EA_IMMED|EA_PC_REL)) { 453 1.23 tsutsui /* not alterable address mode */ 454 1.24 tsutsui DPRINTF(("%s: not alterable address mode\n", __func__)); 455 1.23 tsutsui return SIGILL; 456 1.23 tsutsui } 457 1.1 briggs 458 1.23 tsutsui /* src is always int or larger. */ 459 1.23 tsutsui len = insn->is_datasize; 460 1.23 tsutsui if (len < 4) 461 1.23 tsutsui src += (4 - len); 462 1.23 tsutsui step = (len == 1 && ea->ea_regnum == 15 /* sp */) ? 2 : len; 463 1.23 tsutsui 464 1.23 tsutsui if (ea->ea_flags & EA_FRAME_EA) { 465 1.23 tsutsui /* Using LC040 frame EA */ 466 1.23 tsutsui #ifdef DEBUG_FPE 467 1.23 tsutsui if (ea->ea_flags & (EA_PREDECR|EA_POSTINCR)) { 468 1.24 tsutsui printf("%s: frame ea %08x w/r%d\n", 469 1.26 isaki __func__, ea->ea_fea, ea->ea_regnum); 470 1.23 tsutsui } else { 471 1.24 tsutsui printf("%s: frame ea %08x\n", __func__, ea->ea_fea); 472 1.23 tsutsui } 473 1.23 tsutsui #endif 474 1.23 tsutsui dst = (char *)ea->ea_fea; 475 1.23 tsutsui copyout(src, dst + ea->ea_moffs, len); 476 1.23 tsutsui if (ea->ea_flags & EA_PREDECR) { 477 1.23 tsutsui frame->f_regs[ea->ea_regnum] = ea->ea_fea; 478 1.23 tsutsui ea->ea_fea -= step; 479 1.23 tsutsui ea->ea_moffs = 0; 480 1.23 tsutsui } else if (ea->ea_flags & EA_POSTINCR) { 481 1.23 tsutsui ea->ea_fea += step; 482 1.23 tsutsui frame->f_regs[ea->ea_regnum] = ea->ea_fea; 483 1.23 tsutsui ea->ea_moffs = 0; 484 1.23 tsutsui } else { 485 1.23 tsutsui ea->ea_moffs += step; 486 1.23 tsutsui } 487 1.23 tsutsui /* That's it, folks */ 488 1.23 tsutsui } else if (ea->ea_flags & EA_ABS) { 489 1.24 tsutsui DPRINTF(("%s: abs addr %08x\n", __func__, ea->ea_absaddr)); 490 1.23 tsutsui dst = (char *)ea->ea_absaddr; 491 1.23 tsutsui copyout(src, dst + ea->ea_moffs, len); 492 1.23 tsutsui ea->ea_moffs += len; 493 1.23 tsutsui } else if (ea->ea_flags & EA_DIRECT) { 494 1.23 tsutsui if (len > 4) { 495 1.24 tsutsui DPRINTF(("%s: operand doesn't fit CPU reg\n", 496 1.26 isaki __func__)); 497 1.23 tsutsui return SIGILL; 498 1.23 tsutsui } 499 1.23 tsutsui if (ea->ea_moffs > 0) { 500 1.24 tsutsui DPRINTF(("%s: more than one move to CPU reg\n", 501 1.26 isaki __func__)); 502 1.23 tsutsui return SIGILL; 503 1.23 tsutsui } 504 1.23 tsutsui dst = (char *)&frame->f_regs[ea->ea_regnum]; 505 1.23 tsutsui /* The destination is an int. */ 506 1.23 tsutsui if (len < 4) { 507 1.23 tsutsui dst += (4 - len); 508 1.24 tsutsui DPRINTF(("%s: short/byte opr - dst addr adjusted\n", 509 1.26 isaki __func__)); 510 1.23 tsutsui } 511 1.24 tsutsui DPRINTF(("%s: dst %p\n", __func__, dst)); 512 1.23 tsutsui memcpy(dst, src, len); 513 1.23 tsutsui } else /* One of MANY indirect forms... */ { 514 1.24 tsutsui DPRINTF(("%s: using register %c%d\n", __func__, 515 1.26 isaki (ea->ea_regnum >= 8) ? 'a' : 'd', ea->ea_regnum & 7)); 516 1.23 tsutsui /* point to the register */ 517 1.23 tsutsui reg = &(frame->f_regs[ea->ea_regnum]); 518 1.1 briggs 519 1.23 tsutsui /* do pre-decrement */ 520 1.23 tsutsui if (ea->ea_flags & EA_PREDECR) { 521 1.24 tsutsui DPRINTF(("%s: predecr mode - reg decremented\n", 522 1.26 isaki __func__)); 523 1.23 tsutsui *reg -= step; 524 1.23 tsutsui ea->ea_moffs = 0; 525 1.23 tsutsui } 526 1.1 briggs 527 1.23 tsutsui /* calculate the effective address */ 528 1.23 tsutsui sig = calc_ea(ea, (char *)*reg, &dst); 529 1.23 tsutsui if (sig) 530 1.23 tsutsui return sig; 531 1.1 briggs 532 1.24 tsutsui DPRINTF(("%s: dst addr=%p+%d\n", __func__, dst, ea->ea_moffs)); 533 1.23 tsutsui copyout(src, dst + ea->ea_moffs, len); 534 1.1 briggs 535 1.23 tsutsui /* do post-increment */ 536 1.23 tsutsui if (ea->ea_flags & EA_POSTINCR) { 537 1.23 tsutsui *reg += step; 538 1.23 tsutsui ea->ea_moffs = 0; 539 1.24 tsutsui DPRINTF(("%s: postinc mode - reg incremented\n", 540 1.26 isaki __func__)); 541 1.23 tsutsui } else { 542 1.23 tsutsui ea->ea_moffs += len; 543 1.23 tsutsui } 544 1.1 briggs } 545 1.1 briggs 546 1.23 tsutsui return 0; 547 1.1 briggs } 548 1.1 briggs 549 1.1 briggs /* 550 1.1 briggs * fetch_immed: fetch immediate operand 551 1.1 briggs */ 552 1.1 briggs static int 553 1.20 dsl fetch_immed(struct frame *frame, struct instruction *insn, int *dst) 554 1.1 briggs { 555 1.23 tsutsui int data, ext_bytes; 556 1.27 thorpej unsigned short sval; 557 1.1 briggs 558 1.23 tsutsui ext_bytes = insn->is_datasize; 559 1.1 briggs 560 1.23 tsutsui if (0 < ext_bytes) { 561 1.27 thorpej if (ufetch_short((void *)(insn->is_pc + insn->is_advance), 562 1.27 thorpej &sval)) 563 1.23 tsutsui return SIGSEGV; 564 1.27 thorpej data = sval; 565 1.23 tsutsui if (ext_bytes == 1) { 566 1.23 tsutsui /* sign-extend byte to long */ 567 1.23 tsutsui data &= 0xff; 568 1.23 tsutsui if (data & 0x80) 569 1.23 tsutsui data |= 0xffffff00; 570 1.23 tsutsui } else if (ext_bytes == 2) { 571 1.23 tsutsui /* sign-extend word to long */ 572 1.23 tsutsui data &= 0xffff; 573 1.23 tsutsui if (data & 0x8000) 574 1.28 isaki data |= 0xffff0000; 575 1.23 tsutsui } 576 1.23 tsutsui insn->is_advance += 2; 577 1.23 tsutsui dst[0] = data; 578 1.23 tsutsui } 579 1.23 tsutsui if (2 < ext_bytes) { 580 1.27 thorpej if (ufetch_short((void *)(insn->is_pc + insn->is_advance), 581 1.27 thorpej &sval)) 582 1.23 tsutsui return SIGSEGV; 583 1.23 tsutsui insn->is_advance += 2; 584 1.23 tsutsui dst[0] <<= 16; 585 1.27 thorpej dst[0] |= sval; 586 1.23 tsutsui } 587 1.23 tsutsui if (4 < ext_bytes) { 588 1.27 thorpej if (ufetch_short((void *)(insn->is_pc + insn->is_advance), 589 1.27 thorpej &sval)) 590 1.23 tsutsui return SIGSEGV; 591 1.27 thorpej data = sval; 592 1.23 tsutsui dst[1] = data << 16; 593 1.27 thorpej if (ufetch_short((void *)(insn->is_pc + insn->is_advance + 2), 594 1.27 thorpej &sval)) 595 1.23 tsutsui return SIGSEGV; 596 1.23 tsutsui insn->is_advance += 4; 597 1.27 thorpej dst[1] |= sval; 598 1.23 tsutsui } 599 1.23 tsutsui if (8 < ext_bytes) { 600 1.27 thorpej if (ufetch_short((void *)(insn->is_pc + insn->is_advance), 601 1.27 thorpej &sval)) 602 1.23 tsutsui return SIGSEGV; 603 1.27 thorpej data = sval; 604 1.23 tsutsui dst[2] = data << 16; 605 1.27 thorpej if (ufetch_short((void *)(insn->is_pc + insn->is_advance + 2), 606 1.27 thorpej &sval)) 607 1.23 tsutsui return SIGSEGV; 608 1.23 tsutsui insn->is_advance += 4; 609 1.27 thorpej dst[2] |= sval; 610 1.1 briggs } 611 1.1 briggs 612 1.23 tsutsui return 0; 613 1.1 briggs } 614 1.1 briggs 615 1.1 briggs /* 616 1.12 toshii * fetch_disp: fetch displacement in full extension words 617 1.1 briggs */ 618 1.1 briggs static int 619 1.21 dsl fetch_disp(struct frame *frame, struct instruction *insn, int size, int *res) 620 1.1 briggs { 621 1.23 tsutsui int disp, word; 622 1.27 thorpej unsigned short sval; 623 1.1 briggs 624 1.23 tsutsui if (size == 1) { 625 1.27 thorpej if (ufetch_short((void *)(insn->is_pc + insn->is_advance), 626 1.27 thorpej &sval)) 627 1.23 tsutsui return SIGSEGV; 628 1.27 thorpej disp = sval; 629 1.23 tsutsui if (disp & 0x8000) { 630 1.23 tsutsui /* sign-extend */ 631 1.23 tsutsui disp |= 0xffff0000; 632 1.23 tsutsui } 633 1.23 tsutsui insn->is_advance += 2; 634 1.23 tsutsui } else if (size == 2) { 635 1.27 thorpej if (ufetch_short((void *)(insn->is_pc + insn->is_advance), 636 1.27 thorpej &sval)) 637 1.23 tsutsui return SIGSEGV; 638 1.27 thorpej word = sval; 639 1.23 tsutsui disp = word << 16; 640 1.27 thorpej if (ufetch_short((void *)(insn->is_pc + insn->is_advance + 2), 641 1.27 thorpej &sval)) 642 1.23 tsutsui return SIGSEGV; 643 1.27 thorpej disp |= sval; 644 1.23 tsutsui insn->is_advance += 4; 645 1.23 tsutsui } else { 646 1.23 tsutsui disp = 0; 647 1.1 briggs } 648 1.23 tsutsui *res = disp; 649 1.23 tsutsui return 0; 650 1.1 briggs } 651 1.1 briggs 652 1.1 briggs /* 653 1.1 briggs * Calculates an effective address for all address modes except for 654 1.1 briggs * register direct, absolute, and immediate modes. However, it does 655 1.1 briggs * not take care of predecrement/postincrement of register content. 656 1.1 briggs * Returns a signal value (0 == no error). 657 1.1 briggs */ 658 1.1 briggs static int 659 1.21 dsl calc_ea(struct insn_ea *ea, char *ptr, char **eaddr) 660 1.21 dsl /* ptr: base address (usually a register content) */ 661 1.21 dsl /* eaddr: pointer to result pointer */ 662 1.1 briggs { 663 1.27 thorpej int word; 664 1.27 thorpej unsigned short sval; 665 1.1 briggs 666 1.24 tsutsui DPRINTF(("%s: reg indirect (reg) = %p\n", __func__, ptr)); 667 1.1 briggs 668 1.23 tsutsui if (ea->ea_flags & EA_OFFSET) { 669 1.23 tsutsui /* apply the signed offset */ 670 1.24 tsutsui DPRINTF(("%s: offset %d\n", __func__, ea->ea_offset)); 671 1.23 tsutsui ptr += ea->ea_offset; 672 1.23 tsutsui } else if (ea->ea_flags & EA_INDEXED) { 673 1.24 tsutsui DPRINTF(("%s: indexed mode\n", __func__)); 674 1.1 briggs 675 1.23 tsutsui if (ea->ea_flags & EA_BASE_SUPPRSS) { 676 1.23 tsutsui /* base register is suppressed */ 677 1.23 tsutsui ptr = (char *)ea->ea_basedisp; 678 1.23 tsutsui } else { 679 1.23 tsutsui ptr += ea->ea_basedisp; 680 1.23 tsutsui } 681 1.1 briggs 682 1.23 tsutsui if (ea->ea_flags & EA_MEM_INDIR) { 683 1.24 tsutsui DPRINTF(("%s: mem indir mode: basedisp=%08x, " 684 1.26 isaki "outerdisp=%08x\n", 685 1.26 isaki __func__, ea->ea_basedisp, ea->ea_outerdisp)); 686 1.24 tsutsui DPRINTF(("%s: addr fetched from %p\n", __func__, ptr)); 687 1.23 tsutsui /* memory indirect modes */ 688 1.27 thorpej if (ufetch_short((u_short *)ptr, &sval)) 689 1.23 tsutsui return SIGSEGV; 690 1.27 thorpej word = sval; 691 1.23 tsutsui word <<= 16; 692 1.27 thorpej if (ufetch_short((u_short *)(ptr + 2), &sval)) 693 1.23 tsutsui return SIGSEGV; 694 1.27 thorpej word |= sval; 695 1.24 tsutsui DPRINTF(("%s: fetched ptr 0x%08x\n", __func__, word)); 696 1.23 tsutsui ptr = (char *)word + ea->ea_outerdisp; 697 1.23 tsutsui } 698 1.1 briggs } 699 1.1 briggs 700 1.23 tsutsui *eaddr = ptr; 701 1.1 briggs 702 1.23 tsutsui return 0; 703 1.1 briggs } 704