summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/cpu/ks0164/ks0164.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/devices/cpu/ks0164/ks0164.cpp')
-rw-r--r--src/devices/cpu/ks0164/ks0164.cpp771
1 files changed, 771 insertions, 0 deletions
diff --git a/src/devices/cpu/ks0164/ks0164.cpp b/src/devices/cpu/ks0164/ks0164.cpp
new file mode 100644
index 00000000000..1dce547896e
--- /dev/null
+++ b/src/devices/cpu/ks0164/ks0164.cpp
@@ -0,0 +1,771 @@
+// license:BSD-3-Clause
+// copyright-holders:Olivier Galibert, David Carne
+
+// KS0164 core
+
+#include "emu.h"
+#include "ks0164.h"
+#include "ks0164d.h"
+
+DEFINE_DEVICE_TYPE(KS0164CPU, ks0164_cpu_device, "ks0164cpu", "Samsung KS0164 audio processor")
+
+ks0164_cpu_device::ks0164_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : cpu_device(mconfig, KS0164CPU, tag, owner, clock)
+ , m_program_config("program", ENDIANNESS_BIG, 16, 16)
+{
+}
+
+void ks0164_cpu_device::device_start()
+{
+ space(AS_PROGRAM).cache(m_program_cache);
+ space(AS_PROGRAM).specific(m_program);
+
+ state_add(STATE_GENPC, "GENPC", m_r[R_PC]).callexport().noshow();
+ state_add(STATE_GENPCBASE, "CURPC", m_r[R_PC]).callexport().noshow();
+ state_add(STATE_GENFLAGS, "GENFLAGS", m_r[R_PSW]).callimport().formatstr("%8s").noshow();
+ state_add(KS0164_PC, "PC", m_r[R_PC]).callimport();
+ state_add(KS0164_PSW, "PSW", m_r[R_PSW]).callimport();
+
+ state_add(KS0164_SP, "SP", m_r[R_SP]);
+
+ state_add(KS0164_R0, "R0", m_r[0]);
+ state_add(KS0164_R1, "R1", m_r[1]);
+ state_add(KS0164_R2, "R2", m_r[2]);
+ state_add(KS0164_R3, "R3", m_r[3]);
+
+ save_item(NAME(m_r));
+
+ set_icountptr(m_icount);
+
+ m_irq = 0x10000;
+ memset(m_r, 0, sizeof(m_r));
+}
+
+void ks0164_cpu_device::device_reset()
+{
+ m_irq = 1;
+ memset(m_r, 0, sizeof(m_r));
+ m_r[R_PSW] = F_I;
+}
+
+uint32_t ks0164_cpu_device::execute_min_cycles() const noexcept
+{
+ return 1;
+}
+
+uint32_t ks0164_cpu_device::execute_max_cycles() const noexcept
+{
+ return 5;
+}
+
+void ks0164_cpu_device::execute_set_input(int inputnum, int state)
+{
+ if(state)
+ m_irq |= 1 << inputnum;
+ else
+ m_irq &= ~(1 << inputnum);
+}
+
+device_memory_interface::space_config_vector ks0164_cpu_device::memory_space_config() const
+{
+ return space_config_vector {
+ std::make_pair(AS_PROGRAM, &m_program_config)
+ };
+}
+
+std::unique_ptr<util::disasm_interface> ks0164_cpu_device::create_disassembler()
+{
+ return std::make_unique<ks0164_disassembler>();
+}
+
+void ks0164_cpu_device::state_string_export(const device_state_entry &entry, std::string &str) const
+{
+ switch(entry.index()) {
+ case STATE_GENFLAGS:
+ str = util::string_format("%c %c%c%c%c %x",
+ m_r[R_PSW] & F_I ? 'I' : '-',
+ m_r[R_PSW] & F_V ? 'V' : '-',
+ m_r[R_PSW] & F_C ? 'C' : '-',
+ m_r[R_PSW] & F_N ? 'N' : '-',
+ m_r[R_PSW] & F_Z ? 'Z' : '-',
+ m_r[R_PSW] & 0xf);
+ break;
+ }
+}
+
+void ks0164_cpu_device::handle_irq()
+{
+ u16 mask = m_irq & util::make_bitmask<u16>((m_r[R_PSW] & 15) + 1);
+ if(mask) {
+ int index;
+ for(index = 0; !(mask & (1 << index)); index ++);
+ if(index) {
+ // Normal irq (not reset), save pc and psw
+ if(m_r[R_PSW] & F_I)
+ return;
+ standard_irq_callback(0, m_r[R_PC]);
+ m_program.write_word(m_r[R_SP] - 2, m_r[R_PC]);
+ m_program.write_word(m_r[R_SP] - 4, m_r[R_PSW]);
+ m_r[R_SP] -= 4;
+ m_icount -= 2;
+ } else
+ m_irq &= 0xfffe;
+
+ m_r[R_PSW] = (m_r[R_PSW] & 0xfff0) | (index ? index - 1 : 0);
+ m_r[R_PC] = m_program_cache.read_word(index*2);
+ m_icount --;
+ }
+}
+
+u16 ks0164_cpu_device::snz(u16 r)
+{
+ u16 f = 0;
+ if(!r)
+ f |= F_Z;
+ if(r & 0x8000)
+ f |= F_N;
+ m_r[R_PSW] = (m_r[R_PSW] & ~F_MASK) | f;
+ return r;
+}
+
+void ks0164_cpu_device::do_alu(u16 opcode, u16 v2)
+{
+ int r = (opcode >> 8) & 7;
+ switch((opcode >> 11) & 7) {
+ case 0: { // add
+ u16 v1 = m_r[r];
+ u16 res = v1 + v2;
+ u16 f = 0;
+ if(!res)
+ f |= F_Z;
+ if(res & 0x8000)
+ f |= F_N;
+ if(((v1 & v2) | ((~res) & (v1 | v2))) & 0x8000)
+ f |= F_C;
+ if(((v1 ^ res) & (v2 ^ res)) & 0x8000)
+ f |= F_V;
+ m_r[r] = res;
+ m_r[R_PSW] = (m_r[R_PSW] & ~F_MASK) | f;
+ break;
+ }
+ case 1: { // sub
+ u16 v1 = m_r[r];
+ u16 res = v1 - v2;
+ u16 f = 0;
+ if(!res)
+ f |= F_Z;
+ if(res & 0x8000)
+ f |= F_N;
+ if(((v2 & res) | ((~v1) & (v2 | res))) & 0x8000)
+ f |= F_C;
+ if(((v1 ^ v2) & (v1 ^ res)) & 0x8000)
+ f |= F_V;
+ m_r[r] = res;
+ m_r[R_PSW] = (m_r[R_PSW] & ~F_MASK) | f;
+ break;
+ }
+ case 2: { // cmp
+ u16 v1 = m_r[r];
+ u16 res = v1 - v2;
+ u16 f = 0;
+ if(!res)
+ f |= F_Z;
+ if(res & 0x8000)
+ f |= F_N;
+ if(((v2 & res) | ((~v1) & (v2 | res))) & 0x8000)
+ f |= F_C;
+ if(((v1 ^ v2) & (v1 ^ res)) & 0x8000)
+ f |= F_V;
+ m_r[R_PSW] = (m_r[R_PSW] & ~F_MASK) | f;
+ break;
+ }
+ case 3: // and
+ m_r[r] = snz(m_r[r] & v2);
+ break;
+ case 4: // or
+ m_r[r] = snz(m_r[r] | v2);
+ break;
+ case 5: // xor
+ m_r[r] = snz(m_r[r] ^ v2);
+ break;
+ case 6: // set
+ m_r[r] = snz(v2);
+ break;
+ case 7: { // mul
+ u32 res;
+ if(opcode & 0x0080)
+ res = s16(m_r[r]) * s16(v2);
+ else
+ res = u16(m_r[r]) * u16(v2);
+
+ u16 f = 0;
+ if(!res)
+ f |= F_Z;
+ if(res & 0x8000)
+ f |= F_N;
+ if(res & 0xffff0000)
+ f |= F_C;
+ if(res >= 0x00008000 && res < 0xffff8000)
+ f |= F_V;
+ m_r[r] = res;
+ m_r[R_PSW] = (m_r[R_PSW] & ~F_MASK) | f;
+ break;
+ }
+ }
+}
+
+void ks0164_cpu_device::unk(u16 opcode)
+{
+ logerror("Unknown opcode %04x at address %04x\n", opcode, m_r[R_PC]-2);
+}
+
+void ks0164_cpu_device::execute_run()
+{
+ while(m_icount > 0) {
+ if(m_irq)
+ handle_irq();
+ debugger_instruction_hook(m_r[R_PC]);
+ u16 opcode = m_program_cache.read_word(m_r[R_PC]);
+ m_r[R_PC] += 2;
+
+ // First switch level on bits 15-14 and 2-0
+ switch(((opcode >> 11) & 0x18) | (opcode & 0x7)) {
+
+ case 0x00: case 0x01: case 0x02: case 0x03: case 0x04: case 0x05: case 0x06: case 0x07: {
+ // Conditional branches
+ // 00cc ccoo oooo oooo
+ bool cond;
+ switch((opcode >> 10) & 0xf) {
+ case 0x0: cond = !(m_r[R_PSW] & F_Z); break;
+ case 0x1: cond = m_r[R_PSW] & F_Z ; break;
+ case 0x2: cond = !(m_r[R_PSW] & F_C); break;
+ case 0x3: cond = m_r[R_PSW] & F_C ; break;
+ case 0x4: cond = !(m_r[R_PSW] & F_N); break;
+ case 0x5: cond = m_r[R_PSW] & F_N ; break;
+ case 0x6: cond = !(m_r[R_PSW] & F_V); break;
+ case 0x7: cond = m_r[R_PSW] & F_V ; break;
+ case 0x8: cond = false; break;
+ case 0x9: cond = !(m_r[R_PSW] & F_Z) && !(m_r[R_PSW] & F_C); break;
+ case 0xa: cond = (m_r[R_PSW] & F_Z) || (m_r[R_PSW] & F_C); break;
+ case 0xb: cond = (!(m_r[R_PSW] & F_Z) && (m_r[R_PSW] & F_N) && (m_r[R_PSW] & F_V)) || (!(m_r[R_PSW] & F_Z) && !(m_r[R_PSW] & F_V) && !(m_r[R_PSW] & F_N)); break;
+ case 0xc: cond = ((m_r[R_PSW] & F_N) && (m_r[R_PSW] & F_V)) || (!(m_r[R_PSW] & F_V) && !(m_r[R_PSW] & F_N)); break;
+ case 0xd: cond = (m_r[R_PSW] & F_Z) || ((m_r[R_PSW] & F_N) && !(m_r[R_PSW] & F_V)) || ((m_r[R_PSW] & F_V) && !(m_r[R_PSW] & F_N)); break;
+ case 0xe: cond = ((m_r[R_PSW] & F_N) && !(m_r[R_PSW] & F_V)) || ((m_r[R_PSW] & F_V) && !(m_r[R_PSW] & F_N)); break;
+ case 0xf: default: cond = true; break;
+ }
+ if(cond) {
+ m_r[R_PC] += util::sext(opcode, 10);
+ }
+ break;
+ }
+
+ case 0x08: case 0x09: case 0x0a: case 0x0b: case 0x0c: case 0x0d: case 0x0e: case 0x0f: {
+ // ALU functions with 8-bit immediate
+ // 01ff frrr iiii iiii
+
+ do_alu(opcode, s8(opcode));
+ break;
+ }
+
+ case 0x14: {
+ // ALU functions with other register
+ // 10ff frrr Ssss w100
+ u16 rv = m_r[(opcode >> 4) & 7];
+ u16 v = opcode & 0x0008 ? rv : opcode & 0x0080 ? s8(rv) : u8(rv);
+
+ do_alu(opcode, v);
+ break;
+ }
+
+ case 0x15: {
+ // ALU functions with immediate
+ // 10ff frrr S... w101
+ u16 rv = m_program_cache.read_word(m_r[R_PC]);
+ m_r[R_PC] += 2;
+ u16 v = opcode & 0x0008 ? rv : opcode & 0x0080 ? s8(rv) : u8(rv);
+
+ do_alu(opcode, v);
+ break;
+ }
+
+ case 0x16: {
+ // ALU functions from memory indexed
+ // 10ff frrr Ssss w110
+ u16 a = m_r[(opcode >> 4) & 7];
+ u16 v = opcode & 0x0008 ? m_program.read_word(a) : opcode & 0x0080 ? s8(m_program.read_byte(a)) : u8(m_program.read_byte(a));
+ m_icount -= 2;
+
+ do_alu(opcode, v);
+ break;
+ }
+
+ case 0x17: {
+ // ALU functions from memory indexed and offset
+ // 10ff frrr Ssss w111
+ u16 a = m_r[(opcode >> 4) & 7] + m_program_cache.read_word(m_r[R_PC]);
+ m_r[R_PC] += 2;
+ u16 v = opcode & 0x0008 ? m_program.read_word(a) : opcode & 0x0080 ? s8(m_program.read_byte(a)) : u8(m_program.read_byte(a));
+ m_icount -= 2;
+
+ do_alu(opcode, v);
+ break;
+ }
+
+ case 0x18: {
+ switch((opcode >> 12) & 3) {
+ case 0: {
+ // Data move with pre/post incrementation
+ // 1100 arrr bsss c000
+
+ int r1 = (opcode >> 8) & 7;
+ int r2 = (opcode >> 4) & 7;
+ switch(bitswap<3>(opcode, 11, 7, 3)) {
+ case 1: m_program.write_word(m_r[r1], m_r[r2]); m_r[r1] += 2; break;
+ case 4: m_r[r1] -= 2; m_program.write_word(m_r[r1], m_r[r2]); break;
+ default: unk(opcode); break;
+ }
+ m_icount --;
+ break;
+ }
+
+ case 1: {
+ // Min/max with immediate
+ // 1101 Mrrr S000 1000
+ u16 v1 = m_r[(opcode >> 8) & 7];
+ u16 v2 = m_program_cache.read_word(m_r[R_PC]);
+ m_r[R_PC] += 2;
+ u16 res;
+ switch(bitswap<2>(opcode, 11, 7)) {
+ case 0: res = std::max<u16>(v1, v2); break;
+ case 1: res = std::max<s16>(v1, v2); break;
+ case 2: res = std::min<u16>(v1, v2); break;
+ case 3: default: res = std::min<s16>(v1, v2); break;
+ }
+ m_r[(opcode >> 8) & 7] = res;
+ break;
+ }
+
+ case 2: {
+ // Bit test in register
+ // 1110 .rrr bbbb .000
+ if(m_r[(opcode >> 8) & 7] & (1 << ((opcode >> 4) & 0xf)))
+ m_r[R_PSW] &= ~F_Z;
+ else
+ m_r[R_PSW] |= F_Z;
+ break;
+ }
+
+ case 3: {
+ unk(opcode);
+ break;
+ }
+ }
+ break;
+ }
+
+ case 0x19: {
+ switch((opcode >> 12) & 3) {
+ case 0: {
+ // Push all registers
+ // 1100 .... .... .001
+
+ m_program.write_word(m_r[R_SP] - 2, m_r[0]);
+ m_program.write_word(m_r[R_SP] - 4, m_r[1]);
+ m_program.write_word(m_r[R_SP] - 6, m_r[2]);
+ m_program.write_word(m_r[R_SP] - 8, m_r[3]);
+ m_r[R_SP] -= 8;
+ break;
+ }
+
+ case 1: {
+ // Absolute jump
+ // 1101 .... .... .001
+ m_r[R_PC] = m_program.read_word(m_r[R_PC]);
+ break;
+ }
+
+ case 2: {
+ // Bit set in register
+ // 1110 .rrr bbbb .001
+ if(m_r[(opcode >> 8) & 7] & (1 << ((opcode >> 4) & 0xf)))
+ m_r[R_PSW] &= ~F_Z;
+ else {
+ m_r[R_PSW] |= F_Z;
+ m_r[(opcode >> 8) & 7] |= 1 << ((opcode >> 4) & 0xf);
+ }
+ break;
+ }
+
+ case 3: {
+ unk(opcode);
+ break;
+ }
+ }
+ break;
+ }
+
+ case 0x1a: {
+ switch((opcode >> 12) & 3) {
+ case 0: {
+ // Data move with pre/post incrementation
+ // 1100 arrr bsss c010
+
+ int r1 = (opcode >> 8) & 7;
+ int r2 = (opcode >> 4) & 7;
+ switch(bitswap<3>(opcode, 11, 7, 3)) {
+ case 1: m_r[r1] = m_program.read_word(m_r[r2]); m_r[r2] += 2; break;
+ default: unk(opcode); break;
+ }
+ m_icount --;
+ break;
+ }
+
+ case 1: {
+ // Absolute subroutine call
+ // 1101 .... .... .010
+
+ u16 a = m_program.read_word(m_r[R_PC]);
+ m_program.write_word(m_r[R_SP] - 2, m_r[R_PC] + 2);
+ m_r[R_SP] -= 2;
+ m_r[R_PC] = a;
+ m_icount -= 2;
+ break;
+ }
+
+ case 2: {
+ // Bit test from memory indexed
+ // 1110 .rrr bbbb w010
+
+ u16 a = m_r[(opcode >> 8) & 7];
+ u16 v = opcode & 0x0008 ? m_program.read_word(a) : m_program.read_byte(a);
+ if(v & (1 << ((opcode >> 4) & 0xf)))
+ m_r[R_PSW] &= ~F_Z;
+ else
+ m_r[R_PSW] |= F_Z;
+ m_icount -= 2;
+ break;
+ }
+
+ case 3: {
+ unk(opcode);
+ break;
+ }
+ }
+ break;
+ }
+
+ case 0x1b: {
+ switch((opcode >> 12) & 3) {
+ case 0: {
+ // Pop all registers
+ // 1100 .... .... .011
+
+ m_r[0] = m_program.read_word(m_r[R_SP] + 6);
+ m_r[1] = m_program.read_word(m_r[R_SP] + 4);
+ m_r[2] = m_program.read_word(m_r[R_SP] + 2);
+ m_r[3] = m_program.read_word(m_r[R_SP] + 0);
+ m_r[R_SP] += 8;
+ break;
+ }
+
+ case 1: {
+ // Return from subroutine
+ // 1101 .... .... .011
+
+ m_r[R_PC] = m_program.read_word(m_r[R_SP]);
+ m_r[R_SP] += 2;
+ m_icount --;
+ break;
+ }
+
+ case 2: {
+ // Bit test from memory indexed and offset
+ // 1110 .rrr bbbb w011
+
+ u16 a = m_r[(opcode >> 8) & 7] + m_program_cache.read_word(m_r[R_PC]);
+ m_r[R_PC] += 2;
+ u16 v = opcode & 0x0008 ? m_program.read_word(a) : m_program.read_byte(a);
+ if(v & (1 << ((opcode >> 4) & 0xf)))
+ m_r[R_PSW] &= ~F_Z;
+ else
+ m_r[R_PSW] |= F_Z;
+ m_icount -= 2;
+ break;
+ }
+
+ case 3: {
+ unk(opcode);
+ break;
+ }
+ }
+ break;
+ }
+
+ case 0x1c: {
+ switch((opcode >> 12) & 3) {
+ case 0: {
+ // Unsigned shifts
+ // 1100 drrr nnnn .100
+
+ int r = (opcode >> 8) & 7;
+ int shift = (opcode >> 4) & 0xf;
+ u16 v1 = m_r[r];
+ u16 res;
+
+ if(!shift) {
+ m_r[R_PSW] = (m_r[R_PSW] & ~F_MASK) | (v1 ? v1 & 0x8000 ? F_N : 0 : F_Z);
+ res = v1;
+ } else if(opcode & 0x0800) {
+ res = v1 >> shift;
+ u16 f = res ? 0 : F_Z;
+ if(v1 & (1 << (shift - 1)))
+ f |= F_C;
+ m_r[R_PSW] = (m_r[R_PSW] & ~F_MASK) | f;
+ } else {
+ res = v1 << shift;
+ u16 f = res ? res & 0x8000 ? F_N : 0 : F_Z;
+ if(v1 & (1 << (16-shift)))
+ f |= F_C;
+ m_r[R_PSW] = (m_r[R_PSW] & ~F_MASK) | f;
+ }
+ m_r[r] = res;
+ break;
+ }
+
+ case 1: {
+ // Return from interrupt
+ // 1101 .... .... .100
+
+ m_r[R_PSW] = m_program.read_word(m_r[R_SP] + 0);
+ m_r[R_PC] = m_program.read_word(m_r[R_SP] + 2);
+ m_r[R_SP] += 4;
+ m_icount -= 2;
+ break;
+ }
+
+ case 2: {
+ // Bit clear in register
+ // 1110 .rrr bbbb .100
+ if(m_r[(opcode >> 8) & 7] & (1 << ((opcode >> 4) & 0xf))) {
+ m_r[(opcode >> 8) & 7] &= ~(1 << ((opcode >> 4) & 0xf));
+ m_r[R_PSW] &= ~F_Z;
+ } else
+ m_r[R_PSW] |= F_Z;
+ break;
+ }
+
+ case 3: {
+ // Decrement and branch
+ // 1111 .rrr .... .100
+ int r = (opcode >> 8) & 7;
+ u16 a = m_program_cache.read_word(m_r[R_PC]);
+ m_r[R_PC] += 2;
+
+ m_r[r] --;
+ if(m_r[r] != 0)
+ m_r[R_PC] = a;
+ break;
+ }
+ }
+ break;
+ }
+
+ case 0x1d: {
+ switch((opcode >> 12) & 3) {
+ case 0: {
+ // Signed shifts
+ // 1100 drrr nnnn .101
+
+ int r = (opcode >> 8) & 7;
+ int shift = (opcode >> 4) & 0xf;
+ u16 v1 = m_r[r];
+ u16 res;
+
+ if(!shift) {
+ m_r[R_PSW] = (m_r[R_PSW] & ~F_MASK) | (v1 ? v1 & 0x8000 ? F_N : 0 : F_Z);
+ res = v1;
+ } else if(opcode & 0x0800) {
+ res = s16(v1) >> shift;
+ u16 f = res ? res & 0x8000 ? F_N : 0 : F_Z;
+ if(v1 & (1 << (shift - 1)))
+ f |= F_C;
+ m_r[R_PSW] = (m_r[R_PSW] & ~F_MASK) | f;
+ } else {
+ res = v1 << shift;
+ u16 f = res ? res & 0x8000 ? F_N : 0 : F_Z;
+ if(v1 & (1 << (16-shift)))
+ f |= F_C;
+ m_r[R_PSW] = (m_r[R_PSW] & ~F_MASK) | f;
+ }
+ m_r[r] = res;
+ break;
+ }
+
+ case 1: {
+ // Neg/not
+ // 1101 .rrr S... .101
+
+ u16 v = m_r[(opcode >> 8) & 7];
+ if(opcode & 0x0080)
+ v = -s16(v);
+ else
+ v = ~v;
+ m_r[(opcode >> 8) & 7] = v;
+ m_r[R_PSW] = (m_r[R_PSW] & ~F_MASK) | (v ? v & 0x8000 ? F_N : 0 : F_Z);
+ break;
+ }
+
+ case 2: {
+ unk(opcode);
+ break;
+ }
+
+ case 3: {
+ // Compare with immediate and branch if equal
+ // 1111 .rrr .... .101
+
+ u16 v = m_program_cache.read_word(m_r[R_PC]);
+ u16 a = m_program_cache.read_word(m_r[R_PC] + 2);
+ m_r[R_PC] += 4;
+
+ do_alu((opcode & 0x07ff) | 0x1000, v);
+ if(m_r[R_PSW] & F_Z)
+ m_r[R_PC] = a;
+ break;
+ }
+ }
+ break;
+ }
+
+ case 0x1e: {
+ switch((opcode >> 12) & 3) {
+ case 0: {
+ // Rotate without carry?
+ // 1100 drrr nnnn .110
+ /*
+ From btplay2k flash.u22:
+ Surrounding code gives some context to usage here? + opcode is sandwiched between other shift/rotate commands
+ 6E2C: 7010 r0 = 10
+ 6E2E: 8817 0001 r0 -= (r1 + 1).bu
+ 6E32: 0406 beq 6e3a
+ 6E34: CA1C r2 >>= 1
+ 6E36: F004 6E34 dbra r0, 6e34
+ ...
+ 6E52: B017 0001 r0 = (r1 + 1).bu
+ 6E56: CA1E ?ca1e
+ 6E58: F004 6E56 dbra r0, 6e56
+ */
+
+ int r = (opcode >> 8) & 7;
+ int shift = (opcode >> 4) & 0xf;
+ u16 v1 = m_r[r];
+ u16 res;
+
+ if(!shift) {
+ m_r[R_PSW] = (m_r[R_PSW] & ~F_MASK) | (v1 ? v1 & 0x8000 ? F_N : 0 : F_Z);
+ res = v1;
+ } else if(opcode & 0x0800) {
+ res = (v1 >> shift) | (v1 << (16 - shift));
+ u16 f = res ? 0 : F_Z;
+ if(v1 & (1 << (shift - 1)))
+ f |= F_C;
+ m_r[R_PSW] = (m_r[R_PSW] & ~F_MASK) | f;
+ } else {
+ res = (v1 << shift) | (v1 >> (16 - shift));
+ u16 f = res ? res & 0x8000 ? F_N : 0 : F_Z;
+ if(v1 & (1 << (16-shift)))
+ f |= F_C;
+ m_r[R_PSW] = (m_r[R_PSW] & ~F_MASK) | f;
+ }
+ m_r[r] = res;
+ break;
+ }
+
+ case 1: {
+ unk(opcode);
+ break;
+ }
+
+ case 2: {
+ // Write memory indexed
+ // 1110 .rrr .sss w110
+ u16 a = m_r[(opcode >> 8) & 7];
+ if(opcode & 0x0008)
+ m_program.write_word(a, m_r[(opcode >> 4) & 7]);
+ else
+ m_program.write_byte(a, m_r[(opcode >> 4) & 7]);
+ break;
+ }
+
+ case 3: {
+ unk(opcode);
+ break;
+ }
+ }
+ break;
+ }
+
+ case 0x1f: {
+ switch((opcode >> 12) & 3) {
+ case 0: {
+ // Rotate through carry
+ // 1100 drrr nnnn .111
+
+ int r = (opcode >> 8) & 7;
+ int shift = (opcode >> 4) & 0xf;
+ u32 v1 = m_r[r] | (m_r[R_PSW] & F_C ? 0x10000 : 0);
+ u16 res;
+
+ if(!shift) {
+ m_r[R_PSW] = (m_r[R_PSW] & ~(F_N|F_Z|F_V)) | (v1 & 0xffff ? v1 & 0x8000 ? F_N : 0 : F_Z);
+ res = v1;
+ } else if(opcode & 0x0800) {
+ res = (v1 >> shift) | (v1 << (17-shift));
+ u16 f = res ? res & 0x8000 ? F_N : 0 : F_Z;
+ if(v1 & (1 << (shift - 1)))
+ f |= F_C;
+ m_r[R_PSW] = (m_r[R_PSW] & ~F_MASK) | f;
+ } else {
+ res = (v1 << shift) | (v1 >> (17-shift));
+ u16 f = res ? res & 0x8000 ? F_N : 0 : F_Z;
+ if(v1 & (1 << (16-shift)))
+ f |= F_C;
+ m_r[R_PSW] = (m_r[R_PSW] & ~F_MASK) | f;
+ }
+ m_r[r] = res;
+ break;
+ }
+
+ case 1: {
+ unk(opcode);
+ break;
+ }
+
+ case 2: {
+ // Write memory indexed and offset
+ // 1110 .rrr .sss w111
+ u16 a = m_r[(opcode >> 8) & 7] + m_program_cache.read_word(m_r[R_PC]);
+ m_r[R_PC] += 2;
+ if(opcode & 0x0008)
+ m_program.write_word(a, m_r[(opcode >> 4) & 7]);
+ else
+ m_program.write_byte(a, m_r[(opcode >> 4) & 7]);
+ break;
+ }
+
+ case 3: {
+ unk(opcode);
+ break;
+ }
+ }
+ break;
+ }
+
+ default:
+ unk(opcode);
+ break;
+ }
+
+ m_r[R_ZERO] = 0;
+ }
+}