diff --git a/.gitattributes b/.gitattributes index 45dc0696797..bffd3fb5ec8 100644 --- a/.gitattributes +++ b/.gitattributes @@ -141,6 +141,9 @@ src/emu/cpu/i386/x87ops.c svneol=native#text/plain src/emu/cpu/i4004/4004dasm.c svneol=native#text/plain src/emu/cpu/i4004/i4004.c svneol=native#text/plain src/emu/cpu/i4004/i4004.h svneol=native#text/plain +src/emu/cpu/i8008/8008dasm.c svneol=native#text/plain +src/emu/cpu/i8008/i8008.c svneol=native#text/plain +src/emu/cpu/i8008/i8008.h svneol=native#text/plain src/emu/cpu/i8085/8085dasm.c svneol=native#text/plain src/emu/cpu/i8085/i8085.c svneol=native#text/plain src/emu/cpu/i8085/i8085.h svneol=native#text/plain @@ -345,6 +348,9 @@ src/emu/cpu/sc61860/sc61860.h svneol=native#text/plain src/emu/cpu/sc61860/scdasm.c svneol=native#text/plain src/emu/cpu/sc61860/scops.c svneol=native#text/plain src/emu/cpu/sc61860/sctable.c svneol=native#text/plain +src/emu/cpu/scmp/scmp.c svneol=native#text/plain +src/emu/cpu/scmp/scmp.h svneol=native#text/plain +src/emu/cpu/scmp/scmpdasm.c svneol=native#text/plain src/emu/cpu/se3208/se3208.c svneol=native#text/plain src/emu/cpu/se3208/se3208.h svneol=native#text/plain src/emu/cpu/se3208/se3208dis.c svneol=native#text/plain diff --git a/src/emu/cpu/cpu.mak b/src/emu/cpu/cpu.mak index 51538622bcb..ffba0fefc81 100644 --- a/src/emu/cpu/cpu.mak +++ b/src/emu/cpu/cpu.mak @@ -544,6 +544,32 @@ $(CPUOBJ)/i4004/i4004.o: $(CPUSRC)/i4004/i4004.c \ $(CPUSRC)/i4004/i4004.h +#------------------------------------------------- +# Intel 8008 +#------------------------------------------------- + +ifneq ($(filter I8008,$(CPUS)),) +OBJDIRS += $(CPUOBJ)/i8008 +CPUOBJS += $(CPUOBJ)/i8008/i8008.o +DASMOBJS += $(CPUOBJ)/i8008/8008dasm.o +endif + +$(CPUOBJ)/i8008/i8008.o: $(CPUSRC)/i8008/i8008.c \ + $(CPUSRC)/i8008/i8008.h + +#------------------------------------------------- +# National Semiconductor SC/MP +#------------------------------------------------- + +ifneq ($(filter SCMP,$(CPUS)),) +OBJDIRS += $(CPUOBJ)/scmp +CPUOBJS += $(CPUOBJ)/scmp/scmp.o +DASMOBJS += $(CPUOBJ)/scmp/scmpdasm.o +endif + +$(CPUOBJ)/scmp/scmp.o: $(CPUSRC)/scmp/scmp.c \ + $(CPUSRC)/scmp/scmp.h + #------------------------------------------------- # Intel 8080/8085A diff --git a/src/emu/cpu/i8008/8008dasm.c b/src/emu/cpu/i8008/8008dasm.c new file mode 100644 index 00000000000..10389a13bb1 --- /dev/null +++ b/src/emu/cpu/i8008/8008dasm.c @@ -0,0 +1,115 @@ +/***************************************************************************** + * + * 8008dasm.c + * + * Intel 8008 CPU Disassembly + * + * Initial version by Miodrag Milanovic + * + *****************************************************************************/ + +#include "cpuintrf.h" + +#define OP(A) oprom[(A) - PC] +#define ARG(A) opram[(A) - PC] + +static char reg[] = { 'a', 'b', 'c', 'd', 'e', 'h', 'l', 'm' }; +static char flag_names[] = { 'c', 'z', 's', 'p' }; + +CPU_DISASSEMBLE( i8008 ) +{ + UINT32 flags = 0; + unsigned PC = pc; + UINT8 op = OP(pc++); + switch (op >> 6) + { + case 0x03: // starting with 11 + if (op==0xff) { + sprintf (buffer,"hlt"); + } else { + sprintf (buffer,"l%c%c",reg[(op >> 3) & 7],reg[op & 7]); + } + break; + case 0x00: // starting with 00 + switch(op & 7) { + case 0 : if(((op >> 3) & 7)==0) { + sprintf (buffer,"hlt"); + } else { + if(((op >> 3) & 7)==7) { + sprintf (buffer,"illegal"); + } else { + sprintf (buffer,"in%c",reg[(op >> 3) & 7]); + } + } + break; + case 1 : if(((op >> 3) & 7)==0) { + sprintf (buffer,"hlt"); + } else { + if(((op >> 3) & 7)==7) { + sprintf (buffer,"illegal"); + } else { + sprintf (buffer,"dc%c",reg[(op >> 3) & 7]); + } + } + break; + case 2 : { + switch((op >> 3) & 7) { + case 0 : sprintf (buffer,"rlc"); break; + case 1 : sprintf (buffer,"rrc"); break; + case 2 : sprintf (buffer,"ral"); break; + case 3 : sprintf (buffer,"rar"); break; + default : sprintf (buffer,"illegal"); break; + } + } + break; + case 3 : sprintf (buffer,"r%c%c",(BIT(op,5) ? 't' : 'f'),flag_names[(op>>3)&3]); break; + case 4 : { + switch((op >> 3) & 7) { + case 0 : sprintf (buffer,"adi %02x",ARG(pc)); pc++; break; + case 1 : sprintf (buffer,"aci %02x",ARG(pc)); pc++; break; + case 2 : sprintf (buffer,"sui %02x",ARG(pc)); pc++; break; + case 3 : sprintf (buffer,"sbi %02x",ARG(pc)); pc++; break; + case 4 : sprintf (buffer,"ndi %02x",ARG(pc)); pc++; break; + case 5 : sprintf (buffer,"xri %02x",ARG(pc)); pc++; break; + case 6 : sprintf (buffer,"ori %02x",ARG(pc)); pc++; break; + case 7 : sprintf (buffer,"cpi %02x",ARG(pc)); pc++; break; + } + } + break; + case 5 : sprintf (buffer,"rst %02x",(op>>3) & 7); break; + case 6 : sprintf (buffer,"l%ci %02x",reg[(op >> 3) & 7],ARG(pc)); pc++; break; + case 7 : sprintf (buffer,"ret"); break; + } + break; + case 0x01: // starting with 01 + switch(op & 7) { + case 0 : sprintf (buffer,"j%c%c %02x%02x",(BIT(op,5)? 't' : 'f'),flag_names[(op>>3)&3], ARG(pc+1) & 0x3f,ARG(pc)); pc+=2; break; + case 2 : sprintf (buffer,"c%c%c %02x%02x",(BIT(op,5)? 't' : 'f'),flag_names[(op>>3)&3], ARG(pc+1) & 0x3f,ARG(pc)); pc+=2; break; + case 4 : sprintf (buffer,"jmp %02x%02x",ARG(pc+1) & 0x3f,ARG(pc)); pc+=2; break; + case 6 : sprintf (buffer,"cal %02x%02x",ARG(pc+1) & 0x3f,ARG(pc)); pc+=2; break; + case 1 : + case 3 : + case 5 : + case 7 : if (((op>>4)&3)==0) { + sprintf (buffer,"inp %02x",(op >> 1) & 0x07); + } else { + sprintf (buffer,"out %02x",(op >> 1) & 0x1f); + } + break; + } + break; + case 0x02: // starting with 10 + switch((op >> 3) & 7) { + case 0 : sprintf (buffer,"ad%c",reg[op & 7]); break; + case 1 : sprintf (buffer,"ac%c",reg[op & 7]); break; + case 2 : sprintf (buffer,"su%c",reg[op & 7]); break; + case 3 : sprintf (buffer,"sb%c",reg[op & 7]); break; + case 4 : sprintf (buffer,"nd%c",reg[op & 7]); break; + case 5 : sprintf (buffer,"xr%c",reg[op & 7]); break; + case 6 : sprintf (buffer,"or%c",reg[op & 7]); break; + case 7 : sprintf (buffer,"cp%c",reg[op & 7]); break; + } + break; + } + return (pc - PC) | flags | DASMFLAG_SUPPORTED; +} diff --git a/src/emu/cpu/i8008/i8008.c b/src/emu/cpu/i8008/i8008.c new file mode 100644 index 00000000000..52b5c5f32c5 --- /dev/null +++ b/src/emu/cpu/i8008/i8008.c @@ -0,0 +1,710 @@ +/***************************************************************************** + * + * i8008.c + * + * Intel 8008 CPU + * + * Initial version by Miodrag Milanovic + * + *****************************************************************************/ +#include "debugger.h" +#include "i8008.h" + +#define VERBOSE 0 + +#define LOG(x) do { if (VERBOSE) logerror x; } while (0) + +static UINT8 PARITY[256]; + +/*************************************************************************** + TYPE DEFINITIONS +***************************************************************************/ + +typedef struct _i8008_state i8008_state; +struct _i8008_state +{ + UINT8 A,B,C,D,E,H,L; + PAIR PC; // It is in fact one of ADDR regs + PAIR ADDR[8]; // Address registers + UINT8 CF; // Carry flag + UINT8 ZF; // Zero flag + UINT8 SF; // Sign flag + UINT8 PF; // Parity flag + UINT8 HALT; + const device_config *device; + const address_space *program; + const address_space *io; + cpu_state_table state; + int icount; + int pc_pos; // PC possition in ADDR + + cpu_irq_callback irq_callback; + UINT8 irq_state; +}; + +/*************************************************************************** + MACROS +***************************************************************************/ +#define REG_1 ((opcode >> 3) & 7) +#define REG_2 (opcode & 7) +#define GET_PC (cpustate->ADDR[cpustate->pc_pos]) + +/*************************************************************************** + CPU STATE DESCRIPTION +***************************************************************************/ + +#define I8008_STATE_ENTRY(_name, _format, _member, _datamask, _flags) \ + CPU_STATE_ENTRY(I8008_##_name, #_name, _format, i8008_state, _member, _datamask, ~0, _flags) + +static const cpu_state_entry state_array[] = +{ + I8008_STATE_ENTRY(PC, "%04X", PC.w.l, 0x3fff, 0) + I8008_STATE_ENTRY(GENPC,"%04X", PC.w.l, 0x3fff, CPUSTATE_NOSHOW) + I8008_STATE_ENTRY(A, "%02X", A, 0xff, 0) + I8008_STATE_ENTRY(B, "%02X", B, 0xff, 0) + I8008_STATE_ENTRY(C, "%02X", C, 0xff, 0) + I8008_STATE_ENTRY(D, "%02X", D, 0xff, 0) + I8008_STATE_ENTRY(E, "%02X", E, 0xff, 0) + I8008_STATE_ENTRY(H, "%02X", H, 0xff, 0) + I8008_STATE_ENTRY(L, "%02X", L, 0xff, 0) + I8008_STATE_ENTRY(ADDR1, "%04X", ADDR[0].w.l, 0x0fff, 0) + I8008_STATE_ENTRY(ADDR2, "%04X", ADDR[1].w.l, 0x0fff, 0) + I8008_STATE_ENTRY(ADDR3, "%04X", ADDR[2].w.l, 0x0fff, 0) + I8008_STATE_ENTRY(ADDR4, "%04X", ADDR[3].w.l, 0x0fff, 0) + I8008_STATE_ENTRY(ADDR5, "%04X", ADDR[4].w.l, 0x0fff, 0) + I8008_STATE_ENTRY(ADDR6, "%04X", ADDR[5].w.l, 0x0fff, 0) + I8008_STATE_ENTRY(ADDR7, "%04X", ADDR[6].w.l, 0x0fff, 0) + I8008_STATE_ENTRY(ADDR8, "%04X", ADDR[7].w.l, 0x0fff, 0) +}; + +static const cpu_state_table state_table_template = +{ + NULL, /* pointer to the base of state (offsets are relative to this) */ + 0, /* subtype this table refers to */ + ARRAY_LENGTH(state_array), /* number of entries */ + state_array /* array of entries */ +}; + +/*************************************************************************** + INLINE FUNCTIONS +***************************************************************************/ + +INLINE i8008_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_I8008); + return (i8008_state *)device->token; +} + +INLINE void PUSH_STACK(i8008_state *cpustate) +{ + cpustate->pc_pos = (cpustate->pc_pos + 1) & 7; +} + +INLINE void POP_STACK(i8008_state *cpustate) +{ + cpustate->ADDR[cpustate->pc_pos].d = 0; + cpustate->pc_pos = (cpustate->pc_pos - 1) & 7; +} + +INLINE UINT8 ROP(i8008_state *cpustate) +{ + UINT8 retVal = memory_decrypted_read_byte(cpustate->program, GET_PC.w.l); + GET_PC.w.l = (GET_PC.w.l + 1) & 0x3fff; + cpustate->PC = GET_PC; + return retVal; +} + +INLINE UINT8 GET_REG(i8008_state *cpustate,UINT8 reg) +{ + UINT8 retVal; + switch(reg) { + case 0 : retVal = cpustate->A; break; + case 1 : retVal = cpustate->B; break; + case 2 : retVal = cpustate->C; break; + case 3 : retVal = cpustate->D; break; + case 4 : retVal = cpustate->E; break; + case 5 : retVal = cpustate->H; break; + case 6 : retVal = cpustate->L; break; + default: retVal = memory_read_byte_8le(cpustate->program, (cpustate->H << 8) + cpustate->L); break; + } + return retVal; +} + +INLINE void SET_REG(i8008_state *cpustate,UINT8 reg, UINT8 val) +{ + switch(reg) { + case 0 : cpustate->A = val; break; + case 1 : cpustate->B = val; break; + case 2 : cpustate->C = val; break; + case 3 : cpustate->D = val; break; + case 4 : cpustate->E = val; break; + case 5 : cpustate->H = val; break; + case 6 : cpustate->L = val; break; + default: memory_write_byte_8le(cpustate->program, (cpustate->H << 8) + cpustate->L, val); break; + } +} + +INLINE UINT8 ARG(i8008_state *cpustate) +{ + UINT8 retVal = memory_raw_read_byte(cpustate->program, GET_PC.w.l); + GET_PC.w.l = (GET_PC.w.l + 1) & 0x3fff; + cpustate->PC = GET_PC; + return retVal; +} + +INLINE void UPDATE_FLAGS(i8008_state *cpustate,UINT8 val) +{ + cpustate->ZF = (val == 0) ? 1 : 0; + cpustate->SF = (val & 0x80) ? 1 : 0; + cpustate->PF = PARITY[val]; +} + +INLINE UINT8 DO_CONDITION(i8008_state *cpustate, UINT8 val) +{ + UINT8 v = (val >> 5) & 1; + UINT8 cond = 0; + switch((val>> 3) & 0x03) { + case 0 : + if (cpustate->CF==v) cond = 1; + break; + case 1 : + if (cpustate->ZF==v) cond = 1; + break; + case 2 : + if (cpustate->SF==v) cond = 1; + break; + case 3 : + if (cpustate->PF==v) cond = 1; + break; + } + return cond; +} + +INLINE UINT16 GET_ADDR(i8008_state *cpustate) +{ + UINT8 lo = ARG(cpustate); + UINT8 hi = ARG(cpustate); + return ((hi & 0x3f) << 8) + lo; +} + +INLINE void illegal(i8008_state *cpustate,UINT8 opcode) +{ +#if VERBOSE + UINT16 pc = cpustate->PC.w.l; + LOG(("I8008 illegal instruction %04X $%02X\n", pc, opcode)); +#endif +} + +static void execute_one(i8008_state *cpustate, int opcode) +{ + UINT16 tmp; + + switch (opcode >> 6) + { + case 0x03: // starting with 11 + if (opcode==0xff) { + // HLT + cpustate->icount -= 4; + GET_PC.w.l = GET_PC.w.l - 1; + cpustate->PC = GET_PC; + cpustate->HALT = 1; + } else { + // Lrr + cpustate->icount -= 5; + if (REG_1==7) cpustate->icount -= 2; + if (REG_2==7) cpustate->icount -= 3; + SET_REG(cpustate,REG_1, GET_REG(cpustate,REG_2)); + } + break; + case 0x00: // starting with 00 + switch(opcode & 7) { + case 0 : if(((opcode >> 3) & 7)==0) { + // HLT + cpustate->icount -= 4; + GET_PC.w.l = GET_PC.w.l - 1; + cpustate->PC = GET_PC; + cpustate->HALT = 1; + } else { + if(((opcode >> 3) & 7)==7) { + // ILLEGAL + cpustate->icount -= 5; + illegal(cpustate,opcode); + } else { + // INr + cpustate->icount -= 5; + tmp = GET_REG(cpustate,REG_1) + 1; + SET_REG(cpustate,REG_1, tmp & 0xff); + UPDATE_FLAGS(cpustate,tmp & 0xff); + } + } + break; + case 1 : if(((opcode >> 3) & 7)==0) { + // HLT + cpustate->icount -= 4; + GET_PC.w.l = GET_PC.w.l - 1; + cpustate->PC = GET_PC; + cpustate->HALT = 1; + } else { + if(((opcode >> 3) & 7)==7) { + // ILLEGAL + cpustate->icount -= 5; + illegal(cpustate,opcode); + } else { + // DCr + cpustate->icount -= 5; + tmp = GET_REG(cpustate,REG_1) - 1; + SET_REG(cpustate,REG_1, tmp & 0xff); + UPDATE_FLAGS(cpustate,tmp & 0xff); + } + } + break; + case 2 : { + // All instuction from this group have same timing + cpustate->icount -= 5; + switch((opcode >> 3) & 7) { + case 0 : + // RLC + tmp = cpustate->A; + cpustate->A = (cpustate->A << 1) | BIT(tmp,7); + cpustate->CF = BIT(tmp,7); + break; + case 1 : + // RRC + tmp = cpustate->A; + cpustate->A = (cpustate->A >> 1) | (BIT(tmp,0) ? 0x80 : 0x00); + cpustate->CF = BIT(tmp,0); + break; + case 2 : + // RAL + tmp = cpustate->A; + cpustate->A = (cpustate->A << 1) | cpustate->CF; + cpustate->CF = BIT(tmp,7); + break; + case 3 : + // RAR + tmp = cpustate->A; + cpustate->A = (cpustate->A >> 1) | (cpustate->CF ? 0x80 : 0x00); + cpustate->CF = BIT(tmp,0); + break; + default : + // ILLEGAL + illegal(cpustate,opcode); + break; + } + } + break; + case 3 : + // Rcc + { + cpustate->icount -= 3; + if (DO_CONDITION(cpustate,opcode)==1) { + cpustate->icount -= 2; + POP_STACK(cpustate); + cpustate->PC = GET_PC; + } + } + break; + case 4 : { + cpustate->icount -= 8; + switch((opcode >> 3) & 7) { + case 0 : + // ADI + tmp = GET_REG(cpustate,0) + ARG(cpustate); + SET_REG(cpustate,0,tmp & 0xff); + UPDATE_FLAGS(cpustate,tmp & 0xff); + cpustate->CF = (tmp >> 8) & 1; + break; + case 1 : + // ACI + tmp = GET_REG(cpustate,0) + ARG(cpustate) + cpustate->CF; + SET_REG(cpustate,0,tmp & 0xff); + UPDATE_FLAGS(cpustate,tmp & 0xff); + cpustate->CF = (tmp >> 8) & 1; + break; + case 2 : + // SUI + tmp = GET_REG(cpustate,0) - ARG(cpustate); + SET_REG(cpustate,0,tmp & 0xff); + UPDATE_FLAGS(cpustate,tmp & 0xff); + cpustate->CF = (tmp >> 8) & 1; + break; + case 3 : + // SBI + tmp = GET_REG(cpustate,0) - ARG(cpustate) - cpustate->CF; + SET_REG(cpustate,0,tmp & 0xff); + UPDATE_FLAGS(cpustate,tmp & 0xff); + cpustate->CF = (tmp >> 8) & 1; + break; + case 4 : + // NDI + tmp = GET_REG(cpustate,0) & ARG(cpustate); + SET_REG(cpustate,0,tmp & 0xff); + UPDATE_FLAGS(cpustate,tmp & 0xff); + break; + case 5 : + // XRI + tmp = GET_REG(cpustate,0) ^ ARG(cpustate); + SET_REG(cpustate,0,tmp & 0xff); + UPDATE_FLAGS(cpustate,tmp & 0xff); + break; + case 6 : + // ORI + tmp = GET_REG(cpustate,0) | ARG(cpustate); + SET_REG(cpustate,0,tmp & 0xff); + UPDATE_FLAGS(cpustate,tmp & 0xff); + break; + case 7 : + // CPI + tmp = GET_REG(cpustate,0) - ARG(cpustate); + UPDATE_FLAGS(cpustate,tmp & 0xff); + cpustate->CF = (tmp >> 8) & 1; + break; + } + } + break; + case 5 : // RST + cpustate->icount -= 5; + PUSH_STACK(cpustate); + GET_PC.w.l = opcode & 0x38; + cpustate->PC = GET_PC; + break; + case 6 : // LrI + cpustate->icount -= 8; + if (REG_1==7) cpustate->icount -= 1; // LMI + SET_REG(cpustate,REG_1, ARG(cpustate)); break; + case 7 : // RET + cpustate->icount -= 5; + POP_STACK(cpustate); + cpustate->PC = GET_PC; + break; + } + break; + + case 0x01: // starting with 01 + switch(opcode & 7) { + case 0 : + // Jcc + cpustate->icount -= 9; + tmp = GET_ADDR(cpustate); + if (DO_CONDITION(cpustate,opcode)==1) { + cpustate->icount -= 2; + GET_PC.w.l = tmp; + cpustate->PC = GET_PC; + } + break; + case 2 : + // Ccc + cpustate->icount -= 9; + tmp = GET_ADDR(cpustate); + if (DO_CONDITION(cpustate,opcode)==1) { + cpustate->icount -= 2; + PUSH_STACK(cpustate); + GET_PC.w.l = tmp; + cpustate->PC = GET_PC; + } + break; + case 4 : + // JMP + cpustate->icount -= 11; + GET_PC.w.l = GET_ADDR(cpustate); + cpustate->PC = GET_PC; + break; + case 6 : + // CAL + cpustate->icount -= 11; + tmp = GET_ADDR(cpustate); + PUSH_STACK(cpustate); + GET_PC.w.l = tmp; + cpustate->PC = GET_PC; + break; + default : + if (((opcode>>4)&3)==0) { + // INP + cpustate->icount -= 8; + cpustate->A = memory_read_byte_8le(cpustate->io, (opcode >> 1) & 0x1f); + } else { + // OUT + cpustate->icount -= 6; + memory_write_byte_8le(cpustate->io, (opcode >> 1) & 0x1f, cpustate->A); + } + break; + } + break; + case 0x02: // starting with 10 + cpustate->icount -= 5; + if ((opcode & 7)==7) cpustate->icount -= 3; // operations with memory + switch((opcode >> 3) & 7) { + case 0 : + // ADx + tmp = GET_REG(cpustate,0) + GET_REG(cpustate,opcode & 7); + SET_REG(cpustate,0,tmp & 0xff); + UPDATE_FLAGS(cpustate,tmp & 0xff); + cpustate->CF = (tmp >> 8) & 1; + break; + case 1 : + // ACx + tmp = GET_REG(cpustate,0) + GET_REG(cpustate,opcode & 7) + cpustate->CF; + SET_REG(cpustate,0,tmp & 0xff); + UPDATE_FLAGS(cpustate,tmp & 0xff); + cpustate->CF = (tmp >> 8) & 1; + break; + case 2 : + // SUx + tmp = GET_REG(cpustate,0) - GET_REG(cpustate,opcode & 7); + SET_REG(cpustate,0,tmp & 0xff); + UPDATE_FLAGS(cpustate,tmp & 0xff); + cpustate->CF = (tmp >> 8) & 1; + break; + case 3 : + // SBx + tmp = GET_REG(cpustate,0) - GET_REG(cpustate,opcode & 7) - cpustate->CF; + SET_REG(cpustate,0,tmp & 0xff); + UPDATE_FLAGS(cpustate,tmp & 0xff); + cpustate->CF = (tmp >> 8) & 1; + break; + case 4 : + // NDx + tmp = GET_REG(cpustate,0) & GET_REG(cpustate,opcode & 7); + SET_REG(cpustate,0,tmp & 0xff); + UPDATE_FLAGS(cpustate,tmp & 0xff); + break; + case 5 : + // XRx + tmp = GET_REG(cpustate,0) ^ GET_REG(cpustate,opcode & 7); + SET_REG(cpustate,0,tmp & 0xff); + UPDATE_FLAGS(cpustate,tmp & 0xff); + break; + case 6 : + // ORx + tmp = GET_REG(cpustate,0) | GET_REG(cpustate,opcode & 7); + SET_REG(cpustate,0,tmp & 0xff); + UPDATE_FLAGS(cpustate,tmp & 0xff); + break; + case 7 : + // CPx + tmp = GET_REG(cpustate,0) - GET_REG(cpustate,opcode & 7); + UPDATE_FLAGS(cpustate,tmp & 0xff); + cpustate->CF = (tmp >> 8) & 1; + break; + } + break; + } +} + + +/*************************************************************************** + COMMON EXECUTION +***************************************************************************/ +static void take_interrupt(i8008_state *cpustate) +{ + if (cpustate->HALT) { + GET_PC.w.l = (GET_PC.w.l + 1) & 0x3fff; + cpustate->PC = GET_PC; + cpustate->HALT = 0; + } + // For now only support one byte operation to be executed + execute_one(cpustate,(*cpustate->irq_callback)(cpustate->device, 0)); +} + +static CPU_EXECUTE( i8008 ) +{ + i8008_state *cpustate = get_safe_token(device); + + cpustate->icount = cycles; + + do + { + if (cpustate->irq_state != CLEAR_LINE) { + take_interrupt(cpustate); + } + debugger_instruction_hook(device, cpustate->PC.d); + execute_one(cpustate, ROP(cpustate)); + + } while (cpustate->icount > 0); + + return cycles - cpustate->icount; +} + +/*************************************************************************** + CORE INITIALIZATION +***************************************************************************/ +static void init_tables (void) +{ + int i; + UINT8 p; + for (i = 0; i < 256; i++) + { + p = 0; + if (BIT(i,0)) p++; + if (BIT(i,1)) p++; + if (BIT(i,2)) p++; + if (BIT(i,3)) p++; + if (BIT(i,4)) p++; + if (BIT(i,5)) p++; + if (BIT(i,6)) p++; + if (BIT(i,7)) p++; + PARITY[i] = ((p&1) ? 0 : 1); + } +} + +static CPU_INIT( i8008 ) +{ + i8008_state *cpustate = get_safe_token(device); + + /* set up the state table */ + cpustate->state = state_table_template; + cpustate->state.baseptr = cpustate; + cpustate->state.subtypemask = 1; + + cpustate->device = device; + + cpustate->program = memory_find_address_space(device, ADDRESS_SPACE_PROGRAM); + cpustate->io = memory_find_address_space(device, ADDRESS_SPACE_IO); + + cpustate->irq_callback = irqcallback; + + init_tables(); + + state_save_register_device_item(device, 0, cpustate->PC); + state_save_register_device_item(device, 0, cpustate->A); + state_save_register_device_item(device, 0, cpustate->B); + state_save_register_device_item(device, 0, cpustate->C); + state_save_register_device_item(device, 0, cpustate->D); + state_save_register_device_item(device, 0, cpustate->E); + state_save_register_device_item(device, 0, cpustate->H); + state_save_register_device_item(device, 0, cpustate->L); + state_save_register_device_item(device, 0, cpustate->CF); + state_save_register_device_item(device, 0, cpustate->SF); + state_save_register_device_item(device, 0, cpustate->ZF); + state_save_register_device_item(device, 0, cpustate->PF); + state_save_register_device_item(device, 0, cpustate->pc_pos); + state_save_register_device_item(device, 0, cpustate->ADDR[0]); + state_save_register_device_item(device, 0, cpustate->ADDR[1]); + state_save_register_device_item(device, 0, cpustate->ADDR[2]); + state_save_register_device_item(device, 0, cpustate->ADDR[3]); + state_save_register_device_item(device, 0, cpustate->ADDR[4]); + state_save_register_device_item(device, 0, cpustate->ADDR[5]); + state_save_register_device_item(device, 0, cpustate->ADDR[6]); + state_save_register_device_item(device, 0, cpustate->ADDR[7]); + state_save_register_device_item(device, 0, cpustate->HALT); + state_save_register_device_item(device, 0, cpustate->irq_state); +} + + + +/*************************************************************************** + COMMON RESET +***************************************************************************/ + +static CPU_RESET( i8008 ) +{ + i8008_state *cpustate = get_safe_token(device); + + cpustate->CF = cpustate->SF = cpustate->ZF = cpustate->PF = 0; + cpustate->A = cpustate->B = cpustate->C = cpustate->D = cpustate->E = cpustate->H = cpustate->L = 0; + cpustate->PC.d = 0; + cpustate->pc_pos = 0; + cpustate->HALT = 0; + cpustate->irq_state = CLEAR_LINE; + memset(cpustate->ADDR,0,sizeof(cpustate->ADDR)); + +} + +/**************************************************************************** + * Set IRQ line state + ****************************************************************************/ +static void set_irq_line(i8008_state *cpustate, int irqline, int state) +{ + cpustate->irq_state = state; +} + +/*************************************************************************** + COMMON STATE IMPORT/EXPORT +***************************************************************************/ + +static CPU_IMPORT_STATE( i8008 ) +{ +} + +static CPU_EXPORT_STATE( i8008 ) +{ +} + +/*************************************************************************** + COMMON SET INFO +***************************************************************************/ +static CPU_SET_INFO( i8008 ) +{ + i8008_state *cpustate = 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(cpustate, 0, info->i); break; + } +} + +/*************************************************************************** + 8008 GET INFO +***************************************************************************/ + +CPU_GET_INFO( i8008 ) +{ + i8008_state *cpustate = (device != NULL && device->token != NULL) ? get_safe_token(device) : NULL; + switch (state) + { + /* --- the following bits of info are returned as 64-bit signed integers --- */ + case CPUINFO_INT_CONTEXT_SIZE: info->i = sizeof(i8008_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_LITTLE; 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 = 1; break; + case CPUINFO_INT_MAX_INSTRUCTION_BYTES: info->i = 3; break; + case CPUINFO_INT_MIN_CYCLES: info->i = 8; break; + case CPUINFO_INT_MAX_CYCLES: info->i = 16; break; + + case CPUINFO_INT_DATABUS_WIDTH_PROGRAM: info->i = 8; break; + case CPUINFO_INT_ADDRBUS_WIDTH_PROGRAM: info->i = 14; 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 = 8; break; + case CPUINFO_INT_ADDRBUS_WIDTH_IO: info->i = 8; break; + case CPUINFO_INT_ADDRBUS_SHIFT_IO: info->i = 0; break; + + /* --- the following bits of info are returned as pointers to functions --- */ + case CPUINFO_FCT_SET_INFO: info->setinfo = CPU_SET_INFO_NAME(i8008); break; + case CPUINFO_FCT_INIT: info->init = CPU_INIT_NAME(i8008); break; + case CPUINFO_FCT_RESET: info->reset = CPU_RESET_NAME(i8008); break; + case CPUINFO_FCT_EXECUTE: info->execute = CPU_EXECUTE_NAME(i8008); break; + case CPUINFO_FCT_DISASSEMBLE: info->disassemble = CPU_DISASSEMBLE_NAME(i8008); break; + case CPUINFO_FCT_IMPORT_STATE: info->import_state = CPU_IMPORT_STATE_NAME(i8008); break; + case CPUINFO_FCT_EXPORT_STATE: info->export_state = CPU_EXPORT_STATE_NAME(i8008); break; + + /* --- the following bits of info are returned as pointers --- */ + case CPUINFO_PTR_INSTRUCTION_COUNTER: info->icount = &cpustate->icount; break; + case CPUINFO_PTR_STATE_TABLE: info->state_table = &cpustate->state; break; + + /* --- the following bits of info are returned as NULL-terminated strings --- */ + case DEVINFO_STR_NAME: strcpy(info->s, "8008"); break; + case DEVINFO_STR_FAMILY: strcpy(info->s, "Intel 8008"); 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 Miodrag Milanovic"); break; + + case CPUINFO_STR_FLAGS: + sprintf(info->s, "%c%c%c%c", + cpustate->CF ? 'C':'.', + cpustate->ZF ? 'Z':'.', + cpustate->SF ? 'S':'.', + cpustate->PF ? 'P':'.'); + break; + } +} diff --git a/src/emu/cpu/i8008/i8008.h b/src/emu/cpu/i8008/i8008.h new file mode 100644 index 00000000000..5687bb03cf4 --- /dev/null +++ b/src/emu/cpu/i8008/i8008.h @@ -0,0 +1,33 @@ +#ifndef __I8008_H__ +#define __I8008_H__ + +#include "cpuintrf.h" + + +/*************************************************************************** + CONSTANTS +***************************************************************************/ + +enum +{ + I8008_PC, + I8008_A,I8008_B,I8008_C,I8008_D,I8008_E,I8008_H,I8008_L, + I8008_ADDR1,I8008_ADDR2,I8008_ADDR3,I8008_ADDR4,I8008_ADDR5,I8008_ADDR6,I8008_ADDR7,I8008_ADDR8, + I8008_GENPC = REG_GENPC, + I8008_GENSP = REG_GENSP, + I8008_GENPCBASE = REG_GENPCBASE +}; + +/*************************************************************************** + TYPE DEFINITIONS +***************************************************************************/ + +/*************************************************************************** + FUNCTION PROTOTYPES +***************************************************************************/ + +CPU_GET_INFO( i8008 ); +#define CPU_I8008 CPU_GET_INFO_NAME( i8008 ) + +CPU_DISASSEMBLE( i8008 ); +#endif diff --git a/src/emu/cpu/scmp/scmp.c b/src/emu/cpu/scmp/scmp.c new file mode 100644 index 00000000000..529a4a28ad2 --- /dev/null +++ b/src/emu/cpu/scmp/scmp.c @@ -0,0 +1,663 @@ +/***************************************************************************** + * + * scmp.c + * + * National Semiconductor SC/MP CPU Disassembly + * + * Initial version by Miodrag Milanovic + * + *****************************************************************************/ + +#include "debugger.h" +#include "scmp.h" + +#define VERBOSE 0 + +#define LOG(x) do { if (VERBOSE) logerror x; } while (0) + +/*************************************************************************** + TYPE DEFINITIONS +***************************************************************************/ + +typedef struct _scmp_state scmp_state; +struct _scmp_state +{ + scmp_config config; + PAIR PC; + PAIR P1; + PAIR P2; + PAIR P3; + UINT8 AC; + UINT8 ER; + UINT8 SR; + + const device_config *device; + const address_space *program; + const address_space *io; + cpu_state_table state; + int icount; + + devcb_resolved_write8 flag_out_func; + devcb_resolved_write_line sout_func; + devcb_resolved_read_line sin_func; + devcb_resolved_read_line sensea_func; + devcb_resolved_read_line senseb_func; + devcb_resolved_write_line halt_func; +}; + +/*************************************************************************** + MACROS +***************************************************************************/ + +/*************************************************************************** + CPU STATE DESCRIPTION +***************************************************************************/ + +#define SCMP_STATE_ENTRY(_name, _format, _member, _datamask, _flags) \ + CPU_STATE_ENTRY(SCMP_##_name, #_name, _format, scmp_state, _member, _datamask, ~0, _flags) + +static const cpu_state_entry state_array[] = +{ + SCMP_STATE_ENTRY(PC, "%04X", PC.w.l, 0xffff, 0) + SCMP_STATE_ENTRY(GENPC,"%04X", PC.w.l, 0xffff, CPUSTATE_NOSHOW) + SCMP_STATE_ENTRY(P1, "%04X", P1.w.l, 0xffff, 0) + SCMP_STATE_ENTRY(P2, "%04X", P2.w.l, 0xffff, 0) + SCMP_STATE_ENTRY(P3, "%04X", P3.w.l, 0xffff, 0) + SCMP_STATE_ENTRY(AC, "%02X", AC, 0xff, 0) + SCMP_STATE_ENTRY(ER, "%02X", ER, 0xff, 0) + SCMP_STATE_ENTRY(SR, "%02X", SR, 0xff, 0) + +}; + +static const cpu_state_table state_table_template = +{ + NULL, /* pointer to the base of state (offsets are relative to this) */ + 0, /* subtype this table refers to */ + ARRAY_LENGTH(state_array), /* number of entries */ + state_array /* array of entries */ +}; + +/*************************************************************************** + INLINE FUNCTIONS +***************************************************************************/ + +INLINE scmp_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_SCMP); + return (scmp_state *)device->token; +} + +INLINE UINT16 ADD12(UINT16 addr, INT8 val) +{ + return ((addr + val) & 0x0fff) | (addr & 0xf000); +} + +INLINE UINT8 ROP(scmp_state *cpustate) +{ + UINT16 pc = cpustate->PC.w.l; + cpustate->PC.w.l = ADD12(cpustate->PC.w.l,1); + return memory_decrypted_read_byte(cpustate->program, pc); +} + +INLINE UINT8 ARG(scmp_state *cpustate) +{ + UINT16 pc = cpustate->PC.w.l; + cpustate->PC.w.l = ADD12(cpustate->PC.w.l,1); + return memory_raw_read_byte(cpustate->program, pc); +} + +INLINE UINT8 RM(scmp_state *cpustate,UINT32 a) +{ + return memory_read_byte_8le(cpustate->program, a); +} + +INLINE void WM(scmp_state *cpustate,UINT32 a, UINT8 v) +{ + memory_write_byte_8le(cpustate->program, a, v); +} + +INLINE void illegal(scmp_state *cpustate,UINT8 opcode) +{ +#if VERBOSE + UINT16 pc = cpustate->PC.w.l; + LOG(("SC/MP illegal instruction %04X $%02X\n", pc-1, opcode)); +#endif +} + +INLINE PAIR *GET_PTR_REG(scmp_state *cpustate, int num) +{ + switch(num) { + case 1: return &cpustate->P1; + case 2: return &cpustate->P2; + case 3: return &cpustate->P3; + default : + return &cpustate->PC; + } +} + +INLINE void BIN_ADD(scmp_state *cpustate, UINT8 val) +{ + UINT16 tmp = cpustate->AC + val + ((cpustate->SR >> 7) & 1); + UINT8 ov = (((cpustate->AC & 0x80)==(val & 0x80)) && ((cpustate->AC & 0x80)!=(tmp & 0x80))) ? 0x40 : 0x00; + + cpustate->AC = tmp & 0xff; + cpustate->SR &= 0x3f; // clear CY/L and OV flag + cpustate->SR |= (tmp & 0x100) ? 0x80 : 0x00; // set CY/L + cpustate->SR |= ov; +} + +INLINE void DEC_ADD(scmp_state *cpustate, UINT8 val) +{ + UINT16 tmp = cpustate->AC + val + ((cpustate->SR >> 7) & 1); + if ((tmp & 0x0f) > 9) tmp +=6; + cpustate->AC = tmp % 0xa0; + cpustate->SR &= 0x7f; // clear CY/L flag + cpustate->SR |= (tmp > 0x99) ? 0x80 : 0x00; +} + +INLINE UINT16 GET_ADDR(scmp_state *cpustate, UINT8 code) +{ + UINT16 addr = 0; + INT8 offset = 0; + UINT16 retVal = 0; + UINT16 ptr = GET_PTR_REG(cpustate,code & 0x03)->w.l; + + UINT8 arg = ARG(cpustate); + if (arg == 0x80) { + offset = cpustate->ER; + } else { + if (arg & 0x80) { + offset = (INT8)arg; + } else { + offset = arg; + } + } + + addr = ADD12(ptr,offset); + + if (code & 0x04) { + if (code & 0x03) { + // Auto-indexed + if (offset < 0) { + // pre decrement + GET_PTR_REG(cpustate,code & 0x03)->w.l = addr; + retVal = addr; + } else { + // post increment + retVal = ptr; + GET_PTR_REG(cpustate,code & 0x03)->w.l = addr; + } + } else { + // Immediate + } + } else { + // Indexed + retVal = addr; + } + return retVal; +} + +static void execute_one(scmp_state *cpustate, int opcode) +{ + UINT8 tmp; + UINT8 ptr = opcode & 3; + if (BIT(opcode,7)) { + // two bytes instructions + switch (opcode) + { + // Memory Reference Instructions + case 0xc0 : case 0xc1 : case 0xc2 : case 0xc3 : + case 0xc5 : case 0xc6 : case 0xc7 : + //LD + cpustate->icount -= 18; + cpustate->AC = RM(cpustate,GET_ADDR(cpustate,opcode)); + break; + case 0xc8 : case 0xc9 : case 0xca : case 0xcb : + case 0xcd : case 0xce : case 0xcf : + // ST + cpustate->icount -= 18; + WM(cpustate,GET_ADDR(cpustate,opcode),cpustate->AC); + break; + case 0xd0 : case 0xd1 : case 0xd2 : case 0xd3 : + case 0xd5 : case 0xd6 : case 0xd7 : + // AND + cpustate->icount -= 18; + cpustate->AC &= RM(cpustate,GET_ADDR(cpustate,opcode)); + break; + case 0xd8 : case 0xd9 : case 0xda : case 0xdb : + case 0xdd : case 0xde : case 0xdf : + //OR + cpustate->icount -= 18; + cpustate->AC |= RM(cpustate,GET_ADDR(cpustate,opcode)); + break; + case 0xe0 : case 0xe1 : case 0xe2 : case 0xe3 : + case 0xe5 : case 0xe6 : case 0xe7 : + // XOR + cpustate->icount -= 18; + cpustate->AC ^= RM(cpustate,GET_ADDR(cpustate,opcode)); + break; + case 0xe8 : case 0xe9 : case 0xea : case 0xeb : + case 0xed : case 0xee : case 0xef : + // DAD + cpustate->icount -= 23; + DEC_ADD(cpustate,RM(cpustate,GET_ADDR(cpustate,opcode))); + break; + case 0xf0 : case 0xf1 : case 0xf2 : case 0xf3 : + case 0xf5 : case 0xf6 : case 0xf7 : + // ADD + cpustate->icount -= 19; + BIN_ADD(cpustate,RM(cpustate,GET_ADDR(cpustate,opcode))); + break; + case 0xf8 : case 0xf9 : case 0xfa : case 0xfb : + case 0xfd : case 0xfe : case 0xff : + // CAD + cpustate->icount -= 20; + BIN_ADD(cpustate,~RM(cpustate,GET_ADDR(cpustate,opcode))); + break; + // Memory Increment/Decrement Instructions + case 0xa8 : case 0xa9 : case 0xaa : case 0xab : + // IDL + { + UINT16 addr = GET_ADDR(cpustate,opcode); + cpustate->icount -= 22; + cpustate->AC = RM(cpustate,addr) + 1; + WM(cpustate,addr,cpustate->AC); + } + break; + case 0xb8 : case 0xb9 : case 0xba : case 0xbb : + // DLD + { + UINT16 addr = GET_ADDR(cpustate,opcode); + cpustate->icount -= 22; + cpustate->AC = RM(cpustate,addr) - 1; + WM(cpustate,addr,cpustate->AC); + } + break; + // Immediate Instructions + case 0xc4 : // LDI + cpustate->icount -= 10; + cpustate->AC = ARG(cpustate); + break; + case 0xd4 : // ANI + cpustate->icount -= 10; + cpustate->AC &= ARG(cpustate); + break; + case 0xdc : // ORI + cpustate->icount -= 10; + cpustate->AC |= ARG(cpustate); + break; + case 0xe4 : // XRI + cpustate->icount -= 10; + cpustate->AC ^= ARG(cpustate); + break; + case 0xec : // DAI + cpustate->icount -= 15; + DEC_ADD(cpustate,ARG(cpustate)); + break; + case 0xf4 : // ADI + cpustate->icount -= 11; + BIN_ADD(cpustate,ARG(cpustate)); + break; + case 0xfc : // CAI + cpustate->icount -= 12; + BIN_ADD(cpustate,~ARG(cpustate)); + break; + // Transfer Instructions + case 0x90 : case 0x91 : case 0x92 : case 0x93 :// JMP + cpustate->icount -= 11; + cpustate->PC.w.l = ADD12(GET_PTR_REG(cpustate,ptr)->w.l,(INT8)ARG(cpustate)); + break; + case 0x94 : case 0x95 : case 0x96 : case 0x97 : + // JP + cpustate->icount -= 9; + tmp = ARG(cpustate); + if (!cpustate->AC & 0x80) { + cpustate->PC.w.l = ADD12(GET_PTR_REG(cpustate,ptr)->w.l,(INT8)tmp); + cpustate->icount -= 2; + } + break; + case 0x98 : case 0x99 : case 0x9a : case 0x9b : + // JZ + cpustate->icount -= 9; + tmp = ARG(cpustate); + if (!cpustate->AC) { + cpustate->PC.w.l = ADD12(GET_PTR_REG(cpustate,ptr)->w.l,(INT8)tmp); + cpustate->icount -= 2; + } + break; + case 0x9c : case 0x9d : case 0x9e : case 0x9f : + // JNZ + cpustate->icount -= 9; + tmp = ARG(cpustate); + if (cpustate->AC) { + cpustate->PC.w.l = ADD12(GET_PTR_REG(cpustate,ptr)->w.l,(INT8)tmp); + cpustate->icount -= 2; + } + break; + // Double-Byte Miscellaneous Instructions + case 0x8f: // DLY + tmp = ARG(cpustate); + cpustate->icount -= 13 + (cpustate->AC * 2) + (((UINT32)tmp) << 1) + (((UINT32)tmp) << 9); + cpustate->AC = 0xff; + break; + // Others are illegal + default : cpustate->icount -= 1; + illegal (cpustate,opcode); + break; + } + } else { + // one byte instructions + switch (opcode) + { + // Extension Register Instructions + case 0x40: // LDE + cpustate->icount -= 6; + cpustate->AC = cpustate->ER; + break; + case 0x01: // XAE + cpustate->icount -= 7; + tmp = cpustate->AC; + cpustate->AC = cpustate->ER; + cpustate->ER = tmp; + break; + case 0x50: // ANE + cpustate->icount -= 6; + cpustate->AC &= cpustate->ER; + break; + case 0x58: // ORE + cpustate->icount -= 6; + cpustate->AC |= cpustate->ER; + break; + case 0x60: // XRE + cpustate->icount -= 6; + cpustate->AC ^= cpustate->ER; + break; + case 0x68: // DAE + cpustate->icount -= 11; + DEC_ADD(cpustate,cpustate->ER); + break; + case 0x70: // ADE + cpustate->icount -= 7; + BIN_ADD(cpustate,cpustate->ER); + break; + case 0x78: // CAE + cpustate->icount -= 8; + BIN_ADD(cpustate,~cpustate->ER); + break; + // Pointer Register Move Instructions + case 0x30: case 0x31: case 0x32: case 0x33: // XPAL + cpustate->icount -= 8; + tmp = cpustate->AC; + cpustate->AC = GET_PTR_REG(cpustate,ptr)->b.l; + GET_PTR_REG(cpustate,ptr)->b.l = tmp; + break; + case 0x34: case 0x35 :case 0x36: case 0x37: + // XPAH + cpustate->icount -= 8; + tmp = cpustate->AC; + cpustate->AC = GET_PTR_REG(cpustate,ptr)->b.h; + GET_PTR_REG(cpustate,ptr)->b.h = tmp; + break; + case 0x3c: case 0x3d :case 0x3e: case 0x3f: + // XPPC + { + UINT16 tmp = ADD12(cpustate->PC.w.l,-1); // Since PC is incremented we need to fix it + cpustate->icount -= 7; + cpustate->PC.w.l = GET_PTR_REG(cpustate,ptr)->w.l; + GET_PTR_REG(cpustate,ptr)->w.l = tmp; + // After exchange CPU increment PC + cpustate->PC.w.l = ADD12(cpustate->PC.w.l,1); + } + break; + // Shift, Rotate, Serial I/O Instructions + case 0x19: // SIO + cpustate->icount -= 5; + devcb_call_write_line(&cpustate->sout_func, cpustate->ER & 0x01); + cpustate->ER >>= 1; + cpustate->ER |= devcb_call_read_line(&cpustate->sin_func) ? 0x80 : 0x00; + break; + case 0x1c: // SR + cpustate->icount -= 5; + cpustate->AC >>= 1; + break; + case 0x1d: // SRL + cpustate->icount -= 5; + cpustate->AC >>= 1; + cpustate->AC |= cpustate->SR & 0x80; // add C/L flag + break; + case 0x1e: // RR + cpustate->icount -= 5; + cpustate->AC = (cpustate->AC >> 1) | ((cpustate->AC & 0x01) << 7); + break; + case 0x1f: // RRL + cpustate->icount -= 5; + tmp = (cpustate->AC & 0x01) << 7; + cpustate->AC = (cpustate->AC >> 1) | (cpustate->SR & 0x80); + cpustate->SR = (cpustate->SR & 0x7f) | tmp; + break; + // Single Byte Miscellaneous Instructions + case 0x00: // HALT + cpustate->icount -= 8; + devcb_call_write_line(&cpustate->halt_func, 1); + devcb_call_write_line(&cpustate->halt_func, 0); + break; + case 0x02: // CCL + cpustate->icount -= 5; + cpustate->SR &= 0x7f; + break; + case 0x03: // SCL + cpustate->icount -= 5; + cpustate->SR |= 0x80; + break; + case 0x04: // DINT + cpustate->icount -= 6; + cpustate->SR &= 0xf7; + break; + case 0x05: // IEN + cpustate->icount -= 6; + cpustate->SR |= 0x08; + break; + case 0x06: // CSA + cpustate->icount -= 5; + cpustate->SR &= 0xcf; // clear SA and SB flags + cpustate->SR |= devcb_call_read_line(&cpustate->sensea_func) ? 0x10 : 0x00; + cpustate->SR |= devcb_call_read_line(&cpustate->senseb_func) ? 0x20 : 0x00; + cpustate->AC = cpustate->SR; + break; + case 0x07: // CAS + cpustate->icount -= 6; + cpustate->SR = cpustate->AC; + devcb_call_write8(&cpustate->flag_out_func, 0, cpustate->SR & 0x07); + break; + case 0x08: // NOP + cpustate->icount -= 5; + break; + // Others are illegal + default : cpustate->icount -= 1; + illegal (cpustate,opcode); + break; + } + } +} + + +/*************************************************************************** + COMMON EXECUTION +***************************************************************************/ +static void take_interrupt(scmp_state *cpustate) +{ + UINT16 tmp = ADD12(cpustate->PC.w.l,-1); // We fix PC so at return it goes to current location + cpustate->SR &= 0xf7; // clear IE flag + + cpustate->icount -= 8; // assumption + // do XPPC 3 + cpustate->PC.w.l = GET_PTR_REG(cpustate,3)->w.l; + GET_PTR_REG(cpustate,3)->w.l = tmp; + // After exchange CPU increment PC + cpustate->PC.w.l = ADD12(cpustate->PC.w.l,1); +} + +static CPU_EXECUTE( scmp ) +{ + scmp_state *cpustate = get_safe_token(device); + + cpustate->icount = cycles; + + do + { + if ((cpustate->SR & 0x08) && (devcb_call_read_line(&cpustate->sensea_func))) { + take_interrupt(cpustate); + } + debugger_instruction_hook(device, cpustate->PC.d); + execute_one(cpustate, ROP(cpustate)); + + } while (cpustate->icount > 0); + + return cycles - cpustate->icount; +} + +/*************************************************************************** + CORE INITIALIZATION +***************************************************************************/ + +static CPU_INIT( scmp ) +{ + scmp_state *cpustate = get_safe_token(device); + + if (device->static_config != NULL) + cpustate->config = *(scmp_config *)device->static_config; + /* set up the state table */ + cpustate->state = state_table_template; + cpustate->state.baseptr = cpustate; + cpustate->state.subtypemask = 1; + + cpustate->device = device; + + cpustate->program = memory_find_address_space(device, ADDRESS_SPACE_PROGRAM); + + /* resolve callbacks */ + devcb_resolve_write8(&cpustate->flag_out_func, &cpustate->config.flag_out_func, device); + devcb_resolve_write_line(&cpustate->sout_func, &cpustate->config.sout_func, device); + devcb_resolve_read_line(&cpustate->sin_func, &cpustate->config.sin_func, device); + devcb_resolve_read_line(&cpustate->sensea_func, &cpustate->config.sensea_func, device); + devcb_resolve_read_line(&cpustate->senseb_func, &cpustate->config.senseb_func, device); + devcb_resolve_write_line(&cpustate->halt_func, &cpustate->config.halt_func, device); + + state_save_register_device_item(device, 0, cpustate->PC); + state_save_register_device_item(device, 0, cpustate->P1); + state_save_register_device_item(device, 0, cpustate->P2); + state_save_register_device_item(device, 0, cpustate->P3); + state_save_register_device_item(device, 0, cpustate->AC); + state_save_register_device_item(device, 0, cpustate->ER); + state_save_register_device_item(device, 0, cpustate->SR); +} + + + +/*************************************************************************** + COMMON RESET +***************************************************************************/ + +static CPU_RESET( scmp ) +{ + scmp_state *cpustate = get_safe_token(device); + + cpustate->PC.d = 0; + cpustate->P1.d = 0; + cpustate->P2.d = 0; + cpustate->P3.d = 0; + cpustate->AC = 0; + cpustate->ER = 0; + cpustate->SR = 0; +} + + + +/*************************************************************************** + COMMON STATE IMPORT/EXPORT +***************************************************************************/ + +static CPU_IMPORT_STATE( scmp ) +{ +} + +static CPU_EXPORT_STATE( scmp ) +{ +} + +/*************************************************************************** + COMMON SET INFO +***************************************************************************/ +static CPU_SET_INFO( scmp ) +{ +} + +/*************************************************************************** + SCMP GET INFO +***************************************************************************/ + +CPU_GET_INFO( scmp ) +{ + scmp_state *cpustate = (device != NULL && device->token != NULL) ? get_safe_token(device) : NULL; + switch (state) + { + /* --- the following bits of info are returned as 64-bit signed integers --- */ + case CPUINFO_INT_CONTEXT_SIZE: info->i = sizeof(scmp_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_LITTLE; 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 = 1; break; + case CPUINFO_INT_MAX_INSTRUCTION_BYTES: info->i = 2; break; + case CPUINFO_INT_MIN_CYCLES: info->i = 5; break; + case CPUINFO_INT_MAX_CYCLES: info->i = 131593; break; // DLY instruction max time + + case CPUINFO_INT_DATABUS_WIDTH_PROGRAM: info->i = 8; break; + case CPUINFO_INT_ADDRBUS_WIDTH_PROGRAM: info->i = 16; 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; + + /* --- the following bits of info are returned as pointers to functions --- */ + case CPUINFO_FCT_SET_INFO: info->setinfo = CPU_SET_INFO_NAME(scmp); break; + case CPUINFO_FCT_INIT: info->init = CPU_INIT_NAME(scmp); break; + case CPUINFO_FCT_RESET: info->reset = CPU_RESET_NAME(scmp); break; + case CPUINFO_FCT_EXECUTE: info->execute = CPU_EXECUTE_NAME(scmp); break; + case CPUINFO_FCT_DISASSEMBLE: info->disassemble = CPU_DISASSEMBLE_NAME(scmp); break; + case CPUINFO_FCT_IMPORT_STATE: info->import_state = CPU_IMPORT_STATE_NAME(scmp); break; + case CPUINFO_FCT_EXPORT_STATE: info->export_state = CPU_EXPORT_STATE_NAME(scmp); break; + + /* --- the following bits of info are returned as pointers --- */ + case CPUINFO_PTR_INSTRUCTION_COUNTER: info->icount = &cpustate->icount; break; + case CPUINFO_PTR_STATE_TABLE: info->state_table = &cpustate->state; break; + + /* --- the following bits of info are returned as NULL-terminated strings --- */ + case DEVINFO_STR_NAME: strcpy(info->s, "SC/MP"); break; + case DEVINFO_STR_FAMILY: strcpy(info->s, "National Semiconductor SC/MP"); 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 Miodrag Milanovic"); break; + + case CPUINFO_STR_FLAGS: + sprintf(info->s, "%c%c%c%c%c%c%c%c", + (cpustate->SR & 0x80) ? 'C' : '.', + (cpustate->SR & 0x40) ? 'V' : '.', + (cpustate->SR & 0x20) ? 'B' : '.', + (cpustate->SR & 0x10) ? 'A' : '.', + (cpustate->SR & 0x08) ? 'I' : '.', + (cpustate->SR & 0x04) ? '2' : '.', + (cpustate->SR & 0x02) ? '1' : '.', + (cpustate->SR & 0x01) ? '0' : '.'); + break; + } +} diff --git a/src/emu/cpu/scmp/scmp.h b/src/emu/cpu/scmp/scmp.h new file mode 100644 index 00000000000..62df8e84208 --- /dev/null +++ b/src/emu/cpu/scmp/scmp.h @@ -0,0 +1,43 @@ +#ifndef __SCMP_H__ +#define __SCMP_H__ + +#include "cpuintrf.h" +#include "devcb.h" + +/*************************************************************************** + CONSTANTS +***************************************************************************/ + +enum +{ + SCMP_PC, SCMP_P1, SCMP_P2, SCMP_P3, SCMP_AC, SCMP_ER, SCMP_SR, + SCMP_GENPC = REG_GENPC, + SCMP_GENSP = REG_GENSP, + SCMP_GENPCBASE = REG_GENPCBASE +}; + +/*************************************************************************** + TYPE DEFINITIONS +***************************************************************************/ +typedef struct _scmp_config scmp_config; +struct _scmp_config +{ + devcb_write8 flag_out_func; + devcb_write_line sout_func; + devcb_read_line sin_func; + devcb_read_line sensea_func; + devcb_read_line senseb_func; + devcb_write_line halt_func; +}; +#define SCMP_CONFIG(name) const scmp_config (name) = + +/*************************************************************************** + FUNCTION PROTOTYPES +***************************************************************************/ + +CPU_GET_INFO( scmp ); +#define CPU_SCMP CPU_GET_INFO_NAME( scmp ) + +CPU_DISASSEMBLE( scmp ); + +#endif diff --git a/src/emu/cpu/scmp/scmpdasm.c b/src/emu/cpu/scmp/scmpdasm.c new file mode 100644 index 00000000000..e0113efe543 --- /dev/null +++ b/src/emu/cpu/scmp/scmpdasm.c @@ -0,0 +1,153 @@ +/***************************************************************************** + * + * scmpdasm.c + * + * National Semiconductor SC/MP CPU Disassembly + * + * Initial version by Miodrag Milanovic + * + *****************************************************************************/ + +#include "cpuintrf.h" + +#define OP(A) oprom[(A) - PC] +#define ARG(A) opram[(A) - PC] + +CPU_DISASSEMBLE( scmp ) +{ + unsigned PC = pc; + UINT8 op = OP(pc++); + UINT8 ptr = op & 3; + + if (BIT(op,7)) { + // two bytes instructions + char as[10]; + char aspr[10]; + UINT8 arg = ARG(pc); pc++; + if (arg==0x80) { + sprintf(as,"E"); + } else { + if (arg & 0x80) { + sprintf(as,"-$%02x",0x100-arg); + } else { + sprintf(as,"+$%02x",arg); + } + } + sprintf(aspr,"%s(%d)",as,ptr); + + switch (op) + { + // Memory Reference Instructions + case 0xc0 : sprintf (buffer,"ld %s",as); break; + case 0xc1 : case 0xc2 : case 0xc3 : + sprintf (buffer,"ld %s",aspr);break; + case 0xc5 : case 0xc6 : case 0xc7 : + sprintf (buffer,"ld @%s",aspr); break; + case 0xc8 : sprintf (buffer,"st %s",as); break; + case 0xc9 : case 0xca : case 0xcb : + sprintf (buffer,"st %s",aspr);break; + case 0xcd : case 0xce : case 0xcf : + sprintf (buffer,"st @%s",aspr); break; + case 0xd0 : sprintf (buffer,"and %s",as); break; + case 0xd1 : case 0xd2 : case 0xd3 : + sprintf (buffer,"and %s",aspr);break; + case 0xd5 : case 0xd6 : case 0xd7 : + sprintf (buffer,"and @%s",aspr); break; + case 0xd8 : sprintf (buffer,"or %s",as); break; + case 0xd9 : case 0xda : case 0xdb : + sprintf (buffer,"or %s",aspr);break; + case 0xdd : case 0xde : case 0xdf : + sprintf (buffer,"or @%s",aspr); break; + case 0xe0 : sprintf (buffer,"xor %s",as); break; + case 0xe1 : case 0xe2 : case 0xe3 : + sprintf (buffer,"xor %s",aspr);break; + case 0xe5 : case 0xe6 : case 0xe7 : + sprintf (buffer,"xor @%s",aspr); break; + case 0xe8 : sprintf (buffer,"dad %s",as); break; + case 0xe9 : case 0xea : case 0xeb : + sprintf (buffer,"dad %s",aspr);break; + case 0xed : case 0xee : case 0xef : + sprintf (buffer,"dad @%s",aspr); break; + case 0xf0 : sprintf (buffer,"add %s",as); break; + case 0xf1 : case 0xf2 : case 0xf3 : + sprintf (buffer,"add %s",aspr);break; + case 0xf5 : case 0xf6 : case 0xf7 : + sprintf (buffer,"add @%s",aspr); break; + case 0xf8 : sprintf (buffer,"cad %s",as); break; + case 0xf9 : case 0xfa : case 0xfb : + sprintf (buffer,"cad %s",aspr);break; + case 0xfd : case 0xfe : case 0xff : + sprintf (buffer,"cad @%s",aspr); break; + // Memory Increment/Decrement Instructions + case 0xa8 : case 0xa9 : case 0xaa : case 0xab : + sprintf (buffer,"ild %s",aspr); break; + case 0xb8 : case 0xb9 : case 0xba : case 0xbb : + sprintf (buffer,"dld %s",aspr); break; + // Immediate Instructions + case 0xc4 : sprintf (buffer,"ldi $%02x",arg); break; + case 0xd4 : sprintf (buffer,"ani $%02x",arg); break; + case 0xdc : sprintf (buffer,"ori $%02x",arg); break; + case 0xe4 : sprintf (buffer,"xri $%02x",arg); break; + case 0xec : sprintf (buffer,"dai $%02x",arg); break; + case 0xf4 : sprintf (buffer,"adi $%02x",arg); break; + case 0xfc : sprintf (buffer,"cai $%02x",arg); break; + // Transfer Instructions + case 0x90 : sprintf (buffer,"jmp %s",as);break; + case 0x91 : case 0x92 : case 0x93 : + sprintf (buffer,"jmp %s",aspr);break; + case 0x94 : sprintf (buffer,"jp %s",as); break; + case 0x95 : case 0x96 : case 0x97 : + sprintf (buffer,"jp %s",aspr); break; + case 0x98 : sprintf (buffer,"jz %s",as); break; + case 0x99 : case 0x9a : case 0x9b : + sprintf (buffer,"jz %s",aspr); break; + case 0x9c : sprintf (buffer,"jnz %s",as); break; + case 0x9d : case 0x9e : case 0x9f : + sprintf (buffer,"jnz %s",aspr); break; + // Double-Byte Miscellaneous Instructions + case 0x8f: sprintf (buffer,"dly $%02x",arg); break; + // Others are illegal + default : sprintf (buffer,"illegal"); pc--; break; // Illegal we consider without param + } + } else { + // one byte instructions + switch (op) + { + // Extension Register Instructions + case 0x40: sprintf (buffer,"lde"); break; + case 0x01: sprintf (buffer,"xae"); break; + case 0x50: sprintf (buffer,"ane"); break; + case 0x58: sprintf (buffer,"ore"); break; + case 0x60: sprintf (buffer,"xre"); break; + case 0x68: sprintf (buffer,"dae"); break; + case 0x70: sprintf (buffer,"ade"); break; + case 0x78: sprintf (buffer,"cae"); break; + // Pointer Register Move Instructions + case 0x30: case 0x31 :case 0x32: case 0x33: + sprintf (buffer,"xpal %d",ptr); break; + case 0x34: case 0x35 :case 0x36: case 0x37: + sprintf (buffer,"xpah %d",ptr); break; + case 0x3c: case 0x3d :case 0x3e: case 0x3f: + sprintf (buffer,"xppc %d",ptr); break; + // Shift, Rotate, Serial I/O Instructions + case 0x19: sprintf (buffer,"sio"); break; + case 0x1c: sprintf (buffer,"sr"); break; + case 0x1d: sprintf (buffer,"srl"); break; + case 0x1e: sprintf (buffer,"rr"); break; + case 0x1f: sprintf (buffer,"rrl"); break; + // Single Byte Miscellaneous Instructions + case 0x00: sprintf (buffer,"halt"); break; + case 0x02: sprintf (buffer,"ccl"); break; + case 0x03: sprintf (buffer,"scl"); break; + case 0x04: sprintf (buffer,"dint"); break; + case 0x05: sprintf (buffer,"ien"); break; + case 0x06: sprintf (buffer,"csa"); break; + case 0x07: sprintf (buffer,"cas"); break; + case 0x08: sprintf (buffer,"nop"); break; + // Others are illegal + default : sprintf (buffer,"illegal"); break; + } + } + + return (pc - PC); +} diff --git a/src/mame/mame.mak b/src/mame/mame.mak index 272daf2b09a..1bb83ad6a74 100644 --- a/src/mame/mame.mak +++ b/src/mame/mame.mak @@ -116,6 +116,8 @@ CPUS += TMS0980 CPUS += I4004 CPUS += SUPERFX CPUS += Z8 +CPUS += I8008 +CPUS += SCMP #------------------------------------------------- diff --git a/src/tools/unidasm.c b/src/tools/unidasm.c index ad38e5ba7bf..63b9a7a67b0 100644 --- a/src/tools/unidasm.c +++ b/src/tools/unidasm.c @@ -113,6 +113,7 @@ CPU_DISASSEMBLE( h6280 ); CPU_DISASSEMBLE( h8 ); CPU_DISASSEMBLE( hd6309 ); CPU_DISASSEMBLE( i4004 ); +CPU_DISASSEMBLE( i8008 ); CPU_DISASSEMBLE( i8085 ); CPU_DISASSEMBLE( x86_16 ); CPU_DISASSEMBLE( x86_32 ); @@ -170,6 +171,7 @@ CPU_DISASSEMBLE( rsp ); CPU_DISASSEMBLE( s2650 ); CPU_DISASSEMBLE( saturn ); CPU_DISASSEMBLE( sc61860 ); +CPU_DISASSEMBLE( scmp ); CPU_DISASSEMBLE( se3208 ); CPU_DISASSEMBLE( sh2 ); CPU_DISASSEMBLE( sh4 ); @@ -234,6 +236,7 @@ static const dasm_table_entry dasm_table[] = { "hd6309", _8bit, 0, CPU_DISASSEMBLE_NAME(hd6309) }, { "i386", _8bit, 0, CPU_DISASSEMBLE_NAME(x86_32) }, { "i4004", _8bit, 0, CPU_DISASSEMBLE_NAME(i4004) }, + { "i8008", _8bit, 0, CPU_DISASSEMBLE_NAME(i8008) }, { "i8085", _8bit, 0, CPU_DISASSEMBLE_NAME(i8085) }, { "i80286", _8bit, 0, CPU_DISASSEMBLE_NAME(x86_16) }, { "i8086", _8bit, 0, CPU_DISASSEMBLE_NAME(x86_16) }, @@ -293,6 +296,7 @@ static const dasm_table_entry dasm_table[] = { "s2650", _8bit, 0, CPU_DISASSEMBLE_NAME(s2650) }, { "saturn", _8bit, 0, CPU_DISASSEMBLE_NAME(saturn) }, { "sc61860", _8bit, 0, CPU_DISASSEMBLE_NAME(sc61860) }, + { "scmp", _8bit, 0, CPU_DISASSEMBLE_NAME(scmp) }, { "se3208", _16le, 0, CPU_DISASSEMBLE_NAME(se3208) }, { "sh2", _16be, 0, CPU_DISASSEMBLE_NAME(sh2) }, { "sh4", _16le, 0, CPU_DISASSEMBLE_NAME(sh4) },