Files
nes/6502.cpp

193 lines
4.5 KiB
C++

#include "6502.h"
#include "mem.h"
#include "debug.h"
namespace cpu6502
{
static uint32_t clock = 0;
static uint32_t t = 0;
// P register Flags
#define fC 0b00000001 // Carry
#define fZ 0b00000010 // Zero
#define fI 0b00000100 // Interrupt disable
#define fD 0b00001000 // Decimal
#define fB 0b00010000 // Interrupt type?
#define f1 0b00100000 // -Unused-
#define fV 0b01000000 // Overflow
#define fN 0b10000000 // Negative
// Jump types
#define cUnconditional 255
#define cNZ 0
#define cZ 1
#define cNC 2
#define cC 3
#define cNN 4
#define cN 5
#define cNV 6
#define cV 7
// Addressing modes
#define aAccumulator 0
#define aImmediate 1
#define aZeroPage 2
#define aZeroPageX 3
#define aZeroPageY 4
#define aRelative 5
#define aIndirect 6
#define aIndirectX 7
#define aIndirectY 8
#define aAbsolute 9
#define aAbsoluteX 10
#define aAbsoluteY 11
uint8_t regs[7];
uint8_t *_rA = &regs[0];
uint8_t *_rX = &regs[1];
uint8_t *_rY = &regs[2];
uint8_t *_rS = &regs[3];
uint8_t *_rP = &regs[4];
uint16_t *_rPC = (uint16_t*)&regs[5];
#define rA (*_rA)
#define rX (*_rX)
#define rY (*_rY)
#define rS (*_rS)
#define rP (*_rP)
#define rPC (*_rPC)
bool reading_m1 = false;
uint8_t READ_MEM_8(const uint16_t addr, const bool code=false)
{
if (debug::isbreak(addr, 2)) debug::stop();
t+=1; //[TODO]
const uint8_t tag = mem::getTag(addr);
if ( !(tag&MEMTAG_IGNORE) ) {
if (!code) {
if ( tag & MEMTAG_INST ) {
} else {
mem::setTag(addr, tag | MEMTAG_DATA);
}
} else {
if ( (reading_m1) && ( tag & MEMTAG_DATA ) ) {
}
}
}
reading_m1 = false;
return mem::readMem(addr);
}
uint8_t READ_MEM_8()
{
const uint8_t data = READ_MEM_8(rPC, true);
const uint8_t tag = mem::getTag(rPC);
if ( !(tag & MEMTAG_IGNORE) ) mem::setTag(rPC, tag | MEMTAG_CODE);
rPC++;
return data;
}
uint8_t READ_M1()
{
reading_m1 = true;
return READ_MEM_8();
}
uint16_t READ_MEM_16()
{
const uint8_t L = READ_MEM_8();
const uint8_t H = READ_MEM_8();
return (H << 8) + L;
}
uint16_t READ_MEM_16(const uint16_t addr)
{
return READ_MEM_8(addr) + (READ_MEM_8(addr+1) << 8);
}
const uint8_t WRITE_MEM_8(const uint16_t addr, const uint8_t value)
{
t+=1; // [TODO]
mem::writeMem(addr, value);
if (debug::isbreak(addr, 4)) debug::stop();
debug::setmemmodified(addr);
const uint8_t tag = mem::getTag(addr);
if ( !(tag & MEMTAG_IGNORE) ) {
if ( tag & MEMTAG_INST ) {
//printf("WARNING! WRITING DATA OVER CODE!!! $%4X\n", addr);
//z80debug::stop();
} else {
mem::setTag(addr, tag | MEMTAG_DATA | MEMTAG_TDATA);
}
}
return value;
}
void WRITE_MEM_16(const uint16_t addr, const uint16_t value)
{
WRITE_MEM_8(addr, value & 0xff);
WRITE_MEM_8(addr+1, (value>>8) & 0xff);
}
void reset()
{
mem::reset();
rPC = 0x00;
rA = rX = rY = rS = rP = 0xff;
t = 0;
}
void interrupt(uint8_t type)
{
}
void BRK()
{
rPC++;
WRITE_MEM_16(0x0100+rS, rPC); rS-=2;
WRITE_MEM_8(0x0100+rS, rP|f1|fB); rS--;
rP |= fI;
rPC = READ_MEM_16(0xfffe);
t++;
}
void ORA(uint8_t addr_mode)
{
}
uint32_t step()
{
t = 0;
uint16_t current_opcode_address = rPC;
const uint8_t opcode = READ_M1();
uint8_t tag = mem::getTag(current_opcode_address);
if ( !(tag & MEMTAG_IGNORE) ) tag = tag | MEMTAG_INST;
mem::setTag(current_opcode_address, tag | (!(tag&MEMTAG_TOUCHED) ? MEMTAG_TREPEAT : MEMTAG_TINST) );
uint16_t tmp;
switch (opcode)
{
case 0x00: BRK(); break;
case 0x01: ORA(aIndirectX); break;
};
// [TODO] Gestionar interrupcions
//debug::setcursor(rPC);
//debug::history::store();
mem::update_mapped(t);
return t;
}
}