File:  [The Machine Emulator] / tme / ic / m68k / m68k-misc-auto.sh
Revision 1.1.1.3 (vendor branch): download - view: text, annotated - select for diffs
Tue Apr 24 16:42:00 2018 UTC (8 years, 3 months ago) by root
Branches: heeltoe, fredette, MAIN
CVS tags: tme-0_8heeltoe, tme-0_8, tme-0_6, HEAD
tme-0.6

#! /bin/sh

# $Id: m68k-misc-auto.sh,v 1.1.1.3 2018/04/24 16:42:00 root Exp $

# ic/m68k/m68k-misc-auto.sh - automatically generates C code 
# for miscellaneous m68k emulation support:

#
# Copyright (c) 2002, 2003 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! */
EOF

# we need our own inclusion protection, since the instruction word
# fetch macros need to be multiply included:
if $header; then
    echo ""
    echo "#ifndef _IC_M68K_MISC_H"
    echo "#define _IC_M68K_MISC_H"
fi

# emit the register mapping macros:
if $header; then

    echo ""
    echo "/* the register mapping: */"
    echo "#define TME_M68K_IREG_UNDEF		(-1)"
    ireg32_next=0
    
    # NB: these are in a deliberate order, matching the order of
    # registers in instruction encodings:
    for regtype in d a; do
	capregtype=`echo ${regtype} | tr a-z A-Z`
	for regnum in 0 1 2 3 4 5 6 7; do
	    echo "#define TME_M68K_IREG_${capregtype}${regnum}		(${ireg32_next})"
	    echo "#define tme_m68k_ireg_${regtype}${regnum}		tme_m68k_ireg_uint32(TME_M68K_IREG_${capregtype}${regnum})"
	    ireg32_next=`expr ${ireg32_next} + 1`
	done
    done

    # the current, next, and last program counter:
    echo "#define TME_M68K_IREG_PC		(${ireg32_next})"
    echo "#define tme_m68k_ireg_pc		tme_m68k_ireg_uint32(TME_M68K_IREG_PC)"
    ireg32_next=`expr ${ireg32_next} + 1`
    echo "#define TME_M68K_IREG_PC_NEXT		(${ireg32_next})"
    echo "#define tme_m68k_ireg_pc_next		tme_m68k_ireg_uint32(TME_M68K_IREG_PC_NEXT)"
    ireg32_next=`expr ${ireg32_next} + 1`
    echo "#define TME_M68K_IREG_PC_LAST		(${ireg32_next})"
    echo "#define tme_m68k_ireg_pc_last		tme_m68k_ireg_uint32(TME_M68K_IREG_PC_LAST)"
    ireg32_next=`expr ${ireg32_next} + 1`
    
    # the status register and ccr:
    echo "#define tme_m68k_ireg_sr		tme_m68k_ireg_uint16(${ireg32_next} << 1)"
    echo "#define tme_m68k_ireg_ccr		tme_m68k_ireg_uint8(${ireg32_next} << 2)"
    ireg32_next=`expr ${ireg32_next} + 1`

    # the shadow status register and format/offset word:
    echo "#define TME_M68K_IREG_SHADOW_SR	(${ireg32_next} << 1)"
    echo "#define tme_m68k_ireg_shadow_sr	tme_m68k_ireg_uint16(TME_M68K_IREG_SHADOW_SR)"
    echo "#define TME_M68K_IREG_FORMAT_OFFSET	((${ireg32_next} << 1) + 1)"
    echo "#define tme_m68k_ireg_format_offset	tme_m68k_ireg_uint16(TME_M68K_IREG_FORMAT_OFFSET)"
    ireg32_next=`expr ${ireg32_next} + 1`

    # the memory buffers:
    for mem_which in x y z; do
	cap_mem_which=`echo ${mem_which} | tr a-z A-Z`
	echo "#define TME_M68K_IREG_MEM${cap_mem_which}32		(${ireg32_next})"
	echo "#define tme_m68k_ireg_mem${mem_which}32		tme_m68k_ireg_uint32(TME_M68K_IREG_MEM${cap_mem_which}32)"
	echo "#define TME_M68K_IREG_MEM${cap_mem_which}16		(${ireg32_next} << 1)"
	echo "#define tme_m68k_ireg_mem${mem_which}16		tme_m68k_ireg_uint16(TME_M68K_IREG_MEM${cap_mem_which}16)"
	echo "#define TME_M68K_IREG_MEM${cap_mem_which}8		(${ireg32_next} << 2)"
	echo "#define tme_m68k_ireg_mem${mem_which}8		tme_m68k_ireg_uint8(TME_M68K_IREG_MEM${cap_mem_which}8)"
	ireg32_next=`expr ${ireg32_next} + 1`
    done

    # the control registers:
    for reg in usp isp msp sfc dfc vbr cacr caar; do
	capreg=`echo $reg | tr a-z A-Z`
	echo "#define TME_M68K_IREG_${capreg}		(${ireg32_next})"
	echo "#define tme_m68k_ireg_${reg}		tme_m68k_ireg_uint32(TME_M68K_IREG_${capreg})"
	ireg32_next=`expr ${ireg32_next} + 1`
    done

    # this is the count of variable 32-bit registers:
    echo "#define TME_M68K_IREG32_COUNT		(${ireg32_next})"

    # the immediate register.  there are actually three 32-bit
    # registers in a row, to allow the fpgen specop to fetch up to a
    # 96-bit immediate:
    echo "#define TME_M68K_IREG_IMM32		(${ireg32_next})"
    echo "#define tme_m68k_ireg_imm32		tme_m68k_ireg_uint32(TME_M68K_IREG_IMM32)"
    ireg32_next=`expr ${ireg32_next} + 3`

    # the effective address register:
    echo "#define TME_M68K_IREG_EA		(${ireg32_next})"
    echo "#define tme_m68k_ireg_ea		tme_m68k_ireg_uint32(TME_M68K_IREG_EA)"
    ireg32_next=`expr ${ireg32_next} + 1`

    # the constant registers:
    for reg in zero one two three four five six seven eight; do
	capreg=`echo $reg | tr a-z A-Z`
	echo "#define TME_M68K_IREG_${capreg}		(${ireg32_next})"
	ireg32_next=`expr ${ireg32_next} + 1`
    done
