diff options
Diffstat (limited to 'emulators/tme/patches/patch-aq')
-rw-r--r-- | emulators/tme/patches/patch-aq | 169 |
1 files changed, 169 insertions, 0 deletions
diff --git a/emulators/tme/patches/patch-aq b/emulators/tme/patches/patch-aq new file mode 100644 index 00000000000..f180e4d6fb3 --- /dev/null +++ b/emulators/tme/patches/patch-aq @@ -0,0 +1,169 @@ +$NetBSD: patch-aq,v 1.1 2007/03/17 13:44:19 tsutsui Exp $ + +--- ic/m68k/m68k-insns.c.orig 2005-03-23 20:53:02.000000000 +0900 ++++ ic/m68k/m68k-insns.c 2007-03-14 20:28:31.000000000 +0900 +@@ -485,9 +485,8 @@ + TME_M68K_INSN(tme_m68k_cmp2_chk2) + { + tme_uint32_t ireg; +- unsigned int size_bytes, size_name, size_ireg; ++ unsigned int size_bytes, size_ireg; + tme_uint32_t uvalue, ulower, uupper; +- tme_int32_t value, lower, upper; + + TME_M68K_INSN_CANFAULT; + +@@ -495,60 +494,109 @@ + ireg = TME_M68K_IREG_D0 + TME_FIELD_EXTRACTU(TME_M68K_INSN_SPECOP, 12, 4); + size_bytes = TME_FIELD_EXTRACTU(TME_M68K_INSN_OPCODE, 9, 2); + size_ireg = 2 - size_bytes; +- size_name = TME_M68K_SIZE_8 + size_bytes; ++ ++ /* size comes back from cp2 instruction as: ++ 0 : byte ++ 1 : word ++ 2 : long ++ we convert to ++ 0 : byte ++ 1 : word ++ 4 : long ++ */ + size_bytes = 1 << size_bytes; + + /* read in the two bounds: */ +- (*_tme_m68k_read_mem[size_name])(ic, TME_M68K_IREG_MEMX32 << size_ireg); ++ (*_tme_m68k_read_mem[size_bytes])(ic, TME_M68K_IREG_MEMX32 << size_ireg); + if (!TME_M68K_SEQUENCE_RESTARTING) { + ic->_tme_m68k_ea_address += size_bytes; + } +- (*_tme_m68k_read_mem[size_name])(ic, TME_M68K_IREG_MEMY32 << size_ireg); ++ (*_tme_m68k_read_mem[size_bytes])(ic, TME_M68K_IREG_MEMY32 << size_ireg); + +- /* if we have an address register, sign-extend the bounds to 32 +- bits: */ ++ /* if value is an address register, sign-extend the bounds to 32 bits, ++ then set size of bounds and value to 32 bits (so we check entire ++ longword value) ++ */ + if (ireg >= TME_M68K_IREG_A0) { +- if (size_name == TME_M68K_SIZE_8) { ++ if (size_bytes == TME_M68K_SIZE_8) { + ic->tme_m68k_ireg_int32(TME_M68K_IREG_MEMX32) = TME_EXT_S8_S32(ic->tme_m68k_ireg_int8(TME_M68K_IREG_MEMX8)); + ic->tme_m68k_ireg_int32(TME_M68K_IREG_MEMY32) = TME_EXT_S8_S32(ic->tme_m68k_ireg_int8(TME_M68K_IREG_MEMY8)); + } +- else if (size_name == TME_M68K_SIZE_16) { ++ else if (size_bytes == TME_M68K_SIZE_16) { + ic->tme_m68k_ireg_int32(TME_M68K_IREG_MEMX32) = TME_EXT_S16_S32(ic->tme_m68k_ireg_int16(TME_M68K_IREG_MEMX16)); + ic->tme_m68k_ireg_int32(TME_M68K_IREG_MEMY32) = TME_EXT_S16_S32(ic->tme_m68k_ireg_int16(TME_M68K_IREG_MEMY16)); + } +- size_bytes = sizeof(tme_uint32_t); +- size_name = TME_M68K_SIZE_32; ++ size_bytes = TME_M68K_SIZE_32; + } + +- /* get the values to check: */ +- switch (size_name) { ++ /* get the bounds and value */ ++ switch (size_bytes) { + case TME_M68K_SIZE_8: +- uvalue = ic->tme_m68k_ireg_uint8(ireg); + ulower = ic->tme_m68k_ireg_uint8(TME_M68K_IREG_MEMX8); + uupper = ic->tme_m68k_ireg_uint8(TME_M68K_IREG_MEMY8); +- value = ic->tme_m68k_ireg_int8(ireg); +- lower = ic->tme_m68k_ireg_int8(TME_M68K_IREG_MEMX8); +- upper = ic->tme_m68k_ireg_int8(TME_M68K_IREG_MEMY8); ++ ++ /* if value is a data register, read the entire register, extract ++ the appropriate number of bytes, and sign extend to our own ++ longword size for comparison. ++ if value is an address register, just use the entire register as is ++ */ ++ if (ireg < TME_M68K_IREG_A0) ++ uvalue = (tme_uint32_t)TME_EXT_S8_S32 ++ ((tme_int32_t)(ic->tme_m68k_ireg_uint32(ireg) & 0xFF)); ++ else ++ uvalue = ic->tme_m68k_ireg_uint32(ireg); ++ + break; + case TME_M68K_SIZE_16: +- uvalue = ic->tme_m68k_ireg_uint16(ireg); + ulower = ic->tme_m68k_ireg_uint16(TME_M68K_IREG_MEMX16); + uupper = ic->tme_m68k_ireg_uint16(TME_M68K_IREG_MEMY16); +- value = ic->tme_m68k_ireg_int16(ireg); +- lower = ic->tme_m68k_ireg_int16(TME_M68K_IREG_MEMX16); +- upper = ic->tme_m68k_ireg_int16(TME_M68K_IREG_MEMY16); ++ ++ /* if value is a data register, read the entire register, extract ++ the appropriate number of bytes, and sign extend to our own ++ longword size for comparison. ++ if value is an address register, just use the entire register as is ++ */ ++ if (ireg < TME_M68K_IREG_A0) ++ uvalue = (tme_uint32_t)TME_EXT_S16_S32 ++ ((tme_int32_t)(ic->tme_m68k_ireg_uint32(ireg) & 0xFFFF)); ++ else ++ uvalue = ic->tme_m68k_ireg_uint32(ireg); ++ + break; + case TME_M68K_SIZE_32: +- uvalue = ic->tme_m68k_ireg_uint32(ireg); + ulower = ic->tme_m68k_ireg_uint32(TME_M68K_IREG_MEMX32); + uupper = ic->tme_m68k_ireg_uint32(TME_M68K_IREG_MEMY32); +- value = ic->tme_m68k_ireg_int32(ireg); +- lower = ic->tme_m68k_ireg_int32(TME_M68K_IREG_MEMX32); +- upper = ic->tme_m68k_ireg_int32(TME_M68K_IREG_MEMY32); ++ ++ uvalue = ic->tme_m68k_ireg_uint32(ireg); ++ + break; + default: abort(); + } + ++ /* cmp2 / chk2 can be used for unsigned, or signed. ++ for either type, the lower bound "should be" <= upper bound ++ (per m68000 family programmer's reference manual) ++ ++ cmp2 instruction doesn't know if signed or unsigned ++ if bound 250 250 then bound is the one value, check unsigned or signed ++ ++ if bound 253 255 could be unsigned 253 255 ++ or signed -3 -1 ++ either way, ok to check. ++ ++ if bound 255 5 then only makes sense to check signed -1 5 ++ ++ if bound 255 253 then doesn't make sense either way! ++ its either 255 253 unsigned or -1 -3 signed. ++ ++ reverse engineering the code, by running many test cases shows that ++ the motorola 68020 microcode does the following. ++ ++ Always check unsigned. ++ if low <= high, then out of bounds if either < low or > high. ++ if high > low, then out of bounds if BOTH < low AND > high. ++ */ ++ + /* do the comparison. if the value is out-of-bounds and this is + a chk2 instruction, trap: */ + ic->tme_m68k_ireg_ccr = (ic->tme_m68k_ireg_ccr & TME_M68K_FLAG_X); +@@ -556,13 +604,14 @@ + || uvalue == uupper) { + ic->tme_m68k_ireg_ccr |= TME_M68K_FLAG_Z; + } +- else if ((ulower > uupper) +- /* signed comparison: */ +- ? (value < lower || value > upper) +- /* unsigned comparison: */ +- : (uvalue < ulower || uvalue > uupper)) { ++ else if (((ulower <= uupper) && (uvalue < ulower || uvalue > uupper)) || ++ ((ulower > uupper) && (uvalue < ulower && uvalue > uupper))) { + ic->tme_m68k_ireg_ccr |= TME_M68K_FLAG_C; +- if (TME_M68K_INSN_OPCODE & TME_BIT(11)) { ++ ++ /* if chk2 instruction, ++ also cause a CHK instruction exception (vector number 6) ++ */ ++ if (TME_FIELD_EXTRACTU(TME_M68K_INSN_SPECOP, 11, 1)) { + ic->tme_m68k_ireg_pc_last = ic->tme_m68k_ireg_pc; + ic->tme_m68k_ireg_pc = ic->tme_m68k_ireg_pc_next; + TME_M68K_INSN_EXCEPTION(TME_M68K_EXCEPTION_INST(TME_M68K_VECTOR_CHK)); |