📄 m6808.c
字号:
/*** m6808: Portable 6808 emulator ******************************************
m6808.c
References:
6809 Simulator V09, By L.C. Benschop, Eidnhoven The Netherlands.
m6809: Portable 6809 emulator, DS (6809 code in MAME, derived from
the 6809 Simulator V09)
6809 Microcomputer Programming & Interfacing with Experiments"
by Andrew C. Staugaard, Jr.; Howard W. Sams & Co., Inc.
System dependencies: word must be 16 bit unsigned int
byte must be 8 bit unsigned int
long must be more than 16 bits
arrays up to 65536 bytes must be supported
machine must be twos complement
*****************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include "m6808.h"
#include "driver.h"
/* 6808 registers */
static byte cc,areg,breg,unused1;
static word xreg,sreg,pcreg;
static word eaddr; /* effective address */
static int pending_interrupts;
/* public globals */
int m6808_ICount=50000;
int m6808_Flags; /* flags for speed optimization */
/* handlers for speed optimization */
static int (*rd_s_handler)(int);
static int (*rd_s_handler_wd)(int);
static void (*wr_s_handler)(int,int);
static void (*wr_s_handler_wd)(int,int);
/* DS -- THESE ARE RE-DEFINED IN m6808.h TO RAM, ROM or FUNCTIONS IN cpuintrf.c */
#define M_RDMEM(A) M6808_RDMEM(A)
#define M_WRMEM(A,V) M6808_WRMEM(A,V)
#define M_RDOP(A) M6808_RDOP(A)
#define M_RDOP_ARG(A) M6808_RDOP_ARG(A)
/* macros to access memory */
#define IMMBYTE(b) {b=M_RDOP_ARG(pcreg++);}
#define IMMWORD(w) {w = (M_RDOP_ARG(pcreg)<<8) + M_RDOP_ARG(pcreg+1); pcreg+=2;}
#define PUSHBYTE(b) {(*wr_s_handler)(sreg,b);sreg--;}
#define PUSHWORD(w) {sreg--;(*wr_s_handler_wd)(sreg,w);sreg--;}
#define PULLBYTE(b) {sreg++;b=(*rd_s_handler)(sreg);}
#define PULLWORD(w) {sreg++;w=(*rd_s_handler_wd)(sreg);sreg++;}
/* CC masks HI NZVC
7654 3210 */
#define CLR_HNZVC cc&=0xd0
#define CLR_NZV cc&=0xf1
#define CLR_HNZC cc&=0xd2
#define CLR_NZVC cc&=0xf0
#define CLR_Z cc&=0xfb
#define CLR_NZC cc&=0xf2
#define CLR_ZC cc&=0xfa
/* macros for CC -- CC bits affected should be reset before calling */
#define SET_Z(a) if(!a)SEZ
#define SET_Z8(a) SET_Z((byte)a)
#define SET_Z16(a) SET_Z((word)a)
#define SET_N8(a) cc|=((a&0x80)>>4)
#define SET_N16(a) cc|=((a&0x8000)>>12)
#define SET_H(a,b,r) cc|=(((a^b^r)&0x10)<<1)
#define SET_C8(a) cc|=((a&0x100)>>8)
#define SET_C16(a) cc|=((a&0x10000)>>16)
#define SET_V8(a,b,r) cc|=(((a^b^r^(r>>1))&0x80)>>6)
#define SET_V16(a,b,r) cc|=(((a^b^r^(r>>1))&0x8000)>>14)
static byte flags8i[256]= /* increment */
{
0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x0a,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,
0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,
0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,
0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,
0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,
0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,
0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,
0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08
};
static byte flags8d[256]= /* decrement */
{
0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,
0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,
0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,
0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,
0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,
0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,
0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,
0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,
0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08
};
#define SET_FLAGS8I(a) {cc|=flags8i[(a)&0xff];}
#define SET_FLAGS8D(a) {cc|=flags8d[(a)&0xff];}
/* combos */
#define SET_NZ8(a) {SET_N8(a);SET_Z(a);}
#define SET_NZ16(a) {SET_N16(a);SET_Z(a);}
#define SET_FLAGS8(a,b,r) {SET_N8(r);SET_Z8(r);SET_V8(a,b,r);SET_C8(r);}
#define SET_FLAGS16(a,b,r) {SET_N16(r);SET_Z16(r);SET_V16(a,b,r);SET_C16(r);}
/* for treating an unsigned byte as a signed word */
#define SIGNED(b) ((word)(b&0x80?b|0xff00:b))
/* macros to access dreg */
#define GETDREG ((areg<<8)|breg)
#define SETDREG(n) {areg=(n)>>8;breg=(n);}
/* Macros for addressing modes */
#define DIRECT IMMBYTE(eaddr)
#define IMM8 eaddr=pcreg++
#define IMM16 {eaddr=pcreg;pcreg+=2;}
#define EXTENDED IMMWORD(eaddr)
#define INDEXED {eaddr=xreg+(byte)M_RDOP(pcreg++);}
/* macros to set status flags */
#define SEC cc|=0x01
#define CLC cc&=0xfe
#define SEZ cc|=0x04
#define CLZ cc&=0xfb
#define SEN cc|=0x08
#define CLN cc&=0xf7
#define SEV cc|=0x02
#define CLV cc&=0xfd
#define SEH cc|=0x20
#define CLH cc&=0xdf
#define SEI cc|=0x10
#define CLI cc&=~0x10
/* macros for convenience */
#define DIRBYTE(b) {DIRECT;b=M_RDMEM(eaddr);}
#define DIRWORD(w) {DIRECT;w=M_RDMEM_WORD(eaddr);}
#define EXTBYTE(b) {EXTENDED;b=M_RDMEM(eaddr);}
#define EXTWORD(w) {EXTENDED;w=M_RDMEM_WORD(eaddr);}
#define IDXBYTE(b) {INDEXED;b=M_RDMEM(eaddr);}
#define IDXWORD(w) {INDEXED;w=M_RDMEM_WORD(eaddr);}
/* Macros for branch instructions */
#define BRANCH(f) {IMMBYTE(t);if(f){pcreg+=SIGNED(t);change_pc(pcreg);}}
#define LBRANCH(f) {IMMWORD(t);if(f){pcreg+=t;change_pc(pcreg);}}
#define NXORV ((cc&0x08)^((cc&0x02)<<2))
/* what they say it is ... */
static unsigned char cycles1[] =
{
/* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
/*0*/ 0, 2, 0, 0, 0, 0, 2, 2, 4, 4, 2, 2, 2, 2, 2, 2,
/*1*/ 2, 2, 0, 0, 0, 0, 2, 2, 0, 2, 0, 2, 0, 0, 0, 0,
/*2*/ 4, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
/*3*/ 4, 4, 4, 4, 4, 4, 4, 4, 0, 5, 0,19, 0, 0, 9,12,
/*4*/ 2, 0, 0, 2, 2, 0, 2, 2, 2, 2, 2, 0, 2, 2, 0, 2,
/*5*/ 2, 0, 0, 2, 2, 0, 2, 2, 2, 2, 2, 0, 2, 2, 0, 2,
/*6*/ 7, 0, 0, 7, 7, 0, 7, 7, 7, 7, 7, 0, 7, 7, 4, 7,
/*7*/ 6, 0, 0, 6, 6, 0, 6, 6, 6, 6, 6, 0, 6, 6, 3, 6,
/*8*/ 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 2, 3, 8, 3, 0,
/*9*/ 3, 3, 3, 0, 3, 3, 3, 4, 3, 3, 3, 3, 4, 0, 4, 5,
/*A*/ 5, 5, 5, 0, 5, 5, 5, 6, 5, 5, 5, 5, 6, 8, 6, 7,
/*B*/ 4, 4, 4, 0, 4, 4, 4, 5, 4, 4, 4, 4, 5, 9, 5, 6,
/*C*/ 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 2, 0, 0, 3, 0,
/*D*/ 3, 3, 3, 0, 3, 3, 3, 4, 3, 3, 3, 3, 0, 0, 4, 5,
/*E*/ 5, 5, 5, 0, 5, 5, 5, 6, 5, 5, 5, 5, 4, 0, 6, 7,
/*F*/ 4, 4, 4, 0, 4, 4, 4, 5, 4, 4, 4, 4, 0, 0, 5, 6,
};
static int rd_slow( int addr )
{
return M_RDMEM(addr);
}
static int rd_slow_wd( int addr )
{
return( (M_RDMEM(addr)<<8) | (M_RDMEM((addr+1)&0xffff)) );
}
static int rd_fast( int addr )
{
extern unsigned char *RAM;
return RAM[addr];
}
static int rd_fast_wd( int addr )
{
extern unsigned char *RAM;
return( (RAM[addr]<<8) | (RAM[(addr+1)&0xffff]) );
}
static void wr_slow( int addr, int v )
{
M_WRMEM(addr,v);
}
static void wr_slow_wd( int addr, int v )
{
M_WRMEM(addr,v>>8);
M_WRMEM(((addr)+1)&0xFFFF,v&255);
}
static void wr_fast( int addr, int v )
{
extern unsigned char *RAM;
RAM[addr] = v;
}
static void wr_fast_wd( int addr, int v )
{
extern unsigned char *RAM;
RAM[addr] = v>>8;
RAM[(addr+1)&0xffff] = v&255;
}
INLINE unsigned M_RDMEM_WORD (dword A)
{
int i;
i = M_RDMEM(A)<<8;
i |= M_RDMEM(((A)+1)&0xFFFF);
return i;
}
INLINE void M_WRMEM_WORD (dword A,word V)
{
M_WRMEM (A,V>>8);
M_WRMEM (((A)+1)&0xFFFF,V&255);
}
/****************************************************************************/
/* Set all registers to given values */
/****************************************************************************/
void m6808_SetRegs(m6808_Regs *Regs)
{
pcreg = Regs->pc;change_pc(pcreg);
sreg = Regs->s;
xreg = Regs->x;
areg = Regs->a;
breg = Regs->b;
cc = Regs->cc;
pending_interrupts = Regs->pending_interrupts;
}
/****************************************************************************/
/* Get all registers in given buffer */
/****************************************************************************/
void m6808_GetRegs(m6808_Regs *Regs)
{
Regs->pc = pcreg;
Regs->s = sreg;
Regs->x = xreg;
Regs->a = areg;
Regs->b = breg;
Regs->cc = cc;
Regs->pending_interrupts = pending_interrupts;
}
/****************************************************************************/
/* Return program counter */
/****************************************************************************/
unsigned m6808_GetPC(void)
{
return pcreg;
}
/* Generate interrupts */
INLINE void Interrupt(void)
{
if ((pending_interrupts & M6808_INT_NMI) != 0)
{
pending_interrupts &= ~M6808_INT_NMI;
/* NMI */
PUSHWORD(pcreg);
PUSHWORD(xreg);
PUSHBYTE(breg);
PUSHBYTE(areg);
PUSHBYTE(cc);
SEI;
pcreg=M_RDMEM_WORD(0xfffc);change_pc(pcreg);
m6808_ICount -= 19;
} else
if ( ( cc & 0x10 ) == 0 ) {
if ((pending_interrupts & M6808_INT_IRQ) != 0) {
pending_interrupts &= ~M6808_INT_IRQ;
/* standard IRQ */
PUSHWORD(pcreg)
PUSHWORD(xreg)
PUSHBYTE(breg)
PUSHBYTE(areg)
PUSHBYTE(cc)
SEI;
pcreg=M_RDMEM_WORD(0xfff8);change_pc(pcreg);
m6808_ICount -= 19;
}
else
if ((pending_interrupts & M6808_INT_OCI) != 0) {
pending_interrupts &= ~M6808_INT_OCI;
/* standard IRQ */
PUSHWORD(pcreg)
PUSHWORD(xreg)
PUSHBYTE(breg)
PUSHBYTE(areg)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -