From 645d198bee4ba9760a1477d3556e768e629f458b Mon Sep 17 00:00:00 2001
From: Thomas Harte <thomas.harte@gmail.com>
Date: Tue, 14 Jul 2020 22:17:56 -0400
Subject: [PATCH] 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<bool is_zx81> 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<bool is_zx81> class ConcreteMachine:
 
 			if(!target.loading_command.empty()) {
 				type_string(target.loading_command);
+				should_autorun_ = true;
 			}
 
 			insert_media(target.media);
@@ -264,6 +250,15 @@ template<bool is_zx81> 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<bool is_zx81> class ConcreteMachine:
 		CPU::Z80::Processor<ConcreteMachine, false, is_zx81> 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<uint8_t> ram_;
 		uint16_t ram_mask_, ram_base_;
@@ -445,7 +454,8 @@ template<bool is_zx81> 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;