unsp.c: Modernized cpu core. [Wilbert Pol]

This commit is contained in:
Wilbert Pol 2013-12-29 18:01:08 +00:00
parent e1d321eb6b
commit 491451cf26
2 changed files with 261 additions and 279 deletions

View File

@ -10,14 +10,23 @@
#include "debugger.h" #include "debugger.h"
#include "unsp.h" #include "unsp.h"
INLINE unsp_state *get_safe_token(device_t *device)
const device_type UNSP = &device_creator<unsp_device>;
unsp_device::unsp_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
: cpu_device(mconfig, UNSP, "u'nSP", tag, owner, clock, "unsp", __FILE__)
, m_program_config("program", ENDIANNESS_BIG, 16, 23, 0)
{ {
assert(device != NULL);
assert(device->type() == UNSP);
return (unsp_state *)downcast<legacy_cpu_device *>(device)->token();
} }
static void unsp_set_irq_line(unsp_state *unsp, int irqline, int state);
offs_t unsp_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options)
{
extern CPU_DISASSEMBLE( unsp );
return CPU_DISASSEMBLE_NAME(unsp)(this, buffer, pc, oprom, opram, options);
}
/*****************************************************************************/ /*****************************************************************************/
@ -30,8 +39,8 @@ static void unsp_set_irq_line(unsp_state *unsp, int irqline, int state);
#define UNSP_LPC (((UNSP_REG(SR) & 0x3f) << 16) | UNSP_REG(PC)) #define UNSP_LPC (((UNSP_REG(SR) & 0x3f) << 16) | UNSP_REG(PC))
#define UNSP_REG(reg) unsp->r[UNSP_##reg - 1] #define UNSP_REG(reg) m_r[UNSP_##reg - 1]
#define UNSP_REG_I(reg) unsp->r[reg] #define UNSP_REG_I(reg) m_r[reg]
#define UNSP_LREG_I(reg) (((UNSP_REG(SR) << 6) & 0x3f0000) | UNSP_REG_I(reg)) #define UNSP_LREG_I(reg) (((UNSP_REG(SR) << 6) & 0x3f0000) | UNSP_REG_I(reg))
#define UNSP_N 0x0200 #define UNSP_N 0x0200
@ -42,43 +51,43 @@ static void unsp_set_irq_line(unsp_state *unsp, int irqline, int state);
#define STANDARD_ALU_CASES \ #define STANDARD_ALU_CASES \
case 0: \ case 0: \
lres = r0 + r1; \ lres = r0 + r1; \
unsp_update_nzsc(unsp, lres, r0, r1); \ unsp_update_nzsc(lres, r0, r1); \
break; \ break; \
case 1: \ case 1: \
lres = r0 + r1; \ lres = r0 + r1; \
if(UNSP_REG(SR) & UNSP_C) lres++; \ if(UNSP_REG(SR) & UNSP_C) lres++; \
unsp_update_nzsc(unsp, lres, r0, r1); \ unsp_update_nzsc(lres, r0, r1); \
break; \ break; \
case 3: \ case 3: \
lres = r0 + (~r1 & 0x0000ffff); \ lres = r0 + (~r1 & 0x0000ffff); \
if(UNSP_REG(SR) & UNSP_C) lres++; \ if(UNSP_REG(SR) & UNSP_C) lres++; \
unsp_update_nzsc(unsp, lres, r0, r1); \ unsp_update_nzsc(lres, r0, r1); \
break; \ break; \
case 2: \ case 2: \
case 4: \ case 4: \
lres = r0 + (~r1 & 0x0000ffff) + 1; \ lres = r0 + (~r1 & 0x0000ffff) + 1; \
unsp_update_nzsc(unsp, lres, r0, r1); \ unsp_update_nzsc(lres, r0, r1); \
break; \ break; \
case 6: \ case 6: \
lres = -r1; \ lres = -r1; \
unsp_update_nz(unsp, lres); \ unsp_update_nz(lres); \
break; \ break; \
case 8: \ case 8: \
lres = r0 ^ r1; \ lres = r0 ^ r1; \
unsp_update_nz(unsp, lres); \ unsp_update_nz(lres); \
break; \ break; \
case 9: \ case 9: \
lres = r1; \ lres = r1; \
unsp_update_nz(unsp, lres); \ unsp_update_nz(lres); \
break; \ break; \
case 10: \ case 10: \
lres = r0 | r1; \ lres = r0 | r1; \
unsp_update_nz(unsp, lres); \ unsp_update_nz(lres); \
break; \ break; \
case 11: \ case 11: \
case 12: \ case 12: \
lres = r0 & r1; \ lres = r0 & r1; \
unsp_update_nz(unsp, lres); \ unsp_update_nz(lres); \
break break
#define WRITEBACK_OPA \ #define WRITEBACK_OPA \
@ -89,47 +98,91 @@ static void unsp_set_irq_line(unsp_state *unsp, int irqline, int state);
/*****************************************************************************/ /*****************************************************************************/
static void unimplemented_opcode(unsp_state *unsp, UINT16 op) void unsp_device::unimplemented_opcode(UINT16 op)
{ {
fatalerror("UNSP: unknown opcode %04x at %04x\n", op, UNSP_LPC << 1); fatalerror("UNSP: unknown opcode %04x at %04x\n", op, UNSP_LPC << 1);
} }
/*****************************************************************************/ /*****************************************************************************/
INLINE UINT16 READ16(unsp_state *unsp, UINT32 address) UINT16 unsp_device::READ16(UINT32 address)
{ {
return unsp->program->read_word(address << 1); return m_program->read_word(address << 1);
} }
INLINE void WRITE16(unsp_state *unsp, UINT32 address, UINT16 data) void unsp_device::WRITE16(UINT32 address, UINT16 data)
{ {
unsp->program->write_word(address << 1, data); m_program->write_word(address << 1, data);
} }
/*****************************************************************************/ /*****************************************************************************/
static CPU_INIT( unsp ) void unsp_device::device_start()
{ {
unsp_state *unsp = get_safe_token(device); memset(m_r, 0, sizeof(UINT16) * UNSP_GPR_COUNT);
memset(unsp->r, 0, sizeof(UINT16) * UNSP_GPR_COUNT); m_irq = 0;
m_fiq = 0;
m_curirq = 0;
m_sirq = 0;
m_sb = 0;
m_saved_sb = 0;
unsp->device = device; m_program = &space(AS_PROGRAM);
unsp->program = &device->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(STATE_GENPC, "GENPC", m_debugger_temp).callexport().noshow();
m_icountptr = &m_icount;
} }
static CPU_RESET( unsp ) void unsp_device::state_export(const device_state_entry &entry)
{ {
unsp_state *unsp = get_safe_token(device); switch (entry.index())
memset(unsp->r, 0, sizeof(UINT16) * UNSP_GPR_COUNT); {
case UNSP_PC:
m_debugger_temp = UNSP_LPC << 1;
break;
UNSP_REG(PC) = READ16(unsp, 0xfff7); case STATE_GENPC:
unsp->irq = 0; m_debugger_temp = UNSP_LPC << 1;
unsp->fiq = 0; break;
}
}
void unsp_device::state_import(const device_state_entry &entry)
{
switch (entry.index())
{
case UNSP_PC:
UNSP_REG(PC) = (m_debugger_temp & 0x0001fffe) >> 1;
UNSP_REG(SR) = (UNSP_REG(SR) & 0xffc0) | ((m_debugger_temp & 0x007e0000) >> 17);
break;
}
}
void unsp_device::device_reset()
{
memset(m_r, 0, sizeof(UINT16) * UNSP_GPR_COUNT);
UNSP_REG(PC) = READ16(0xfff7);
m_irq = 0;
m_fiq = 0;
} }
/*****************************************************************************/ /*****************************************************************************/
static void unsp_update_nz(unsp_state *unsp, UINT32 value) void unsp_device::unsp_update_nz(UINT32 value)
{ {
UNSP_REG(SR) &= ~(UNSP_N | UNSP_Z); UNSP_REG(SR) &= ~(UNSP_N | UNSP_Z);
if(value & 0x8000) if(value & 0x8000)
@ -142,10 +195,10 @@ static void unsp_update_nz(unsp_state *unsp, UINT32 value)
} }
} }
static void unsp_update_nzsc(unsp_state *unsp, UINT32 value, UINT16 r0, UINT16 r1) void unsp_device::unsp_update_nzsc(UINT32 value, UINT16 r0, UINT16 r1)
{ {
UNSP_REG(SR) &= ~(UNSP_C | UNSP_S); UNSP_REG(SR) &= ~(UNSP_C | UNSP_S);
unsp_update_nz(unsp, value); unsp_update_nz(value);
if(value != (UINT16)value) if(value != (UINT16)value)
{ {
UNSP_REG(SR) |= UNSP_C; UNSP_REG(SR) |= UNSP_C;
@ -157,29 +210,28 @@ static void unsp_update_nzsc(unsp_state *unsp, UINT32 value, UINT16 r0, UINT16 r
} }
} }
static void unsp_push(unsp_state *unsp, UINT16 value, UINT16 *reg) void unsp_device::unsp_push(UINT16 value, UINT16 *reg)
{ {
WRITE16(unsp, (*reg)--, value); WRITE16((*reg)--, value);
} }
static UINT16 unsp_pop(unsp_state *unsp, UINT16 *reg) UINT16 unsp_device::unsp_pop(UINT16 *reg)
{ {
return READ16(unsp, ++(*reg)); return READ16(++(*reg));
} }
static CPU_EXECUTE( unsp ) void unsp_device::execute_run()
{ {
unsp_state *unsp = get_safe_token(device);
UINT32 op; UINT32 op;
UINT32 lres; UINT32 lres;
UINT16 r0, r1; UINT16 r0, r1;
lres = 0; lres = 0;
while (unsp->icount > 0) while (m_icount > 0)
{ {
debugger_instruction_hook(device, UNSP_LPC<<1); debugger_instruction_hook(this, UNSP_LPC<<1);
op = READ16(unsp, UNSP_LPC); op = READ16(UNSP_LPC);
UNSP_REG(PC)++; UNSP_REG(PC)++;
@ -271,15 +323,15 @@ static CPU_EXECUTE( unsp )
// r, [bp+imm6] // 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: 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); r0 = UNSP_REG_I(OPA);
r1 = READ16(unsp, UNSP_REG(BP) + OPIMM); r1 = READ16(UNSP_REG(BP) + OPIMM);
switch(OP0) switch(OP0)
{ {
STANDARD_ALU_CASES; STANDARD_ALU_CASES;
case 13: // store r, [bp+imm6] case 13: // store r, [bp+imm6]
WRITE16(unsp, UNSP_REG(BP) + OPIMM, UNSP_REG_I(OPA)); WRITE16(UNSP_REG(BP) + OPIMM, UNSP_REG_I(OPA));
break; break;
default: default:
unimplemented_opcode(unsp, op); unimplemented_opcode(op);
break; break;
} }
WRITEBACK_OPA; WRITEBACK_OPA;
@ -293,7 +345,7 @@ static CPU_EXECUTE( unsp )
{ {
STANDARD_ALU_CASES; STANDARD_ALU_CASES;
default: default:
unimplemented_opcode(unsp, op); unimplemented_opcode(op);
break; break;
} }
WRITEBACK_OPA; WRITEBACK_OPA;
@ -303,38 +355,38 @@ static CPU_EXECUTE( unsp )
case 0x29: case 0x29:
if(op == 0x9a90) // retf if(op == 0x9a90) // retf
{ {
UNSP_REG(SR) = unsp_pop(unsp, &UNSP_REG(SP)); UNSP_REG(SR) = unsp_pop(&UNSP_REG(SP));
UNSP_REG(PC) = unsp_pop(unsp, &UNSP_REG(SP)); UNSP_REG(PC) = unsp_pop(&UNSP_REG(SP));
break; break;
} }
else if(op == 0x9a98) // reti else if(op == 0x9a98) // reti
{ {
int i; int i;
UNSP_REG(SR) = unsp_pop(unsp, &UNSP_REG(SP)); UNSP_REG(SR) = unsp_pop(&UNSP_REG(SP));
UNSP_REG(PC) = unsp_pop(unsp, &UNSP_REG(SP)); UNSP_REG(PC) = unsp_pop(&UNSP_REG(SP));
if(unsp->fiq & 2) if(m_fiq & 2)
{ {
unsp->fiq &= 1; m_fiq &= 1;
} }
else if(unsp->irq & 2) else if(m_irq & 2)
{ {
unsp->irq &= 1; m_irq &= 1;
} }
unsp->sirq &= ~(1 << unsp->curirq); m_sirq &= ~(1 << m_curirq);
for(i = 0; i < 9; i++) for(i = 0; i < 9; i++)
{ {
if((unsp->sirq & (1 << i)) != 0 && i != unsp->curirq) if((m_sirq & (1 << i)) != 0 && i != m_curirq)
{ {
unsp->sirq &= ~(1 << i); m_sirq &= ~(1 << i);
unsp->curirq = 0; m_curirq = 0;
unsp_set_irq_line(unsp, UNSP_IRQ0_LINE + i, 1); execute_set_input(UNSP_IRQ0_LINE + i, 1);
i = -1; i = -1;
break; break;
} }
} }
if(i != -1) if(i != -1)
{ {
unsp->curirq = 0; m_curirq = 0;
} }
break; break;
} }
@ -344,7 +396,7 @@ static CPU_EXECUTE( unsp )
r1 = OPA; r1 = OPA;
while(r0--) while(r0--)
{ {
UNSP_REG_I(++r1) = unsp_pop(unsp, &UNSP_REG_I(OPB)); UNSP_REG_I(++r1) = unsp_pop(&UNSP_REG_I(OPB));
} }
} }
break; break;
@ -355,7 +407,7 @@ static CPU_EXECUTE( unsp )
r1 = OPA; r1 = OPA;
while(r0--) while(r0--)
{ {
unsp_push(unsp, UNSP_REG_I(r1--), &UNSP_REG_I(OPB)); unsp_push(UNSP_REG_I(r1--), &UNSP_REG_I(OPB));
} }
break; break;
@ -365,30 +417,30 @@ static CPU_EXECUTE( unsp )
{ {
case 0: // r, [r] case 0: // r, [r]
r0 = UNSP_REG_I(OPA); r0 = UNSP_REG_I(OPA);
r1 = READ16(unsp, (OPN & 4) ? UNSP_LREG_I(OPB) : UNSP_REG_I(OPB)); r1 = READ16((OPN & 4) ? UNSP_LREG_I(OPB) : UNSP_REG_I(OPB));
switch(OP0) switch(OP0)
{ {
STANDARD_ALU_CASES; STANDARD_ALU_CASES;
case 13: // store r, [r] case 13: // store r, [r]
WRITE16(unsp, (OPN & 4) ? UNSP_LREG_I(OPB) : UNSP_REG_I(OPB), UNSP_REG_I(OPA)); WRITE16((OPN & 4) ? UNSP_LREG_I(OPB) : UNSP_REG_I(OPB), UNSP_REG_I(OPA));
break; break;
default: default:
unimplemented_opcode(unsp, op); unimplemented_opcode(op);
break; break;
} }
WRITEBACK_OPA; WRITEBACK_OPA;
break; break;
case 1: // r, [<ds:>r--] case 1: // r, [<ds:>r--]
r0 = UNSP_REG_I(OPA); r0 = UNSP_REG_I(OPA);
r1 = READ16(unsp, (OPN & 4) ? UNSP_LREG_I(OPB) : UNSP_REG_I(OPB)); r1 = READ16((OPN & 4) ? UNSP_LREG_I(OPB) : UNSP_REG_I(OPB));
switch(OP0) switch(OP0)
{ {
STANDARD_ALU_CASES; STANDARD_ALU_CASES;
case 13: // store r, [<ds:>r--] case 13: // store r, [<ds:>r--]
WRITE16(unsp, (OPN & 4) ? UNSP_LREG_I(OPB) : UNSP_REG_I(OPB), UNSP_REG_I(OPA)); WRITE16((OPN & 4) ? UNSP_LREG_I(OPB) : UNSP_REG_I(OPB), UNSP_REG_I(OPA));
break; break;
default: default:
unimplemented_opcode(unsp, op); unimplemented_opcode(op);
break; break;
} }
UNSP_REG_I(OPB)--; UNSP_REG_I(OPB)--;
@ -396,15 +448,15 @@ static CPU_EXECUTE( unsp )
break; break;
case 2: // r, [<ds:>r++] case 2: // r, [<ds:>r++]
r0 = UNSP_REG_I(OPA); r0 = UNSP_REG_I(OPA);
r1 = READ16(unsp, (OPN & 4) ? UNSP_LREG_I(OPB) : UNSP_REG_I(OPB)); r1 = READ16((OPN & 4) ? UNSP_LREG_I(OPB) : UNSP_REG_I(OPB));
switch(OP0) switch(OP0)
{ {
STANDARD_ALU_CASES; STANDARD_ALU_CASES;
case 13: // store r, [<ds:>r++] case 13: // store r, [<ds:>r++]
WRITE16(unsp, (OPN & 4) ? UNSP_LREG_I(OPB) : UNSP_REG_I(OPB), UNSP_REG_I(OPA)); WRITE16((OPN & 4) ? UNSP_LREG_I(OPB) : UNSP_REG_I(OPB), UNSP_REG_I(OPA));
break; break;
default: default:
unimplemented_opcode(unsp, op); unimplemented_opcode(op);
break; break;
} }
UNSP_REG_I(OPB)++; UNSP_REG_I(OPB)++;
@ -413,12 +465,12 @@ static CPU_EXECUTE( unsp )
case 3: // r, [<ds:>++r] case 3: // r, [<ds:>++r]
UNSP_REG_I(OPB)++; UNSP_REG_I(OPB)++;
r0 = UNSP_REG_I(OPA); r0 = UNSP_REG_I(OPA);
r1 = READ16(unsp, (OPN & 4) ? UNSP_LREG_I(OPB) : UNSP_REG_I(OPB)); r1 = READ16((OPN & 4) ? UNSP_LREG_I(OPB) : UNSP_REG_I(OPB));
switch(OP0) switch(OP0)
{ {
STANDARD_ALU_CASES; STANDARD_ALU_CASES;
default: default:
unimplemented_opcode(unsp, op); unimplemented_opcode(op);
break; break;
} }
WRITEBACK_OPA; WRITEBACK_OPA;
@ -438,7 +490,7 @@ static CPU_EXECUTE( unsp )
{ {
STANDARD_ALU_CASES; STANDARD_ALU_CASES;
default: default:
unimplemented_opcode(unsp, op); unimplemented_opcode(op);
break; break;
} }
WRITEBACK_OPA; WRITEBACK_OPA;
@ -449,33 +501,33 @@ static CPU_EXECUTE( unsp )
if(!((OP0 == 4 || OP0 == 6 || OP0 == 9 || OP0 == 12) && OPA != OPB)) if(!((OP0 == 4 || OP0 == 6 || OP0 == 9 || OP0 == 12) && OPA != OPB))
{ {
r0 = UNSP_REG_I(OPB); r0 = UNSP_REG_I(OPB);
r1 = READ16(unsp, UNSP_LPC); r1 = READ16(UNSP_LPC);
UNSP_REG(PC)++; UNSP_REG(PC)++;
switch(OP0) switch(OP0)
{ {
STANDARD_ALU_CASES; STANDARD_ALU_CASES;
default: default:
unimplemented_opcode(unsp, op); unimplemented_opcode(op);
break; break;
} }
WRITEBACK_OPA; WRITEBACK_OPA;
} }
else else
{ {
unimplemented_opcode(unsp, op); unimplemented_opcode(op);
} }
break; break;
// ALU, Direct 16 // ALU, Direct 16
case 2: // r, [imm16] case 2: // r, [imm16]
r0 = UNSP_REG_I(OPB); r0 = UNSP_REG_I(OPB);
r1 = READ16(unsp, READ16(unsp, UNSP_LPC)); r1 = READ16(READ16(UNSP_LPC));
UNSP_REG(PC)++; UNSP_REG(PC)++;
switch(OP0) switch(OP0)
{ {
STANDARD_ALU_CASES; STANDARD_ALU_CASES;
default: default:
unimplemented_opcode(unsp, op); unimplemented_opcode(op);
break; break;
} }
WRITEBACK_OPA; WRITEBACK_OPA;
@ -489,12 +541,12 @@ static CPU_EXECUTE( unsp )
{ {
STANDARD_ALU_CASES; STANDARD_ALU_CASES;
default: default:
unimplemented_opcode(unsp, op); unimplemented_opcode(op);
break; break;
} }
if(OP0 != 4 && OP0 < 12) if(OP0 != 4 && OP0 < 12)
{ {
WRITE16(unsp, READ16(unsp, UNSP_LPC), (UINT16)lres); WRITE16(READ16(UNSP_LPC), (UINT16)lres);
} }
UNSP_REG(PC)++; UNSP_REG(PC)++;
break; break;
@ -502,23 +554,23 @@ static CPU_EXECUTE( unsp )
// ALU, Shifted // ALU, Shifted
default: default:
{ {
UINT32 shift = (UNSP_REG_I(OPB) << 4) | unsp->sb; UINT32 shift = (UNSP_REG_I(OPB) << 4) | m_sb;
if(shift & 0x80000) if(shift & 0x80000)
{ {
shift |= 0xf00000; shift |= 0xf00000;
} }
shift >>= (OPN - 3); shift >>= (OPN - 3);
unsp->sb = shift & 0x0f; m_sb = shift & 0x0f;
r1 = (shift >> 4) & 0x0000ffff; r1 = (shift >> 4) & 0x0000ffff;
switch(OP0) switch(OP0)
{ {
case 9: // load r, r asr n case 9: // load r, r asr n
unsp_update_nz(unsp, r1); unsp_update_nz(r1);
UNSP_REG_I(OPA) = r1; UNSP_REG_I(OPA) = r1;
break; break;
default: default:
unimplemented_opcode(unsp, op); unimplemented_opcode(op);
break; break;
} }
break; break;
@ -531,17 +583,17 @@ static CPU_EXECUTE( unsp )
{ {
if(OPA == OPB) if(OPA == OPB)
{ {
WRITE16(unsp, READ16(unsp, UNSP_LPC), UNSP_REG_I(OPB)); WRITE16(READ16(UNSP_LPC), UNSP_REG_I(OPB));
UNSP_REG(PC)++; UNSP_REG(PC)++;
} }
else else
{ {
unimplemented_opcode(unsp, op); unimplemented_opcode(op);
} }
} }
else else
{ {
unimplemented_opcode(unsp, op); unimplemented_opcode(op);
} }
break; break;
@ -552,20 +604,20 @@ static CPU_EXECUTE( unsp )
switch(OP0) switch(OP0)
{ {
case 9: // load r, r >> imm2 case 9: // load r, r >> imm2
lres = ((UNSP_REG_I(OPB) << 4) | unsp->sb) >> (OPN - 3); lres = ((UNSP_REG_I(OPB) << 4) | m_sb) >> (OPN - 3);
unsp->sb = lres & 0x0f; m_sb = lres & 0x0f;
unsp_update_nz(unsp, (UINT16)(lres >> 4)); unsp_update_nz((UINT16)(lres >> 4));
UNSP_REG_I(OPA) = (UINT16)(lres >> 4); UNSP_REG_I(OPA) = (UINT16)(lres >> 4);
break; break;
default: default:
unimplemented_opcode(unsp, op); unimplemented_opcode(op);
break; break;
} }
} }
else else
{ {
UINT32 shift = ((unsp->sb << 16) | UNSP_REG_I(OPB)) << (OPN + 1); UINT32 shift = ((m_sb << 16) | UNSP_REG_I(OPB)) << (OPN + 1);
unsp->sb = (shift >> 16) & 0x0f; m_sb = (shift >> 16) & 0x0f;
r0 = UNSP_REG_I(OPA); r0 = UNSP_REG_I(OPA);
r1 = shift & 0x0000ffff; r1 = shift & 0x0000ffff;
@ -573,21 +625,21 @@ static CPU_EXECUTE( unsp )
{ {
case 0: // add r, r << imm2 case 0: // add r, r << imm2
lres = r0 + r1; lres = r0 + r1;
unsp_update_nzsc(unsp, lres, r0, r1); unsp_update_nzsc(lres, r0, r1);
UNSP_REG_I(OPA) = (UINT16)lres; UNSP_REG_I(OPA) = (UINT16)lres;
break; break;
case 9: // load r, r << imm2 case 9: // load r, r << imm2
lres = r1; lres = r1;
unsp_update_nz(unsp, lres); unsp_update_nz(lres);
UNSP_REG_I(OPA) = (UINT16)lres; UNSP_REG_I(OPA) = (UINT16)lres;
break; break;
case 10: // or r, r << imm2 case 10: // or r, r << imm2
lres = r0 | r1; lres = r0 | r1;
unsp_update_nz(unsp, lres); unsp_update_nz(lres);
UNSP_REG_I(OPA) = (UINT16)lres; UNSP_REG_I(OPA) = (UINT16)lres;
break; break;
default: default:
unimplemented_opcode(unsp, op); unimplemented_opcode(op);
break; break;
} }
} }
@ -597,25 +649,25 @@ static CPU_EXECUTE( unsp )
case 0x60: case 0x61: case 0x62: case 0x63: case 0x64: case 0x66: case 0x68: case 0x69: case 0x6a: case 0x6b: case 0x6c: 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 if(OPN & 4) // ROR
{ {
lres = ((((unsp->sb << 16) | UNSP_REG_I(OPB)) << 4) | unsp->sb) >> (OPN - 3); lres = ((((m_sb << 16) | UNSP_REG_I(OPB)) << 4) | m_sb) >> (OPN - 3);
unsp->sb = lres & 0x0f; m_sb = lres & 0x0f;
r1 = (UINT16)(lres >> 4); r1 = (UINT16)(lres >> 4);
} }
else else
{ {
lres = ((((unsp->sb << 16) | UNSP_REG_I(OPB)) << 4) | unsp->sb) << (OPN + 1); lres = ((((m_sb << 16) | UNSP_REG_I(OPB)) << 4) | m_sb) << (OPN + 1);
unsp->sb = (lres >> 20) & 0x0f; m_sb = (lres >> 20) & 0x0f;
r1 = (UINT16)(lres >> 4); r1 = (UINT16)(lres >> 4);
} }
switch(OP0) switch(OP0)
{ {
case 9: // load r, r ror imm2 case 9: // load r, r ror imm2
unsp_update_nz(unsp, r1); unsp_update_nz(r1);
UNSP_REG_I(OPA) = r1; UNSP_REG_I(OPA) = r1;
break; break;
default: default:
unimplemented_opcode(unsp, op); unimplemented_opcode(op);
break; break;
} }
break; break;
@ -623,24 +675,24 @@ static CPU_EXECUTE( unsp )
// ALU, Direct 8 // 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: 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); //print("%s %s, [%02x]", alu[OP0], reg[OPA], OPIMM);
unimplemented_opcode(unsp, op); unimplemented_opcode(op);
break; break;
// Call // Call
case 0x1f: case 0x1f:
if(OPA == 0) if(OPA == 0)
{ {
r1 = READ16(unsp, UNSP_LPC); r1 = READ16(UNSP_LPC);
UNSP_REG(PC)++; UNSP_REG(PC)++;
unsp_push(unsp, UNSP_REG(PC), &UNSP_REG(SP)); unsp_push(UNSP_REG(PC), &UNSP_REG(SP));
unsp_push(unsp, UNSP_REG(SR), &UNSP_REG(SP)); unsp_push(UNSP_REG(SR), &UNSP_REG(SP));
UNSP_REG(PC) = r1; UNSP_REG(PC) = r1;
UNSP_REG(SR) &= 0xffc0; UNSP_REG(SR) &= 0xffc0;
UNSP_REG(SR) |= OPIMM; UNSP_REG(SR) |= OPIMM;
} }
else else
{ {
unimplemented_opcode(unsp, op); unimplemented_opcode(op);
} }
break; break;
@ -648,7 +700,7 @@ static CPU_EXECUTE( unsp )
case 0x2f: case 0x3f: case 0x6f: case 0x7f: case 0x2f: case 0x3f: case 0x6f: case 0x7f:
if (OPA == 7 && OP1 == 2) if (OPA == 7 && OP1 == 2)
{ {
UNSP_REG(PC) = READ16(unsp, UNSP_LPC); UNSP_REG(PC) = READ16(UNSP_LPC);
UNSP_REG(SR) &= 0xffc0; UNSP_REG(SR) &= 0xffc0;
UNSP_REG(SR) |= OPIMM; UNSP_REG(SR) |= OPIMM;
} }
@ -669,7 +721,7 @@ static CPU_EXECUTE( unsp )
} }
else else
{ {
unimplemented_opcode(unsp, op); unimplemented_opcode(op);
} }
break; break;
@ -692,7 +744,7 @@ static CPU_EXECUTE( unsp )
} }
else else
{ {
unimplemented_opcode(unsp, op); unimplemented_opcode(op);
} }
break; break;
@ -703,32 +755,32 @@ static CPU_EXECUTE( unsp )
switch(OPIMM) switch(OPIMM)
{ {
case 0: case 0:
unsp->irq &= ~1; m_irq &= ~1;
unsp->fiq &= ~1; m_fiq &= ~1;
break; break;
case 1: case 1:
unsp->irq |= 1; m_irq |= 1;
unsp->fiq &= ~1; m_fiq &= ~1;
break; break;
case 2: case 2:
unsp->irq &= ~1; m_irq &= ~1;
unsp->fiq |= 1; m_fiq |= 1;
break; break;
case 3: case 3:
unsp->irq |= 1; m_irq |= 1;
unsp->fiq |= 1; m_fiq |= 1;
break; break;
case 8: // irq off case 8: // irq off
unsp->irq &= ~1; m_irq &= ~1;
break; break;
case 9: // irq on case 9: // irq on
unsp->irq |= 1; m_irq |= 1;
break; break;
case 12: // fiq off case 12: // fiq off
unsp->fiq &= ~1; m_fiq &= ~1;
break; break;
case 13: // fiq on case 13: // fiq on
unsp->fiq |= 1; m_fiq |= 1;
break; break;
case 37: // nop case 37: // nop
break; break;
@ -736,29 +788,29 @@ static CPU_EXECUTE( unsp )
} }
else else
{ {
unimplemented_opcode(unsp, op); unimplemented_opcode(op);
} }
break; break;
} }
} }
unsp->icount -= 5; m_icount -= 5;
unsp->icount = MAX(unsp->icount, 0); m_icount = MAX(m_icount, 0);
} }
} }
/*****************************************************************************/ /*****************************************************************************/
static void unsp_set_irq_line(unsp_state *unsp, int irqline, int state) void unsp_device::execute_set_input(int irqline, int state)
{ {
UINT16 irq_vector = 0; UINT16 irq_vector = 0;
unsp->sirq &= ~(1 << irqline); m_sirq &= ~(1 << irqline);
if(!state) if(!state)
{ {
logerror("clearing irq %d (%04x, %04x)\n", irqline, unsp->sirq, unsp->curirq); logerror("clearing irq %d (%04x, %04x)\n", irqline, m_sirq, m_curirq);
return; return;
} }
@ -772,154 +824,43 @@ static void unsp_set_irq_line(unsp_state *unsp, int irqline, int state)
case UNSP_IRQ5_LINE: case UNSP_IRQ5_LINE:
case UNSP_IRQ6_LINE: case UNSP_IRQ6_LINE:
case UNSP_IRQ7_LINE: case UNSP_IRQ7_LINE:
if(unsp->fiq & 2) if(m_fiq & 2)
{ {
// FIQ is being serviced, ignore this IRQ trigger. // FIQ is being serviced, ignore this IRQ trigger.
unsp->sirq |= state << irqline; m_sirq |= state << irqline;
return; return;
} }
if(unsp->irq != 1) if(m_irq != 1)
{ {
// IRQ is disabled, ignore this IRQ trigger. // IRQ is disabled, ignore this IRQ trigger.
unsp->sirq |= state << irqline; m_sirq |= state << irqline;
return; return;
} }
unsp->irq |= 2; m_irq |= 2;
unsp->curirq |= (1 << irqline); m_curirq |= (1 << irqline);
logerror("taking irq %d (%04x, %04x)\n", irqline, unsp->sirq, unsp->curirq); logerror("taking irq %d (%04x, %04x)\n", irqline, m_sirq, m_curirq);
irq_vector = 0xfff8 + (irqline - UNSP_IRQ0_LINE); irq_vector = 0xfff8 + (irqline - UNSP_IRQ0_LINE);
break; break;
case UNSP_FIQ_LINE: case UNSP_FIQ_LINE:
if(unsp->fiq != 1) if(m_fiq != 1)
{ {
// FIQ is disabled, ignore this FIQ trigger. // FIQ is disabled, ignore this FIQ trigger.
unsp->sirq |= state << irqline; m_sirq |= state << irqline;
return; return;
} }
unsp->fiq |= 2; m_fiq |= 2;
unsp->curirq |= (1 << irqline); m_curirq |= (1 << irqline);
logerror("taking fiq %d (%04x, %04x)\n", irqline, unsp->sirq, unsp->curirq); logerror("taking fiq %d (%04x, %04x)\n", irqline, m_sirq, m_curirq);
irq_vector = 0xfff6; irq_vector = 0xfff6;
break; break;
case UNSP_BRK_LINE: case UNSP_BRK_LINE:
break; break;
} }
unsp->saved_sb = unsp->sb; m_saved_sb = m_sb;
unsp_push(unsp, UNSP_REG(PC), &UNSP_REG(SP)); unsp_push(UNSP_REG(PC), &UNSP_REG(SP));
unsp_push(unsp, UNSP_REG(SR), &UNSP_REG(SP)); unsp_push(UNSP_REG(SR), &UNSP_REG(SP));
UNSP_REG(PC) = READ16(unsp, irq_vector); UNSP_REG(PC) = READ16(irq_vector);
UNSP_REG(SR) = 0; 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 CPUINFO_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 + AS_PROGRAM: info->i = 16; break;
case CPUINFO_INT_ADDRBUS_WIDTH + AS_PROGRAM: info->i = 23; break;
case CPUINFO_INT_ADDRBUS_SHIFT + AS_PROGRAM: info->i = 0; break;
case CPUINFO_INT_DATABUS_WIDTH + AS_DATA: info->i = 0; break;
case CPUINFO_INT_ADDRBUS_WIDTH + AS_DATA: info->i = 0; break;
case CPUINFO_INT_ADDRBUS_SHIFT + AS_DATA: info->i = 0; break;
case CPUINFO_INT_DATABUS_WIDTH + AS_IO: info->i = 0; break;
case CPUINFO_INT_ADDRBUS_WIDTH + AS_IO: info->i = 0; break;
case CPUINFO_INT_ADDRBUS_SHIFT + AS_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 CPUINFO_STR_NAME: strcpy(info->s, "u'nSP"); break;
case CPUINFO_STR_SHORTNAME: strcpy(info->s, "unsp"); break;
case CPUINFO_STR_FAMILY: strcpy(info->s, "u'nSP"); break;
case CPUINFO_STR_VERSION: strcpy(info->s, "1.0"); break;
case CPUINFO_STR_SOURCE_FILE: strcpy(info->s, __FILE__); break;
case CPUINFO_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;
}
}
DEFINE_LEGACY_CPU_DEVICE(UNSP, unsp);

