diff --git a/Machines/Enterprise/Enterprise.cpp b/Machines/Enterprise/Enterprise.cpp index 31bf6e0a6..cfe9342f4 100644 --- a/Machines/Enterprise/Enterprise.cpp +++ b/Machines/Enterprise/Enterprise.cpp @@ -358,6 +358,13 @@ template class ConcreteMachine: } break; + case 0x80: case 0x81: case 0x82: case 0x83: + case 0x84: case 0x85: case 0x86: case 0x87: + case 0x88: case 0x89: case 0x8a: case 0x8b: + case 0x8c: case 0x8d: case 0x8e: case 0x8f: + *cycle.value = nick_->read(); + break; + case 0xb0: *cycle.value = pages_[0]; break; case 0xb1: *cycle.value = pages_[1]; break; case 0xb2: *cycle.value = pages_[2]; break; diff --git a/Machines/Enterprise/Nick.cpp b/Machines/Enterprise/Nick.cpp index bbe5d2ff4..96b699e07 100644 --- a/Machines/Enterprise/Nick.cpp +++ b/Machines/Enterprise/Nick.cpp @@ -91,8 +91,8 @@ void Nick::write(uint16_t address, uint8_t value) { } } -uint8_t Nick::read([[maybe_unused]] uint16_t address) { - return 0xff; +uint8_t Nick::read() { + return last_read_; } Cycles Nick::get_time_until_z80_slot(Cycles after_period) const { @@ -141,9 +141,6 @@ void Nick::run_for(Cycles duration) { // HSYNC is signalled for four windows at the start of the line. // I currently believe this happens regardless of Vsync mode. - // - // This is also when the non-palette line parameters - // are loaded, if appropriate. if(!window) { set_output_type(OutputType::Sync); @@ -153,6 +150,9 @@ void Nick::run_for(Cycles duration) { if(!right_margin_) is_sync_or_pixels_ = false; } + // Default to noting read. + last_read_ = 0xff; + while(window < 4 && window < end_window) { if(should_reload_line_parameters_) { switch(window) { @@ -161,6 +161,9 @@ void Nick::run_for(Cycles duration) { // Byte 0: lines remaining. lines_remaining_ = ram_[line_parameter_pointer_]; + // Byte 1: current interrupt output plus graphics modes... + last_read_ = ram_[line_parameter_pointer_ + 1]; + // Set the new interrupt line output. interrupt_line_ = ram_[line_parameter_pointer_ + 1] & 0x80; @@ -200,6 +203,7 @@ void Nick::run_for(Cycles duration) { // Determine the margins. left_margin_ = ram_[line_parameter_pointer_ + 2] & 0x3f; right_margin_ = ram_[line_parameter_pointer_ + 3] & 0x3f; + last_read_ = ram_[line_parameter_pointer_ + 3]; // Set up the alternative palettes, switch(mode_) { @@ -249,6 +253,7 @@ void Nick::run_for(Cycles duration) { start_line_data_pointer_[0] |= ram_[line_parameter_pointer_ + 5] << 8; line_data_pointer_[0] = start_line_data_pointer_[0]; + last_read_ = ram_[line_parameter_pointer_ + 5]; break; // Fourth slot: Line data pointer 2. @@ -257,6 +262,7 @@ void Nick::run_for(Cycles duration) { start_line_data_pointer_[1] |= ram_[line_parameter_pointer_ + 7] << 8; line_data_pointer_[1] = start_line_data_pointer_[1]; + last_read_ = ram_[line_parameter_pointer_ + 7]; break; } } @@ -301,6 +307,7 @@ void Nick::run_for(Cycles duration) { assert(base < 7); palette_[base] = mapped_colour(ram_[line_parameter_pointer_ + base + 8]); palette_[base + 1] = mapped_colour(ram_[line_parameter_pointer_ + base + 9]); + last_read_ = ram_[line_parameter_pointer_ + base + 9]; } ++output_duration_; @@ -534,6 +541,7 @@ template void Nick::output_pixel(uint16_t *target, int ram_[(line_data_pointer_[0] + index + 1) & 0xffff] }; index += is_lpixel ? 1 : 2; + last_read_ = pixels[1]; switch(bpp) { default: @@ -582,6 +590,7 @@ template void Nick::output_character(uint16_t *target, (line_data_pointer_[1] << index_bits) + (character & ((1 << index_bits) - 1)) ) & 0xffff]; + last_read_ = pixels; switch(bpp) { default: @@ -607,6 +616,7 @@ template void Nick::output_attributed(uint16_t *target, int columns) c for(int c = 0; c < columns; c++) { const uint8_t pixels = ram_[(line_data_pointer_[1] + c) & 0xffff]; const uint8_t attributes = ram_[(line_data_pointer_[0] + c) & 0xffff]; + last_read_ = pixels; const uint16_t palette[2] = { palette_[attributes >> 4], palette_[attributes & 0x0f] diff --git a/Machines/Enterprise/Nick.hpp b/Machines/Enterprise/Nick.hpp index d19760859..3092895de 100644 --- a/Machines/Enterprise/Nick.hpp +++ b/Machines/Enterprise/Nick.hpp @@ -19,8 +19,17 @@ class Nick { public: Nick(const uint8_t *ram); + /// Writes to a Nick register; only the low two bits are decoded. void write(uint16_t address, uint8_t value); - uint8_t read(uint16_t address); + + /// Reads from the Nick range. Nobody seems to be completely clear what + /// this should return; I've set it up to return the last fetched video or mode + /// line byte during periods when those things are being fetched, 0xff at all + /// other times. Including during refresh, since I don't know what addresses + /// are generated then. + /// + /// This likely isn't accurate, but is the most accurate guess I could make. + uint8_t read(); void run_for(Cycles); Cycles get_time_until_z80_slot(Cycles after_period) const; @@ -60,6 +69,7 @@ class Nick { bool should_reload_line_parameters_ = true; uint16_t line_data_pointer_[2]; uint16_t start_line_data_pointer_[2]; + mutable uint8_t last_read_ = 0xff; // Current mode line parameters. uint8_t lines_remaining_ = 0x00;