diff --git a/Machines/Sinclair/Keyboard/Keyboard.cpp b/Machines/Sinclair/Keyboard/Keyboard.cpp index 686179835..1e9db2bf8 100644 --- a/Machines/Sinclair/Keyboard/Keyboard.cpp +++ b/Machines/Sinclair/Keyboard/Keyboard.cpp @@ -72,7 +72,7 @@ const uint16_t *CharacterMapper::sequence_for_character(char character) const { #define SHIFT(...) {KeyShift, __VA_ARGS__, MachineTypes::MappedKeyboardMachine::KeyEndSequence} #define SYMSHIFT(...) {KeySymbolShift, __VA_ARGS__, MachineTypes::MappedKeyboardMachine::KeyEndSequence} #define X {MachineTypes::MappedKeyboardMachine::KeyNotMapped} - constexpr KeySequence spectrum_key_sequences[] = { + static constexpr KeySequence spectrum_key_sequences[] = { /* NUL */ X, /* SOH */ X, /* STX */ X, /* ETX */ X, /* EOT */ X, /* ENQ */ X, @@ -137,7 +137,7 @@ const uint16_t *CharacterMapper::sequence_for_character(char character) const { /* z */ KEYS(KeyZ), }; - constexpr KeySequence zx81_key_sequences[] = { + static constexpr KeySequence zx81_key_sequences[] = { /* NUL */ X, /* SOH */ X, /* STX */ X, /* ETX */ X, /* EOT */ X, /* ENQ */ X, @@ -203,7 +203,7 @@ const uint16_t *CharacterMapper::sequence_for_character(char character) const { /* | */ X, /* } */ X, }; - static KeySequence zx80_key_sequences[] = { + static constexpr KeySequence zx80_key_sequences[] = { /* NUL */ X, /* SOH */ X, /* STX */ X, /* ETX */ X, /* EOT */ X, /* ENQ */ X, diff --git a/Machines/Sinclair/ZXSpectrum/ZXSpectrum.cpp b/Machines/Sinclair/ZXSpectrum/ZXSpectrum.cpp index 73f339027..ef2aa417a 100644 --- a/Machines/Sinclair/ZXSpectrum/ZXSpectrum.cpp +++ b/Machines/Sinclair/ZXSpectrum/ZXSpectrum.cpp @@ -39,6 +39,8 @@ #include "../../../ClockReceiver/JustInTime.hpp" +#include "../../../Processors/Z80/State/State.hpp" + #include "../Keyboard/Keyboard.hpp" #include @@ -211,15 +213,15 @@ template class ConcreteMachine: case PartialMachineCycle::ReadOpcode: // Fast loading: ROM version. // - // The below patches over the 'LD-BYTES' routine from the 48kb ROM. - if(use_fast_tape_hack_ && address == 0x0556 && read_pointers_[0] == &rom_[0xc000]) { - if(perform_rom_ld_bytes()) { - // Stop pressing enter, if neccessry. - if(duration_to_press_enter_ > Cycles(0)) { - duration_to_press_enter_ = Cycles(0); - keyboard_.set_key_state(ZX::Keyboard::KeyEnter, false); - } + // The below patches over part of the 'LD-BYTES' routine from the 48kb ROM. + if(use_fast_tape_hack_ && address == 0x056b && read_pointers_[0] == &rom_[0xc000]) { + // Stop pressing enter, if neccessry. + if(duration_to_press_enter_ > Cycles(0)) { + duration_to_press_enter_ = Cycles(0); + keyboard_.set_key_state(ZX::Keyboard::KeyEnter, false); + } + if(perform_rom_ld_bytes_56b()) { *cycle.value = 0xc9; // i.e. RET. break; } @@ -627,31 +629,42 @@ template class ConcreteMachine: } // Reimplements the 'LD-BYTES' routine, as documented at - // https://skoolkid.github.io/rom/asm/0556.html i.e. + // https://skoolkid.github.io/rom/asm/0556.html but picking + // up from address 56b i.e. // // In: - // A: 0x00 or 0xff for block type; - // F: carry set if loading, clear if verifying; + // A': 0x00 or 0xff for block type; + // F': carry set if loading, clear if verifying; // DE: block length; // IX: start address. // // Out: // F: carry set for success, clear for error. - bool perform_rom_ld_bytes() { + // + // And, empirically: + // IX: one beyond final address written; + // DE: 0; + // L: parity byte; + // H: 0 for no error, 0xff for error; + // A: same as H. + // BC: ??? + bool perform_rom_ld_bytes_56b() { using Parser = Storage::Tape::ZXSpectrum::Parser; Parser parser(Parser::MachineType::ZXSpectrum); using Register = CPU::Z80::Register; - uint8_t flags = uint8_t(z80_.get_value_of_register(Register::Flags)); + uint8_t flags = uint8_t(z80_.get_value_of_register(Register::FlagsDash)); if(!(flags & 1)) return false; - const uint8_t block_type = uint8_t(z80_.get_value_of_register(Register::A)); + const uint8_t block_type = uint8_t(z80_.get_value_of_register(Register::ADash)); const auto block = parser.find_block(tape_player_.get_tape()); if(!block || block_type != (*block).type) return false; uint16_t length = z80_.get_value_of_register(Register::DE); uint16_t target = z80_.get_value_of_register(Register::IX); + flags = 0x93; + uint8_t parity = 0x00; while(length--) { auto next = parser.get_byte(tape_player_.get_tape()); if(!next) { @@ -660,10 +673,25 @@ template class ConcreteMachine: } write_pointers_[target >> 14][target] = *next; + parity ^= *next; ++target; } + auto stored_parity = parser.get_byte(tape_player_.get_tape()); + if(!stored_parity) { + flags &= ~1; + } else { + z80_.set_value_of_register(Register::L, *stored_parity); + } + z80_.set_value_of_register(Register::Flags, flags); + z80_.set_value_of_register(Register::DE, length); + z80_.set_value_of_register(Register::IX, target); + + const uint8_t h = (flags & 1) ? 0x00 : 0xff; + z80_.set_value_of_register(Register::H, h); + z80_.set_value_of_register(Register::A, h); + return true; } diff --git a/Reflection/Struct.cpp b/Reflection/Struct.cpp index 46a1c65a8..babd12744 100644 --- a/Reflection/Struct.cpp +++ b/Reflection/Struct.cpp @@ -212,6 +212,7 @@ std::string Reflection::Struct::description() const { for(const auto &key: all_keys()) { if(!is_first) stream << ", "; is_first = false; + stream << key << ": "; const auto count = count_of(key);