diff options
author | 2010-01-14 05:35:34 +0000 | |
---|---|---|
committer | 2010-01-14 05:35:34 +0000 | |
commit | 8d183da73824a2766617c0d3e72c0bfc7c3387b4 (patch) | |
tree | d966c8fd7e52350bb2e7c47976562a06082ba535 | |
parent | 8c013355f795b4b715cbe440d83b5c2956ea505b (diff) |
Added a mostly-complete SunPlus u'nSP core based on the one in Segher's "Unununium". [Harmony]
-rw-r--r-- | .gitattributes | 3 | ||||
-rw-r--r-- | src/emu/cpu/cpu.mak | 15 | ||||
-rw-r--r-- | src/emu/cpu/unsp/unsp.c | 918 | ||||
-rw-r--r-- | src/emu/cpu/unsp/unsp.h | 72 | ||||
-rw-r--r-- | src/emu/cpu/unsp/unspdasm.c | 262 |
5 files changed, 1270 insertions, 0 deletions
diff --git a/.gitattributes b/.gitattributes index fecb7d118b4..e437d160e76 100644 --- a/.gitattributes +++ b/.gitattributes @@ -459,6 +459,9 @@ src/emu/cpu/tms9900/tms9900.c svneol=native#text/plain src/emu/cpu/tms9900/tms9900.h svneol=native#text/plain src/emu/cpu/tms9900/tms9980a.c svneol=native#text/plain src/emu/cpu/tms9900/tms9995.c svneol=native#text/plain +src/emu/cpu/unsp/unsp.c svneol=native#text/plain +src/emu/cpu/unsp/unsp.h svneol=native#text/plain +src/emu/cpu/unsp/unspdasm.c svneol=native#text/plain src/emu/cpu/upd7810/7810dasm.c svneol=native#text/plain src/emu/cpu/upd7810/7810ops.c svneol=native#text/plain src/emu/cpu/upd7810/7810tbl.c svneol=native#text/plain diff --git a/src/emu/cpu/cpu.mak b/src/emu/cpu/cpu.mak index a53af75d272..cfde296258a 100644 --- a/src/emu/cpu/cpu.mak +++ b/src/emu/cpu/cpu.mak @@ -1317,6 +1317,21 @@ $(CPUOBJ)/ssp1610/ssp1601.o: $(CPUSRC)/ssp1601/ssp1601.c \ #------------------------------------------------- +# SunPlus u'nSP +#------------------------------------------------- + +ifneq ($(filter UNSP,$(CPUS)),) +OBJDIRS += $(CPUOBJ)/unsp +CPUOBJS += $(CPUOBJ)/unsp/unsp.o +DASMOBJS += $(CPUOBJ)/unsp/unspdasm.o +endif + +$(CPUOBJ)/unsp/unsp.o: $(CPUSRC)/unsp/unsp.c \ + $(CPUSRC)/unsp/unsp.h + + + +#------------------------------------------------- # Atmel 8-bit AVR #------------------------------------------------- diff --git a/src/emu/cpu/unsp/unsp.c b/src/emu/cpu/unsp/unsp.c new file mode 100644 index 00000000000..7fc8f4bc540 --- /dev/null +++ b/src/emu/cpu/unsp/unsp.c @@ -0,0 +1,918 @@ +/**************************\ +* +* SunPlus u'nSP core +* +* by Harmony +* +\**************************/ + +#include "emu.h" +#include "debugger.h" +#include "unsp.h" + +INLINE unsp_state *get_safe_token(const device_config *device) +{ + assert(device != NULL); + assert(device->token != NULL); + assert(device->type == CPU); + assert(cpu_get_type(device) == CPU_UNSP); + return (unsp_state *)device->token; +} + +static void unsp_set_irq_line(unsp_state *unsp, int irqline, int state); + +/*****************************************************************************/ + +#define OP0 (op >> 12) +#define OPA ((op >> 9) & 7) +#define OP1 ((op >> 6) & 7) +#define OPN ((op >> 3) & 7) +#define OPB (op & 7) +#define OPIMM (op & 0x3f) + +#define UNSP_LPC (((UNSP_REG(SR) & 0x3f) << 16) | UNSP_REG(PC)) + +#define UNSP_REG(reg) unsp->r[UNSP_##reg - 1] +#define UNSP_REG_I(reg) unsp->r[reg] +#define UNSP_LREG_I(reg) (((UNSP_REG(SR) << 6) & 0x3f0000) | UNSP_REG_I(reg)) + +#define UNSP_N 0x0200 +#define UNSP_Z 0x0100 +#define UNSP_S 0x0080 +#define UNSP_C 0x0040 + +#define STANDARD_ALU_CASES \ + case 0: \ + lres = r0 + r1; \ + unsp_update_nzsc(unsp, lres, r0, r1); \ + break; \ + case 1: \ + lres = r0 + r1; \ + if(UNSP_REG(SR) & UNSP_C) lres++; \ + unsp_update_nzsc(unsp, lres, r0, r1); \ + break; \ + case 3: \ + lres = r0 + (~r1 & 0x0000ffff); \ + if(UNSP_REG(SR) & UNSP_C) lres++; \ + unsp_update_nzsc(unsp, lres, r0, r1); \ + break; \ + case 2: \ + case 4: \ + lres = r0 + (~r1 & 0x0000ffff) + 1; \ + unsp_update_nzsc(unsp, lres, r0, r1); \ + break; \ + case 6: \ + lres = -r1; \ + unsp_update_nz(unsp, lres); \ + break; \ + case 8: \ + lres = r0 ^ r1; \ + unsp_update_nz(unsp, lres); \ + break; \ + case 9: \ + lres = r1; \ + unsp_update_nz(unsp, lres); \ + break; \ + case 10: \ + lres = r0 | r1; \ + unsp_update_nz(unsp, lres); \ + break; \ + case 11: \ + case 12: \ + lres = r0 & r1; \ + unsp_update_nz(unsp, lres); \ + break + +#define WRITEBACK_OPA \ + if(OP0 != 4 && OP0 < 12) \ + { \ + UNSP_REG_I(OPA) = (UINT16)lres; \ + } + +/*****************************************************************************/ + +static void unimplemented_opcode(unsp_state *unsp, UINT16 op) +{ + fatalerror("UNSP: unknown opcode %04x at %04x\n", op, UNSP_LPC << 1); +} + +/*****************************************************************************/ + +INLINE UINT16 READ16(unsp_state *unsp, UINT32 address) +{ + return memory_read_word_16be(unsp->program, address << 1); +} + +INLINE void WRITE16(unsp_state *unsp, UINT32 address, UINT16 data) +{ + memory_write_word_16be(unsp->program, address << 1, data); +} + +/*****************************************************************************/ + +static CPU_INIT( unsp ) +{ + unsp_state *unsp = get_safe_token(device); + memset(unsp->r, 0, sizeof(UINT16) * UNSP_GPR_COUNT); + + unsp->device = device; + unsp->program = memory_find_address_space(device, ADDRESS_SPACE_PROGRAM); + unsp->irq = 0; + unsp->fiq = 0; +} + +static CPU_RESET( unsp ) +{ + unsp_state *unsp = get_safe_token(device); + memset(unsp->r, 0, sizeof(UINT16) * UNSP_GPR_COUNT); + + UNSP_REG(PC) = READ16(unsp, 0xfff7); +} + +/*****************************************************************************/ + +static void unsp_update_nz(unsp_state *unsp, UINT32 value) +{ + UNSP_REG(SR) &= ~(UNSP_N | UNSP_Z); + if(value & 0x8000) + { + UNSP_REG(SR) |= UNSP_N; + } + if((UINT16)value == 0) + { + UNSP_REG(SR) |= UNSP_Z; + } +} + +static void unsp_update_nzsc(unsp_state *unsp, UINT32 value, UINT16 r0, UINT16 r1) +{ + UNSP_REG(SR) &= ~(UNSP_C | UNSP_S); + unsp_update_nz(unsp, value); + if(value != (UINT16)value) + { + UNSP_REG(SR) |= UNSP_C; + } + + if((INT16)r0 < (INT16)r1) + { + UNSP_REG(SR) |= UNSP_S; + } +} + +static void unsp_push(unsp_state *unsp, UINT16 value, UINT16 *reg) +{ + WRITE16(unsp, (*reg)--, value); +} + +static UINT16 unsp_pop(unsp_state *unsp, UINT16 *reg) +{ + return READ16(unsp, ++(*reg)); +} + +static CPU_EXECUTE( unsp ) +{ + unsp_state *unsp = get_safe_token(device); + UINT32 op; + UINT32 lres; + UINT16 r0, r1; + lres = 0; + + unsp->icount = cycles; + + while (unsp->icount > 0) + { + debugger_instruction_hook(device, UNSP_LPC<<1); + + op = READ16(unsp, UNSP_LPC); + + UNSP_REG(PC)++; + + if(OP0 < 0xf && OPA == 0x7 && OP1 < 2) + { + switch(OP0) + { + case 0: // JB + if(!(UNSP_REG(SR) & UNSP_C)) + { + UNSP_REG(PC) += (OP1 == 0) ? OPIMM : (0 - OPIMM); + } + break; + case 1: // JAE + if(UNSP_REG(SR) & UNSP_C) + { + UNSP_REG(PC) += (OP1 == 0) ? OPIMM : (0 - OPIMM); + } + break; + case 2: // JGE + if(!(UNSP_REG(SR) & UNSP_S)) + { + UNSP_REG(PC) += (OP1 == 0) ? OPIMM : (0 - OPIMM); + } + break; + case 3: // JL + if(UNSP_REG(SR) & UNSP_S) + { + UNSP_REG(PC) += (OP1 == 0) ? OPIMM : (0 - OPIMM); + } + break; + case 4: // JNE + if(!(UNSP_REG(SR) & UNSP_Z)) + { + UNSP_REG(PC) += (OP1 == 0) ? OPIMM : (0 - OPIMM); + } + break; + case 5: // JE + if(UNSP_REG(SR) & UNSP_Z) + { + UNSP_REG(PC) += (OP1 == 0) ? OPIMM : (0 - OPIMM); + } + break; + case 6: // JPL + if(!(UNSP_REG(SR) & UNSP_N)) + { + UNSP_REG(PC) += (OP1 == 0) ? OPIMM : (0 - OPIMM); + } + break; + case 7: // JMI + if(UNSP_REG(SR) & UNSP_N) + { + UNSP_REG(PC) += (OP1 == 0) ? OPIMM : (0 - OPIMM); + } + break; + case 8: // JBE + if((UNSP_REG(SR) & (UNSP_Z | UNSP_C)) != UNSP_C) + { + UNSP_REG(PC) += (OP1 == 0) ? OPIMM : (0 - OPIMM); + } + break; + case 9: // JA + if((UNSP_REG(SR) & (UNSP_Z | UNSP_C)) == UNSP_C) + { + UNSP_REG(PC) += (OP1 == 0) ? OPIMM : (0 - OPIMM); + } + break; + case 10: // JLE + if(UNSP_REG(SR) & (UNSP_Z | UNSP_S)) + { + UNSP_REG(PC) += (OP1 == 0) ? OPIMM : (0 - OPIMM); + } + break; + case 11: // JG + if(!(UNSP_REG(SR) & (UNSP_Z | UNSP_S))) + { + UNSP_REG(PC) += (OP1 == 0) ? OPIMM : (0 - OPIMM); + } + break; + case 14: // JMP + UNSP_REG(PC) += (OP1 == 0) ? OPIMM : (0 - OPIMM); + break; + } + } + else + { + switch((OP1 << 4) | OP0) + { + // 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, UNSP_REG(BP) + OPIMM); + switch(OP0) + { + STANDARD_ALU_CASES; + case 13: // store r, [bp+imm6] + WRITE16(unsp, UNSP_REG(BP) + OPIMM, UNSP_REG_I(OPA)); + break; + default: + unimplemented_opcode(unsp, op); + break; + } + 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) + { + STANDARD_ALU_CASES; + default: + unimplemented_opcode(unsp, op); + break; + } + WRITEBACK_OPA; + break; + + // Pop / Interrupt return + case 0x29: + if(op == 0x9a90) // retf + { + UNSP_REG(SR) = unsp_pop(unsp, &UNSP_REG(SP)); + UNSP_REG(PC) = unsp_pop(unsp, &UNSP_REG(SP)); + break; + } + else if(op == 0x9a98) // reti + { + int i; + UNSP_REG(SR) = unsp_pop(unsp, &UNSP_REG(SP)); + UNSP_REG(PC) = unsp_pop(unsp, &UNSP_REG(SP)); + if(unsp->fiq & 2) + { + unsp->fiq &= 1; + } + else if(unsp->irq & 2) + { + unsp->irq &= 1; + } + unsp->sirq &= ~(1 << unsp->curirq); + for(i = 0; i < 9; i++) + { + if((unsp->sirq & (1 << i)) != 0 && i != unsp->curirq) + { + unsp->sirq &= ~(1 << i); + unsp->curirq = 0; + unsp_set_irq_line(unsp, UNSP_IRQ0_LINE + i, 1); + i = -1; + break; + } + } + if(i != -1) + { + unsp->curirq = 0; + } + break; + } + else + { + r0 = OPN; + r1 = OPA; + while(r0--) + { + UNSP_REG_I(++r1) = unsp_pop(unsp, &UNSP_REG_I(OPB)); + } + } + break; + + // Push + case 0x2d: + r0 = OPN; + r1 = OPA; + while(r0--) + { + unsp_push(unsp, UNSP_REG_I(r1--), &UNSP_REG_I(OPB)); + } + break; + + // 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) + { + case 0: // r, [r] + r0 = UNSP_REG_I(OPA); + r1 = READ16(unsp, (OPN & 4) ? UNSP_LREG_I(OPB) : UNSP_REG_I(OPB)); + switch(OP0) + { + STANDARD_ALU_CASES; + case 13: // store r, [r] + WRITE16(unsp, (OPN & 4) ? UNSP_LREG_I(OPB) : UNSP_REG_I(OPB), UNSP_REG_I(OPA)); + break; + default: + unimplemented_opcode(unsp, op); + break; + } + WRITEBACK_OPA; + break; + case 1: // r, [<ds:>r--] + r0 = UNSP_REG_I(OPA); + r1 = READ16(unsp, (OPN & 4) ? UNSP_LREG_I(OPB) : UNSP_REG_I(OPB)); + switch(OP0) + { + STANDARD_ALU_CASES; + case 13: // store r, [<ds:>r--] + WRITE16(unsp, (OPN & 4) ? UNSP_LREG_I(OPB) : UNSP_REG_I(OPB), UNSP_REG_I(OPA)); + break; + default: + unimplemented_opcode(unsp, op); + break; + } + UNSP_REG_I(OPB)--; + WRITEBACK_OPA; + break; + case 2: // r, [<ds:>r++] + r0 = UNSP_REG_I(OPA); + r1 = READ16(unsp, (OPN & 4) ? UNSP_LREG_I(OPB) : UNSP_REG_I(OPB)); + switch(OP0) + { + STANDARD_ALU_CASES; + case 13: // store r, [<ds:>r++] + WRITE16(unsp, (OPN & 4) ? UNSP_LREG_I(OPB) : UNSP_REG_I(OPB), UNSP_REG_I(OPA)); + break; + default: + unimplemented_opcode(unsp, op); + break; + } + UNSP_REG_I(OPB)++; + WRITEBACK_OPA; + break; + case 3: // r, [<ds:>++r] + UNSP_REG_I(OPB)++; + r0 = UNSP_REG_I(OPA); + r1 = READ16(unsp, (OPN & 4) ? UNSP_LREG_I(OPB) : UNSP_REG_I(OPB)); + switch(OP0) + { + STANDARD_ALU_CASES; + default: + unimplemented_opcode(unsp, op); + break; + } + WRITEBACK_OPA; + 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) + { + // r, r + case 0: + r0 = UNSP_REG_I(OPA); + r1 = UNSP_REG_I(OPB); + switch(OP0) + { + STANDARD_ALU_CASES; + default: + unimplemented_opcode(unsp, op); + break; + } + WRITEBACK_OPA; + 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, UNSP_LPC); + UNSP_REG(PC)++; + switch(OP0) + { + STANDARD_ALU_CASES; + default: + unimplemented_opcode(unsp, op); + break; + } + WRITEBACK_OPA; + } + else + { + unimplemented_opcode(unsp, op); + } + break; + + // ALU, Direct 16 + case 2: // r, [imm16] + r0 = UNSP_REG_I(OPB); + r1 = READ16(unsp, READ16(unsp, UNSP_LPC)); + UNSP_REG(PC)++; + switch(OP0) + { + STANDARD_ALU_CASES; + default: + unimplemented_opcode(unsp, op); + break; + } + WRITEBACK_OPA; + 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(unsp, op); + break; + } + if(OP0 != 4 && OP0 < 12) + { + WRITE16(unsp, READ16(unsp, UNSP_LPC), (UINT16)lres); + } + UNSP_REG(PC)++; + break; + + // ALU, Shifted + default: + { + UINT32 shift = (UNSP_REG_I(OPB) << 4) | unsp->sb; + if(shift & 0x80000) + { + shift |= 0xf00000; + } + shift >>= (OPN - 3); + unsp->sb = shift & 0x0f; + r1 = (shift >> 4) & 0x0000ffff; + + switch(OP0) + { + case 9: // load r, r asr n + unsp_update_nz(unsp, r1); + UNSP_REG_I(OPA) = r1; + break; + default: + unimplemented_opcode(unsp, op); + break; + } + break; + } + } + break; + + case 0x4d: + if(OPN == 3) + { + if(OPA == OPB) + { + WRITE16(unsp, READ16(unsp, UNSP_LPC), UNSP_REG_I(OPB)); + UNSP_REG(PC)++; + } + else + { + unimplemented_opcode(unsp, op); + } + } + else + { + unimplemented_opcode(unsp, op); + } + 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) | unsp->sb) >> (OPN - 3); + unsp->sb = lres & 0x0f; + unsp_update_nz(unsp, (UINT16)(lres >> 4)); + UNSP_REG_I(OPA) = (UINT16)(lres >> 4); + break; + default: + unimplemented_opcode(unsp, op); + break; + } + } + else + { + UINT32 shift = ((unsp->sb << 16) | UNSP_REG_I(OPB)) << (OPN + 1); + unsp->sb = (shift >> 16) & 0x0f; + r0 = UNSP_REG_I(OPA); + r1 = shift & 0x0000ffff; + + switch(OP0) + { + case 0: // add r, r << imm2 + lres = r0 + r1; + unsp_update_nzsc(unsp, lres, r0, r1); + UNSP_REG_I(OPA) = (UINT16)lres; + break; + case 9: // load r, r << imm2 + lres = r1; + unsp_update_nz(unsp, lres); + UNSP_REG_I(OPA) = (UINT16)lres; + break; + case 10: // or r, r << imm2 + lres = r0 | r1; + unsp_update_nz(unsp, lres); + UNSP_REG_I(OPA) = (UINT16)lres; + break; + default: + unimplemented_opcode(unsp, op); + break; + } + } + 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 = ((((unsp->sb << 16) | UNSP_REG_I(OPB)) << 4) | unsp->sb) >> (OPN - 3); + unsp->sb = lres & 0x0f; + r1 = (UINT16)(lres >> 4); + } + else + { + lres = ((((unsp->sb << 16) | UNSP_REG_I(OPB)) << 4) | unsp->sb) << (OPN + 1); + unsp->sb = (lres >> 20) & 0x0f; + r1 = (UINT16)(lres >> 4); + } + + switch(OP0) + { + case 9: // load r, r ror imm2 + unsp_update_nz(unsp, r1); + UNSP_REG_I(OPA) = r1; + break; + default: + unimplemented_opcode(unsp, op); + break; + } + 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(unsp, op); + break; + + // Call + case 0x1f: + if(OPA == 0) + { + r1 = READ16(unsp, UNSP_LPC); + UNSP_REG(PC)++; + unsp_push(unsp, UNSP_REG(PC), &UNSP_REG(SP)); + unsp_push(unsp, UNSP_REG(SR), &UNSP_REG(SP)); + UNSP_REG(PC) = r1; + UNSP_REG(SR) &= 0xffc0; + UNSP_REG(SR) |= OPIMM; + } + else + { + unimplemented_opcode(unsp, op); + } + 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) + { + lres -= UNSP_REG_I(OPA) << 16; + } + UNSP_REG(R4) = lres >> 16; + UNSP_REG(R3) = (UINT16)lres; + break; + } + else + { + unimplemented_opcode(unsp, 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)lres; + break; + } + else + { + unimplemented_opcode(unsp, op); + } + break; + + // Interrupt flags + case 0x5f: + if(OPA == 0) + { + switch(OPIMM) + { + case 0: + unsp->irq &= ~1; + unsp->fiq &= ~1; + break; + case 1: + unsp->irq |= 1; + unsp->fiq &= ~1; + break; + case 2: + unsp->irq &= ~1; + unsp->fiq |= 1; + break; + case 3: + unsp->irq |= 1; + unsp->fiq |= 1; + break; + case 8: // irq off + unsp->irq &= ~1; + break; + case 9: // irq on + unsp->irq |= 1; + break; + case 12: // fiq off + unsp->fiq &= ~1; + break; + case 13: // fiq on + unsp->fiq |= 1; + break; + case 37: // nop + break; + } + } + else + { + unimplemented_opcode(unsp, op); + } + break; + } + } + + unsp->icount -= 5; + unsp->icount = MAX(unsp->icount, 0); + } + + return cycles - unsp->icount; +} + + +/*****************************************************************************/ + +static void unsp_set_irq_line(unsp_state *unsp, int irqline, int state) +{ + UINT16 irq_vector = 0; + + unsp->sirq &= ~(1 << irqline); + + if(!state) + { + logerror("clearing irq %d (%04x, %04x)\n", irqline, unsp->sirq, unsp->curirq); + return; + } + + switch (irqline) + { + case UNSP_IRQ0_LINE: + case UNSP_IRQ1_LINE: + case UNSP_IRQ2_LINE: + case UNSP_IRQ3_LINE: + case UNSP_IRQ4_LINE: + case UNSP_IRQ5_LINE: + case UNSP_IRQ6_LINE: + case UNSP_IRQ7_LINE: + if(unsp->fiq & 2) + { + // FIQ is being serviced, ignore this IRQ trigger. + unsp->sirq |= state << irqline; + return; + } + if(unsp->irq != 1) + { + // IRQ is disabled, ignore this IRQ trigger. + unsp->sirq |= state << irqline; + return; + } + unsp->irq |= 2; + unsp->curirq |= (1 << irqline); + logerror("taking irq %d (%04x, %04x)\n", irqline, unsp->sirq, unsp->curirq); + irq_vector = 0xfff8 + (irqline - UNSP_IRQ0_LINE); + break; + case UNSP_FIQ_LINE: + if(unsp->fiq != 1) + { + // FIQ is disabled, ignore this FIQ trigger. + unsp->sirq |= state << irqline; + return; + } + unsp->fiq |= 2; + unsp->curirq |= (1 << irqline); + logerror("taking fiq %d (%04x, %04x)\n", irqline, unsp->sirq, unsp->curirq); + irq_vector = 0xfff6; + break; + case UNSP_BRK_LINE: + break; + } + + unsp->saved_sb = unsp->sb; + unsp_push(unsp, UNSP_REG(PC), &UNSP_REG(SP)); + unsp_push(unsp, UNSP_REG(SR), &UNSP_REG(SP)); + UNSP_REG(PC) = READ16(unsp, irq_vector); + UNSP_REG(SR) = 0; +} + +static CPU_SET_INFO( unsp ) +{ + unsp_state *unsp = get_safe_token(device); + + switch (state) + { + case CPUINFO_INT_INPUT_STATE + UNSP_IRQ0_LINE: + case CPUINFO_INT_INPUT_STATE + UNSP_IRQ1_LINE: + case CPUINFO_INT_INPUT_STATE + UNSP_IRQ2_LINE: + case CPUINFO_INT_INPUT_STATE + UNSP_IRQ3_LINE: + case CPUINFO_INT_INPUT_STATE + UNSP_IRQ4_LINE: + case CPUINFO_INT_INPUT_STATE + UNSP_IRQ5_LINE: + case CPUINFO_INT_INPUT_STATE + UNSP_IRQ6_LINE: + case CPUINFO_INT_INPUT_STATE + UNSP_IRQ7_LINE: + case CPUINFO_INT_INPUT_STATE + UNSP_FIQ_LINE: + case CPUINFO_INT_INPUT_STATE + UNSP_BRK_LINE: + unsp_set_irq_line(unsp, state - CPUINFO_INT_INPUT_STATE, (int)info->i); + break; + + case CPUINFO_INT_REGISTER + UNSP_SP: UNSP_REG(SP) = info->i; break; + case CPUINFO_INT_REGISTER + UNSP_R1: UNSP_REG(R1) = info->i; break; + case CPUINFO_INT_REGISTER + UNSP_R2: UNSP_REG(R2) = info->i; break; + case CPUINFO_INT_REGISTER + UNSP_R3: UNSP_REG(R3) = info->i; break; + case CPUINFO_INT_REGISTER + UNSP_R4: UNSP_REG(R4) = info->i; break; + case CPUINFO_INT_REGISTER + UNSP_BP: UNSP_REG(BP) = info->i; break; + case CPUINFO_INT_REGISTER + UNSP_SR: UNSP_REG(SR) = info->i; break; + case CPUINFO_INT_PC: /* Intentional fallthrough */ + case CPUINFO_INT_REGISTER + UNSP_PC: + UNSP_REG(PC) = (info->i & 0x0001fffe) >> 1; + UNSP_REG(SR) = (UNSP_REG(SR) & 0xffc0) | ((info->i & 0x007e0000) >> 17); + break; + case CPUINFO_INT_REGISTER + UNSP_IRQ: unsp->irq = info->i; break; + case CPUINFO_INT_REGISTER + UNSP_FIQ: unsp->fiq = info->i; break; + case CPUINFO_INT_REGISTER + UNSP_SB: unsp->sb = info->i; break; + } +} + +CPU_GET_INFO( unsp ) +{ + unsp_state *unsp = (device != NULL && device->token != NULL) ? get_safe_token(device) : NULL; + + switch(state) + { + case CPUINFO_INT_CONTEXT_SIZE: info->i = sizeof(unsp_state); break; + case CPUINFO_INT_INPUT_LINES: info->i = 0; break; + case CPUINFO_INT_DEFAULT_IRQ_VECTOR: info->i = 0; break; + case DEVINFO_INT_ENDIANNESS: info->i = ENDIANNESS_BIG; break; + case CPUINFO_INT_CLOCK_MULTIPLIER: info->i = 1; break; + case CPUINFO_INT_CLOCK_DIVIDER: info->i = 1; break; + case CPUINFO_INT_MIN_INSTRUCTION_BYTES: info->i = 2; break; + case CPUINFO_INT_MAX_INSTRUCTION_BYTES: info->i = 4; break; + case CPUINFO_INT_MIN_CYCLES: info->i = 5; break; + case CPUINFO_INT_MAX_CYCLES: info->i = 5; break; + + case CPUINFO_INT_DATABUS_WIDTH_PROGRAM: info->i = 16; break; + case CPUINFO_INT_ADDRBUS_WIDTH_PROGRAM: info->i = 23; break; + case CPUINFO_INT_ADDRBUS_SHIFT_PROGRAM: info->i = 0; break; + case CPUINFO_INT_DATABUS_WIDTH_DATA: info->i = 0; break; + case CPUINFO_INT_ADDRBUS_WIDTH_DATA: info->i = 0; break; + case CPUINFO_INT_ADDRBUS_SHIFT_DATA: info->i = 0; break; + case CPUINFO_INT_DATABUS_WIDTH_IO: info->i = 0; break; + case CPUINFO_INT_ADDRBUS_WIDTH_IO: info->i = 0; break; + case CPUINFO_INT_ADDRBUS_SHIFT_IO: info->i = 0; break; + + case CPUINFO_INT_REGISTER + UNSP_SP: info->i = UNSP_REG(SP); break; + case CPUINFO_INT_REGISTER + UNSP_R1: info->i = UNSP_REG(R1); break; + case CPUINFO_INT_REGISTER + UNSP_R2: info->i = UNSP_REG(R2); break; + case CPUINFO_INT_REGISTER + UNSP_R3: info->i = UNSP_REG(R3); break; + case CPUINFO_INT_REGISTER + UNSP_R4: info->i = UNSP_REG(R4); break; + case CPUINFO_INT_REGISTER + UNSP_BP: info->i = UNSP_REG(BP); break; + case CPUINFO_INT_REGISTER + UNSP_SR: info->i = UNSP_REG(SR); break; + case CPUINFO_INT_PC: /* Intentional fallthrough */ + case CPUINFO_INT_REGISTER + UNSP_PC: info->i = UNSP_LPC << 1; break; + case CPUINFO_INT_REGISTER + UNSP_IRQ: info->i = unsp->irq; break; + case CPUINFO_INT_REGISTER + UNSP_FIQ: info->i = unsp->fiq; break; + case CPUINFO_INT_REGISTER + UNSP_SB: info->i = unsp->sb; break; + + /* --- the following bits of info are returned as pointers to data or functions --- */ + case CPUINFO_FCT_SET_INFO: info->setinfo = CPU_SET_INFO_NAME(unsp); break; + case CPUINFO_FCT_INIT: info->init = CPU_INIT_NAME(unsp); break; + case CPUINFO_FCT_RESET: info->reset = CPU_RESET_NAME(unsp); break; + case CPUINFO_FCT_EXECUTE: info->execute = CPU_EXECUTE_NAME(unsp); break; + case CPUINFO_FCT_BURN: info->burn = NULL; break; + case CPUINFO_FCT_DISASSEMBLE: info->disassemble = CPU_DISASSEMBLE_NAME(unsp); break; + case CPUINFO_PTR_INSTRUCTION_COUNTER: info->icount = &unsp->icount; break; + + /* --- the following bits of info are returned as NULL-terminated strings --- */ + case DEVINFO_STR_NAME: strcpy(info->s, "u'nSP"); break; + case DEVINFO_STR_FAMILY: strcpy(info->s, "u'nSP"); break; + case DEVINFO_STR_VERSION: strcpy(info->s, "1.0"); break; + case DEVINFO_STR_SOURCE_FILE: strcpy(info->s, __FILE__); break; + case DEVINFO_STR_CREDITS: strcpy(info->s, "Copyright Nicola Salmoria and the MAME Team"); break; + + case CPUINFO_STR_FLAGS: strcpy(info->s, " "); break; + + case CPUINFO_STR_REGISTER + UNSP_SP: sprintf(info->s, "SP: %04x", UNSP_REG(SP)); break; + case CPUINFO_STR_REGISTER + UNSP_R1: sprintf(info->s, "R1: %04x", UNSP_REG(R1)); break; + case CPUINFO_STR_REGISTER + UNSP_R2: sprintf(info->s, "R2: %04x", UNSP_REG(R2)); break; + case CPUINFO_STR_REGISTER + UNSP_R3: sprintf(info->s, "R3: %04x", UNSP_REG(R3)); break; + case CPUINFO_STR_REGISTER + UNSP_R4: sprintf(info->s, "R4: %04x", UNSP_REG(R4)); break; + case CPUINFO_STR_REGISTER + UNSP_BP: sprintf(info->s, "BP: %04x", UNSP_REG(BP)); break; + case CPUINFO_STR_REGISTER + UNSP_SR: sprintf(info->s, "SR: %04x", UNSP_REG(SR)); break; + case CPUINFO_STR_REGISTER + UNSP_PC: sprintf(info->s, "PC: %06x (%06x)", UNSP_LPC, UNSP_LPC << 1); break; + case CPUINFO_STR_REGISTER + UNSP_IRQ: sprintf(info->s, "IRQ: %d", unsp->irq); break; + case CPUINFO_STR_REGISTER + UNSP_FIQ: sprintf(info->s, "FIQ: %d", unsp->fiq); break; + case CPUINFO_STR_REGISTER + UNSP_SB: sprintf(info->s, "SB: %d", unsp->sb); break; + } +} diff --git a/src/emu/cpu/unsp/unsp.h b/src/emu/cpu/unsp/unsp.h new file mode 100644 index 00000000000..cf0961373eb --- /dev/null +++ b/src/emu/cpu/unsp/unsp.h @@ -0,0 +1,72 @@ +/**************************\ +* +* SunPlus u'nSP emulator +* +* by Harmony +* +\**************************/ + +#pragma once + +#ifndef __UNSP_H__ +#define __UNSP_H__ + +typedef struct _unspimp_state unspimp_state; +typedef struct _unsp_state unsp_state; +struct _unsp_state +{ + UINT16 r[16]; + UINT8 irq; + UINT8 fiq; + UINT16 curirq; + UINT16 sirq; + UINT8 sb; + UINT8 saved_sb; + + const device_config *device; + const address_space *program; + int icount; + + unspimp_state *impstate; +}; + +enum +{ + UNSP_SP = 1, + UNSP_R1, + UNSP_R2, + UNSP_R3, + UNSP_R4, + UNSP_BP, + UNSP_SR, + UNSP_PC, + + UNSP_GPR_COUNT = UNSP_PC, + + UNSP_IRQ, + UNSP_FIQ, + UNSP_SB, + +}; + +enum +{ + UNSP_IRQ0_LINE = 0, + UNSP_IRQ1_LINE, + UNSP_IRQ2_LINE, + UNSP_IRQ3_LINE, + UNSP_IRQ4_LINE, + UNSP_IRQ5_LINE, + UNSP_IRQ6_LINE, + UNSP_IRQ7_LINE, + UNSP_FIQ_LINE, + UNSP_BRK_LINE, + + UNSP_NUM_LINES +}; + +CPU_GET_INFO( unsp ); +#define CPU_UNSP CPU_GET_INFO_NAME( unsp ) +CPU_DISASSEMBLE( unsp ); + +#endif /* __UNSP_H__ */ diff --git a/src/emu/cpu/unsp/unspdasm.c b/src/emu/cpu/unsp/unspdasm.c new file mode 100644 index 00000000000..da23ae83da8 --- /dev/null +++ b/src/emu/cpu/unsp/unspdasm.c @@ -0,0 +1,262 @@ +/**************************\ +* +* SunPlus u'nSP disassembler +* +* by Harmony +* +\**************************/ + +#include "emu.h" +#include <stdarg.h> + +static char *output; + +static void ATTR_PRINTF(1,2) print(const char *fmt, ...) +{ + va_list vl; + + va_start(vl, fmt); + vsprintf(output, fmt, vl); + va_end(vl); +} + +/*****************************************************************************/ + +static const char *reg[] = +{ + "sp", "r1", "r2", "r3", "r4", "bp", "sr", "pc" +}; + +static const char *jmp[] = +{ + "jb", "jae", "jge", "jl", "jne", "je", "jpl", "jmi", + "jbe", "ja", "jle", "jg", "jvc", "jvs", "jmp", "<inv>" +}; + +static const char *alu[] = +{ + "add", "adc", "sub", "sbc", + "cmp", "<inv>", "neg", "<inv>", + "xor", "load", "or", "and", + "test", "store", "<inv>", "<inv>" +}; + +/*****************************************************************************/ + +#define OP0 (op >> 12) +#define OPA ((op >> 9) & 7) +#define OP1 ((op >> 6) & 7) +#define OPN ((op >> 3) & 7) +#define OPB (op & 7) +#define OPIMM (op & 0x3f) +#define OP2X ((OP0 < 14 && OP1 == 4 && (OPN >= 1 && OPN <= 3)) || (OP0 == 15 && (OP1 == 1 || OP1 == 2))) + +/*****************************************************************************/ + +#define UNSP_DASM_OK ((2 * (OP2X ? 2 : 1)) | DASMFLAG_SUPPORTED) + +CPU_DISASSEMBLE( unsp ) +{ + UINT16 op = *(UINT16 *)oprom; + UINT16 imm16 = *(UINT16 *)(oprom + 2); + op = BIG_ENDIANIZE_INT16(op); + imm16 = BIG_ENDIANIZE_INT16(imm16); + + output = buffer; + + print("<inv>"); + + if(OP0 < 0xf && OPA == 0x7 && OP1 < 2) + { + print("%s %04x", jmp[OP0], OP1 ? (pc - OPIMM*2) : (pc + OPIMM*2)); + return UNSP_DASM_OK; + } + + switch((OP1 << 4) | OP0) + { + // ALU, Indexed + case 0x00: case 0x01: case 0x02: case 0x03: case 0x04: case 0x06: case 0x08: case 0x09: case 0x0a: case 0x0b: case 0x0c: case 0x0d: + print("%s %s, [bp+%02x]", alu[OP0], reg[OPA], OPIMM); + return UNSP_DASM_OK; + + // ALU, Immediate + case 0x10: case 0x11: case 0x12: case 0x13: case 0x14: case 0x16: case 0x18: case 0x19: case 0x1a: case 0x1b: case 0x1c: + print("%s %s, %02x", alu[OP0], reg[OPA], OPIMM); + return UNSP_DASM_OK; + + // Pop / Interrupt return + case 0x29: + if(op == 0x9a90) + { + print("retf"); + return UNSP_DASM_OK; + } + else if(op == 0x9a98) + { + print("reti"); + return UNSP_DASM_OK; + } + else if((OPA + 1) < 8 && ((OPA + OPN) < 8)) + { + print("pop %s, %s [%s]", reg[OPA+1], reg[OPA+OPN], reg[OPB]); + return UNSP_DASM_OK; + } + break; + + // Push + case 0x2d: + if((OPA + 1) >= OPN && OPA < (OPN + 7)) + { + print("push %s, %s [%s]", reg[(OPA+1)-OPN], reg[OPA], reg[OPB]); + return UNSP_DASM_OK; + } + break; + + // 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) + { + case 0: + print("%s %s, [%s%s]", alu[OP0], reg[OPA], (OPN & 4) ? "ds:" : "", reg[OPB]); + return UNSP_DASM_OK; + case 1: + print("%s %s, [%s%s--]", alu[OP0], reg[OPA], (OPN & 4) ? "ds:" : "", reg[OPB]); + return UNSP_DASM_OK; + case 2: + print("%s %s, [%s%s++]", alu[OP0], reg[OPA], (OPN & 4) ? "ds:" : "", reg[OPB]); + return UNSP_DASM_OK; + case 3: + print("%s %s, [%s++%s]", alu[OP0], reg[OPA], (OPN & 4) ? "ds:" : "", reg[OPB]); + return UNSP_DASM_OK; + } + return UNSP_DASM_OK; + + // 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) + { + // ALU, Register + case 0: + print("%s %s, %s", alu[OP0], reg[OPA], reg[OPB]); + return UNSP_DASM_OK; + + // ALU, 16-bit Immediate + case 1: + if(!((OP0 == 4 || OP0 == 6 || OP0 == 9 || OP0 == 12) && OPA != OPB)) + { + if(OP0 != 4 && OP0 != 12) + { + print("%s %s, %s, %04x", alu[OP0], reg[OPA], reg[OPB], imm16); + return UNSP_DASM_OK; + } + else + { + print("%s %s, %04x", alu[OP0], reg[OPB], imm16); + return UNSP_DASM_OK; + } + } + break; + + // ALU, Direct 16 + case 2: + print("%s %s, [%04x]", alu[OP0], reg[OPA], imm16); + return UNSP_DASM_OK; + + // ALU, Direct 16 + case 3: + print("%s [%04x], %s, %s", alu[OP0], imm16, reg[OPA], reg[OPB]); + return UNSP_DASM_OK; + + // ALU, Shifted + default: + print("%s %s, %s asr %d", alu[OP0], reg[OPA], reg[OPB], (OPN & 3) + 1); + return UNSP_DASM_OK; + } + case 0x4d: + if(OPN == 3) + { + if(OPA == OPB) + { + print("store [%04x], %s", imm16, reg[OPB]); + } + } + return UNSP_DASM_OK; + + // ALU, Shifted + case 0x50: case 0x51: case 0x52: case 0x53: case 0x54: case 0x56: case 0x58: case 0x59: case 0x5a: case 0x5b: case 0x5c: + print("%s %s, %s %s %d", alu[OP0], reg[OPA], reg[OPB], (OPN & 4) ? ">>" : "<<", (OPN & 3) + 1); + return UNSP_DASM_OK; + + // ALU, Rotated + case 0x60: case 0x61: case 0x62: case 0x63: case 0x64: case 0x66: case 0x68: case 0x69: case 0x6a: case 0x6b: case 0x6c: + print("%s %s, %s %s %d", alu[OP0], reg[OPA], reg[OPB], (OPN & 4) ? "ror" : "rol", (OPN & 3) + 1); + return UNSP_DASM_OK; + + // 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); + return UNSP_DASM_OK; + + // Call + case 0x1f: + if(OPA == 0) + { + print("call %06x", ((OPIMM << 16) | imm16) << 1); + } + return UNSP_DASM_OK; + + // Multiply, Unsigned * Signed + case 0x0f: + if(OPN == 1 && OPA != 7) + { + print("mulus %s, %s", reg[OPA], reg[OPB]); + } + return UNSP_DASM_OK; + + // Multiply, Signed * Signed + case 0x4f: + if(OPN == 1 && OPA != 7) + { + print("mulss %s, %s", reg[OPA], reg[OPB]); + } + return UNSP_DASM_OK; + + // Interrupt flags + case 0x5f: + if(OPA == 0) + { + switch(OPIMM) + { + case 0: + print("int off"); + break; + case 1: + print("int irq"); + break; + case 2: + print("int fiq"); + break; + case 3: + print("int irq,fiq"); + break; + case 8: + print("irq off"); + break; + case 9: + print("irq on"); + break; + case 12: + print("fiq off"); + break; + case 14: + print("fiq on"); + break; + case 37: + print("nop"); + break; + } + } + return UNSP_DASM_OK; + } + return UNSP_DASM_OK; +} |