From 421826d4b60ce1b928d9467d1b5bfca6b6853302 Mon Sep 17 00:00:00 2001 From: "Raimon @ quifisraimon" Date: Wed, 9 Sep 2026 10:02:13 +0200 Subject: [PATCH] =?UTF-8?q?-=20First=20commit:=20-=20[NEW]=20Afegit=20el?= =?UTF-8?q?=20m=C3=B2dul=20"acabat"=20del=206502=20-=20[NEW]=20Afegit=20el?= =?UTF-8?q?=20m=C3=B3dul=20"atari2600"=20director=20-=20[NEW]=20Afeggits?= =?UTF-8?q?=20stubs=20de=20display,=20speaker,=20mem,=20tia=20i=20pia?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 1 + 6502m.cpp | 618 ++++++++++++++++++++++++++++++++++++++++++++++++++ 6502m.h | 11 + atari2600.cpp | 81 +++++++ atari2600.h | 12 + display.h | 15 ++ lagueirtofile | 43 ++++ mem.h | 8 + pia.h | 7 + speaker.h | 12 + tia.h | 7 + 11 files changed, 815 insertions(+) create mode 100644 .gitignore create mode 100644 6502m.cpp create mode 100644 6502m.h create mode 100644 atari2600.cpp create mode 100644 atari2600.h create mode 100644 display.h create mode 100644 lagueirtofile create mode 100644 mem.h create mode 100644 pia.h create mode 100644 speaker.h create mode 100644 tia.h diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..6f2ae84 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +nes diff --git a/6502m.cpp b/6502m.cpp new file mode 100644 index 0000000..b520539 --- /dev/null +++ b/6502m.cpp @@ -0,0 +1,618 @@ +#include "6502m.h" +#include "mem.h" + + // 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 + +namespace m6502 +{ + uint8_t interrupt_vector = 0xfe; + + uint8_t rA; + uint8_t rX; + uint8_t rY; + uint8_t rS; + uint8_t rP; + uint8_t rPC_lo; + uint8_t rPC_hi; + //#define rPC (*_rPC) + + uint8_t rB; + uint8_t rT; + uint8_t rI; + uint8_t rAD_lo; + uint8_t rAD_hi; + //#define rAD (*_rAD) + uint8_t rTEMP_lo; + uint8_t rTEMP_hi; + //#define rTEMP (*_rTEMP) + + uint16_t exec_PC; + uint16_t getPC() { return exec_PC; } + + // Explicit 16-bit accessors prevent UB and stay host-endian safe + inline uint16_t get_PC() { return (uint16_t)rPC_lo | ((uint16_t)rPC_hi << 8); } + inline void set_PC(uint16_t val) { rPC_lo = val & 0xFF; rPC_hi = val >> 8; } + inline uint16_t inc_PC() { if (++rPC_lo == 0) rPC_hi++; return get_PC(); } // Natural 16-bit bump + + inline uint16_t get_AD() { return (uint16_t)rAD_lo | ((uint16_t)rAD_hi << 8); } + inline void set_AD(uint16_t val) { rAD_lo = val & 0xFF; rAD_hi = val >> 8; } + inline void inc_AD() { if (++rAD_lo == 0) rAD_hi++; } // Natural 16-bit bump + + inline uint16_t get_TEMP() { return (uint16_t)rTEMP_lo | ((uint16_t)rTEMP_hi << 8); } + inline void set_TEMP(uint16_t val) { rTEMP_lo = val & 0xFF; rTEMP_hi = val >> 8; } + inline void inc_TEMP() { if (++rTEMP_lo == 0) rTEMP_hi++; } // Natural 16-bit bump + + uint8_t microcode[256]; + uint8_t microcode_pos = 0; + uint8_t microcode_last = 0; + + enum microInstructions { + miFetchOpcode, + miFakeFetchOperand, + miFetchOperandLo, + miFetchOperandHi, + miFetchOperandHiAndIndexX, + miFetchOperandHiAndIndexY, + miPushPCHi, + miPushPCLo, + miPushP, + miPCLoInt, + miPCHiInt, + miIndexX, + miFetchAddressLo, + miFetchAddressHi, + miFetchAddressHiAndIndex, + miReadAddress, + miReadAddressAndSkip, + miWriteRegister, + miWriteAddress, + miPushA, + miFetchOperandAndCheckBranch, + miCheckIfPageCrossed, + miPullPCHi, + miPullPCLo, + miPullP, + miPullA, + miIncrementPC, + miFetchAddressHiToPC, + miIndexY, + miNumMicroinstructions + }; + + + uint8_t instructions[256][7] = { + /* 0x00 BRK */ { miFetchOperandLo, miPushPCHi, miPushPCLo, miPushP, miPCLoInt, miPCHiInt, miFetchOpcode }, + /* 0x01 ORA X,ind */ { miFetchOperandLo, miIndexX, miFetchAddressLo, miFetchAddressHi, miReadAddress, miFetchOpcode }, + /* 0x02 --- */ { miFetchOpcode }, + /* 0x03 --- */ { miFetchOpcode }, + /* 0x04 --- */ { miFetchOpcode }, + /* 0x05 ORA zpg */ { miFetchOperandLo, miReadAddress, miFetchOpcode }, + /* 0x06 ASL zpg */ { miFetchOperandLo, miReadAddress, miWriteAddress, miWriteAddress, miFetchOpcode }, + /* 0x07 --- */ { miFetchOpcode }, + /* 0x08 PHP */ { miFetchOperandLo, miPushP, miFetchOpcode }, + /* 0x09 ORA imm */ { miFetchOperandLo, miFetchOpcode }, + /* 0x0A ASL A */ { miFakeFetchOperand, miFetchOpcode }, + /* 0x0B --- */ { miFetchOpcode }, + /* 0x0C --- */ { miFetchOpcode }, + /* 0x0D ORA abs */ { miFetchOperandLo, miFetchOperandHi, miReadAddress, miFetchOpcode }, + /* 0x0E ASL abs */ { miFetchOperandLo, miFetchOperandHi, miReadAddress, miWriteAddress, miWriteAddress, miFetchOpcode }, + /* 0x0F --- */ { miFetchOpcode }, + + /* 0x10 BPL */ { miFetchOperandAndCheckBranch, miCheckIfPageCrossed, miFakeFetchOperand, miFetchOpcode }, + /* 0x11 ORA ind,Y */ { miFetchOperandLo, miFetchAddressLo, miFetchAddressHiAndIndex, miReadAddressAndSkip, miReadAddress, miFetchOpcode }, + /* 0x12 --- */ { miFetchOpcode }, + /* 0x13 --- */ { miFetchOpcode }, + /* 0x14 --- */ { miFetchOpcode }, + /* 0x15 ORA zpg,X */ { miFetchOperandLo, miIndexX, miReadAddress, miFetchOpcode }, + /* 0x16 ASL zpg,X */ { miFetchOperandLo, miIndexX, miReadAddress, miWriteAddress, miWriteAddress, miFetchOpcode }, + /* 0x17 --- */ { miFetchOpcode }, + /* 0x18 CLC */ { miFetchOperandLo, miFetchOpcode }, + /* 0x19 ORA abs,Y */ { miFetchOperandLo, miFetchOperandHiAndIndexY, miReadAddressAndSkip, miReadAddress, miFetchOpcode }, + /* 0x1A --- */ { miFetchOpcode }, + /* 0x1B --- */ { miFetchOpcode }, + /* 0x1C --- */ { miFetchOpcode }, + /* 0x1D ORA abs,X */ { miFetchOperandLo, miFetchOperandHiAndIndexX, miReadAddressAndSkip, miReadAddress, miFetchOpcode }, + /* 0x1E ASL abs,X */ { miFetchOperandLo, miFetchOperandHiAndIndexX, miReadAddress, miReadAddress, miWriteAddress, miWriteAddress, miFetchOpcode }, + /* 0x1F --- */ { miFetchOpcode }, + + /* 0x20 JSR abs */ { miFetchAddressLo, miFakeFetchOperand, miPushPCHi, miPushPCLo, miFetchAddressHi, miFetchOpcode }, + /* 0x21 AND X,ind */ { miFetchOperandLo, miIndexX, miFetchAddressLo, miFetchAddressHi, miReadAddress, miFetchOpcode }, + /* 0x22 --- */ { miFetchOpcode }, + /* 0x23 --- */ { miFetchOpcode }, + /* 0x24 BIT zpg */ { miFetchOperandLo, miReadAddress, miFetchOpcode }, + /* 0x25 AND zpg */ { miFetchOperandLo, miReadAddress, miFetchOpcode }, + /* 0x26 ROL zpg */ { miFetchOperandLo, miReadAddress, miWriteAddress, miWriteAddress, miFetchOpcode }, + /* 0x27 --- */ { miFetchOpcode }, + /* 0x28 PLP */ { miFetchOperandLo, miPullP, miFetchOpcode }, + /* 0x29 AND imm */ { miFetchOperandLo, miFetchOpcode }, + /* 0x2A ROL A */ { miFakeFetchOperand, miFetchOpcode }, + /* 0x2B --- */ { miFetchOpcode }, + /* 0x2C BIT abs */ { miFetchOperandLo, miFetchOperandHi, miReadAddress, miFetchOpcode }, + /* 0x2D AND abs */ { miFetchOperandLo, miFetchOperandHi, miReadAddress, miFetchOpcode }, + /* 0x2E ROL abs */ { miFetchOperandLo, miFetchOperandHi, miReadAddress, miWriteAddress, miWriteAddress, miFetchOpcode }, + /* 0x2F --- */ { miFetchOpcode }, + + /* 0x30 BMI */ { miFetchOperandAndCheckBranch, miCheckIfPageCrossed, miFakeFetchOperand, miFetchOpcode }, + /* 0x31 AND ind,Y */ { miFetchOperandLo, miFetchAddressLo, miFetchAddressHiAndIndex, miReadAddressAndSkip, miReadAddress, miFetchOpcode }, + /* 0x32 --- */ { miFetchOpcode }, + /* 0x33 --- */ { miFetchOpcode }, + /* 0x34 --- */ { miFetchOpcode }, + /* 0x35 AND zpg,X */ { miFetchOperandLo, miIndexX, miReadAddress, miFetchOpcode }, + /* 0x36 ROL zpg,X */ { miFetchOperandLo, miIndexX, miReadAddress, miWriteAddress, miWriteAddress, miFetchOpcode }, + /* 0x37 --- */ { miFetchOpcode }, + /* 0x38 SEC */ { miFetchOperandLo, miFetchOpcode }, + /* 0x39 AND abs,Y */ { miFetchOperandLo, miFetchOperandHiAndIndexY, miReadAddressAndSkip, miReadAddress, miFetchOpcode }, + /* 0x3A --- */ { miFetchOpcode }, + /* 0x3B --- */ { miFetchOpcode }, + /* 0x3C --- */ { miFetchOpcode }, + /* 0x3D AND abs,X */ { miFetchOperandLo, miFetchOperandHiAndIndexX, miReadAddressAndSkip, miReadAddress, miFetchOpcode }, + /* 0x3E ROL abs,X */ { miFetchOperandLo, miFetchOperandHiAndIndexX, miReadAddress, miReadAddress, miWriteAddress, miWriteAddress, miFetchOpcode }, + /* 0x3F --- */ { miFetchOpcode }, + + /* 0x40 RTI */ { miFetchOperandLo, miFakeFetchOperand, miPullP, miPullPCLo, miPullPCHi, miFetchOpcode }, + /* 0x41 EOR X,ind */ { miFetchOperandLo, miIndexX, miFetchAddressLo, miFetchAddressHi, miReadAddress, miFetchOpcode }, + /* 0x42 --- */ { miFetchOpcode }, + /* 0x43 --- */ { miFetchOpcode }, + /* 0x44 --- */ { miFetchOpcode }, + /* 0x45 EOR zpg */ { miFetchOperandLo, miReadAddress, miFetchOpcode }, + /* 0x46 LSR zpg */ { miFetchOperandLo, miReadAddress, miWriteAddress, miWriteAddress, miFetchOpcode }, + /* 0x47 --- */ { miFetchOpcode }, + /* 0x48 PHA */ { miFetchOperandLo, miPushA, miFetchOpcode }, + /* 0x49 EOR imm */ { miFetchOperandLo, miFetchOpcode }, + /* 0x4A LSR A */ { miFakeFetchOperand, miFetchOpcode }, + /* 0x4B --- */ { miFetchOpcode }, + /* 0x4C JMP abs */ { miFetchAddressLo, miFetchAddressHi, miFetchOpcode }, + /* 0x4D EOR abs */ { miFetchOperandLo, miFetchOperandHi, miReadAddress, miFetchOpcode }, + /* 0x4E LSR abs */ { miFetchOperandLo, miFetchOperandHi, miReadAddress, miWriteAddress, miWriteAddress, miFetchOpcode }, + /* 0x4F --- */ { miFetchOpcode }, + + /* 0x50 BVC */ { miFetchOperandAndCheckBranch, miCheckIfPageCrossed, miFakeFetchOperand, miFetchOpcode }, + /* 0x51 EOR ind,Y */ { miFetchOperandLo, miFetchAddressLo, miFetchAddressHiAndIndex, miReadAddressAndSkip, miReadAddress, miFetchOpcode }, + /* 0x52 --- */ { miFetchOpcode }, + /* 0x53 --- */ { miFetchOpcode }, + /* 0x54 --- */ { miFetchOpcode }, + /* 0x55 EOR zpg,X */ { miFetchOperandLo, miIndexX, miReadAddress, miFetchOpcode }, + /* 0x56 LSR zpg,X */ { miFetchOperandLo, miIndexX, miReadAddress, miWriteAddress, miWriteAddress, miFetchOpcode }, + /* 0x57 --- */ { miFetchOpcode }, + /* 0x58 CLI */ { miFetchOperandLo, miFetchOpcode }, + /* 0x59 EOR abs,Y */ { miFetchOperandLo, miFetchOperandHiAndIndexY, miReadAddressAndSkip, miReadAddress, miFetchOpcode }, + /* 0x5A --- */ { miFetchOpcode }, + /* 0x5B --- */ { miFetchOpcode }, + /* 0x5C --- */ { miFetchOpcode }, + /* 0x5D EOR abs,X */ { miFetchOperandLo, miFetchOperandHiAndIndexX, miReadAddressAndSkip, miReadAddress, miFetchOpcode }, + /* 0x5E LSR abs,X */ { miFetchOperandLo, miFetchOperandHiAndIndexX, miReadAddress, miReadAddress, miWriteAddress, miWriteAddress, miFetchOpcode }, + /* 0x5F --- */ { miFetchOpcode }, + + /* 0x60 RTS */ { miFetchOperandLo, miFakeFetchOperand, miPullPCLo, miPullPCHi, miIncrementPC, miFetchOpcode }, + /* 0x61 ADC X,ind */ { miFetchOperandLo, miIndexX, miFetchAddressLo, miFetchAddressHi, miReadAddress, miFetchOpcode }, + /* 0x62 --- */ { miFetchOpcode }, + /* 0x63 --- */ { miFetchOpcode }, + /* 0x64 --- */ { miFetchOpcode }, + /* 0x65 ADC zpg */ { miFetchOperandLo, miReadAddress, miFetchOpcode }, + /* 0x66 ROR zpg */ { miFetchOperandLo, miReadAddress, miWriteAddress, miWriteAddress, miFetchOpcode }, + /* 0x67 --- */ { miFetchOpcode }, + /* 0x68 PLA */ { miFetchOperandLo, miFakeFetchOperand, miPullA, miFetchOpcode }, + /* 0x69 ADC imm */ { miFetchOperandLo, miFetchOpcode }, + /* 0x6A ROR A */ { miFakeFetchOperand, miFetchOpcode }, + /* 0x6B --- */ { miFetchOpcode }, + /* 0x6C JMP ind */ { miFetchOperandLo, miFetchOperandHi, miFetchAddressLo, miFetchAddressHiToPC, miFetchOpcode }, + /* 0x6D ADC abs */ { miFetchOperandLo, miFetchOperandHi, miReadAddress, miFetchOpcode }, + /* 0x6E ROR abs */ { miFetchOperandLo, miFetchOperandHi, miReadAddress, miWriteAddress, miWriteAddress, miFetchOpcode }, + /* 0x6F --- */ { miFetchOpcode }, + + /* 0x70 BVS */ { miFetchOperandAndCheckBranch, miCheckIfPageCrossed, miFakeFetchOperand, miFetchOpcode }, + /* 0x71 ADC ind,Y */ { miFetchOperandLo, miFetchAddressLo, miFetchAddressHiAndIndex, miReadAddressAndSkip, miReadAddress, miFetchOpcode }, + /* 0x72 --- */ { miFetchOpcode }, + /* 0x73 --- */ { miFetchOpcode }, + /* 0x74 --- */ { miFetchOpcode }, + /* 0x75 ADC zpg,X */ { miFetchOperandLo, miIndexX, miReadAddress, miFetchOpcode }, + /* 0x76 ROR zpg,X */ { miFetchOperandLo, miIndexX, miReadAddress, miWriteAddress, miWriteAddress, miFetchOpcode }, + /* 0x77 --- */ { miFetchOpcode }, + /* 0x78 SEI */ { miFetchOperandLo, miFetchOpcode }, + /* 0x79 ADC abs,Y */ { miFetchOperandLo, miFetchOperandHiAndIndexY, miReadAddressAndSkip, miReadAddress, miFetchOpcode }, + /* 0x7A --- */ { miFetchOpcode }, + /* 0x7B --- */ { miFetchOpcode }, + /* 0x7C --- */ { miFetchOpcode }, + /* 0x7D ADC abs,X */ { miFetchOperandLo, miFetchOperandHiAndIndexX, miReadAddressAndSkip, miReadAddress, miFetchOpcode }, + /* 0x7E ROR abs,X */ { miFetchOperandLo, miFetchOperandHiAndIndexX, miReadAddress, miReadAddress, miWriteAddress, miWriteAddress, miFetchOpcode }, + /* 0x7F --- */ { miFetchOpcode }, + + /* 0x80 --- */ { miFetchOpcode }, + /* 0x81 STA X,ind */ { miFetchOperandLo, miIndexX, miFetchAddressLo, miFetchAddressHi, miWriteRegister, miFetchOpcode }, + /* 0x82 --- */ { miFetchOpcode }, + /* 0x83 --- */ { miFetchOpcode }, + /* 0x84 STY zpg */ { miFetchOperandLo, miWriteRegister, miFetchOpcode }, + /* 0x85 STA zpg */ { miFetchOperandLo, miWriteRegister, miFetchOpcode }, + /* 0x86 STX zpg */ { miFetchOperandLo, miWriteRegister, miFetchOpcode }, + /* 0x87 --- */ { miFetchOpcode }, + /* 0x88 DEY */ { miFetchOperandLo, miFetchOpcode }, + /* 0x89 --- */ { miFetchOpcode }, + /* 0x8A TXA */ { miFetchOperandLo, miFetchOpcode }, + /* 0x8B --- */ { miFetchOpcode }, + /* 0x8C STY abs */ { miFetchOperandLo, miFetchOperandHi, miWriteRegister, miFetchOpcode }, + /* 0x8D STA abs */ { miFetchOperandLo, miFetchOperandHi, miWriteRegister, miFetchOpcode }, + /* 0x8E STX abs */ { miFetchOperandLo, miFetchOperandHi, miWriteRegister, miFetchOpcode }, + /* 0x8F --- */ { miFetchOpcode }, + + /* 0x90 BCC */ { miFetchOperandAndCheckBranch, miCheckIfPageCrossed, miFakeFetchOperand, miFetchOpcode }, + /* 0x91 STA ind,Y */ { miFetchOperandLo, miFetchAddressLo, miFetchAddressHiAndIndex, miReadAddress, miWriteRegister, miFetchOpcode }, + /* 0x92 --- */ { miFetchOpcode }, + /* 0x93 --- */ { miFetchOpcode }, + /* 0x94 STY zpg,X */ { miFetchOperandLo, miIndexX, miWriteRegister, miFetchOpcode }, + /* 0x95 STA zpg,X */ { miFetchOperandLo, miIndexX, miWriteRegister, miFetchOpcode }, + /* 0x96 STX zpg,X */ { miFetchOperandLo, miIndexX, miWriteRegister, miFetchOpcode }, + /* 0x97 --- */ { miFetchOpcode }, + /* 0x98 TYA */ { miFetchOperandLo, miFetchOpcode }, + /* 0x99 STA abs,Y */ { miFetchOperandLo, miFetchOperandHiAndIndexY, miReadAddress, miWriteRegister, miFetchOpcode }, + /* 0x9A TXS */ { miFetchOperandLo, miFetchOpcode }, + /* 0x9B --- */ { miFetchOpcode }, + /* 0x9C --- */ { miFetchOpcode }, + /* 0x9D STA abs,X */ { miFetchOperandLo, miFetchOperandHiAndIndexX, miReadAddress, miWriteRegister, miFetchOpcode }, + /* 0x9E --- */ { miFetchOpcode }, + /* 0x9F --- */ { miFetchOpcode }, + + /* 0xA0 LDY imm */ { miFetchOperandLo, miFetchOpcode }, + /* 0xA1 LDA X,ind */ { miFetchOperandLo, miIndexX, miFetchAddressLo, miFetchAddressHi, miReadAddress, miFetchOpcode }, + /* 0xA2 LDX imm */ { miFetchOperandLo, miFetchOpcode }, + /* 0xA3 --- */ { miFetchOpcode }, + /* 0xA4 LDY zpg */ { miFetchOperandLo, miReadAddress, miFetchOpcode }, + /* 0xA5 LDA zpg */ { miFetchOperandLo, miReadAddress, miFetchOpcode }, + /* 0xA6 LDX zpg */ { miFetchOperandLo, miReadAddress, miFetchOpcode }, + /* 0xA7 --- */ { miFetchOpcode }, + /* 0xA8 TAY */ { miFetchOperandLo, miFetchOpcode }, + /* 0xA9 LDA imm */ { miFetchOperandLo, miFetchOpcode }, + /* 0xAA TAX */ { miFetchOperandLo, miFetchOpcode }, + /* 0xAB --- */ { miFetchOpcode }, + /* 0xAC LDY abs */ { miFetchOperandLo, miFetchOperandHi, miReadAddress, miFetchOpcode }, + /* 0xAD LDA abs */ { miFetchOperandLo, miFetchOperandHi, miReadAddress, miFetchOpcode }, + /* 0xAE LDX abs */ { miFetchOperandLo, miFetchOperandHi, miReadAddress, miFetchOpcode }, + /* 0xAF --- */ { miFetchOpcode }, + + /* 0xB0 BCS */ { miFetchOperandAndCheckBranch, miCheckIfPageCrossed, miFakeFetchOperand, miFetchOpcode }, + /* 0xB1 LDA ind,Y */ { miFetchOperandLo, miFetchAddressLo, miFetchAddressHiAndIndex, miReadAddressAndSkip, miReadAddress, miFetchOpcode }, + /* 0xB2 --- */ { miFetchOpcode }, + /* 0xB3 --- */ { miFetchOpcode }, + /* 0xB4 LDY zpg,X */ { miFetchOperandLo, miIndexX, miReadAddress, miFetchOpcode }, + /* 0xB5 LDA zpg,X */ { miFetchOperandLo, miIndexX, miReadAddress, miFetchOpcode }, + /* 0xB6 LDX zpg,Y */ { miFetchOperandLo, miIndexY, miReadAddress, miFetchOpcode }, + /* 0xB7 --- */ { miFetchOpcode }, + /* 0xB8 CLV */ { miFetchOperandLo, miFetchOpcode }, + /* 0xB9 LDA abs,Y */ { miFetchOperandLo, miFetchOperandHiAndIndexY, miReadAddressAndSkip, miReadAddress, miFetchOpcode }, + /* 0xBA TSX */ { miFetchOperandLo, miFetchOpcode }, + /* 0xBB --- */ { miFetchOpcode }, + /* 0xBC LDY abs,X */ { miFetchOperandLo, miFetchOperandHiAndIndexX, miReadAddressAndSkip, miReadAddress, miFetchOpcode }, + /* 0xBD LDA abs,X */ { miFetchOperandLo, miFetchOperandHiAndIndexX, miReadAddressAndSkip, miReadAddress, miFetchOpcode }, + /* 0xBE LDX abs,Y */ { miFetchOperandLo, miFetchOperandHiAndIndexY, miReadAddressAndSkip, miReadAddress, miFetchOpcode }, + /* 0xBF --- */ { miFetchOpcode }, + + /* 0xC0 CPY, imm */ { miFetchOperandLo, miFetchOpcode }, + /* 0xC1 CMP X,ind */ { miFetchOperandLo, miIndexX, miFetchAddressLo, miFetchAddressHi, miReadAddress, miFetchOpcode }, + /* 0xC2 --- */ { miFetchOpcode }, + /* 0xC3 --- */ { miFetchOpcode }, + /* 0xC4 CPY zpg */ { miFetchOperandLo, miReadAddress, miFetchOpcode }, + /* 0xC5 CMP zpg */ { miFetchOperandLo, miReadAddress, miFetchOpcode }, + /* 0xC6 DEC zpg */ { miFetchOperandLo, miReadAddress, miWriteAddress, miWriteAddress, miFetchOpcode }, + /* 0xC7 --- */ { miFetchOpcode }, + /* 0xC8 INY */ { miFetchOperandLo, miFetchOpcode }, + /* 0xC9 CMP imm */ { miFetchOperandLo, miFetchOpcode }, + /* 0xCA DEX */ { miFetchOperandLo, miFetchOpcode }, + /* 0xCB --- */ { miFetchOpcode }, + /* 0xCC CPY abs */ { miFetchOperandLo, miFetchOperandHi, miReadAddress, miFetchOpcode }, + /* 0xCD CMP abs */ { miFetchOperandLo, miFetchOperandHi, miReadAddress, miFetchOpcode }, + /* 0xCE DEC abs */ { miFetchOperandLo, miFetchOperandHi, miReadAddress, miWriteAddress, miWriteAddress, miFetchOpcode }, + /* 0xCF --- */ { miFetchOpcode }, + + /* 0xD0 BNE */ { miFetchOperandAndCheckBranch, miCheckIfPageCrossed, miFakeFetchOperand, miFetchOpcode }, + /* 0xD1 CMP ind,Y */ { miFetchOperandLo, miFetchAddressLo, miFetchAddressHiAndIndex, miReadAddressAndSkip, miReadAddress, miFetchOpcode }, + /* 0xD2 --- */ { miFetchOpcode }, + /* 0xD3 --- */ { miFetchOpcode }, + /* 0xD4 --- */ { miFetchOpcode }, + /* 0xD5 CMP zpg,X */ { miFetchOperandLo, miIndexX, miReadAddress, miFetchOpcode }, + /* 0xD6 DEC zpg,X */ { miFetchOperandLo, miIndexX, miReadAddress, miWriteAddress, miWriteAddress, miFetchOpcode }, + /* 0xD7 --- */ { miFetchOpcode }, + /* 0xD8 CLD */ { miFetchOperandLo, miFetchOpcode }, + /* 0xD9 CMP abs,Y */ { miFetchOperandLo, miFetchOperandHiAndIndexY, miReadAddressAndSkip, miReadAddress, miFetchOpcode }, + /* 0xDA --- */ { miFetchOpcode }, + /* 0xDB --- */ { miFetchOpcode }, + /* 0xDC --- */ { miFetchOpcode }, + /* 0xDD CMP abs,X */ { miFetchOperandLo, miFetchOperandHiAndIndexX, miReadAddressAndSkip, miReadAddress, miFetchOpcode }, + /* 0xDE DEC abs,X */ { miFetchOperandLo, miFetchOperandHiAndIndexX, miReadAddress, miReadAddress, miWriteAddress, miWriteAddress, miFetchOpcode }, + /* 0xDF --- */ { miFetchOpcode }, + + /* 0xE0 CPX, imm */ { miFetchOperandLo, miFetchOpcode }, + /* 0xE1 SBC X,ind */ { miFetchOperandLo, miIndexX, miFetchAddressLo, miFetchAddressHi, miReadAddress, miFetchOpcode }, + /* 0xE2 --- */ { miFetchOpcode }, + /* 0xE3 --- */ { miFetchOpcode }, + /* 0xE4 CPX zpg */ { miFetchOperandLo, miReadAddress, miFetchOpcode }, + /* 0xE5 SBC zpg */ { miFetchOperandLo, miReadAddress, miFetchOpcode }, + /* 0xE6 INC zpg */ { miFetchOperandLo, miReadAddress, miWriteAddress, miWriteAddress, miFetchOpcode }, + /* 0xE7 --- */ { miFetchOpcode }, + /* 0xE8 INX */ { miFetchOperandLo, miFetchOpcode }, + /* 0xE9 SBC imm */ { miFetchOperandLo, miFetchOpcode }, + /* 0xEA NOP */ { miFetchOpcode }, + /* 0xEB --- */ { miFetchOpcode }, + /* 0xEC CPX abs */ { miFetchOperandLo, miFetchOperandHi, miReadAddress, miFetchOpcode }, + /* 0xED SBC abs */ { miFetchOperandLo, miFetchOperandHi, miReadAddress, miFetchOpcode }, + /* 0xEE INC abs */ { miFetchOperandLo, miFetchOperandHi, miReadAddress, miWriteAddress, miWriteAddress, miFetchOpcode }, + /* 0xEF --- */ { miFetchOpcode }, + + /* 0xF0 BEQ */ { miFetchOperandAndCheckBranch, miCheckIfPageCrossed, miFakeFetchOperand, miFetchOpcode }, + /* 0xF1 SBC ind,Y */ { miFetchOperandLo, miFetchAddressLo, miFetchAddressHiAndIndex, miReadAddressAndSkip, miReadAddress, miFetchOpcode }, + /* 0xF2 --- */ { miFetchOpcode }, + /* 0xF3 --- */ { miFetchOpcode }, + /* 0xF4 --- */ { miFetchOpcode }, + /* 0xF5 SBC zpg,X */ { miFetchOperandLo, miIndexX, miReadAddress, miFetchOpcode }, + /* 0xF6 INC zpg,X */ { miFetchOperandLo, miIndexX, miReadAddress, miWriteAddress, miWriteAddress, miFetchOpcode }, + /* 0xF7 --- */ { miFetchOpcode }, + /* 0xF8 SED */ { miFetchOperandLo, miFetchOpcode }, + /* 0xF9 SBC abs,Y */ { miFetchOperandLo, miFetchOperandHiAndIndexY, miReadAddressAndSkip, miReadAddress, miFetchOpcode }, + /* 0xFA --- */ { miFetchOpcode }, + /* 0xFB --- */ { miFetchOpcode }, + /* 0xFC --- */ { miFetchOpcode }, + /* 0xFD SBC abs,X */ { miFetchOperandLo, miFetchOperandHiAndIndexX, miReadAddressAndSkip, miReadAddress, miFetchOpcode }, + /* 0xFE INC abs,X */ { miFetchOperandLo, miFetchOperandHiAndIndexX, miReadAddress, miReadAddress, miWriteAddress, miWriteAddress, miFetchOpcode }, + /* 0xFF --- */ { miFetchOpcode }, + }; + + void SetFlags(uint8_t flags) + { + if (flags&fC) rP = ( rP & ~fC ) | ( rTEMP_hi & fC ); + if (flags&fN) rP = ( rP & ~fN ) | ( rTEMP_lo & fN ); + if (flags&fZ) rP = ( rTEMP_lo ? rP & ~fZ : rP | fZ ); + if (flags&fV) rP = ( (rTEMP_lo ^ rA) & (rTEMP_lo ^ rB) & 0x80 ) ? rP | fV : rP & ~fV; + } + + void DoDecimalADC() + { + uint8_t c_in = (rP & fC) ? 1 : 0; + uint8_t low = (rA & 0x0F) + (rB & 0x0F) + c_in; + if (low > 9) low += 6; + uint8_t high = (rA >> 4) + (rB >> 4) + (low > 0x0F ? 1 : 0); + + // Set Zero and Negative flags based on BINARY addition result (NMOS 6502 accurate) + uint16_t bin_sum = (uint16_t)rA + rB + c_in; + rTEMP_lo = bin_sum & 0xFF; + if (~(rA ^ rB) & (rA ^ rTEMP_lo) & 0x80) rP |= fV; else rP &= ~fV; + SetFlags(fN | fZ); + + if (high > 9) high += 6; + rP = (high > 15) ? (rP | fC) : (rP & ~fC); + rA = ((high << 4) | (low & 0x0F)) & 0xFF; + } + + void DoDecimalSBC() + { + uint8_t c_in = (rP & fC) ? 1 : 0; + uint16_t bin_diff = (uint16_t)rA - rB - (1 - c_in); + + int low = (rA & 0x0F) - (rB & 0x0F) - (1 - c_in); + int high = (rA >> 4) - (rB >> 4); + if (low < 0) { low -= 6; high--; } + if (high < 0) high -= 6; + + rTEMP_lo = bin_diff & 0xFF; + if ((rA ^ rB) & (rA ^ rTEMP_lo) & 0x80) rP |= fV; else rP &= ~fV; + if (!(bin_diff & 0x100)) rP |= fC; else rP &= ~fC; + SetFlags(fN | fZ); + + rA = ((high << 4) | (low & 0x0F)) & 0xFF; + } + + void DoBinaryADC() + { + uint8_t c_in = (rP & fC) ? 1 : 0; + uint16_t sum = (uint16_t)rA + rB + c_in; + rTEMP_lo = sum & 0xFF; + if (sum > 0xFF) rP |= fC; else rP &= ~fC; + if (~(rA ^ rB) & (rA ^ rTEMP_lo) & 0x80) rP |= fV; else rP &= ~fV; + SetFlags(fN | fZ); + rA = rTEMP_lo; + } + + void DoBinarySBC() + { + uint8_t tmp = rB; + rB ^= 0xFF; + DoBinaryADC(); + rB = tmp; + } + + void DoOpcodeWork() + { + if (rI==0xCA) { rX--; rB = rX; SetFlags(fN|fZ); return; } /* DEX */ + if (rI==0x88) { rY--; rB = rY; SetFlags(fN|fZ); return; } /* DEY */ + if (rI==0xE8) { rX++; rB = rX; SetFlags(fN|fZ); return; } /* INX */ + if (rI==0xC8) { rY++; rB = rY; SetFlags(fN|fZ); return; } /* INY */ + + if (rI==0xA8) { rY = rA; rB = rY; SetFlags(fN|fZ); return; } /* TAY */ + if (rI==0x98) { rA = rY; rB = rA; SetFlags(fN|fZ); return; } /* TYA */ + if (rI==0xAA) { rX = rA; rB = rX; SetFlags(fN|fZ); return; } /* TAX */ + if (rI==0x8A) { rA = rX; rB = rA; SetFlags(fN|fZ); return; } /* TXA */ + if (rI==0xBA) { rX = rS; rB = rX; SetFlags(fN|fZ); return; } /* TSX */ + if (rI==0x9A) { rS = rX; rB = rS; SetFlags(fN|fZ); return; } /* TXS */ + + switch (rI&0x03) { + case 0: /* Clear/set flags*/ + if ( (rI&0x1c)==0x18 ) { + switch (rI>>5) { + case 0: rP &= ~fC; break; + case 1: rP |= fC; break; + case 2: rP &= ~fI; break; + case 3: rP |= fI; break; + case 5: rP &= ~fV; break; + case 6: rP &= ~fD; break; + case 7: rP |= fD; break; + } + } else if ( ((rI>>5)==5) && (rI!=0xB0) ) { + /* LDY */ rTEMP_lo = rB; SetFlags(fN|fZ); rY = rTEMP_lo; break; + } else if ( ((rI&0xD3)==0xC0) && (((rI>>2)&3)!=2) ) { + if ( (rI&0xf0)==0xC0 ) { + /* CPY */ set_TEMP(rY + ~rB); SetFlags(fN|fZ|fC); break; + } else { + /* CPX */ set_TEMP(rX + ~rB); SetFlags(fN|fZ|fC); break; + } + } + break; + case 1: /* ALU */ + + switch ((rI>>5)&0x07) { + case 0: /* ORA */ rTEMP_lo = rA | rB; SetFlags(fN|fZ); rA = rTEMP_lo; break; + case 1: /* AND */ rTEMP_lo = rA & rB; SetFlags(fN|fZ); rA = rTEMP_lo; break; + case 2: /* EOR */ rTEMP_lo = rA ^ rB; SetFlags(fN|fZ); rA = rTEMP_lo; break; + case 7: /* SBC */ if (rP & fD) DoDecimalSBC(); else DoBinarySBC(); break; + case 3: /* ADC */ if (rP & fD) DoDecimalADC(); else DoBinaryADC(); break; + case 5: /* LDA */ rTEMP_lo = rB; SetFlags(fN|fZ); rA = rTEMP_lo; break; + case 6: /* CMP */ + uint16_t diff = (uint16_t)rA - rB; + rP = (diff < 0x100) ? (rP | fC) : (rP & ~fC); + rTEMP_lo = diff & 0xFF; + SetFlags(fN|fZ); + break; + }; + if ( (rI==0x24) || (rI==0x2C) ) /* BIT */ { rTEMP_lo = rA & rB; rP = (rP&~(fN|fV)) | (rB&(fN|fV)); SetFlags(fZ); } + break; + case 2: + if ( ((rI>>5)==5) ) { + /* LDX */ rTEMP_lo = rB; SetFlags(fN|fZ); rX = rTEMP_lo; break; + } + break; + + }; + } + + void DoRMW() + { + switch (rI&0x03) { + case 2: /* RMW */ + if ((rI & 0xF)==0xA) rB = rA; + switch ((rI>>5)&0x07) { + case 0: /* ASL */ rP = ( rP & ~fC ) | ( (rB & 0x80)>>7 ); rB = rB << 1; SetFlags(fN|fZ); break; + case 1: /* ROL */ rT = rP & fC; rP = ( rP & ~fC ) | ( (rB & 0x80)>>7 ); rB = (rB << 1) | rT; SetFlags(fN|fZ); break; + case 2: /* LSR */ rP = ( rP & ~fC ) | ( (rB & fC) ); rB = rB >> 1; SetFlags(fN|fZ); break; + case 3: /* ROR */ rT = (rP & fC) << 7; rP = ( rP & ~fC ) | ( (rB & fC) ); rB = (rB >> 1) | rT; SetFlags(fN|fZ); break; + case 6: /* DEC */ rB--; SetFlags(fN|fZ); break; + case 7: /* INC */ rB++; SetFlags(fN|fZ); break; + }; + if ((rI & 0xF)==0xA) rA = rB; + break; + }; + } + + bool BranchCondition() + { + const uint8_t flags[4] = {fN, fV, fC, fZ}; + const uint8_t flag = flags[rI>>6]; + const bool condition = (rI>>5)&1; + return (rP & flag) == condition; + } + + void InsertFetchOpcode() + { + microcode[microcode_pos] = miFetchOpcode; + microcode_last = microcode_pos+1; + } + + void FetchOpcode() + { + DoOpcodeWork(); + + exec_PC = get_PC(); + rI = mem::read(exec_PC); + inc_PC(); + int i=0; do { microcode[microcode_last++] = instructions[rI][i++]; } while (instructions[rI][i-1] != miFetchOpcode); + } + + void FakeFetchOperand() { rAD_lo = mem::read(get_PC()); } + void FetchOperandLo() { rAD_lo = rB = mem::read(get_PC()); inc_PC(); set_TEMP(rB); } + void FetchOperandHi() { rAD_hi = mem::read(get_PC()); inc_PC(); } + void FetchOperandHiAndIndexX() { rAD_hi = mem::read(get_PC()); inc_PC(); set_TEMP(rAD_lo + rX); rAD_lo = rTEMP_lo; } + void FetchOperandHiAndIndexY() { rAD_hi = mem::read(get_PC()); inc_PC(); set_TEMP(rAD_lo + rY); rAD_lo = rTEMP_lo; } + + void PushPCHi() { mem::write(0x0100+(rS--), rPC_hi); } + void PushPCLo() { mem::write(0x0100+(rS--), rPC_lo); } + void PushP() { mem::write(0x0100+(rS--), rP|f1|fB); rP |= fI; } + void PCLoInt() { rPC_lo = mem::read(0xff00+interrupt_vector); } + void PCHiInt() { rPC_hi = mem::read(0xff00+interrupt_vector+1); } + + void IndexX() { rB = mem::read(get_AD()); rAD_lo += rX; } + void FetchAddressLo() { rT = mem::read(get_AD()); inc_AD(); } + void FetchAddressHi() { rAD_hi = mem::read(get_AD()); rAD_lo = rT; } + void FetchAddressHiAndIndex() { rAD_hi = mem::read(get_AD()); set_TEMP(rAD_lo + rY); rAD_lo = rTEMP_lo; } + void ReadAddress() { rB = mem::read(get_AD()); rAD_hi += rTEMP_hi; } + + void ReadAddressAndSkip() { rB = mem::read(get_AD()); rAD_hi += rTEMP_hi; if (rTEMP_hi) InsertFetchOpcode(); } + void WriteRegister() { mem::write(get_AD(), (rI&3)==1 ? rA : (rI&3)==2 ? rX : rY ); } + void WriteAddress() { mem::write(get_AD(), rB); DoRMW(); } + void PushA() { mem::write(0x0100+(rS--), rA); } + void FetchOperandAndCheckBranch() { + int8_t offset = (int8_t)mem::read(get_PC()); inc_PC(); + rB = (uint8_t)offset; + + if (!BranchCondition()) { + InsertFetchOpcode(); + return; + } + set_TEMP(rPC_lo + offset); + rT = rPC_hi; + rPC_lo = rTEMP_lo; + } + + void CheckIfPageCrossed() { + FakeFetchOperand(); + + int8_t offset = (int8_t)rB; + + if (offset >= 0 && rTEMP_hi != 0) { + rPC_hi++; + } else if (offset < 0 && rTEMP_hi == 0) { + rPC_hi--; + } else { + InsertFetchOpcode(); + } + } + + void PullPCHi() { rPC_hi = mem::read(0x0100+(++rS)); } + void PullPCLo() { rPC_lo = mem::read(0x0100+(++rS)); } + void PullP() { rP = mem::read(0x0100+(++rS)); } + void PullA() { rA = mem::read(0x0100+(++rS)); } + + void IncrementPC() { inc_PC(); } + void FetchAddressHiToPC() { uint16_t high_addr = (get_AD() & 0xFF00) | ((get_AD() + 1) & 0x00FF); rPC_hi = mem::read(high_addr); rPC_lo = rT; } + void IndexY() { rB = mem::read(get_AD()); rAD_lo += rY; } + + void (*microinstructions[miNumMicroinstructions])(void) { + FetchOpcode, FakeFetchOperand, FetchOperandLo, FetchOperandHi, FetchOperandHiAndIndexX, FetchOperandHiAndIndexY, + PushPCHi, PushPCLo, PushP, PCLoInt, PCHiInt, + IndexX, FetchAddressLo, FetchAddressHi, FetchAddressHiAndIndex, ReadAddress, + ReadAddressAndSkip, WriteRegister, WriteAddress, PushA, FetchOperandAndCheckBranch, + CheckIfPageCrossed, PullPCHi, PullPCLo, PullP, PullA, + IncrementPC, FetchAddressHiToPC, IndexY }; + + void reset() + { + + } + + void interrupt(uint8_t type) + { + interrupt_vector = type; + } + + bool tick() + { + uint8_t m_inst = microcode[microcode_pos++]; + microinstructions[m_inst](); + + // tornem true si anem a començar una nova instrucció i, per tant, el step ha acabat + return (m_inst == miFetchOpcode); + } + +} diff --git a/6502m.h b/6502m.h new file mode 100644 index 0000000..b0c2715 --- /dev/null +++ b/6502m.h @@ -0,0 +1,11 @@ +#pragma once +#include + +namespace m6502 +{ + void reset(); + void interrupt(uint8_t type); + bool tick(); + + uint16_t getPC(); +} diff --git a/atari2600.cpp b/atari2600.cpp new file mode 100644 index 0000000..22010c6 --- /dev/null +++ b/atari2600.cpp @@ -0,0 +1,81 @@ +#include "atari2600.h" +#include "6502m.h" +#include "mem.h" +#include "tia.h" +#include "pia.h" +#include "display.h" +#include "speaker.h" +//#include "keyboard.h" +//#include "z80debugger.h" + +namespace atari2600 +{ + static bool should_exit = false; + static bool paused = false; + + void init() + { + paused = false; + m6502::reset(); + mem::reset(); + tia::reset(); + pia::reset(); + + display::init(); + speaker::init(); + //speaker::register_source(psg::get_sample); + //speaker::register_source(keyboard::get_sample); + } + + void quit() + { + should_exit = true; + } + + void step() + { + uint8_t t_states; + uint16_t pc = m6502::getPC(); + +// if (z80debugger::isbreak(pc, 9)) { +// msx::pause(); +// z80debugger::show(); +// return; +// } else { + bool instruction_done = false; + while (!instruction_done) { + instruction_done = m6502::tick(); + tia::tick(); + tia::tick(); + tia::tick(); + pia::tick(); + t_states++; + } + //speaker::update(t_states); +// } + } + + void pause() + { + display::setTitle(" (paused)"); + paused = true; + display::redraw(); + } + + void resume() + { + display::setTitle(""); + paused = false; + } + + bool is_paused() + { + return paused; + } + + bool is_quitting() + { + return should_exit; + } + +} diff --git a/atari2600.h b/atari2600.h new file mode 100644 index 0000000..8f64a1e --- /dev/null +++ b/atari2600.h @@ -0,0 +1,12 @@ +#pragma once + +namespace atari2600 +{ + void init(); + void quit(); + void step(); + void pause(); + void resume(); + bool is_paused(); + bool is_quitting(); +} diff --git a/display.h b/display.h new file mode 100644 index 0000000..566ae08 --- /dev/null +++ b/display.h @@ -0,0 +1,15 @@ +#pragma once + +namespace display +{ + void init(); + void focus(); + void redraw(const bool present=true); + void present(); + void setTitle(const char* title); + + void incZoom(); + void decZoom(); + void toggleFullscreen(); + const bool getFullscreen(); +} diff --git a/lagueirtofile b/lagueirtofile new file mode 100644 index 0000000..589df46 --- /dev/null +++ b/lagueirtofile @@ -0,0 +1,43 @@ +[linux] +cppflags = -Wall -Os -ffunction-sections -fdata-sections -std=c++20 -Isource +libs = -Wl,--gc-sections -lSDL3 +executable = atari2600 +sourcepath = source+ +buildpath = build + +[linux_debug] default +cppflags = -D DEBUG -g -Wall -std=c++20 -Isource +libs = -lSDL3 -lGL +executable = atari2600_debug +sourcepath = source+ +buildpath = build + +[windows] +cppflags = -Wall -Os -ffunction-sections -fdata-sections -std=c++20 -Isource +libs = icon.res -Wl,--gc-sections -lmingw32 -lSDL3 -lopengl32 -mwindows -static-libstdc++ -static-libgcc -lpthread -mwindows +executable = atari2600.exe +sourcepath = source+ +buildpath = build + +[windows_debug] +cppflags = -D DEBUG -g -Wall -std=c++20 -Isource +libs = -lmingw32 -lSDL3 +executable = atari2600_debug.exe +sourcepath = source+ +buildpath = build + +[macos] +compiler = clang++ +cppflags = -Wall -Os -Wno-deprecated -ffunction-sections -fdata-sections -std=c++20 -Isource +libs = -lSDL3 +executable = atari2600 +sourcepath = source+ +buildpath = build + +[macos_debug] +compiler = clang++ +cppflags = -D DEBUG -g -Wall -Wno-deprecated -std=c++20 -Isource +libs = -lSDL3 +executable = atari2600_debug +sourcepath = source+ +buildpath = build diff --git a/mem.h b/mem.h new file mode 100644 index 0000000..77d3238 --- /dev/null +++ b/mem.h @@ -0,0 +1,8 @@ +#pragma once + +namespace mem +{ + void reset(); + uint8_t read(uint16_t address); + void write(uint16_t address, uint8_t value); +} \ No newline at end of file diff --git a/pia.h b/pia.h new file mode 100644 index 0000000..4e28253 --- /dev/null +++ b/pia.h @@ -0,0 +1,7 @@ +#pragma once + +namespace pia +{ + void reset(); + void tick(); +} diff --git a/speaker.h b/speaker.h new file mode 100644 index 0000000..973e8ee --- /dev/null +++ b/speaker.h @@ -0,0 +1,12 @@ +#pragma once +#include + +namespace speaker +{ + void init(); + void quit(); + void enable(); + void disable(); + void register_source(uint8_t(*callback)()); + void update(const uint32_t dt); +} diff --git a/tia.h b/tia.h new file mode 100644 index 0000000..b98b1a0 --- /dev/null +++ b/tia.h @@ -0,0 +1,7 @@ +#pragma once + +namespace tia +{ + void reset(); + void tick(); +}