fi

# emit the flags->conditions mapping.  note that the nesting of the
# flag variables is deliberate, to make this array indexable with the
# condition code register:
if $header; then :; else
    echo ""
    echo "/* the flags->conditions mapping: */"
    echo "const tme_uint16_t _tme_m68k_conditions[32] = {"
    for xflag in 0 1; do
	for nflag in 0 1; do
	    for zflag in 0 1; do
		for vflag in 0 1; do
		    for cflag in 0 1; do
		    
			# the True condition:
			echo -n "TME_BIT(TME_M68K_C_T)"
			
			# the High condition:
			if test $cflag != 1 && test $zflag != 1; then
			    echo -n " | TME_BIT(TME_M68K_C_HI)"
			fi
			
			# the Low or Same condition:
			if test $cflag = 1 || test $zflag = 1; then
			    echo -n " | TME_BIT(TME_M68K_C_LS)"
			fi
			
			# the Carry Clear and Carry Set conditions:
			if test $cflag != 1; then
			    echo -n " | TME_BIT(TME_M68K_C_CC)"
			else
			    echo -n " | TME_BIT(TME_M68K_C_CS)"
			fi
			
			# the Not Equal and Equal conditions:
			if test $zflag != 1; then
			    echo -n " | TME_BIT(TME_M68K_C_NE)"
			else
			    echo -n " | TME_BIT(TME_M68K_C_EQ)"
			fi
			
			# the Overflow Clear and Overflow Set conditions:
			if test $vflag != 1; then
			    echo -n " | TME_BIT(TME_M68K_C_VC)"
			else
			    echo -n " | TME_BIT(TME_M68K_C_VS)"
			fi
			
			# the Plus and Minus conditions:
			if test $nflag != 1; then
			    echo -n " | TME_BIT(TME_M68K_C_PL)"
			else
			    echo -n " | TME_BIT(TME_M68K_C_MI)"
			fi
			
			# the Greater or Equal condition:
			if (test $nflag = 1 && test $vflag = 1) || \
			   (test $nflag != 1 && test $vflag != 1); then
			    echo -n " | TME_BIT(TME_M68K_C_GE)"
			fi
			
			# the Less Than condition:
			if (test $nflag = 1 && test $vflag != 1) || \
			   (test $nflag != 1 && test $vflag = 1); then
			    echo -n " | TME_BIT(TME_M68K_C_LT)"
			fi

			# the Greater Than condition:
			if (test $nflag = 1 && test $vflag = 1 && test $zflag != 1) || \
			   (test $nflag != 1 && test $vflag != 1 && test $zflag != 1); then
			    echo -n " | TME_BIT(TME_M68K_C_GT)"
			fi
		    
			# the Less Than or Equal condition:
			if test $zflag = 1 || \
			   (test $nflag = 1 && test $vflag != 1) || \
			   (test $nflag != 1 && test $vflag = 1); then
			    echo -n " | TME_BIT(TME_M68K_C_LE)"
			fi

			echo ","
		    done
		done
	    done
	done
    done
    echo "};"
fi

