diff --git a/Machines/Sinclair/ZXSpectrum/State.hpp b/Machines/Sinclair/ZXSpectrum/State.hpp index 1333c8d62..ae9632ecd 100644 --- a/Machines/Sinclair/ZXSpectrum/State.hpp +++ b/Machines/Sinclair/ZXSpectrum/State.hpp @@ -20,13 +20,27 @@ namespace ZXSpectrum { struct State: public Reflection::StructImpl { CPU::Z80::State z80; Video::State video; + + // In 16kb or 48kb mode, RAM will be 16kb or 48kb and represent + // memory in standard linear order. In 128kb mode, RAM will be + // 128kb with the first 16kb representing bank 0, the next bank 1, etc. std::vector ram; + // Meaningful for 128kb machines only. + uint8_t last_7ffd = 0; + uint8_t last_fffd = 0; + + // Meaningful for the +2a and +3 only. + uint8_t last_1ffd = 0; + State() { if(needs_declare()) { DeclareField(z80); DeclareField(video); DeclareField(ram); + DeclareField(last_7ffd); + DeclareField(last_fffd); + DeclareField(last_1ffd); } } }; diff --git a/Machines/Sinclair/ZXSpectrum/ZXSpectrum.cpp b/Machines/Sinclair/ZXSpectrum/ZXSpectrum.cpp index bde983d91..2632f5295 100644 --- a/Machines/Sinclair/ZXSpectrum/ZXSpectrum.cpp +++ b/Machines/Sinclair/ZXSpectrum/ZXSpectrum.cpp @@ -138,6 +138,12 @@ template class ConcreteMachine: } } else { memcpy(ram_.data(), state->ram.data(), std::min(ram_.size(), state->ram.size())); + + port1ffd_ = state->last_1ffd; + port7ffd_ = state->last_7ffd; + update_memory_map(); + + GI::AY38910::Utility::select_register(ay_, state->last_fffd); } } } @@ -400,10 +406,6 @@ template class ConcreteMachine: // Set the proper video base pointer. set_video_address(); - - // Potentially lock paging, _after_ the current - // port values have taken effect. - disable_paging_ |= *cycle.value & 0x20; } // Test for +2a/+3 paging (i.e. port 1ffd). @@ -729,6 +731,10 @@ template class ConcreteMachine: set_memory(2, 2); set_memory(3, port7ffd_ & 7); } + + // Potentially lock paging, _after_ the current + // port values have taken effect. + disable_paging_ = port7ffd_ & 0x20; } void set_memory(int bank, uint8_t source) { diff --git a/Storage/State/Z80.cpp b/Storage/State/Z80.cpp index d676b6248..9cf63eeee 100644 --- a/Storage/State/Z80.cpp +++ b/Storage/State/Z80.cpp @@ -28,20 +28,25 @@ std::vector read_memory(Storage::FileHolder &file, size_t size, bool is while(cursor != size) { const uint8_t next = file.get8(); - if(next != 0xed) { + // If the next byte definitely doesn't, or can't, + // start an ED ED sequence then just take it. + if(next != 0xed || cursor == size - 1) { result[cursor] = next; ++cursor; continue; } + // Grab the next byte. If it's not ED then write + // both and continue. const uint8_t after = file.get8(); if(after != 0xed) { result[cursor] = next; - ++cursor; - file.seek(-1, SEEK_CUR); + result[cursor+1] = after; + cursor += 2; continue; } + // An ED ED has begun, so grab the RLE sequence. const uint8_t count = file.get8(); const uint8_t value = file.get8(); @@ -112,7 +117,8 @@ std::unique_ptr Z80::load(const std::string &file_name } state->z80.registers.program_counter = file.get16le(); - switch(file.get8()) { + const uint8_t model = file.get8(); + switch(model) { default: return nullptr; case 0: result->model = Target::Model::FortyEightK; break; case 3: result->model = Target::Model::OneTwoEightK; break; @@ -122,7 +128,7 @@ std::unique_ptr Z80::load(const std::string &file_name case 13: result->model = Target::Model::Plus2a; break; } - const uint8_t last7ffd = file.get8(); (void)last7ffd; // TODO + state->last_7ffd = file.get8(); file.seek(1, SEEK_CUR); if(file.get8() & 0x80) { @@ -135,7 +141,7 @@ std::unique_ptr Z80::load(const std::string &file_name } } - const uint8_t lastfffd = file.get8(); (void)lastfffd; // TODO + state->last_fffd = file.get8(); file.seek(16, SEEK_CUR); // Sound chip registers: TODO. if(bonus_header_size != 23) { @@ -165,7 +171,7 @@ std::unique_ptr Z80::load(const std::string &file_name file.seek(3, SEEK_CUR); if(bonus_header_size == 55) { - const uint8_t last1ffd = file.get8(); (void)last1ffd; // TODO + state->last_1ffd = file.get8(); } }