1/* 2 * fp_scan.S 3 * 4 * Copyright Roman Zippel, 1997. All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, and the entire permission notice in its entirety, 11 * including the disclaimer of warranties. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. The name of the author may not be used to endorse or promote 16 * products derived from this software without specific prior 17 * written permission. 18 * 19 * ALTERNATIVELY, this product may be distributed under the terms of 20 * the GNU General Public License, in which case the provisions of the GPL are 21 * required INSTEAD OF the above restrictions. (This clause is 22 * necessary due to a potential bad interaction between the GPL and 23 * the restrictions contained in a BSD-style copyright.) 24 * 25 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED 26 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 27 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 28 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, 29 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 30 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 31 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 33 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 34 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 35 * OF THE POSSIBILITY OF SUCH DAMAGE. 36 */ 37 38#include "fp_emu.h" 39#include "fp_decode.h" 40 41 .globl fp_scan, fp_datasize 42 43 .data 44 45| %d2 - first two instr words 46| %d1 - operand size 47 48/* operand formats are: 49 50 Long = 0, i.e. fmove.l 51 Single, i.e. fmove.s 52 Extended, i.e. fmove.x 53 Packed-BCD, i.e. fmove.p 54 Word, i.e. fmove.w 55 Double, i.e. fmove.d 56*/ 57 58 .text 59 60| On entry: 61| FPDATA - base of emulated FPU registers 62 63fp_scan: 64| normal fpu instruction? (this excludes fsave/frestore) 65 fp_get_pc %a0 66 printf PDECODE,"%08x: ",1,%a0 67 getuser.b (%a0),%d0,fp_err_ua1,%a0 68#if 1 69 cmp.b #0xf2,%d0 | cpid = 1 70#else 71 cmp.b #0xfc,%d0 | cpid = 6 72#endif 73 jne fp_nonstd 74| first two instruction words are kept in %d2 75 getuser.l (%a0)+,%d2,fp_err_ua1,%a0 76 fp_put_pc %a0 77fp_decode_cond: | separate conditional instr 78 fp_decode_cond_instr_type 79 80 .long fp_decode_move, fp_fscc 81 .long fp_fbccw, fp_fbccl 82 83fp_decode_move: | separate move instr 84 fp_decode_move_instr_type 85 86 .long fp_fgen_fp, fp_ill 87 .long fp_fgen_ea, fp_fmove_fp2mem 88 .long fp_fmovem_cr, fp_fmovem_cr 89 .long fp_fmovem_fp, fp_fmovem_fp 90 91| now all arithmetic instr and a few move instr are left 92fp_fgen_fp: | source is a fpu register 93 clr.b (FPD_FPSR+2,FPDATA) | clear the exception byte 94 fp_decode_sourcespec 95 printf PDECODE,"f<op>.x fp%d",1,%d0 96 fp_get_fp_reg 97 lea (FPD_TEMPFP1,FPDATA),%a1 | copy src into a temp location 98 move.l (%a0)+,(%a1)+ 99 move.l (%a0)+,(%a1)+ 100 move.l (%a0),(%a1) 101 lea (-8,%a1),%a0 102 jra fp_getdest 103 104fp_fgen_ea: | source is <ea> 105 clr.b (FPD_FPSR+2,FPDATA) | clear the exception byte 106 | sort out fmovecr, keep data size in %d1 107 fp_decode_sourcespec 108 cmp.w #7,%d0 109 jeq fp_fmovecr 110 move.w %d0,%d1 | store data size twice in %d1 111 swap %d1 | one can be trashed below 112 move.w %d0,%d1 113#ifdef FPU_EMU_DEBUG 114 lea 0f,%a0 115 clr.l %d0 116 move.b (%a0,%d1.w),%d0 117 printf PDECODE,"f<op>.%c ",1,%d0 118 119 .data 1200: .byte 'l','s','x','p','w','d','b',0 121 .previous 122#endif 123 124/* 125 fp_getsource, fp_getdest 126 127 basically, we end up with a pointer to the source operand in 128 %a1, and a pointer to the destination operand in %a0. both 129 are, of course, 96-bit extended floating point numbers. 130*/ 131 132fp_getsource: 133 | decode addressing mode for source 134 fp_decode_addr_mode 135 136 .long fp_data, fp_ill 137 .long fp_indirect, fp_postinc 138 .long fp_predecr, fp_disp16 139 .long fp_extmode0, fp_extmode1 140 141 | addressing mode: data register direct 142fp_data: 143 fp_mode_data_direct 144 jsr fp_get_data_reg 145 lea (FPD_TEMPFP1,FPDATA),%a0 146 jmp ([0f:w,%pc,%d1.w*4]) 147 148 .align 4 1490: 150 .long fp_data_long, fp_data_single 151 .long fp_ill, fp_ill 152 .long fp_data_word, fp_ill 153 .long fp_data_byte, fp_ill 154 155 | data types that fit in an integer data register 156fp_data_byte: 157 extb.l %d0 158 jra fp_data_long 159 160fp_data_word: 161 ext.l %d0 162 163fp_data_long: 164 jsr fp_conv_long2ext 165 jra fp_getdest 166 167fp_data_single: 168 jsr fp_conv_single2ext 169 jra fp_getdest 170 171 | addressing mode: address register indirect 172fp_indirect: 173 fp_mode_addr_indirect 174 jra fp_fetchsource 175 176 | addressing mode: address register indirect with postincrement 177fp_postinc: 178 fp_mode_addr_indirect_postinc 179 jra fp_fetchsource 180 181 | addressing mode: address register indirect with predecrement 182fp_predecr: 183 fp_mode_addr_indirect_predec 184 jra fp_fetchsource 185 186 | addressing mode: address register/programm counter indirect 187 | with 16bit displacement 188fp_disp16: 189 fp_mode_addr_indirect_disp16 190 jra fp_fetchsource 191 192 | all other indirect addressing modes will finally end up here 193fp_extmode0: 194 fp_mode_addr_indirect_extmode0 195 jra fp_fetchsource 196 197| all pc relative addressing modes and immediate/absolute modes end up here 198| the first ones are sent to fp_extmode0 or fp_disp16 199| and only the latter are handled here 200fp_extmode1: 201 fp_decode_addr_reg 202 jmp ([0f:w,%pc,%d0*4]) 203 204 .align 4 2050: 206 .long fp_abs_short, fp_abs_long 207 .long fp_disp16, fp_extmode0 208 .long fp_immediate, fp_ill 209 .long fp_ill, fp_ill 210 211 | addressing mode: absolute short 212fp_abs_short: 213 fp_mode_abs_short 214 jra fp_fetchsource 215 216 | addressing mode: absolute long 217fp_abs_long: 218 fp_mode_abs_long 219 jra fp_fetchsource 220 221 | addressing mode: immediate data 222fp_immediate: 223 printf PDECODE,"#" 224 fp_get_pc %a0 225 move.w (fp_datasize,%d1.w*2),%d0 226 addq.w #1,%d0 227 and.w #-2,%d0 228#ifdef FPU_EMU_DEBUG 229 movem.l %d0/%d1,-(%sp) 230 movel %a0,%a1 231 clr.l %d1 232 jra 2f 2331: getuser.b (%a1)+,%d1,fp_err_ua1,%a1 234 printf PDECODE,"%02x",1,%d1 2352: dbra %d0,1b 236 movem.l (%sp)+,%d0/%d1 237#endif 238 lea (%a0,%d0.w),%a1 239 fp_put_pc %a1 240| jra fp_fetchsource 241 242fp_fetchsource: 243 move.l %a0,%a1 244 swap %d1 245 lea (FPD_TEMPFP1,FPDATA),%a0 246 jmp ([0f:w,%pc,%d1.w*4]) 247 248 .align 4 2490: .long fp_long, fp_single 250 .long fp_ext, fp_pack 251 .long fp_word, fp_double 252 .long fp_byte, fp_ill 253 254fp_long: 255 getuser.l (%a1),%d0,fp_err_ua1,%a1 256 jsr fp_conv_long2ext 257 jra fp_getdest 258 259fp_single: 260 getuser.l (%a1),%d0,fp_err_ua1,%a1 261 jsr fp_conv_single2ext 262 jra fp_getdest 263 264fp_ext: 265 getuser.l (%a1)+,%d0,fp_err_ua1,%a1 266 lsr.l #8,%d0 267 lsr.l #7,%d0 268 lsr.w #1,%d0 269 move.l %d0,(%a0)+ 270 getuser.l (%a1)+,%d0,fp_err_ua1,%a1 271 move.l %d0,(%a0)+ 272 getuser.l (%a1),%d0,fp_err_ua1,%a1 273 move.l %d0,(%a0) 274 subq.l #8,%a0 275 jra fp_getdest 276 277fp_pack: 278 /* not supported yet */ 279 jra fp_ill 280 281fp_word: 282 getuser.w (%a1),%d0,fp_err_ua1,%a1 283 ext.l %d0 284 jsr fp_conv_long2ext 285 jra fp_getdest 286 287fp_double: 288 jsr fp_conv_double2ext 289 jra fp_getdest 290 291fp_byte: 292 getuser.b (%a1),%d0,fp_err_ua1,%a1 293 extb.l %d0 294 jsr fp_conv_long2ext 295| jra fp_getdest 296 297fp_getdest: 298 move.l %a0,%a1 299 bfextu %d2{#22,#3},%d0 300 printf PDECODE,",fp%d\n",1,%d0 301 fp_get_fp_reg 302 movem.l %a0/%a1,-(%sp) 303 pea fp_finalrounding 304 bfextu %d2{#25,#7},%d0 305 jmp ([0f:w,%pc,%d0*4]) 306 307 .align 4 3080: 309 .long fp_fmove_mem2fp, fp_fint, fp_fsinh, fp_fintrz 310 .long fp_fsqrt, fp_ill, fp_flognp1, fp_ill 311 .long fp_fetoxm1, fp_ftanh, fp_fatan, fp_ill 312 .long fp_fasin, fp_fatanh, fp_fsin, fp_ftan 313 .long fp_fetox, fp_ftwotox, fp_ftentox, fp_ill 314 .long fp_flogn, fp_flog10, fp_flog2, fp_ill 315 .long fp_fabs, fp_fcosh, fp_fneg, fp_ill 316 .long fp_facos, fp_fcos, fp_fgetexp, fp_fgetman 317 .long fp_fdiv, fp_fmod, fp_fadd, fp_fmul 318 .long fpa_fsgldiv, fp_frem, fp_fscale, fpa_fsglmul 319 .long fp_fsub, fp_ill, fp_ill, fp_ill 320 .long fp_ill, fp_ill, fp_ill, fp_ill 321 .long fp_fsincos0, fp_fsincos1, fp_fsincos2, fp_fsincos3 322 .long fp_fsincos4, fp_fsincos5, fp_fsincos6, fp_fsincos7 323 .long fp_fcmp, fp_ill, fp_ftst, fp_ill 324 .long fp_ill, fp_ill, fp_ill, fp_ill 325 .long fp_fsmove, fp_fssqrt, fp_ill, fp_ill 326 .long fp_fdmove, fp_fdsqrt, fp_ill, fp_ill 327 .long fp_ill, fp_ill, fp_ill, fp_ill 328 .long fp_ill, fp_ill, fp_ill, fp_ill 329 .long fp_ill, fp_ill, fp_ill, fp_ill 330 .long fp_ill, fp_ill, fp_ill, fp_ill 331 .long fp_fsabs, fp_ill, fp_fsneg, fp_ill 332 .long fp_fdabs, fp_ill, fp_fdneg, fp_ill 333 .long fp_fsdiv, fp_ill, fp_fsadd, fp_fsmul 334 .long fp_fddiv, fp_ill, fp_fdadd, fp_fdmul 335 .long fp_fssub, fp_ill, fp_ill, fp_ill 336 .long fp_fdsub, fp_ill, fp_ill, fp_ill 337 .long fp_ill, fp_ill, fp_ill, fp_ill 338 .long fp_ill, fp_ill, fp_ill, fp_ill 339 .long fp_ill, fp_ill, fp_ill, fp_ill 340 .long fp_ill, fp_ill, fp_ill, fp_ill 341 342 | Instructions follow 343 344 | Move an (emulated) ROM constant 345fp_fmovecr: 346 bfextu %d2{#27,#5},%d0 347 printf PINSTR,"fp_fmovecr #%d",1,%d0 348 move.l %d0,%d1 349 add.l %d0,%d0 350 add.l %d1,%d0 351 lea (fp_constants,%d0*4),%a0 352 move.l #0x801cc0ff,%d0 353 addq.l #1,%d1 354 lsl.l %d1,%d0 355 jcc 1f 356 fp_set_sr FPSR_EXC_INEX2 | INEX2 exception 3571: moveq #-128,%d0 | continue with fmove 358 and.l %d0,%d2 359 jra fp_getdest 360 361 .data 362 .align 4 363fp_constants: 364 .long 0x00004000,0xc90fdaa2,0x2168c235 | pi 365 .extend 0,0,0,0,0,0,0,0,0,0 366 .long 0x00003ffd,0x9a209a84,0xfbcff798 | log10(2) 367 .long 0x00004000,0xadf85458,0xa2bb4a9a | e 368 .long 0x00003fff,0xb8aa3b29,0x5c17f0bc | log2(e) 369 .long 0x00003ffd,0xde5bd8a9,0x37287195 | log10(e) 370 .long 0x00000000,0x00000000,0x00000000 | 0.0 371 .long 0x00003ffe,0xb17217f7,0xd1cf79ac | 1n(2) 372 .long 0x00004000,0x935d8ddd,0xaaa8ac17 | 1n(10) 373 | read this as "1.0 * 2^0" - note the high bit in the mantissa 374 .long 0x00003fff,0x80000000,0x00000000 | 10^0 375 .long 0x00004002,0xa0000000,0x00000000 | 10^1 376 .long 0x00004005,0xc8000000,0x00000000 | 10^2 377 .long 0x0000400c,0x9c400000,0x00000000 | 10^4 378 .long 0x00004019,0xbebc2000,0x00000000 | 10^8 379 .long 0x00004034,0x8e1bc9bf,0x04000000 | 10^16 380 .long 0x00004069,0x9dc5ada8,0x2b70b59e | 10^32 381 .long 0x000040d3,0xc2781f49,0xffcfa6d5 | 10^64 382 .long 0x000041a8,0x93ba47c9,0x80e98ce0 | 10^128 383 .long 0x00004351,0xaa7eebfb,0x9df9de8e | 10^256 384 .long 0x000046a3,0xe319a0ae,0xa60e91c7 | 10^512 385 .long 0x00004d48,0xc9767586,0x81750c17 | 10^1024 386 .long 0x00005a92,0x9e8b3b5d,0xc53d5de5 | 10^2048 387 .long 0x00007525,0xc4605202,0x8a20979b | 10^4096 388 .previous 389 390fp_fmove_mem2fp: 391 printf PINSTR,"fmove %p,%p\n",2,%a0,%a1 392 move.l (%a1)+,(%a0)+ 393 move.l (%a1)+,(%a0)+ 394 move.l (%a1),(%a0) 395 subq.l #8,%a0 396 rts 397 398fpa_fsglmul: 399 move.l #fp_finalrounding_single_fast,(%sp) 400 jra fp_fsglmul 401 402fpa_fsgldiv: 403 move.l #fp_finalrounding_single_fast,(%sp) 404 jra fp_fsgldiv 405 406.macro fp_dosingleprec instr 407 printf PINSTR,"single " 408 move.l #fp_finalrounding_single,(%sp) 409 jra \instr 410.endm 411 412.macro fp_dodoubleprec instr 413 printf PINSTR,"double " 414 move.l #fp_finalrounding_double,(%sp) 415 jra \instr 416.endm 417 418fp_fsmove: 419 fp_dosingleprec fp_fmove_mem2fp 420 421fp_fssqrt: 422 fp_dosingleprec fp_fsqrt 423 424fp_fdmove: 425 fp_dodoubleprec fp_fmove_mem2fp 426 427fp_fdsqrt: 428 fp_dodoubleprec fp_fsqrt 429 430fp_fsabs: 431 fp_dosingleprec fp_fabs 432 433fp_fsneg: 434 fp_dosingleprec fp_fneg 435 436fp_fdabs: 437 fp_dodoubleprec fp_fabs 438 439fp_fdneg: 440 fp_dodoubleprec fp_fneg 441 442fp_fsdiv: 443 fp_dosingleprec fp_fdiv 444 445fp_fsadd: 446 fp_dosingleprec fp_fadd 447 448fp_fsmul: 449 fp_dosingleprec fp_fmul 450 451fp_fddiv: 452 fp_dodoubleprec fp_fdiv 453 454fp_fdadd: 455 fp_dodoubleprec fp_fadd 456 457fp_fdmul: 458 fp_dodoubleprec fp_fmul 459 460fp_fssub: 461 fp_dosingleprec fp_fsub 462 463fp_fdsub: 464 fp_dodoubleprec fp_fsub 465 466fp_nonstd: 467 fp_get_pc %a0 468 getuser.l (%a0),%d0,fp_err_ua1,%a0 469 printf ,"nonstd ((%08x)=%08x)\n",2,%a0,%d0 470 moveq #-1,%d0 471 rts 472 473 .data 474 .align 4 475 476 | data sizes corresponding to the operand formats 477fp_datasize: 478 .word 4, 4, 12, 12, 2, 8, 1, 0 479