--- tme/ic/m68k/m68k-insns-auto.sh 2018/04/24 16:37:52 1.1 +++ tme/ic/m68k/m68k-insns-auto.sh 2018/04/24 16:40:24 1.1.1.3 @@ -1,6 +1,6 @@ #! /bin/sh -# $Id: m68k-insns-auto.sh,v 1.1 2018/04/24 16:37:52 root Exp $ +# $Id: m68k-insns-auto.sh,v 1.1.1.3 2018/04/24 16:40:24 root Exp $ # ic/m68k/m68k-insns-auto.sh - automatically generates C code # for many m68k emulation instructions: @@ -48,7 +48,7 @@ done PROG=`basename $0` cat < 0) {" case "${name}" in - [al]sr) + lsr) echo " if (63 > SHIFTMAX_INT${size}_T" echo " && count > ${size}) {" echo " res = 0;" @@ -458,6 +458,27 @@ for size in 8 16 32; do echo " flags |= (flags * TME_M68K_FLAG_X);" echo " res >>= 1;" ;; + asr) + echo " if (63 > SHIFTMAX_INT${size}_T" + echo " && count > ${size}) {" + echo " res = 0 - (res < 0);" + echo " }" + echo "#ifdef SHIFTSIGNED_INT${size}_T" + echo " res >>= (count - 1);" + echo "#else /* !SHIFTSIGNED_INT${size}_T */" + echo " for (; --count > 0; ) {" + echo " res = (res & ~((tme_${sign}int${size}_t) 1)) / 2;" + echo " }" + echo "#endif /* !SHIFTSIGNED_INT${size}_T */" + echo " flags = (res & 1);" + echo " flags *= TME_M68K_FLAG_C;" + echo " flags |= (flags * TME_M68K_FLAG_X);" + echo "#ifdef SHIFTSIGNED_INT${size}_T" + echo " res >>= 1;" + echo "#else /* !SHIFTSIGNED_INT${size}_T */" + echo " res = (res & ~((tme_${sign}int${size}_t) 1)) / 2;" + echo "#endif /* !SHIFTSIGNED_INT${size}_T */" + ;; [al]sl) if test ${name} = asl; then echo "" @@ -465,27 +486,28 @@ for size in 8 16 32; do echo " shifting in order to generate V." echo "" echo " in general, the idea is to get all of the bits that will ever" - echo " appear in the sign position into sign_bits; if sign_bits is" - echo " all-bits-one or all-bits zero, clear V, else set V. a good trick" - echo " is that ((sign_bits + 1) & sign_bits) is nonzero iff all of the" - echo " bits in sign_bits are the same." + echo " appear in the sign position into sign_bits, with a mask in" + echo " sign_bits_mask. if (sign_bits & sign_bits_mask) is zero or" + echo " sign_bits_mask, clear V, else set V." echo "" - echo " start by loading all of the operand into sign_bits." + echo " start by loading the operand into sign_bits and setting" + echo " sign_bits_mask to all-bits-one." echo "" echo " if the shift count is exactly ${size} - 1, then all of the bits" echo " of the operand will appear in the sign position." echo "" echo " if the shift count is less than ${size} - 1, then some of the" echo " less significant bits of the operand will never appear in the" - echo " sign position, so we can shift them off of sign_bits now." + echo " sign position, so we can shift sign_bits_mask to ignore them." echo "" echo " if the shift count is greater than ${size} - 1, then all of the" echo " bits in the operand, plus at least one zero bit, will appear in" echo " the sign position. the only way that the sign bit will never" echo " change during the shift is if the operand was zero to begin with." - echo " we need to change sign_bits such that ((sign_bits + 1) &" - echo " sign_bits) will be zero iff the operand was zero to begin with." - echo " the magic below does just that: */" + echo " without any changes to sign_bits or sign_bits_mask, the final" + echo " test will always work, except when sign_bits is all-bits-one." + echo " the magic below clears the least-significant bit of sign_bits" + echo " iff sign_bits is all-bits-one: */" echo " sign_bits = res;" fi echo " if (63 > SHIFTMAX_INT${size}_T" @@ -498,16 +520,17 @@ for size in 8 16 32; do echo " flags |= (flags * TME_M68K_FLAG_X);" echo " res <<= 1;" if test ${name} = asl; then + echo " sign_bits_mask = (tme_uint${size}_t) -1;" echo " if (count != ${size} - 1) {" echo " if (count < ${size}) {" - echo " sign_bits >>= ((${size} - 1) - count);" + echo " sign_bits_mask <<= ((${size} - 1) - count);" echo " }" echo " else {" - echo " sign_bits |= (sign_bits << 1);" - echo " sign_bits &= -2;" + echo " sign_bits ^= !(sign_bits + 1);" echo " }" echo " }" - echo " if ((sign_bits + 1) & sign_bits) {" + echo " sign_bits &= sign_bits_mask;" + echo " if (sign_bits != 0 && sign_bits != sign_bits_mask) {" echo " flags |= TME_M68K_FLAG_V;" echo " }" fi @@ -657,8 +680,6 @@ for size in 8 16 32; do echo " tme_uint32_t addend;" echo "" - echo " TME_M68K_INSN_CANFAULT;" - echo "" echo " /* figure out what direction to move in, and where to start from: */" echo " ea_mode = TME_FIELD_EXTRACTU(TME_M68K_INSN_OPCODE, 3, 3);" echo " direction = 1;" @@ -677,6 +698,9 @@ for size in 8 16 32; do echo "" echo " /* do the transfer: */" echo " mask = TME_M68K_INSN_SPECOP;" + echo " if (mask != 0) {" + echo " TME_M68K_INSN_CANFAULT;" + echo " }" echo " for (bit = 1; bit != 0; bit <<= 1) {" echo " if (mask & bit) {" if test $name = rm; then @@ -737,13 +761,15 @@ for size in 8 16 32; do echo "{" echo " if (*((tme_int${size}_t *) _op0) < 0) {" echo " ic->tme_m68k_ireg_ccr |= TME_M68K_FLAG_N;" + echo " ic->tme_m68k_ireg_pc_last = ic->tme_m68k_ireg_pc;" echo " ic->tme_m68k_ireg_pc = ic->tme_m68k_ireg_pc_next;" - echo " TME_M68K_INSN_EXCEPTION(TME_M68K_EXCEPTION_GROUP2(6));" + echo " TME_M68K_INSN_EXCEPTION(TME_M68K_EXCEPTION_INST(TME_M68K_VECTOR_CHK));" echo " }" echo " if (*((tme_int${size}_t *) _op0) > *((tme_int${size}_t *) _op1)) {" echo " ic->tme_m68k_ireg_ccr &= ~TME_M68K_FLAG_N;" + echo " ic->tme_m68k_ireg_pc_last = ic->tme_m68k_ireg_pc;" echo " ic->tme_m68k_ireg_pc = ic->tme_m68k_ireg_pc_next;" - echo " TME_M68K_INSN_EXCEPTION(TME_M68K_EXCEPTION_GROUP2(6));" + echo " TME_M68K_INSN_EXCEPTION(TME_M68K_EXCEPTION_INST(TME_M68K_VECTOR_CHK));" echo " }" echo " TME_M68K_INSN_OK;" echo "}" @@ -772,7 +798,7 @@ for size in 8 16 32; do echo " int do_write;" echo " tme_uint16_t specopx = ic->_tme_m68k_insn_specop;" if test $name = cas2_; then - echo " tme_uint16_t specopy = ic->_tme_m68k_insn_specop2;" + echo " tme_uint16_t specopy = TME_M68K_INSN_OP0(tme_uint16_t);" echo " tme_uint32_t addrx;" echo " tme_uint32_t addry;" echo "" @@ -874,11 +900,38 @@ for size in 8 16 32; do echo "TME_M68K_INSN(tme_m68k_moves${size})" echo "{" echo " int ireg;" + echo " unsigned int ea_reg;" + echo " unsigned int increment;" + echo " TME_M68K_INSN_PRIV;" + echo " TME_M68K_INSN_CANFAULT;" echo " ireg = TME_M68K_IREG_D0 + TME_FIELD_EXTRACTU(TME_M68K_INSN_SPECOP, 12, 4);" + echo "" + echo " /* we have to handle postincrement and predecrement ourselves: */" + echo " if (!TME_M68K_SEQUENCE_RESTARTING) {" + echo " ea_reg = TME_M68K_IREG_A0 + TME_FIELD_EXTRACTU(TME_M68K_INSN_OPCODE, 0, 3);" + echo " increment = TME_M68K_SIZE_${size};" + echo " if (increment == TME_M68K_SIZE_8 && ea_reg == TME_M68K_IREG_A7) {" + echo " increment = TME_M68K_SIZE_16;" + echo " }" + echo " switch (TME_FIELD_EXTRACTU(TME_M68K_INSN_OPCODE, 3, 3)) {" + echo " case 3: ic->tme_m68k_ireg_uint32(ea_reg) += increment; break;" + echo " case 4: ic->_tme_m68k_ea_address = (ic->tme_m68k_ireg_uint32(ea_reg) -= increment); break;" + echo " default: break;" + echo " }" + echo " }" + echo "" echo " if (TME_M68K_INSN_SPECOP & TME_BIT(11)) {" - echo " ic->tme_m68k_ireg_memx${size} = ic->tme_m68k_ireg_uint${size}(ireg${reg_size_shift});" + echo " if (!TME_M68K_SEQUENCE_RESTARTING) {" + echo " ic->tme_m68k_ireg_memx${size} = ic->tme_m68k_ireg_uint${size}(ireg${reg_size_shift});" + echo " ic->_tme_m68k_ea_function_code = ic->tme_m68k_ireg_dfc;" + echo " }" + echo " tme_m68k_write_memx${size}(ic);" echo " }" echo " else {" + echo " if (!TME_M68K_SEQUENCE_RESTARTING) {" + echo " ic->_tme_m68k_ea_function_code = ic->tme_m68k_ireg_sfc;" + echo " }" + echo " tme_m68k_read_memx${size}(ic);" if test ${size} != 32; then echo " if (ireg >= TME_M68K_IREG_A0) {" echo " ic->tme_m68k_ireg_uint32(ireg) = " @@ -1037,6 +1090,12 @@ for size in 8 16 32 any; do ;; esac + # track statistics: + echo "" + echo "#ifdef _TME_M68K_STATS" + echo " ic->tme_m68k_stats.tme_m68k_stats_memory_total++;" + echo "#endif /* _TME_M68K_STATS */" + # if this is a write, log the value written: if test $name = write; then echo "" @@ -1366,7 +1425,7 @@ for size in 8 16 32 any; do echo " /* only byte transfers can be unaligned: */" echo " if (resid > sizeof(tme_uint8_t)" echo " && (linear_address & 1)) {" - echo " exception = TME_M68K_EXCEPTION_GROUP0_AERR;" + echo " exception = TME_M68K_EXCEPTION_AERR;" echo " break;" echo " }" echo "" @@ -1385,7 +1444,7 @@ for size in 8 16 32 any; do echo " /* an instruction fetch must be aligned: */" echo " if (flags & TME_M68K_BUS_CYCLE_FETCH) {" echo " if (linear_address & 1) {" - echo " exception = TME_M68K_EXCEPTION_GROUP0_AERR;" + echo " exception = TME_M68K_EXCEPTION_AERR;" echo " break;" echo " }" echo " assert(!(resid & 1));" @@ -1418,7 +1477,7 @@ for size in 8 16 32 any; do echo " if (!TME_M68K_TLB_OK_FAST_${capname}(tlb, function_code, linear_address, linear_address)" echo " || (rmw_rwlock != NULL" echo " && rmw_rwlock != tlb->tme_m68k_tlb_bus_rwlock)) {" - echo " exception = TME_M68K_EXCEPTION_GROUP0_BERR;" + echo " exception = TME_M68K_EXCEPTION_BERR;" echo " break;" echo " }" echo "" @@ -1454,11 +1513,20 @@ for size in 8 16 32 any; do echo " cycle.tme_bus_cycle_address = physical_address;" echo " }" echo "" + echo " /* otherwise, if we didn't get a bus error, but some" + echo " synchronous event has happened: */" + echo " else 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_m68k_instruction_burst_remaining = 0;" + echo " }" + echo "" echo " /* otherwise, any other error might be a bus error: */" echo " else if (err != TME_OK) {" echo " err = tme_bus_tlb_fault(&tlb->tme_m68k_tlb_bus_tlb, &cycle, err);" echo " if (err != TME_OK) {" - echo " exception = TME_M68K_EXCEPTION_GROUP0_BERR;" + echo " exception = TME_M68K_EXCEPTION_BERR;" echo " break;" echo " }" echo " }" @@ -1702,9 +1770,9 @@ for _sign in u s; do echo "TME_M68K_INSN(tme_m68k_mul${_sign}${_size})" echo "{" if test $large = 64; then - echo "#ifndef HAVE_UINT${large}_T" + echo "#ifndef TME_HAVE_INT${large}_T" echo " abort();" - echo "#else /* HAVE_UINT${large}_T */" + echo "#else /* TME_HAVE_INT${large}_T */" echo " unsigned int flag_v;" echo " int ireg_dh;" fi @@ -1744,8 +1812,11 @@ for _sign in u s; do echo " if (((tme_int${large}_t) res) < 0) flags |= TME_M68K_FLAG_N;" echo " if (res == 0) flags |= TME_M68K_FLAG_Z;" if test $large = 64; then - echo -n " if (res > 0xffffffff" - if test $_sign = s; then echo -n " || res < -2147483648"; fi + if test $_sign = s; then + echo -n " if (res > 0x7fffffffL || res < ((0L - 0x7fffffffL) - 1L)" + else + echo -n " if (res > 0xffffffffUL" + fi echo ") flags |= flag_v;" fi echo " ic->tme_m68k_ireg_ccr = flags;" @@ -1753,7 +1824,7 @@ for _sign in u s; do echo "" echo " TME_M68K_INSN_OK;" if test $large = 64; then - echo "#endif /* HAVE_UINT${large}_T */" + echo "#endif /* TME_HAVE_INT${large}_T */" fi echo "}" @@ -1762,9 +1833,9 @@ for _sign in u s; do echo "TME_M68K_INSN(tme_m68k_div${_sign}${_size})" echo "{" if test $large = 64; then - echo "#ifndef HAVE_UINT${large}_T" + echo "#ifndef TME_HAVE_INT${large}_T" echo " abort();" - echo "#else /* HAVE_UINT${large}_T */" + echo "#else /* TME_HAVE_INT${large}_T */" echo " int ireg_dr;" fi echo " int ireg_dq;" @@ -1796,8 +1867,9 @@ for _sign in u s; do echo " dividend = (tme_${sign}int${large}_t) ic->tme_m68k_ireg_${sign}int32(ireg_dq);" echo " divisor = TME_M68K_INSN_OP1(tme_${sign}int${small}_t);" echo " if (divisor == 0) {" + echo " ic->tme_m68k_ireg_pc_last = ic->tme_m68k_ireg_pc;" echo " ic->tme_m68k_ireg_pc = ic->tme_m68k_ireg_pc_next;" - echo " TME_M68K_INSN_EXCEPTION(TME_M68K_EXCEPTION_GROUP2(5));" + echo " TME_M68K_INSN_EXCEPTION(TME_M68K_EXCEPTION_INST(TME_M68K_VECTOR_DIV0));" echo " }" echo "" @@ -1808,13 +1880,13 @@ for _sign in u s; do echo "" echo " /* set the flags and return the quotient and remainder: */" echo " flags = ic->tme_m68k_ireg_ccr & TME_M68K_FLAG_X;" - echo -n " if (quotient > 0xffff" - if test $small = 16; then - if test $_sign = s; then echo -n " || quotient < -32768"; fi - else - echo -n "ffff" - if test $_sign = s; then echo -n " || quotient < -2147483648"; fi - fi + echo -n " if (" + case "${small}${_sign}" in + 16s) echo -n "quotient > 0x7fff || quotient < -32768" ;; + 16u) echo -n "quotient > 0xffff" ;; + 32s) echo -n "quotient > 0x7fffffffL || quotient < ((0L - 0x7fffffffL) - 1L)" ;; + 32u) echo -n "quotient > 0xffffffffUL" ;; + esac echo ") {" echo " flags |= TME_M68K_FLAG_V;" echo " }" @@ -1835,7 +1907,7 @@ for _sign in u s; do echo "" echo " TME_M68K_INSN_OK;" if test $large = 64; then - echo "#endif /* HAVE_UINT${large}_T */" + echo "#endif /* TME_HAVE_INT${large}_T */" fi echo "}"