diff --git a/Components/6532/6532.hpp b/Components/6532/6532.hpp index 69f85b996..b9b72ff7e 100644 --- a/Components/6532/6532.hpp +++ b/Components/6532/6532.hpp @@ -131,7 +131,7 @@ template class MOS6532 { port_{{.output_mask = 0, .output = 0}, {.output_mask = 0, .output = 0}}, a7_interrupt_({.last_port_value = 0, .enabled = false}), interrupt_line_(false), - timer_{.value = 0, .activeShift = 0, .writtenShift = 0, .interrupt_enabled = false} + timer_{.value = 16320, .activeShift = 6, .writtenShift = 6, .interrupt_enabled = false} {} inline void set_port_did_change(int port) diff --git a/Machines/Atari2600/Atari2600.cpp b/Machines/Atari2600/Atari2600.cpp index 3353c7290..8abeb1d67 100644 --- a/Machines/Atari2600/Atari2600.cpp +++ b/Machines/Atari2600/Atari2600.cpp @@ -19,6 +19,7 @@ #include "Cartridges/CartridgeMegaBoy.hpp" #include "Cartridges/CartridgeMNetwork.hpp" #include "Cartridges/CartridgeParkerBros.hpp" +#include "Cartridges/CartridgePitfall2.hpp" #include "Cartridges/CartridgeTigervision.hpp" #include "Cartridges/CartridgeUnpaged.hpp" @@ -82,14 +83,16 @@ void Machine::set_switch_is_enabled(Atari2600Switch input, bool state) { void Machine::configure_as_target(const StaticAnalyser::Target &target) { const std::vector &rom = target.cartridges.front()->get_segments().front().data; switch(target.atari.paging_model) { - case StaticAnalyser::Atari2600PagingModel::None: bus_.reset(new CartridgeUnpaged(rom)); break; - case StaticAnalyser::Atari2600PagingModel::CommaVid: bus_.reset(new CartridgeCommaVid(rom)); break; case StaticAnalyser::Atari2600PagingModel::ActivisionStack: bus_.reset(new CartridgeActivisionStack(rom)); break; - case StaticAnalyser::Atari2600PagingModel::ParkerBros: bus_.reset(new CartridgeParkerBros(rom)); break; - case StaticAnalyser::Atari2600PagingModel::Tigervision: bus_.reset(new CartridgeTigervision(rom)); break; case StaticAnalyser::Atari2600PagingModel::CBSRamPlus: bus_.reset(new CartridgeCBSRAMPlus(rom)); break; + case StaticAnalyser::Atari2600PagingModel::CommaVid: bus_.reset(new CartridgeCommaVid(rom)); break; case StaticAnalyser::Atari2600PagingModel::MegaBoy: bus_.reset(new CartridgeMegaBoy(rom)); break; case StaticAnalyser::Atari2600PagingModel::MNetwork: bus_.reset(new CartridgeMNetwork(rom)); break; + case StaticAnalyser::Atari2600PagingModel::None: bus_.reset(new CartridgeUnpaged(rom)); break; + case StaticAnalyser::Atari2600PagingModel::ParkerBros: bus_.reset(new CartridgeParkerBros(rom)); break; + case StaticAnalyser::Atari2600PagingModel::Pitfall2: bus_.reset(new CartridgePitfall2(rom)); break; + case StaticAnalyser::Atari2600PagingModel::Tigervision: bus_.reset(new CartridgeTigervision(rom)); break; + case StaticAnalyser::Atari2600PagingModel::Atari8k: if(target.atari.uses_superchip) { bus_.reset(new CartridgeAtari8kSuperChip(rom)); diff --git a/Machines/Atari2600/Cartridges/Cartridge.hpp b/Machines/Atari2600/Cartridges/Cartridge.hpp index 8581270fe..37dbb30a7 100644 --- a/Machines/Atari2600/Cartridges/Cartridge.hpp +++ b/Machines/Atari2600/Cartridges/Cartridge.hpp @@ -24,6 +24,7 @@ template class Cartridge: void run_for_cycles(int number_of_cycles) { CPU6502::Processor>::run_for_cycles(number_of_cycles); } void set_reset_line(bool state) { CPU6502::Processor>::set_reset_line(state); } + void advance_cycles(unsigned int cycles) {} // to satisfy CPU6502::Processor unsigned int perform_bus_operation(CPU6502::BusOperation operation, uint16_t address, uint8_t *value) { @@ -40,6 +41,7 @@ template class Cartridge: cycles_since_speaker_update_ += cycles_run_for; cycles_since_video_update_ += cycles_run_for; cycles_since_6532_update_ += (cycles_run_for / 3); + static_cast(this)->advance_cycles(cycles_run_for / 3); if(operation != CPU6502::BusOperation::Ready) { // give the cartridge a chance to respond to the bus access diff --git a/Machines/Atari2600/Cartridges/CartridgePitfall2.hpp b/Machines/Atari2600/Cartridges/CartridgePitfall2.hpp new file mode 100644 index 000000000..5592f175b --- /dev/null +++ b/Machines/Atari2600/Cartridges/CartridgePitfall2.hpp @@ -0,0 +1,134 @@ +// +// CartridgePitfall2.h +// Clock Signal +// +// Created by Thomas Harte on 18/03/2017. +// Copyright © 2017 Thomas Harte. All rights reserved. +// + +#ifndef Atari2600_CartridgePitfall2_hpp +#define Atari2600_CartridgePitfall2_hpp + +namespace Atari2600 { + +class CartridgePitfall2: public Cartridge { + public: + CartridgePitfall2(const std::vector &rom) : + Cartridge(rom), + random_number_generator_(0), + featcher_address_{0, 0, 0, 0, 0, 0, 0, 0}, + mask_{0, 0, 0, 0, 0, 0, 0, 0}, + cycles_since_audio_update_(0) { + rom_ptr_ = rom_.data(); + } + + void advance_cycles(unsigned int cycles) { + cycles_since_audio_update_ += cycles; + } + + void perform_bus_operation(CPU6502::BusOperation operation, uint16_t address, uint8_t *value) { + address &= 0x1fff; + if(!(address & 0x1000)) return; + + switch(address) { + +#pragma mark - Reads + + // The random number generator + case 0x1000: case 0x1001: case 0x1002: case 0x1003: case 0x1004: + if(isReadOperation(operation)) { + *value = random_number_generator_; + } + random_number_generator_ = (uint8_t)( + (random_number_generator_ << 1) | + (~( (random_number_generator_ >> 7) ^ + (random_number_generator_ >> 5) ^ + (random_number_generator_ >> 4) ^ + (random_number_generator_ >> 3) + ) & 1)); + break; + + case 0x1005: case 0x1006: case 0x1007: + *value = update_audio(); + break; + + case 0x1008: case 0x1009: case 0x100a: case 0x100b: case 0x100c: case 0x100d: case 0x100e: case 0x100f: + *value = rom_[8192 + address_for_counter(address & 7)]; + break; + + case 0x1010: case 0x1011: case 0x1012: case 0x1013: case 0x1014: case 0x1015: case 0x1016: case 0x1017: + *value = rom_[8192 + address_for_counter(address & 7)] & mask_[address & 7]; + break; + +#pragma mark - Writes + + case 0x1040: case 0x1041: case 0x1042: case 0x1043: case 0x1044: case 0x1045: case 0x1046: case 0x1047: + top_[address & 7] = *value; + break; + case 0x1048: case 0x1049: case 0x104a: case 0x104b: case 0x104c: case 0x104d: case 0x104e: case 0x104f: + bottom_[address & 7] = *value; + break; + case 0x1050: case 0x1051: case 0x1052: case 0x1053: case 0x1054: case 0x1055: case 0x1056: case 0x1057: + featcher_address_[address & 7] = (featcher_address_[address & 7] & 0xff00) | *value; + mask_[address & 7] = 0x00; + break; + case 0x1058: case 0x1059: case 0x105a: case 0x105b: case 0x105c: case 0x105d: case 0x105e: case 0x105f: + featcher_address_[address & 7] = (featcher_address_[address & 7] & 0x00ff) | (uint16_t)(*value << 8); + break; + case 0x1070: case 0x1071: case 0x1072: case 0x1073: case 0x1074: case 0x1075: case 0x1076: case 0x1077: + random_number_generator_ = 0; + break; + +#pragma mark - Paging + + case 0x1ff8: rom_ptr_ = rom_.data(); break; + case 0x1ff9: rom_ptr_ = rom_.data() + 4096; break; + +#pragma mark - Business as usual + + default: + if(isReadOperation(operation)) { + *value = rom_ptr_[address & 4095]; + } + break; + } + } + + private: + inline uint16_t address_for_counter(int counter) { + uint16_t fetch_address = (featcher_address_[counter] & 2047) ^ 2047; + if((featcher_address_[counter] & 0xff) == top_[counter]) mask_[counter] = 0xff; + if((featcher_address_[counter] & 0xff) == bottom_[counter]) mask_[counter] = 0x00; + featcher_address_[counter]--; + return fetch_address; + } + + inline uint8_t update_audio() { + const unsigned int clock_divisor = 57; + unsigned int cycles_to_run_for = cycles_since_audio_update_ / clock_divisor; + cycles_since_audio_update_ %= clock_divisor; + + int table_position = 0; + for(int c = 0; c < 3; c++) { + audio_channel_[c] = (audio_channel_[c] + cycles_to_run_for) % (1 + top_[5 + c]); + if((featcher_address_[5 + c] & 0x1000) && ((top_[5 + c] - audio_channel_[c]) > bottom_[5 + c])) { + table_position |= 0x4 >> c; + } + } + + static uint8_t level_table[8] = { 0x0, 0x4, 0x5, 0x9, 0x6, 0xa, 0xb, 0xf }; + return level_table[table_position]; + } + + uint16_t featcher_address_[8]; + uint8_t top_[8], bottom_[8], mask_[8]; + uint8_t music_mode_[3]; + uint8_t random_number_generator_; + uint8_t *rom_ptr_; + uint8_t audio_channel_[3]; + unsigned int cycles_since_audio_update_; +}; + +} + +#endif /* Atari2600_CartridgePitfall2_hpp */ diff --git a/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj b/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj index 3915a3812..b9f53cea6 100644 --- a/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj +++ b/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj @@ -953,6 +953,7 @@ 4BEAC08B1E7E0DF800EE56B2 /* CartridgeTigervision.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = CartridgeTigervision.hpp; sourceTree = ""; }; 4BEAC08C1E7E0DF800EE56B2 /* CartridgeUnpaged.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = CartridgeUnpaged.hpp; sourceTree = ""; }; 4BEAC08D1E7E0E1A00EE56B2 /* Bus.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = Bus.hpp; sourceTree = ""; }; + 4BEAC08E1E7E110500EE56B2 /* CartridgePitfall2.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = CartridgePitfall2.hpp; sourceTree = ""; }; 4BEE0A6A1D72496600532C7B /* Cartridge.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Cartridge.cpp; sourceTree = ""; }; 4BEE0A6B1D72496600532C7B /* Cartridge.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = Cartridge.hpp; sourceTree = ""; }; 4BEE0A6D1D72496600532C7B /* PRG.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PRG.cpp; sourceTree = ""; }; @@ -1971,6 +1972,7 @@ 4BEAC08A1E7E0DF800EE56B2 /* CartridgeParkerBros.hpp */, 4BEAC08B1E7E0DF800EE56B2 /* CartridgeTigervision.hpp */, 4BEAC08C1E7E0DF800EE56B2 /* CartridgeUnpaged.hpp */, + 4BEAC08E1E7E110500EE56B2 /* CartridgePitfall2.hpp */, ); path = Cartridges; sourceTree = "";