diff options
Diffstat (limited to 'src/devices/cpu/unsp/unsp.cpp')
-rw-r--r-- | src/devices/cpu/unsp/unsp.cpp | 1086 |
1 files changed, 539 insertions, 547 deletions
diff --git a/src/devices/cpu/unsp/unsp.cpp b/src/devices/cpu/unsp/unsp.cpp index c8a4025f5cd..8d141637ecc 100644 --- a/src/devices/cpu/unsp/unsp.cpp +++ b/src/devices/cpu/unsp/unsp.cpp @@ -20,7 +20,16 @@ DEFINE_DEVICE_TYPE(UNSP, unsp_device, "unsp", "SunPlus u'nSP") unsp_device::unsp_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : cpu_device(mconfig, UNSP, tag, owner, clock) , m_program_config("program", ENDIANNESS_BIG, 16, 23, -1) - , m_irq(0), m_fiq(0), m_curirq(0), m_sirq(0), m_sb(0), m_saved_sb(0), m_program(nullptr), m_icount(0), m_debugger_temp(0) + , m_enable_irq(false) + , m_enable_fiq(false) + , m_irq(false) + , m_fiq(false) + , m_curirq(0) + , m_sirq(0) + , m_sb(0) + , m_program(nullptr) + , m_icount(0) + , m_debugger_temp(0) { } @@ -57,54 +66,6 @@ std::unique_ptr<util::disasm_interface> unsp_device::create_disassembler() #define UNSP_S 0x0080 #define UNSP_C 0x0040 -#define STANDARD_ALU_CASES \ - case 0: \ - lres = r0 + r1; \ - unsp_update_nzsc(lres, r0, r1); \ - break; \ - case 1: \ - lres = r0 + r1; \ - if(UNSP_REG(SR) & UNSP_C) lres++; \ - unsp_update_nzsc(lres, r0, r1); \ - break; \ - case 3: \ - lres = r0 + (~r1 & 0x0000ffff); \ - if(UNSP_REG(SR) & UNSP_C) lres++; \ - unsp_update_nzsc(lres, r0, r1); \ - break; \ - case 2: \ - case 4: \ - lres = r0 + (~r1 & 0x0000ffff) + 1; \ - unsp_update_nzsc(lres, r0, r1); \ - break; \ - case 6: \ - lres = -r1; \ - unsp_update_nz(lres); \ - break; \ - case 8: \ - lres = r0 ^ r1; \ - unsp_update_nz(lres); \ - break; \ - case 9: \ - lres = r1; \ - unsp_update_nz(lres); \ - break; \ - case 10: \ - lres = r0 | r1; \ - unsp_update_nz(lres); \ - break; \ - case 11: \ - case 12: \ - lres = r0 & r1; \ - unsp_update_nz(lres); \ - break - -#define WRITEBACK_OPA \ - if(OP0 != 4 && OP0 < 12) \ - { \ - UNSP_REG_I(OPA) = (uint16_t)lres; \ - } - /*****************************************************************************/ void unsp_device::unimplemented_opcode(uint16_t op) @@ -114,12 +75,12 @@ void unsp_device::unimplemented_opcode(uint16_t op) /*****************************************************************************/ -uint16_t unsp_device::READ16(uint32_t address) +uint16_t unsp_device::read16(uint32_t address) { return m_program->read_word(address); } -void unsp_device::WRITE16(uint32_t address, uint16_t data) +void unsp_device::write16(uint32_t address, uint16_t data) { m_program->write_word(address, data); } @@ -129,27 +90,31 @@ void unsp_device::WRITE16(uint32_t address, uint16_t data) void unsp_device::device_start() { memset(m_r, 0, sizeof(uint16_t) * 16); - m_irq = 0; - m_fiq = 0; + m_enable_irq = false; + m_enable_fiq = false; + m_irq = false; + m_fiq = false; m_curirq = 0; m_sirq = 0; m_sb = 0; - m_saved_sb = 0; + memset(m_saved_sb, 0, sizeof(uint8_t) * 3); m_debugger_temp = 0; m_program = &space(AS_PROGRAM); - state_add( UNSP_SP, "SP", UNSP_REG(SP)).formatstr("%04X"); - state_add( UNSP_R1, "R1", UNSP_REG(R1)).formatstr("%04X"); - state_add( UNSP_R2, "R2", UNSP_REG(R2)).formatstr("%04X"); - state_add( UNSP_R3, "R3", UNSP_REG(R3)).formatstr("%04X"); - state_add( UNSP_R4, "R4", UNSP_REG(R4)).formatstr("%04X"); - state_add( UNSP_BP, "BP", UNSP_REG(BP)).formatstr("%04X"); - state_add( UNSP_SR, "SR", UNSP_REG(SR)).formatstr("%04X"); - state_add( UNSP_PC, "PC", m_debugger_temp).callimport().callexport().formatstr("%06X"); - state_add( UNSP_IRQ, "IRQ", m_irq).formatstr("%1u"); - state_add( UNSP_FIQ, "FIQ", m_fiq).formatstr("%1u"); - state_add( UNSP_SB, "SB", m_sb).formatstr("%1u"); + state_add( UNSP_SP, "SP", UNSP_REG(SP)).formatstr("%04X"); + state_add( UNSP_R1, "R1", UNSP_REG(R1)).formatstr("%04X"); + state_add( UNSP_R2, "R2", UNSP_REG(R2)).formatstr("%04X"); + state_add( UNSP_R3, "R3", UNSP_REG(R3)).formatstr("%04X"); + state_add( UNSP_R4, "R4", UNSP_REG(R4)).formatstr("%04X"); + state_add( UNSP_BP, "BP", UNSP_REG(BP)).formatstr("%04X"); + state_add( UNSP_SR, "SR", UNSP_REG(SR)).formatstr("%04X"); + state_add( UNSP_PC, "PC", m_debugger_temp).callimport().callexport().formatstr("%06X"); + state_add( UNSP_IRQ_EN, "IRQE", m_enable_irq).formatstr("%1u"); + state_add( UNSP_FIQ_EN, "FIQE", m_enable_fiq).formatstr("%1u"); + state_add( UNSP_IRQ, "IRQ", m_irq).formatstr("%1u"); + state_add( UNSP_FIQ, "FIQ", m_fiq).formatstr("%1u"); + state_add( UNSP_SB, "SB", m_sb).formatstr("%1u"); state_add(STATE_GENPC, "GENPC", m_debugger_temp).callexport().noshow(); state_add(STATE_GENPCBASE, "CURPC", m_debugger_temp).callexport().noshow(); @@ -184,14 +149,16 @@ void unsp_device::device_reset() { memset(m_r, 0, sizeof(uint16_t) * 16); - UNSP_REG(PC) = READ16(0xfff7); - m_irq = 0; - m_fiq = 0; + UNSP_REG(PC) = read16(0xfff7); + m_enable_irq = false; + m_enable_fiq = false; + m_irq = false; + m_fiq = false; } /*****************************************************************************/ -void unsp_device::unsp_update_nz(uint32_t value) +void unsp_device::update_nz(uint32_t value) { UNSP_REG(SR) &= ~(UNSP_N | UNSP_Z); if(value & 0x8000) @@ -204,10 +171,9 @@ void unsp_device::unsp_update_nz(uint32_t value) } } -void unsp_device::unsp_update_nzsc(uint32_t value, uint16_t r0, uint16_t r1) +void unsp_device::update_sc(uint32_t value, uint16_t r0, uint16_t r1) { UNSP_REG(SR) &= ~(UNSP_C | UNSP_S); - unsp_update_nz(value); if(value != (uint16_t)value) { UNSP_REG(SR) |= UNSP_C; @@ -219,30 +185,91 @@ void unsp_device::unsp_update_nzsc(uint32_t value, uint16_t r0, uint16_t r1) } } -void unsp_device::unsp_push(uint16_t value, uint16_t *reg) +void unsp_device::push(uint16_t value, uint16_t *reg) +{ + write16((*reg)--, value); +} + +uint16_t unsp_device::pop(uint16_t *reg) { - WRITE16((*reg)--, value); + return read16(++(*reg)); +} + +void unsp_device::trigger_fiq() +{ + if (!m_enable_fiq || m_fiq) + return; + + m_fiq = true; + + m_saved_sb[m_irq ? 1 : 0] = m_sb; + m_sb = m_saved_sb[2]; + + push(UNSP_REG(PC), &UNSP_REG(SP)); + push(UNSP_REG(SR), &UNSP_REG(SP)); + UNSP_REG(PC) = read16(0xfff6); + UNSP_REG(SR) = 0; +} + +void unsp_device::trigger_irq(int line) +{ + if (!m_enable_irq || m_irq) + return; + + m_irq = true; + + m_saved_sb[0] = m_sb; + m_sb = m_saved_sb[1]; + + push(UNSP_REG(PC), &UNSP_REG(SP)); + push(UNSP_REG(SR), &UNSP_REG(SP)); + UNSP_REG(PC) = read16(0xfff8 + line); + UNSP_REG(SR) = 0; } -uint16_t unsp_device::unsp_pop(uint16_t *reg) +void unsp_device::check_irqs() { - return READ16(++(*reg)); + int highest_irq = -1; + for (int i = 0; i <= 8; i++) + { + if (BIT(m_sirq, i)) + { + highest_irq = i; + break; + } + } + + if (highest_irq < 0) + return; + + if (highest_irq == UNSP_FIQ_LINE) + { + trigger_fiq(); + } + else + { + trigger_irq(highest_irq); + } } void unsp_device::execute_run() { - uint32_t op; - uint32_t lres; - uint16_t r0, r1; - lres = 0; + uint32_t lres = 0; + uint16_t r0 = 0; + uint16_t r1 = 0; + uint32_t r2 = 0; while (m_icount > 0) { + check_irqs(); + debugger_instruction_hook(UNSP_LPC); - op = READ16(UNSP_LPC); + const uint32_t op = read16(UNSP_LPC); UNSP_REG(PC)++; + const uint8_t lower_op = (OP1 << 4) | OP0; + if(OP0 < 0xf && OPA == 0x7 && OP1 < 2) { switch(OP0) @@ -250,560 +277,557 @@ void unsp_device::execute_run() case 0: // JB if(!(UNSP_REG(SR) & UNSP_C)) { + m_icount -= 4; UNSP_REG(PC) += (OP1 == 0) ? OPIMM : (0 - OPIMM); } - break; + else + m_icount -= 2; + continue; case 1: // JAE if(UNSP_REG(SR) & UNSP_C) { + m_icount -= 4; UNSP_REG(PC) += (OP1 == 0) ? OPIMM : (0 - OPIMM); } - break; + else + m_icount -= 2; + continue; case 2: // JGE if(!(UNSP_REG(SR) & UNSP_S)) { + m_icount -= 4; UNSP_REG(PC) += (OP1 == 0) ? OPIMM : (0 - OPIMM); } - break; + else + m_icount -= 2; + continue; case 3: // JL if(UNSP_REG(SR) & UNSP_S) { + m_icount -= 4; UNSP_REG(PC) += (OP1 == 0) ? OPIMM : (0 - OPIMM); } - break; + else + m_icount -= 2; + continue; case 4: // JNE if(!(UNSP_REG(SR) & UNSP_Z)) { + m_icount -= 4; UNSP_REG(PC) += (OP1 == 0) ? OPIMM : (0 - OPIMM); } - break; + else + m_icount -= 2; + continue; case 5: // JE if(UNSP_REG(SR) & UNSP_Z) { + m_icount -= 4; UNSP_REG(PC) += (OP1 == 0) ? OPIMM : (0 - OPIMM); } - break; + else + m_icount -= 2; + continue; case 6: // JPL if(!(UNSP_REG(SR) & UNSP_N)) { + m_icount -= 4; UNSP_REG(PC) += (OP1 == 0) ? OPIMM : (0 - OPIMM); } - break; + else + m_icount -= 2; + continue; case 7: // JMI if(UNSP_REG(SR) & UNSP_N) { + m_icount -= 4; UNSP_REG(PC) += (OP1 == 0) ? OPIMM : (0 - OPIMM); } - break; + else + m_icount -= 2; + continue; case 8: // JBE if((UNSP_REG(SR) & (UNSP_Z | UNSP_C)) != UNSP_C) { + m_icount -= 4; UNSP_REG(PC) += (OP1 == 0) ? OPIMM : (0 - OPIMM); } - break; + else + m_icount -= 2; + continue; case 9: // JA if((UNSP_REG(SR) & (UNSP_Z | UNSP_C)) == UNSP_C) { + m_icount -= 4; UNSP_REG(PC) += (OP1 == 0) ? OPIMM : (0 - OPIMM); } - break; + else + m_icount -= 2; + continue; case 10: // JLE if(UNSP_REG(SR) & (UNSP_Z | UNSP_S)) { + m_icount -= 4; UNSP_REG(PC) += (OP1 == 0) ? OPIMM : (0 - OPIMM); } - break; + else + m_icount -= 2; + continue; case 11: // JG if(!(UNSP_REG(SR) & (UNSP_Z | UNSP_S))) { + m_icount -= 4; UNSP_REG(PC) += (OP1 == 0) ? OPIMM : (0 - OPIMM); } - break; + else + m_icount -= 2; + continue; case 14: // JMP UNSP_REG(PC) += (OP1 == 0) ? OPIMM : (0 - OPIMM); - break; + m_icount -= 4; + continue; + default: + unimplemented_opcode(op); + continue; } } - else + else if (lower_op == 0x2d) // Push { - switch((OP1 << 4) | OP0) + r0 = OPN; + r1 = OPA; + m_icount -= 4 + 2 * r0; + + while (r0--) { - // r, [bp+imm6] - case 0x00: case 0x01: case 0x02: case 0x03: case 0x04: case 0x06: case 0x08: case 0x09: case 0x0a: case 0x0b: case 0x0c: case 0x0d: - r0 = UNSP_REG_I(OPA); - r1 = READ16(UNSP_REG(BP) + OPIMM); - switch(OP0) + push(UNSP_REG_I(r1--), &UNSP_REG_I(OPB)); + } + continue; + } + else if (lower_op == 0x29) // Pop + { + if (op == 0x9a98) // reti + { + m_icount -= 8; + UNSP_REG(SR) = pop(&UNSP_REG(SP)); + UNSP_REG(PC) = pop(&UNSP_REG(SP)); + + if(m_fiq) + { + m_fiq = false; + m_saved_sb[2] = m_sb; + m_sb = m_saved_sb[m_irq ? 1 : 0]; + } + else if(m_irq) + { + m_irq = false; + m_saved_sb[1] = m_sb; + m_sb = m_saved_sb[0]; + } + + check_irqs(); + continue; + } + else + { + r0 = OPN; + r1 = OPA; + m_icount -= 4 + 2 * r0; + + while (r0--) + { + UNSP_REG_I(++r1) = pop(&UNSP_REG_I(OPB)); + } + continue; + } + } + else if (OP0 == 0xf) + { + switch (OP1) + { + case 0x00: // Multiply, Unsigned * Signed + if(OPN == 1 && OPA != 7) { - STANDARD_ALU_CASES; - case 13: // store r, [bp+imm6] - WRITE16(UNSP_REG(BP) + OPIMM, UNSP_REG_I(OPA)); - break; - default: - unimplemented_opcode(op); - break; + m_icount -= 12; + lres = UNSP_REG_I(OPA) * UNSP_REG_I(OPB); + if(UNSP_REG_I(OPB) & 0x8000) + { + lres -= UNSP_REG_I(OPA) << 16; + } + UNSP_REG(R4) = lres >> 16; + UNSP_REG(R3) = (uint16_t)lres; } - WRITEBACK_OPA; - break; - - // r, imm6 - case 0x10: case 0x11: case 0x12: case 0x13: case 0x14: case 0x16: case 0x18: case 0x19: case 0x1a: case 0x1b: case 0x1c: - r0 = UNSP_REG_I(OPA); - r1 = OPIMM; - switch(OP0) + else { - STANDARD_ALU_CASES; - default: - unimplemented_opcode(op); - break; + unimplemented_opcode(op); } - WRITEBACK_OPA; - break; + continue; - // Pop / Interrupt return - case 0x29: - if(op == 0x9a90) // retf + case 0x01: // Call + if(!(OPA & 1)) { - UNSP_REG(SR) = unsp_pop(&UNSP_REG(SP)); - UNSP_REG(PC) = unsp_pop(&UNSP_REG(SP)); - break; + m_icount -= 9; + r1 = read16(UNSP_LPC); + UNSP_REG(PC)++; + push(UNSP_REG(PC), &UNSP_REG(SP)); + push(UNSP_REG(SR), &UNSP_REG(SP)); + UNSP_REG(PC) = r1; + UNSP_REG(SR) &= 0xffc0; + UNSP_REG(SR) |= OPIMM; } - else if(op == 0x9a98) // reti + else { - int i; - UNSP_REG(SR) = unsp_pop(&UNSP_REG(SP)); - UNSP_REG(PC) = unsp_pop(&UNSP_REG(SP)); - if(m_fiq & 2) - { - m_fiq &= 1; - } - else if(m_irq & 2) - { - m_irq &= 1; - } - m_sirq &= ~(1 << m_curirq); - for(i = 0; i < 9; i++) + unimplemented_opcode(op); + } + continue; + + case 0x02: // Far Jump + if (OPA == 7) + { + m_icount -= 5; + UNSP_REG(PC) = read16(UNSP_LPC); + UNSP_REG(PC)++; + UNSP_REG(SR) &= 0xffc0; + UNSP_REG(SR) |= OPIMM; + } + else + { + unimplemented_opcode(op); + } + continue; + + case 0x04: // Multiply, Signed * Signed + if(OPN == 1 && OPA != 7) + { + m_icount -= 12; + lres = UNSP_REG_I(OPA) * UNSP_REG_I(OPB); + if(UNSP_REG_I(OPB) & 0x8000) { - if((m_sirq & (1 << i)) != 0 && i != m_curirq) - { - m_sirq &= ~(1 << i); - m_curirq = 0; - execute_set_input(UNSP_IRQ0_LINE + i, 1); - i = -1; - break; - } + lres -= UNSP_REG_I(OPA) << 16; } - if(i != -1) + if(UNSP_REG_I(OPA) & 0x8000) { - m_curirq = 0; + lres -= UNSP_REG_I(OPB) << 16; } - break; + UNSP_REG(R4) = lres >> 16; + UNSP_REG(R3) = (uint16_t)lres; } else { - r0 = OPN; - r1 = OPA; - while(r0--) - { - UNSP_REG_I(++r1) = unsp_pop(&UNSP_REG_I(OPB)); - } + unimplemented_opcode(op); } - break; + continue; - // Push - case 0x2d: - r0 = OPN; - r1 = OPA; - while(r0--) + case 0x05: // Interrupt flags + m_icount -= 2; + switch(OPIMM) { - unsp_push(UNSP_REG_I(r1--), &UNSP_REG_I(OPB)); + case 0: + m_enable_irq = false; + m_enable_fiq = false; + break; + case 1: + m_enable_irq = true; + m_enable_fiq = false; + break; + case 2: + m_enable_irq = false; + m_enable_fiq = true; + break; + case 3: + m_enable_irq = true; + m_enable_fiq = true; + break; + case 8: // irq off + m_enable_irq = false; + break; + case 9: // irq on + m_enable_irq = true; + break; + case 12: // fiq off + m_enable_fiq = false; + break; + case 14: // fiq on + m_enable_fiq = true; + break; + case 37: // nop + break; + default: + unimplemented_opcode(op); + break; } - break; + continue; + + default: + unimplemented_opcode(op); + continue; + } + } + + // At this point, we should be dealing solely with ALU ops. - // ALU, Indirect - case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: case 0x36: case 0x38: case 0x39: case 0x3a: case 0x3b: case 0x3c: case 0x3d: - switch(OPN & 3) + r0 = UNSP_REG_I(OPA); + + switch (OP1) + { + case 0x00: // r, [bp+imm6] + m_icount -= 6; + + r2 = UNSP_REG(BP) + OPIMM; + if (OP0 != 0x0d) + r1 = read16(r2); + break; + + case 0x01: // r, imm6 + m_icount -= 2; + + r1 = OPIMM; + break; + + case 0x03: // Indirect + { + m_icount -= 6; + if (OPA == 7) + m_icount -= 1; + + const uint8_t lsbits = OPN & 3; + const uint8_t opb = OPB; + if (OPN & 4) + { + switch (lsbits) { case 0: // r, [r] - r0 = UNSP_REG_I(OPA); - r1 = READ16((OPN & 4) ? UNSP_LREG_I(OPB) : UNSP_REG_I(OPB)); - switch(OP0) - { - STANDARD_ALU_CASES; - case 13: // store r, [r] - WRITE16((OPN & 4) ? UNSP_LREG_I(OPB) : UNSP_REG_I(OPB), UNSP_REG_I(OPA)); - break; - default: - unimplemented_opcode(op); - break; - } - WRITEBACK_OPA; + r2 = UNSP_LREG_I(opb); + if (OP0 != 0x0d) + r1 = read16(r2); break; case 1: // r, [<ds:>r--] - r0 = UNSP_REG_I(OPA); - r1 = READ16((OPN & 4) ? UNSP_LREG_I(OPB) : UNSP_REG_I(OPB)); - switch(OP0) - { - STANDARD_ALU_CASES; - case 13: // store r, [<ds:>r--] - WRITE16((OPN & 4) ? UNSP_LREG_I(OPB) : UNSP_REG_I(OPB), UNSP_REG_I(OPA)); - break; - default: - unimplemented_opcode(op); - break; - } - UNSP_REG_I(OPB)--; - WRITEBACK_OPA; + r2 = UNSP_LREG_I(opb); + if (OP0 != 0x0d) + r1 = read16(r2); + UNSP_REG_I(opb)--; break; case 2: // r, [<ds:>r++] - r0 = UNSP_REG_I(OPA); - r1 = READ16((OPN & 4) ? UNSP_LREG_I(OPB) : UNSP_REG_I(OPB)); - switch(OP0) - { - STANDARD_ALU_CASES; - case 13: // store r, [<ds:>r++] - WRITE16((OPN & 4) ? UNSP_LREG_I(OPB) : UNSP_REG_I(OPB), UNSP_REG_I(OPA)); - break; - default: - unimplemented_opcode(op); - break; - } - UNSP_REG_I(OPB)++; - WRITEBACK_OPA; + r2 = UNSP_LREG_I(opb); + if (OP0 != 0x0d) + r1 = read16(r2); + UNSP_REG_I(opb)++; break; case 3: // r, [<ds:>++r] - UNSP_REG_I(OPB)++; - r0 = UNSP_REG_I(OPA); - r1 = READ16((OPN & 4) ? UNSP_LREG_I(OPB) : UNSP_REG_I(OPB)); - switch(OP0) - { - STANDARD_ALU_CASES; - default: - unimplemented_opcode(op); - break; - } - WRITEBACK_OPA; + UNSP_REG_I(opb)++; + r2 = UNSP_LREG_I(opb); + if (OP0 != 0x0d) + r1 = read16(r2); + break; + default: break; } - break; - - // ALU, 16-bit ops - case 0x40: case 0x41: case 0x42: case 0x43: case 0x44: case 0x46: case 0x48: case 0x49: case 0x4a: case 0x4b: case 0x4c: - switch(OPN) + } + else + { + switch (lsbits) { - // r, r - case 0: - r0 = UNSP_REG_I(OPA); - r1 = UNSP_REG_I(OPB); - switch(OP0) - { - STANDARD_ALU_CASES; - default: - unimplemented_opcode(op); - break; - } - WRITEBACK_OPA; + case 0: // r, [r] + r2 = UNSP_REG_I(opb); + if (OP0 != 0x0d) + r1 = read16(r2); break; - - // ALU, 16-bit Immediate - case 1: // r, r, imm16 - if(!((OP0 == 4 || OP0 == 6 || OP0 == 9 || OP0 == 12) && OPA != OPB)) - { - r0 = UNSP_REG_I(OPB); - r1 = READ16(UNSP_LPC); - UNSP_REG(PC)++; - switch(OP0) - { - STANDARD_ALU_CASES; - default: - unimplemented_opcode(op); - break; - } - WRITEBACK_OPA; - } - else - { - unimplemented_opcode(op); - } + case 1: // r, [<ds:>r--] + r2 = UNSP_REG_I(opb); + if (OP0 != 0x0d) + r1 = read16(r2); + UNSP_REG_I(opb)--; break; - - // ALU, Direct 16 - case 2: // r, [imm16] - r0 = UNSP_REG_I(OPB); - r1 = READ16(READ16(UNSP_LPC)); - UNSP_REG(PC)++; - switch(OP0) - { - STANDARD_ALU_CASES; - default: - unimplemented_opcode(op); - break; - } - WRITEBACK_OPA; + case 2: // r, [<ds:>r++] + r2 = UNSP_REG_I(opb); + if (OP0 != 0x0d) + r1 = read16(r2); + UNSP_REG_I(opb)++; break; - - // ALU, Direct 16 - case 3: // [imm16], r - r0 = UNSP_REG_I(OPB); - r1 = UNSP_REG_I(OPA); - switch(OP0) - { - STANDARD_ALU_CASES; - default: - unimplemented_opcode(op); - break; - } - if(OP0 != 4 && OP0 < 12) - { - WRITE16(READ16(UNSP_LPC), (uint16_t)lres); - } - UNSP_REG(PC)++; + case 3: // r, [<ds:>++r] + UNSP_REG_I(opb)++; + r2 = UNSP_REG_I(opb); + if (OP0 != 0x0d) + r1 = read16(r2); break; - - // ALU, Shifted default: - { - uint32_t shift = (UNSP_REG_I(OPB) << 4) | m_sb; - if(shift & 0x80000) - { - shift |= 0xf00000; - } - shift >>= (OPN - 3); - m_sb = shift & 0x0f; - r1 = (shift >> 4) & 0x0000ffff; - - switch(OP0) - { - case 9: // load r, r asr n - unsp_update_nz(r1); - UNSP_REG_I(OPA) = r1; - break; - default: - unimplemented_opcode(op); - break; - } break; - } - } - break; - - case 0x4d: - if(OPN == 3) - { - if(OPA == OPB) - { - WRITE16(READ16(UNSP_LPC), UNSP_REG_I(OPB)); - UNSP_REG(PC)++; - } - else - { - unimplemented_opcode(op); - } - } - else - { - unimplemented_opcode(op); } - break; + } + break; + } - // ALU, Shifted - case 0x50: case 0x51: case 0x52: case 0x53: case 0x54: case 0x56: case 0x58: case 0x59: case 0x5a: case 0x5b: case 0x5c: - if(OPN & 4) - { - switch(OP0) - { - case 9: // load r, r >> imm2 - lres = ((UNSP_REG_I(OPB) << 4) | m_sb) >> (OPN - 3); - m_sb = lres & 0x0f; - unsp_update_nz((uint16_t)(lres >> 4)); - UNSP_REG_I(OPA) = (uint16_t)(lres >> 4); - break; - default: - unimplemented_opcode(op); - break; - } - } - else - { - uint32_t shift = ((m_sb << 16) | UNSP_REG_I(OPB)) << (OPN + 1); - m_sb = (shift >> 16) & 0x0f; - r0 = UNSP_REG_I(OPA); - r1 = shift & 0x0000ffff; + case 0x04: // 16-bit ops + switch (OPN) + { + case 0x00: // r + m_icount -= 3; + if (OPA == 7) + m_icount -= 2; - switch(OP0) - { - case 0: // add r, r << imm2 - lres = r0 + r1; - unsp_update_nzsc(lres, r0, r1); - UNSP_REG_I(OPA) = (uint16_t)lres; - break; - case 9: // load r, r << imm2 - lres = r1; - unsp_update_nz(lres); - UNSP_REG_I(OPA) = (uint16_t)lres; - break; - case 10: // or r, r << imm2 - lres = r0 | r1; - unsp_update_nz(lres); - UNSP_REG_I(OPA) = (uint16_t)lres; - break; - default: - unimplemented_opcode(op); - break; - } - } - break; + r1 = UNSP_REG_I(OPB); + break; - // ALU, Rotated - case 0x60: case 0x61: case 0x62: case 0x63: case 0x64: case 0x66: case 0x68: case 0x69: case 0x6a: case 0x6b: case 0x6c: - if(OPN & 4) // ROR - { - lres = ((((m_sb << 16) | UNSP_REG_I(OPB)) << 4) | m_sb) >> (OPN - 3); - m_sb = lres & 0x0f; - r1 = (uint16_t)(lres >> 4); - } - else - { - lres = ((((m_sb << 16) | UNSP_REG_I(OPB)) << 4) | m_sb) << (OPN + 1); - m_sb = (lres >> 20) & 0x0f; - r1 = (uint16_t)(lres >> 4); - } + case 0x01: // imm16 + m_icount -= 4; + if (OPA == 7) + m_icount -= 1; - switch(OP0) - { - case 9: // load r, r ror imm2 - unsp_update_nz(r1); - UNSP_REG_I(OPA) = r1; - break; - default: - unimplemented_opcode(op); - break; - } - break; + r0 = UNSP_REG_I(OPB); + r1 = read16(UNSP_LPC); + UNSP_REG(PC)++; + break; - // ALU, Direct 8 - case 0x70: case 0x71: case 0x72: case 0x73: case 0x74: case 0x76: case 0x78: case 0x79: case 0x7a: case 0x7b: case 0x7c: - //print("%s %s, [%02x]", alu[OP0], reg[OPA], OPIMM); - unimplemented_opcode(op); - break; + case 0x02: // [imm16] + m_icount -= 7; + if (OPA == 7) + m_icount -= 1; - // Call - case 0x1f: - if(OPA == 0) - { - r1 = READ16(UNSP_LPC); + r0 = UNSP_REG_I(OPB); + r2 = read16(UNSP_LPC); UNSP_REG(PC)++; - unsp_push(UNSP_REG(PC), &UNSP_REG(SP)); - unsp_push(UNSP_REG(SR), &UNSP_REG(SP)); - UNSP_REG(PC) = r1; - UNSP_REG(SR) &= 0xffc0; - UNSP_REG(SR) |= OPIMM; - } - else - { - unimplemented_opcode(op); - } - break; - // Far Jump - case 0x2f: case 0x3f: case 0x6f: case 0x7f: - if (OPA == 7 && OP1 == 2) - { - UNSP_REG(PC) = READ16(UNSP_LPC); - UNSP_REG(SR) &= 0xffc0; - UNSP_REG(SR) |= OPIMM; - } - break; - - // Multiply, Unsigned * Signed - case 0x0f: - if(OPN == 1 && OPA != 7) - { - lres = UNSP_REG_I(OPA) * UNSP_REG_I(OPB); - if(UNSP_REG_I(OPB) & 0x8000) + if (OP0 != 0x0d) { - lres -= UNSP_REG_I(OPA) << 16; + r1 = read16(r2); } - UNSP_REG(R4) = lres >> 16; - UNSP_REG(R3) = (uint16_t)lres; break; - } - else - { - unimplemented_opcode(op); - } - break; - // Multiply, Signed * Signed - case 0x4f: - if(OPN == 1 && OPA != 7) - { - lres = UNSP_REG_I(OPA) * UNSP_REG_I(OPB); - if(UNSP_REG_I(OPB) & 0x8000) - { - lres -= UNSP_REG_I(OPA) << 16; - } - if(UNSP_REG_I(OPA) & 0x8000) - { - lres -= UNSP_REG_I(OPB) << 16; - } - UNSP_REG(R4) = lres >> 16; - UNSP_REG(R3) = (uint16_t)lres; + case 0x03: // store [imm16], r + m_icount -= 7; + if (OPA == 7) + m_icount -= 1; + + r1 = r0; + r0 = UNSP_REG_I(OPB); + r2 = read16(UNSP_LPC); + UNSP_REG(PC)++; break; - } - else - { - unimplemented_opcode(op); - } - break; - // Interrupt flags - case 0x5f: - if(OPA == 0) - { - switch(OPIMM) - { - case 0: - m_irq &= ~1; - m_fiq &= ~1; - break; - case 1: - m_irq |= 1; - m_fiq &= ~1; - break; - case 2: - m_irq &= ~1; - m_fiq |= 1; - break; - case 3: - m_irq |= 1; - m_fiq |= 1; - break; - case 8: // irq off - m_irq &= ~1; - break; - case 9: // irq on - m_irq |= 1; - break; - case 12: // fiq off - m_fiq &= ~1; - break; - case 13: // fiq on - m_fiq |= 1; - break; - case 37: // nop - break; - } - } - else + default: // Shifted ops { - unimplemented_opcode(op); + m_icount -= 3; + if (OPA == 7) + m_icount -= 2; + + uint32_t shift = (UNSP_REG_I(OPB) << 4) | m_sb; + if (shift & 0x80000) + shift |= 0xf00000; + shift >>= (OPN - 3); + m_sb = shift & 0x0f; + r1 = (uint16_t)(shift >> 4); + break; } - break; + } + break; + + case 0x05: // More shifted ops + m_icount -= 3; + if (OPA == 7) + m_icount -= 2; + + if (OPN & 4) // Shift right + { + const uint32_t shift = ((UNSP_REG_I(OPB) << 4) | m_sb) >> (OPN - 3); + m_sb = shift & 0x0f; + r1 = (uint16_t)(shift >> 4); + } + else // Shift left + { + const uint32_t shift = ((m_sb << 16) | UNSP_REG_I(OPB)) << (OPN + 1); + m_sb = (shift >> 16) & 0x0f; + r1 = (uint16_t)shift; + } + break; + + case 0x06: // Rotated ops + { + m_icount -= 3; + if (OPA == 7) + m_icount -= 2; + + uint32_t shift = (((m_sb << 16) | UNSP_REG_I(OPB)) << 4) | m_sb; + if (OPN & 4) // Rotate right + { + shift >>= (OPN - 3); + m_sb = shift & 0x0f; + } + else + { + shift <<= (OPN + 1); + m_sb = (shift >> 20) & 0x0f; + } + r1 = (uint16_t)(shift >> 4); + break; } + + case 0x07: // Direct 8 + m_icount -= 5; + if (OPA == 7) + m_icount -= 1; + + r1 = read16(OPIMM); + break; + + default: + break; } - m_icount -= 5; - m_icount = std::max(m_icount, 0); + switch (OP0) + { + case 0x00: // Add + lres = r0 + r1; + break; + case 0x01: // Add w/ carry + lres = r0 + r1; + if(UNSP_REG(SR) & UNSP_C) + lres++; + break; + case 0x02: // Subtract + case 0x04: // Compare + lres = r0 + (uint16_t)(~r1) + 1; + break; + case 0x03: // Subtract w/ carry + lres = r0 + (uint16_t)(~r1); + if(UNSP_REG(SR) & UNSP_C) + lres++; + break; + case 0x06: // Negate + lres = -r1; + break; + case 0x08: // XOR + lres = r0 ^ r1; + break; + case 0x09: // Load + lres = r1; + break; + case 0x0a: // OR + lres = r0 | r1; + break; + case 0x0b: // AND + case 0x0c: // Test + lres = r0 & r1; + break; + case 0x0d: // Store + write16(r2, r0); + continue; + default: + unimplemented_opcode(op); + continue; + } + + if (OP0 != 0x0d && OPA != 0x07) // If not a store opcode and not updating the PC, update negative/zero flags. + update_nz(lres); + + if (OP0 < 0x05 && OPA != 0x07) // If Add, Add w/ Carry, Subtract, Subtract w/ Carry, Compare, and not updating the PC, update sign/carry flags. + update_sc(lres, r0, r1); + + if (OP0 == 0x04 || OP0 == 0x0c) // Compare and Test don't write back results. + continue; + + if (OP1 == 0x04 && OPN == 0x03) // store [imm16], r + write16(r2, lres); + else + UNSP_REG_I(OPA) = lres; } } @@ -812,8 +836,6 @@ void unsp_device::execute_run() void unsp_device::execute_set_input(int irqline, int state) { - uint16_t irq_vector = 0; - m_sirq &= ~(1 << irqline); if(!state) @@ -831,40 +853,10 @@ void unsp_device::execute_set_input(int irqline, int state) case UNSP_IRQ5_LINE: case UNSP_IRQ6_LINE: case UNSP_IRQ7_LINE: - if(m_fiq & 2) - { - // FIQ is being serviced, ignore this IRQ trigger. - m_sirq |= state << irqline; - return; - } - if(m_irq != 1) - { - // IRQ is disabled, ignore this IRQ trigger. - m_sirq |= state << irqline; - return; - } - m_irq |= 2; - m_curirq |= (1 << irqline); - irq_vector = 0xfff8 + (irqline - UNSP_IRQ0_LINE); - break; case UNSP_FIQ_LINE: - if(m_fiq != 1) - { - // FIQ is disabled, ignore this FIQ trigger. - m_sirq |= state << irqline; - return; - } - m_fiq |= 2; - m_curirq |= (1 << irqline); - irq_vector = 0xfff6; + m_sirq |= (1 << irqline); break; case UNSP_BRK_LINE: break; } - - m_saved_sb = m_sb; - unsp_push(UNSP_REG(PC), &UNSP_REG(SP)); - unsp_push(UNSP_REG(SR), &UNSP_REG(SP)); - UNSP_REG(PC) = READ16(irq_vector); - UNSP_REG(SR) = 0; } |