File:  [The Machine Emulator] / tme / ic / sparc / sparc-insns-auto.sh
Revision 1.1.1.2 (vendor branch): download - view: text, annotated - select for diffs
Tue Apr 24 16:43:57 2018 UTC (8 years, 3 months ago) by root
Branches: heeltoe, fredette, MAIN
CVS tags: tme-0_8heeltoe, tme-0_8, HEAD
tme-0.8

#! /bin/sh

# $Id: sparc-insns-auto.sh,v 1.1.1.2 2018/04/24 16:43:57 root Exp $

# ic/sparc/sparc-insns-auto.sh - automatically generates C code 
# for many SPARC emulation instructions:

#
# Copyright (c) 2005 Matt Fredette
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# 1. Redistributions of source code must retain the above copyright
#    notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
#    notice, this list of conditions and the following disclaimer in the
#    documentation and/or other materials provided with the distribution.
# 3. All advertising materials mentioning features or use of this software
#    must display the following acknowledgement:
#      This product includes software developed by Matt Fredette.
# 4. The name of the author may not be used to endorse or promote products
#    derived from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
# INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
#

header=false

for option
do
    case $option in
    --header) header=true ;;
    esac
done

PROG=`basename $0`
cat <<EOF
/* automatically generated by $PROG, do not edit! */
_TME_RCSID("\$Id: sparc-insns-auto.sh,v 1.1.1.2 2018/04/24 16:43:57 root Exp $");

EOF
if $header; then :; else
    cat <<EOF
#include "sparc-impl.h"

/* an all-bits-zero float for use with _tme_sparc*_fpu_mem_fpreg(): */
#if TME_FLOAT_FORMAT_NULL != 0
#error "TME_FLOAT_FORMAT_NULL changed"
#endif
static struct tme_float _tme_sparc_float_null;
EOF
fi

