diff --git a/Machines/AppleII/AppleII.cpp b/Machines/AppleII/AppleII.cpp index bce8d2171..778dcd38c 100644 --- a/Machines/AppleII/AppleII.cpp +++ b/Machines/AppleII/AppleII.cpp @@ -63,7 +63,7 @@ template class ConcreteMachine: uint8_t *ram_, *aux_ram_; }; - CPU::MOS6502::Processor m6502_; + CPU::MOS6502::Processor<(model == Analyser::Static::AppleII::Target::Model::EnhancedIIe) ? CPU::MOS6502::Personality::PSynertek65C02 : CPU::MOS6502::Personality::P6502, ConcreteMachine, false> m6502_; VideoBusHandler video_bus_handler_; std::unique_ptr> video_; int cycles_into_current_line_ = 0; @@ -301,7 +301,7 @@ template class ConcreteMachine: public: ConcreteMachine(const Analyser::Static::AppleII::Target &target, const ROMMachine::ROMFetcher &rom_fetcher): - m6502_((model == Analyser::Static::AppleII::Target::Model::EnhancedIIe) ? CPU::MOS6502::Personality::P65C02 : CPU::MOS6502::Personality::P6502, *this), + m6502_(*this), video_bus_handler_(ram_, aux_ram_), audio_toggle_(audio_queue_), speaker_(audio_toggle_) { diff --git a/Machines/Atari2600/Cartridges/Cartridge.hpp b/Machines/Atari2600/Cartridges/Cartridge.hpp index f5e7987d9..4276bdc7b 100644 --- a/Machines/Atari2600/Cartridges/Cartridge.hpp +++ b/Machines/Atari2600/Cartridges/Cartridge.hpp @@ -32,7 +32,7 @@ template class Cartridge: public: Cartridge(const std::vector &rom) : - m6502_(CPU::MOS6502::Personality::P6502, *this), + m6502_(*this), rom_(rom), bus_extender_(rom_.data(), rom.size()) { // The above works because bus_extender_ is declared after rom_ in the instance storage list; @@ -204,7 +204,7 @@ template class Cartridge: } protected: - CPU::MOS6502::Processor, true> m6502_; + CPU::MOS6502::Processor, true> m6502_; std::vector rom_; private: diff --git a/Machines/Commodore/1540/Implementation/C1540.cpp b/Machines/Commodore/1540/Implementation/C1540.cpp index b6cf3416e..be61e8cb8 100644 --- a/Machines/Commodore/1540/Implementation/C1540.cpp +++ b/Machines/Commodore/1540/Implementation/C1540.cpp @@ -18,7 +18,7 @@ using namespace Commodore::C1540; MachineBase::MachineBase(Personality personality, const ROMMachine::ROMFetcher &rom_fetcher) : Storage::Disk::Controller(1000000), - m6502_(CPU::MOS6502::Personality::P6502, *this), + m6502_(*this), drive_(new Storage::Disk::Drive(1000000, 300, 2)), serial_port_VIA_port_handler_(new SerialPortVIA(serial_port_VIA_)), serial_port_(new SerialPort), diff --git a/Machines/Commodore/1540/Implementation/C1540Base.hpp b/Machines/Commodore/1540/Implementation/C1540Base.hpp index 25e938371..2c4458999 100644 --- a/Machines/Commodore/1540/Implementation/C1540Base.hpp +++ b/Machines/Commodore/1540/Implementation/C1540Base.hpp @@ -143,7 +143,7 @@ class MachineBase: void set_activity_observer(Activity::Observer *observer); protected: - CPU::MOS6502::Processor m6502_; + CPU::MOS6502::Processor m6502_; std::shared_ptr drive_; uint8_t ram_[0x800]; diff --git a/Machines/Commodore/Vic-20/Vic20.cpp b/Machines/Commodore/Vic-20/Vic20.cpp index 027fec716..8268d063a 100644 --- a/Machines/Commodore/Vic-20/Vic20.cpp +++ b/Machines/Commodore/Vic-20/Vic20.cpp @@ -293,7 +293,7 @@ class ConcreteMachine: public Activity::Source { public: ConcreteMachine(const Analyser::Static::Commodore::Target &target, const ROMMachine::ROMFetcher &rom_fetcher) : - m6502_(CPU::MOS6502::Personality::P6502, *this), + m6502_(*this), user_port_via_port_handler_(new UserPortVIA), keyboard_via_port_handler_(new KeyboardVIA), serial_port_(new SerialPort), @@ -703,7 +703,7 @@ class ConcreteMachine: void update_video() { mos6560_->run_for(cycles_since_mos6560_update_.flush()); } - CPU::MOS6502::Processor m6502_; + CPU::MOS6502::Processor m6502_; std::vector character_rom_; std::vector basic_rom_; diff --git a/Machines/Electron/Electron.cpp b/Machines/Electron/Electron.cpp index 4cb17c68e..295d85248 100644 --- a/Machines/Electron/Electron.cpp +++ b/Machines/Electron/Electron.cpp @@ -50,7 +50,7 @@ class ConcreteMachine: public Activity::Source { public: ConcreteMachine(const Analyser::Static::Acorn::Target &target, const ROMMachine::ROMFetcher &rom_fetcher) : - m6502_(CPU::MOS6502::Personality::P6502, *this), + m6502_(*this), sound_generator_(audio_queue_), speaker_(sound_generator_) { memset(key_states_, 0, sizeof(key_states_)); @@ -541,7 +541,7 @@ class ConcreteMachine: m6502_.set_irq_line(interrupt_status_ & 1); } - CPU::MOS6502::Processor m6502_; + CPU::MOS6502::Processor m6502_; // Things that directly constitute the memory map. uint8_t roms_[16][16384]; diff --git a/Machines/Oric/Oric.cpp b/Machines/Oric/Oric.cpp index 62ee0afbe..2d2d7e040 100644 --- a/Machines/Oric/Oric.cpp +++ b/Machines/Oric/Oric.cpp @@ -207,7 +207,7 @@ template class Co public: ConcreteMachine(const Analyser::Static::Oric::Target &target, const ROMMachine::ROMFetcher &rom_fetcher) : - m6502_(CPU::MOS6502::Personality::P6502, *this), + m6502_(*this), ay8910_(audio_queue_), speaker_(ay8910_), via_port_handler_(audio_queue_, ay8910_, speaker_, tape_player_, keyboard_), @@ -575,7 +575,7 @@ template class Co const uint16_t basic_invisible_ram_top_ = 0xffff; const uint16_t basic_visible_ram_top_ = 0xbfff; - CPU::MOS6502::Processor m6502_; + CPU::MOS6502::Processor m6502_; // RAM and ROM std::vector rom_, microdisc_rom_, colour_rom_; diff --git a/Processors/6502/6502.hpp b/Processors/6502/6502.hpp index 00fb75429..ab27ceff8 100644 --- a/Processors/6502/6502.hpp +++ b/Processors/6502/6502.hpp @@ -37,11 +37,18 @@ enum Register { The list of 6502 variants supported by this implementation. */ enum Personality { - P6502, // the original 6502, replete with various undocumented instructions - P65C02, // the 65C02; an extended 6502 with a few extra instructions and addressing modes for existing instructions - P65SC02, // like the 65C02, but lacking bit instructions + P6502, // the original [NMOS] 6502, replete with various undocumented instructions + PNES6502, // the NES's 6502, which is like a 6502 but lacks decimal mode (though it retains the decimal flag) + PSynertek65C02, // a 6502 extended with BRA, P[H/L][X/Y], STZ, TRB, TSB and the (zp) addressing mode and a few other additions + PWDC65C02, // like the Synertek, but with BBR, BBS, RMB and SMB + PRockwell65C02, // like the WDC, but with STP and WAI }; +#define is_65c02(p) ((p) >= Personality::PSynertek65C02) +#define has_bbrbbsrmbsmb(p) ((p) >= Personality::PWDC65C02) +#define has_stpwai(p) ((p) >= Personality::PRockwell65C02) +#define has_decimal_mode(p) ((p) != Personality::PNES6502) + /* Flags as defined on the 6502; can be used to decode the result of @c get_value_of_register(Flags) or to form a value for the corresponding set. @@ -199,12 +206,12 @@ class ProcessorBase: public ProcessorStorage { can also nominate whether the processor includes support for the ready line. Declining to support the ready line can produce a minor runtime performance improvement. */ -template class Processor: public ProcessorBase { +template class Processor: public ProcessorBase { public: /*! Constructs an instance of the 6502 that will use @c bus_handler for all bus communications. */ - Processor(Personality personality, T &bus_handler) : ProcessorBase(personality), personality_(personality), bus_handler_(bus_handler) {} + Processor(T &bus_handler) : ProcessorBase(personality), bus_handler_(bus_handler) {} /*! Runs the 6502 for a supplied number of cycles. @@ -221,7 +228,6 @@ template class Processor: public ProcessorBas void set_ready_line(bool active); private: - Personality personality_; T &bus_handler_; }; diff --git a/Processors/6502/Implementation/6502Implementation.hpp b/Processors/6502/Implementation/6502Implementation.hpp index 401b26e12..3c6478289 100644 --- a/Processors/6502/Implementation/6502Implementation.hpp +++ b/Processors/6502/Implementation/6502Implementation.hpp @@ -12,7 +12,7 @@ 6502.hpp, but it's implementation stuff. */ -template void Processor::run_for(const Cycles cycles) { +template void Processor::run_for(const Cycles cycles) { static const MicroOp do_branch[] = { CycleReadFromPC, CycleAddSignedOperandToPC, @@ -98,7 +98,7 @@ if(number_of_cycles <= Cycles(0)) break; // governs everything else on the 6502: that two bytes will always // be fetched. if( - personality_ == P6502 || + is_65c02(personality) || (operation_&7) != 3 || operation_ == 0xcb || operation_ == 0xdb @@ -150,7 +150,7 @@ if(number_of_cycles <= Cycles(0)) break; case CycleReadVectorHigh: read_mem(pc_.bytes.high, nextAddress.full+1); break; case OperationSetI: inverse_interrupt_flag_ = 0; - if(personality_ != P6502) decimal_flag_ = false; + if(is_65c02(personality)) decimal_flag_ = false; continue; case CyclePullPCL: s_++; read_mem(pc_.bytes.low, s_ | 0x100); break; @@ -264,7 +264,7 @@ if(number_of_cycles <= Cycles(0)) break; case OperationINS: operand_++; // deliberate fallthrough case OperationSBC: - if(decimal_flag_) { + if(decimal_flag_ && has_decimal_mode(personality)) { const uint16_t notCarry = carry_flag_ ^ 0x1; const uint16_t decimalResult = static_cast(a_) - static_cast(operand_) - notCarry; uint16_t temp16; @@ -283,7 +283,7 @@ if(number_of_cycles <= Cycles(0)) break; carry_flag_ = (temp16 > 0xff) ? 0 : Flag::Carry; a_ = static_cast(temp16); - if(personality_ != P6502) { + if(is_65c02(personality)) { negative_result_ = zero_result_ = a_; read_mem(operand_, address_.full); break; @@ -295,7 +295,7 @@ if(number_of_cycles <= Cycles(0)) break; // deliberate fallthrough case OperationADC: - if(decimal_flag_) { + if(decimal_flag_ && has_decimal_mode(personality)) { const uint16_t decimalResult = static_cast(a_) + static_cast(operand_) + static_cast(carry_flag_); uint8_t low_nibble = (a_ & 0xf) + (operand_ & 0xf) + carry_flag_; @@ -309,7 +309,7 @@ if(number_of_cycles <= Cycles(0)) break; a_ = static_cast(result); zero_result_ = static_cast(decimalResult); - if(personality_ != P6502) { + if(is_65c02(personality)) { negative_result_ = zero_result_ = a_; read_mem(operand_, address_.full); break; @@ -611,7 +611,7 @@ if(number_of_cycles <= Cycles(0)) break; continue; } - if(uses_ready_line && ready_line_is_enabled_ && isReadOperation(nextBusOperation)) { + if(uses_ready_line && ready_line_is_enabled_ && (is_65c02(personality) || isReadOperation(nextBusOperation))) { ready_is_active_ = true; break; } @@ -629,7 +629,7 @@ if(number_of_cycles <= Cycles(0)) break; bus_handler_.flush(); } -template void Processor::set_ready_line(bool active) { +template void Processor::set_ready_line(bool active) { assert(uses_ready_line); if(active) { ready_line_is_enabled_ = true; diff --git a/Processors/6502/Implementation/6502Storage.cpp b/Processors/6502/Implementation/6502Storage.cpp index d8fae7c4f..da0a9285a 100644 --- a/Processors/6502/Implementation/6502Storage.cpp +++ b/Processors/6502/Implementation/6502Storage.cpp @@ -29,7 +29,7 @@ using namespace CPU::MOS6502; #define Read(...) CycleFetchOperandFromAddress, __VA_ARGS__ #define Write(...) __VA_ARGS__, CycleWriteOperandToAddress -#define ReadModifyWrite(...) CycleFetchOperandFromAddress, (personality == P6502) ? CycleWriteOperandToAddress : CycleFetchOperandFromAddress, __VA_ARGS__, CycleWriteOperandToAddress +#define ReadModifyWrite(...) CycleFetchOperandFromAddress, is_65c02(personality) ? CycleFetchOperandFromAddress : CycleWriteOperandToAddress, __VA_ARGS__, CycleWriteOperandToAddress #define AbsoluteRead(op) Program(Absolute, Read(op)) #define AbsoluteXRead(op) Program(AbsoluteXr, Read(op)) @@ -225,7 +225,7 @@ ProcessorStorage::ProcessorStorage(Personality personality) { const InstructionList code = instructions; \ memcpy(&operations_[location], code, sizeof(InstructionList)); \ } - if(personality != P6502) { + if(is_65c02(personality)) { // Add P[L/H][X/Y]. Install(0x5a, Program(CyclePushY)); Install(0xda, Program(CyclePushX)); @@ -235,17 +235,6 @@ ProcessorStorage::ProcessorStorage(Personality personality) { // Add BRA. Install(0x80, Program(OperationBRA)); - // Add BBS and BBR. These take five cycles. My guessed breakdown is: - // 1. read opcode - // 2. read operand - // 3. read zero page - // 4. read second operand - // 5. read from PC without top byte fixed yet - // ... with the caveat that (3) and (4) could be the other way around. - for(int location = 0x0f; location <= 0xff; location += 0x10) { - Install(location, Program(OperationLoadAddressZeroPage, CycleFetchOperandFromAddress, OperationBBRBBS)); - } - // Add NOPs. // The 1-byte, 1-cycle (!) NOPs. @@ -304,12 +293,33 @@ ProcessorStorage::ProcessorStorage(Personality personality) { Install(0x14, ZeroReadModifyWrite(OperationTRB)); Install(0x1c, AbsoluteReadModifyWrite(OperationTRB)); - // Add RMB and SMB. - for(int c = 0x07; c <= 0x77; c += 0x10) { - Install(c, ZeroReadModifyWrite(OperationRMB)); + if(has_bbrbbsrmbsmb(personality)) { + // Add BBS and BBR. These take five cycles. My guessed breakdown is: + // 1. read opcode + // 2. read operand + // 3. read zero page + // 4. read second operand + // 5. read from PC without top byte fixed yet + // ... with the caveat that (3) and (4) could be the other way around. + for(int location = 0x0f; location <= 0xff; location += 0x10) { + Install(location, Program(OperationLoadAddressZeroPage, CycleFetchOperandFromAddress, OperationBBRBBS)); + } + + // Add RMB and SMB. + for(int c = 0x07; c <= 0x77; c += 0x10) { + Install(c, ZeroReadModifyWrite(OperationRMB)); + } + for(int c = 0x87; c <= 0xf7; c += 0x10) { + Install(c, ZeroReadModifyWrite(OperationSMB)); + } + } else { + // TODO } - for(int c = 0x87; c <= 0xf7; c += 0x10) { - Install(c, ZeroReadModifyWrite(OperationSMB)); + + if(has_stpwai(personality)) { + + } else { + // TODO } } #undef Install