--- tme/ic/m68k/m68k-insns.c 2018/04/24 16:37:52 1.1 +++ tme/ic/m68k/m68k-insns.c 2018/04/24 16:41:53 1.1.1.4 @@ -1,11 +1,42 @@ -/* m68k-insns.c - m68k instruction functions: */ +/* $Id: m68k-insns.c,v 1.1.1.4 2018/04/24 16:41:53 root Exp $ */ -/* $Header: /var/lib/cvsd/tme/tme/ic/m68k/m68k-insns.c,v 1.1 2018/04/24 16:37:52 root Exp $ */ +/* ic/m68k/m68k-insns.c - m68k instruction functions: */ + +/* + * 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. + */ /* includes: */ #include "m68k-impl.h" -_TME_RCSID("$Id: m68k-insns.c,v 1.1 2018/04/24 16:37:52 root Exp $"); +_TME_RCSID("$Id: m68k-insns.c,v 1.1.1.4 2018/04/24 16:41:53 root Exp $"); #define TME_M68K_STD_FLAGS \ do { \ @@ -128,16 +159,26 @@ TME_M68K_INSN(tme_m68k_dbcc) } /* this cannot fault: */ -TME_M68K_INSN(tme_m68k_bcc) +static void +_tme_m68k_bcc(struct tme_m68k *ic, tme_int32_t disp) { if (TME_M68K_COND_TRUE(ic, TME_FIELD_EXTRACTU(TME_M68K_INSN_OPCODE, 8, 4))) { - TME_M68K_INSN_BRANCH(ic->tme_m68k_ireg_pc + 2 + TME_M68K_INSN_OP0(tme_uint32_t)); + TME_M68K_INSN_BRANCH(ic->tme_m68k_ireg_pc + 2 + disp); } TME_M68K_INSN_OK; } +TME_M68K_INSN(tme_m68k_bcc) +{ + _tme_m68k_bcc(ic, TME_EXT_S8_S32((tme_int8_t) TME_M68K_INSN_OPCODE)); +} +TME_M68K_INSN(tme_m68k_bccl) +{ + _tme_m68k_bcc(ic, TME_M68K_INSN_OP0(tme_int32_t)); +} /* this can fault: */ -TME_M68K_INSN(tme_m68k_bsr) +static void +_tme_m68k_bsr(struct tme_m68k *ic, tme_int32_t disp) { TME_M68K_INSN_CANFAULT; tme_m68k_push32(ic, ic->tme_m68k_ireg_pc_next); @@ -145,9 +186,21 @@ TME_M68K_INSN(tme_m68k_bsr) restarting here, because after this point, nothing can fault for the remainder of this instruction (the executor makes no stores on behalf of a bsr): */ - TME_M68K_INSN_BRANCH(ic->tme_m68k_ireg_pc + 2 + TME_M68K_INSN_OP0(tme_uint32_t)); + tme_m68k_log(ic, 250, TME_OK, + (TME_M68K_LOG_HANDLE(ic), + _("bsr 0x%08x"), + (ic->tme_m68k_ireg_pc + 2 + disp))); + TME_M68K_INSN_BRANCH(ic->tme_m68k_ireg_pc + 2 + disp); TME_M68K_INSN_OK; } +TME_M68K_INSN(tme_m68k_bsr) +{ + _tme_m68k_bsr(ic, TME_EXT_S8_S32((tme_int8_t) TME_M68K_INSN_OPCODE)); +} +TME_M68K_INSN(tme_m68k_bsrl) +{ + _tme_m68k_bsr(ic, TME_M68K_INSN_OP0(tme_int32_t)); +} /* this can fault: */ TME_M68K_INSN(tme_m68k_pea) @@ -164,36 +217,79 @@ TME_M68K_INSN(tme_m68k_pea) /* this cannot fault: */ TME_M68K_INSN(tme_m68k_bkpt) { - TME_M68K_INSN_EXCEPTION(TME_M68K_EXCEPTION_GROUP1_ILL); + TME_M68K_INSN_EXCEPTION(TME_M68K_EXCEPTION_ILL); } /* this cannot fault: */ TME_M68K_INSN(tme_m68k_illegal) { - TME_M68K_INSN_EXCEPTION(TME_M68K_EXCEPTION_GROUP1_ILL); + TME_M68K_INSN_EXCEPTION(TME_M68K_EXCEPTION_ILL); } /* this can fault: */ TME_M68K_INSN(tme_m68k_tas) { + struct tme_m68k_rmw rmw; struct tme_m68k_tlb *tlb; + tme_shared tme_int8_t *mem; tme_uint8_t flags; tme_int8_t value; - - TME_M68K_INSN_CANFAULT; + tme_int8_t value_written; + tme_int8_t value_verify; /* start the read/modify/write cycle: */ - tlb = tme_m68k_rmw_start(ic); - if (tlb == NULL) + rmw.tme_m68k_rmw_addresses[0] = ic->_tme_m68k_ea_address; + rmw.tme_m68k_rmw_address_count = 1; + rmw.tme_m68k_rmw_size = sizeof(tme_uint8_t); + if (tme_m68k_rmw_start(ic, + &rmw)) TME_M68K_INSN_OK; - /* the read part of the read/modify/write cycle: */ - tme_m68k_read8(ic, tlb, - &ic->_tme_m68k_ea_function_code, - &ic->_tme_m68k_ea_address, - &ic->tme_m68k_ireg_memx8, - TME_M68K_BUS_CYCLE_RMW); + /* if this TLB entry allows fast reading: */ + if (!rmw.tme_m68k_rmw_slow_reads[0]) { + + /* get this TLB entry: */ + tlb = rmw.tme_m68k_rmw_tlbs[0]; + + /* make the emulator memory pointer: */ + mem = (tme_shared tme_int8_t *) (tlb->tme_m68k_tlb_emulator_off_read + ic->_tme_m68k_ea_address); + /* read memory: */ + value + = tme_memory_atomic_read8((tme_shared tme_uint8_t *) mem, + tlb->tme_m68k_tlb_bus_rwlock, + sizeof(tme_uint8_t)); + + /* spin the tas in a compare-and-exchange loop: */ + for (;;) { + + /* make the value to write: */ + value_written = value | 0x80; + + /* try the compare-and-exchange: */ + value_verify + = tme_memory_atomic_cx8((tme_shared tme_uint8_t *) mem, + value, + value_written, + tlb->tme_m68k_tlb_bus_rwlock, + sizeof(tme_uint8_t)); + + /* if the compare-and-exchange failed: */ + if (__tme_predict_false(value_verify != value)) { + + /* loop with the new value read from the memory: */ + value = value_verify; + continue; + } + + /* stop now: */ + break; + } + + /* store the value read: */ + ic->tme_m68k_ireg_memx8 = value; + } + /* the modify part of the read/modify/write cycle: */ value = ic->tme_m68k_ireg_memx8; flags = ic->tme_m68k_ireg_ccr & TME_M68K_FLAG_X; @@ -202,15 +298,10 @@ TME_M68K_INSN(tme_m68k_tas) ic->tme_m68k_ireg_ccr = flags; ic->tme_m68k_ireg_memx8 |= 0x80; - /* the write part of the read/modify/write cycle: */ - tme_m68k_write8(ic, tlb, - &ic->_tme_m68k_ea_function_code, - &ic->_tme_m68k_ea_address, - &ic->tme_m68k_ireg_memx8, - TME_M68K_BUS_CYCLE_RMW); - /* finish the read/modify/write cycle: */ - tme_m68k_rmw_finish(ic, tlb); + tme_m68k_rmw_finish(ic, + &rmw, + TRUE); TME_M68K_INSN_OK; } @@ -246,15 +337,16 @@ TME_M68K_INSN(tme_m68k_move_usp) TME_M68K_INSN(tme_m68k_trap) { ic->tme_m68k_ireg_pc = ic->tme_m68k_ireg_pc_next; - TME_M68K_INSN_EXCEPTION(TME_M68K_EXCEPTION_GROUP2(32 + TME_FIELD_EXTRACTU(TME_M68K_INSN_OPCODE, 0, 4))); + TME_M68K_INSN_EXCEPTION(TME_M68K_EXCEPTION_INST(TME_M68K_VECTOR_TRAP_0 + TME_FIELD_EXTRACTU(TME_M68K_INSN_OPCODE, 0, 4))); } /* this cannot fault: */ TME_M68K_INSN(tme_m68k_trapv) { if (ic->tme_m68k_ireg_ccr & TME_M68K_FLAG_V) { + 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_GROUP2(7)); + TME_M68K_INSN_EXCEPTION(TME_M68K_EXCEPTION_INST(TME_M68K_VECTOR_TRAP)); } TME_M68K_INSN_OK; } @@ -283,20 +375,31 @@ TME_M68K_INSN(tme_m68k_movec) { int ireg; tme_uint32_t *creg; + tme_uint32_t mask; + int illegal; TME_M68K_INSN_PRIV; /* in case we're reading the msp or isp and we're on that stack, this flushes %a7 to that register: */ tme_m68k_change_sr(ic, ic->tme_m68k_ireg_sr); ireg = TME_M68K_IREG_D0 + TME_FIELD_EXTRACTU(TME_M68K_INSN_SPECOP, 12, 4); + mask = 0xffffffff; + illegal = FALSE; switch (TME_FIELD_EXTRACTU(TME_M68K_INSN_SPECOP, 0, 12)) { - case 0x000: creg = &ic->tme_m68k_ireg_sfc; break; - case 0x001: creg = &ic->tme_m68k_ireg_dfc; break; + case 0x000: creg = &ic->tme_m68k_ireg_sfc; mask = TME_M68K_FC_7; break; + case 0x001: creg = &ic->tme_m68k_ireg_dfc; mask = TME_M68K_FC_7; break; + case 0x002: creg = &ic->tme_m68k_ireg_cacr; mask = 0x3; illegal = (ic->tme_m68k_type < TME_M68K_M68020); break; case 0x800: creg = &ic->tme_m68k_ireg_usp; break; case 0x801: creg = &ic->tme_m68k_ireg_vbr; break; - default: TME_M68K_INSN_EXCEPTION(TME_M68K_EXCEPTION_GROUP1_ILL); creg = NULL; + case 0x802: creg = &ic->tme_m68k_ireg_caar; illegal = (ic->tme_m68k_type != TME_M68K_M68020); break; + case 0x803: creg = &ic->tme_m68k_ireg_msp; illegal = (ic->tme_m68k_type < TME_M68K_M68020); break; + case 0x804: creg = &ic->tme_m68k_ireg_isp; illegal = (ic->tme_m68k_type < TME_M68K_M68020); break; + default: illegal = TRUE; creg = NULL; + } + if (illegal) { + TME_M68K_INSN_EXCEPTION(TME_M68K_EXCEPTION_ILL); } if (TME_M68K_INSN_OPCODE & TME_BIT(0)) { - *creg = ic->tme_m68k_ireg_uint32(ireg); + *creg = ic->tme_m68k_ireg_uint32(ireg) & mask; } else { ic->tme_m68k_ireg_uint32(ireg) = *creg; @@ -310,8 +413,38 @@ TME_M68K_INSN(tme_m68k_movec) /* this cannot fault: */ TME_M68K_INSN(tme_m68k_reset) { + struct tme_bus_connection *conn_bus; + int rc; + TME_M68K_INSN_PRIV; - abort(); + + /* get the bus connection: */ + conn_bus = &ic->_tme_m68k_bus_connection->tme_m68k_bus_connection; + + /* unlock for the callout: */ + tme_m68k_callout_unlock(ic); + + /* assert the RESET line: */ + rc = (*conn_bus->tme_bus_signal) + (conn_bus, + (TME_BUS_SIGNAL_RESET + | TME_BUS_SIGNAL_LEVEL_ASSERTED)); + assert (rc == TME_OK); + + /* XXX RESET is supposed to be asserted for 512 clocks, + so a sleep is needed here: */ + + /* negate the RESET line: */ + rc = (*conn_bus->tme_bus_signal) + (conn_bus, + (TME_BUS_SIGNAL_RESET + | TME_BUS_SIGNAL_LEVEL_NEGATED)); + assert (rc == TME_OK); + + /* relock after the callout: */ + tme_m68k_callout_relock(ic); + + TME_M68K_INSN_OK; } /* this can fault: */ @@ -350,6 +483,10 @@ TME_M68K_INSN(tme_m68k_rts) { TME_M68K_INSN_CANFAULT; tme_m68k_pop32(ic, &ic->tme_m68k_ireg_memx32); + tme_m68k_log(ic, 250, TME_OK, + (TME_M68K_LOG_HANDLE(ic), + _("rts 0x%08x"), + ic->tme_m68k_ireg_memx32)); TME_M68K_INSN_BRANCH(ic->tme_m68k_ireg_memx32); TME_M68K_INSN_OK; } @@ -359,6 +496,10 @@ TME_M68K_INSN(tme_m68k_jsr) { TME_M68K_INSN_CANFAULT; tme_m68k_push32(ic, ic->tme_m68k_ireg_pc_next); + tme_m68k_log(ic, 250, TME_OK, + (TME_M68K_LOG_HANDLE(ic), + _("jsr 0x%08x"), + ic->_tme_m68k_ea_address)); TME_M68K_INSN_BRANCH(ic->_tme_m68k_ea_address); TME_M68K_INSN_OK; } @@ -393,7 +534,7 @@ TME_M68K_INSN(tme_m68k_stop) /* this cannot fault: */ TME_M68K_INSN(tme_m68k_priv) { - TME_M68K_INSN_EXCEPTION(TME_M68K_EXCEPTION_GROUP1_PRIV); + TME_M68K_INSN_EXCEPTION(TME_M68K_EXCEPTION_PRIV); } /* this can fault: */ @@ -402,7 +543,6 @@ TME_M68K_INSN(tme_m68k_cmp2_chk2) tme_uint32_t ireg; unsigned int size_bytes, size_name, size_ireg; tme_uint32_t uvalue, ulower, uupper; - tme_int32_t value, lower, upper; TME_M68K_INSN_CANFAULT; @@ -410,8 +550,17 @@ TME_M68K_INSN(tme_m68k_cmp2_chk2) 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_bytes = 1 << size_bytes; +#if TME_M68K_SIZE_8 != 1 +#error "TME_M68K_SIZE_8 must be 1" +#endif +#if TME_M68K_SIZE_16 != 2 +#error "TME_M68K_SIZE_16 must be 2" +#endif +#if TME_M68K_SIZE_32 != 4 +#error "TME_M68K_SIZE_32 must be 4" +#endif + size_name = size_bytes; /* read in the two bounds: */ (*_tme_m68k_read_mem[size_name])(ic, TME_M68K_IREG_MEMX32 << size_ireg); @@ -438,28 +587,19 @@ TME_M68K_INSN(tme_m68k_cmp2_chk2) /* get the values to check: */ switch (size_name) { case TME_M68K_SIZE_8: - uvalue = ic->tme_m68k_ireg_uint8(ireg); + uvalue = ic->tme_m68k_ireg_uint8(ireg << 2); 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); break; case TME_M68K_SIZE_16: - uvalue = ic->tme_m68k_ireg_uint16(ireg); + uvalue = ic->tme_m68k_ireg_uint16(ireg << 1); 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); 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); break; default: abort(); } @@ -472,14 +612,13 @@ TME_M68K_INSN(tme_m68k_cmp2_chk2) 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) : (uvalue < ulower || uvalue > uupper)) { ic->tme_m68k_ireg_ccr |= TME_M68K_FLAG_C; - if (TME_M68K_INSN_OPCODE & TME_BIT(11)) { + if (TME_M68K_INSN_SPECOP & TME_BIT(11)) { + 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_GROUP2(6)); + TME_M68K_INSN_EXCEPTION(TME_M68K_EXCEPTION_INST(TME_M68K_VECTOR_CHK)); } } @@ -502,8 +641,9 @@ TME_M68K_INSN(tme_m68k_rtm) TME_M68K_INSN(tme_m68k_trapcc) { if (TME_M68K_COND_TRUE(ic, TME_FIELD_EXTRACTU(TME_M68K_INSN_OPCODE, 8, 4))) { + 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_GROUP2(7)); + TME_M68K_INSN_EXCEPTION(TME_M68K_EXCEPTION_INST(TME_M68K_VECTOR_TRAP)); } TME_M68K_INSN_OK; } @@ -552,6 +692,7 @@ TME_M68K_INSN(tme_m68k_bfffo) tme_int32_t bf_offset; unsigned int bf_width; tme_uint32_t bf_value; + unsigned int bf_pos; /* get the bitfield offset from a data register or as an immediate: */ specop = TME_M68K_INSN_SPECOP; @@ -565,9 +706,14 @@ TME_M68K_INSN(tme_m68k_bfffo) /* get the bitfield value: */ bf_value = tme_m68k_bitfield_read_unsigned(ic); + /* find the first set bit: */ + for (bf_pos = 0, bf_value <<= (32 - bf_width); + bf_pos < bf_width && !(bf_value & 0x80000000); + bf_pos++, bf_value <<= 1); + /* set the result: */ ic->tme_m68k_ireg_uint32(TME_M68K_IREG_D0 + TME_FIELD_EXTRACTU(specop, 12, 3)) - = bf_offset + bf_width - ffs((int) bf_value); + = bf_offset + bf_pos; TME_M68K_INSN_OK; } @@ -697,6 +843,26 @@ TME_M68K_INSN(tme_m68k_unpk) TME_M68K_INSN_OK; } +/* these just redispatch into one of the multiply or divide insns: */ +TME_M68K_INSN(tme_m68k_mull) +{ + if (TME_M68K_INSN_SPECOP & TME_BIT(11)) { + tme_m68k_mulsl(ic, _op0, _op1); + } + else { + tme_m68k_mulul(ic, _op0, _op1); + } +} +TME_M68K_INSN(tme_m68k_divl) +{ + if (TME_M68K_INSN_SPECOP & TME_BIT(11)) { + tme_m68k_divsl(ic, _op0, _op1); + } + else { + tme_m68k_divul(ic, _op0, _op1); + } +} + #include "m68k-bus-auto.c" #include "m68k-insns-auto.c"