commit 033acb7124f4f3571283bab38809bd256cfc65e3 Author: Raimon Zamora Date: Fri Jan 31 14:04:44 2025 +0100 - First commit, working on the cpu diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..6f2ae84 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +nes diff --git a/6502.cpp b/6502.cpp new file mode 100644 index 0000000..e89610a --- /dev/null +++ b/6502.cpp @@ -0,0 +1,192 @@ +#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 = ®s[0]; + uint8_t *_rX = ®s[1]; + uint8_t *_rY = ®s[2]; + uint8_t *_rS = ®s[3]; + uint8_t *_rP = ®s[4]; + uint16_t *_rPC = (uint16_t*)®s[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; + } + +} diff --git a/6502.h b/6502.h new file mode 100644 index 0000000..3eaf87c --- /dev/null +++ b/6502.h @@ -0,0 +1,10 @@ +#pragma once + +#include + +namespace cpu6502 +{ + void reset(); + void interrupt(uint8_t type); + uint32_t step(); +} diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..cc74e44 --- /dev/null +++ b/Makefile @@ -0,0 +1,17 @@ +compile: + g++ -g *.cpp -lSDL2 -o nes + +run: compile + ./nes tetris.gb + +debug: compile + gdb --args nes tetris.gb + +debug1: compile + gdb -ex run nes + +release: + g++ -O3 *.cpp -lSDL2 -o nes + +profile: + g++ -g *.cpp -lSDL2 -o nes -pg diff --git a/debug.h b/debug.h new file mode 100644 index 0000000..403aeec --- /dev/null +++ b/debug.h @@ -0,0 +1,10 @@ +#pragma once +#include + +namespace debug +{ + void stop(); + + const bool isbreak(uint16_t address, uint8_t type = 1); + void setmemmodified(uint16_t address); +} \ No newline at end of file diff --git a/mem.h b/mem.h new file mode 100644 index 0000000..f12db3f --- /dev/null +++ b/mem.h @@ -0,0 +1,28 @@ +#pragma once +#include + +namespace mem +{ + #define MEMTAG_NONE 0x00 + #define MEMTAG_DATA 0x01 + #define MEMTAG_INST 0x02 + #define MEMTAG_CODE 0x04 + #define MEMTAG_IGNORE 0x08 + #define MEMTAG_TDATA 0x10 + #define MEMTAG_TINST 0x20 + #define MEMTAG_TREPEAT 0x40 + #define MEMTAG_MODIFIED 0x80 + + #define MEMTAG_KNOWN 0x07 + #define MEMTAG_TOUCHED 0x70 + + void reset(); + + uint8_t readMem(uint16_t address); + void writeMem(uint16_t address, uint8_t value); + + uint8_t getTag(uint16_t address); + void setTag(uint16_t address, uint8_t value); + + void update_mapped(uint32_t dt); +} \ No newline at end of file