blob: 45d6f4264e2612fb2d845ab30aac85ff66655f02 [file] [log] [blame] [raw]
#ifndef _CPU_H
#define _CPU_H
#define REG_AC AC
#define REG_X X
#define REG_Y Y
#define REG_SP SP
#define REG_PC PC
#define REG_ST ST
#define SETFLAGS_ZN(VALUE) ST = (ST&0x7D)|(((VALUE)==0)<<1)|((VALUE)&0x80)
#include "mem.h"
#include "SaveState.h"
class TED;
class CPU : public SaveState {
protected:
unsigned char currins;
unsigned char nextins;
unsigned char farins;
unsigned int ptr;
unsigned int PC;
unsigned char SP;
// 76543210
unsigned int ST; // NV1BDIZC
unsigned char AC;
unsigned char X;
unsigned char Y;
void ADC(const unsigned char value);
void SBC(const unsigned char value);
void DoCompare(unsigned char reg, unsigned char value);
unsigned int cycle;
unsigned int IRQcount;
MemoryHandler *mem;
unsigned char *irq_register;
unsigned char *stack;
unsigned char irq_sequence;
virtual unsigned char CheckVFlag() { return (ST&0x40); };
inline virtual void ClearVFlag() { ST&=0xBF; };
inline void SetVFlag() { ST|=0x40; };
enum {
INTERRUPT_NMI = 0xFFFA,
INTERRUPT_RESET = 0xFFFC,
INTERRUPT_IRQ = 0xFFFE,
};
unsigned short irqVector;
unsigned int nmiLevel;
public:
CPU(MemoryHandler *memhandler, unsigned char *irqreg, unsigned char *cpustack);
virtual ~CPU();
void Reset(void);
void softreset(void);
void setPC(unsigned int addr);
void process();
void process(unsigned int clks);
void stopcycle();
void step();
unsigned int getPC() { return PC; };
unsigned int getSP() { return SP; };
unsigned int getST() { return ST; };
unsigned int getAC() { return AC; };
unsigned int getX() { return X; };
unsigned int getY() { return Y; };
unsigned int getnextins() { return nextins; };
unsigned int getptr() { return ptr; };
unsigned int getcycle() { return cycle; };
unsigned int getcins();
unsigned int getRemainingCycles();
void setST(unsigned int v) { ST = v; };
virtual void dumpState();
virtual void readState();
// breakpoint variables
static bool bp_active;
static bool bp_reached;
struct {
unsigned int address;
bool enabled;
bool slot_free;
} bp[11];
unsigned int nr_activebps;
bool cpu_jammed;
static const unsigned int nr_of_bps;
int disassemble(int pc, char *line);
void regDump(char *line, int rowcount);
MemoryHandler &getMem() { return *mem; };
void setMem(MemoryHandler *_mem, unsigned char *_i, unsigned char *_s) {
mem = _mem;
irq_register = _i;
stack = _s;
}
void triggerNmi() {
if (!nmiLevel) {
irqVector = INTERRUPT_NMI;
nmiLevel = 1;
IRQcount = 1;
irq_sequence = 0x10;
}
}
void clearNmi() {
nmiLevel = 0;
}
};
inline void CPU::ADC(const unsigned char value)
{
if (ST&0x08) {
unsigned int bin_adc = AC + value + (ST&0x01);
unsigned char AL, AH;
AL=(AC&0x0F) + (value & 0x0F) + (ST&0x01);
AH=(AC >> 4) + (value >> 4 ) ;
// fix lower nybble
if (AL>9) {
AL+=6;
AH++;
}
// zero bit depends on the normal ADC...
(bin_adc)&0xFF ? ST&=0xFD : ST|=0x02;
// negative flag also...
( AH & 0x08 ) ? ST|=0x80 : ST&=0x7F;
// V flag
((((AH << 4) ^ AC) & 0x80) && !((AC ^ value) & 0x80)) ? SetVFlag() : ClearVFlag();
// fix upper nybble
if (AH>9)
AH+=6;
// set the Carry if the decimal add has an overflow
(AH > 0x0f) ? ST|=0x01 : ST&=0xFE;
// calculate new AC value
AC = (AH<<4)|(AL & 0x0F);
} else {
unsigned int bin_adc = AC + value + (ST&0x01);
(bin_adc>=0x100) ? ST|=0x01 : ST&=0xFE;
(!((AC ^ value) & 0x80) && ((AC ^ bin_adc) & 0x80) ) ? SetVFlag() : ClearVFlag();
AC=(unsigned char) bin_adc;
SETFLAGS_ZN(AC);
}
}
inline void CPU::SBC(const unsigned char value)
{
if (ST&0x08) { // if in decimal mode
unsigned int bin_sbc = (AC - value - (1-(ST&0x01)));
unsigned int dec_sbc = (AC & 0x0F) - (value & 0x0F) - (1-(ST&0x01));
// Calculate the upper nybble.
// fix upper nybble
if (dec_sbc&0x10)
dec_sbc = ((dec_sbc-6)&0x0F) | ((AC&0xF0) - (value&0xF0) - 0x10);
else
dec_sbc = (dec_sbc&0x0F) | ((AC&0xF0) - (value&0xF0));
if (dec_sbc&0x100)
dec_sbc-= 0x60;
// all flags depend on the normal SBC...
(bin_sbc<0x100) ? ST|=0x01 : ST&=0xFE ; // carry flag
SETFLAGS_ZN( bin_sbc & 0xFF );
((AC^bin_sbc)&0x80 && (AC^value)&0x80 ) ? SetVFlag() : ClearVFlag(); // V flag
AC=(unsigned char) dec_sbc;
} else {
unsigned int bin_sbc = (AC - value - (1-(ST&0x01)));
(bin_sbc<0x100) ? ST|=0x01 : ST&=0xFE;
(((AC ^ value) & 0x80) && ((AC ^ bin_sbc) & 0x80) ) ? SetVFlag() : ClearVFlag();
AC=(unsigned char) bin_sbc;
SETFLAGS_ZN(AC);
}
}
class DRIVECPU : public CPU {
protected:
unsigned char *flag_v_pin_edge;
unsigned char *is_so_enable;
virtual unsigned char CheckVFlag();
virtual void ClearVFlag();
public:
DRIVECPU(MemoryHandler *memhandler, unsigned char *irqreg, unsigned char *cpustack,
unsigned char *vpin, unsigned char *so_enable, unsigned int id);
virtual ~DRIVECPU() { };
};
#endif // _CPU_H