From 645d198bee4ba9760a1477d3556e768e629f458b Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Tue, 14 Jul 2020 22:17:56 -0400 Subject: [PATCH 1/3] Causes ZX80 and ZX81 software that doesn't already autorun to do so. --- Machines/ZX8081/ZX8081.cpp | 46 +++++++++++++++++++++++--------------- 1 file changed, 28 insertions(+), 18 deletions(-) diff --git a/Machines/ZX8081/ZX8081.cpp b/Machines/ZX8081/ZX8081.cpp index e998da86f..cdba753d0 100644 --- a/Machines/ZX8081/ZX8081.cpp +++ b/Machines/ZX8081/ZX8081.cpp @@ -80,21 +80,6 @@ template class ConcreteMachine: rom_ = std::move(*roms[0]); rom_.resize(use_zx81_rom ? 8192 : 4096); - if constexpr (is_zx81) { - tape_trap_address_ = 0x37c; - tape_return_address_ = 0x380; - vsync_start_ = HalfCycles(32); - vsync_end_ = HalfCycles(64); - automatic_tape_motor_start_address_ = 0x0340; - automatic_tape_motor_end_address_ = 0x03c3; - } else { - tape_trap_address_ = 0x220; - tape_return_address_ = 0x248; - vsync_start_ = HalfCycles(26); - vsync_end_ = HalfCycles(66); - automatic_tape_motor_start_address_ = 0x0206; - automatic_tape_motor_end_address_ = 0x024d; - } rom_mask_ = uint16_t(rom_.size() - 1); switch(target.memory_model) { @@ -118,6 +103,7 @@ template class ConcreteMachine: if(!target.loading_command.empty()) { type_string(target.loading_command); + should_autorun_ = true; } insert_media(target.media); @@ -264,6 +250,15 @@ template class ConcreteMachine: } } + if(should_autorun_ && address == print_status_address_) { + const uint16_t status_code = z80_.get_value_of_register(CPU::Z80::Register::A); + const uint16_t line_number = 0; // TODO. + if(!status_code && !line_number) { + type_string("r \n"); + } + should_autorun_ = false; + } + // Check for automatic tape control. if(use_automatic_tape_motor_control_) { tape_player_.set_motor_control((address >= automatic_tape_motor_start_address_) && (address < automatic_tape_motor_end_address_)); @@ -425,8 +420,22 @@ template class ConcreteMachine: CPU::Z80::Processor z80_; Video video_; - uint16_t tape_trap_address_, tape_return_address_; - uint16_t automatic_tape_motor_start_address_, automatic_tape_motor_end_address_; + // If fast tape loading is enabled then the PC will be trapped at tape_trap_address_; + // the emulator will then do a high-level reinterpretation of the standard ZX80/81 reading + // of a single byte, and the next thing executed will be at tape_return_address_; + static constexpr uint16_t tape_trap_address_ = is_zx81 ? 0x37c : 0x220; + static constexpr uint16_t tape_return_address_ = is_zx81 ? 0x380 : 0x248; + + // If automatic tape motor control is enabled then the tape will be permitted to play any time + // the program counter is >= automatic_tape_motor_start_address_ and < automatic_tape_motor_end_address_. + static constexpr uint16_t automatic_tape_motor_start_address_ = is_zx81 ? 0x340 : 0x206; + static constexpr uint16_t automatic_tape_motor_end_address_ = is_zx81 ? 0x3c3 : 0x24d; + + // When automatically loading, if the PC gets to the print_status_address_ in order to print 0/0 + // after loading from tape (i.e. loading completed, in context) then the emulator will automatically + // RUN whatever has been loaded. + static constexpr uint16_t print_status_address_ = is_zx81 ? 0x6d1 : 0x4a8; + bool should_autorun_ = false; std::vector ram_; uint16_t ram_mask_, ram_base_; @@ -445,7 +454,8 @@ template class ConcreteMachine: bool nmi_is_enabled_ = false; - HalfCycles vsync_start_, vsync_end_; + static constexpr auto vsync_start_ = is_zx81 ? HalfCycles(32) : HalfCycles(26); + static constexpr auto vsync_end_ = is_zx81 ? HalfCycles(64) : HalfCycles(66); HalfCycles horizontal_counter_; uint8_t latched_video_byte_ = 0; From 371c26251c34c50a2392a74f3e103a5bc6da6918 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Tue, 14 Jul 2020 22:36:04 -0400 Subject: [PATCH 2/3] Switches strategy for the ZX80. --- Machines/ZX8081/ZX8081.cpp | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/Machines/ZX8081/ZX8081.cpp b/Machines/ZX8081/ZX8081.cpp index cdba753d0..5472b3ebc 100644 --- a/Machines/ZX8081/ZX8081.cpp +++ b/Machines/ZX8081/ZX8081.cpp @@ -250,12 +250,8 @@ template class ConcreteMachine: } } - if(should_autorun_ && address == print_status_address_) { - const uint16_t status_code = z80_.get_value_of_register(CPU::Z80::Register::A); - const uint16_t line_number = 0; // TODO. - if(!status_code && !line_number) { - type_string("r \n"); - } + if(should_autorun_ && address == finished_load_address_) { + type_string("r \n"); should_autorun_ = false; } @@ -431,10 +427,12 @@ template class ConcreteMachine: static constexpr uint16_t automatic_tape_motor_start_address_ = is_zx81 ? 0x340 : 0x206; static constexpr uint16_t automatic_tape_motor_end_address_ = is_zx81 ? 0x3c3 : 0x24d; - // When automatically loading, if the PC gets to the print_status_address_ in order to print 0/0 - // after loading from tape (i.e. loading completed, in context) then the emulator will automatically - // RUN whatever has been loaded. - static constexpr uint16_t print_status_address_ = is_zx81 ? 0x6d1 : 0x4a8; + // When automatically loading, if the PC gets to the finished_load_address_ in order to print 0/0 + // (so it's anything that indicates that loading completed, but the program did not autorun) then the + // emulator will automatically RUN whatever has been loaded. + static constexpr uint16_t finished_load_address_ = is_zx81 ? + 0x6d1 : // ZX81: this is the routine that prints 0/0 (i.e. success). + 0x256; // ZX80: this is the start of the list command; the ZX80 lists a program after loading. bool should_autorun_ = false; std::vector ram_; From e1c57b6fbed1d7cc321528b69ac6e75f4222f364 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Tue, 14 Jul 2020 23:45:51 -0400 Subject: [PATCH 3/3] Further ensures both ZX80 and ZX81 functionality. --- Machines/ZX8081/ZX8081.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Machines/ZX8081/ZX8081.cpp b/Machines/ZX8081/ZX8081.cpp index 5472b3ebc..eb7912bd0 100644 --- a/Machines/ZX8081/ZX8081.cpp +++ b/Machines/ZX8081/ZX8081.cpp @@ -251,10 +251,12 @@ template class ConcreteMachine: } if(should_autorun_ && address == finished_load_address_) { - type_string("r \n"); + type_string(is_zx81 ? "r \n" : "r\n "); // Spaces here are not especially scientific; they merely ensure sufficient pauses for both the ZX80 and 81, empirically. should_autorun_ = false; } + if(address >= 0x24d && address < 0x256) printf("PC: %04x\n", address); + // Check for automatic tape control. if(use_automatic_tape_motor_control_) { tape_player_.set_motor_control((address >= automatic_tape_motor_start_address_) && (address < automatic_tape_motor_end_address_)); @@ -432,7 +434,7 @@ template class ConcreteMachine: // emulator will automatically RUN whatever has been loaded. static constexpr uint16_t finished_load_address_ = is_zx81 ? 0x6d1 : // ZX81: this is the routine that prints 0/0 (i.e. success). - 0x256; // ZX80: this is the start of the list command; the ZX80 lists a program after loading. + 0x203; // ZX80: this is the JR that exits the ZX80's LOAD and returns to MAIN-EXEC. bool should_autorun_ = false; std::vector ram_;