diff --git a/Machines/Atari2600/Atari2600.cpp b/Machines/Atari2600/Atari2600.cpp index 97a907762..bf189ee2b 100644 --- a/Machines/Atari2600/Atari2600.cpp +++ b/Machines/Atari2600/Atari2600.cpp @@ -211,6 +211,15 @@ unsigned int Machine::perform_bus_operation(CPU6502::BusOperation operation, uin case 0x18: update_audio(); speaker_->set_divider(decodedAddress - 0x17, *value); break; case 0x19: case 0x1a: update_audio(); speaker_->set_volume(decodedAddress - 0x19, *value); break; + + case 0x3f: + if(paging_model_ == StaticAnalyser::Atari2600PagingModel::Tigervision && (masked_address == 0x3f)) + { + int selected_page = (*value) % (rom_size_ / 2048); + rom_pages_[0] = &rom_[selected_page * 2048]; + rom_pages_[1] = rom_pages_[0] + 1024; + } + break; } } } diff --git a/OSBindings/Mac/Clock Signal.xcodeproj/xcshareddata/xcschemes/Clock Signal.xcscheme b/OSBindings/Mac/Clock Signal.xcodeproj/xcshareddata/xcschemes/Clock Signal.xcscheme index 6cceb313b..fc79e9f59 100644 --- a/OSBindings/Mac/Clock Signal.xcodeproj/xcshareddata/xcschemes/Clock Signal.xcscheme +++ b/OSBindings/Mac/Clock Signal.xcodeproj/xcshareddata/xcschemes/Clock Signal.xcscheme @@ -26,7 +26,8 @@ buildConfiguration = "Debug" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" - shouldUseLaunchSchemeArgsEnv = "YES"> + shouldUseLaunchSchemeArgsEnv = "YES" + codeCoverageEnabled = "YES"> diff --git a/OSBindings/Mac/Clock Signal/Audio/CSAudioQueue.m b/OSBindings/Mac/Clock Signal/Audio/CSAudioQueue.m index 83280ad8b..4f740aaba 100644 --- a/OSBindings/Mac/Clock Signal/Audio/CSAudioQueue.m +++ b/OSBindings/Mac/Clock Signal/Audio/CSAudioQueue.m @@ -23,10 +23,11 @@ static NSLock *CSAudioQueueDeallocLock; #pragma mark - AudioQueue callbacks -- (void)audioQueue:(AudioQueueRef)theAudioQueue didCallbackWithBuffer:(AudioQueueBufferRef)buffer +/*! + @returns @c YES if the queue is running dry; @c NO otherwise. +*/ +- (BOOL)audioQueue:(AudioQueueRef)theAudioQueue didCallbackWithBuffer:(AudioQueueBufferRef)buffer { - [self.delegate audioQueueIsRunningDry:self]; - [_storedBuffersLock lock]; for(int c = 0; c < NumberOfStoredAudioQueueBuffer; c++) { @@ -35,11 +36,12 @@ static NSLock *CSAudioQueueDeallocLock; if(_storedBuffers[c]) AudioQueueFreeBuffer(_audioQueue, _storedBuffers[c]); _storedBuffers[c] = buffer; [_storedBuffersLock unlock]; - return; + return YES; } } [_storedBuffersLock unlock]; AudioQueueFreeBuffer(_audioQueue, buffer); + return YES; } static void audioOutputCallback( @@ -47,10 +49,16 @@ static void audioOutputCallback( AudioQueueRef inAQ, AudioQueueBufferRef inBuffer) { + // Pull the delegate call for audio queue running dry outside of the locked region, to allow non-deadlocking + // lifecycle -dealloc events to result from it. if([CSAudioQueueDeallocLock tryLock]) { - [(__bridge CSAudioQueue *)inUserData audioQueue:inAQ didCallbackWithBuffer:inBuffer]; + CSAudioQueue *queue = (__bridge CSAudioQueue *)inUserData; + BOOL isRunningDry = NO; + isRunningDry = [queue audioQueue:inAQ didCallbackWithBuffer:inBuffer]; + id delegate = queue.delegate; [CSAudioQueueDeallocLock unlock]; + if(isRunningDry) [delegate audioQueueIsRunningDry:queue]; } } diff --git a/StaticAnalyser/Atari/StaticAnalyser.cpp b/StaticAnalyser/Atari/StaticAnalyser.cpp index e48be34ed..ec477ec9e 100644 --- a/StaticAnalyser/Atari/StaticAnalyser.cpp +++ b/StaticAnalyser/Atari/StaticAnalyser.cpp @@ -93,11 +93,13 @@ static void DeterminePagingFor2kCartridge(StaticAnalyser::Target &target, const static void DeterminePagingFor8kCartridge(StaticAnalyser::Target &target, const Storage::Cartridge::Cartridge::Segment &segment, const std::vector &disassemblies) { std::set internal_accesses; + std::set external_stores; for(const StaticAnalyser::MOS6502::Disassembly &disassembly : disassemblies) { internal_accesses.insert(disassembly.internal_stores.begin(), disassembly.internal_stores.end()); internal_accesses.insert(disassembly.internal_modifies.begin(), disassembly.internal_modifies.end()); internal_accesses.insert(disassembly.internal_loads.begin(), disassembly.internal_loads.end()); + external_stores.insert(disassembly.external_stores.begin(), disassembly.external_stores.end()); } bool looks_like_atari = false; @@ -132,11 +134,13 @@ static void DeterminePagingForCartridge(StaticAnalyser::Target &target, const St std::vector disassemblies; std::set internal_stores; + std::set external_stores; for(std::vector::difference_type base = 0; base < segment.data.size(); base += 4096) { std::vector sub_data(segment.data.begin() + base, segment.data.begin() + base + 4096); disassemblies.push_back(StaticAnalyser::MOS6502::Disassemble(sub_data, address_mapper, {entry_address, break_address})); internal_stores.insert(disassemblies.back().internal_stores.begin(), disassemblies.back().internal_stores.end()); + external_stores.insert(disassemblies.back().external_stores.begin(), disassemblies.back().external_stores.end()); } if(segment.data.size() == 8192) @@ -159,18 +163,13 @@ static void DeterminePagingForCartridge(StaticAnalyser::Target &target, const St } target.atari.uses_superchip = has_superchip; if(is_ram_plus) target.atari.paging_model = StaticAnalyser::Atari2600PagingModel::CBSRamPlus; -// if(internal_stores.size() > 4) -// { -// bool writes_above_128 = false; -// for(uint16_t address : internal_stores) -// { -// writes_above_128 |= ((address & 0x1fff) > 0x10ff) && ((address & 0x1fff) < 0x1200); -// } -// if(writes_above_128) -// target.atari.paging_model = StaticAnalyser::Atari2600PagingModel::CBSRamPlus; -// else -// target.atari.uses_superchip = true; -// } + + // check for a Tigervision or Tigervision-esque scheme + if(target.atari.paging_model == StaticAnalyser::Atari2600PagingModel::None) + { + bool looks_like_tigervision = external_stores.find(0x3f) != external_stores.end(); + if(looks_like_tigervision) target.atari.paging_model = StaticAnalyser::Atari2600PagingModel::Tigervision; + } } void StaticAnalyser::Atari::AddTargets(