summaryrefslogtreecommitdiffstatshomepage
path: root/trunk/src/emu/cpu/nec/v25.c
diff options
context:
space:
mode:
Diffstat (limited to 'trunk/src/emu/cpu/nec/v25.c')
-rw-r--r--trunk/src/emu/cpu/nec/v25.c805
1 files changed, 805 insertions, 0 deletions
diff --git a/trunk/src/emu/cpu/nec/v25.c b/trunk/src/emu/cpu/nec/v25.c
new file mode 100644
index 00000000000..039bba02b56
--- /dev/null
+++ b/trunk/src/emu/cpu/nec/v25.c
@@ -0,0 +1,805 @@
+/****************************************************************************
+
+ NEC V25/V35 emulator
+
+ ---------------------------------------------
+
+ TODO:
+
+ Using V20/V30 cycle counts for now. V25/V35 cycle counts
+ vary based on whether internal RAM access is enabled (RAMEN).
+ Likewise, the programmable clock divider (PCK) currently only
+ affects the timers, not instruction execution.
+
+ BTCLR and STOP instructions not implemented.
+
+ IBRK flag (trap I/O instructions) not implemented.
+
+ Interrupt macro service function not implemented.
+
+ Port implementation is incomplete: mode control registers are ignored.
+
+ Timer implementation is incomplete: polling is not implemented
+ (reading any of the registers just returns the last value written)
+
+ Serial interface and DMA functions not implemented.
+ Note that these functions differ considerably between
+ the V25/35 and the V25+/35+.
+
+ Make internal RAM into a real RAM region, and use an
+ internal address map (remapped when IDB is written to)
+ instead of memory access wrapper functions.
+ That way the internal RAM would be visible to the debugger,
+ among other benefits.
+
+****************************************************************************/
+
+#include "emu.h"
+#include "debugger.h"
+
+typedef UINT8 BOOLEAN;
+typedef UINT8 BYTE;
+typedef UINT16 WORD;
+typedef UINT32 DWORD;
+
+#include "nec.h"
+#include "v25priv.h"
+
+/* default configuration */
+static const nec_config default_config =
+{
+ NULL
+};
+
+extern int necv_dasm_one(char *buffer, UINT32 eip, const UINT8 *oprom, const nec_config *config);
+
+INLINE v25_state_t *get_safe_token(device_t *device)
+{
+ assert(device != NULL);
+ assert(device->type() == V25 || device->type() == V35);
+ return (v25_state_t *)downcast<legacy_cpu_device *>(device)->token();
+}
+
+static TIMER_CALLBACK(v25_timer_callback)
+{
+ v25_state_t *nec_state = (v25_state_t *)ptr;
+ nec_state->pending_irq |= param;
+}
+
+INLINE void prefetch(v25_state_t *nec_state)
+{
+ nec_state->prefetch_count--;
+}
+
+static void do_prefetch(v25_state_t *nec_state, int previous_ICount)
+{
+ int diff = previous_ICount - (int) nec_state->icount;
+
+ /* The implementation is not accurate, but comes close.
+ * It does not respect that the V30 will fetch two bytes
+ * at once directly, but instead uses only 2 cycles instead
+ * of 4. There are however only very few sources publicly
+ * available and they are vague.
+ */
+ while (nec_state->prefetch_count<0)
+ {
+ nec_state->prefetch_count++;
+ if (diff>nec_state->prefetch_cycles)
+ diff -= nec_state->prefetch_cycles;
+ else
+ nec_state->icount -= nec_state->prefetch_cycles;
+ }
+
+ if (nec_state->prefetch_reset)
+ {
+ nec_state->prefetch_count = 0;
+ nec_state->prefetch_reset = 0;
+ return;
+ }
+
+ while (diff>=nec_state->prefetch_cycles && nec_state->prefetch_count < nec_state->prefetch_size)
+ {
+ diff -= nec_state->prefetch_cycles;
+ nec_state->prefetch_count++;
+ }
+
+}
+
+INLINE UINT8 fetch(v25_state_t *nec_state)
+{
+ prefetch(nec_state);
+ return nec_state->direct->read_raw_byte((Sreg(PS)<<4)+nec_state->ip++, nec_state->fetch_xor);
+}
+
+INLINE UINT16 fetchword(v25_state_t *nec_state)
+{
+ UINT16 r = FETCH();
+ r |= (FETCH()<<8);
+ return r;
+}
+
+#define nec_state_t v25_state_t
+
+#include "v25instr.h"
+#include "necmacro.h"
+#include "necea.h"
+#include "necmodrm.h"
+
+static UINT8 parity_table[256];
+
+static UINT8 fetchop(v25_state_t *nec_state)
+{
+ UINT8 ret;
+
+ prefetch(nec_state);
+ ret = nec_state->direct->read_decrypted_byte(( Sreg(PS)<<4)+nec_state->ip++, nec_state->fetch_xor);
+
+ if (nec_state->MF == 0)
+ if (nec_state->config->v25v35_decryptiontable)
+ {
+ ret = nec_state->config->v25v35_decryptiontable[ret];
+ }
+ return ret;
+}
+
+
+
+/***************************************************************************/
+
+static CPU_RESET( v25 )
+{
+ v25_state_t *nec_state = get_safe_token(device);
+ int tmp;
+ attotime time;
+
+ nec_state->ip = 0;
+ nec_state->IBRK = 1;
+ nec_state->F0 = 0;
+ nec_state->F1 = 0;
+ nec_state->TF = 0;
+ nec_state->IF = 0;
+ nec_state->DF = 0;
+ nec_state->SignVal = 0;
+ nec_state->AuxVal = 0;
+ nec_state->OverVal = 0;
+ nec_state->ZeroVal = 1;
+ nec_state->CarryVal = 0;
+ nec_state->ParityVal = 1;
+ nec_state->pending_irq = 0;
+ nec_state->unmasked_irq = INT_IRQ | NMI_IRQ;
+ nec_state->bankswitch_irq = 0;
+ nec_state->priority_inttu = 7;
+ nec_state->priority_intd = 7;
+ nec_state->priority_intp = 7;
+ nec_state->priority_ints0 = 7;
+ nec_state->priority_ints1 = 7;
+ nec_state->IRQS = nec_state->ISPR = 0;
+ nec_state->nmi_state = 0;
+ nec_state->irq_state = 0;
+ nec_state->poll_state = 1;
+ nec_state->mode_state = nec_state->MF = (nec_state->config->v25v35_decryptiontable) ? 0 : 1;
+ nec_state->intp_state[0] = 0;
+ nec_state->intp_state[1] = 0;
+ nec_state->intp_state[2] = 0;
+ nec_state->halted = 0;
+
+ nec_state->TM0 = nec_state->MD0 = nec_state->TM1 = nec_state->MD1 = 0;
+ nec_state->TMC0 = nec_state->TMC1 = 0;
+
+ nec_state->RAMEN = 1;
+ nec_state->TB = 20;
+ nec_state->PCK = 8;
+ nec_state->IDB = 0xFFE00;
+
+ tmp = nec_state->PCK << nec_state->TB;
+ time = attotime::from_hz(nec_state->device->unscaled_clock()) * tmp;
+ nec_state->timers[3]->adjust(time, INTTB, time);
+
+ nec_state->timers[0]->adjust(attotime::never);
+ nec_state->timers[1]->adjust(attotime::never);
+ nec_state->timers[2]->adjust(attotime::never);
+
+ SetRB(7);
+ Sreg(PS) = 0xffff;
+ Sreg(SS) = 0;
+ Sreg(DS0) = 0;
+ Sreg(DS1) = 0;
+
+ CHANGE_PC;
+}
+
+static CPU_EXIT( v25 )
+{
+
+}
+
+static void nec_interrupt(v25_state_t *nec_state, unsigned int_num, INTSOURCES source)
+{
+ UINT32 dest_seg, dest_off;
+
+ i_pushf(nec_state);
+ nec_state->TF = nec_state->IF = 0;
+ nec_state->MF = nec_state->mode_state;
+
+ switch(source)
+ {
+ case BRKN: /* force native mode */
+ nec_state->MF = 1;
+ break;
+ case BRKS: /* force secure mode */
+ if (nec_state->config->v25v35_decryptiontable)
+ nec_state->MF = 0;
+ else
+ logerror("%06x: BRKS executed with no decryption table\n",PC(nec_state));
+ break;
+ case INT_IRQ: /* get vector */
+ int_num = (*nec_state->irq_callback)(nec_state->device, 0);
+ break;
+ default:
+ break;
+ }
+
+ dest_off = read_mem_word(int_num*4);
+ dest_seg = read_mem_word(int_num*4+2);
+
+ PUSH(Sreg(PS));
+ PUSH(nec_state->ip);
+ nec_state->ip = (WORD)dest_off;
+ Sreg(PS) = (WORD)dest_seg;
+ CHANGE_PC;
+}
+
+static void nec_bankswitch(v25_state_t *nec_state, unsigned bank_num)
+{
+ int tmp = CompressFlags();
+
+ nec_state->TF = nec_state->IF = 0;
+ nec_state->MF = nec_state->mode_state;
+
+ SetRB(bank_num);
+
+ Wreg(PSW_SAVE) = tmp;
+ Wreg(PC_SAVE) = nec_state->ip;
+ nec_state->ip = Wreg(VECTOR_PC);
+ CHANGE_PC;
+}
+
+static void nec_trap(v25_state_t *nec_state)
+{
+ nec_instruction[fetchop(nec_state)](nec_state);
+ nec_interrupt(nec_state, NEC_TRAP_VECTOR, BRK);
+}
+
+#define INTERRUPT(source, vector, priority) \
+ if(pending & (source)) { \
+ nec_state->IRQS = vector; \
+ nec_state->ISPR |= (1 << (priority)); \
+ nec_state->pending_irq &= ~(source); \
+ if(nec_state->bankswitch_irq & (source)) \
+ nec_bankswitch(nec_state, priority); \
+ else \
+ nec_interrupt(nec_state, vector, source); \
+ break; /* break out of loop */ \
+ }
+
+/* interrupt sources subject to priority control */
+#define SOURCES (INTTU0 | INTTU1 | INTTU2 | INTD0 | INTD1 | INTP0 | INTP1 | INTP2 \
+ | INTSER0 | INTSR0 | INTST0 | INTSER1 | INTSR1 | INTST1 | INTTB)
+
+static void external_int(v25_state_t *nec_state)
+{
+ int pending = nec_state->pending_irq & nec_state->unmasked_irq;
+
+ if (pending & NMI_IRQ)
+ {
+ nec_interrupt(nec_state, NEC_NMI_VECTOR, NMI_IRQ);
+ nec_state->pending_irq &= ~NMI_IRQ;
+ }
+ else if (pending & SOURCES)
+ {
+ for(int i = 0; i < 8; i++)
+ {
+ if (nec_state->ISPR & (1 << i)) break;
+
+ if (nec_state->priority_inttu == i)
+ {
+ INTERRUPT(INTTU0, NEC_INTTU0_VECTOR, i)
+ INTERRUPT(INTTU1, NEC_INTTU1_VECTOR, i)
+ INTERRUPT(INTTU2, NEC_INTTU2_VECTOR, i)
+ }
+
+ if (nec_state->priority_intd == i)
+ {
+ INTERRUPT(INTD0, NEC_INTD0_VECTOR, i)
+ INTERRUPT(INTD1, NEC_INTD1_VECTOR, i)
+ }
+
+ if (nec_state->priority_intp == i)
+ {
+ INTERRUPT(INTP0, NEC_INTP0_VECTOR, i)
+ INTERRUPT(INTP1, NEC_INTP1_VECTOR, i)
+ INTERRUPT(INTP2, NEC_INTP2_VECTOR, i)
+ }
+
+ if (nec_state->priority_ints0 == i)
+ {
+ INTERRUPT(INTSER0, NEC_INTSER0_VECTOR, i)
+ INTERRUPT(INTSR0, NEC_INTSR0_VECTOR, i)
+ INTERRUPT(INTST0, NEC_INTST0_VECTOR, i)
+ }
+
+ if (nec_state->priority_ints1 == i)
+ {
+ INTERRUPT(INTSER1, NEC_INTSER1_VECTOR, i)
+ INTERRUPT(INTSR1, NEC_INTSR1_VECTOR, i)
+ INTERRUPT(INTST1, NEC_INTST1_VECTOR, i)
+ }
+
+ if (i == 7)
+ INTERRUPT(INTTB, NEC_INTTB_VECTOR, 7)
+ }
+ }
+ else if (pending & INT_IRQ)
+ {
+ /* the actual vector is retrieved after pushing flags */
+ /* and clearing the IF */
+ nec_interrupt(nec_state, (UINT32)-1, INT_IRQ);
+ nec_state->irq_state = CLEAR_LINE;
+ nec_state->pending_irq &= ~INT_IRQ;
+ }
+}
+
+/****************************************************************************/
+/* OPCODES */
+/****************************************************************************/
+
+#include "necinstr.c"
+#include "v25instr.c"
+
+/*****************************************************************************/
+
+static void set_irq_line(v25_state_t *nec_state, int irqline, int state)
+{
+ switch (irqline)
+ {
+ case 0:
+ nec_state->irq_state = state;
+ if (state == CLEAR_LINE)
+ nec_state->pending_irq &= ~INT_IRQ;
+ else
+ {
+ nec_state->pending_irq |= INT_IRQ;
+ nec_state->halted = 0;
+ }
+ break;
+ case INPUT_LINE_NMI:
+ if (nec_state->nmi_state == state) return;
+ nec_state->nmi_state = state;
+ if (state != CLEAR_LINE)
+ {
+ nec_state->pending_irq |= NMI_IRQ;
+ nec_state->halted = 0;
+ }
+ break;
+ case NEC_INPUT_LINE_INTP0:
+ case NEC_INPUT_LINE_INTP1:
+ case NEC_INPUT_LINE_INTP2:
+ irqline -= NEC_INPUT_LINE_INTP0;
+ if (nec_state->intp_state[irqline] == state) return;
+ nec_state->intp_state[irqline] = state;
+ if (state != CLEAR_LINE)
+ nec_state->pending_irq |= (INTP0 << irqline);
+ break;
+ case NEC_INPUT_LINE_POLL:
+ nec_state->poll_state = state;
+ break;
+ }
+}
+
+static CPU_DISASSEMBLE( v25 )
+{
+ v25_state_t *nec_state = get_safe_token(device);
+
+ return necv_dasm_one(buffer, pc, oprom, nec_state->config);
+}
+
+static void v25_init(legacy_cpu_device *device, device_irq_callback irqcallback)
+{
+ const nec_config *config = device->static_config() ? (const nec_config *)device->static_config() : &default_config;
+ v25_state_t *nec_state = get_safe_token(device);
+
+ unsigned int i, j, c;
+
+ static const WREGS wreg_name[8]={ AW, CW, DW, BW, SP, BP, IX, IY };
+ static const BREGS breg_name[8]={ AL, CL, DL, BL, AH, CH, DH, BH };
+
+ for (i = 0; i < 256; i++)
+ {
+ for (j = i, c = 0; j > 0; j >>= 1)
+ if (j & 1) c++;
+ parity_table[i] = !(c & 1);
+ }
+
+ for (i = 0; i < 256; i++)
+ {
+ Mod_RM.reg.b[i] = breg_name[(i & 0x38) >> 3];
+ Mod_RM.reg.w[i] = wreg_name[(i & 0x38) >> 3];
+ }
+
+ for (i = 0xc0; i < 0x100; i++)
+ {
+ Mod_RM.RM.w[i] = wreg_name[i & 7];
+ Mod_RM.RM.b[i] = breg_name[i & 7];
+ }
+
+ memset(nec_state, 0, sizeof(*nec_state));
+
+ nec_state->config = config;
+
+ for (i = 0; i < 4; i++)
+ nec_state->timers[i] = device->machine().scheduler().timer_alloc(FUNC(v25_timer_callback), nec_state);
+
+ device->save_item(NAME(nec_state->ram.w));
+ device->save_item(NAME(nec_state->intp_state));
+
+ device->save_item(NAME(nec_state->ip));
+ device->save_item(NAME(nec_state->IBRK));
+ device->save_item(NAME(nec_state->F0));
+ device->save_item(NAME(nec_state->F1));
+ device->save_item(NAME(nec_state->TF));
+ device->save_item(NAME(nec_state->IF));
+ device->save_item(NAME(nec_state->DF));
+ device->save_item(NAME(nec_state->MF));
+ device->save_item(NAME(nec_state->RBW));
+ device->save_item(NAME(nec_state->RBB));
+ device->save_item(NAME(nec_state->SignVal));
+ device->save_item(NAME(nec_state->AuxVal));
+ device->save_item(NAME(nec_state->OverVal));
+ device->save_item(NAME(nec_state->ZeroVal));
+ device->save_item(NAME(nec_state->CarryVal));
+ device->save_item(NAME(nec_state->ParityVal));
+ device->save_item(NAME(nec_state->pending_irq));
+ device->save_item(NAME(nec_state->unmasked_irq));
+ device->save_item(NAME(nec_state->bankswitch_irq));
+ device->save_item(NAME(nec_state->priority_inttu));
+ device->save_item(NAME(nec_state->priority_intd));
+ device->save_item(NAME(nec_state->priority_intp));
+ device->save_item(NAME(nec_state->priority_ints0));
+ device->save_item(NAME(nec_state->priority_ints1));
+ device->save_item(NAME(nec_state->IRQS));
+ device->save_item(NAME(nec_state->ISPR));
+ device->save_item(NAME(nec_state->nmi_state));
+ device->save_item(NAME(nec_state->irq_state));
+ device->save_item(NAME(nec_state->poll_state));
+ device->save_item(NAME(nec_state->mode_state));
+ device->save_item(NAME(nec_state->halted));
+ device->save_item(NAME(nec_state->TM0));
+ device->save_item(NAME(nec_state->MD0));
+ device->save_item(NAME(nec_state->TM1));
+ device->save_item(NAME(nec_state->MD1));
+ device->save_item(NAME(nec_state->TMC0));
+ device->save_item(NAME(nec_state->TMC1));
+ device->save_item(NAME(nec_state->RAMEN));
+ device->save_item(NAME(nec_state->TB));
+ device->save_item(NAME(nec_state->PCK));
+ device->save_item(NAME(nec_state->IDB));
+
+ nec_state->irq_callback = irqcallback;
+ nec_state->device = device;
+ nec_state->program = device->space(AS_PROGRAM);
+ nec_state->direct = &nec_state->program->direct();
+ nec_state->io = device->space(AS_IO);
+}
+
+
+
+static CPU_EXECUTE( v25 )
+{
+ v25_state_t *nec_state = get_safe_token(device);
+ int prev_ICount;
+
+ int pending = nec_state->pending_irq & nec_state->unmasked_irq;
+
+ if (nec_state->halted && pending)
+ {
+ for(int i = 0; i < 8; i++)
+ {
+ if (nec_state->ISPR & (1 << i)) break;
+
+ if (nec_state->priority_inttu == i && (pending & (INTTU0|INTTU1|INTTU2)))
+ nec_state->halted = 0;
+
+ if (nec_state->priority_intd == i && (pending & (INTD0|INTD1)))
+ nec_state->halted = 0;
+
+ if (nec_state->priority_intp == i && (pending & (INTP0|INTP1|INTP2)))
+ nec_state->halted = 0;
+
+ if (nec_state->priority_ints0 == i && (pending & (INTSER0|INTSR0|INTST0)))
+ nec_state->halted = 0;
+
+ if (nec_state->priority_ints1 == i && (pending & (INTSER1|INTSR1|INTST1)))
+ nec_state->halted = 0;
+
+ if (i == 7 && (pending & INTTB))
+ nec_state->halted = 0;
+ }
+ }
+
+ if (nec_state->halted)
+ {
+ nec_state->icount = 0;
+ debugger_instruction_hook(device, (Sreg(PS)<<4) + nec_state->ip);
+ return;
+ }
+
+ while(nec_state->icount>0) {
+ /* Dispatch IRQ */
+ if (nec_state->no_interrupt==0 && (nec_state->pending_irq & nec_state->unmasked_irq))
+ {
+ if (nec_state->pending_irq & NMI_IRQ)
+ external_int(nec_state);
+ else if (nec_state->IF)
+ external_int(nec_state);
+ }
+
+ /* No interrupt allowed between last instruction and this one */
+ if (nec_state->no_interrupt)
+ nec_state->no_interrupt--;
+
+ debugger_instruction_hook(device, (Sreg(PS)<<4) + nec_state->ip);
+ prev_ICount = nec_state->icount;
+ nec_instruction[fetchop(nec_state)](nec_state);
+ do_prefetch(nec_state, prev_ICount);
+ }
+}
+
+/* Wrappers for the different CPU types */
+static CPU_INIT( v25 )
+{
+ v25_state_t *nec_state = get_safe_token(device);
+
+ v25_init(device, irqcallback);
+ nec_state->fetch_xor = 0;
+ nec_state->chip_type=V20_TYPE;
+ nec_state->prefetch_size = 4; /* 3 words */
+ nec_state->prefetch_cycles = 4; /* four cycles per byte */
+}
+
+static CPU_INIT( v35 )
+{
+ v25_state_t *nec_state = get_safe_token(device);
+
+ v25_init(device, irqcallback);
+ nec_state->fetch_xor = BYTE_XOR_LE(0);
+ nec_state->chip_type=V30_TYPE;
+ nec_state->prefetch_size = 6; /* 3 words */
+ nec_state->prefetch_cycles = 2; /* two cycles per byte / four per word */
+
+}
+
+
+
+/**************************************************************************
+ * Generic set_info
+ **************************************************************************/
+
+static CPU_SET_INFO( v25 )
+{
+ v25_state_t *nec_state = get_safe_token(device);
+
+ switch (state)
+ {
+ /* --- the following bits of info are set as 64-bit signed integers --- */
+ case CPUINFO_INT_INPUT_STATE + 0: set_irq_line(nec_state, 0, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + INPUT_LINE_NMI: set_irq_line(nec_state, INPUT_LINE_NMI, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + NEC_INPUT_LINE_INTP0: set_irq_line(nec_state, NEC_INPUT_LINE_INTP0, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + NEC_INPUT_LINE_INTP1: set_irq_line(nec_state, NEC_INPUT_LINE_INTP1, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + NEC_INPUT_LINE_INTP2: set_irq_line(nec_state, NEC_INPUT_LINE_INTP2, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + NEC_INPUT_LINE_POLL: set_irq_line(nec_state, NEC_INPUT_LINE_POLL, info->i); break;
+
+ case CPUINFO_INT_PC:
+ case CPUINFO_INT_REGISTER + NEC_PC:
+ if( info->i - (Sreg(PS)<<4) < 0x10000 )
+ {
+ nec_state->ip = info->i - (Sreg(PS)<<4);
+ }
+ else
+ {
+ Sreg(PS) = info->i >> 4;
+ nec_state->ip = info->i & 0x0000f;
+ }
+ break;
+ case CPUINFO_INT_REGISTER + NEC_IP: nec_state->ip = info->i; break;
+ case CPUINFO_INT_SP:
+ if( info->i - (Sreg(SS)<<4) < 0x10000 )
+ {
+ Wreg(SP) = info->i - (Sreg(SS)<<4);
+ }
+ else
+ {
+ Sreg(SS) = info->i >> 4;
+ Wreg(SP) = info->i & 0x0000f;
+ }
+ break;
+ case CPUINFO_INT_REGISTER + NEC_SP: Wreg(SP) = info->i; break;
+ case CPUINFO_INT_REGISTER + NEC_FLAGS: ExpandFlags(info->i); break;
+ case CPUINFO_INT_REGISTER + NEC_AW: Wreg(AW) = info->i; break;
+ case CPUINFO_INT_REGISTER + NEC_CW: Wreg(CW) = info->i; break;
+ case CPUINFO_INT_REGISTER + NEC_DW: Wreg(DW) = info->i; break;
+ case CPUINFO_INT_REGISTER + NEC_BW: Wreg(BW) = info->i; break;
+ case CPUINFO_INT_REGISTER + NEC_BP: Wreg(BP) = info->i; break;
+ case CPUINFO_INT_REGISTER + NEC_IX: Wreg(IX) = info->i; break;
+ case CPUINFO_INT_REGISTER + NEC_IY: Wreg(IY) = info->i; break;
+ case CPUINFO_INT_REGISTER + NEC_ES: Sreg(DS1) = info->i; break;
+ case CPUINFO_INT_REGISTER + NEC_CS: Sreg(PS) = info->i; break;
+ case CPUINFO_INT_REGISTER + NEC_SS: Sreg(SS) = info->i; break;
+ case CPUINFO_INT_REGISTER + NEC_DS: Sreg(DS0) = info->i; break;
+ }
+}
+
+
+
+/**************************************************************************
+ * Generic get_info
+ **************************************************************************/
+
+static CPU_GET_INFO( v25v35 )
+{
+ v25_state_t *nec_state = (device != NULL && device->token() != NULL) ? get_safe_token(device) : NULL;
+ int flags;
+
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case CPUINFO_INT_CONTEXT_SIZE: info->i = sizeof(v25_state_t); break;
+ case CPUINFO_INT_INPUT_LINES: info->i = 1; break;
+ case CPUINFO_INT_DEFAULT_IRQ_VECTOR: info->i = 0xff; break;
+ case DEVINFO_INT_ENDIANNESS: info->i = ENDIANNESS_LITTLE; break;
+ case CPUINFO_INT_CLOCK_MULTIPLIER: info->i = 1; break;
+ case CPUINFO_INT_CLOCK_DIVIDER: info->i = 2; break;
+ case CPUINFO_INT_MIN_INSTRUCTION_BYTES: info->i = 1; break;
+ case CPUINFO_INT_MAX_INSTRUCTION_BYTES: info->i = 8; break;
+ case CPUINFO_INT_MIN_CYCLES: info->i = 1; break;
+ case CPUINFO_INT_MAX_CYCLES: info->i = 80; break;
+
+ case DEVINFO_INT_DATABUS_WIDTH + AS_PROGRAM: info->i = 16; break;
+ case DEVINFO_INT_ADDRBUS_WIDTH + AS_PROGRAM: info->i = 20; break;
+ case DEVINFO_INT_ADDRBUS_SHIFT + AS_PROGRAM: info->i = 0; break;
+ case DEVINFO_INT_DATABUS_WIDTH + AS_DATA: info->i = 0; break;
+ case DEVINFO_INT_ADDRBUS_WIDTH + AS_DATA: info->i = 0; break;
+ case DEVINFO_INT_ADDRBUS_SHIFT + AS_DATA: info->i = 0; break;
+ case DEVINFO_INT_DATABUS_WIDTH + AS_IO: info->i = 16; break;
+ case DEVINFO_INT_ADDRBUS_WIDTH + AS_IO: info->i = 17; break;
+ case DEVINFO_INT_ADDRBUS_SHIFT + AS_IO: info->i = 0; break;
+
+ case CPUINFO_INT_INPUT_STATE + 0: info->i = (nec_state->pending_irq & INT_IRQ) ? ASSERT_LINE : CLEAR_LINE; break;
+ case CPUINFO_INT_INPUT_STATE + INPUT_LINE_NMI: info->i = nec_state->nmi_state; break;
+ case CPUINFO_INT_INPUT_STATE + NEC_INPUT_LINE_INTP0: info->i = nec_state->intp_state[0]; break;
+ case CPUINFO_INT_INPUT_STATE + NEC_INPUT_LINE_INTP1: info->i = nec_state->intp_state[1]; break;
+ case CPUINFO_INT_INPUT_STATE + NEC_INPUT_LINE_INTP2: info->i = nec_state->intp_state[2]; break;
+ case CPUINFO_INT_INPUT_STATE + NEC_INPUT_LINE_POLL: info->i = nec_state->poll_state; break;
+
+ case CPUINFO_INT_PREVIOUSPC: /* not supported */ break;
+
+ case CPUINFO_INT_PC:
+ case CPUINFO_INT_REGISTER + NEC_PC: info->i = ((Sreg(PS)<<4) + nec_state->ip); break;
+ case CPUINFO_INT_REGISTER + NEC_IP: info->i = nec_state->ip; break;
+ case CPUINFO_INT_SP: info->i = (Sreg(SS)<<4) + Wreg(SP); break;
+ case CPUINFO_INT_REGISTER + NEC_SP: info->i = Wreg(SP); break;
+ case CPUINFO_INT_REGISTER + NEC_FLAGS: info->i = CompressFlags(); break;
+ case CPUINFO_INT_REGISTER + NEC_AW: info->i = Wreg(AW); break;
+ case CPUINFO_INT_REGISTER + NEC_CW: info->i = Wreg(CW); break;
+ case CPUINFO_INT_REGISTER + NEC_DW: info->i = Wreg(DW); break;
+ case CPUINFO_INT_REGISTER + NEC_BW: info->i = Wreg(BW); break;
+ case CPUINFO_INT_REGISTER + NEC_BP: info->i = Wreg(BP); break;
+ case CPUINFO_INT_REGISTER + NEC_IX: info->i = Wreg(IX); break;
+ case CPUINFO_INT_REGISTER + NEC_IY: info->i = Wreg(IY); break;
+ case CPUINFO_INT_REGISTER + NEC_ES: info->i = Sreg(DS1); break;
+ case CPUINFO_INT_REGISTER + NEC_CS: info->i = Sreg(PS); break;
+ case CPUINFO_INT_REGISTER + NEC_SS: info->i = Sreg(SS); break;
+ case CPUINFO_INT_REGISTER + NEC_DS: info->i = Sreg(DS0); break;
+ case CPUINFO_INT_REGISTER + NEC_PENDING: info->i = nec_state->pending_irq; 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(v25); break;
+ case CPUINFO_FCT_INIT: /* set per-CPU */ break;
+ case CPUINFO_FCT_RESET: info->reset = CPU_RESET_NAME(v25); break;
+ case CPUINFO_FCT_EXIT: info->exit = CPU_EXIT_NAME(v25); break;
+ case CPUINFO_FCT_EXECUTE: info->execute = CPU_EXECUTE_NAME(v25); break;
+ case CPUINFO_FCT_BURN: info->burn = NULL; break;
+ case CPUINFO_FCT_DISASSEMBLE: info->disassemble = CPU_DISASSEMBLE_NAME(v25); break;
+ case CPUINFO_PTR_INSTRUCTION_COUNTER: info->icount = &nec_state->icount; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case DEVINFO_STR_NAME: strcpy(info->s, "NEC"); break;
+ case DEVINFO_STR_FAMILY: strcpy(info->s, "NEC V-Series"); break;
+ case DEVINFO_STR_VERSION: strcpy(info->s, "2.0"); break;
+ case DEVINFO_STR_SOURCE_FILE: strcpy(info->s, __FILE__); break;
+ case DEVINFO_STR_CREDITS: strcpy(info->s, "Bryan McPhail (V25/V35 support added by Alex W. Jackson)"); break;
+
+ case CPUINFO_STR_FLAGS:
+ flags = CompressFlags();
+ sprintf(info->s, "%c %d %c%c%c%c%c%c%c%c%c%c%c%c",
+ flags & 0x8000 ? 'N':'S',
+ (flags & 0x7000) >> 12,
+ flags & 0x0800 ? 'O':'.',
+ flags & 0x0400 ? 'D':'.',
+ flags & 0x0200 ? 'I':'.',
+ flags & 0x0100 ? 'T':'.',
+ flags & 0x0080 ? 'S':'.',
+ flags & 0x0040 ? 'Z':'.',
+ flags & 0x0020 ? '1':'.',
+ flags & 0x0010 ? 'A':'.',
+ flags & 0x0008 ? '0':'.',
+ flags & 0x0004 ? 'P':'.',
+ flags & 0x0002 ? '.':'I',
+ flags & 0x0001 ? 'C':'.');
+ break;
+
+ case CPUINFO_STR_REGISTER + NEC_PC: sprintf(info->s, "PC:%05X", (Sreg(PS)<<4) + nec_state->ip); break;
+ case CPUINFO_STR_REGISTER + NEC_IP: sprintf(info->s, "IP:%04X", nec_state->ip); break;
+ case CPUINFO_STR_REGISTER + NEC_SP: sprintf(info->s, "SP:%04X", Wreg(SP)); break;
+ case CPUINFO_STR_REGISTER + NEC_FLAGS: sprintf(info->s, "F:%04X", CompressFlags()); break;
+ case CPUINFO_STR_REGISTER + NEC_AW: sprintf(info->s, "AW:%04X", Wreg(AW)); break;
+ case CPUINFO_STR_REGISTER + NEC_CW: sprintf(info->s, "CW:%04X", Wreg(CW)); break;
+ case CPUINFO_STR_REGISTER + NEC_DW: sprintf(info->s, "DW:%04X", Wreg(DW)); break;
+ case CPUINFO_STR_REGISTER + NEC_BW: sprintf(info->s, "BW:%04X", Wreg(BW)); break;
+ case CPUINFO_STR_REGISTER + NEC_BP: sprintf(info->s, "BP:%04X", Wreg(BP)); break;
+ case CPUINFO_STR_REGISTER + NEC_IX: sprintf(info->s, "IX:%04X", Wreg(IX)); break;
+ case CPUINFO_STR_REGISTER + NEC_IY: sprintf(info->s, "IY:%04X", Wreg(IY)); break;
+ case CPUINFO_STR_REGISTER + NEC_ES: sprintf(info->s, "DS1:%04X", Sreg(DS1)); break;
+ case CPUINFO_STR_REGISTER + NEC_CS: sprintf(info->s, "PS:%04X", Sreg(PS)); break;
+ case CPUINFO_STR_REGISTER + NEC_SS: sprintf(info->s, "SS:%04X", Sreg(SS)); break;
+ case CPUINFO_STR_REGISTER + NEC_DS: sprintf(info->s, "DS0:%04X", Sreg(DS0)); break;
+ }
+}
+
+
+/**************************************************************************
+ * CPU-specific set_info
+ **************************************************************************/
+
+CPU_GET_INFO( v25 )
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case DEVINFO_INT_DATABUS_WIDTH + AS_PROGRAM: info->i = 8; break;
+ case DEVINFO_INT_DATABUS_WIDTH + AS_IO: info->i = 8; break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case CPUINFO_FCT_INIT: info->init = CPU_INIT_NAME(v25); break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case DEVINFO_STR_NAME: strcpy(info->s, "V25"); break;
+
+ default: CPU_GET_INFO_CALL(v25v35); break;
+ }
+}
+
+
+/**************************************************************************
+ * CPU-specific set_info
+ **************************************************************************/
+
+CPU_GET_INFO( v35 )
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case DEVINFO_INT_DATABUS_WIDTH + AS_PROGRAM: info->i = 16; break;
+ case DEVINFO_INT_DATABUS_WIDTH + AS_IO: info->i = 16; break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case CPUINFO_FCT_INIT: info->init = CPU_INIT_NAME(v35); break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case DEVINFO_STR_NAME: strcpy(info->s, "V35"); break;
+
+ default: CPU_GET_INFO_CALL(v25v35); break;
+ }
+}
+
+DEFINE_LEGACY_CPU_DEVICE(V25, v25);
+DEFINE_LEGACY_CPU_DEVICE(V35, v35);