View File

@ -11,24 +11,6 @@
#ifndef __UNSP_H__ #ifndef __UNSP_H__
#define __UNSP_H__ #define __UNSP_H__
struct unspimp_state;
struct unsp_state
{
UINT16 r[16];
UINT8 irq;
UINT8 fiq;
UINT16 curirq;
UINT16 sirq;
UINT8 sb;
UINT8 saved_sb;
legacy_cpu_device *device;
address_space *program;
int icount;
unspimp_state *impstate;
};
enum enum
{ {
UNSP_SP = 1, UNSP_SP = 1,
@ -64,7 +46,66 @@ enum
UNSP_NUM_LINES UNSP_NUM_LINES
}; };
DECLARE_LEGACY_CPU_DEVICE(UNSP, unsp);
CPU_DISASSEMBLE( unsp ); class unsp_device : public cpu_device
{
public:
// construction/destruction
unsp_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
protected:
// device-level overrides
virtual void device_start();
virtual void device_reset();
// device_execute_interface overrides
virtual UINT32 execute_min_cycles() const { return 5; }
virtual UINT32 execute_max_cycles() const { return 5; }
virtual UINT32 execute_input_lines() const { return 0; }
virtual void execute_run();
virtual void execute_set_input(int inputnum, int state);
// device_memory_interface overrides
virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const { return (spacenum == AS_PROGRAM) ? &m_program_config : NULL; }
// device_state_interface overrides
virtual void state_import(const device_state_entry &entry);
virtual void state_export(const device_state_entry &entry);
// device_disasm_interface overrides
virtual UINT32 disasm_min_opcode_bytes() const { return 2; }
virtual UINT32 disasm_max_opcode_bytes() const { return 4; }
virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options);
private:
address_space_config m_program_config;
UINT16 m_r[16];
UINT8 m_irq;
UINT8 m_fiq;
UINT16 m_curirq;
UINT16 m_sirq;
UINT8 m_sb;
UINT8 m_saved_sb;
address_space *m_program;
int m_icount;
UINT32 m_debugger_temp;
void unimplemented_opcode(UINT16 op);
inline UINT16 READ16(UINT32 address);
inline void WRITE16(UINT32 address, UINT16 data);
inline void unsp_update_nz(UINT32 value);
inline void unsp_update_nzsc(UINT32 value, UINT16 r0, UINT16 r1);
inline void unsp_push(UINT16 value, UINT16 *reg);
inline UINT16 unsp_pop(UINT16 *reg);
};
extern const device_type UNSP;
#endif /* __UNSP_H__ */ #endif /* __UNSP_H__ */