📄 s2650.c
字号:
/*******************************************************
*
* Portable Signetics 2650 cpu emulation
*
* Written by Juergen Buchmueller for use with MAME
*
*******************************************************/
#include "string.h"
#include "memory.h"
#include "types.h"
#include "S2650/s2650.h"
#include "S2650/s2650cpu.h"
/* define this to expand all EA calculations inline */
#define INLINE_EA
int S2650_ICount = 0;
static S2650_Regs S;
/* condition code changes for a byte */
static byte ccc[0x200] = {
0x00,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,
0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,
0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,
0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,
0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,
0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,
0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,
0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,
0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
0x04,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,
0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,
0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,
0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,
0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,
0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,
0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,
0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,
0x84,0x84,0x84,0x84,0x84,0x84,0x84,0x84,0x84,0x84,0x84,0x84,0x84,0x84,0x84,0x84,
0x84,0x84,0x84,0x84,0x84,0x84,0x84,0x84,0x84,0x84,0x84,0x84,0x84,0x84,0x84,0x84,
0x84,0x84,0x84,0x84,0x84,0x84,0x84,0x84,0x84,0x84,0x84,0x84,0x84,0x84,0x84,0x84,
0x84,0x84,0x84,0x84,0x84,0x84,0x84,0x84,0x84,0x84,0x84,0x84,0x84,0x84,0x84,0x84,
0x84,0x84,0x84,0x84,0x84,0x84,0x84,0x84,0x84,0x84,0x84,0x84,0x84,0x84,0x84,0x84,
0x84,0x84,0x84,0x84,0x84,0x84,0x84,0x84,0x84,0x84,0x84,0x84,0x84,0x84,0x84,0x84,
0x84,0x84,0x84,0x84,0x84,0x84,0x84,0x84,0x84,0x84,0x84,0x84,0x84,0x84,0x84,0x84,
0x84,0x84,0x84,0x84,0x84,0x84,0x84,0x84,0x84,0x84,0x84,0x84,0x84,0x84,0x84,0x84,
};
#define SET_CC(value) { S.psl = (S.psl & ~CC) | ccc[value]; }
#define SET_CC_OVF(value,before) { S.psl = (S.psl & ~(OVF+CC)) | ccc[value + ( ( (value^before) << 1) & 256 )]; }
/* read next opcode */
static byte RDOP(void)
{
byte result = cpu_readop(S.page + S.iar);
S.iar = (S.iar + 1) & PMSK;
return result;
}
/* read next opcode argument */
static byte RDOPARG(void)
{
byte result = cpu_readop_arg(S.page + S.iar);
S.iar = (S.iar + 1) & PMSK;
return result;
}
#define RDMEM(addr) cpu_readmem16(addr)
/* handy table to build relative offsets from HR */
static int S2650_relative[0x100] = {
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
-64,-63,-62,-61,-60,-59,-58,-57,-56,-55,-54,-53,-52,-51,-50,-49,
-48,-47,-46,-45,-44,-43,-42,-41,-40,-39,-38,-37,-36,-35,-34,-33,
-32,-31,-30,-29,-28,-27,-26,-25,-24,-23,-22,-21,-20,-19,-18,-17,
-16,-15,-14,-13,-12,-11,-10, -9, -8, -7, -6, -5, -4, -3, -2, -1,
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
-64,-63,-62,-61,-60,-59,-58,-57,-56,-55,-54,-53,-52,-51,-50,-49,
-48,-47,-46,-45,-44,-43,-42,-41,-40,-39,-38,-37,-36,-35,-34,-33,
-32,-31,-30,-29,-28,-27,-26,-25,-24,-23,-22,-21,-20,-19,-18,-17,
-16,-15,-14,-13,-12,-11,-10, -9, -8, -7, -6, -5, -4, -3, -2, -1,
};
/* build effective address with relative addressing */
#define _REL_EA(page) { \
byte hr; \
hr = RDOPARG(); /* get 'holding register' */ \
/* build effective address within current 8K page */\
S.ea = page + ((S.iar + S2650_relative[hr]) & PMSK);\
if (hr & 0x80) /* indirect bit set ? */ \
{ \
int addr = S.ea; \
S2650_ICount -= 2; \
/* build indirect 32K address */ \
S.ea = RDMEM(addr) << 8; \
if (!(++addr & PMSK)) \
addr -= PLEN; \
S.ea = (S.ea + RDMEM(addr)) & AMSK; \
} \
}
/* build effective address with absolute addressing */
#define _ABS_EA() { \
byte hr, dr; \
hr = RDOPARG(); /* get 'holding register' */ \
dr = RDOPARG(); /* get 'data bus register' */ \
/* build effective address within current 8K page */ \
S.ea = S.page + (((hr << 8) + dr) & PMSK); \
/* indirect addressing ? */ \
if (hr & 0x80) \
{ \
int addr = S.ea; \
S2650_ICount -= 2; \
/* build indirect 32K address */ \
/* build indirect 32K address */ \
S.ea = RDMEM(addr) << 8; \
if (!(++addr & PMSK)) \
addr -= PLEN; \
S.ea = (S.ea + RDMEM(addr)) & AMSK; \
} \
/* check for indexed addressing mode */ \
switch (hr & 0x60) \
{ \
case 0x00: /* not indexed */ \
break; \
case 0x20: /* auto increment indexed */ \
S.reg[S.r] += 1; \
S.ea = (S.ea & PAGE)+((S.ea+S.reg[S.r]) & PMSK); \
S.r = 0; /* absolute addressing reg is R0 */ \
break; \
case 0x40: /* auto decrement indexed */ \
S.reg[S.r] -= 1; \
S.ea = (S.ea & PAGE)+((S.ea+S.reg[S.r]) & PMSK); \
S.r = 0; /* absolute addressing reg is R0 */ \
break; \
case 0x60: /* indexed */ \
S.ea = (S.ea & PAGE)+((S.ea+S.reg[S.r]) & PMSK); \
S.r = 0; /* absolute addressing reg is R0 */ \
break; \
} \
}
/* build effective address with absolute addressing (branch) */
#define _BRA_EA() { \
byte hr, dr; \
hr = RDOPARG(); /* get 'holding register' */ \
dr = RDOPARG(); /* get 'data bus register' */ \
/* build address in 32K address space */ \
S.ea = ((hr << 8) + dr) & AMSK; \
/* indirect addressing ? */ \
if (hr & 0x80) \
{ \
int addr = S.ea; \
S2650_ICount -= 2; \
/* build indirect 32K address */ \
S.ea = RDMEM(addr) << 8; \
if (!(++addr & PMSK)) \
addr -= PLEN; \
S.ea = (S.ea + RDMEM(addr)) & AMSK; \
} \
}
/* swap registers 1-3 with 4-6 */
/* this is done when the RS bit in PSL changes */
#define SWAP_REGS { \
byte swap; \
swap = S.reg[1]; \
S.reg[1] = S.reg[4]; \
S.reg[4] = swap; \
swap = S.reg[2]; \
S.reg[2] = S.reg[5]; \
S.reg[5] = swap; \
swap = S.reg[3]; \
S.reg[3] = S.reg[6]; \
S.reg[6] = swap; \
}
/* BRanch Relative if cond is true */
#define S_BRR(cond) { \
if (cond) { \
REL_EA(S.page); \
S.page = S.ea & PAGE; \
S.iar = S.ea & PMSK; \
change_pc(S.ea); \
} else S.iar = (S.iar + 1) & PMSK; \
}
/* Zero Branch Relative */
#define S_ZBRR() { \
REL_EA(0x0000); \
S.page = S.ea & PAGE; \
S.iar = S.ea & PMSK; \
change_pc(S.ea); \
}
/* BRanch Absolute if cond is true */
#define S_BRA(cond) { \
if (cond) { \
BRA_EA(); \
S.page = S.ea & PAGE; \
S.iar = S.ea & PMSK; \
change_pc(S.ea); \
} else S.iar = (S.iar + 2) & PMSK; \
}
/* Branch indeXed Absolute (R3) */
#define S_BXA() { \
BRA_EA(); \
S.ea = (S.ea + S.reg[3]) & AMSK; \
S.page = S.ea & PAGE; \
S.iar = S.ea & PMSK; \
change_pc(S.ea); \
}
/* Branch to Subroutine Relative if cond is true */
#define S_BSR(cond) { \
if (cond) { \
REL_EA(S.page); \
S.psu = (S.psu & ~SP) | ((S.psu + 1) & SP); \
S.ras[S.psu & SP] = S.iar; \
S.page = S.ea & PAGE; \
S.iar = S.ea & PMSK; \
change_pc(S.ea); \
} else S.iar = (S.iar + 1) & PMSK; \
}
/* Zero Branch to Subroutine Relative */
#define S_ZBSR() { \
REL_EA(0x0000); \
S.psu = (S.psu & ~SP) | ((S.psu + 1) & SP); \
S.ras[S.psu & SP] = S.iar; \
S.page = S.ea & PAGE; \
S.iar = S.ea & PMSK; \
change_pc(S.ea); \
}
/* Branch to Subroutine Absolute */
#define S_BSA(cond) { \
if (cond) { \
BRA_EA(); \
S.psu = (S.psu & ~SP) | ((S.psu + 1) & SP); \
S.ras[S.psu & SP] = S.iar; \
S.page = S.ea & PAGE; \
S.iar = S.ea & PMSK; \
change_pc(S.ea); \
} else S.iar = (S.iar + 2) & PMSK; \
}
/* Branch to Subroutine indeXed Absolute (R3) */
#define S_BSXA() { \
BRA_EA(); \
S.ea = (S.ea + S.reg[3]) & AMSK; \
S.psu = (S.psu & ~SP) | ((S.psu + 1) & SP); \
S.ras[S.psu & SP] = S.iar; \
S.page = S.ea & PAGE; \
S.iar = S.ea & PMSK; \
change_pc(S.ea); \
}
/* RETurn from subroutine */
#define S_RET(cond) { \
if (cond) { \
S.ea = S.ras[S.psu & SP]; \
S.psu = (S.psu & ~SP) | ((S.psu - 1) & SP); \
S.page = S.ea & PAGE; \
S.iar = S.ea & PMSK; \
change_pc(S.ea); \
} \
}
/* RETurn from subroutine and Enable interrupts */
#define S_RETE(cond) { \
if (cond) { \
S.ea = S.ras[S.psu & SP]; \
S.psu = (S.psu & ~SP) | ((S.psu - 1) & SP); \
S.page = S.ea & PAGE; \
S.iar = S.ea & PMSK; \
change_pc(S.ea); \
S.psu &= ~II; \
} \
}
/* LOaD destination with source */
#define S_LOD(dest,source) { \
dest = source; \
SET_CC(dest); \
}
/* SToRe source to memory addr (CC unchanged) */
#define S_STR(address,source) cpu_writemem16(address, source)
/* logical and destination with source */
#define S_AND(dest,source) { \
dest &= source; \
SET_CC(dest); \
}
/* logical inclusive or destination with source */
#define S_IOR(dest,source) { \
dest |= source; \
SET_CC(dest); \
}
/* logical exclusive or destination with source */
#define S_EOR(dest,source) { \
dest ^= source; \
SET_CC(dest); \
}
/* add source to destination */
#define S_ADD(dest,source) { \
byte before = dest; \
/* add source; carry only if WC is set */ \
dest = dest + source + ((S.psl >> 3) & S.psl & C); \
S.psl &= ~(C + OVF + IDC); \
if (dest < before) \
S.psl |= C; \
if ((dest & 15) < (before & 15)) \
S.psl |= IDC; \
SET_CC_OVF(dest,before); \
}
/* subtract source from destination */
#define S_SUB(dest,source) { \
byte before = dest; \
/* add source; carry only if WC is set */ \
dest = dest - source - ((S.psl >> 3) & (S.psl ^ C) & C); \
S.psl &= ~(C + OVF + IDC); \
if (dest <= before) \
S.psl |= C; \
if ((dest & 15) > (before & 15)) \
S.psl |= IDC; \
SET_CC_OVF(dest,before); \
}
#define S_COM(reg,val) { \
int d; \
S.psl &= ~CC; \
if (S.psl & COM) \
d = (byte)reg - (byte)val; \
else \
d = (char)reg - (char)val; \
if (d < 0) \
S.psl |= 0x80; \
else \
if (d > 0) \
S.psl |= 0x40; \
}
#define S_DAR(dest) { \
if (!(S.psl & IDC)) \
dest += 0x0a; \
if (!(S.psl & C)) \
dest += 0xa0; \
}
/* rotate register left */
#define S_RRL(dest) { \
byte before = dest; \
if (S.psl & WC) \
{ \
byte c = S.psl & C; \
S.psl &= ~(C + IDC); \
dest = (before << 1) | c; \
S.psl |= (before >> 7) + (dest & IDC); \
} else dest = (before << 1) | (before >> 7); \
SET_CC_OVF(dest,before); \
}
/* rotate register right */
#define S_RRR(dest) { \
byte before = dest; \
if (S.psl & WC) \
{ \
byte c = S.psl & C; \
S.psl &= ~(C + IDC); \
dest = (before >> 1) | (c << 7); \
S.psl |= (before & C) + (dest & IDC); \
} else dest = (before >> 1) | (before << 7); \
SET_CC_OVF(dest,before); \
}
/* store processor status upper to register 0 */
#define S_SPSU() { \
R0 = S.psu & ~PSU34; \
SET_CC(R0); \
}
/* store processor status lower to register 0 */
#define S_SPSL() { \
R0 = S.psl; \
SET_CC(R0); \
}
/* clear processor status upper, selective */
#define S_CPSU() { \
byte cpsu = RDOPARG(); \
S.psu = S.psu & ~cpsu; \
}
/* clear processor status lower, selective */
#define S_CPSL() { \
byte cpsl = RDOPARG(); \
/* select 1st register set now ? */ \
if ((cpsl & RS) && (S.psl & RS)) \
SWAP_REGS; \
S.psl = S.psl & ~cpsl; \
}
/* preset processor status upper, selective */
#define S_PPSU() { \
byte ppsu = RDOPARG() & ~PSU34; \
S.psu = S.psu | ppsu; \
}
/* preset processor status lower, selective */
#define S_PPSL() { \
byte ppsl = RDOPARG(); \
/* select 2nd register set now ? */ \
if ((ppsl & RS) && !(S.psl & RS)) \
SWAP_REGS; \
S.psl = S.psl | ppsl; \
}
/* test processor status upper */
#define S_TPSU() { \
byte tpsu = RDOPARG(); \
S.psl &= ~CC; \
if ((S.psu & tpsu) != tpsu) \
S.psl |= 0x80; \
}
/* test processor status lower */
#define S_TPSL() { \
byte tpsl = RDOPARG(); \
if ((S.psl & tpsl) != tpsl) \
S.psl = (S.psl & ~CC) | 0x80; \
else \
S.psl &= ~CC; \
}
/* test under mask immediate */
#define S_TMI(value) { \
byte tmi = RDOPARG(); \
S.psl &= ~CC; \
if ((value & tmi) != tmi) \
S.psl |= 0x80; \
}
#ifdef INLINE_EA
#define REL_EA(page) _REL_EA(page)
#define ABS_EA() _ABS_EA()
#define BRA_EA() _BRA_EA()
#else
static void REL_EA(unsigned short page)
_REL_EA(page)
static void ABS_EA(void)
_ABS_EA()
static void BRA_EA(void)
_BRA_EA()
#endif
void S2650_SetRegs(S2650_Regs * rgs)
{
S = *rgs;
}
void S2650_GetRegs(S2650_Regs * rgs)
{
*rgs = S;
}
int S2650_GetPC(void)
{
return S.page + S.iar;
}
void S2650_set_flag(int state)
{
if (state)
S.psu |= FO;
else
S.psu &= ~FO;
}
int S2650_get_flag(void)
{
return (S.psu & FO) ? 1 : 0;
}
void S2650_set_sense(int state)
{
if (state)
S.psu |= SI;
else
S.psu &= ~SI;
}
int S2650_get_sense(void)
{
return (S.psu & SI) ? 1 : 0;
}
void S2650_Reset(void)
{
memset(&S, 0, sizeof(S));
S.irq = S2650_INT_NONE;
S.psl = COM | WC;
S.psu = SI;
}
void S2650_Cause_Interrupt(int type)
{
S.irq = type; /* set interrupt request (vector) */
}
void S2650_Clear_Pending_Interrupts(void)
{
S.irq = S2650_INT_NONE; /* clear interrupt request */
}
static int S2650_Cycles[0x100] = {
2,2,2,2, 2,2,2,2, 3,3,3,3, 4,4,4,4,
2,2,2,2, 2,2,2,2, 3,3,3,3, 3,3,3,3,
2,2,2,2, 2,2,2,2, 3,3,3,3, 4,4,4,4,
2,2,2,2, 3,3,3,3, 3,3,3,3, 3,3,3,3,
2,2,2,2, 2,2,2,2, 3,3,3,3, 4,4,4,4,
2,2,2,2, 3,3,3,3, 3,3,3,3, 3,3,3,3,
2,2,2,2, 2,2,2,2, 3,3,3,3, 4,4,4,4,
2,2,2,2, 2,2,2,2, 3,3,3,3, 3,3,3,3,
2,2,2,2, 2,2,2,2, 3,3,3,3, 4,4,4,4,
2,2,2,2, 2,2,2,2, 3,3,3,3, 3,3,3,3,
2,2,2,2, 2,2,2,2, 3,3,3,3, 4,4,4,4,
2,2,2,2, 2,2,2,2, 3,3,3,3, 3,3,3,3,
2,2,2,2, 2,2,2,2, 3,3,3,3, 4,4,4,4,
2,2,2,2, 3,3,3,3, 3,3,3,3, 3,3,3,3,
2,2,2,2, 2,2,2,2, 3,3,3,3, 4,4,4,4,
2,2,2,2, 3,3,3,3, 3,3,3,3, 3,3,3,3
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -