diff --git a/cpu.cpp b/cpu.cpp index c1ce5f3..0fa80a4 100644 --- a/cpu.cpp +++ b/cpu.cpp @@ -1,4 +1,4 @@ -// (C) 2018-2024 by Folkert van Heusden +// (C) 2018-2025 by Folkert van Heusden // Released under MIT license #include @@ -741,6 +741,59 @@ bool cpu::double_operand_instructions(const uint16_t instr) return false; } +uint32_t cpu::shifter(uint32_t value, int shift, bool is32b) +{ + uint64_t sign_extend = is32b ? B64_MSWSET : (B64_MSWSET | B32_MSWSET); + uint32_t sign_mask = is32b ? B32_MSBSET : B16_MSBSET; + uint32_t mask = is32b ? 0xffffffff : 0xffff; + bool sign = value & sign_mask; + + TRACE("shift %012o with %d", value, shift); + + setPSW_v(false); + + if (shift == 0) + setPSW_c(false); + else if (shift < 32) { + setPSW_c((value << (shift - 1)) & sign_mask); + + for(int i=0; i> shift_n; + setPSW_c(value & 1); + value = (uint64_t(value) | sign_extend) >> 1; + } + else { + value >>= shift_n; + setPSW_c(value & 1); + value >>= 1; + } + + bool new_sign = value & sign_mask; + setPSW_v(sign != new_sign); + } + + value &= mask; + setPSW_n(value & sign_mask); + setPSW_z(value == 0); + + return value; +} + bool cpu::additional_double_operand_instructions(const uint16_t instr) { const uint8_t reg = (instr >> 6) & 7; @@ -817,114 +870,28 @@ bool cpu::additional_double_operand_instructions(const uint16_t instr) } case 2: { // ASH - uint32_t R = get_register(reg), oldR = R; - - auto g_dst = getGAM(dst_mode, dst_reg, wm_word); + uint32_t R = get_register(reg); + auto g_dst = getGAM(dst_mode, dst_reg, wm_word); addToMMR1(g_dst); - uint16_t shift = g_dst.value.value() & 077; + int shift = g_dst.value.value() & 077; - TRACE("shift %06o with %d", R, shift); + uint32_t new_value = shifter(R, shift, false); - bool sign = SIGN(R, wm_word); - - if (shift == 0) { - setPSW_c(false); - setPSW_v(false); - } - else if (shift < 32) { - if (shift > 15) - setPSW_c((R << (shift - 16)) & 1); - setPSW_v(false); - for(int i=0; i>= 1; - R |= sign_extend; - } - } - - setPSW_n(SIGN(R, wm_word)); - setPSW_z((R & 0xffff) == 0); - - set_register(reg, R); + set_register(reg, new_value); return true; } case 3: { // ASHC - uint32_t R0R1 = (uint32_t(get_register(reg)) << 16) | get_register(reg | 1); - bool sign = R0R1 & B32_MSBSET; - - auto g_dst = getGAM(dst_mode, dst_reg, wm_word); + uint32_t R0R1 = (uint32_t(get_register(reg)) << 16) | get_register(reg | 1); + auto g_dst = getGAM(dst_mode, dst_reg, wm_word); addToMMR1(g_dst); - uint16_t shift = g_dst.value.value() & 077; + int shift = g_dst.value.value() & 077; - TRACE("shift %012o (base-reg: R%d) with %d", R0R1, reg, shift); + uint32_t new_value = shifter(R0R1, shift, true); - setPSW_v(false); - - if (shift == 0) - setPSW_c(false); - else if (shift < 32) { - setPSW_c((R0R1 << (shift - 1)) & B32_MSBSET); - - setPSW_v(false); - for(int i=0; i> shift_n; - setPSW_c(R0R1 & 1); - R0R1 = (uint64_t(R0R1) | B64_MSWSET) >> 1; - } - else { - R0R1 >>= shift_n; - - setPSW_c(R0R1 & 1); - - R0R1 >>= 1; - } - - bool new_sign = R0R1 & B32_MSBSET; - setPSW_v(sign != new_sign); - } - - set_register(reg, R0R1 >> 16 ); - set_register(reg | 1, R0R1 & 65535); - - setPSW_n(R0R1 & B32_MSBSET); - setPSW_z(R0R1 == 0); + set_register(reg, new_value >> 16 ); + set_register(reg | 1, new_value & 65535); return true; } diff --git a/cpu.h b/cpu.h index 32dab40..b09f4ef 100644 --- a/cpu.h +++ b/cpu.h @@ -21,7 +21,9 @@ class bus; constexpr const int initial_trap_delay = 8; constexpr const int max_stacktrace_depth = 16; +constexpr const uint16_t B16_MSBSET = 0x8000; constexpr const uint32_t B32_MSBSET = 0x80000000; +constexpr const uint32_t B32_MSWSET = 0xffff0000; constexpr const uint64_t B64_MSWSET = 0xffffffff00000000ll; typedef struct { @@ -84,6 +86,8 @@ private: bool check_pending_interrupts() const; // needs the 'qi_lock'-lock bool execute_any_pending_interrupt(); + uint32_t shifter(uint32_t value, int shift, bool is32b); + uint16_t add_register(const int nr, const uint16_t value); void addToMMR1(const gam_rc_t & g);