Added Intel 8008 and National Semiconductor SC/MP CPU cores

This commit is contained in:
Miodrag Milanovic 2009-11-23 08:19:29 +00:00
parent 65250dc49c
commit d98fa09e1f
10 changed files with 1755 additions and 0 deletions

6
.gitattributes vendored
View File

@ -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/4004dasm.c svneol=native#text/plain
src/emu/cpu/i4004/i4004.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/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/8085dasm.c svneol=native#text/plain
src/emu/cpu/i8085/i8085.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 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/scdasm.c svneol=native#text/plain
src/emu/cpu/sc61860/scops.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/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.c svneol=native#text/plain
src/emu/cpu/se3208/se3208.h svneol=native#text/plain src/emu/cpu/se3208/se3208.h svneol=native#text/plain
src/emu/cpu/se3208/se3208dis.c svneol=native#text/plain src/emu/cpu/se3208/se3208dis.c svneol=native#text/plain

View File

@ -544,6 +544,32 @@ $(CPUOBJ)/i4004/i4004.o: $(CPUSRC)/i4004/i4004.c \
$(CPUSRC)/i4004/i4004.h $(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 # Intel 8080/8085A

View File

@ -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;
}

710
src/emu/cpu/i8008/i8008.c Normal file
View File

@ -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;
}
}

33
src/emu/cpu/i8008/i8008.h Normal file
View File

@ -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

663
src/emu/cpu/scmp/scmp.c Normal file
View File

@ -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;
}
}

43
src/emu/cpu/scmp/scmp.h Normal file
View File

@ -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

153
src/emu/cpu/scmp/scmpdasm.c Normal file
View File

@ -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);
}

View File

@ -116,6 +116,8 @@ CPUS += TMS0980
CPUS += I4004 CPUS += I4004
CPUS += SUPERFX CPUS += SUPERFX
CPUS += Z8 CPUS += Z8
CPUS += I8008
CPUS += SCMP
#------------------------------------------------- #-------------------------------------------------

View File

@ -113,6 +113,7 @@ CPU_DISASSEMBLE( h6280 );
CPU_DISASSEMBLE( h8 ); CPU_DISASSEMBLE( h8 );
CPU_DISASSEMBLE( hd6309 ); CPU_DISASSEMBLE( hd6309 );
CPU_DISASSEMBLE( i4004 ); CPU_DISASSEMBLE( i4004 );
CPU_DISASSEMBLE( i8008 );
CPU_DISASSEMBLE( i8085 ); CPU_DISASSEMBLE( i8085 );
CPU_DISASSEMBLE( x86_16 ); CPU_DISASSEMBLE( x86_16 );
CPU_DISASSEMBLE( x86_32 ); CPU_DISASSEMBLE( x86_32 );
@ -170,6 +171,7 @@ CPU_DISASSEMBLE( rsp );
CPU_DISASSEMBLE( s2650 ); CPU_DISASSEMBLE( s2650 );
CPU_DISASSEMBLE( saturn ); CPU_DISASSEMBLE( saturn );
CPU_DISASSEMBLE( sc61860 ); CPU_DISASSEMBLE( sc61860 );
CPU_DISASSEMBLE( scmp );
CPU_DISASSEMBLE( se3208 ); CPU_DISASSEMBLE( se3208 );
CPU_DISASSEMBLE( sh2 ); CPU_DISASSEMBLE( sh2 );
CPU_DISASSEMBLE( sh4 ); CPU_DISASSEMBLE( sh4 );
@ -234,6 +236,7 @@ static const dasm_table_entry dasm_table[] =
{ "hd6309", _8bit, 0, CPU_DISASSEMBLE_NAME(hd6309) }, { "hd6309", _8bit, 0, CPU_DISASSEMBLE_NAME(hd6309) },
{ "i386", _8bit, 0, CPU_DISASSEMBLE_NAME(x86_32) }, { "i386", _8bit, 0, CPU_DISASSEMBLE_NAME(x86_32) },
{ "i4004", _8bit, 0, CPU_DISASSEMBLE_NAME(i4004) }, { "i4004", _8bit, 0, CPU_DISASSEMBLE_NAME(i4004) },
{ "i8008", _8bit, 0, CPU_DISASSEMBLE_NAME(i8008) },
{ "i8085", _8bit, 0, CPU_DISASSEMBLE_NAME(i8085) }, { "i8085", _8bit, 0, CPU_DISASSEMBLE_NAME(i8085) },
{ "i80286", _8bit, 0, CPU_DISASSEMBLE_NAME(x86_16) }, { "i80286", _8bit, 0, CPU_DISASSEMBLE_NAME(x86_16) },
{ "i8086", _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) }, { "s2650", _8bit, 0, CPU_DISASSEMBLE_NAME(s2650) },
{ "saturn", _8bit, 0, CPU_DISASSEMBLE_NAME(saturn) }, { "saturn", _8bit, 0, CPU_DISASSEMBLE_NAME(saturn) },
{ "sc61860", _8bit, 0, CPU_DISASSEMBLE_NAME(sc61860) }, { "sc61860", _8bit, 0, CPU_DISASSEMBLE_NAME(sc61860) },
{ "scmp", _8bit, 0, CPU_DISASSEMBLE_NAME(scmp) },
{ "se3208", _16le, 0, CPU_DISASSEMBLE_NAME(se3208) }, { "se3208", _16le, 0, CPU_DISASSEMBLE_NAME(se3208) },
{ "sh2", _16be, 0, CPU_DISASSEMBLE_NAME(sh2) }, { "sh2", _16be, 0, CPU_DISASSEMBLE_NAME(sh2) },
{ "sh4", _16le, 0, CPU_DISASSEMBLE_NAME(sh4) }, { "sh4", _16le, 0, CPU_DISASSEMBLE_NAME(sh4) },