--- tme/ic/m68k/m68k-insns.c 2018/04/24 16:39:00 1.1.1.2 +++ tme/ic/m68k/m68k-insns.c 2018/04/24 16:41:53 1.1.1.4 @@ -1,4 +1,4 @@ -/* $Id: m68k-insns.c,v 1.1.1.2 2018/04/24 16:39:00 root Exp $ */ +/* $Id: m68k-insns.c,v 1.1.1.4 2018/04/24 16:41:53 root Exp $ */ /* ic/m68k/m68k-insns.c - m68k instruction functions: */ @@ -36,7 +36,7 @@ /* includes: */ #include "m68k-impl.h" -_TME_RCSID("$Id: m68k-insns.c,v 1.1.1.2 2018/04/24 16:39:00 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 { \ @@ -159,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); @@ -176,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) @@ -195,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; @@ -233,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; } @@ -277,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; } @@ -315,18 +376,27 @@ 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; 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) & mask; @@ -351,12 +421,14 @@ TME_M68K_INSN(tme_m68k_reset) /* 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 - | TME_BUS_SIGNAL_EDGE)); + | TME_BUS_SIGNAL_LEVEL_ASSERTED)); assert (rc == TME_OK); /* XXX RESET is supposed to be asserted for 512 clocks, @@ -366,9 +438,11 @@ TME_M68K_INSN(tme_m68k_reset) rc = (*conn_bus->tme_bus_signal) (conn_bus, (TME_BUS_SIGNAL_RESET - | TME_BUS_SIGNAL_LEVEL_NEGATED - | TME_BUS_SIGNAL_EDGE)); + | TME_BUS_SIGNAL_LEVEL_NEGATED)); assert (rc == TME_OK); + + /* relock after the callout: */ + tme_m68k_callout_relock(ic); TME_M68K_INSN_OK; } @@ -409,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; } @@ -418,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; } @@ -452,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: */ @@ -461,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; @@ -469,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); @@ -497,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(); } @@ -531,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)); } } @@ -561,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; } @@ -611,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; @@ -624,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; } @@ -756,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"