|
|
1.1 ! root 1: #! /bin/sh ! 2: ! 3: # $Id: m68k-insns-auto.sh,v 1.19 2003/05/16 21:48:11 fredette Exp $ ! 4: ! 5: # ic/m68k/m68k-insns-auto.sh - automatically generates C code ! 6: # for many m68k emulation instructions: ! 7: ! 8: # ! 9: # Copyright (c) 2002, 2003 Matt Fredette ! 10: # All rights reserved. ! 11: # ! 12: # Redistribution and use in source and binary forms, with or without ! 13: # modification, are permitted provided that the following conditions ! 14: # are met: ! 15: # 1. Redistributions of source code must retain the above copyright ! 16: # notice, this list of conditions and the following disclaimer. ! 17: # 2. Redistributions in binary form must reproduce the above copyright ! 18: # notice, this list of conditions and the following disclaimer in the ! 19: # documentation and/or other materials provided with the distribution. ! 20: # 3. All advertising materials mentioning features or use of this software ! 21: # must display the following acknowledgement: ! 22: # This product includes software developed by Matt Fredette. ! 23: # 4. The name of the author may not be used to endorse or promote products ! 24: # derived from this software without specific prior written permission. ! 25: # ! 26: # THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR ! 27: # IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ! 28: # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ! 29: # DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, ! 30: # INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ! 31: # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR ! 32: # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ! 33: # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, ! 34: # STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ! 35: # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE ! 36: # POSSIBILITY OF SUCH DAMAGE. ! 37: # ! 38: ! 39: header=false ! 40: ! 41: for option ! 42: do ! 43: case $option in ! 44: --header) header=true ;; ! 45: esac ! 46: done ! 47: ! 48: PROG=`basename $0` ! 49: cat <<EOF ! 50: /* automatically generated by $PROG, do not edit! */ ! 51: _TME_RCSID("\$Id: m68k-insns-auto.sh,v 1.19 2003/05/16 21:48:11 fredette Exp $"); ! 52: ! 53: EOF ! 54: if $header; then :; else ! 55: cat <<EOF ! 56: #include "m68k-impl.h" ! 57: ! 58: EOF ! 59: fi ! 60: ! 61: # permute for the three different operand sizes we need to handle: ! 62: for size in 8 16 32; do ! 63: ! 64: # the shifts needed to get register contents of a specific size: ! 65: case ${size} in ! 66: 8) reg_size_shift=' << 2' ;; ! 67: 16) reg_size_shift=' << 1' ;; ! 68: 32) reg_size_shift='' ;; ! 69: esac ! 70: ! 71: # generate the ALU functions: ! 72: for name in add sub cmp neg or and eor not tst move moveq clr cmpa negx addx subx cmpm; do ! 73: ! 74: # characterize each operation: ! 75: optype=normal ; src=op0 ; dst=op1 ; res=op1 ; arith=no ; with_x=false ; store_res=true ! 76: case "$name" in ! 77: add) op=' + ' ; arith=add ;; ! 78: sub) op=' - ' ; arith=sub ;; ! 79: cmp) op=' - ' ; arith=sub ; store_res=false ;; ! 80: neg) op=' - ' ; arith=sub ; dst=0 ; src=op1 ;; ! 81: or) op=' | ' ;; ! 82: and) op=' & ' ;; ! 83: eor) op=' ^ ' ;; ! 84: not) op='~ ' ; dst= ; src=op1 ;; ! 85: tst) op='' ; dst= ; src=op1 ; store_res=false ;; ! 86: move) op='' ; dst= ; src=op1 ; res=op0 ;; ! 87: moveq) op='' ; dst= ; src=opc8 ; if test ${size} != 32; then continue; fi ;; ! 88: clr) op='' ; dst= ; src=0 ;; ! 89: cmpa) op=' - ' ; arith=sub ; src=op0.16s32 ; store_res=false ! 90: if test $size != 16; then continue; fi ;; ! 91: negx) op=' - ' ; arith=sub ; with_x=true ; dst=0 ; src=op1 ;; ! 92: addx) op=' + ' ; arith=add ; optype=mathx ; with_x=true ;; ! 93: subx) op=' - ' ; arith=sub ; optype=mathx ; with_x=true ;; ! 94: cmpm) op=' - ' ; arith=sub ; optype=mathx ; store_res=false ;; ! 95: *) echo "$0 internal error: unknown ALU function $name" 1>&2 ; exit 1 ;; ! 96: esac ! 97: ! 98: # placeholder for another permutation: ! 99: : ! 100: ! 101: # if we're making the header, just emit a declaration: ! 102: if $header; then ! 103: echo "TME_M68K_INSN_DECL(tme_m68k_${name}${size});" ! 104: continue ! 105: fi ! 106: ! 107: # open the function: ! 108: echo "" ! 109: echo -n "/* this does a ${size}-bit \"$name " ! 110: case "${src}/${dst}" in *op0*) echo -n "SRC, " ;; esac ! 111: echo "DST\": */" ! 112: echo "TME_M68K_INSN(tme_m68k_${name}${size})" ! 113: echo "{" ! 114: ! 115: # declare our locals: ! 116: if test $name = cmpa; then size=32; fi ! 117: echo -n " tme_uint${size}_t res" ! 118: case "${src}/${dst}" in *op0*) echo -n ", op0" ;; esac ! 119: case "${src}/${dst}" in *op1*) echo -n ", op1" ;; esac ! 120: echo ";" ! 121: echo " tme_uint8_t flags;" ! 122: ! 123: # load the operand(s): ! 124: echo "" ! 125: echo " /* load the operand(s): */" ! 126: case ${optype} in ! 127: mathx) ! 128: echo " unsigned int function_code = TME_M68K_FUNCTION_CODE_DATA(ic);" ! 129: ! 130: # NB: in my 68000 Programmer's Manual, the description ! 131: # of subx is a little backwards from addx and cmpm. in ! 132: # subx, the reg field at bits 0-2 is called the "x" ! 133: # field, where in addx and cmpm it's called the "y" ! 134: # field, and similarly for the reg field at bits 9-11. ! 135: # fortunately, the meanings of the two reg fields is ! 136: # always the same despite this - the reg field at bits ! 137: # 0-2 always identifies the source operand, and the ! 138: # reg field at bits 9-11 always identifies the ! 139: # destination operand: ! 140: echo " int ireg_src = TME_FIELD_EXTRACTU(TME_M68K_INSN_OPCODE, 0, 3);" ! 141: echo " int ireg_dst = TME_FIELD_EXTRACTU(TME_M68K_INSN_OPCODE, 9, 3);" ! 142: ! 143: # the stack pointer must always be adjusted by a multiple of two. ! 144: # assuming ireg < 8, ((ireg + 1) >> 3) == 1 iff ireg == 7, meaning %a7: ! 145: echo -n " tme_uint32_t ireg_src_adjust = sizeof(tme_uint${size}_t)"; ! 146: if test ${size} = 8; then ! 147: echo -n " + ((ireg_src + 1) >> 3)" ! 148: fi ! 149: echo ";" ! 150: echo -n " tme_uint32_t ireg_dst_adjust = sizeof(tme_uint${size}_t)"; ! 151: if test ${size} = 8; then ! 152: echo -n " + ((ireg_dst + 1) >> 3)" ! 153: fi ! 154: echo ";" ! 155: ! 156: case ${name} in ! 157: ! 158: # cmpm always uses memory and is always postincrement: ! 159: cmpm) ! 160: echo "" ! 161: echo " TME_M68K_INSN_CANFAULT;" ! 162: echo "" ! 163: echo " if (!TME_M68K_SEQUENCE_RESTARTING) {" ! 164: echo " ic->_tme_m68k_ea_function_code = function_code;" ! 165: echo " ic->_tme_m68k_ea_address = ic->tme_m68k_ireg_uint32(TME_M68K_IREG_A0 + ireg_dst);" ! 166: echo " ic->tme_m68k_ireg_uint32(TME_M68K_IREG_A0 + ireg_dst) += ireg_dst_adjust;" ! 167: echo " }" ! 168: echo " tme_m68k_read_memx${size}(ic);" ! 169: echo " if (!TME_M68K_SEQUENCE_RESTARTING) {" ! 170: echo " ic->_tme_m68k_ea_function_code = function_code;" ! 171: echo " ic->_tme_m68k_ea_address = ic->tme_m68k_ireg_uint32(TME_M68K_IREG_A0 + ireg_src);" ! 172: echo " ic->tme_m68k_ireg_uint32(TME_M68K_IREG_A0 + ireg_src) += ireg_src_adjust;" ! 173: echo " }" ! 174: echo " tme_m68k_read_mem${size}(ic, TME_M68K_IREG_MEMY${size});" ! 175: echo " ${dst} = ic->tme_m68k_ireg_memx${size};" ! 176: echo " ${src} = ic->tme_m68k_ireg_memy${size};" ! 177: ;; ! 178: ! 179: # addx and subx use either registers or memory. if they use memory, ! 180: # they always predecrement: ! 181: addx|subx) ! 182: echo " tme_uint16_t memory;" ! 183: echo "" ! 184: echo " memory = (TME_M68K_INSN_OPCODE & TME_BIT(3));" ! 185: echo " if (memory) {" ! 186: echo " TME_M68K_INSN_CANFAULT;" ! 187: echo " if (!TME_M68K_SEQUENCE_RESTARTING) {" ! 188: echo " ic->tme_m68k_ireg_uint32(TME_M68K_IREG_A0 + ireg_dst) -= ireg_dst_adjust;" ! 189: echo " ic->_tme_m68k_ea_function_code = function_code;" ! 190: echo " ic->_tme_m68k_ea_address = ic->tme_m68k_ireg_uint32(TME_M68K_IREG_A0 + ireg_dst);" ! 191: echo " }" ! 192: echo " tme_m68k_read_memx${size}(ic);" ! 193: echo " if (!TME_M68K_SEQUENCE_RESTARTING) {" ! 194: echo " ic->tme_m68k_ireg_uint32(TME_M68K_IREG_A0 + ireg_src) -= ireg_src_adjust;" ! 195: echo " ic->_tme_m68k_ea_function_code = function_code;" ! 196: echo " ic->_tme_m68k_ea_address = ic->tme_m68k_ireg_uint32(TME_M68K_IREG_A0 + ireg_src);" ! 197: echo " }" ! 198: echo " tme_m68k_read_mem${size}(ic, TME_M68K_IREG_MEMY${size});" ! 199: echo " ${dst} = ic->tme_m68k_ireg_memx${size};" ! 200: echo " ${src} = ic->tme_m68k_ireg_memy${size};" ! 201: echo " }" ! 202: echo " else {" ! 203: echo " ${src} = ic->tme_m68k_ireg_uint${size}((TME_M68K_IREG_D0 + ireg_src)${reg_size_shift});" ! 204: echo " ${dst} = ic->tme_m68k_ireg_uint${size}((TME_M68K_IREG_D0 + ireg_dst)${reg_size_shift});" ! 205: echo " }" ! 206: ;; ! 207: *) echo "$0 internal error: unknown mathx ${name}" 1>&2 ; exit 1 ;; ! 208: esac ! 209: ;; ! 210: normal) ! 211: for which in src dst; do ! 212: eval 'what=$'${which} ! 213: case "x${what}" in ! 214: x|x0) ;; ! 215: xop[01].16s32) ! 216: what=`echo ${what} | sed -e 's/\..*//'` ! 217: eval ${which}"=${what}" ! 218: echo " ${what} = (tme_uint32_t) ((tme_int32_t) *((tme_int16_t *) _${what}));" ! 219: ;; ! 220: xop[01]) ! 221: echo " ${what} = *((tme_uint${size}_t *) _${what});" ! 222: ;; ! 223: xopc8) ! 224: eval ${which}"='TME_EXT_S8_U${size}((tme_int8_t) (TME_M68K_INSN_OPCODE & 0xff))'" ! 225: ;; ! 226: *) echo "$0 internal error: unknown what ${what}" 1>&2 ; exit 1 ;; ! 227: esac ! 228: done ! 229: ;; ! 230: *) echo "$0 internal error: unknown optype ${optype}" 1>&2 ; exit 1 ;; ! 231: esac ! 232: ! 233: # perform the operation: ! 234: echo "" ! 235: echo " /* perform the operation: */" ! 236: echo -n " res = ${dst}${op}${src}" ! 237: if $with_x; then ! 238: echo -n "${op}((ic->tme_m68k_ireg_ccr / TME_M68K_FLAG_X) & 1)" ! 239: fi ! 240: echo ";" ! 241: ! 242: # store the result: ! 243: if $store_res; then ! 244: echo "" ! 245: echo " /* store the result: */" ! 246: case ${optype} in ! 247: mathx) ! 248: echo " if (memory) {" ! 249: echo " if (!TME_M68K_SEQUENCE_RESTARTING) {" ! 250: echo " ic->tme_m68k_ireg_memx${size} = res;" ! 251: echo " ic->_tme_m68k_ea_function_code = function_code;" ! 252: echo " ic->_tme_m68k_ea_address = ic->tme_m68k_ireg_uint32(TME_M68K_IREG_A0 + ireg_dst);" ! 253: echo " }" ! 254: echo " tme_m68k_write_memx${size}(ic);" ! 255: echo " }" ! 256: echo " else {" ! 257: echo " ic->tme_m68k_ireg_uint${size}((TME_M68K_IREG_D0 + ireg_dst)${reg_size_shift}) = res;" ! 258: echo " }" ! 259: ;; ! 260: normal) ! 261: echo " *((tme_uint${size}_t *) _${res}) = res;" ! 262: ;; ! 263: *) echo "$0 internal error: unknown optype ${optype}" 1>&2 ; exit 1 ;; ! 264: esac ! 265: fi ! 266: ! 267: # start the status flags, maybe preserving X: ! 268: echo "" ! 269: echo " /* set the flags: */" ! 270: case "${name}:${arith}" in ! 271: cmp*|*:no) ! 272: flag_x= ! 273: ;; ! 274: *) ! 275: flag_x=" | TME_M68K_FLAG_X" ! 276: ;; ! 277: esac ! 278: ! 279: # set N. we cast to tme_uint8_t as soon as we know the ! 280: # bit we want is within the range of the type, to try ! 281: # to affect the generated assembly: ! 282: echo " flags = ((tme_uint8_t) (((tme_uint${size}_t) res) >> (${size} - 1))) * TME_M68K_FLAG_N;" ! 283: ! 284: # set Z: ! 285: if $with_x; then ! 286: echo " if (res == 0) flags |= (ic->tme_m68k_ireg_ccr & TME_M68K_FLAG_Z);" ! 287: else ! 288: echo " if (res == 0) flags |= TME_M68K_FLAG_Z;" ! 289: fi ! 290: ! 291: # set V and C and maybe X: ! 292: case $arith in ! 293: add) ! 294: case $size in ! 295: 8) ones="0xff" ;; ! 296: 16) ones="0xffff" ;; ! 297: 32) ones="0xffffffff" ;; ! 298: esac ! 299: # if the operands are the same sign, and the result has ! 300: # a different sign, set V. we cast to tme_uint8_t as ! 301: # soon as we know the bit we want is within the range ! 302: # of the type, to try to affect the generated assembly: ! 303: echo " flags |= ((tme_uint8_t) (((${src} ^ ${dst} ^ ${ones}) & (${dst} ^ res)) >> (${size} - 1))) * TME_M68K_FLAG_V;" ! 304: # if src is greater than the logical inverse of dst, set C: ! 305: echo -n " if (${src} > (${dst} ^ ${ones})" ! 306: if $with_x; then ! 307: echo -n " || (${src} == (${dst} ^ ${ones}) && (ic->tme_m68k_ireg_ccr & TME_M68K_FLAG_X))" ! 308: fi ! 309: echo ") flags |= TME_M68K_FLAG_C${flag_x};" ! 310: ;; ! 311: sub) ! 312: # if the operands are different signs, and the result has ! 313: # a different sign from the first operand, set V. we ! 314: # cast to tme_uint8_t as soon as we know the bit we want ! 315: # is within the range of the type, to try to affect the ! 316: # generated assembly: ! 317: echo " flags |= ((tme_uint8_t) (((${src} ^ ${dst}) & (${dst} ^ res)) >> (${size} - 1))) * TME_M68K_FLAG_V;" ! 318: # if src is greater than dst, set C: ! 319: echo -n " if (${src} > ${dst}" ! 320: if $with_x; then ! 321: echo -n " || (${src} == ${dst} && (ic->tme_m68k_ireg_ccr & TME_M68K_FLAG_X))" ! 322: fi ! 323: echo ") flags |= TME_M68K_FLAG_C${flag_x};" ! 324: ;; ! 325: no) ;; ! 326: esac ! 327: ! 328: # preserve X: ! 329: if test "x${flag_x}" = x; then ! 330: echo " flags |= (ic->tme_m68k_ireg_ccr & TME_M68K_FLAG_X);" ! 331: fi ! 332: ! 333: # set the flags: ! 334: echo " ic->tme_m68k_ireg_ccr = flags;" ! 335: ! 336: # done: ! 337: echo "" ! 338: echo " TME_M68K_INSN_OK;" ! 339: echo "}" ! 340: ! 341: if test $name = cmpa; then size=16; fi ! 342: done ! 343: ! 344: # generate the address math functions: ! 345: for name in suba adda movea; do ! 346: ! 347: # the address math functions don't need an 8-bit version: ! 348: if test $size = 8; then continue; fi ! 349: ! 350: # if we're making the header, just emit a declaration: ! 351: if $header; then ! 352: echo "TME_M68K_INSN_DECL(tme_m68k_${name}${size});" ! 353: continue ! 354: fi ! 355: ! 356: echo "" ! 357: echo "/* the ${name} function on a ${size}-byte EA: */" ! 358: echo "TME_M68K_INSN(tme_m68k_${name}${size})" ! 359: echo "{" ! 360: case $name in ! 361: suba) op='-' ; src="_op0" ; dst="_op1" ;; ! 362: adda) op='+' ; src="_op0" ; dst="_op1" ;; ! 363: movea) op='' ; src="_op1" ; dst="_op0" ;; ! 364: esac ! 365: echo " *((tme_int32_t *) ${dst}) ${op}= *((tme_int${size}_t *) ${src});" ! 366: echo " TME_M68K_INSN_OK;" ! 367: echo "}" ! 368: done ! 369: ! 370: # generate the bit functions: ! 371: for name in btst bchg bclr bset; do ! 372: ! 373: # the bit functions don't need a 16-bit version: ! 374: if test $size = 16; then continue; fi ! 375: ! 376: # if we're making the header, just emit a declaration: ! 377: if $header; then ! 378: echo "TME_M68K_INSN_DECL(tme_m68k_${name}${size});" ! 379: continue ! 380: fi ! 381: ! 382: echo "" ! 383: echo "/* the ${name} function on a ${size}-byte EA: */" ! 384: echo "TME_M68K_INSN(tme_m68k_${name}${size})" ! 385: echo "{" ! 386: echo " tme_uint${size}_t value, bit;" ! 387: echo " bit = _TME_BIT(tme_uint${size}_t, TME_M68K_INSN_OP0(tme_uint8_t) & (${size} - 1));" ! 388: echo " value = TME_M68K_INSN_OP1(tme_uint${size}_t);" ! 389: echo " if (value & bit) {" ! 390: echo " ic->tme_m68k_ireg_ccr &= ~TME_M68K_FLAG_Z;" ! 391: echo " }" ! 392: echo " else {" ! 393: echo " ic->tme_m68k_ireg_ccr |= TME_M68K_FLAG_Z;" ! 394: echo " }" ! 395: case ${name} in ! 396: btst) ;; ! 397: bchg) echo " TME_M68K_INSN_OP1(tme_uint${size}_t) = value ^ bit;" ;; ! 398: bclr) echo " TME_M68K_INSN_OP1(tme_uint${size}_t) = value & ~bit;" ;; ! 399: bset) echo " TME_M68K_INSN_OP1(tme_uint${size}_t) = value | bit;" ;; ! 400: esac ! 401: echo " TME_M68K_INSN_OK;" ! 402: echo "}" ! 403: done ! 404: ! 405: # generate the shift/rotate functions: ! 406: for func in as ls ro rox; do ! 407: for dir in l r; do ! 408: name="${func}${dir}" ! 409: ! 410: # if we're making the header, just emit a declaration: ! 411: if $header; then ! 412: echo "TME_M68K_INSN_DECL(tme_m68k_${name}${size});" ! 413: continue ! 414: fi ! 415: ! 416: echo "" ! 417: echo "/* the ${name} function on a ${size}-byte EA: */" ! 418: echo "TME_M68K_INSN(tme_m68k_${name}${size})" ! 419: echo "{" ! 420: echo " unsigned int count;" ! 421: sign=u ! 422: case "${name}" in ! 423: asr) sign= ;; ! 424: asl) echo " tme_uint${size}_t sign_bits;" ;; ! 425: rox[lr]) echo " tme_uint8_t xbit;" ;; ! 426: *) ;; ! 427: esac ! 428: echo " tme_${sign}int${size}_t res;" ! 429: echo " tme_uint8_t flags;" ! 430: echo "" ! 431: echo " /* get the count and operand: */" ! 432: echo " count = TME_M68K_INSN_OP0(tme_uint8_t) & 63;" ! 433: echo " res = TME_M68K_INSN_OP1(tme_${sign}int${size}_t);" ! 434: ! 435: echo "" ! 436: echo " /* generate the X, V, and C flags assuming the count is zero: */" ! 437: echo " flags = ic->tme_m68k_ireg_ccr & TME_M68K_FLAG_X;" ! 438: case "${name}" in ! 439: rox[lr]) ! 440: echo " xbit = (flags / TME_M68K_FLAG_X);" ! 441: echo " flags |= (xbit * TME_M68K_FLAG_C);" ! 442: ;; ! 443: esac ! 444: ! 445: echo "" ! 446: echo " /* if the count is nonzero, update the result and" ! 447: echo " generate the X, V, and C flags: */" ! 448: echo " if (count > 0) {" ! 449: case "${name}" in ! 450: [al]sr) ! 451: echo " if (63 > SHIFTMAX_INT${size}_T" ! 452: echo " && count > ${size}) {" ! 453: echo " res = 0;" ! 454: echo " }" ! 455: echo " res >>= (count - 1);" ! 456: echo " flags = (res & 1);" ! 457: echo " flags *= TME_M68K_FLAG_C;" ! 458: echo " flags |= (flags * TME_M68K_FLAG_X);" ! 459: echo " res >>= 1;" ! 460: ;; ! 461: [al]sl) ! 462: if test ${name} = asl; then ! 463: echo "" ! 464: echo " /* we need to see how the sign of the result will change during" ! 465: echo " shifting in order to generate V." ! 466: echo "" ! 467: echo " in general, the idea is to get all of the bits that will ever" ! 468: echo " appear in the sign position into sign_bits; if sign_bits is" ! 469: echo " all-bits-one or all-bits zero, clear V, else set V. a good trick" ! 470: echo " is that ((sign_bits + 1) & sign_bits) is nonzero iff all of the" ! 471: echo " bits in sign_bits are the same." ! 472: echo "" ! 473: echo " start by loading all of the operand into sign_bits." ! 474: echo "" ! 475: echo " if the shift count is exactly ${size} - 1, then all of the bits" ! 476: echo " of the operand will appear in the sign position." ! 477: echo "" ! 478: echo " if the shift count is less than ${size} - 1, then some of the" ! 479: echo " less significant bits of the operand will never appear in the" ! 480: echo " sign position, so we can shift them off of sign_bits now." ! 481: echo "" ! 482: echo " if the shift count is greater than ${size} - 1, then all of the" ! 483: echo " bits in the operand, plus at least one zero bit, will appear in" ! 484: echo " the sign position. the only way that the sign bit will never" ! 485: echo " change during the shift is if the operand was zero to begin with." ! 486: echo " we need to change sign_bits such that ((sign_bits + 1) &" ! 487: echo " sign_bits) will be zero iff the operand was zero to begin with." ! 488: echo " the magic below does just that: */" ! 489: echo " sign_bits = res;" ! 490: fi ! 491: echo " if (63 > SHIFTMAX_INT${size}_T" ! 492: echo " && count > ${size}) {" ! 493: echo " res = 0;" ! 494: echo " }" ! 495: echo " res <<= (count - 1);" ! 496: echo " flags = (res >> (${size} - 1));" ! 497: echo " flags *= TME_M68K_FLAG_C;" ! 498: echo " flags |= (flags * TME_M68K_FLAG_X);" ! 499: echo " res <<= 1;" ! 500: if test ${name} = asl; then ! 501: echo " if (count != ${size} - 1) {" ! 502: echo " if (count < ${size}) {" ! 503: echo " sign_bits >>= ((${size} - 1) - count);" ! 504: echo " }" ! 505: echo " else {" ! 506: echo " sign_bits |= (sign_bits << 1);" ! 507: echo " sign_bits &= -2;" ! 508: echo " }" ! 509: echo " }" ! 510: echo " if ((sign_bits + 1) & sign_bits) {" ! 511: echo " flags |= TME_M68K_FLAG_V;" ! 512: echo " }" ! 513: fi ! 514: ;; ! 515: ro[lr]) ! 516: echo " count &= (${size} - 1);" ! 517: if test $dir = l; then ! 518: echo " res = (res << count) | (res >> (${size} - count));" ! 519: echo " flags |= ((res & 1) * TME_M68K_FLAG_C);" ! 520: else ! 521: echo " res = (res << (${size} - count)) | (res >> count);" ! 522: echo " flags |= ((res >> (${size} - 1)) * TME_M68K_FLAG_C);" ! 523: fi ! 524: ;; ! 525: rox[lr]) ! 526: echo " count %= (${size} + 1);" ! 527: echo " flags = xbit;" ! 528: echo " if (count > 0) {" ! 529: if test $dir = l; then ! 530: echo " flags = (res >> (${size} - count)) & 1;" ! 531: echo " if (${size} > SHIFTMAX_INT${size}_T" ! 532: echo " && count == ${size}) {" ! 533: echo " res = 0 | (xbit << (${size} - 1)) | (res >> ((${size} + 1) - ${size}));" ! 534: echo " }" ! 535: echo " else if (${size} > SHIFTMAX_INT${size}_T" ! 536: echo " && count == 1) {" ! 537: echo " res = (res << 1) | (xbit << (1 - 1)) | 0;" ! 538: echo " }" ! 539: echo " else {" ! 540: echo " res = (res << count) | (xbit << (count - 1)) | (res >> ((${size} + 1) - count));" ! 541: echo " }" ! 542: else ! 543: echo " flags = (res >> (count - 1)) & 1;" ! 544: echo " if (${size} > SHIFTMAX_INT${size}_T" ! 545: echo " && count == ${size}) {" ! 546: echo " res = (res << ((${size} + 1) - ${size})) | (xbit << (${size} - ${size})) | 0;" ! 547: echo " }" ! 548: echo " else if (${size} > SHIFTMAX_INT${size}_T" ! 549: echo " && count == 1) {" ! 550: echo " res = 0 | (xbit << (${size} - 1)) | (res >> 1);" ! 551: echo " }" ! 552: echo " else {" ! 553: echo " res = (res << ((${size} + 1) - count)) | (xbit << (${size} - count)) | (res >> count);" ! 554: echo " }" ! 555: fi ! 556: echo " }" ! 557: echo " flags *= TME_M68K_FLAG_C;" ! 558: echo " flags |= (flags * TME_M68K_FLAG_X);" ! 559: ;; ! 560: esac ! 561: echo " }" ! 562: ! 563: echo "" ! 564: echo " /* store the result: */" ! 565: echo " TME_M68K_INSN_OP1(tme_${sign}int${size}_t) = res;" ! 566: ! 567: echo "" ! 568: echo " /* generate the N flag. we cast to tme_uint8_t as soon as we" ! 569: echo " know the bit we want is within the range of the type, to try" ! 570: echo " to affect the generated assembly: */" ! 571: echo " flags |= ((tme_uint8_t) (((tme_uint${size}_t) res) >> (${size} - 1))) * TME_M68K_FLAG_N;" ! 572: ! 573: echo "" ! 574: echo " /* generate the Z flag: */" ! 575: echo " if (res == 0) flags |= TME_M68K_FLAG_Z;" ! 576: ! 577: echo "" ! 578: echo " /* store the flags: */" ! 579: echo " ic->tme_m68k_ireg_ccr = flags;" ! 580: echo " TME_M68K_INSN_OK;" ! 581: echo "}" ! 582: done ! 583: done ! 584: ! 585: # movep_rm, movep_mr, movem_rm, and movem_mr: ! 586: for name in rm mr; do ! 587: ! 588: # movep and movem don't need 8-bit versions: ! 589: if test ${size} = 8; then continue; fi ! 590: ! 591: # if we're making the header, just emit declarations: ! 592: if $header; then ! 593: echo "TME_M68K_INSN_DECL(tme_m68k_movep_${name}${size});" ! 594: echo "TME_M68K_INSN_DECL(tme_m68k_movem_${name}${size});" ! 595: continue ! 596: fi ! 597: ! 598: # emit the movep function: ! 599: echo "" ! 600: echo "/* the movep_${name} function on a ${size}-bit dreg: */" ! 601: echo "TME_M68K_INSN(tme_m68k_movep_${name}${size})" ! 602: echo "{" ! 603: echo " unsigned int function_code;" ! 604: echo " tme_uint32_t linear_address;" ! 605: if test $name = rm; then ! 606: echo " tme_uint${size}_t value;" ! 607: fi ! 608: echo " int dreg;" ! 609: echo "" ! 610: echo " TME_M68K_INSN_CANFAULT;" ! 611: echo "" ! 612: echo " function_code = TME_M68K_FUNCTION_CODE_DATA(ic);" ! 613: echo " linear_address = TME_M68K_INSN_OP1(tme_uint32_t);" ! 614: echo " linear_address += (tme_int32_t) ((tme_int16_t) TME_M68K_INSN_SPECOP);" ! 615: echo " dreg = TME_M68K_IREG_D0 + TME_FIELD_EXTRACTU(TME_M68K_INSN_OPCODE, 9, 3);" ! 616: ! 617: # set value: ! 618: if test $name = rm; then ! 619: echo " value = ic->tme_m68k_ireg_uint${size}(dreg${reg_size_shift});" ! 620: value="value" ! 621: else ! 622: value="ic->tme_m68k_ireg_uint${size}(dreg${reg_size_shift})" ! 623: fi ! 624: ! 625: # transfer the bytes: ! 626: pos=${size} ! 627: while test $pos != 0; do ! 628: pos=`expr ${pos} - 8` ! 629: echo " if (!TME_M68K_SEQUENCE_RESTARTING) {" ! 630: echo " ic->_tme_m68k_ea_function_code = function_code;" ! 631: echo " ic->_tme_m68k_ea_address = linear_address;" ! 632: if test $name = rm; then ! 633: echo " ic->tme_m68k_ireg_memx8 = TME_FIELD_EXTRACTU(${value}, ${pos}, 8);" ! 634: echo " }" ! 635: echo " tme_m68k_write_memx8(ic);" ! 636: else ! 637: echo " }" ! 638: echo " tme_m68k_read_memx8(ic);" ! 639: echo " if (!TME_M68K_SEQUENCE_RESTARTING) {" ! 640: echo " TME_FIELD_DEPOSIT${size}(${value}, ${pos}, 8, ic->tme_m68k_ireg_memx8);" ! 641: echo " }" ! 642: fi ! 643: echo " linear_address += 2;" ! 644: done ! 645: ! 646: echo " TME_M68K_INSN_OK;" ! 647: echo "}" ! 648: ! 649: # emit the movem function: ! 650: echo "" ! 651: echo "/* the movem_${name} function on ${size}-bit registers: */" ! 652: echo "TME_M68K_INSN(tme_m68k_movem_${name}${size})" ! 653: echo "{" ! 654: echo " int ireg, direction;" ! 655: echo " tme_uint16_t mask, bit;" ! 656: echo " unsigned int ea_mode;" ! 657: echo " tme_uint32_t addend;" ! 658: ! 659: echo "" ! 660: echo " TME_M68K_INSN_CANFAULT;" ! 661: echo "" ! 662: echo " /* figure out what direction to move in, and where to start from: */" ! 663: echo " ea_mode = TME_FIELD_EXTRACTU(TME_M68K_INSN_OPCODE, 3, 3);" ! 664: echo " direction = 1;" ! 665: echo " ireg = TME_M68K_IREG_D0;" ! 666: if test $name = rm; then ! 667: echo " if (ea_mode == 4) {" ! 668: echo " direction = -1;" ! 669: echo " ireg = TME_M68K_IREG_A7;" ! 670: echo " if (!TME_M68K_SEQUENCE_RESTARTING) {" ! 671: echo " ic->_tme_m68k_ea_address -= sizeof(tme_uint${size}_t);" ! 672: echo " }" ! 673: echo " }" ! 674: fi ! 675: echo " addend = (tme_uint32_t) (direction * sizeof(tme_uint${size}_t));" ! 676: ! 677: echo "" ! 678: echo " /* do the transfer: */" ! 679: echo " mask = TME_M68K_INSN_SPECOP;" ! 680: echo " for (bit = 1; bit != 0; bit <<= 1) {" ! 681: echo " if (mask & bit) {" ! 682: if test $name = rm; then ! 683: echo " if (!TME_M68K_SEQUENCE_RESTARTING) {" ! 684: echo " ic->tme_m68k_ireg_memx${size} = ic->tme_m68k_ireg_uint${size}(ireg${reg_size_shift});" ! 685: echo " }" ! 686: echo " tme_m68k_write_memx${size}(ic);" ! 687: echo " if (!TME_M68K_SEQUENCE_RESTARTING) {" ! 688: else ! 689: echo " tme_m68k_read_memx${size}(ic);" ! 690: echo " if (!TME_M68K_SEQUENCE_RESTARTING) {" ! 691: echo -n " ic->tme_m68k_ireg_uint32(ireg) = " ! 692: if test $size = 32; then ! 693: echo "ic->tme_m68k_ireg_memx${size};" ! 694: else ! 695: echo "TME_EXT_S${size}_U32((tme_int${size}_t) ic->tme_m68k_ireg_memx${size});" ! 696: fi ! 697: fi ! 698: echo " ic->_tme_m68k_ea_address += addend;" ! 699: echo " }" ! 700: echo " }" ! 701: echo " ireg += direction;" ! 702: echo " }" ! 703: echo "" ! 704: ! 705: # for the predecrement and postincrement modes, update the ! 706: # address register: ! 707: if test $name = rm; then ! 708: echo " /* if this is the predecrement mode, update the address register: */" ! 709: echo " if (ea_mode == 4) {" ! 710: echo " ic->tme_m68k_ireg_uint32(TME_M68K_IREG_A0" ! 711: echo " + TME_FIELD_EXTRACTU(TME_M68K_INSN_OPCODE, 0, 3))" ! 712: echo " = (ic->_tme_m68k_ea_address + sizeof(tme_uint${size}_t));" ! 713: echo " }" ! 714: else ! 715: echo " /* if this is the postincrement mode, update the address register: */" ! 716: echo " if (ea_mode == 3) {" ! 717: echo " ic->tme_m68k_ireg_uint32(TME_M68K_IREG_A0" ! 718: echo " + TME_FIELD_EXTRACTU(TME_M68K_INSN_OPCODE, 0, 3))" ! 719: echo " = ic->_tme_m68k_ea_address;" ! 720: echo " }" ! 721: fi ! 722: ! 723: echo " TME_M68K_INSN_OK;" ! 724: echo "}" ! 725: done ! 726: ! 727: # chk32 and chk16: ! 728: if test $size != 8; then ! 729: ! 730: # if we're making the header, just emit a declaration: ! 731: if $header; then ! 732: echo "TME_M68K_INSN_DECL(tme_m68k_chk${size});" ! 733: else ! 734: echo "" ! 735: echo "/* chk${size}: */" ! 736: echo "TME_M68K_INSN(tme_m68k_chk${size})" ! 737: echo "{" ! 738: echo " if (*((tme_int${size}_t *) _op0) < 0) {" ! 739: echo " ic->tme_m68k_ireg_ccr |= TME_M68K_FLAG_N;" ! 740: echo " ic->tme_m68k_ireg_pc = ic->tme_m68k_ireg_pc_next;" ! 741: echo " TME_M68K_INSN_EXCEPTION(TME_M68K_EXCEPTION_GROUP2(6));" ! 742: echo " }" ! 743: echo " if (*((tme_int${size}_t *) _op0) > *((tme_int${size}_t *) _op1)) {" ! 744: echo " ic->tme_m68k_ireg_ccr &= ~TME_M68K_FLAG_N;" ! 745: echo " ic->tme_m68k_ireg_pc = ic->tme_m68k_ireg_pc_next;" ! 746: echo " TME_M68K_INSN_EXCEPTION(TME_M68K_EXCEPTION_GROUP2(6));" ! 747: echo " }" ! 748: echo " TME_M68K_INSN_OK;" ! 749: echo "}" ! 750: fi ! 751: fi ! 752: ! 753: # cas and cas2: ! 754: for name in cas cas2_; do ! 755: ! 756: # cas2 doesn't do byte operands: ! 757: buffers=x ! 758: if test $name = cas2_; then ! 759: if test $size = 8; then continue; fi ! 760: buffers="x y" ! 761: fi ! 762: ! 763: if $header; then ! 764: echo "TME_M68K_INSN_DECL(tme_m68k_${name}${size});" ! 765: else ! 766: echo "" ! 767: echo "/* ${name}${size}: */" ! 768: echo "TME_M68K_INSN(tme_m68k_${name}${size})" ! 769: echo "{" ! 770: echo " struct tme_m68k_tlb *tlb;" ! 771: echo " int ireg_dc, ireg_du;" ! 772: echo " int do_write;" ! 773: echo " tme_uint16_t specopx = ic->_tme_m68k_insn_specop;" ! 774: if test $name = cas2_; then ! 775: echo " tme_uint16_t specopy = ic->_tme_m68k_insn_specop2;" ! 776: echo " tme_uint32_t addrx;" ! 777: echo " tme_uint32_t addry;" ! 778: echo "" ! 779: echo " /* get the function code and addresses we'll be dealing with: */" ! 780: echo " ic->_tme_m68k_ea_function_code = TME_M68K_FUNCTION_CODE_DATA(ic);" ! 781: echo " addrx = ic->tme_m68k_ireg_uint32(TME_M68K_IREG_D0" ! 782: echo " + TME_FIELD_EXTRACTU(specopx, 12, 4));" ! 783: echo " addry = ic->tme_m68k_ireg_uint32(TME_M68K_IREG_D0" ! 784: echo " + TME_FIELD_EXTRACTU(specopy, 12, 4));" ! 785: fi ! 786: echo "" ! 787: echo " /* start the read/modify/write cycle: */" ! 788: echo " tlb = tme_m68k_rmw_start(ic);" ! 789: echo " if (tlb == NULL) {" ! 790: echo " TME_M68K_INSN_OK;" ! 791: echo " }" ! 792: echo "" ! 793: echo " /* read: */" ! 794: for buffer in $buffers; do ! 795: if test $name = cas2_; then ! 796: echo " ic->_tme_m68k_ea_address = addr${buffer};" ! 797: fi ! 798: echo " tme_m68k_read${size}(ic, tlb," ! 799: echo " &ic->_tme_m68k_ea_function_code," ! 800: echo " &ic->_tme_m68k_ea_address," ! 801: echo " &ic->tme_m68k_ireg_mem${buffer}${size}," ! 802: echo " TME_M68K_BUS_CYCLE_RMW);" ! 803: done ! 804: ! 805: echo "" ! 806: echo " /* modify: */" ! 807: for buffer in $buffers; do ! 808: i= ! 809: if test $buffer = y; then ! 810: echo " if (ic->tme_m68k_ireg_ccr & TME_M68K_FLAG_Z) {" ! 811: i=" " ! 812: fi ! 813: echo "${i} ireg_dc = TME_M68K_IREG_D0 + TME_FIELD_EXTRACTU(specop${buffer}, 0, 3);" ! 814: echo "${i} tme_m68k_cmp${size}(ic, &ic->tme_m68k_ireg_uint${size}(ireg_dc), &ic->tme_m68k_ireg_mem${buffer}${size});" ! 815: if test $buffer = y; then ! 816: echo " }" ! 817: fi ! 818: done ! 819: ! 820: echo "" ! 821: echo " /* write: */" ! 822: echo " if (ic->tme_m68k_ireg_ccr & TME_M68K_FLAG_Z) {" ! 823: for buffer in $buffers; do ! 824: if test $name = cas2_; then ! 825: echo " ic->_tme_m68k_ea_address = addr${buffer};" ! 826: fi ! 827: echo " ireg_du = TME_M68K_IREG_D0 + TME_FIELD_EXTRACTU(specop${buffer}, 6, 3);" ! 828: echo " ic->tme_m68k_ireg_mem${buffer}${size} = ic->tme_m68k_ireg_uint${size}(ireg_du);" ! 829: echo " tme_m68k_write${size}(ic, tlb," ! 830: echo " &ic->_tme_m68k_ea_function_code," ! 831: echo " &ic->_tme_m68k_ea_address," ! 832: echo " &ic->tme_m68k_ireg_mem${buffer}${size}," ! 833: echo " TME_M68K_BUS_CYCLE_RMW);" ! 834: done ! 835: echo " }" ! 836: echo " else {" ! 837: echo " /* XXX the 68040 always does a write to finish its cycle: */" ! 838: echo " do_write = FALSE;" ! 839: for buffer in $buffers; do ! 840: echo " ireg_dc = TME_M68K_IREG_D0 + TME_FIELD_EXTRACTU(specop${buffer}, 0, 3);" ! 841: echo -n " if (do_write" ! 842: if test $name = cas2_; then ! 843: echo "" ! 844: echo " && ic->tme_m68k_ireg_mem${buffer}${size} != ic->tme_m68k_ireg_uint${size}(ireg_dc)) {" ! 845: echo " ic->_tme_m68k_ea_address = addr${buffer};" ! 846: else ! 847: echo ") {" ! 848: fi ! 849: echo " tme_m68k_write${size}(ic, tlb," ! 850: echo " &ic->_tme_m68k_ea_function_code," ! 851: echo " &ic->_tme_m68k_ea_address," ! 852: echo " &ic->tme_m68k_ireg_mem${buffer}${size}," ! 853: echo " TME_M68K_BUS_CYCLE_RMW);" ! 854: echo " do_write = FALSE;" ! 855: echo " }" ! 856: echo " ic->tme_m68k_ireg_uint${size}(ireg_dc) = ic->tme_m68k_ireg_mem${buffer}${size};" ! 857: done ! 858: echo " }" ! 859: echo "" ! 860: echo " /* finish the read/modify/write cycle: */" ! 861: echo " tme_m68k_rmw_finish(ic, tlb);" ! 862: echo "" ! 863: echo " TME_M68K_INSN_OK;" ! 864: echo "}" ! 865: fi ! 866: done ! 867: ! 868: # moves: ! 869: if $header; then ! 870: echo "TME_M68K_INSN_DECL(tme_m68k_moves${size});" ! 871: else ! 872: echo "" ! 873: echo "/* moves${size}: */" ! 874: echo "TME_M68K_INSN(tme_m68k_moves${size})" ! 875: echo "{" ! 876: echo " int ireg;" ! 877: echo " ireg = TME_M68K_IREG_D0 + TME_FIELD_EXTRACTU(TME_M68K_INSN_SPECOP, 12, 4);" ! 878: echo " if (TME_M68K_INSN_SPECOP & TME_BIT(11)) {" ! 879: echo " ic->tme_m68k_ireg_memx${size} = ic->tme_m68k_ireg_uint${size}(ireg${reg_size_shift});" ! 880: echo " }" ! 881: echo " else {" ! 882: if test ${size} != 32; then ! 883: echo " if (ireg >= TME_M68K_IREG_A0) {" ! 884: echo " ic->tme_m68k_ireg_uint32(ireg) = " ! 885: echo " TME_EXT_S${size}_U32((tme_int${size}_t) ic->tme_m68k_ireg_memx${size});" ! 886: echo " }" ! 887: echo " else" ! 888: echo -n " " ! 889: fi ! 890: echo " ic->tme_m68k_ireg_uint${size}(ireg${reg_size_shift}) = ic->tme_m68k_ireg_memx${size};" ! 891: echo " }" ! 892: echo " TME_M68K_INSN_OK;" ! 893: echo "}" ! 894: fi ! 895: done ! 896: ! 897: # generate the memory read and write functions: ! 898: ! 899: # permute on size: ! 900: for size in 8 16 32 any; do ! 901: ! 902: # permute on read or write: ! 903: for name in read write; do ! 904: capname=`echo $name | tr a-z A-Z` ! 905: if test $name = read; then ! 906: lockname="rd" ! 907: from="from" ! 908: else ! 909: lockname="wr" ! 910: from="to" ! 911: fi ! 912: ! 913: # permute on the special-purpose what: ! 914: for what in memx mem inst stack; do ! 915: ! 916: # placeholder for another permutation: ! 917: : ! 918: ! 919: # dispatch on the size: ! 920: _first=_first ; _last=_last ! 921: case "$size" in ! 922: 8) _first= ; _last= ;; ! 923: esac ! 924: ! 925: # set up the details of each special purpose: ! 926: rval="void" ! 927: args="" ! 928: args_proto="" ! 929: fc="" ! 930: addr="" ! 931: count="" ! 932: tlb="TME_M68K_TLB_ENTRY(ic, function_code, linear_address${_first})" ! 933: flags="TME_M68K_BUS_CYCLE_NORMAL" ! 934: case "${name}-${what}-${size}" in ! 935: *-memx-8 | *-memx-16 | *-memx-32) ! 936: action="${name}_${what}${size}" ! 937: fcptr="&ic->_tme_m68k_ea_function_code" ! 938: addrptr="&ic->_tme_m68k_ea_address" ! 939: reg="ic->tme_m68k_ireg_memx${size}" ! 940: regptr="&${reg}" ! 941: ;; ! 942: *-mem-any) ! 943: action="${name}_${what}" ! 944: args_proto=", tme_uint8_t *, unsigned int" ! 945: args=", tme_uint8_t *buffer, unsigned int count" ! 946: fcptr="&ic->_tme_m68k_ea_function_code" ! 947: addrptr="&ic->_tme_m68k_ea_address" ! 948: reg= ! 949: regptr="buffer" ! 950: ;; ! 951: *-mem-8 | *-mem-16 | *-mem-32) ! 952: action="${name}_${what}${size}" ! 953: args_proto=", int" ! 954: args="${args_proto} ireg" ! 955: fcptr="&ic->_tme_m68k_ea_function_code" ! 956: addrptr="&ic->_tme_m68k_ea_address" ! 957: reg="ic->tme_m68k_ireg_uint${size}(ireg)" ! 958: regptr="&${reg}" ! 959: ;; ! 960: read-stack-16 | read-stack-32) ! 961: action="pop${size}" ! 962: args_proto=", tme_uint${size}_t *" ! 963: args="${args_proto}_value" ! 964: fc="TME_M68K_FUNCTION_CODE_DATA(ic)" ! 965: addrptr="&ic->tme_m68k_ireg_a7" ! 966: regptr="_value" ! 967: reg="*${regptr}" ! 968: ;; ! 969: write-stack-16 | write-stack-32) ! 970: action="push${size}" ! 971: args_proto=", tme_uint${size}_t " ! 972: args="${args_proto}value" ! 973: fc="TME_M68K_FUNCTION_CODE_DATA(ic)" ! 974: addr="ic->tme_m68k_ireg_a7 - sizeof(tme_uint${size}_t)" ! 975: reg="value" ! 976: regptr="&${reg}" ! 977: ;; ! 978: read-inst-16 | read-inst-32) ! 979: rval="tme_uint${size}_t" ! 980: action="fetch${size}" ! 981: args_proto=", tme_uint32_t" ! 982: args="${args_proto} pc" ! 983: fc="TME_M68K_FUNCTION_CODE_PROGRAM(ic)" ! 984: addrptr="&pc" ! 985: tlb="TME_ATOMIC_READ(struct tme_m68k_tlb *, ic->_tme_m68k_itlb)"; ! 986: flags="TME_M68K_BUS_CYCLE_FETCH" ! 987: ;; ! 988: *) ! 989: continue ! 990: ;; ! 991: esac ! 992: ! 993: # if we're making the header, just emit a declaration: ! 994: if $header; then ! 995: echo "${rval} tme_m68k_${action} _TME_P((struct tme_m68k *${args_proto}));" ! 996: continue ! 997: fi ! 998: ! 999: # start the function: ! 1000: echo "" ! 1001: echo "/* this ${name}s a ${size}-bit ${what} value: */" ! 1002: echo "${rval}" ! 1003: echo "tme_m68k_${action}(struct tme_m68k *ic${args}) " ! 1004: echo "{" ! 1005: ! 1006: # our locals: ! 1007: echo -n " unsigned int function_code = " ! 1008: if test "x${fc}" != x; then ! 1009: echo "${fc};" ! 1010: fc="function_code" ! 1011: fcptr="&function_code" ! 1012: else ! 1013: fc=`echo ${fcptr} | sed -e 's,^&,,'` ! 1014: echo "${fc};" ! 1015: fi ! 1016: echo -n " tme_uint32_t linear_address${_first} = " ! 1017: if test "x${addr}" != x; then ! 1018: echo "${addr};" ! 1019: addr="linear_address${_first}" ! 1020: addrptr="&linear_address${_first}" ! 1021: else ! 1022: addr=`echo ${addrptr} | sed -e 's,^&,,'` ! 1023: echo "${addr};" ! 1024: fi ! 1025: if test "x${count}" = x; then ! 1026: if test $size = any; then count=count; else count="sizeof(tme_uint${size}_t)"; fi ! 1027: fi ! 1028: if test x$_last != x; then ! 1029: echo " tme_uint32_t linear_address${_last} = linear_address_first + ${count} - 1;"; ! 1030: fi ! 1031: echo " struct tme_m68k_tlb *tlb = ${tlb};" ! 1032: case "$what" in ! 1033: inst) ! 1034: echo " unsigned int insn_buffer_off = TME_ALIGN(ic->_tme_m68k_insn_buffer_off, sizeof(tme_uint${size}_t));" ! 1035: regptr="((tme_uint${size}_t *) &ic->_tme_m68k_insn_buffer[insn_buffer_off])" ! 1036: reg="*${regptr}" ! 1037: ;; ! 1038: esac ! 1039: ! 1040: # if this is a write, log the value written: ! 1041: if test $name = write; then ! 1042: echo "" ! 1043: echo " /* log the value written: */" ! 1044: if test $size != any; then ! 1045: echo " tme_m68k_verify_mem${size}(ic, ${fc}, ${addr}, ${reg}, TME_BUS_CYCLE_WRITE);" ! 1046: echo " tme_m68k_log(ic, 1000, TME_OK, " ! 1047: echo " (TME_M68K_LOG_HANDLE(ic)," ! 1048: echo " _(\"${action}\t%d:0x%08x:\t0x%0"`expr ${size} / 4`"x\")," ! 1049: echo " ${fc}," ! 1050: echo " ${addr}," ! 1051: echo " ${reg}));" ! 1052: else ! 1053: echo " tme_m68k_verify_mem_any(ic, ${fc}, ${addr}, ${regptr}, ${count}, TME_BUS_CYCLE_WRITE);" ! 1054: echo " tme_m68k_log_start(ic, 1000, TME_OK) {" ! 1055: echo " unsigned int byte_i;" ! 1056: echo " tme_log_part(TME_M68K_LOG_HANDLE(ic)," ! 1057: echo " _(\"${action} %d:0x%08x count %d:\")," ! 1058: echo " ${fc}," ! 1059: echo " ${addr}," ! 1060: echo " ${count});" ! 1061: echo " for (byte_i = 0; byte_i < count ; byte_i++) {" ! 1062: echo " tme_log_part(TME_M68K_LOG_HANDLE(ic), \" 0x%02x\", (${regptr})[byte_i]);" ! 1063: echo " }" ! 1064: echo " } tme_m68k_log_finish(ic);" ! 1065: fi ! 1066: fi ! 1067: ! 1068: echo "" ! 1069: echo " /* do the bus cycle(s) ourselves from emulator memory if we can." ! 1070: echo " the emulator memory allocator and TLB filler must guarantee" ! 1071: echo " that all tme_m68k_tlb_emulator_off_${name} pointers be 32-bit" ! 1072: echo " aligned, so that a 16-bit-aligned linear address gets a" ! 1073: echo " 16-bit-aligned emulator address: */" ! 1074: echo " if (__tme_predict_true(!TME_M68K_SEQUENCE_RESTARTING" ! 1075: if test $size != 8; then ! 1076: echo " && !(linear_address${_first} & 1)" ! 1077: fi ! 1078: echo " && TME_M68K_TLB_OK_FAST_${capname}(tlb," ! 1079: echo " function_code," ! 1080: echo " linear_address${_first}," ! 1081: echo " linear_address${_last}))) {" ! 1082: ! 1083: memptr="(tlb->tme_m68k_tlb_emulator_off_${name} + linear_address${_first})" ! 1084: mem="*((tme_uint${size}_t *) ${memptr})" ! 1085: if test $name = read; then ! 1086: simple="${reg} = tme_betoh_u${size}(${mem});" ! 1087: else ! 1088: simple="${mem} = tme_htobe_u${size}(${reg});" ! 1089: fi ! 1090: ! 1091: echo "" ! 1092: ! 1093: # if this is an 8-bit transfer: ! 1094: if test $size = 8; then ! 1095: echo " /* for an 8-bit transfer we can always do a simple " ! 1096: echo " assignment. the ${lockname}lock is unnecessary, since we assume" ! 1097: echo " that 8-bit accesses are always atomic: */" ! 1098: if test $name = read; then ! 1099: echo " ${reg} = ${mem};" ! 1100: else ! 1101: echo " ${mem} = ${reg};" ! 1102: fi ! 1103: ! 1104: # if this is a 16-bit transfer: ! 1105: elif test $size = 16; then ! 1106: echo " /* for a 16-bit transfer we can always do a simple" ! 1107: echo " assignment - we tested that the linear address" ! 1108: echo " is 16-bit aligned, which, since the TLB emulator" ! 1109: echo " offset is guaranteed to be 32-bit aligned, guarantees" ! 1110: echo " that the final emulator address is 16-bit aligned." ! 1111: echo "" ! 1112: echo " we need the ${lockname}lock if we're on an architecture" ! 1113: echo " where an aligned access may not be atomic: */" ! 1114: echo " tme_memory_aligned_${lockname}lock(tlb->tme_m68k_tlb_bus_rwlock);" ! 1115: echo " ${simple}" ! 1116: echo " tme_memory_aligned_unlock(tlb->tme_m68k_tlb_bus_rwlock);" ! 1117: ! 1118: # if this is a 32-bit transfer: ! 1119: elif test $size = 32; then ! 1120: ! 1121: echo " /* if the emulator host allows ${size}-bit quantities to be" ! 1122: echo " transferred ${from} 16-bit aligned addresses, or if this" ! 1123: echo " address is ${size}-bit aligned, do the transfer as a simple" ! 1124: echo " assignment, otherwise transfer two 16-bit words." ! 1125: echo "" ! 1126: echo " we need the ${lockname}lock if we're on an architecture where" ! 1127: echo " an aligned access may not be atomic, or if we're doing" ! 1128: echo " an unaligned access on an architecture where they may" ! 1129: echo " not be atomic: */" ! 1130: misaligned="(linear_address${_first} & (sizeof(tme_uint${size}_t) - 1))" ! 1131: echo "#if ALIGNOF_INT${size}_T <= ALIGNOF_INT16_T" ! 1132: echo "#ifdef TME_UNALIGNED_ACCESS_ATOMIC" ! 1133: echo " ${simple}" ! 1134: echo "#else /* !TME_UNALIGNED_ACCESS_ATOMIC */" ! 1135: echo " if (${misaligned}) {" ! 1136: echo " tme_memory_unaligned_${lockname}lock(tlb->tme_m68k_tlb_bus_rwlock);" ! 1137: echo " ${simple}" ! 1138: echo " tme_memory_unaligned_unlock(tlb->tme_m68k_tlb_bus_rwlock);" ! 1139: echo " }" ! 1140: echo " else {" ! 1141: echo " tme_memory_aligned_${lockname}lock(tlb->tme_m68k_tlb_bus_rwlock);" ! 1142: echo " ${simple}" ! 1143: echo " tme_memory_aligned_unlock(tlb->tme_m68k_tlb_bus_rwlock);" ! 1144: echo " }" ! 1145: echo "#endif /* !TME_UNALIGNED_ACCESS_ATOMIC */" ! 1146: echo "#else /* ALIGNOF_INT${size}_T > ALIGNOF_INT16_T */" ! 1147: echo " if (TME_SEQUENCE_ACCESS_NOT_COSTLIER || ${misaligned}) {" ! 1148: echo " tme_memory_sequence_${lockname}lock(tlb->tme_m68k_tlb_bus_rwlock); " ! 1149: if test $name = read; then ! 1150: echo "#ifdef WORDS_BIGENDIAN" ! 1151: echo " ${reg} = (((tme_uint${size}_t) ((tme_uint16_t *) ${memptr})[0]) << 16) | ((tme_uint16_t *) ${memptr})[1];" ! 1152: echo "#else /* !WORDS_BIGENDIAN */" ! 1153: echo " ${reg} = tme_betoh_u32((((tme_uint${size}_t) ((tme_uint16_t *) ${memptr})[1]) << 16) | ((tme_uint16_t *) ${memptr})[0]);" ! 1154: echo "#endif /* !WORDS_BIGENDIAN */" ! 1155: else ! 1156: echo " ((tme_uint16_t *) ${memptr})[0] = tme_htobe_u16(${reg} >> 16);" ! 1157: echo " ((tme_uint16_t *) ${memptr})[1] = tme_htobe_u16(${reg} & 0xffff);" ! 1158: fi ! 1159: echo " tme_memory_sequence_unlock(tlb->tme_m68k_tlb_bus_rwlock); " ! 1160: echo " }" ! 1161: echo " else {" ! 1162: echo " tme_memory_aligned_${lockname}lock(tlb->tme_m68k_tlb_bus_rwlock); " ! 1163: echo " ${simple}" ! 1164: echo " tme_memory_aligned_unlock(tlb->tme_m68k_tlb_bus_rwlock); " ! 1165: echo " }" ! 1166: echo "#endif /* ALIGNOF_INT${size}_T != 1 */" ! 1167: ! 1168: # if this is an any-transfer: ! 1169: elif test $size = any; then ! 1170: echo " tme_memory_sequence_${lockname}lock(tlb->tme_m68k_tlb_bus_rwlock);" ! 1171: if test $name = read; then ! 1172: echo " memcpy(${regptr}, ${memptr}, ${count});" ! 1173: else ! 1174: echo " memcpy(${memptr}, ${regptr}, ${count});" ! 1175: fi ! 1176: echo " tme_memory_sequence_unlock(tlb->tme_m68k_tlb_bus_rwlock);" ! 1177: ! 1178: fi ! 1179: echo " TME_M68K_SEQUENCE_TRANSFER_STEP;" ! 1180: echo " }" ! 1181: ! 1182: echo "" ! 1183: echo " /* otherwise, do the bus cycles the slow way: */" ! 1184: echo " else {" ! 1185: if test $size != any; then ! 1186: echo " tme_m68k_${name}${size}(ic, tlb," ! 1187: echo " ${fcptr}," ! 1188: echo " ${addrptr}," ! 1189: echo " ${regptr}," ! 1190: echo " ${flags});" ! 1191: else ! 1192: echo " tme_m68k_${name}(ic, tlb, ${fcptr}, ${addrptr}, ${regptr}, ${count}, TME_M68K_BUS_CYCLE_RAW);" ! 1193: fi ! 1194: echo " }" ! 1195: ! 1196: # if this is a read, log the value read: ! 1197: if test $name = read; then ! 1198: echo "" ! 1199: echo " /* log the value read: */" ! 1200: if test $size != any; then ! 1201: echo " tme_m68k_verify_mem${size}(ic, ${fc}, ${addr}, ${reg}, TME_BUS_CYCLE_READ);" ! 1202: echo " tme_m68k_log(ic, 1000, TME_OK," ! 1203: echo " (TME_M68K_LOG_HANDLE(ic)," ! 1204: echo " _(\"${action}\t%d:0x%08x:\t0x%0"`expr ${size} / 4`"x\")," ! 1205: echo " ${fc}," ! 1206: echo " ${addr}," ! 1207: echo " ${reg}));" ! 1208: else ! 1209: echo " tme_m68k_verify_mem_any(ic, ${fc}, ${addr}, ${regptr}, ${count}, TME_BUS_CYCLE_READ);" ! 1210: echo " tme_m68k_log_start(ic, 1000, TME_OK) {" ! 1211: echo " unsigned int byte_i;" ! 1212: echo " tme_log_part(TME_M68K_LOG_HANDLE(ic)," ! 1213: echo " _(\"${action} %d:0x%08x count %d:\")," ! 1214: echo " ${fc}," ! 1215: echo " ${addr}," ! 1216: echo " ${count});" ! 1217: echo " for (byte_i = 0; byte_i < count ; byte_i++) {" ! 1218: echo " tme_log_part(TME_M68K_LOG_HANDLE(ic), \" 0x%02x\", (${regptr})[byte_i]);" ! 1219: echo " }" ! 1220: echo " } tme_m68k_log_finish(ic);" ! 1221: fi ! 1222: fi ! 1223: ! 1224: # perform any updating and value returning: ! 1225: case "$what" in ! 1226: stack) ! 1227: if test $name = read; then dir="+"; else dir="-"; fi ! 1228: echo " if (!TME_M68K_SEQUENCE_RESTARTING) {" ! 1229: echo " ic->tme_m68k_ireg_a7 ${dir}= sizeof(tme_uint${size}_t);" ! 1230: echo " }" ! 1231: ;; ! 1232: inst) ! 1233: echo " ic->_tme_m68k_insn_buffer_off = insn_buffer_off + sizeof(tme_uint${size}_t);" ! 1234: echo " return(${reg});" ! 1235: ;; ! 1236: esac ! 1237: ! 1238: echo "}" ! 1239: : ! 1240: done ! 1241: ! 1242: # the general-purpose cycle-making read and write macros: ! 1243: if test ${size} != any; then ! 1244: ! 1245: # if we're making the header, emit a macro: ! 1246: if $header; then ! 1247: echo "#define tme_m68k_${name}${size}(ic, t, fc, la, _v, f) \\" ! 1248: echo " tme_m68k_${name}(ic, t, fc, la, (tme_uint8_t *) (_v), sizeof(tme_uint${size}_t), f)" ! 1249: fi ! 1250: else ! 1251: ! 1252: # if we're making the header, just emit a declaration: ! 1253: if $header; then ! 1254: echo "void tme_m68k_${name} _TME_P((struct tme_m68k *, struct tme_m68k_tlb *, unsigned int *, tme_uint32_t *, tme_uint8_t *, unsigned int, unsigned int));" ! 1255: continue ! 1256: fi ! 1257: ! 1258: echo "" ! 1259: echo "/* this ${name}s a region of address space using actual bus cycles: */" ! 1260: echo "void" ! 1261: echo "tme_m68k_${name}(struct tme_m68k *ic, " ! 1262: echo " struct tme_m68k_tlb *tlb," ! 1263: echo " unsigned int *_function_code, " ! 1264: echo " tme_uint32_t *_linear_address, " ! 1265: echo " tme_uint8_t *reg," ! 1266: echo " unsigned int reg_size," ! 1267: echo " unsigned int flags)" ! 1268: echo "{" ! 1269: ! 1270: # our locals: ! 1271: echo " unsigned int function_code;" ! 1272: echo " tme_uint32_t linear_address;" ! 1273: echo " tme_bus_addr_t physical_address;" ! 1274: echo " int shift;" ! 1275: echo " struct tme_bus_cycle cycle;" ! 1276: echo " unsigned int transferred, resid, cycle_size;" ! 1277: echo " int exception;" ! 1278: echo " tme_rwlock_t *rmw_rwlock;" ! 1279: echo " int err;" ! 1280: echo "#ifndef WORDS_BIGENDIAN" ! 1281: echo " tme_uint8_t *reg_p;" ! 1282: echo " unsigned int buffer_i;" ! 1283: echo "#endif /* !WORDS_BIGENDIAN */" ! 1284: ! 1285: echo "" ! 1286: echo " /* if we're not restarting, everything is fresh: */" ! 1287: echo " if (!TME_M68K_SEQUENCE_RESTARTING) {" ! 1288: echo " function_code = *_function_code;" ! 1289: echo " linear_address = *_linear_address;" ! 1290: echo " transferred = 0;" ! 1291: echo " }" ! 1292: ! 1293: echo "" ! 1294: echo " /* otherwise, if this is the transfer that faulted, restore" ! 1295: echo " our state to the cycle that faulted, then take into account" ! 1296: echo " any data provided by a software rerun of the faulted cycle: */" ! 1297: echo " else if (ic->_tme_m68k_sequence._tme_m68k_sequence_transfer_faulted" ! 1298: echo " == ic->_tme_m68k_sequence._tme_m68k_sequence_transfer_next) {" ! 1299: echo " function_code = *_function_code = ic->_tme_m68k_group0_function_code;" ! 1300: echo " linear_address = ic->_tme_m68k_group0_address;" ! 1301: echo " transferred = ic->_tme_m68k_sequence._tme_m68k_sequence_transfer_faulted_after;" ! 1302: echo " if (transferred >= reg_size) abort();" ! 1303: echo " *_linear_address = linear_address - transferred;" ! 1304: echo " resid = reg_size - transferred;" ! 1305: echo " if (ic->_tme_m68k_group0_buffer_${name}_size > resid) abort();" ! 1306: echo " if (ic->_tme_m68k_group0_buffer_${name}_softrr > resid) abort();" ! 1307: if test $name = read; then cmp=">"; else cmp="=="; fi ! 1308: echo " if (ic->_tme_m68k_group0_buffer_${name}_softrr ${cmp} 0) {" ! 1309: echo "#ifdef WORDS_BIGENDIAN" ! 1310: echo " memcpy(reg + transferred, " ! 1311: echo " ic->_tme_m68k_group0_buffer_${name}," ! 1312: echo " ic->_tme_m68k_group0_buffer_${name}_size);" ! 1313: echo "#else /* !WORDS_BIGENDIAN */" ! 1314: echo " reg_p = (reg + reg_size - 1) - transferred;" ! 1315: echo " for (buffer_i = 0;" ! 1316: echo " buffer_i < ic->_tme_m68k_group0_buffer_${name}_size;" ! 1317: echo " buffer_i++) {" ! 1318: echo " *(reg_p--) = ic->_tme_m68k_group0_buffer_${name}[buffer_i];" ! 1319: echo " }" ! 1320: echo "#endif /* !WORDS_BIGENDIAN */" ! 1321: echo " }" ! 1322: echo " transferred += ic->_tme_m68k_group0_buffer_${name}_softrr;" ! 1323: echo " }" ! 1324: ! 1325: echo "" ! 1326: echo " /* otherwise, a later transfer has faulted. just step the" ! 1327: echo " transfer number and return: */" ! 1328: echo " else {" ! 1329: echo " TME_M68K_SEQUENCE_TRANSFER_STEP;" ! 1330: echo " return;" ! 1331: echo " }" ! 1332: ! 1333: echo "" ! 1334: echo " /* do as many bus cycles as needed to complete the transfer: */" ! 1335: echo " rmw_rwlock = tlb->tme_m68k_tlb_bus_rwlock;" ! 1336: echo " exception = TME_M68K_EXCEPTION_NONE;" ! 1337: echo " cycle_size = 0;" ! 1338: echo " for(; transferred < reg_size; ) {" ! 1339: echo " resid = reg_size - transferred;" ! 1340: ! 1341: echo "" ! 1342: echo " /* start the bus cycle structure: */" ! 1343: echo " cycle.tme_bus_cycle_type = TME_BUS_CYCLE_${capname};" ! 1344: echo " if (TME_ENDIAN_NATIVE == TME_ENDIAN_BIG" ! 1345: echo " || (flags & TME_M68K_BUS_CYCLE_RAW)) {" ! 1346: echo " cycle.tme_bus_cycle_buffer = reg + transferred;" ! 1347: echo " cycle.tme_bus_cycle_buffer_increment = 1;" ! 1348: echo " }" ! 1349: echo " else {" ! 1350: echo " cycle.tme_bus_cycle_buffer = reg + reg_size - (1 + transferred);" ! 1351: echo " cycle.tme_bus_cycle_buffer_increment = -1;" ! 1352: echo " }" ! 1353: ! 1354: echo "" ! 1355: echo " /* if we're emulating a CPU with a 16-bit bus interface: */" ! 1356: echo " if (ic->_tme_m68k_bus_16bit) {" ! 1357: echo "" ! 1358: echo " /* if we're trying to transfer a non-power-of-two" ! 1359: echo " number of bytes, either the CPU is broken (no" ! 1360: echo " instructions ever transfer a non-power-of-two" ! 1361: echo " number of bytes), or this function allowed an" ! 1362: echo " unaligned transfer: */" ! 1363: echo " assert((resid & (resid - 1)) == 0" ! 1364: echo " || (flags & TME_M68K_BUS_CYCLE_RAW));" ! 1365: echo "" ! 1366: echo " /* only byte transfers can be unaligned: */" ! 1367: echo " if (resid > sizeof(tme_uint8_t)" ! 1368: echo " && (linear_address & 1)) {" ! 1369: echo " exception = TME_M68K_EXCEPTION_GROUP0_AERR;" ! 1370: echo " break;" ! 1371: echo " }" ! 1372: echo "" ! 1373: echo " /* set the bus-size specific parts of the bus cycle structure: */" ! 1374: echo " cycle_size = TME_MIN(resid, sizeof(tme_uint16_t));" ! 1375: echo " cycle.tme_bus_cycle_size = cycle_size;" ! 1376: echo " cycle.tme_bus_cycle_port = TME_BUS_CYCLE_PORT(0, TME_BUS16_LOG2);" ! 1377: echo " cycle.tme_bus_cycle_lane_routing = " ! 1378: echo " &tme_m68k_router_16[TME_M68K_BUS_ROUTER_INDEX(TME_BUS16_LOG2, cycle_size, linear_address)];" ! 1379: echo " }" ! 1380: echo "" ! 1381: echo " /* otherwise we're emulating a CPU with a 32-bit bus interface: */" ! 1382: echo " else {" ! 1383: if test $name = read; then ! 1384: echo "" ! 1385: echo " /* an instruction fetch must be aligned: */" ! 1386: echo " if (flags & TME_M68K_BUS_CYCLE_FETCH) {" ! 1387: echo " if (linear_address & 1) {" ! 1388: echo " exception = TME_M68K_EXCEPTION_GROUP0_AERR;" ! 1389: echo " break;" ! 1390: echo " }" ! 1391: echo " assert(!(resid & 1));" ! 1392: echo " }" ! 1393: fi ! 1394: echo "" ! 1395: echo " /* set the bus-size specific parts of the bus cycle structure: */" ! 1396: echo " cycle_size = TME_MIN(resid, sizeof(tme_uint32_t) - (linear_address & (sizeof(tme_uint32_t) - 1)));" ! 1397: echo " cycle.tme_bus_cycle_size = cycle_size;" ! 1398: echo " cycle.tme_bus_cycle_port = TME_BUS_CYCLE_PORT(0, TME_BUS32_LOG2);" ! 1399: echo " cycle.tme_bus_cycle_lane_routing = " ! 1400: echo " &tme_m68k_router_32[TME_M68K_BUS_ROUTER_INDEX(TME_BUS32_LOG2, cycle_size, linear_address)];" ! 1401: echo " }" ! 1402: ! 1403: echo "" ! 1404: echo " /* reload the TLB entry: */" ! 1405: echo " if (!TME_M68K_TLB_OK_SLOW_${capname}(tlb, function_code, linear_address)) {" ! 1406: echo " tme_m68k_tlb_fill(ic, tlb," ! 1407: echo " function_code," ! 1408: echo " linear_address," ! 1409: echo " TME_BUS_CYCLE_${capname});" ! 1410: echo " }" ! 1411: echo "" ! 1412: echo " /* if this is a part of a read/modify/write cycle: */" ! 1413: echo " if (flags & TME_M68K_BUS_CYCLE_RMW) {" ! 1414: echo "" ! 1415: echo " /* if this TLB entry doesn't support fast ${name}s, or" ! 1416: echo " if the TLB lock has changed, that's a bus error." ! 1417: echo " see the discussion in tme_m68k_rmw_start: */" ! 1418: echo " if (!TME_M68K_TLB_OK_FAST_${capname}(tlb, function_code, linear_address, linear_address)" ! 1419: echo " || (rmw_rwlock != NULL" ! 1420: echo " && rmw_rwlock != tlb->tme_m68k_tlb_bus_rwlock)) {" ! 1421: echo " exception = TME_M68K_EXCEPTION_GROUP0_BERR;" ! 1422: echo " break;" ! 1423: echo " }" ! 1424: echo "" ! 1425: echo " /* if we haven't locked this memory yet, do so: */" ! 1426: echo " if (rmw_rwlock == NULL) {" ! 1427: echo " rmw_rwlock = tlb->tme_m68k_tlb_bus_rwlock;" ! 1428: echo " tme_rwlock_wrlock(rmw_rwlock);" ! 1429: echo " }" ! 1430: echo " }" ! 1431: ! 1432: echo "" ! 1433: echo " /* form the physical address for the bus cycle handler: */" ! 1434: echo " physical_address = tlb->tme_m68k_tlb_addr_offset + linear_address;" ! 1435: echo " shift = tlb->tme_m68k_tlb_addr_shift;" ! 1436: echo " if (shift < 0) {" ! 1437: echo " physical_address <<= (0 - shift);" ! 1438: echo " }" ! 1439: echo " else if (shift > 0) {" ! 1440: echo " physical_address >>= shift;" ! 1441: echo " }" ! 1442: echo " cycle.tme_bus_cycle_address = physical_address;" ! 1443: ! 1444: echo "" ! 1445: echo " /* run the bus cycle: */" ! 1446: echo " err = (*tlb->tme_m68k_tlb_bus_tlb.tme_bus_tlb_cycle)" ! 1447: echo " (tlb->tme_m68k_tlb_bus_tlb.tme_bus_tlb_cycle_private, &cycle);" ! 1448: echo "" ! 1449: echo " /* if we deadlocked, we have no locks to release" ! 1450: echo " ourselves, so sleep a while waiting for things" ! 1451: echo " to clear up, then try again: */" ! 1452: echo " if (err == TME_EDEADLK) {" ! 1453: echo " TME_THREAD_DEADLOCK_SLEEP();" ! 1454: echo " cycle.tme_bus_cycle_address = physical_address;" ! 1455: echo " }" ! 1456: echo "" ! 1457: echo " /* otherwise, any other error might be a bus error: */" ! 1458: echo " else if (err != TME_OK) {" ! 1459: echo " err = tme_bus_tlb_fault(&tlb->tme_m68k_tlb_bus_tlb, &cycle, err);" ! 1460: echo " if (err != TME_OK) {" ! 1461: echo " exception = TME_M68K_EXCEPTION_GROUP0_BERR;" ! 1462: echo " break;" ! 1463: echo " }" ! 1464: echo " }" ! 1465: echo "" ! 1466: echo " /* update: */" ! 1467: echo " linear_address += cycle.tme_bus_cycle_size;" ! 1468: echo " transferred += cycle.tme_bus_cycle_size;" ! 1469: echo " }" ! 1470: ! 1471: echo "" ! 1472: echo " /* if we got an exception and there is a locked" ! 1473: echo " read/modify/write rwlock, unlock it: */" ! 1474: echo " if (exception != TME_M68K_EXCEPTION_NONE" ! 1475: echo " && (flags & TME_M68K_BUS_CYCLE_RMW)" ! 1476: echo " && rmw_rwlock != NULL) {" ! 1477: echo " tme_rwlock_unlock(rmw_rwlock);" ! 1478: echo " }" ! 1479: ! 1480: echo "" ! 1481: echo " /* if we faulted, stash the information the fault stacker" ! 1482: echo " will need and start exception processing: */" ! 1483: echo " if (exception != TME_M68K_EXCEPTION_NONE) {" ! 1484: echo -n " ic->_tme_m68k_group0_flags = flags" ! 1485: if test $name = read; then ! 1486: echo -n " | TME_M68K_BUS_CYCLE_READ" ! 1487: fi ! 1488: echo ";" ! 1489: echo " ic->_tme_m68k_group0_function_code = function_code;" ! 1490: echo " ic->_tme_m68k_group0_address = linear_address;" ! 1491: echo " ic->_tme_m68k_group0_sequence = ic->_tme_m68k_sequence;" ! 1492: echo " ic->_tme_m68k_group0_sequence._tme_m68k_sequence_transfer_faulted_after = transferred;" ! 1493: echo " ic->_tme_m68k_group0_buffer_${name}_size = cycle_size;" ! 1494: if test $name = write; then ! 1495: echo "#ifdef WORDS_BIGENDIAN" ! 1496: echo " memcpy(ic->_tme_m68k_group0_buffer_${name}," ! 1497: echo " reg + transferred," ! 1498: echo " ic->_tme_m68k_group0_buffer_${name}_size);" ! 1499: echo "#else /* !WORDS_BIGENDIAN */" ! 1500: echo " reg_p = (reg + reg_size - 1) - transferred;" ! 1501: echo " for (buffer_i = 0;" ! 1502: echo " buffer_i < ic->_tme_m68k_group0_buffer_${name}_size;" ! 1503: echo " buffer_i++) {" ! 1504: echo " ic->_tme_m68k_group0_buffer_${name}[buffer_i] = *(reg_p--);" ! 1505: echo " }" ! 1506: echo "#endif /* !WORDS_BIGENDIAN */" ! 1507: fi ! 1508: echo " if (ic->_tme_m68k_group0_hook != NULL) {" ! 1509: echo " (*ic->_tme_m68k_group0_hook)(ic);" ! 1510: echo " }" ! 1511: echo " ic->_tme_m68k_group0_sequence._tme_m68k_sequence_transfer_faulted = "; ! 1512: echo " ic->_tme_m68k_group0_sequence._tme_m68k_sequence_transfer_next;" ! 1513: echo " tme_m68k_exception(ic, exception);" ! 1514: echo " }" ! 1515: ! 1516: echo "" ! 1517: echo " /* otherwise, this transfer has now completed: */" ! 1518: echo " TME_M68K_SEQUENCE_TRANSFER_STEP;" ! 1519: ! 1520: echo "}" ! 1521: fi ! 1522: done ! 1523: ! 1524: done ! 1525: ! 1526: # generate the BCD math functions: ! 1527: for name in abcd sbcd nbcd; do ! 1528: ! 1529: # if we're making the header, just emit a declaration: ! 1530: if $header; then ! 1531: echo "TME_M68K_INSN_DECL(tme_m68k_${name});" ! 1532: continue ! 1533: fi ! 1534: ! 1535: # emit the function: ! 1536: echo "" ! 1537: echo "TME_M68K_INSN(tme_m68k_${name})" ! 1538: echo "{" ! 1539: echo " tme_uint8_t dst, dst_msd, dst_lsd;" ! 1540: echo " tme_uint8_t src, src_msd, src_lsd;" ! 1541: echo " tme_uint8_t res, res_msd, res_lsd;" ! 1542: echo " tme_uint8_t flags;" ! 1543: ! 1544: # get the operands: ! 1545: if test $name != nbcd; then ! 1546: echo " int memory;" ! 1547: echo " int rx, ry, function_code;" ! 1548: echo "" ! 1549: echo " TME_M68K_INSN_CANFAULT;" ! 1550: echo "" ! 1551: echo " /* load the operands: */" ! 1552: echo " rx = TME_FIELD_EXTRACTU(TME_M68K_INSN_OPCODE, 0, 3);" ! 1553: echo " ry = TME_FIELD_EXTRACTU(TME_M68K_INSN_OPCODE, 9, 3);" ! 1554: echo " memory = (TME_M68K_INSN_OPCODE & TME_BIT(3)) != 0;" ! 1555: echo " function_code = TME_M68K_FUNCTION_CODE_DATA(ic);" ! 1556: echo " if (memory) {" ! 1557: echo " if (!TME_M68K_SEQUENCE_RESTARTING) {" ! 1558: echo " ic->_tme_m68k_ea_function_code = function_code;" ! 1559: echo " ic->_tme_m68k_ea_address = ic->tme_m68k_ireg_uint32(TME_M68K_IREG_A0 + rx);" ! 1560: echo " }" ! 1561: echo " tme_m68k_read_memx8(ic);" ! 1562: echo " if (!TME_M68K_SEQUENCE_RESTARTING) {" ! 1563: echo " ic->_tme_m68k_ea_function_code = function_code;" ! 1564: echo " ic->_tme_m68k_ea_address = ic->tme_m68k_ireg_uint32(TME_M68K_IREG_A0 + ry);" ! 1565: echo " }" ! 1566: echo " tme_m68k_read_mem8(ic, TME_M68K_IREG_MEMY32);" ! 1567: echo " src = ic->tme_m68k_ireg_memx8;" ! 1568: echo " dst = ic->tme_m68k_ireg_memy8;" ! 1569: echo " }" ! 1570: echo " else {" ! 1571: echo " src = ic->tme_m68k_ireg_uint8(rx << 2);" ! 1572: echo " dst = ic->tme_m68k_ireg_uint8(ry << 2);" ! 1573: echo " }" ! 1574: else ! 1575: echo "" ! 1576: echo " dst = 0x00;" ! 1577: echo " src = TME_M68K_INSN_OP1(tme_uint8_t);" ! 1578: fi ! 1579: echo " dst_lsd = TME_FIELD_EXTRACTU(dst, 0, 4);" ! 1580: echo " dst_msd = TME_FIELD_EXTRACTU(dst, 4, 4);" ! 1581: echo " src_lsd = TME_FIELD_EXTRACTU(src, 0, 4);" ! 1582: echo " src_msd = TME_FIELD_EXTRACTU(src, 4, 4);" ! 1583: ! 1584: # perform the operation: ! 1585: echo "" ! 1586: echo " /* perform the operation: */" ! 1587: if test $name = abcd; then op='+' ; opc='-' ; else op='-' ; opc='+' ; fi ! 1588: echo " res_lsd = dst_lsd ${op} src_lsd ${op} ((ic->tme_m68k_ireg_ccr & TME_M68K_FLAG_X) != 0);" ! 1589: echo " res_msd = dst_msd ${op} src_msd;" ! 1590: echo " flags = 0;" ! 1591: echo " if (res_lsd > 9) {" ! 1592: echo " res_lsd ${opc}= 10;" ! 1593: echo " res_msd ${op}= 1;" ! 1594: echo " }" ! 1595: echo " if (res_msd > 9) {" ! 1596: echo " res_msd ${opc}= 10;" ! 1597: echo " flags |= TME_M68K_FLAG_C | TME_M68K_FLAG_X;" ! 1598: echo " }" ! 1599: echo " res = (res_msd << 4) + (res_lsd & 0xf);" ! 1600: echo " if (res == 0) flags |= TME_M68K_FLAG_N;" ! 1601: echo "" ! 1602: ! 1603: # store the result ! 1604: echo " /* store the result and set the flags: */" ! 1605: if test $name != nbcd; then ! 1606: echo " if (memory) {" ! 1607: echo " if (!TME_M68K_SEQUENCE_RESTARTING) {" ! 1608: echo " ic->tme_m68k_ireg_memx8 = res;" ! 1609: echo " ic->_tme_m68k_ea_function_code = function_code;" ! 1610: echo " ic->_tme_m68k_ea_address = ic->tme_m68k_ireg_uint32(TME_M68K_IREG_A0 + ry);" ! 1611: # the stack pointer must always be incremented by a multiple of two. ! 1612: # assuming rx < 8, ((rx + 1) >> 3) == 1 iff rx == 7, meaning %a7: ! 1613: echo " ic->tme_m68k_ireg_uint32(TME_M68K_IREG_A0 + rx) += sizeof(tme_uint8_t) + ((rx + 1) >> 3);" ! 1614: echo " ic->tme_m68k_ireg_uint32(TME_M68K_IREG_A0 + ry) += sizeof(tme_uint8_t) + ((ry + 1) >> 3);" ! 1615: echo " ic->tme_m68k_ireg_ccr = flags;" ! 1616: echo " }" ! 1617: echo " tme_m68k_write_memx8(ic);" ! 1618: echo " }" ! 1619: echo " else {" ! 1620: echo " ic->tme_m68k_ireg_uint8(ry << 2) = res;" ! 1621: echo " ic->tme_m68k_ireg_ccr = flags;" ! 1622: echo " }" ! 1623: else ! 1624: echo " TME_M68K_INSN_OP1(tme_uint8_t) = res;" ! 1625: echo " ic->tme_m68k_ireg_ccr = flags;" ! 1626: fi ! 1627: echo "" ! 1628: echo " TME_M68K_INSN_OK;" ! 1629: echo "}" ! 1630: done ! 1631: ! 1632: # generate the ccr and sr functions: ! 1633: for reg in ccr sr; do ! 1634: for name in ori andi eori move_to; do ! 1635: if test $reg = ccr; then size=8 ; else size=16 ; fi ! 1636: ! 1637: # if we're making the header, just emit a declaration: ! 1638: if $header; then ! 1639: echo "TME_M68K_INSN_DECL(tme_m68k_${name}_${reg});" ! 1640: continue ! 1641: fi ! 1642: ! 1643: # emit the function: ! 1644: echo "" ! 1645: echo "TME_M68K_INSN(tme_m68k_${name}_${reg})" ! 1646: echo "{" ! 1647: echo " tme_uint${size}_t reg;" ! 1648: ! 1649: # form the new register value: ! 1650: src=0 ! 1651: echo -n " reg = " ! 1652: case $name in ! 1653: ori) echo -n "ic->tme_m68k_ireg_${reg} | " ;; ! 1654: andi) echo -n "ic->tme_m68k_ireg_${reg} & " ;; ! 1655: eori) echo -n "ic->tme_m68k_ireg_${reg} ^ " ;; ! 1656: move_to) size=16 ; src=1 ;; ! 1657: esac ! 1658: echo "(TME_M68K_INSN_OP${src}(tme_uint${size}_t) & TME_M68K_FLAG_"`echo $reg | tr a-z A-Z`");" ! 1659: ! 1660: # sr changes are special: ! 1661: if test $reg = sr; then ! 1662: echo " TME_M68K_INSN_PRIV;" ! 1663: echo " TME_M68K_INSN_CHANGE_SR(reg);" ! 1664: else ! 1665: echo " ic->tme_m68k_ireg_${reg} = reg;" ! 1666: fi ! 1667: ! 1668: echo " TME_M68K_INSN_OK;" ! 1669: echo "}" ! 1670: done ! 1671: done ! 1672: ! 1673: # generate the multiply and divide instructions: ! 1674: ! 1675: # permute on signed vs. unsigned: ! 1676: for _sign in u s; do ! 1677: if test $_sign = u; then sign=u; else sign=; fi ! 1678: ! 1679: # permute on short vs. long: ! 1680: for size in s l; do ! 1681: if test $size = s; then ! 1682: _size= ! 1683: small=16 ! 1684: large=32 ! 1685: reg_size_shift=' << 1' ! 1686: else ! 1687: _size=l ! 1688: small=32 ! 1689: large=64 ! 1690: reg_size_shift= ! 1691: fi ! 1692: ! 1693: # if we're making the header, just emit declarations: ! 1694: if $header; then ! 1695: echo "TME_M68K_INSN_DECL(tme_m68k_mul${_sign}${_size});" ! 1696: echo "TME_M68K_INSN_DECL(tme_m68k_div${_sign}${_size});" ! 1697: continue ! 1698: fi ! 1699: ! 1700: # emit the multiply function: ! 1701: echo "" ! 1702: echo "TME_M68K_INSN(tme_m68k_mul${_sign}${_size})" ! 1703: echo "{" ! 1704: if test $large = 64; then ! 1705: echo "#ifndef HAVE_UINT${large}_T" ! 1706: echo " abort();" ! 1707: echo "#else /* HAVE_UINT${large}_T */" ! 1708: echo " unsigned int flag_v;" ! 1709: echo " int ireg_dh;" ! 1710: fi ! 1711: echo " int ireg_dl;" ! 1712: echo " tme_${sign}int${large}_t res;" ! 1713: echo " tme_uint8_t flags;" ! 1714: ! 1715: echo "" ! 1716: echo " /* get the register containing the factor: */" ! 1717: echo -n " ireg_dl = TME_M68K_IREG_D0 + " ! 1718: if test $size = s; then ! 1719: echo "TME_M68K_INSN_OP0(tme_uint32_t);" ! 1720: else ! 1721: echo "TME_FIELD_EXTRACTU(TME_M68K_INSN_SPECOP, 12, 3);" ! 1722: fi ! 1723: ! 1724: echo "" ! 1725: echo " /* perform the multiplication: */" ! 1726: echo " res = (((tme_${sign}int${large}_t) ic->tme_m68k_ireg_${sign}int${small}(ireg_dl${reg_size_shift}))" ! 1727: echo " * TME_M68K_INSN_OP1(tme_${sign}int${small}_t));" ! 1728: ! 1729: echo "" ! 1730: echo " /* store the result: */" ! 1731: echo " ic->tme_m68k_ireg_${sign}int32(ireg_dl) = (tme_${sign}int32_t) res;" ! 1732: if test $large = 64; then ! 1733: echo " flag_v = TME_M68K_FLAG_V;" ! 1734: echo " if (TME_M68K_INSN_SPECOP & TME_BIT(10)) {" ! 1735: echo " flag_v = 0;" ! 1736: echo " ireg_dh = TME_M68K_IREG_D0 + TME_FIELD_EXTRACTU(TME_M68K_INSN_SPECOP, 0, 3);" ! 1737: echo " ic->tme_m68k_ireg_${sign}int32(ireg_dh) = (tme_${sign}int32_t) (res >> 32);" ! 1738: echo " }" ! 1739: fi ! 1740: ! 1741: echo "" ! 1742: echo " /* set the flags: */" ! 1743: echo " flags = ic->tme_m68k_ireg_ccr & TME_M68K_FLAG_X;" ! 1744: echo " if (((tme_int${large}_t) res) < 0) flags |= TME_M68K_FLAG_N;" ! 1745: echo " if (res == 0) flags |= TME_M68K_FLAG_Z;" ! 1746: if test $large = 64; then ! 1747: echo -n " if (res > 0xffffffff" ! 1748: if test $_sign = s; then echo -n " || res < -2147483648"; fi ! 1749: echo ") flags |= flag_v;" ! 1750: fi ! 1751: echo " ic->tme_m68k_ireg_ccr = flags;" ! 1752: ! 1753: echo "" ! 1754: echo " TME_M68K_INSN_OK;" ! 1755: if test $large = 64; then ! 1756: echo "#endif /* HAVE_UINT${large}_T */" ! 1757: fi ! 1758: echo "}" ! 1759: ! 1760: # emit the divide function: ! 1761: echo "" ! 1762: echo "TME_M68K_INSN(tme_m68k_div${_sign}${_size})" ! 1763: echo "{" ! 1764: if test $large = 64; then ! 1765: echo "#ifndef HAVE_UINT${large}_T" ! 1766: echo " abort();" ! 1767: echo "#else /* HAVE_UINT${large}_T */" ! 1768: echo " int ireg_dr;" ! 1769: fi ! 1770: echo " int ireg_dq;" ! 1771: echo " tme_${sign}int${large}_t dividend, quotient;" ! 1772: echo " tme_${sign}int${small}_t divisor, remainder;" ! 1773: echo " tme_uint8_t flags;" ! 1774: ! 1775: echo "" ! 1776: echo " /* get the register(s): */" ! 1777: echo -n " ireg_dq = TME_M68K_IREG_D0 + " ! 1778: if test $size = s; then ! 1779: echo "TME_M68K_INSN_OP0(tme_uint32_t);" ! 1780: else ! 1781: echo "TME_FIELD_EXTRACTU(TME_M68K_INSN_SPECOP, 12, 3);" ! 1782: echo " ireg_dr = TME_M68K_IREG_D0 + TME_FIELD_EXTRACTU(TME_M68K_INSN_SPECOP, 0, 3);" ! 1783: fi ! 1784: ! 1785: echo "" ! 1786: echo " /* form the dividend and the divisor: */" ! 1787: if test $large = 64; then ! 1788: echo " if (TME_M68K_INSN_SPECOP & TME_BIT(10)) {" ! 1789: echo " dividend = (tme_${sign}int${large}_t)" ! 1790: echo " ((((tme_uint${large}_t) ic->tme_m68k_ireg_uint32(ireg_dr)) << 32)" ! 1791: echo " | ic->tme_m68k_ireg_uint32(ireg_dq));" ! 1792: echo " }" ! 1793: echo " else" ! 1794: echo -n " " ! 1795: fi ! 1796: echo " dividend = (tme_${sign}int${large}_t) ic->tme_m68k_ireg_${sign}int32(ireg_dq);" ! 1797: echo " divisor = TME_M68K_INSN_OP1(tme_${sign}int${small}_t);" ! 1798: echo " if (divisor == 0) {" ! 1799: echo " ic->tme_m68k_ireg_pc = ic->tme_m68k_ireg_pc_next;" ! 1800: echo " TME_M68K_INSN_EXCEPTION(TME_M68K_EXCEPTION_GROUP2(5));" ! 1801: echo " }" ! 1802: ! 1803: echo "" ! 1804: echo " /* do the division: */" ! 1805: echo " quotient = dividend / divisor;" ! 1806: echo " remainder = dividend % divisor;" ! 1807: ! 1808: echo "" ! 1809: echo " /* set the flags and return the quotient and remainder: */" ! 1810: echo " flags = ic->tme_m68k_ireg_ccr & TME_M68K_FLAG_X;" ! 1811: echo -n " if (quotient > 0xffff" ! 1812: if test $small = 16; then ! 1813: if test $_sign = s; then echo -n " || quotient < -32768"; fi ! 1814: else ! 1815: echo -n "ffff" ! 1816: if test $_sign = s; then echo -n " || quotient < -2147483648"; fi ! 1817: fi ! 1818: echo ") {" ! 1819: echo " flags |= TME_M68K_FLAG_V;" ! 1820: echo " }" ! 1821: echo " else {" ! 1822: echo " if (((tme_int${small}_t) quotient) < 0) flags |= TME_M68K_FLAG_N;" ! 1823: echo " if (quotient == 0) flags |= TME_M68K_FLAG_Z;" ! 1824: echo " ic->tme_m68k_ireg_${sign}int${small}(ireg_dq${reg_size_shift}) = (tme_${sign}int${small}_t) quotient;" ! 1825: if test $small = 16; then ! 1826: echo " ic->tme_m68k_ireg_${sign}int${small}((ireg_dq${reg_size_shift}) + 1) = remainder;" ! 1827: else ! 1828: echo " if (ireg_dr != ireg_dq) {" ! 1829: echo " ic->tme_m68k_ireg_${sign}int${small}(ireg_dr) = remainder;" ! 1830: echo " }" ! 1831: fi ! 1832: echo " }" ! 1833: echo " ic->tme_m68k_ireg_ccr = flags;" ! 1834: ! 1835: echo "" ! 1836: echo " TME_M68K_INSN_OK;" ! 1837: if test $large = 64; then ! 1838: echo "#endif /* HAVE_UINT${large}_T */" ! 1839: fi ! 1840: echo "}" ! 1841: ! 1842: done ! 1843: done ! 1844: ! 1845: # done: ! 1846: exit 0
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.