# emit the instruction word fetch macros:
if $header; then

    # emit the simple signed and unsigned fetch macros:
    #
    echo ""
    echo "/* the simple signed and unsigned fetch macros: */"

    # permute over size:
    #
    for size in 16 32; do

	# permute for signed or unsigned:
	#
	for capsign in U S; do
	    if test $capsign = U; then sign=u ; un=un ; else sign= ; un= ; fi

	    echo "#define _TME_M68K_EXECUTE_FETCH_${capsign}${size}(v) \\"
	    echo "  _TME_M68K_EXECUTE_FETCH_${size}(tme_${sign}int${size}_t, v)"
	    if test ${size} = 16 && test ${capsign} = U; then
		echo "#define _TME_M68K_EXECUTE_FETCH_${capsign}${size}_FIXED(v, field) \\"
		echo "  _TME_M68K_EXECUTE_FETCH_${size}_FIXED(tme_${sign}int${size}_t, v, field)"
	    fi
	done
    done

    echo ""
    echo "#endif /* _IC_M68K_MISC_H */"

    # permute for the fast vs. slow executors:
    for executor in fast slow; do

	echo ""
	echo -n "#if"
	if test $executor = slow; then echo -n "n"; fi
	echo "def _TME_M68K_EXECUTE_FAST"
	echo ""
	echo "/* these macros are for the ${executor} executor: */"

	# permute over size:
	#
	for size in 16 32; do

	    echo ""
	    echo "/* this fetches a ${size}-bit value for the ${executor} executor: */"
	    echo "#undef _TME_M68K_EXECUTE_FETCH_${size}"
	    echo "#define _TME_M68K_EXECUTE_FETCH_${size}(type, v) \\"

	    if test $executor = slow; then

		# this expression gives the current fetch offset in the instruction:
		#
		offset_fetch="ic->_tme_m68k_insn_fetch_slow_next"

		echo "  /* macros for the ${executor} executor are simple, because \\"
		echo "     tme_m68k_fetch${size}() takes care of all endianness, alignment, \\"
		echo "     and atomic issues, and also stores the fetched value in the \\"
		echo "     instruction fetch buffer (if a previous fetch before a fault \\"
		echo "     didn't store all or part of it there already): */ \\"
		echo "  (v) = (type) tme_m68k_fetch${size}(ic, linear_pc); \\"
		echo "  linear_pc += sizeof(tme_uint${size}_t)"
	    
	    else

		# this expression gives the current fetch offset in the instruction:
		#
		offset_fetch="(fetch_fast_next - ic->_tme_m68k_insn_fetch_fast_start)"
		
		echo "  /* use the raw fetch macro to fetch the value into the variable, \\"
		echo "     and then save it in the instruction buffer.  the save doesn't \\"
		echo "     need to be atomic; no one else can see the instruction buffer. \\"
		echo "     however, the raw fetch macro has already advanced fetch_fast_next, \\"
		echo "     so we need to compensate for that here: */ \\"
		echo "  __TME_M68K_EXECUTE_FETCH_${size}(type, v); \\"
		echo "  tme_memory_write${size}(((tme_uint${size}_t *) ((((tme_uint8_t *) &ic->_tme_m68k_insn_fetch_buffer[0]) - sizeof(tme_uint${size}_t)) + ${offset_fetch})), (tme_uint${size}_t) (v), sizeof(tme_uint16_t))"

		echo ""
		echo "/* this does a raw fetch of a ${size}-bit value for the ${executor} executor: */"
		echo "#undef __TME_M68K_EXECUTE_FETCH_${size}"
		echo "#define __TME_M68K_EXECUTE_FETCH_${size}(type, v) \\"
		echo "  /* if we can't do the fast read, we need to redispatch: */ \\"
		echo "  /* NB: checks in tme_m68k_go_slow(), and proper setting of \\"
		echo "     ic->_tme_m68k_insn_fetch_fast_last in _TME_M68K_EXECUTE_NAME(), \\"
		echo "     allow  us to do a simple pointer comparison here, for \\"
		echo "     any fetch size: */ \\"
		echo "  if (__tme_predict_false(fetch_fast_next > ic->_tme_m68k_insn_fetch_fast_last)) \\"
		echo "    goto _tme_m68k_fast_fetch_failed; \\"
		echo "  (v) = ((type) \\"
		echo "         tme_betoh_u${size}(tme_memory_bus_read${size}((const tme_shared tme_uint${size}_t *) fetch_fast_next, \\"
		echo "                                             tlb->tme_m68k_tlb_bus_rwlock, \\"
		echo "                                             sizeof(tme_uint16_t), \\"
		echo "                                             sizeof(tme_uint32_t)))); \\"
		echo "  fetch_fast_next += sizeof(tme_uint${size}_t)"
	    fi

	    # if this size doesn't get a fixed fetch macro, continue now:
	    #
	    if test ${size} != 16; then
		continue
	    fi

	    echo ""
	    echo "/* this fetches a ${size}-bit value at a fixed instruction position"
	    echo "   for the ${executor} executor: */"
	    echo "#undef _TME_M68K_EXECUTE_FETCH_${size}_FIXED"
	    echo "#define _TME_M68K_EXECUTE_FETCH_${size}_FIXED(type, v, field) \\"
	    echo "  assert(&((struct tme_m68k *) 0)->field \\"
	    echo "         == (type *) (((tme_uint8_t *) &((struct tme_m68k *) 0)->_tme_m68k_insn_fetch_buffer[0]) + ${offset_fetch})); \\"
	    echo -n "  "
	    if test ${executor} = fast; then echo -n _ ; fi
	    echo "_TME_M68K_EXECUTE_FETCH_${size}(type, v)"

	done

	echo ""
	echo -n "#endif /* "
	if test $executor = slow; then echo -n "!"; fi
	echo "_TME_M68K_EXECUTE_FAST */"
    done
fi

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