# permute over architecture:
#
for arch in 32 64; do

    # the sparc64 support depends on a 64-bit integer type:
    #
    if test ${arch} = 64; then
	echo ""
	echo "#ifdef TME_HAVE_INT64_T"
    fi

    # get the name of the register with the integer condition codes, a
    # shift value for 32-bit registers, and the architecture version:
    #
    if test ${arch} = 32; then 
	ccr=32_PSR
	ccr_ireg='tme_sparc32_ireg_psr'
	reg32_shift=''
	version=8
    else
	ccr=64_CCR
	ccr_ireg='tme_sparc64_ireg_ccr'
	reg32_shift=' << 1'
	version=9
    fi

    # fix the architecture version:
    #
    if $header; then :; else
	echo ""
	echo "#undef TME_SPARC_VERSION"
	echo "#define TME_SPARC_VERSION(ic) (${version})"
    fi

    # the alternate ASI function:
    #
    if $header; then :; else
	echo ""
	echo "static tme_uint32_t"
	echo "_tme_sparc${arch}_alternate_asi_mask(struct tme_sparc *ic)"
	echo "{"
	echo "  unsigned int asi_data;"
	echo "  unsigned int asi_mask_flags;"
	echo "  tme_uint32_t asi_mask_data;"
	echo ""
	echo "  /* get the ASI, assuming that the i bit is zero: */"
	echo "  asi_data = TME_FIELD_MASK_EXTRACTU(TME_SPARC_INSN, (0xff << 5));"
	if test ${arch} = 32; then
	    echo ""
	    echo "  /* this is a privileged instruction: */"
	    echo "  TME_SPARC_INSN_PRIV;"
	    echo ""
	    echo "  /* if the i bit is one, this is an illegal instruction: */"
	    echo "  if (__tme_predict_false(TME_SPARC_INSN & TME_BIT(13))) {"
	    echo "    TME_SPARC_INSN_ILL(ic);"
	    echo "  }"
	    echo ""
	    echo "  /* get the flags for this ASI: */"
	    echo "  asi_mask_flags = ic->tme_sparc_asis[asi_data].tme_sparc_asi_mask_flags;"
	    echo ""
	    echo "  /* make the ASI mask: */"
	    echo "  if (asi_mask_flags & TME_SPARC32_ASI_MASK_FLAG_SPECIAL) {"
	    echo "    asi_mask_data"
	    echo "      = TME_SPARC_ASI_MASK_SPECIAL(asi_data, TRUE);"
	    echo "  }"
	    echo "  else {"
	    echo "    asi_mask_data = TME_SPARC32_ASI_MASK(asi_data, asi_data);"
	    echo "  }"
	else
	    echo ""
	    echo "  /* if the i bit is one, use the address space in the ASI register: */"
	    echo "  if (TME_SPARC_INSN & TME_BIT(13)) {"
	    echo "    asi_data = ic->tme_sparc64_ireg_asi;"
	    echo "  }"
	    echo ""
	    echo "  /* get the flags for this ASI: */"
	    echo "  asi_mask_flags = ic->tme_sparc_asis[asi_data].tme_sparc_asi_mask_flags;"
	    
	    echo ""
	    echo "  /* if this is a nonprivileged access: */"
	    echo "  if (!TME_SPARC_PRIV(ic)) {"
	    echo ""
	    echo "    /* if this is a restricted ASI: */"
	    echo "    if (__tme_predict_false((asi_data & TME_SPARC64_ASI_FLAG_UNRESTRICTED) == 0)) {"
	    echo ""
	    echo "      /* force a slow load or store, which will generate the"
	    echo "         privileged_action trap: */"
	    echo "      asi_mask_flags |= TME_SPARC_ASI_MASK_FLAG_UNDEF;"
	    echo "    }"
	    echo ""
	    echo "    /* force a nonprivileged access with the ASI: */"
	    echo "    asi_mask_flags |= TME_SPARC64_ASI_MASK_FLAG_INSN_AS_IF_USER;"
	    echo "  }"
	    echo ""
	    echo "  /* make the ASI mask: */"
	    echo "  if (asi_mask_flags & TME_SPARC64_ASI_MASK_FLAG_SPECIAL) {"
	    echo "    asi_mask_data"
	    echo "      = (asi_mask_flags"
	    echo "         + TME_SPARC_ASI_MASK_SPECIAL(asi_data,"
	    echo "                                      ((asi_mask_flags & TME_SPARC64_ASI_MASK_FLAG_INSN_AS_IF_USER) == 0)));"
	    echo "  }"
	    echo "  else {"
	    echo "    asi_mask_data = TME_SPARC64_ASI_MASK(asi_data, asi_mask_flags);"
	    echo "  }"
	fi
	echo ""
	echo "  /* if this ASI has a special handler: */"
	echo "  if (__tme_predict_false(ic->tme_sparc_asis[TME_SPARC_ASI_MASK_WHICH(asi_mask_data)].tme_sparc_asi_handler != 0)) {"
	echo ""
	echo "    /* force a slow load or store, which will call the special handler: */"
	echo "    asi_mask_data |= TME_SPARC_ASI_MASK_FLAG_UNDEF;"
	echo "  }"
	echo ""
	echo "  return (asi_mask_data);"
	echo "}"
    fi

    # the FPU load and store common function:
    #
    if $header; then :; else
	echo ""
	echo "static struct tme_float *"
	echo "_tme_sparc${arch}_fpu_mem_fpreg(struct tme_sparc *ic,"
	echo "                           tme_uint32_t misaligned,"
	echo "                           struct tme_float *float_buffer)"
	echo "{"
	echo "  unsigned int float_format;"
	echo "  unsigned int fpreg_format;"
	echo "  tme_uint32_t fp_store;"
	echo "  unsigned int fpu_mode;"
	echo "  unsigned int fpreg_number;"
	echo ""
	echo "  /* NB: this checks for various traps by their priority order: */"
	echo ""
	echo "  TME_SPARC_INSN_FPU_ENABLED;"
	echo ""
	echo "  /* get the floating-point format: */"
	echo "  float_format = float_buffer->tme_float_format;"
	echo ""
	echo "  /* convert the floating-point format into the ieee754"
	echo "     floating-point register file format: */"
	echo "#if (TME_FLOAT_FORMAT_NULL | TME_IEEE754_FPREG_FORMAT_NULL) != 0"
	echo "#error \"TME_FLOAT_FORMAT_ or TME_IEEE754_FPREG_FORMAT_ values changed\""
	echo "#endif"
	echo "#if TME_FLOAT_FORMAT_IEEE754_SINGLE < TME_IEEE754_FPREG_FORMAT_SINGLE"
	echo "#error \"TME_FLOAT_FORMAT_ or TME_IEEE754_FPREG_FORMAT_ values changed\""
	echo "#endif"
	echo "#if (TME_FLOAT_FORMAT_IEEE754_SINGLE / TME_IEEE754_FPREG_FORMAT_SINGLE) != (TME_FLOAT_FORMAT_IEEE754_DOUBLE / TME_IEEE754_FPREG_FORMAT_DOUBLE)"
	echo "#error \"TME_FLOAT_FORMAT_ or TME_IEEE754_FPREG_FORMAT_ values changed\""
	echo "#endif"
	echo "  assert (float_format == TME_FLOAT_FORMAT_NULL"
	echo "          || float_format == TME_FLOAT_FORMAT_IEEE754_SINGLE"
	echo "          || float_format == TME_FLOAT_FORMAT_IEEE754_DOUBLE);"
	echo "  fpreg_format = float_format / (TME_FLOAT_FORMAT_IEEE754_SINGLE / TME_IEEE754_FPREG_FORMAT_SINGLE);"
	echo ""
	echo "  /* if the memory address is misaligned, return the"
	echo "     float buffer now.  the eventual load or store will"
	echo "     cause the mem_address_not_aligned trap: */"
	echo ""
	echo "  /* if the memory address is misaligned: */"
	echo "#if TME_IEEE754_FPREG_FORMAT_NULL != 0 || TME_IEEE754_FPREG_FORMAT_SINGLE != 1 || TME_IEEE754_FPREG_FORMAT_DOUBLE != 2 || TME_IEEE754_FPREG_FORMAT_QUAD != 4"
	echo "#error \"TME_IEEE754_FPREG_FORMAT_ values changed\""
	echo "#endif"
	echo "  assert (fpreg_format == TME_IEEE754_FPREG_FORMAT_NULL"
	echo "          || fpreg_format == TME_IEEE754_FPREG_FORMAT_SINGLE"
	echo "          || fpreg_format == TME_IEEE754_FPREG_FORMAT_DOUBLE"
	echo "          || fpreg_format == TME_IEEE754_FPREG_FORMAT_QUAD);"
	echo "  misaligned &= ((sizeof(tme_uint32_t) * fpreg_format) - 1);"
	echo "  if (__tme_predict_false(misaligned)) {"
	echo ""
	if test ${arch} = 32; then
	    echo "    return (float_buffer);"
	else
	    echo "    /* if the memory address is not even 32-bit aligned, or"
	    echo "       if this SPARC doesn't support loads and stores of this"
	    echo "       size at 32-bit alignment: */"
	    echo "    if (misaligned != sizeof(tme_uint32_t)"
	    echo "#if TME_IEEE754_FPREG_FORMAT_SINGLE != 1 || (TME_SPARC_MEMORY_FLAG_HAS_LDDF_STDF_32 * TME_IEEE754_FPREG_FORMAT_DOUBLE) != TME_SPARC_MEMORY_FLAG_HAS_LDQF_STQF_32"
	    echo "#error \"TME_IEEE754_FPREG_FORMAT_ or TME_SPARC_MEMORY_FLAG_ values changed\""
	    echo "#endif"
	    echo "        || (TME_SPARC_MEMORY_FLAGS(ic)"
	    echo "            & (TME_SPARC_MEMORY_FLAG_HAS_LDDF_STDF_32 * fpreg_format)) == 0) {"
	    echo ""
	    echo "      return (float_buffer);"
	    echo "    }"
	fi
        echo "  }"
	echo ""
	echo "  /* see if this is a floating-point load or store: */"
	echo "  /* NB: all of the floating-point instructions that use"
	echo "     this preamble have bit two of op3 clear for a load,"
	echo "     and set for a store: */"
	echo "  fp_store = (TME_SPARC_INSN & TME_BIT(19 + 2));"
	echo ""
	echo "  /* if the FPU isn't in execute mode: */"
	echo "  fpu_mode = ic->tme_sparc_fpu_mode;"
	echo "  if (__tme_predict_false(fpu_mode != TME_SPARC_FPU_MODE_EXECUTE)) {"
	echo ""
	echo "    /* if this is a floating-point load, or if this is a"
	echo "       floating-point store and a floating-point exception"
	echo "       is pending: */"
	echo "    if (!fp_store"
	echo "        || fpu_mode == TME_SPARC_FPU_MODE_EXCEPTION_PENDING) {"
	echo ""
	echo "      /* do an FPU exception check: */"
	echo "      tme_sparc_fpu_exception_check(ic);"
	echo "    }"
	echo "  }"
	echo ""
	echo "  /* if this is not a load or store of a floating-point register: */"
	echo "  if (fpreg_format == TME_IEEE754_FPREG_FORMAT_NULL) {"
	echo "    return (float_buffer);"
	echo "  }"
	echo ""
	echo "  /* decode rd: */"
	echo "  fpreg_number"
	echo "    = tme_sparc_fpu_fpreg_decode(ic,"
	echo "                                 TME_FIELD_MASK_EXTRACTU(TME_SPARC_INSN,"
	echo "                                                         TME_SPARC_FORMAT3_MASK_RD),"
	echo "                                 fpreg_format);"
	echo ""
	echo "  /* make sure this floating-point register has the right precision: */"
	echo "  tme_sparc_fpu_fpreg_format(ic, fpreg_number, fpreg_format | TME_IEEE754_FPREG_FORMAT_BUILTIN);"
	echo ""
	echo "  /* if this is a floating-point load: */"
	echo "  if (!fp_store) {"
	echo ""
	echo "    /* mark rd as dirty: */"
	echo "    TME_SPARC_FPU_DIRTY(ic, fpreg_number);"
	echo "  }"
	echo ""
	echo "  /* return the floating-point register: */"
	echo "  return (&ic->tme_sparc_fpu_fpregs[fpreg_number]);"
	echo "}"
	echo "#define _tme_sparc${arch}_fpu_mem(ic) \\"
	echo "  do { _tme_sparc${arch}_fpu_mem_fpreg(ic, 0, &_tme_sparc_float_null); } while (/* CONSTCOND */ 0)"
    fi

    # permute over instruction:
    #
    case ${arch} in
    32) insns_arch= ;;
    64) insns_arch="ldx stx ldqf stqf ldxa stxa ldfa lddfa stfa stdfa ldqfa stqfa casa casxa mulx sdivx udivx" ;;
    esac
    for insn in \
	add \
	addcc \
	sub \
	subcc \
	or \
	orcc \
	orn \
	orncc \
	and \
	andcc \
	andn \
	andncc \
	xor \
	xorcc \
	xnor \
	xnorcc \
	addx \
	addxcc \
	subx \
	subxcc \
	taddcc taddcctv \
	tsubcc tsubcctv \
	umul umulcc smul smulcc \
	udiv udivcc sdiv sdivcc \
	sll \
	srl \
	sra \
	ldb stb \
	ldh sth \
	ld st \
	ldd std \
	ldstub ldstuba swap swapa \
	ldba stba \
	ldha stha \
	lda sta \
	ldda stda \
	jmpl \
	ldf lddf ldfsr \
	stf stdf stfsr \
	fpop1 fpop2 \
	mulscc \
	${insns_arch} \
	; do

	# if we're making the header, just emit declarations:
	#
	if $header; then
	    echo "TME_SPARC_FORMAT3_DECL(tme_sparc${arch}_${insn}, tme_uint${arch}_t);"
	    continue
	fi

	# an ALU instruction:
	#
	case ${insn} in
	add | sub | or | orn | and | andn | xor | xnor | \
	addx | subx | umul | smul | udiv | sdiv)
	    cc=false
	    ;;
	addcc | subcc | orcc | orncc | andcc | andncc | xorcc | xnorcc | \
	addxcc | subxcc | umulcc | smulcc | udivcc | sdivcc | \
	taddcc | tsubcc | taddcctv | tsubcctv | \
	mulscc)
	    cc=true
	    ;;
	*)
	    cc=
	    ;;
	esac
	if test "x${cc}" != x; then

	    # characterize each function:
	    #
	    sign=u ; size_src=${arch} ; size_dst=${arch} ; arith=logical ; with_c= ; tagged=
	    case "${insn}" in
	    add  | addcc)   op='src1 + src2' ; arith=add ;;
	    sub  | subcc)   op='src1 - src2' ; arith=sub ;;
	    or   | orcc)    op='src1 | src2' ;;
	    orn  | orncc)   op='src1 | ~src2' ;;
	    and  | andcc)   op='src1 & src2' ;;
	    andn | andncc)  op='src1 & ~src2' ;;
	    xor  | xorcc)   op='src1 ^ src2' ;;
	    xnor | xnorcc)  op='src1 ^ ~src2' ;;
	    addx | addxcc)  op='src1 + src2' ; arith=add ; with_c=+ ;;
	    subx | subxcc)  op='src1 - src2' ; arith=sub ; with_c=- ;;
	    taddcc)         op='src1 + src2' ; arith=add ; tagged=x ;;
	    taddcctv)       op='src1 + src2' ; arith=add ; tagged=tv ;;
	    tsubcc)         op='src1 - src2' ; arith=sub ; tagged=x ;;
	    tsubcctv)       op='src1 - src2' ; arith=sub ; tagged=tv ;;
	    umul | umulcc)  arith=mul ; size_src=32 ;;
	    smul | smulcc)  arith=mul ; size_src=32 ; sign= ;;
	    udiv | udivcc)  arith=udiv ; size_src=32 ; size_dst=32 ;;
	    sdiv | sdivcc)  arith=sdiv ; size_src=32 ; sign= ;;
	    mulscc)	    arith=add ; size_src=32 ; size_dst=32 ;;
	    *) echo "$0 internal error: unknown ALU function ${insn}" 1>&2 ; exit 1 ;;
	    esac

	    # open the function:
	    #
	    echo ""
	    echo "/* this does a sparc${arch} \"${insn} SRC1, SRC2, DST\": */"
	    echo "TME_SPARC_FORMAT3(tme_sparc${arch}_${insn}, tme_uint${arch}_t)"
	    echo "{"

	    # declare our locals:
	    #
	    echo "  tme_${sign}int${size_src}_t src1;"
	    echo "  tme_${sign}int${size_src}_t src2;"
	    echo "  tme_${sign}int${size_dst}_t dst;"
	    case "${insn}" in
	    umul* | smul* | udiv* | sdiv*)
		echo "  tme_${sign}int64_t val64;"
		;;
	    mulscc)
		echo "  tme_uint32_t y;"
		;;
	    esac
	    if ${cc}; then
		echo "  tme_uint32_t cc;"
	    fi
	    cc_plus=

	    echo ""
	    echo "  /* get the operands: */"
	    echo "  src1 = (tme_${sign}int${arch}_t) TME_SPARC_FORMAT3_RS1;"
	    echo "  src2 = (tme_${sign}int${arch}_t) TME_SPARC_FORMAT3_RS2;"

	    echo ""
	    echo "  /* perform the operation: */"
	    case "${insn}" in
	    umul | umulcc | smul | smulcc)
		echo "  val64 = (((tme_${sign}int64_t) src1) * src2);"
		echo "  ic->tme_sparc_ireg_uint32(TME_SPARC_IREG_Y${reg32_shift}) = (((tme_uint64_t) val64) >> 32);"
		echo "  dst = ((tme_${sign}int64_t) val64);"
		;;
	    udiv | udivcc | sdiv | sdivcc)
		echo "  val64 = ic->tme_sparc_ireg_uint32(TME_SPARC_IREG_Y${reg32_shift});"
		echo "  val64 = (val64 << 32) + (tme_uint32_t) src1;"
	        echo "  if (__tme_predict_false(src2 == 0)) {"
		echo "    tme_sparc${arch}_trap(ic, TME_SPARC${arch}_TRAP_division_by_zero);"
		echo "  }"
		echo "  val64 /= src2;"
		echo "  dst = (tme_${sign}int32_t) val64;"
		echo ""
		echo "  /* if the division overflowed: */"
		echo "  if (dst != val64) {"
		echo ""
		echo "    /* return the largest appropriate value: */"
		if test "x${sign}" = xu; then
		    echo "    dst = 0xffffffff;"
		else
		    echo "    dst = (tme_int32_t) ((val64 < 0) + (tme_uint32_t) 0x7fffffff);"
		fi
		if ${cc}; then
		    echo ""
		    echo "    /* set V: */"
		    echo "    cc = TME_SPARC${ccr}_ICC_V;"
		fi
		echo "  }"
		if ${cc}; then
		    echo ""
		    echo "  /* otherwise, the division didn't overflow: */"
		    echo "  else {"
		    echo ""
		    echo "    /* clear V: */"
		    echo "    cc = !TME_SPARC${ccr}_ICC_V;"
		    echo "  }"
		    cc_plus='+'
		fi
		;;
	    mulscc)
		echo ""
		echo "  /* \"(1) The multiplier is established as r[rs2] if the i field is zero, or "
		echo "     sign_ext(simm13) if the i field is one.\""
		echo ""
		echo "     \"(3) If the least significant bit of the Y register = 1, the shifted"
		echo "     value from step (2) is added to the multiplier. If the LSB of the"
		echo "     Y register = 0, then 0 is added to the shifted value from step (2).\" */"
		echo "  y = ic->tme_sparc_ireg_uint32(TME_SPARC_IREG_Y${reg32_shift});"
		echo "  if ((y & 1) == 0) {"
		echo "    src2 = 0;"
		echo "  }"
		echo ""
		echo "  /* \"(6) The Y register is shifted right by one bit, with the LSB of the"
		echo "     unshifted r[rs1] replacing the MSB of Y.\" */"
		echo "  y >>= 1;"
		echo "  if (src1 & 1) {"
		echo "    y += 0x80000000;"
		echo "  }"
		echo "  ic->tme_sparc_ireg_uint32(TME_SPARC_IREG_Y${reg32_shift}) = y;"
		echo ""
		echo "  /* \"(2) A 32-bit value is computed by shifting r[rs1] right by one"
		echo "     bit with (N xor V) from the PSR replacing the high-order bit."
		echo "     (This is the proper sign for the previous partial product.)\" */"
		echo "  src1 >>= 1;"
		echo "  if (((ic->${ccr_ireg} ^ (ic->${ccr_ireg} * (TME_SPARC${ccr}_ICC_N / TME_SPARC${ccr}_ICC_V))) & TME_SPARC${ccr}_ICC_N) != 0) {"
		echo "    src1 += 0x80000000;"
		echo "  }"
		echo ""
		echo "  /* \"(4) The sum from step (3) is written into r[rd].\" */"
		echo "  dst = src1 + src2;"
		echo ""
		echo "  /* \"(5) The integer condition codes, icc, are updated according to the"
		echo "     addition performed in step (3).\" */"
		;;
	    *)
		echo "  dst = ${op};"
		if test "x${with_c}" != x; then
		    echo "  dst ${with_c}= ((ic->${ccr_ireg} & TME_SPARC${ccr}_ICC_C) != 0);"
		fi
	    esac

	    # unless this is a tagged-and-trap-on-overflow operation:
	    #
	    if test "x${tagged}" != xtv; then
		echo ""
		echo "  /* store the destination: */"
		echo "  TME_SPARC_FORMAT3_RD = (tme_${sign}int${arch}_t) dst;"
	    fi

	    # if this instruction modifies the condition codes:
	    #
	    if ${cc}; then

		# set the 32-bit, and possibly the 64-bit, condition codes:
		#
		arch_cc=16
		while test `expr ${arch_cc} \< ${arch}` = 1; do
		    arch_cc=`expr ${arch_cc} \* 2`

		    case ${arch_cc} in
		    32) xcc=ICC ;;
		    64) xcc=XCC ;;
		    esac

		    echo ""
		    echo "  /* set Z if the destination is zero: */"
		    echo "  cc ${cc_plus}= ((((tme_int${arch_cc}_t) dst) == 0) * TME_SPARC${ccr}_${xcc}_Z);"
		    cc_plus='+'

		    if test `expr ${arch_cc} \<= ${size_dst}` = 1; then
			echo ""
			echo "  /* set N if the destination is negative: */"
			echo "  cc += ((((tme_int${arch_cc}_t) dst) < 0) * TME_SPARC${ccr}_${xcc}_N);"
		    fi

		    case $arith in
		    add)
			ones="(((tme_${sign}int${arch_cc}_t) 0) - 1)"

			echo ""
			echo "  /* if the operands are the same sign, and the destination has"
			echo "     a different sign, set V: */"
			echo "  cc += ((((tme_int${arch_cc}_t) ((src2 ^ dst) & (src1 ^ (src2 ^ ${ones})))) < 0) * TME_SPARC${ccr}_${xcc}_V);"

			echo ""
			echo "  /* if src1 and src2 both have the high bit set, or if dst does"
			echo "     not have the high bit set and either src1 or src2 does, set C: */"
			echo "  cc += (((tme_int${arch_cc}_t) (((tme_uint${arch_cc}_t) (src1 & src2)) | ((((tme_uint${arch_cc}_t) dst) ^ ${ones}) & ((tme_uint${arch_cc}_t) (src1 | src2))))) < 0) * TME_SPARC${ccr}_${xcc}_C;"
			;;
		    sub) 

			echo ""
			echo "  /* if the operands are different signs, and the destination has"
			echo "     a different sign from the first operand, set V: */"
			echo "  cc += ((((tme_int${arch_cc}_t) ((src1 ^ src2) & (src1 ^ dst))) < 0) * TME_SPARC${ccr}_${xcc}_V);"

			echo ""
			echo "  /* if src2 is greater than src1, set C: */"
			echo -n "  cc += ((((tme_uint${arch_cc}_t) src2) > ((tme_uint${arch_cc}_t) src1))"
			if test "x${with_c}" != x; then
			    echo -n " || (((tme_uint${arch_cc}_t) src2) == ((tme_uint${arch_cc}_t) src1) && (ic->${ccr_ireg} & TME_SPARC${ccr}_ICC_C))"
			fi
			echo ") * TME_SPARC${ccr}_${xcc}_C;"
			;;
		    logical | mul)
			;;
		    udiv | sdiv)
		        # the udivcc and sdivcc V are handled in the operation code
			;;
		    *) echo "$0 internal error: unknown arithmetic type ${arith}" 1>&2 ; exit 1 ;;
		    esac
		done
		
		# if this is a tagged operation:
		#
		if test "x${tagged}" != x; then

		    echo ""
		    echo "  /* set V if bits zero or one of src1 or src2 are set: */"
		    echo "  cc |= ((((src1 | src2) & 3) != 0) * TME_SPARC${ccr}_ICC_V);"

		    # if this is a tagged-and-trap-on-overflow operation:
		    #
		    if test "x${tagged}" = xtv; then

			echo ""
			echo "  /* trap on a tagged overflow: */"
			echo "  if (cc & TME_SPARC${ccr}_ICC_V) {"
			echo "    tme_sparc${arch}_trap(ic, TME_SPARC${arch}_TRAP_tag_overflow);"
			echo "  }"

			echo "  /* store the destination: */"
			echo "  TME_SPARC_FORMAT3_RD = (tme_${sign}int${arch}_t) dst;"
		    fi
		fi

		echo ""
		echo "  /* set the condition codes: */"
		echo -n "  ic->${ccr_ireg} = "
		if test ${arch} = 32; then
		    echo -n "(ic->${ccr_ireg} & ~TME_SPARC32_PSR_ICC) | "
		fi
		echo "cc;"
	    fi

	    echo ""
	    echo "  TME_SPARC_INSN_OK;"
	    echo "}"
	fi

	# a shift instruction:
	#
	case ${insn} in
	sll | srl | sra)

	    # get the sign of this shift:
	    #
	    if test ${insn} = sra; then sign= ; else sign=u; fi

	    echo ""
	    echo "/* the sparc${arch} ${insn} function: */"
	    echo "TME_SPARC_FORMAT3(tme_sparc${arch}_${insn}, tme_uint${arch}_t)"
	    echo "{"
	    echo "  tme_${sign}int${arch}_t dst;"
	    echo "  unsigned int count;"
	    echo ""
	    echo "  /* get the value and the shift count: */"
	    echo "  dst = TME_SPARC_FORMAT3_RS1;"
	    echo "  count = TME_SPARC_FORMAT3_RS2;"

	    # if we're on sparc64:
	    #
	    if test ${arch} = 64; then

		echo ""
		echo "  /* if the X bit is clear: */"
		echo "  if ((TME_SPARC_INSN & TME_BIT(12)) == 0) {"
		echo ""
		echo "    /* limit the count: */"
		echo "    count %= 32;"
		if test ${insn} != sll; then
		    echo ""
		    echo "    /* clip the value to 32 bits: */"
		    echo "    dst = (tme_${sign}int32_t) dst;"
		fi
		echo "  }"
	    fi

	    echo ""
	    echo "  /* limit the count: */"
	    echo "  count %= ${arch};"
	    echo ""
	    echo "  /* do the shift: */"
	    if test "${insn}" = sra; then
		echo "#ifdef SHIFTSIGNED_INT${arch}_T"
	    fi
	    echo "#if defined(SHIFTMAX_INT${arch}_T) && (SHIFTMAX_INT${arch}_T < (${arch} - 1))"
	    echo "#error \"cannot do full shifts of a tme_int${arch}_t\""
	    echo "#endif /* (SHIFTMAX_INT${arch}_T < (${arch} - 1)) */"
	    if test ${insn} = sll; then
		echo "  dst <<= count;"
	    else
		echo "  dst >>= count;"
	    fi
	    if test "${insn}" = sra; then
		echo "#else  /* !SHIFTSIGNED_INT${arch}_T */"
		echo "  for (; count-- > 0; ) {"
		echo "    dst = (dst & ~((tme_${sign}int${arch}_t) 1)) / 2;"
		echo "  }"
		echo "#endif /* !SHIFTSIGNED_INT${arch}_T */"
	    fi
	    
	    echo ""
	    echo "  /* store the destination: */"
	    echo "  TME_SPARC_FORMAT3_RD = dst;"
	    echo ""
	    echo "  TME_SPARC_INSN_OK;"
	    echo "}"
	    ;;
	esac

	# the sdivx, udivx, and mulx instructions:
	#
	case ${insn} in
	sdivx) sign= ;;
	udivx | mulx) sign=u ;;
	*) sign=x ;;
	esac
	if test "x${sign}" != xx; then
	    echo ""
	    echo "/* the sparc${arch} ${insn} function: */"
	    echo "TME_SPARC_FORMAT3(tme_sparc${arch}_${insn}, tme_uint${arch}_t)"
	    echo "{"
	    echo "  tme_${sign}int64_t src1;"
	    echo "  tme_${sign}int64_t src2;"
	    echo "  tme_${sign}int64_t dst;"
	    echo ""
	    echo "  /* get the operands: */"
	    echo "  src1 = TME_SPARC_FORMAT3_RS1;"
	    echo "  src2 = TME_SPARC_FORMAT3_RS2;"
	    echo ""
	    echo "  /* do the ${insn}: */"
	    if test ${insn} = mulx; then
		echo "  dst = src1 * src2;"
	    else
		echo "  if (__tme_predict_false(src2 == 0)) {"
		echo "    tme_sparc${arch}_trap(ic, TME_SPARC${arch}_TRAP_division_by_zero);"
		echo "  }"
		if test ${insn} = sdivx; then
		    echo "  dst = (src2 == -1 && src1 == (((tme_int64_t) 1) << 63) ? src1 : src1 / src2);"
		else
		    echo "  dst = src1 / src2;"
		fi
	    fi
	    echo ""
	    echo "  TME_SPARC_FORMAT3_RD = dst;"
	    echo "  TME_SPARC_INSN_OK;"
	    echo "}"
	fi

	# a load or store instruction:
	#
	size=
	case "${insn}" in
	ldb | stb | ldstub | ldba | stba | ldstuba) size=8 ;;
	ldh | sth | ldha | stha) size=16 ;;
	ld | st | swap | lda | sta | swapa) size=32 ;;
	ldd | std | ldda | stda) size=32 ;;
	ldx | stx | ldxa | stxa | casxa) size=64 ;;
	casa) size=32 ;;
	esac
	if test "x${size}" != x; then

	    # set the alternate space indication:
	    #
	    case "${insn}" in
	    *a) alternate=true ;;
	    *) alternate=false ;;
	    esac

	    # set the atomic and double indications:
	    #
	    atomic=false
	    double=false
	    case "${insn}" in
	    ldstub | ldstuba | swap | swapa | casa | casxa) atomic=true ;;
	    ldd* | std*) double=true ; size=64 ;;
	    esac

	    # if this is only a load, we are reading, otherwise we are writing:
	    #
	    cycle=write
	    capcycle=WRITE
	    slow=store
	    case "${insn}" in
	    ldstub*) ;;
	    ld*) 
		cycle=read
		capcycle=READ
		slow=load
		;;
	    esac

	    # start the instruction:
	    #
	    echo ""
	    echo "/* this does a sparc${arch} ${insn}: */"
	    echo "TME_SPARC_FORMAT3(tme_sparc${arch}_${insn}, tme_uint${arch}_t)"
	    echo "{"

	    # our locals:
	    #
	    if ${alternate}; then
		echo "  tme_uint32_t asi_mask_data;"
		asi_mask_data=asi_mask_data
	    else
		asi_mask_data="ic->tme_sparc_asi_mask_data"
	    fi
	    echo "  tme_uint${arch}_t address;"
	    if test ${arch} = 64 && ${alternate}; then
		echo "  tme_bus_context_t context;"
		context=context
	    else
		context="ic->tme_sparc_memory_context_default"
	    fi
	    echo "  tme_uint32_t asi_mask_flags_slow;"
	    echo "  struct tme_sparc_tlb *dtlb;"
	    echo -n "  "
	    if test ${slow} = load; then echo -n "const "; fi
	    echo "tme_shared tme_uint8_t *memory;"
	    echo "  tme_bus_context_t dtlb_context;"
	    echo "  tme_uint32_t endian_little;"
	    case "${insn}" in
	    ldd* | std* | swap*) echo "  tme_uint32_t value32;" ;;
	    ldstub*) ;;
	    cas*a)
	        echo "  unsigned int reg_rs2;"
	        echo "  tme_uint${size}_t value_compare${size};"
	        echo "  tme_uint${size}_t value_swap${size};"
	        echo "  tme_uint${size}_t value_read${size};"
		;;
	    ld*)
	        echo "  tme_uint${size}_t value${size};"
		size_extend=${arch}
		if test `expr ${size} \< ${arch}` = 1; then
		    if test `expr ${size} \< 32` = 1; then size_extend=32; fi
		    echo "  tme_uint${size_extend}_t value${size_extend};"
		fi
		;;
	    st*) echo "  tme_uint${size}_t value${size};" ;;
	    esac

	    if ${alternate}; then
		echo ""
		echo "  /* get the alternate ASI mask: */"
		echo "  asi_mask_data = _tme_sparc${arch}_alternate_asi_mask(ic);"
	    fi

	    echo ""
	    echo "  /* get the address: */"
	    case "${insn}" in
	    cas*a) echo "  address = TME_SPARC_FORMAT3_RS1;" ;;
	    *) echo "  address = TME_SPARC_FORMAT3_RS1 + TME_SPARC_FORMAT3_RS2;" ;;
	    esac
	    if test ${arch} = 64; then
		echo "  address &= ic->tme_sparc_address_mask;"
	    fi
		
	    echo ""
	    echo "#ifdef _TME_SPARC_STATS"
	    echo "  /* track statistics: */"
	    echo "  ic->tme_sparc_stats.tme_sparc_stats_memory_total++;"
	    echo "#endif /* _TME_SPARC_STATS */"

	    echo ""
	    echo "  /* verify and maybe replay this transfer: */"
	    if ${double}; then verify_size=32; else verify_size=${size}; fi
	    case "${insn}" in
	    ld*) verify_flags=TME_SPARC_RECODE_VERIFY_MEM_LOAD ;;
	    swap* | cas*a) verify_flags="TME_SPARC_RECODE_VERIFY_MEM_LOAD | TME_SPARC_RECODE_VERIFY_MEM_STORE" ;;
	    st*) verify_flags=TME_SPARC_RECODE_VERIFY_MEM_STORE ;;
	    *) verify_flags= ;;
	    esac
	    echo "  tme_sparc_recode_verify_mem(ic, &TME_SPARC_FORMAT3_RD,"
	    echo "                              ${asi_mask_data}, address,"
	    echo "                              (TME_RECODE_SIZE_${verify_size}"
	    echo "                               | ${verify_flags}));"
	    if ${double}; then
		echo "  tme_sparc_recode_verify_mem(ic, &TME_SPARC_FORMAT3_RD_ODD(tme_ic_ireg_uint${arch}),"
		echo "                              ${asi_mask_data}, address + sizeof(tme_uint32_t),"
		echo "                              (TME_RECODE_SIZE_${verify_size}"
		echo "                               | ${verify_flags}));"
	    fi
	    echo "  if (tme_sparc_recode_verify_replay_last_pc(ic) != 0) {"
	    echo "    TME_SPARC_INSN_OK;"
	    echo "  }"

	    # if this is some kind of a store, except for an ldstub:
	    #
	    case "${insn}" in
	    std*)
		echo ""
		echo "  /* log the values stored: */"
		echo "  tme_sparc_log(ic, 1000, TME_OK, "
		echo "               (TME_SPARC_LOG_HANDLE(ic),"
		echo "                _(\"${insn}\t0x%02x:0x%0"`expr ${arch} / 4`"\" TME_PRIx${arch} \":\t0x%08\" TME_PRIx32 \" 0x%08\" TME_PRIx32),"
		echo "                TME_SPARC_ASI_MASK_WHICH(${asi_mask_data} & ~TME_SPARC_ASI_MASK_FLAG_UNDEF),"
		echo "                address,"
		echo "                (tme_uint32_t) TME_SPARC_FORMAT3_RD,"
		echo "                (tme_uint32_t) TME_SPARC_FORMAT3_RD_ODD(tme_ic_ireg_uint${arch})));"
		;;
	    st* | swap* | cas*a)
		echo ""
		echo "  /* log the value stored: */"
		echo "  tme_sparc_log(ic, 1000, TME_OK, "
		echo "               (TME_SPARC_LOG_HANDLE(ic),"
		echo "                _(\"${insn}\t0x%02x:0x%0"`expr ${arch} / 4`"\" TME_PRIx${arch} \":\t0x%0"`expr ${size} / 4`"\" TME_PRIx${size}),"
		echo "                TME_SPARC_ASI_MASK_WHICH(${asi_mask_data} & ~TME_SPARC_ASI_MASK_FLAG_UNDEF),"
		echo "                address,"
		echo "                (tme_uint${size}_t) TME_SPARC_FORMAT3_RD));"
		;;
	    esac

	    if test "${context}" = context; then
		echo ""
		echo "  /* get the context: */"
		if test ${arch} = 64; then
		    echo "  context = ic->tme_sparc_memory_context_primary;"
		    echo "  if (__tme_predict_false(${asi_mask_data}"
		    echo "                          & (TME_SPARC64_ASI_FLAG_SECONDARY"
		    echo "                             + TME_SPARC64_ASI_MASK_FLAG_INSN_NUCLEUS))) {"
		    echo "    if (${asi_mask_data} & TME_SPARC64_ASI_FLAG_SECONDARY) {"
		    echo "      context = ic->tme_sparc_memory_context_secondary;"
		    echo "    }"
		    echo "    else if (TME_SPARC_MEMORY_FLAGS(ic) & TME_SPARC_MEMORY_FLAG_HAS_NUCLEUS) {"
		    echo "      context = 0;"
		    echo "    }"
		    echo "  }"
		fi
	    fi

	    echo ""
	    echo "  /* assume that no DTLB ASI mask flags will require a slow ${slow}: */"
	    echo "  asi_mask_flags_slow = 0;"
	    if test ${arch} = 64; then

		echo ""
		if test ${slow} != load || ${atomic}; then
		    echo "  /* a ${insn} traps on no-fault addresses: */"
		else
		    echo "  /* a ${insn} without a no-fault ASI traps on no-fault addresses: */"
		fi
		echo "  asi_mask_flags_slow |= TME_SPARC64_ASI_FLAG_NO_FAULT;"
		if ${atomic}; then
		    echo ""
		    echo "  /* a ${insn} traps on uncacheable addresses with side-effects: */"
		    echo "  asi_mask_flags_slow |= TME_SPARC64_ASI_MASK_FLAG_TLB_UNCACHEABLE;"
		fi

		if ${alternate}; then
		    echo ""
		    echo "  /* if this ${insn} is using a no-fault ASI: */"
		    echo "  if (__tme_predict_false(${asi_mask_data} & TME_SPARC64_ASI_FLAG_NO_FAULT)) {"
		    echo ""
		    if test ${slow} != load || ${atomic}; then
			echo "    /* a ${insn} with a no-fault ASI traps: */"
			echo "    asi_mask_flags_slow = 0 - (tme_uint32_t) 1;"
		    else
			echo "    /* a ${insn} with a no-fault ASI traps on addresses with side-effects: */"
			echo "    asi_mask_flags_slow = TME_SPARC64_ASI_MASK_FLAG_TLB_SIDE_EFFECTS;"
		    fi
		    echo "  }"
		fi
	    fi

	    echo ""
	    echo "  /* get and busy the DTLB entry: */"
	    echo "  dtlb = &ic->tme_sparc_tlbs[TME_SPARC_DTLB_ENTRY(ic, TME_SPARC_TLB_HASH(ic, ${context}, address))];"
	    echo "  tme_sparc_tlb_busy(dtlb);"

	    echo ""
	    echo "  /* assume that this DTLB applies and allows fast transfers: */"
	    echo "  memory = dtlb->tme_sparc_tlb_emulator_off_${cycle};"

	    echo ""
	    echo "  /* if this DTLB matches any context, it matches this context: */"
	    echo "  dtlb_context = dtlb->tme_sparc_tlb_context;"
	    echo "  if (dtlb_context > ic->tme_sparc_memory_context_max) {"
	    echo "    dtlb_context = ${context};"
	    echo "  }"

	    echo ""
	    echo "  /* we must call the slow ${slow} function if: */"
	    echo "  if (__tme_predict_false("
	    echo ""
	    echo "                          /* the DTLB entry is invalid: */"
	    echo "                          tme_bus_tlb_is_invalid(&dtlb->tme_sparc_tlb_bus_tlb)"
	    echo ""
	    echo "                          /* the DTLB entry does not match the context: */"
	    echo "                          || dtlb_context != ${context}"
	    echo ""
	    echo "                          /* the DTLB entry does not cover the needed addresses: */"
	    echo "                          || (address < (tme_bus_addr${arch}_t) dtlb->tme_sparc_tlb_addr_first)"
	    echo "                          || ((address + ((${size} / 8) - 1)) > (tme_bus_addr${arch}_t) dtlb->tme_sparc_tlb_addr_last)"
	    echo ""
	    echo "                          /* the DTLB entry does not cover the needed address space: */"
	    echo "                          || (!TME_SPARC_TLB_ASI_MASK_OK(dtlb, ${asi_mask_data}))"
	    echo ""
	    echo "                          /* the DTLB entry can't be used for a fast ${insn}: */"
	    echo "                          || (dtlb->tme_sparc_tlb_asi_mask & asi_mask_flags_slow) != 0"
	    echo ""
	    echo "                          /* the DTLB entry does not allow fast transfers: */"
	    if $atomic; then
		echo "                          || (memory != dtlb->tme_sparc_tlb_emulator_off_read)"
	    fi
	    echo "                          || (memory == TME_EMULATOR_OFF_UNDEF)"
	    if test ${size} != 8; then
		echo ""
		echo "                          /* the address is misaligned: */"
		echo "                          || ((address % (${size} / 8)) != 0)"
	    fi
	    if ${double}; then
		echo ""
		echo "                          /* the destination register number is odd: */"
		echo "                          || ((TME_SPARC_INSN & TME_BIT(25)) != 0)"
	    fi
	    echo ""
	    echo "                          )) {"

	    echo ""
	    echo "    /* call the slow ${slow} function: */"
	    echo "    memory = tme_sparc${arch}_ls(ic,"
	    echo "                            address,"
	    echo "                            &TME_SPARC_FORMAT3_RD,"
	    echo -n "                            (TME_SPARC_LSINFO_OP_"
	    if ${atomic}; then
		echo "ATOMIC"
	    elif test ${slow} = store; then
		echo "ST"
	    else
		echo "LD"
	    fi
	    echo -n "                             | "
	    case ${insn} in
	    ldd* | std*)
		echo "TME_SPARC_LSINFO_LDD_STD"
		echo -n "                             | "
		;;
	    esac
	    if ${alternate}; then
		echo "TME_SPARC_LSINFO_ASI(TME_SPARC_ASI_MASK_WHICH(${asi_mask_data} & ~TME_SPARC_ASI_MASK_FLAG_UNDEF))"
		echo "                             | TME_SPARC_LSINFO_A"
		echo -n "                             | "
	    fi
	    echo "(${size} / 8)));"
	    
	    if test ${slow} = store || ${alternate}; then
		echo ""
		echo "    /* if the slow ${slow} function did the transfer: */"
		echo "    if (__tme_predict_false(memory == TME_EMULATOR_OFF_UNDEF)) {"
		echo ""
		echo "      /* unbusy the TLB entry; */"
		echo "      tme_sparc_tlb_unbusy(dtlb);"

	    	# if this is some kind of a load, log the value loaded:
	    	#
		case ${insn} in
		ldd*)
		    echo ""
		    echo "      /* log the value loaded: */"
		    echo "      tme_sparc_recode_verify_mem_load(ic, &TME_SPARC_FORMAT3_RD);"
		    echo "      tme_sparc_recode_verify_mem_load(ic, &TME_SPARC_FORMAT3_RD_ODD(tme_ic_ireg_uint${arch}));"
		    echo "      tme_sparc_log(ic, 1000, TME_OK,"
		    echo "                   (TME_SPARC_LOG_HANDLE(ic),"
		    echo "                    _(\"${insn}\t0x%02x:0x%0"`expr ${arch} / 4`"\" TME_PRIx${arch} \":\t0x%0"`expr ${arch} / 4`"\" TME_PRIx${arch} \" 0x%0"`expr ${arch} / 4`"\" TME_PRIx${arch} \"\"),"
		    echo "                    TME_SPARC_ASI_MASK_WHICH(${asi_mask_data} & ~TME_SPARC_ASI_MASK_FLAG_UNDEF),"
		    echo "                    address,"
		    echo "                    TME_SPARC_FORMAT3_RD,"
		    echo "                    TME_SPARC_FORMAT3_RD_ODD(tme_ic_ireg_uint${arch})));"
		    ;;
		ld* | ldstub* | swap* | cas*a)
		    echo ""
		    echo "      /* log the value loaded: */"
		    echo "      tme_sparc_recode_verify_mem_load(ic, &TME_SPARC_FORMAT3_RD);"
		    echo "      tme_sparc_log(ic, 1000, TME_OK,"
		    echo "                   (TME_SPARC_LOG_HANDLE(ic),"
		    echo "                    _(\"${insn}\t0x%02x:0x%0"`expr ${arch} / 4`"\" TME_PRIx${arch} \":\t0x%0"`expr ${size} / 4`"\" TME_PRIx${arch}),"
		    echo "                    TME_SPARC_ASI_MASK_WHICH(${asi_mask_data} & ~TME_SPARC_ASI_MASK_FLAG_UNDEF),"
		    echo "                    address,"
		    echo "                    TME_SPARC_FORMAT3_RD));"
		    ;;
		esac
		echo ""
		echo "      TME_SPARC_INSN_OK;"
		echo "    }"
	    fi
	    echo "  }"

	    echo ""
	    echo "  /* get the byte order of this transfer: */"
	    if test ${arch} = 32; then
		echo "  endian_little = FALSE;"
	    elif test ${arch} = 64; then
		echo "  endian_little = ${asi_mask_data} & TME_SPARC64_ASI_FLAG_LITTLE;"
		echo "  if (__tme_predict_false(dtlb->tme_sparc_tlb_asi_mask & TME_SPARC64_ASI_FLAG_LITTLE)) {"
		echo "    if (TME_SPARC_MEMORY_FLAGS(ic) & TME_SPARC_MEMORY_FLAG_HAS_INVERT_ENDIAN) {"
		echo "      endian_little ^= TME_SPARC64_ASI_FLAG_LITTLE;"
		echo "    }"
		echo "    else {"
		echo "      assert (FALSE);"
		echo "    }"
		echo "  }"
	    fi

	    echo ""
	    echo "  /* do the fast transfer: */"
	    echo "  memory += address;"

	    # dispatch on the instruction:
	    #
	    case "${insn}" in
	    ldd*)
		echo "  value32 = tme_memory_bus_read32(((const tme_shared tme_uint32_t *) memory) + 0, dtlb->tme_sparc_tlb_bus_rwlock, sizeof(tme_uint32_t) * 2, sizeof(tme_uint${arch}_t));"
		echo "  value32 = (endian_little ? tme_letoh_u32(value32) : tme_betoh_u32(value32));"
		echo "  TME_SPARC_FORMAT3_RD = value32;"
		echo "  value32 = tme_memory_bus_read32(((const tme_shared tme_uint32_t *) memory) + 1, dtlb->tme_sparc_tlb_bus_rwlock, sizeof(tme_uint32_t) * 1, sizeof(tme_uint${arch}_t));"
		echo "  value32 = (endian_little ? tme_letoh_u32(value32) : tme_betoh_u32(value32));"
		echo "  TME_SPARC_FORMAT3_RD_ODD(tme_ic_ireg_uint${arch}) = value32;"
		;;
	    std*)
	        echo "  value32 = TME_SPARC_FORMAT3_RD;"
		echo "  value32 = (endian_little ? tme_htole_u32(value32) : tme_htobe_u32(value32));"
		echo "  tme_memory_bus_write32(((tme_shared tme_uint32_t *) memory) + 0, value32, dtlb->tme_sparc_tlb_bus_rwlock, sizeof(tme_uint32_t) * 2, sizeof(tme_uint${arch}_t));"
		echo "  value32 = TME_SPARC_FORMAT3_RD_ODD(tme_ic_ireg_uint${arch});"
		echo "  value32 = (endian_little ? tme_htole_u32(value32) : tme_htobe_u32(value32));"
		echo "  tme_memory_bus_write32(((tme_shared tme_uint32_t *) memory) + 1, value32, dtlb->tme_sparc_tlb_bus_rwlock, sizeof(tme_uint32_t) * 1, sizeof(tme_uint${arch}_t));"
		;;
	    ldstub*)
		echo "  TME_SPARC_FORMAT3_RD = tme_memory_atomic_xchg8(memory, 0xff, dtlb->tme_sparc_tlb_bus_rwlock, sizeof(tme_uint8_t));"
		;;
	    swap*)
		echo "  value32 = TME_SPARC_FORMAT3_RD;"
		echo "  value32 = (endian_little ? tme_htole_u32(value32) : tme_htobe_u32(value32));"
		echo "  value32 = tme_memory_atomic_xchg32((tme_shared tme_uint${size}_t *) memory, value32, dtlb->tme_sparc_tlb_bus_rwlock, sizeof(tme_uint8_t));"
		echo "  value32 = (endian_little ? tme_letoh_u32(value32) : tme_betoh_u32(value32));"
		echo "  TME_SPARC_FORMAT3_RD = value32;"
		;;
	    cas*a)
	        echo "  reg_rs2 = TME_FIELD_MASK_EXTRACTU(TME_SPARC_INSN, TME_SPARC_FORMAT3_MASK_RS2);"
		echo "  TME_SPARC_REG_INDEX(ic, reg_rs2);"
		echo "  value_compare${size} = ic->tme_sparc_ireg_uint${arch}(reg_rs2);"
		echo "  value_compare${size} = (endian_little ? tme_htole_u${size}(value_compare${size}) : tme_htobe_u${size}(value_compare${size}));"
		echo "  value_swap${size} = TME_SPARC_FORMAT3_RD;"
		echo "  value_swap${size} = (endian_little ? tme_htole_u${size}(value_swap${size}) : tme_htobe_u${size}(value_swap${size}));"
		echo "  value_read${size} = tme_memory_atomic_cx${size}((tme_shared tme_uint${size}_t *) memory, value_compare${size}, value_swap${size}, dtlb->tme_sparc_tlb_bus_rwlock, sizeof(tme_uint${size}_t));"
		echo "  value_read${size} = (endian_little ? tme_letoh_u${size}(value_read${size}) : tme_betoh_u${size}(value_read${size}));"
		echo "  TME_SPARC_FORMAT3_RD = value_read${size};"
		;;
	    ld*)
		echo "  value${size} = tme_memory_bus_read${size}((const tme_shared tme_uint${size}_t *) memory, dtlb->tme_sparc_tlb_bus_rwlock, sizeof(tme_uint${size}_t), sizeof(tme_uint${arch}_t));"
		if test ${size} != 8; then
		    echo "  value${size} = (endian_little ? tme_letoh_u${size}(value${size}) : tme_betoh_u${size}(value${size}));"
		fi
		if test `expr ${size} \< ${arch}` = 1; then
		    echo ""
		    echo "  /* possibly sign-extend the loaded value: */"
		    echo "  value${size_extend} = value${size};"
		    echo "  if (TME_SPARC_INSN & TME_BIT(22)) {"
		    echo "    value${size_extend} = (tme_uint${size_extend}_t) (tme_int${size_extend}_t) (tme_int${size}_t) value${size_extend};"
		    echo "  }"
		fi
		echo "  TME_SPARC_FORMAT3_RD = (tme_uint${arch}_t) (tme_int${arch}_t) (tme_int${size_extend}_t) value${size_extend};"
		;;
	    st*)
		echo "  value${size} = TME_SPARC_FORMAT3_RD;"
		if test ${size} != 8; then
		    echo "  value${size} = (endian_little ? tme_htole_u${size}(value${size}) : tme_htobe_u${size}(value${size}));"
		fi
		echo "  tme_memory_bus_write${size}((tme_shared tme_uint${size}_t *) memory, value${size}, dtlb->tme_sparc_tlb_bus_rwlock, sizeof(tme_uint${size}_t), sizeof(tme_uint${arch}_t));"
		;;
	    *) echo "$PROG internal error: unknown memory insn ${insn}" 1>&2 ; exit 1 ;;
	    esac

	    echo ""
	    echo "  /* unbusy the DTLB entry: */"
	    echo "  tme_sparc_tlb_unbusy(dtlb);"
		
	    # if this is some kind of a load, log the value loaded:
	    #
	    case ${insn} in
	    ldd*)
		echo ""
		echo "  /* log the value loaded: */"
		echo "  tme_sparc_recode_verify_mem_load(ic, &TME_SPARC_FORMAT3_RD);"
		echo "  tme_sparc_recode_verify_mem_load(ic, &TME_SPARC_FORMAT3_RD_ODD(tme_ic_ireg_uint${arch}));"
		echo "  tme_sparc_log(ic, 1000, TME_OK,"
		echo "               (TME_SPARC_LOG_HANDLE(ic),"
		echo "                _(\"${insn}\t0x%02x:0x%0"`expr ${arch} / 4`"\" TME_PRIx${arch} \":\t0x%0"`expr ${arch} / 4`"\" TME_PRIx${arch} \" 0x%0"`expr ${arch} / 4`"\" TME_PRIx${arch} \"\"),"
		echo "                TME_SPARC_ASI_MASK_WHICH(${asi_mask_data} & ~TME_SPARC_ASI_MASK_FLAG_UNDEF),"
		echo "                address,"
		echo "                TME_SPARC_FORMAT3_RD,"
		echo "                TME_SPARC_FORMAT3_RD_ODD(tme_ic_ireg_uint${arch})));"
		;;
	    ld* | ldstub* | swap* | cas*a)
		echo ""
		echo "  /* log the value loaded: */"
		echo "  tme_sparc_recode_verify_mem_load(ic, &TME_SPARC_FORMAT3_RD);"
		echo "  tme_sparc_log(ic, 1000, TME_OK,"
		echo "               (TME_SPARC_LOG_HANDLE(ic),"
		echo "                _(\"${insn}\t0x%02x:0x%0"`expr ${arch} / 4`"\" TME_PRIx${arch} \":\t0x%0"`expr ${size} / 4`"\" TME_PRIx${arch}),"
		echo "                TME_SPARC_ASI_MASK_WHICH(${asi_mask_data} & ~TME_SPARC_ASI_MASK_FLAG_UNDEF),"
		echo "                address,"
		echo "                TME_SPARC_FORMAT3_RD));"
		;;
	    esac

	    echo ""
	    echo "  TME_SPARC_INSN_OK;"
	    echo "}"
	fi

	# the jmpl instruction:
	#
	if test ${insn} = jmpl; then

	    echo ""
	    echo "/* this does a sparc${arch} ${insn}: */"
	    echo "TME_SPARC_FORMAT3(tme_sparc${arch}_${insn}, tme_uint${arch}_t)"
	    echo "{"
	    echo "  tme_uint${arch}_t pc_next_next;"
	    echo "  tme_uint32_t ls_faults;"
	    echo ""
	    echo "  /* \"The JMPL instruction causes a register-indirect delayed control"
	    echo "     transfer to the address given by r[rs1] + r[rs2] if the i field is"
	    echo "     zero, or r[rs1] + sign_ext(simm13) if the i field is one. The JMPL"
	    echo "     instruction copies the PC, which contains the address of the JMPL"
	    echo "     instruction, into register r[rd]. If either of the low-order two"
	    echo "     bits of the jump address is nonzero, a mem_address_not_aligned"
	    echo "     trap occurs.\" */"
	    echo ""
	    echo "  /* get the target address: */"
	    echo "  pc_next_next = TME_SPARC_FORMAT3_RS1 + TME_SPARC_FORMAT3_RS2;"
	    if test ${arch} = 64; then
		echo "  pc_next_next &= ic->tme_sparc_address_mask;"
	    fi
	    echo ""
	    echo "  /* set the delayed control transfer: */"
	    echo "  ic->tme_sparc_ireg_uint${arch}(TME_SPARC_IREG_PC_NEXT_NEXT) = pc_next_next;"
	    echo ""
	    echo "  /* check the target address: */"
	    echo "  ls_faults = TME_SPARC_LS_FAULT_NONE;"
	    if test ${arch} = 64; then
		echo "  if (__tme_predict_false((pc_next_next"
		echo "                           + ic->tme_sparc${arch}_ireg_va_hole_start)"
		echo "                          > ((ic->tme_sparc${arch}_ireg_va_hole_start * 2) - 1))) {"
		echo "    ls_faults += TME_SPARC64_LS_FAULT_VA_RANGE_NNPC;"
		echo "  }"
	    fi
	    echo "  if (__tme_predict_false((pc_next_next % sizeof(tme_uint32_t)) != 0)) {"
	    echo "    ls_faults += TME_SPARC_LS_FAULT_ADDRESS_NOT_ALIGNED;"
	    echo "  }"
	    echo "  if (__tme_predict_false(ls_faults != TME_SPARC_LS_FAULT_NONE)) {"
	    echo "    tme_sparc_nnpc_trap(ic, ls_faults);"
	    echo "  }"
	    echo ""
	    echo "  /* write the PC of the jmpl into r[rd]: */"
	    echo "  TME_SPARC_FORMAT3_RD = ic->tme_sparc_ireg_uint${arch}(TME_SPARC_IREG_PC);"
	    echo ""
	    echo "  /* log an indirect call instruction, which has 15 (%o7) for rd: */"
	    echo "  if (TME_FIELD_MASK_EXTRACTU(TME_SPARC_INSN, TME_SPARC_FORMAT3_MASK_RD) == 15) {"
	    echo "    tme_sparc_log(ic, 250, TME_OK,"
	    echo "                  (TME_SPARC_LOG_HANDLE(ic),"
	    echo "                   _(\"call 0x%0"`expr ${arch} / 4`"\" TME_PRIx${arch}),"
	    echo "                   pc_next_next));"
	    echo "  }"
	    echo ""
	    echo "  /* log a ret or retl instruction, which has 0 (%g0) for rd,"
	    echo "     either 31 (%i7) or 15 (%o7) for rs1, and 8 for simm13: */"
	    echo "  else if ((TME_SPARC_INSN | (16 << 14))"
	    echo "           == ((tme_uint32_t) (0x2 << 30) | (0 << 25) | (0x38 << 19) | (31 << 14) | (0x1 << 13) | 8)) {"
	    echo "    tme_sparc_log(ic, 250, TME_OK,"
	    echo "                  (TME_SPARC_LOG_HANDLE(ic),"
	    echo "                   _(\"retl 0x%0"`expr ${arch} / 4`"\" TME_PRIx${arch}),"
	    echo "                   pc_next_next));"
	    echo "  }"
	    echo ""
	    echo "  TME_SPARC_INSN_OK;"
	    echo "}"
	fi

	# this may be an alternate-space version of a floating-point
	# load or store instruction:
	#
	case ${insn} in *a) alternate=a ;; *) alternate= ;; esac

	# the ldf instruction:
	#
	if test ${insn} = "ldf${alternate}"; then

	    echo ""
	    echo "/* this does a sparc${arch} ${insn}: */"
	    echo "TME_SPARC_FORMAT3(tme_sparc${arch}_${insn}, tme_uint${arch}_t)"
	    echo "{"
	    echo "  tme_uint32_t misaligned;"
	    echo "  struct tme_float float_buffer;"
	    echo "  struct tme_float *fpreg;"
	    echo ""
	    echo "  /* get the least significant 32 bits of the address: */"
	    echo "  misaligned = TME_SPARC_FORMAT3_RS1;"
	    echo "  misaligned += (tme_uint32_t) TME_SPARC_FORMAT3_RS2;"
	    if test "${arch}${alternate}" = 64a; then
		echo ""
		echo "  /* see if the address is misaligned for the ASI: */"
		echo "  misaligned = (*ic->_tme_sparc_ls_asi_misaligned)(ic, misaligned);"
	    fi
	    echo ""
	    echo "  /* decode rd: */"
	    echo "  float_buffer.tme_float_format = TME_FLOAT_FORMAT_IEEE754_SINGLE;"
	    echo "  fpreg"
	    echo "    = _tme_sparc${arch}_fpu_mem_fpreg(ic,"
	    echo "                                 misaligned,"
	    echo "                                 &float_buffer);"
	    echo ""
	    echo "  /* do the load: */"
	    echo "  tme_sparc${arch}_ld${alternate}(ic, _rs1, _rs2, &ic->tme_sparc_ireg_uint${arch}(TME_SPARC_IREG_FPX));"
	    echo ""
	    echo "  /* set the floating-point register value: */"
	    echo "  assert (fpreg != &float_buffer);"
	    echo "  fpreg->tme_float_format = TME_FLOAT_FORMAT_IEEE754_SINGLE;"
	    echo "  fpreg->tme_float_value_ieee754_single"
	    echo "    = ic->tme_sparc_ireg_uint32(TME_SPARC_IREG_FPX${reg32_shift});"
	    echo ""
	    echo "  TME_SPARC_INSN_OK;"
	    echo "}"
	fi

	# the stf instruction:
	#
	if test ${insn} = "stf${alternate}"; then

	    echo ""
	    echo "/* this does a sparc${arch} ${insn}: */"
	    echo "TME_SPARC_FORMAT3(tme_sparc${arch}_${insn}, tme_uint${arch}_t)"
	    echo "{"
	    echo "  tme_uint32_t misaligned;"
	    echo "  struct tme_float float_buffer;"
	    echo "  const struct tme_float *fpreg;"
	    echo "  const tme_uint32_t *value_single;"
	    echo ""
	    echo "  /* get the least significant 32 bits of the address: */"
	    echo "  misaligned = TME_SPARC_FORMAT3_RS1;"
	    echo "  misaligned += (tme_uint32_t) TME_SPARC_FORMAT3_RS2;"
	    if test "${arch}${alternate}" = 64a; then
		echo ""
		echo "  /* see if the address is misaligned for the ASI: */"
		echo "  misaligned = (*ic->_tme_sparc_ls_asi_misaligned)(ic, misaligned);"
	    fi
	    echo ""
	    echo "  /* decode rd: */"
	    echo "  float_buffer.tme_float_format = TME_FLOAT_FORMAT_IEEE754_SINGLE;"
	    echo "  fpreg"
	    echo "    = _tme_sparc${arch}_fpu_mem_fpreg(ic,"
	    echo "                                 misaligned,"
	    echo "                                 &float_buffer);"
	    echo ""
	    echo "  /* get this single floating-point register in IEEE754 single-precision format: */"
	    echo "  value_single = tme_ieee754_single_value_get(fpreg, &float_buffer.tme_float_value_ieee754_single);"
	    echo ""
	    echo "  /* set the floating-point register value: */"
	    echo "  ic->tme_sparc_ireg_uint32(TME_SPARC_IREG_FPX${reg32_shift}) = *value_single;"
	    echo ""
	    echo "  /* do the store: */"
	    echo "  tme_sparc${arch}_st${alternate}(ic, _rs1, _rs2, &ic->tme_sparc_ireg_uint${arch}(TME_SPARC_IREG_FPX));"
	    echo ""
	    echo "  assert (fpreg != &float_buffer);"
	    echo "  TME_SPARC_INSN_OK;"
	    echo "}"
	fi

	# the lddf instruction:
	#
	if test ${insn} = "lddf${alternate}"; then

	    echo ""
	    echo "/* this does a sparc${arch} ${insn}: */"
	    echo "TME_SPARC_FORMAT3(tme_sparc${arch}_${insn}, tme_uint${arch}_t)"
	    echo "{"
	    echo "  tme_uint${arch}_t address;"
	    echo "  tme_uint32_t misaligned;"
	    echo "  struct tme_float float_buffer;"
	    echo "  struct tme_float *fpreg;"
	    if test ${arch} != 32; then
		echo "  tme_uint${arch}_t offset;"
	    fi
	    echo ""
	    echo "  /* get the address: */"
	    echo "  address = TME_SPARC_FORMAT3_RS1 + TME_SPARC_FORMAT3_RS2;"
	    echo ""
	    echo "  /* get the least significant 32 bits of the address: */"
	    echo "  misaligned = address;"
	    if test "${arch}${alternate}" = 64a; then
		echo ""
		echo "  /* see if the address is misaligned for the ASI: */"
		echo "  misaligned = (*ic->_tme_sparc_ls_asi_misaligned)(ic, misaligned);"
	    fi
	    echo ""
	    echo "  /* decode rd: */"
	    echo "  float_buffer.tme_float_format = TME_FLOAT_FORMAT_IEEE754_DOUBLE;"
	    echo "  fpreg"
	    echo "    = _tme_sparc${arch}_fpu_mem_fpreg(ic,"
	    echo "                                 misaligned,"
	    echo "                                 &float_buffer);"
	    echo ""
	    if test ${arch} = 32; then
		echo "  /* do the load: */"
		echo "  tme_sparc${arch}_ldd(ic, _rs1, _rs2, &ic->tme_sparc_ireg_uint32(TME_SPARC_IREG_FPX${reg32_shift}));"
		echo ""
		echo "  /* set the double floating-point register value: */"
		echo "  assert (fpreg != &float_buffer);"
		echo "  fpreg->tme_float_format = TME_FLOAT_FORMAT_IEEE754_DOUBLE;"
		echo "  fpreg->tme_float_value_ieee754_double.tme_value64_uint32_hi"
		echo "    = ic->tme_sparc_ireg_uint32((TME_SPARC_IREG_FPX${reg32_shift}) + 0);"
		echo "  fpreg->tme_float_value_ieee754_double.tme_value64_uint32_lo"
		echo "    = ic->tme_sparc_ireg_uint32((TME_SPARC_IREG_FPX${reg32_shift}) + 1);"
	    else
		echo "  /* if bit two of the address is set, and this SPARC supports"
		echo "     32-bit-aligned ${insn} instructions: */"
		echo "  if ((misaligned & sizeof(tme_uint32_t))"
		echo "      && fpreg != &float_buffer) {"
		echo ""
		echo "    /* do two 32-bit loads: */"
		echo "    offset = sizeof(tme_uint32_t) * 0;"
		echo "    tme_sparc${arch}_ld${alternate}(ic, &address, &offset, &ic->tme_sparc_ireg_uint${arch}(TME_SPARC_IREG_FPX + 0));"
		echo "    offset = sizeof(tme_uint32_t) * 1;"
		echo "    tme_sparc${arch}_ld${alternate}(ic, &address, &offset, &ic->tme_sparc_ireg_uint${arch}(TME_SPARC_IREG_FPX + 1));"
		echo ""
		echo "    /* set the double floating-point register value: */"
		echo "    fpreg->tme_float_format = TME_FLOAT_FORMAT_IEEE754_DOUBLE;"
		echo "    fpreg->tme_float_value_ieee754_double.tme_value64_uint32_hi"
		echo "      = ic->tme_sparc_ireg_uint64(TME_SPARC_IREG_FPX + 0);"
		echo "    fpreg->tme_float_value_ieee754_double.tme_value64_uint32_lo"
		echo "      = ic->tme_sparc_ireg_uint64(TME_SPARC_IREG_FPX + 1);"
		echo "  }"
		echo ""
		echo "  /* otherwise, bit two of the address is not set, or this SPARC"
		echo "     doesn't support 32-bit-aligned ${insn} instructions: */"
		echo "  else {"
		echo ""
		echo "    /* do an ldx${alternate}-style load: */"
		echo "    tme_sparc${arch}_ldx${alternate}(ic, _rs1, _rs2, &ic->tme_sparc_ireg_uint${arch}(TME_SPARC_IREG_FPX));"
		echo ""
		echo "    /* set the double floating-point register value: */"
		echo "    assert (fpreg != &float_buffer);"
		echo "    fpreg->tme_float_format = TME_FLOAT_FORMAT_IEEE754_DOUBLE;"
		echo "    fpreg->tme_float_value_ieee754_double.tme_value64_uint"
		echo "      = ic->tme_sparc_ireg_uint64(TME_SPARC_IREG_FPX);"
		echo "  }"
	    fi
	    echo ""
	    echo "  TME_SPARC_INSN_OK;"
	    echo "}"
	fi

	# the stdf instruction:
	#
	if test ${insn} = "stdf${alternate}"; then

	    echo ""
	    echo "/* this does a sparc${arch} ${insn}: */"
	    echo "TME_SPARC_FORMAT3(tme_sparc${arch}_${insn}, tme_uint${arch}_t)"
	    echo "{"
	    echo "  tme_uint${arch}_t address;"
	    echo "  tme_uint32_t misaligned;"
	    echo "  struct tme_float float_buffer;"
	    echo "  struct tme_float *fpreg;"
	    echo "  const union tme_value64 *value_double;"
	    if test ${arch} != 32; then
		echo "  tme_uint${arch}_t offset;"
	    fi
	    echo ""
	    echo "  /* get the address: */"
	    echo "  address = TME_SPARC_FORMAT3_RS1 + TME_SPARC_FORMAT3_RS2;"
	    echo ""
	    echo "  /* get the least significant 32 bits of the address: */"
	    echo "  misaligned = address;"
	    if test "${arch}${alternate}" = 64a; then
		echo ""
		echo "  /* see if the address is misaligned for the ASI: */"
		echo "  misaligned = (*ic->_tme_sparc_ls_asi_misaligned)(ic, misaligned);"
	    fi
	    echo ""
	    echo "  /* decode rd: */"
	    echo "  float_buffer.tme_float_format = TME_FLOAT_FORMAT_IEEE754_DOUBLE;"
	    echo "  fpreg"
	    echo "    = _tme_sparc${arch}_fpu_mem_fpreg(ic,"
	    echo "                                 misaligned,"
	    echo "                                 &float_buffer);"
	    echo ""
	    echo "  /* get this double floating-point register in IEEE754 double-precision format: */"
	    echo "  value_double = tme_ieee754_double_value_get(fpreg, &float_buffer.tme_float_value_ieee754_double);"
	    echo ""
	    if test ${arch} = 32; then
		echo "  /* set the floating-point register value: */"
		echo "  ic->tme_sparc_ireg_uint32((TME_SPARC_IREG_FPX${reg32_shift}) + 0)"
		echo "    = value_double->tme_value64_uint32_hi;"
		echo "  ic->tme_sparc_ireg_uint32((TME_SPARC_IREG_FPX${reg32_shift}) + 1)"
		echo "    = value_double->tme_value64_uint32_lo;"
		echo ""
		echo "  /* do the store: */"
		echo "  tme_sparc${arch}_std(ic, _rs1, _rs2, &ic->tme_sparc_ireg_uint32(TME_SPARC_IREG_FPX${reg32_shift}));"
	    else
		echo "  /* if bit two of the address is set, and this SPARC supports"
		echo "     32-bit-aligned ${insn} instructions: */"
		echo "  if ((misaligned & sizeof(tme_uint32_t))"
		echo "      && fpreg != &float_buffer) {"
		echo ""
		echo "    /* set the floating-point register value: */"
		echo "    ic->tme_sparc_ireg_uint64(TME_SPARC_IREG_FPX + 0)"
		echo "      = value_double->tme_value64_uint32_hi;"
		echo "    ic->tme_sparc_ireg_uint32(TME_SPARC_IREG_FPX + 1)"
		echo "      = value_double->tme_value64_uint32_lo;"
		echo ""
		echo "    /* do two 32-bit stores: */"
		echo "    offset = sizeof(tme_uint32_t) * 0;"
		echo "    tme_sparc${arch}_st${alternate}(ic, &address, &offset, &ic->tme_sparc_ireg_uint${arch}(TME_SPARC_IREG_FPX + 0));"
		echo "    offset = sizeof(tme_uint32_t) * 1;"
		echo "    tme_sparc${arch}_st${alternate}(ic, &address, &offset, &ic->tme_sparc_ireg_uint${arch}(TME_SPARC_IREG_FPX + 1));"
		echo "  }"
		echo ""
		echo "  /* otherwise, bit two of the address is not set, or this SPARC"
		echo "     doesn't support 32-bit-aligned ${insn} instructions: */"
		echo "  else {"
		echo ""
		echo "    /* set the floating-point register value: */"
		echo "    ic->tme_sparc_ireg_uint64(TME_SPARC_IREG_FPX)"
		echo "      = value_double->tme_value64_uint;"
		echo ""
		echo "    /* do an stx${alternate}-style store: */"
		echo "    tme_sparc${arch}_stx${alternate}(ic, _rs1, _rs2, &ic->tme_sparc_ireg_uint${arch}(TME_SPARC_IREG_FPX));"
		echo "  }"
	    fi
	    echo ""
	    echo "  assert (fpreg != &float_buffer);"
	    echo "  TME_SPARC_INSN_OK;"
	    echo "}"
	fi

	# the ldfsr instruction:
	#
	if test ${insn} = ldfsr; then

	    echo ""
	    echo "/* this does a sparc${arch} ${insn}: */"
	    echo "TME_SPARC_FORMAT3(tme_sparc${arch}_${insn}, tme_uint${arch}_t)"
	    echo "{"
	    echo "  tme_uint32_t fsr;"
	    if test ${arch} != 32; then
		echo "  tme_uint32_t reg_rd;"
		echo ""
		echo "  /* see if this is an ldfsr or an ldxfsr: */"
		echo "  reg_rd = TME_FIELD_MASK_EXTRACTU(TME_SPARC_INSN, TME_SPARC_FORMAT3_MASK_RD);"
		echo "  if (__tme_predict_false(reg_rd > 1)) {"
		echo "    TME_SPARC_INSN_ILL(ic);"
		echo "  }"
	    fi
	    echo ""
	    echo "  _tme_sparc${arch}_fpu_mem(ic);"
	    echo ""
	    if test ${arch} = 32; then
		echo "  /* do the load: */"
	    else
		echo "  /* if this is an ldxfsr: */"
		echo "  if (reg_rd == 1) {"
		echo ""
		echo "    /* do the load: */"
		echo "    tme_sparc${arch}_ldx(ic, _rs1, _rs2,  &ic->tme_sparc_ireg_uint${arch}(TME_SPARC_IREG_FPX));"
		echo ""
		echo "    /* update the extended FSR: */"
		echo "    ic->tme_sparc_fpu_xfsr"
		echo "      = (ic->tme_sparc_ireg_uint32((TME_SPARC_IREG_FPX${reg32_shift}) + 1)"
		echo "         & 0x3f /* fcc3 .. fcc1 */);"
		echo "  }"
		echo ""
		echo "  /* otherwise, this is an ldfsr.  do the load: */"
		echo "  else"
		echo -n "  "
	    fi
	    echo "  tme_sparc${arch}_ld(ic, _rs1, _rs2, &ic->tme_sparc_ireg_uint${arch}(TME_SPARC_IREG_FPX));"
	    echo ""
	    echo "  /* update the FSR: */"
	    echo "  fsr = ic->tme_sparc_ireg_uint32(TME_SPARC_IREG_FPX${reg32_shift});"
	    echo "  /* \"An LDFSR instruction does not affect ftt.\" */"
	    echo "  /* \"The LDFSR instruction does not affect qne.\" */"
	    echo "  fsr &= ~(TME_SPARC_FSR_VER | TME_SPARC_FSR_FTT | TME_SPARC_FSR_QNE);"
	    echo "  ic->tme_sparc_fpu_fsr = (ic->tme_sparc_fpu_fsr & (TME_SPARC_FSR_VER | TME_SPARC_FSR_FTT | TME_SPARC_FSR_QNE)) | fsr;"
	    echo ""
	    echo "  TME_SPARC_INSN_OK;"
	    echo "}"
	fi

	# the stfsr instruction:
	#
	if test ${insn} = stfsr; then

	    echo ""
	    echo "/* this does a sparc${arch} ${insn}: */"
	    echo "TME_SPARC_FORMAT3(tme_sparc${arch}_${insn}, tme_uint${arch}_t)"
	    echo "{"
	    if test ${arch} = 64; then
		echo "  tme_uint32_t reg_rd;"
		echo ""
		echo "  /* see if this is an stfsr or an stxfsr: */"
		echo "  reg_rd = TME_FIELD_MASK_EXTRACTU(TME_SPARC_INSN, TME_SPARC_FORMAT3_MASK_RD);"
		echo "  if (__tme_predict_false(reg_rd > 1)) {"
		echo "    TME_SPARC_INSN_ILL(ic);"
		echo "  }"
	    fi
	    echo ""
	    echo "  _tme_sparc${arch}_fpu_mem(ic);"
	    echo ""
	    echo "  /* set the FSR value to store: */"
	    echo "  ic->tme_sparc_ireg_uint32(TME_SPARC_IREG_FPX${reg32_shift}) = ic->tme_sparc_fpu_fsr;"
	    echo ""
	    if test ${arch} = 32; then
		echo "  /* do the store: */"
	    else
		echo "  /* if this is an stxfsr: */"
		echo "  if (reg_rd == 1) {"
		echo ""
		echo "    /* set in the extended FSR to store and do the store: */"
		echo "    ic->tme_sparc_ireg_uint32((TME_SPARC_IREG_FPX${reg32_shift}) + 1) = ic->tme_sparc_fpu_xfsr;"
		echo "    tme_sparc${arch}_stx(ic, _rs1, _rs2, &ic->tme_sparc_ireg_uint${arch}(TME_SPARC_IREG_FPX));"
		echo "  }"
		echo ""
		echo "  /* otherwise, this is a stfsr.  do the store: */"
		echo "  else"
		echo -n "  "
	    fi
	    echo "  tme_sparc${arch}_st(ic, _rs1, _rs2, &ic->tme_sparc_ireg_uint${arch}(TME_SPARC_IREG_FPX));"
	    echo ""
	    echo "  TME_SPARC_INSN_OK;"
	    echo "}"
	fi

	# the fpop1 and fpop2 instructions:
	#
	if test ${insn} = fpop1 || test ${insn} = fpop2; then

	    echo ""
	    echo "/* this does a sparc${arch} ${insn}: */"
	    echo "TME_SPARC_FORMAT3(tme_sparc${arch}_${insn}, tme_uint${arch}_t)"
	    echo "{"
	    echo "  TME_SPARC_INSN_FPU;"
	    echo "  tme_sparc_fpu_${insn}(ic);"
	    echo "  TME_SPARC_INSN_OK;"
	    echo "}"
	fi

    done

    # the slow atomic function:
    #
    if $header; then
	echo "void tme_sparc${arch}_atomic _TME_P((struct tme_sparc *, struct tme_sparc_ls *));"
    else
	echo ""
	echo "/* this does a slow atomic operation: */"
	echo "void"
	echo "tme_sparc${arch}_atomic(struct tme_sparc *ic, struct tme_sparc_ls *ls)"
	echo "{"
	echo "  tme_uint32_t endian_little;"
	echo "  tme_uint32_t insn;"
	if test ${arch} = 64; then
	    echo "  tme_uint${arch}_t value${arch};"
	    echo "  tme_uint${arch}_t value_swap${arch};"
	    echo "  unsigned int reg_rs2;"
	fi
	echo "  tme_uint32_t value32;"
	echo "  tme_uint32_t value_swap32;"
	echo "  tme_uint32_t size;"
	echo ""
	echo "  /* if this is the beginning of the operation: */"
	echo "  if (ls->tme_sparc_ls_state == 0) {"
	echo ""
	echo "    /* start the load part of the operation: */"
	echo "    ls->tme_sparc_ls_state = ls->tme_sparc_ls_size;"
	echo "    assert (ls->tme_sparc_ls_state != 0"
	echo "            && (ls->tme_sparc_ls_state & TME_BIT(7)) == 0);"
	echo ""
	echo "    /* the load must start at the beginning of the buffer: */"
	echo "    assert (ls->tme_sparc_ls_buffer_offset == 0);"
	echo "  }"
	echo ""
	echo "  /* if this is the load part of the operation: */"
	echo "  if ((ls->tme_sparc_ls_state & TME_BIT(7)) == 0) {"
	echo ""
	echo "    /* do one slow load cycle: */"
	echo "    tme_sparc${arch}_load(ic, ls);"
	echo ""
	echo "    /* if the slow load cycle did not load all of the data: */"
	echo "    if (__tme_predict_false(ls->tme_sparc_ls_size != 0)) {"
	echo "      return;"
	echo "    }"
	echo ""
	echo "    /* get the byte order of this transfer: */"
	if test ${arch} = 32; then
	    echo "    endian_little = FALSE;"
	else
	    echo "    endian_little = ls->tme_sparc_ls_lsinfo & TME_SPARC_LSINFO_ENDIAN_LITTLE;"
	fi
	echo ""
	echo "    /* dispatch on the op3 of the instruction: */"
	echo "    insn = TME_SPARC_INSN;"
	echo "    switch ((insn >> 19) & 0x3f) {"
	if test ${arch} = 64; then
	    for size in 32 64; do
		echo ""
		if test ${size} = 32; then
		    echo "    case 0x3c: /* casa */"
		else
		    echo "    case 0x3e: /* casxa */"
		fi
		echo ""
		echo "      /* finish the load part of the compare and swap: */"
		echo "      assert (ls->tme_sparc_ls_state == sizeof(tme_uint${size}_t));"
		echo "      value${size} = ic->tme_sparc_memory_buffer.tme_sparc_memory_buffer${size}s[0];"
		echo "      value_swap${size} = *ls->tme_sparc_ls_rd64;"
		echo "      if (endian_little) {"
		echo "        value${size} = tme_letoh_u${size}(value${size});"
		echo "        value_swap${size} = tme_htole_u${size}(value_swap${size});"
		echo "      }"
		echo "      else {"
		echo "        value${size} = tme_betoh_u${size}(value${size});"
		echo "        value_swap${size} = tme_htobe_u${size}(value_swap${size});"
		echo "      }"
		echo "      *ls->tme_sparc_ls_rd64 = value${size};"
		echo ""
		echo "      /* if the comparison fails: */"
		echo "      reg_rs2 = TME_FIELD_MASK_EXTRACTU(insn, TME_SPARC_FORMAT3_MASK_RS2);"
		echo "      TME_SPARC_REG_INDEX(ic, reg_rs2);"
		echo "      if (value${size} != (tme_uint${size}_t) ic->tme_sparc_ireg_uint${arch}(reg_rs2)) {"
		echo "        return;"
		echo "      }"
		echo ""
		echo "      /* start the store part of the compare and swap: */"
		echo "      ic->tme_sparc_memory_buffer.tme_sparc_memory_buffer${size}s[0] = value_swap${size};"
		echo "      break;"
	    done
	fi
	echo ""
	echo "    case 0x0d: /* ldstub */"
	echo "    case 0x1d: /* ldstuba */"
	echo ""
	echo "      /* finish the load part of the ldstub: */"
	echo "      assert (ls->tme_sparc_ls_state == sizeof(tme_uint8_t));"
	echo "      *ls->tme_sparc_ls_rd${arch} = ic->tme_sparc_memory_buffer.tme_sparc_memory_buffer8s[0];"
	echo ""
	echo "      /* start the store part of the ldstub: */"
	echo "      ic->tme_sparc_memory_buffer.tme_sparc_memory_buffer8s[0] = 0xff;"
	echo "      break;"
	echo ""
	echo "    /* otherwise, this must be swap: */"
	echo "    default:"
	echo "      assert (((insn >> 19) & 0x2f) == 0x0f /* swap, swapa */);"
	echo ""
	echo "      /* finish the load part of the swap: */"
	echo "      assert (ls->tme_sparc_ls_state == sizeof(tme_uint32_t));"
	echo "      value32 = ic->tme_sparc_memory_buffer.tme_sparc_memory_buffer32s[0];"
	echo "      value_swap32 = *ls->tme_sparc_ls_rd${arch};"
	echo "      if (endian_little) {"
	echo "        value32 = tme_letoh_u32(value32);"
	echo "        value_swap32 = tme_htole_u32(value32);"
	echo "      }"
	echo "      else {"
	echo "        value32 = tme_betoh_u32(value32);"
	echo "        value_swap32 = tme_htobe_u32(value32);"
	echo "      }"
	echo "      *ls->tme_sparc_ls_rd${arch} = value32;"
	echo ""
	echo "      /* start the store part of the swap: */"
	echo "      ic->tme_sparc_memory_buffer.tme_sparc_memory_buffer32s[0] = value_swap32;"
	echo "      break;"
	echo "    }"
	echo ""
	echo "    /* start the store part of the operation: */"
	echo "    size = ls->tme_sparc_ls_state;"
	echo "    ls->tme_sparc_ls_address${arch} -= size;"
	echo "    ls->tme_sparc_ls_size = size;"
	echo "    ls->tme_sparc_ls_buffer_offset = 0;"
	echo "    ls->tme_sparc_ls_state = size | TME_BIT(7);"
	echo "  }"
	echo ""
	echo "  /* this is the store part of the operation: */"
	echo ""
	echo "  /* do one slow store cycle: */"
	echo "  tme_sparc${arch}_store(ic, ls);"
	echo ""
	echo "  /* if the slow store cycle did not store all of the data: */"
	echo "  if (__tme_predict_false(ls->tme_sparc_ls_size != 0)) {"
	echo "    return;"
	echo "  }"
	echo "}"
    fi

    # the slow load and store functions:
    #
    for slow in load store; do

	if test ${slow} = load; then
	    cycle="read"
	    capcycle="READ"
	else
	    cycle="write"
	    capcycle="WRITE"
	fi
	if $header; then
	    echo "void tme_sparc${arch}_${slow} _TME_P((struct tme_sparc *, struct tme_sparc_ls *));"
	    continue
	fi

	echo ""
	echo "/* this does one slow ${slow} cycle: */"
	echo "void"
	echo "tme_sparc${arch}_${slow}(struct tme_sparc *ic, "
	echo "                  struct tme_sparc_ls *ls)"
	echo "{"

	# our locals:
	#
	echo "  struct tme_sparc_tlb *tlb;"
	echo "  tme_uint${arch}_t address;"
	echo "  unsigned int cycle_size;"
	echo "  tme_bus_addr_t physical_address;"
	echo "  int shift;"
	echo "  int err;"

	echo ""
	echo "  /* get the TLB entry: */"
	echo "  tlb = ls->tme_sparc_ls_tlb;"
	echo ""
	echo "  /* the TLB entry must be busy and valid: */"
	echo "  assert (tme_bus_tlb_is_valid(&tlb->tme_sparc_tlb_bus_tlb));"
	echo ""
	echo "  /* start the bus cycle structure: */"
	echo "  ls->tme_sparc_ls_bus_cycle.tme_bus_cycle_type = TME_BUS_CYCLE_${capcycle};"
	echo ""
	echo "  /* get the buffer: */"
	echo "  ls->tme_sparc_ls_bus_cycle.tme_bus_cycle_buffer = &ic->tme_sparc_memory_buffer.tme_sparc_memory_buffer8s[ls->tme_sparc_ls_buffer_offset];"
	echo "  ls->tme_sparc_ls_bus_cycle.tme_bus_cycle_buffer_increment = 1;"
	echo ""
	echo "  /* get the current address: */"
	echo "  address = ls->tme_sparc_ls_address${arch};"
	echo "  ls->tme_sparc_ls_bus_cycle.tme_bus_cycle_address = address;"
	echo ""
	echo "  /* start the cycle size: */"
	echo "  cycle_size = ls->tme_sparc_ls_size;"
	echo "  assert (cycle_size > 0);"
	echo "  cycle_size--;"
	echo "  cycle_size = TME_MIN(cycle_size, (((tme_bus_addr${arch}_t) tlb->tme_sparc_tlb_addr_last) - address)) + 1;"
	echo ""
	echo "  /* if this TLB entry allows fast ${cycle}s: */"
	echo "  if (__tme_predict_true(tlb->tme_sparc_tlb_emulator_off_${cycle} != TME_EMULATOR_OFF_UNDEF)) {"
	echo ""
	echo "    /* do a ${cycle}: */"
	echo "    ls->tme_sparc_ls_bus_cycle.tme_bus_cycle_size = cycle_size;"
	echo "    tme_memory_bus_${cycle}_buffer((tlb->tme_sparc_tlb_emulator_off_${cycle} + (tme_uint${arch}_t) ls->tme_sparc_ls_bus_cycle.tme_bus_cycle_address),"
	echo "                                  ls->tme_sparc_ls_bus_cycle.tme_bus_cycle_buffer,"
	echo "                                  ls->tme_sparc_ls_bus_cycle.tme_bus_cycle_size,"
	echo "                                  tlb->tme_sparc_tlb_bus_rwlock,"
	echo "                                  sizeof(tme_uint8_t),"
	echo "                                  sizeof(tme_uint${arch}_t));"
	echo "  }"
	echo ""
	echo "  /* otherwise, this TLB entry does not allow fast ${cycle}s: */"
	echo "  else {"
	echo ""
	echo "    /* finish the cycle size: */"
	echo "    cycle_size = TME_MIN(cycle_size, 1 + ((~ (unsigned int) address) % sizeof(tme_uint${arch}_t)));"
	echo "    ls->tme_sparc_ls_bus_cycle.tme_bus_cycle_size = cycle_size;"
	echo ""
	echo "    /* form the physical address for the bus cycle handler: */"
	echo "    physical_address = ls->tme_sparc_ls_bus_cycle.tme_bus_cycle_address;"
	echo "    physical_address += tlb->tme_sparc_tlb_addr_offset;"
	echo "    shift = tlb->tme_sparc_tlb_addr_shift;"
	echo "    if (shift < 0) {"
	echo "      physical_address <<= (0 - shift);"
	echo "    }"
	echo "    else if (shift > 0) {"
	echo "      physical_address >>= shift;"
	echo "    }"
	echo "    ls->tme_sparc_ls_bus_cycle.tme_bus_cycle_address = physical_address;"
	echo ""
	echo "    /* finish the bus cycle structure: */"
	echo "    (*ic->_tme_sparc_ls_bus_cycle)(ic, ls);"

	echo "    tme_sparc_log(ic, 10000, TME_OK,"
	echo "                 (TME_SPARC_LOG_HANDLE(ic),"
	echo "                  _(\"cycle-${slow}%u\t0x%0"`expr ${arch} / 4`"\" TME_PRIx${arch}),"
	echo "                  (unsigned int) (ls->tme_sparc_ls_bus_cycle.tme_bus_cycle_size * 8),"
	echo "                  (tme_bus_addr${arch}_t) ls->tme_sparc_ls_bus_cycle.tme_bus_cycle_address));"

	echo ""
	echo "    /* callout the bus cycle: */"
	echo "    tme_sparc_tlb_unbusy(tlb);"
	echo "    tme_sparc_callout_unlock(ic);"
	echo "    err = (*tlb->tme_sparc_tlb_bus_tlb.tme_bus_tlb_cycle)"
	echo "           (tlb->tme_sparc_tlb_bus_tlb.tme_bus_tlb_cycle_private,"
	echo "            &ls->tme_sparc_ls_bus_cycle);"
	echo "    tme_sparc_callout_relock(ic);"
	echo "    tme_sparc_tlb_busy(tlb);"
	echo ""
	echo "    /* the TLB entry can't have been invalidated before the ${slow}: */"
	echo "    assert (err != EBADF);"
	echo ""
	echo "    /* if the bus cycle didn't complete normally: */"
	echo "    if (err != TME_OK) {"
	echo ""
	echo "      /* if a real bus fault may have happened, instead of"
	echo "         some synchronous event: */"
	echo "      if (err != TME_BUS_CYCLE_SYNCHRONOUS_EVENT) {"
	echo ""
	echo "        /* call the bus fault handlers: */"
	echo "        err = tme_bus_tlb_fault(&tlb->tme_sparc_tlb_bus_tlb, &ls->tme_sparc_ls_bus_cycle, err);"
	echo "      }"
	echo ""
	echo "      /* if some synchronous event has happened: */"
	echo "      if (err == TME_BUS_CYCLE_SYNCHRONOUS_EVENT) {"
	echo ""
	echo "        /* after the currently executing instruction finishes, check"
	echo "           for external resets, halts, or interrupts: */"
	echo "        ic->_tme_sparc_instruction_burst_remaining = 0;"
	echo "        ic->_tme_sparc_instruction_burst_other = TRUE;"
	echo "      }"
	echo ""
	echo "      /* otherwise, if no real bus fault happened: */"
	echo "      else if (err == TME_OK) {"
	echo ""
	echo "        /* nothing to do */"
	echo "      }"
	echo ""
	echo "      /* otherwise, a real bus fault happened: */"
	echo "      else {"
	echo "        (*ic->_tme_sparc_ls_bus_fault)(ic, ls, err);"
	echo "        return;"
	echo "      }"
	echo "    }"
	echo "  }"

	echo ""
	echo "  /* some data must have been transferred: */"
	echo "  assert (ls->tme_sparc_ls_bus_cycle.tme_bus_cycle_size > 0);"
	
	if test ${slow} = store; then
	    echo ""
	    echo "  /* if this was an atomic operation: */"
	    echo "  if (__tme_predict_false(ls->tme_sparc_ls_lsinfo & TME_SPARC_LSINFO_OP_ATOMIC)) {"
	    echo ""
	    echo "    /* we do not support atomic operations in TLB entries that"
	    echo "       do not support both fast reads and fast writes.  assuming"
	    echo "       that all atomic operations are to regular memory, we"
	    echo "       should always get fast read and fast write TLBs.  when"
	    echo "       we do not, it should only be because the memory has been"
	    echo "       made read-only in the MMU.  the write above was supposed"
	    echo "       to cause a fault (with the instruction rerun later with"
	    echo "       a fast read and fast write TLB entry), but instead it"
	    echo "       succeeded and transferred some data.  we have modified"
	    echo "       memory and cannot recover: */"
	    echo "    abort();"
	    echo "  }"
	fi

	echo ""
	echo "  /* update: */"
	echo "  cycle_size = ls->tme_sparc_ls_bus_cycle.tme_bus_cycle_size;"
	echo "  ls->tme_sparc_ls_address${arch} += cycle_size;"
	echo "  ls->tme_sparc_ls_buffer_offset += cycle_size;"
	echo "  ls->tme_sparc_ls_size -= cycle_size;"
	echo "}"
    done

    # the load/store function:
    #
    if $header; then
	echo "tme_shared tme_uint8_t *tme_sparc${arch}_ls _TME_P((struct tme_sparc *, tme_uint${arch}_t, tme_uint${arch}_t *, tme_uint32_t));"
    else

	echo ""
	echo "/* this does a slow load or store: */"
	echo "tme_shared tme_uint8_t *"
	echo "tme_sparc${arch}_ls(struct tme_sparc *ic,"
	echo "               tme_uint${arch}_t const address_first,"
	echo "               tme_uint${arch}_t *_rd,"
	echo "               tme_uint32_t lsinfo)"
	echo "{"
	echo "  struct tme_sparc_ls ls;"
	echo "  tme_uint32_t size;"
	echo "  tme_uint32_t asi;"
	echo "  tme_uint32_t asi_mask_flags;"
	echo "  tme_uint32_t asi_mask;"
	echo "  tme_bus_context_t context;"
	echo "  tme_uint32_t tlb_hash;"
	echo "  unsigned long tlb_i;"
	echo "  unsigned long handler_i;"
	echo "  struct tme_sparc_tlb *tlb;"
	echo "  unsigned int cycle_type;"
	echo "  tme_uint${arch}_t address;"
	echo "  void (*address_map) _TME_P((struct tme_sparc *, struct tme_sparc_ls *));"
	echo "  tme_bus_addr_t address_bus;"
	echo "  int rc;"
	echo "  const tme_shared tme_uint8_t *emulator_off;"
	echo "  unsigned int buffer_offset;"
	echo "  tme_uint${arch}_t value;"
	echo "  tme_uint32_t value32;"
	echo ""
	echo "  /* we must not be replaying instructions: */"
	echo "  assert (tme_sparc_recode_verify_replay_last_pc(ic) == 0);"
	echo ""
	echo "  /* initialize the pointer to the rd register: */"
	echo "  ls.tme_sparc_ls_rd${arch} = _rd;"
	echo ""
	echo "#ifndef NDEBUG"
	echo ""
	echo "  /* initialize the cycle function: */"
	echo "  ls.tme_sparc_ls_cycle = NULL;"
	echo ""
	echo "  /* initialize the TLB entry pointer: */"
	echo "  ls.tme_sparc_ls_tlb = NULL;"
	echo ""
	echo "#endif /* NDEBUG */"
	echo ""
	echo "  /* initialize the faults: */"
	echo "  ls.tme_sparc_ls_faults = TME_SPARC_LS_FAULT_NONE;"
	echo ""
	echo "  /* initialize the address: */"
	echo "  ls.tme_sparc_ls_address${arch} = address_first;"
	echo ""
	echo "  /* initialize the size: */"
	echo "  size = TME_SPARC_LSINFO_WHICH_SIZE(lsinfo);"
	echo "  ls.tme_sparc_ls_size = size;"
	echo ""
	echo "  /* initialize the info: */"
	echo "  ls.tme_sparc_ls_lsinfo = lsinfo;"
	echo ""
	echo "  /* if the address is not aligned: */"
	echo "  if (__tme_predict_false(((size - 1) & (tme_uint32_t) address_first) != 0)) {"
	echo "    ls.tme_sparc_ls_faults |= TME_SPARC_LS_FAULT_ADDRESS_NOT_ALIGNED;"
	echo "  }"
	echo ""
	echo "  /* otherwise, the address is aligned: */"
	echo "  else {"
	echo ""
	echo "    /* the transfer must not cross a 32-bit boundary: */"
	echo "    assert ((size - 1) <= (tme_uint32_t) ~address_first);"
	echo "  }"
	echo ""
	echo "  /* initialize the address map: */"
	echo "  ls.tme_sparc_ls_address_map = ic->_tme_sparc_ls_address_map;"
	echo ""
	echo "  /* if this is a ldd, ldda, std, or stda, or an instruction"
	echo "     that loads or stores in the same way: */"
	echo "  if (lsinfo & TME_SPARC_LSINFO_LDD_STD) {"
	echo ""
	echo "    /* if the rd register is odd: */"
	echo "    /* NB: we don't check the rd field in the instruction,"
	echo "       because the register number there might be encoded"
	echo "       in some way, or the architecture might ignore bit"
	echo "       zero in the rd field (for example, the sparc32 lddf)."
	echo "       instead, we test the rd register pointer: */"
	echo "    if (__tme_predict_false((ls.tme_sparc_ls_rd${arch}"
	echo "                             - ic->tme_sparc_ic.tme_ic_iregs.tme_ic_iregs_uint${arch}s)"
	echo "                            % 2)) {"
	echo "      ls.tme_sparc_ls_faults |= TME_SPARC_LS_FAULT_LDD_STD_RD_ODD;"
	echo "    }"
	echo "  }"
	
	echo ""
	echo "  /* if the ASI has been specified: */"
	echo "  if (lsinfo & TME_SPARC_LSINFO_A) {"
	echo ""
	echo "    /* get the ASI: */"
	echo "    asi = TME_SPARC_LSINFO_WHICH_ASI(lsinfo);"
	echo ""
	echo "    /* get the flags for this ASI: */"
	echo "    asi_mask_flags = ic->tme_sparc_asis[asi].tme_sparc_asi_mask_flags;"
	echo ""
	if test ${arch} = 32; then
	    echo "    /* make the ASI mask: */"
	    echo "    if (asi_mask_flags & TME_SPARC32_ASI_MASK_FLAG_SPECIAL) {"
	    echo "      asi_mask"
	    echo "        = TME_SPARC_ASI_MASK_SPECIAL(asi, TRUE);"
	    echo "    }"
	    echo "    else {"
	    echo "      asi_mask = TME_SPARC32_ASI_MASK(asi, asi);"
	    echo "    }"
	elif test ${arch} = 64; then
	    echo "    /* if this is a nonprivileged access: */"
	    echo "    if (!TME_SPARC_PRIV(ic)) {"
	    echo ""
	    echo "      /* if this is a restricted ASI: */"
	    echo "      if (__tme_predict_false((asi & TME_SPARC64_ASI_FLAG_UNRESTRICTED) == 0)) {"
	    echo "        ls.tme_sparc_ls_faults |= TME_SPARC64_LS_FAULT_PRIVILEGED_ASI;"
	    echo "      }"
	    echo ""
	    echo "      /* force a nonprivileged access with the ASI: */"
	    echo "      asi_mask_flags |= TME_SPARC64_ASI_MASK_FLAG_INSN_AS_IF_USER;"
	    echo "    }"
	    echo ""
	    echo "    /* make the ASI mask: */"
	    echo "    if (asi_mask_flags & TME_SPARC64_ASI_MASK_FLAG_SPECIAL) {"
	    echo "      asi_mask"
	    echo "        = (asi_mask_flags"
	    echo "           + TME_SPARC_ASI_MASK_SPECIAL(asi,"
	    echo "                                        (asi_mask_flags & TME_SPARC64_ASI_MASK_FLAG_INSN_AS_IF_USER) == 0));"
	    echo "    }"
	    echo "    else {"
	    echo "      asi_mask = TME_SPARC64_ASI_MASK(asi, asi_mask_flags);"
	    echo "    }"
	fi
	echo "    ls.tme_sparc_ls_asi_mask = asi_mask;"
	if test ${arch} = 64; then
	    echo ""
	    echo "    /* if this is a no-fault ASI with a non-load instruction: */"
	    echo "    if (asi_mask & TME_SPARC64_ASI_FLAG_NO_FAULT) {"
	    echo "      if (__tme_predict_false(lsinfo & (TME_SPARC_LSINFO_OP_ST | TME_SPARC_LSINFO_OP_ATOMIC))) {"
	    echo "        ls.tme_sparc_ls_faults |= TME_SPARC64_LS_FAULT_NO_FAULT_NON_LOAD;"
	    echo "      }"
	    echo "    }"
	fi
	echo ""
	echo "    /* get the context for the alternate address space: */"
	if test ${arch} = 32; then
	    echo "    context = ic->tme_sparc_memory_context_default;"
	elif test ${arch} = 64; then
	    echo "    context = ic->tme_sparc_memory_context_primary;"
	    echo "    if (asi_mask & TME_SPARC64_ASI_FLAG_SECONDARY) {"
	    echo "      context = ic->tme_sparc_memory_context_secondary;"
	    echo "    }"
	    echo "    if (__tme_predict_false(asi_mask & TME_SPARC64_ASI_MASK_FLAG_INSN_NUCLEUS)) {"
	    echo "      if (TME_SPARC_MEMORY_FLAGS(ic) & TME_SPARC_MEMORY_FLAG_HAS_NUCLEUS) {"
	    echo "        context = 0;"
	    echo "      }"
	    echo "    }"
	fi
	echo "    ls.tme_sparc_ls_context = context;"
	echo ""
	echo "    /* get the default TLB entry index: */"
	echo "    tlb_hash = TME_SPARC_TLB_HASH(ic, context, address_first);"
	echo "    if (lsinfo & TME_SPARC_LSINFO_OP_FETCH) {"
	echo "      tlb_i = TME_SPARC_ITLB_ENTRY(ic, tlb_hash);"
	echo "    }"
	echo "    else {"
	echo "      tlb_i = TME_SPARC_DTLB_ENTRY(ic, tlb_hash);"
	echo "    }"
	echo "    ls.tme_sparc_ls_tlb_i = tlb_i;"
	echo ""
	echo "    /* call any special handler for this ASI: */"
	echo "    handler_i = ic->tme_sparc_asis[TME_SPARC_ASI_MASK_WHICH(asi_mask)].tme_sparc_asi_handler;"
	echo "    if (__tme_predict_false(handler_i != 0)) {"
	echo "      (*ic->_tme_sparc_ls_asi_handlers[handler_i])(ic, &ls);"
	echo "    }"
	echo ""
	echo "    /* get the final TLB entry index: */"
	echo "    tlb_i = ls.tme_sparc_ls_tlb_i;"
	echo "  }"

	echo ""
	echo "  /* otherwise, the ASI has not been specified: */"
	echo "  else {"
	echo ""
	echo "    /* get the ASI mask: */"
	echo "    asi_mask = ic->tme_sparc_asi_mask_data;"
	echo ""
	echo "    /* add in any ASI mask flags from the instruction: */"
	if test ${arch} = 64; then
	    echo "    /* NB: initially, TME_SPARC64_ASI_FLAG_NO_FAULT is the"
	    echo "       only flag allowed, and only the flush instruction"
	    echo "       can use it: */"
	fi
	echo "    assert (TME_SPARC_LSINFO_WHICH_ASI_FLAGS(lsinfo) == 0"
	if test ${arch} = 64; then
	    echo "            || (TME_SPARC_LSINFO_WHICH_ASI_FLAGS(lsinfo) == TME_SPARC64_ASI_FLAG_NO_FAULT"
	    echo "                && ((ic->_tme_sparc_insn >> 19) & 0x3f) == 0x3b)"
	fi
	echo "            );"
	echo "    asi_mask |= TME_SPARC_LSINFO_WHICH_ASI_FLAGS(lsinfo);"
	echo ""
	echo "    /* set the ASI mask: */"
	echo "    ls.tme_sparc_ls_asi_mask = asi_mask;"
	echo ""
	echo "    /* get the context: */"
	echo "    context = ic->tme_sparc_memory_context_default;"
	echo "    ls.tme_sparc_ls_context = context;"
	echo ""
	echo "    /* this must not be a fetch: */"
	echo "    assert ((lsinfo & TME_SPARC_LSINFO_OP_FETCH) == 0);"
	echo ""
	echo "    /* get the TLB entry index: */"
	echo "    tlb_hash = TME_SPARC_TLB_HASH(ic, context, address_first);"
	echo "    tlb_i = TME_SPARC_DTLB_ENTRY(ic, tlb_hash);"
	echo "    ls.tme_sparc_ls_tlb_i = tlb_i;"
	echo "  }"

	echo ""
	echo "  /* get the TLB entry pointer: */"
	echo "  tlb = &ic->tme_sparc_tlbs[tlb_i];"
	echo "  ls.tme_sparc_ls_tlb = tlb;"

	echo ""
	echo "  /* get the cycle type: */"
	echo "  /* NB: we deliberately set this once, now, since the lsinfo"
	echo "     may change once we start transferring: */"
	echo "  cycle_type"
	echo "    = ((lsinfo"
	echo "        & (TME_SPARC_LSINFO_OP_ST"
	echo "           | TME_SPARC_LSINFO_OP_ATOMIC))"
	echo "       ? TME_BUS_CYCLE_WRITE"
	echo "       : TME_BUS_CYCLE_READ);"

	echo ""
	echo "  /* loop until the transfer is complete: */"
	echo "  for (;;) {"

	echo ""
	echo "    /* if we have faulted: */"
	echo "    if (__tme_predict_false(ls.tme_sparc_ls_faults != TME_SPARC_LS_FAULT_NONE)) {"
	echo ""
	echo "      /* unbusy this TLB, since the trap function may not return: */"
	echo "      tme_bus_tlb_unbusy(&tlb->tme_sparc_tlb_bus_tlb);"
	echo ""
	echo "      /* call the trap function, which will not return if it traps: */"
	echo "      (*ic->_tme_sparc_ls_trap)(ic, &ls);"
	echo ""
	echo "      /* rebusy this TLB: */"
	echo "      tme_bus_tlb_busy(&tlb->tme_sparc_tlb_bus_tlb);"
	echo ""
	echo "      /* since the trap function returned, it must have cleared the fault: */"
	echo "      assert (ls.tme_sparc_ls_faults == TME_SPARC_LS_FAULT_NONE);"
	echo "    }"

	echo ""
	echo "    /* if the transfer is complete, stop now: */"
	echo "    if (__tme_predict_false(ls.tme_sparc_ls_size == 0)) {"
	echo "      break;"
	echo "    }"

	echo ""
	echo "    /* get the current address: */"
	echo "    address = ls.tme_sparc_ls_address${arch};"

	echo ""
	echo "    /* if this TLB entry does not apply or is invalid: */"
	echo "    if ((tlb->tme_sparc_tlb_context != ls.tme_sparc_ls_context"
	echo "         && tlb->tme_sparc_tlb_context <= ic->tme_sparc_memory_context_max)"
	echo "        || address < (tme_bus_addr${arch}_t) tlb->tme_sparc_tlb_addr_first"
	echo "        || address > (tme_bus_addr${arch}_t) tlb->tme_sparc_tlb_addr_last"
	echo "        || !TME_SPARC_TLB_ASI_MASK_OK(tlb, ls.tme_sparc_ls_asi_mask)"
	echo "        || ((tlb->tme_sparc_tlb_cycles_ok & cycle_type) == 0"
	echo "            && (cycle_type == TME_BUS_CYCLE_READ"
	echo "                ? tlb->tme_sparc_tlb_emulator_off_read"
	echo "                : tlb->tme_sparc_tlb_emulator_off_write) == TME_EMULATOR_OFF_UNDEF)"
	echo "        || tme_bus_tlb_is_invalid(&tlb->tme_sparc_tlb_bus_tlb)) {"
	echo ""
	echo "      /* unbusy this TLB entry for filling: */"
	echo "      tme_bus_tlb_unbusy_fill(&tlb->tme_sparc_tlb_bus_tlb);"
	echo ""
	echo "      /* if we haven't mapped this address yet: */"
	echo "      address_map = ls.tme_sparc_ls_address_map;"
	echo "      if (address_map != NULL) {"
	echo "        ls.tme_sparc_ls_address_map = NULL;"
	echo ""
	echo "        /* count this mapping: */"
	echo "        if (ls.tme_sparc_ls_lsinfo & TME_SPARC_LSINFO_OP_FETCH) {"
	echo "          TME_SPARC_STAT(ic, tme_sparc_stats_itlb_map);"
	echo "        }"
	echo "        else {"
	echo "          TME_SPARC_STAT(ic, tme_sparc_stats_dtlb_map);"
	echo "        }"
	echo ""
	echo "        /* initialize the ASI mask and context on this TLB entry: */"
	echo "        /* NB that the ASI mask will likely be updated by either the"
	echo "           address mapping or the TLB fill: */"
	echo "        tlb->tme_sparc_tlb_asi_mask"
	echo "          = (ls.tme_sparc_ls_asi_mask"
	echo "             & ~TME_SPARC_ASI_MASK_FLAGS_AVAIL);"
	echo "        tlb->tme_sparc_tlb_context = ls.tme_sparc_ls_context;"
	echo ""
	echo "        /* NB: if the address mapping traps, we won't get a chance"
	echo "           to finish updating this TLB entry, which is currently in"
	echo "           an inconsistent state - but not necessarily an unusable"
	echo "           state.  poison it to be unusable, including any recode"
	echo "           TLB entry: */"
	echo "        tlb->tme_sparc_tlb_addr_first = 1;"
	echo "        tlb->tme_sparc_tlb_addr_last = 0;"
	echo "#if TME_SPARC_HAVE_RECODE(ic)"
	echo "        if (ls.tme_sparc_ls_lsinfo & TME_SPARC_LSINFO_OP_FETCH) {"
	echo "          tme_sparc${arch}_recode_chain_tlb_update(ic, &ls);"
	echo "        }"
	echo "        else {"
	echo "          tme_sparc${arch}_recode_ls_tlb_update(ic, &ls);"
	echo "        }"
	echo "#endif /* TME_SPARC_HAVE_RECODE(ic) */"
	echo ""
	echo "#ifndef NDEBUG"
	echo ""
	echo "        /* initialize the mapping TLB entry: */"
	echo "        ls.tme_sparc_ls_tlb_map.tme_bus_tlb_addr_first = 0 - (tme_bus_addr_t) 1;"
	echo "        ls.tme_sparc_ls_tlb_map.tme_bus_tlb_addr_last = 0 - (tme_bus_addr_t) 2;"
	echo "        ls.tme_sparc_ls_tlb_map.tme_bus_tlb_cycles_ok = 0;"
	echo "        ls.tme_sparc_ls_tlb_map.tme_bus_tlb_addr_offset = 0 - (tme_bus_addr_t) 1;"
	echo ""
	echo "#endif /* !NDEBUG */"
	echo ""
	echo "        /* map the address: */"
	echo "        (*address_map)(ic, &ls);"
	echo ""
	echo "        /* the address mapping must do any trapping itself: */"
	echo "        assert (ls.tme_sparc_ls_faults == TME_SPARC_LS_FAULT_NONE);"
	echo ""
	echo "        /* if the address mapping completed the transfer: */"
	echo "        if (__tme_predict_false(ls.tme_sparc_ls_size == 0)) {"
	echo ""
	echo "          /* rebusy the TLB entry: */"
	echo "          tme_sparc_tlb_busy(tlb);"
	echo ""
	echo "          /* stop now: */"
	echo "          break;"
	echo "        }"
	echo ""
	echo "        /* the mapping must have actually made a mapping: */"
	echo "        assert (ls.tme_sparc_ls_tlb_map.tme_bus_tlb_addr_first != 0 - (tme_bus_addr_t) 1);"
	echo "        assert (ls.tme_sparc_ls_tlb_map.tme_bus_tlb_addr_last != 0 - (tme_bus_addr_t) 2);"
	echo "        assert (ls.tme_sparc_ls_tlb_map.tme_bus_tlb_cycles_ok != 0);"
	echo "        assert (ls.tme_sparc_ls_tlb_map.tme_bus_tlb_addr_offset != 0 - (tme_bus_addr_t) 1);"
	echo "      }"
	echo ""
	echo "      /* count this fill: */"
	echo "      if (ls.tme_sparc_ls_lsinfo & TME_SPARC_LSINFO_OP_FETCH) {"
	echo "        TME_SPARC_STAT(ic, tme_sparc_stats_itlb_fill);"
	echo "      }"
	echo "      else {"
	echo "        TME_SPARC_STAT(ic, tme_sparc_stats_dtlb_fill);"
	echo "      }"
	echo ""
	echo "      /* get the bus address: */"
	echo "      address_bus = ls.tme_sparc_ls_address${arch} + ls.tme_sparc_ls_tlb_map.tme_bus_tlb_addr_offset;"
	echo ""
	echo "      /* fill the TLB entry: */"
	echo "      tme_sparc_callout_unlock(ic);"
	echo "      rc = (*ic->_tme_sparc_bus_connection->tme_sparc_bus_tlb_fill)"
	echo "        (ic->_tme_sparc_bus_connection,"
	echo "         tlb,"
	echo "         ls.tme_sparc_ls_asi_mask,"
	echo "         address_bus,"
	echo "         cycle_type);"
	echo "      assert (rc == TME_OK);"
	echo "      tme_sparc_callout_relock(ic);"
	echo ""
	echo "      /* map the TLB entry: */"
	echo "      tme_bus_tlb_map(&tlb->tme_sparc_tlb_bus_tlb, address_bus,"
	echo "                      &ls.tme_sparc_ls_tlb_map, ls.tme_sparc_ls_address${arch});"
	echo ""
	echo "      /* update any recode TLB entry: */"
	echo "#if TME_SPARC_HAVE_RECODE(ic)"
	echo "      if (ls.tme_sparc_ls_lsinfo & TME_SPARC_LSINFO_OP_FETCH) {"
	echo "        tme_sparc${arch}_recode_chain_tlb_update(ic, &ls);"
	echo "      }"
	echo "      else {"
	echo "        tme_sparc${arch}_recode_ls_tlb_update(ic, &ls);"
	echo "      }"
	echo "#endif /* TME_SPARC_HAVE_RECODE(ic) */"
	echo ""
	echo "      /* rebusy the TLB entry: */"
	echo "      tme_sparc_tlb_busy(tlb);"
	echo ""
	echo "      /* if this TLB entry is already invalid: */"
	echo "      if (tme_bus_tlb_is_invalid(&tlb->tme_sparc_tlb_bus_tlb)) {"
	echo "        continue;"
	echo "      }"
	echo "    }"

	echo ""
	echo "    /* this TLB entry must apply: */"
	echo "    assert ((tlb->tme_sparc_tlb_context == ls.tme_sparc_ls_context"
	echo "             || tlb->tme_sparc_tlb_context > ic->tme_sparc_memory_context_max)"
	echo "            && ls.tme_sparc_ls_address${arch} >= (tme_bus_addr${arch}_t) tlb->tme_sparc_tlb_addr_first"
	echo "            && ls.tme_sparc_ls_address${arch} <= (tme_bus_addr${arch}_t) tlb->tme_sparc_tlb_addr_last"
	echo "            && ((tlb->tme_sparc_tlb_cycles_ok & cycle_type)"
	echo "                || (cycle_type == TME_BUS_CYCLE_READ"
	echo "                    ? tlb->tme_sparc_tlb_emulator_off_read"
	echo "                    : tlb->tme_sparc_tlb_emulator_off_write) != TME_EMULATOR_OFF_UNDEF)"
	echo "            && TME_SPARC_TLB_ASI_MASK_OK(tlb, ls.tme_sparc_ls_asi_mask));"

	echo ""
	echo "    /* get the current lsinfo: */"
	echo "    lsinfo = ls.tme_sparc_ls_lsinfo;"

	echo ""
	echo "    /* if we have to check the TLB: */"
	echo "    if (__tme_predict_true((lsinfo & TME_SPARC_LSINFO_NO_CHECK_TLB) == 0)) {"
	echo ""
	echo "      /* get the ASI mask for this TLB entry: */"
	echo "      asi_mask = tlb->tme_sparc_tlb_asi_mask;"
	if test ${arch} = 64; then
	    echo ""
	    echo "      /* if this TLB entry is for no-fault accesses only: */"
	    echo "      if (__tme_predict_false(asi_mask & TME_SPARC64_ASI_FLAG_NO_FAULT)) {"
	    echo ""
	    echo "        /* if this access is not using a no-fault ASI: */"
	    echo "        if (__tme_predict_false((ls.tme_sparc_ls_asi_mask & TME_SPARC64_ASI_FLAG_NO_FAULT) == 0)) {"
	    echo "          ls.tme_sparc_ls_faults |= TME_SPARC64_LS_FAULT_NO_FAULT_FAULT;"
	    echo "          continue;"
	    echo "        }"
	    echo "      }"
	    echo ""
	    echo "      /* if this TLB entry is for addresses with side effects: */"
	    echo "      if (asi_mask & TME_SPARC64_ASI_MASK_FLAG_TLB_SIDE_EFFECTS) {"
	    echo ""
	    echo "        /* if this access is using a no-fault ASI: */"
	    echo "        /* NB: a flush may be implemented as a load with a no-fault ASI: */"
	    echo "        if (__tme_predict_false(ls.tme_sparc_ls_asi_mask & TME_SPARC64_ASI_FLAG_NO_FAULT)) {"
	    echo "          ls.tme_sparc_ls_faults |= TME_SPARC64_LS_FAULT_SIDE_EFFECTS;"
	    echo "          continue;"
	    echo "        }"
	    echo "      }"
	    echo ""
	    echo "      /* if this TLB entry is for uncacheable addresses: */"
	    echo "      if (asi_mask & TME_SPARC64_ASI_MASK_FLAG_TLB_UNCACHEABLE) {"
	    echo ""
	    echo "        /* if this is an atomic access: */"
	    echo "        if (__tme_predict_false(lsinfo & TME_SPARC_LSINFO_OP_ATOMIC)) {"
	    echo "          ls.tme_sparc_ls_faults |= TME_SPARC64_LS_FAULT_UNCACHEABLE;"
	    echo "          continue;"
	    echo "        }"
	    echo "      }"
	    echo ""
	    echo "      /* see if this is a little-endian instruction: */"
	    echo "      lsinfo"
	    echo "        = ((lsinfo"
	    echo "            & ~TME_SPARC_LSINFO_ENDIAN_LITTLE)"
	    echo "           + ((ls.tme_sparc_ls_asi_mask"
	    echo "               & TME_SPARC64_ASI_FLAG_LITTLE)"
	    echo "#if TME_SPARC_LSINFO_ENDIAN_LITTLE < TME_SPARC64_ASI_FLAG_LITTLE"
	    echo "#error \"TME_SPARC_LSINFO_ENDIAN_ values changed\""
	    echo "#endif"
	    echo "              * (TME_SPARC_LSINFO_ENDIAN_LITTLE"
	    echo "                 / TME_SPARC64_ASI_FLAG_LITTLE)));"
	    echo ""
	    echo "      /* if this TLB entry has its little-endian bit set: */"
	    echo "      if (__tme_predict_false(asi_mask & TME_SPARC64_ASI_FLAG_LITTLE)) {"
	    echo "        assert (TME_SPARC_MEMORY_FLAGS(ic) & TME_SPARC_MEMORY_FLAG_HAS_INVERT_ENDIAN);"
	    echo "        if (TRUE) {"
	    echo "          lsinfo ^= TME_SPARC_LSINFO_ENDIAN_LITTLE;"
	    echo "        }"
	    echo "      }"
	fi
	echo "    }"

	echo ""
	echo "    /* if we might not have to call a slow cycle function: */"
	echo "    if (__tme_predict_true((lsinfo & TME_SPARC_LSINFO_SLOW_CYCLES) == 0)) {"
	echo ""
	echo "      /* if this TLB entry allows fast transfer of all of the addresses: */"
	echo "      if (__tme_predict_true(((tme_bus_addr${arch}_t) tlb->tme_sparc_tlb_addr_last) >= (address_first + (ls.tme_sparc_ls_size - 1)))) {"
	echo "        emulator_off = tlb->tme_sparc_tlb_emulator_off_read;"
	echo "        if (lsinfo & TME_SPARC_LSINFO_OP_ST) {"
	echo "          emulator_off = tlb->tme_sparc_tlb_emulator_off_write;"
	echo "        }"
	echo "        if (__tme_predict_true(emulator_off != TME_EMULATOR_OFF_UNDEF"
	echo "                               && (((lsinfo & TME_SPARC_LSINFO_OP_ATOMIC) == 0)"
	echo "                                   || emulator_off == tlb->tme_sparc_tlb_emulator_off_write))) {"
	echo ""
	echo "          /* return and let our caller do the transfer: */"
	echo "          /* NB: we break const here: */"
	echo "          return ((tme_shared tme_uint8_t *) emulator_off);"
	echo "        }"
	echo "      }"
	echo ""
	echo "      /* we have to call a slow cycle function: */"
	echo "      lsinfo |= TME_SPARC_LSINFO_SLOW_CYCLES;"
	echo "      assert (ls.tme_sparc_ls_cycle == NULL);"
	if test ${arch} = 32; then
	    endian_little="FALSE"
	else
	    endian_little="(lsinfo & TME_SPARC_LSINFO_ENDIAN_LITTLE)"
	fi
	echo ""
	echo "      /* assume that this operation will transfer the start of the buffer: */"
	echo "      buffer_offset = 0;"
	echo ""
	echo "      /* assume that this is a load or a fetch: */"
	echo "      ls.tme_sparc_ls_cycle = tme_sparc${arch}_load;"
	echo ""
	echo "      /* if this is a store: */"
	echo "      if (lsinfo & TME_SPARC_LSINFO_OP_ST) {"
	echo ""
	echo "        /* put the (first) register to store in the memory buffer: */"
	echo "        value = TME_SPARC_FORMAT3_RD;"
	echo "        value = (${endian_little} ? tme_htole_u${arch}(value) : tme_htobe_u${arch}(value));"
	echo "        ic->tme_sparc_memory_buffer.tme_sparc_memory_buffer${arch}s[0] = value;"
	echo ""
	echo "        /* find the offset in the memory buffer corresponding to the"
	echo "           first address: */"
	echo "        buffer_offset = sizeof(tme_uint${arch}_t) - ls.tme_sparc_ls_size;"
	echo "        if (${endian_little}) {"
	echo "          buffer_offset = 0;"
	echo "        }"

	echo ""
	echo "        /* if this is a std or stda: */"
	echo "        if (lsinfo & TME_SPARC_LSINFO_LDD_STD) {"
	echo ""
	echo "          /* put the odd 32-bit register to store in the memory buffer"
	echo "             after the even 32-bit register.  exactly where this is depends"
	echo "             on the architecture and on the byte order of the store: */"
	echo "          value32 = TME_SPARC_FORMAT3_RD_ODD(tme_ic_ireg_uint${arch});"
	echo "          if (${endian_little}) {"
	echo "            value32 = tme_htole_u32(value32);"
	echo "            ic->tme_sparc_memory_buffer.tme_sparc_memory_buffer32s[1] = value32;"
	echo "            buffer_offset = 0;"
	echo "          }"
	echo "          else {"
	echo "            value32 = tme_htobe_u32(value32);"
	echo "            ic->tme_sparc_memory_buffer.tme_sparc_memory_buffer32s[(${arch} / 32)] = value32;"
	echo "            buffer_offset = sizeof(tme_uint${arch}_t) - sizeof(tme_uint32_t);"
	echo "          }"
	echo "        }"
	echo ""
	echo "        /* set the cycle function: */"
	echo "        ls.tme_sparc_ls_cycle = tme_sparc${arch}_store;"
	echo "      }"
	echo ""
	echo "      /* otherwise, if this is an atomic: */"
	echo "      else if (lsinfo & TME_SPARC_LSINFO_OP_ATOMIC) {"
	echo ""
	echo "        /* set the cycle function: */"
	echo "        ls.tme_sparc_ls_cycle = tme_sparc${arch}_atomic;"
	echo "      }"
	echo ""
	echo "      /* set the buffer offset for the (first) slow cycle: */"
	echo "      ls.tme_sparc_ls_buffer_offset = buffer_offset;"
	echo ""
	echo "      /* clear the state for this operation: */"
	echo "      ls.tme_sparc_ls_state = 0;"
	echo "    }"

	echo ""
	echo "    /* assume that we won't have to check the TLB again: */"
	echo "    ls.tme_sparc_ls_lsinfo = lsinfo | TME_SPARC_LSINFO_NO_CHECK_TLB;"

	echo "    /* call the slow cycle function: */"
	echo "    (*ls.tme_sparc_ls_cycle)(ic, &ls);"
	echo "  }"
	echo ""
	echo "  /* if this was a load that has already completed, a store,"
	echo "     or an atomic, make sure our caller doesn't try to complete"
	echo "     a fast transfer: */"
	echo "  if (ls.tme_sparc_ls_lsinfo"
	echo "      & (TME_SPARC_LSINFO_LD_COMPLETED"
	echo "         | TME_SPARC_LSINFO_OP_ST"
	echo "         | TME_SPARC_LSINFO_OP_ATOMIC)) {"
	echo "    return (TME_EMULATOR_OFF_UNDEF);"
	echo "  }"
	echo ""
	echo "  /* otherwise, this was a load that did slow cycles into the"
	echo "     memory buffer and hasn't updated rd yet.  return a pointer"
	echo "     to the memory buffer so our caller can complete the load: */"
	echo "  return (ic->tme_sparc_memory_buffer.tme_sparc_memory_buffer8s"
	echo "          - address_first);"
	echo "}"
    fi

    # unfix the architecture version:
    #
    if $header; then :; else
	echo ""
	echo "#undef TME_SPARC_VERSION"
	echo "#define TME_SPARC_VERSION(ic) _TME_SPARC_VERSION(ic)"
    fi

    # the sparc64 support depends on a 64-bit integer type:
    #
    if test ${arch} = 64; then
	echo ""
	echo "#endif /* TME_HAVE_INT64_T */"
    fi
done

# done:
#
exit 0

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.