diff --git a/Components/9918/Implementation/9918.cpp b/Components/9918/Implementation/9918.cpp index f77293392..8565e9083 100644 --- a/Components/9918/Implementation/9918.cpp +++ b/Components/9918/Implementation/9918.cpp @@ -852,8 +852,8 @@ void Base::commit_register(int reg, uint8_t value) { case 44: Storage::command_context_.colour = value; - Storage::command_context_.colour4pp = (value & 0xf) | (value << 4); - Storage::command_context_.colour2pp = (value & 0x3) | ((value & 0x3) << 2) | ((value & 0x3) << 4) | ((value & 0x3) << 6); + Storage::command_context_.colour4bpp = (value & 0xf) | (value << 4); + Storage::command_context_.colour2bpp = (value & 0x3) | ((value & 0x3) << 2) | ((value & 0x3) << 4) | ((value & 0x3) << 6); // Check whether a command was blocked on this. if( @@ -911,7 +911,8 @@ void Base::commit_register(int reg, uint8_t value) { } #undef Begin - Storage::command_context_.pixel_operation = CommandContext::LogicalOperation(value & 0xf); + Storage::command_context_.pixel_operation = CommandContext::LogicalOperation(value & 7); + Storage::command_context_.test_source = value & 8; // Kill the command immediately if it's done in zero operations // (e.g. a line of length 0). diff --git a/Components/9918/Implementation/9918Base.hpp b/Components/9918/Implementation/9918Base.hpp index 191608ba2..d47dd308e 100644 --- a/Components/9918/Implementation/9918Base.hpp +++ b/Components/9918/Implementation/9918Base.hpp @@ -579,6 +579,66 @@ template struct Base: public Storage { return ScreenMode::Blank; } + uint32_t command_address() const { + if constexpr (is_yamaha_vdp(personality)) { + switch(this->screen_mode_) { + default: + case ScreenMode::YamahaGraphics4: // 256 pixels @ 4bpp + return + (Storage::command_->location.v[0] >> 1) + + (Storage::command_->location.v[1] << 7); + + case ScreenMode::YamahaGraphics5: // 512 pixels @ 2bpp + return + (Storage::command_->location.v[0] >> 2) + + (Storage::command_->location.v[1] << 7); + + case ScreenMode::YamahaGraphics6: // 512 pixels @ 4bpp + return + (Storage::command_->location.v[0] >> 1) + + (Storage::command_->location.v[1] << 8); + + case ScreenMode::YamahaGraphics7: // 256 pixels @ 8bpp + return + (Storage::command_->location.v[0] >> 0) + + (Storage::command_->location.v[1] << 8); + } + } else { + return 0; + } + } + + std::pair command_colour_mask() const { + if constexpr (is_yamaha_vdp(personality)) { + switch(this->screen_mode_) { + default: + case ScreenMode::YamahaGraphics4: // 256 pixels @ 4bpp + case ScreenMode::YamahaGraphics6: // 512 pixels @ 4bpp + return + std::make_pair( + 0xf0 >> ((Storage::command_->location.v[0] & 1) << 2), + Storage::command_context_.colour4bpp + ); + + case ScreenMode::YamahaGraphics5: // 512 pixels @ 2bpp + return + std::make_pair( + 0xc0 >> ((Storage::command_->location.v[0] & 3) << 1), + Storage::command_context_.colour2bpp + ); + + case ScreenMode::YamahaGraphics7: // 256 pixels @ 8bpp + return + std::make_pair( + 0xff, + Storage::command_context_.colour + ); + } + } else { + return std::make_pair(0, 0); + } + } + void do_external_slot(int access_column) { // Don't do anything if the required time for the access to become executable // has yet to pass. @@ -593,56 +653,47 @@ template struct Base: public Storage { return; } - // Compute the affected address and pixel - unsigned address; - uint8_t mask; - switch(this->screen_mode_) { - default: - case ScreenMode::YamahaGraphics4: // 256 pixels @ 4bpp - address = - (Storage::command_->location.v[0] >> 1) + - (Storage::command_->location.v[1] << 7); - mask = 0xf0 >> ((Storage::command_->location.v[0] & 1) << 2); - break; - case ScreenMode::YamahaGraphics5: // 512 pixels @ 2bpp - address = - (Storage::command_->location.v[0] >> 2) + - (Storage::command_->location.v[1] << 7); - mask = 0xc0 >> ((Storage::command_->location.v[0] & 3) << 1); - break; - case ScreenMode::YamahaGraphics6: // 512 pixels @ 4bpp - address = - (Storage::command_->location.v[0] >> 1) + - (Storage::command_->location.v[1] << 8); - mask = 0xf0 >> ((Storage::command_->location.v[0] & 1) << 2); - break; - case ScreenMode::YamahaGraphics7: // 256 pixels @ 8bpp - address = - (Storage::command_->location.v[0] >> 0) + - (Storage::command_->location.v[1] << 8); - mask = 0xff; - break; - } - switch(Storage::next_command_step_) { // Duplicative, but keeps the compiler happy. case CommandStep::None: break; case CommandStep::ReadPixel: - Storage::command_latch_ = ram_[address]; + Storage::command_latch_ = ram_[command_address()]; Storage::minimum_command_column_ = access_column + 24; Storage::next_command_step_ = CommandStep::WritePixel; break; case CommandStep::WritePixel: { - uint8_t packed_colour = Storage::command_context_.colour & 3; - packed_colour |= packed_colour << 2; - packed_colour |= packed_colour << 4; + const auto [mask, unmasked_colour] = command_colour_mask(); + const auto address = command_address(); + const uint8_t colour = unmasked_colour & mask; + + using LogicalOperation = CommandContext::LogicalOperation; + if(!Storage::command_context_.test_source || colour) { + switch(Storage::command_context_.pixel_operation) { + default: + case LogicalOperation::Copy: + Storage::command_latch_ &= ~mask; + Storage::command_latch_ |= colour; + break; + case LogicalOperation::And: + Storage::command_latch_ &= ~mask | colour; + break; + case LogicalOperation::Or: + Storage::command_latch_ |= colour; + break; + case LogicalOperation::Xor: + Storage::command_latch_ ^= colour; + break; + case LogicalOperation::Not: + Storage::command_latch_ &= ~mask; + Storage::command_latch_ |= colour ^ mask; + break; + } + } - Storage::command_latch_ &= ~mask; - Storage::command_latch_ |= packed_colour & mask; ram_[address] = Storage::command_latch_; Storage::command_->advance(); diff --git a/Components/9918/Implementation/YamahaCommands.hpp b/Components/9918/Implementation/YamahaCommands.hpp index 5b144e521..2ad52c83e 100644 --- a/Components/9918/Implementation/YamahaCommands.hpp +++ b/Components/9918/Implementation/YamahaCommands.hpp @@ -51,9 +51,9 @@ struct CommandContext { /// Colour as written by the CPU. uint8_t colour = 0; /// The low four bits of the CPU-written colour, repeated twice. - uint8_t colour4pp = 0; + uint8_t colour4bpp = 0; /// The low two bits of the CPU-written colour, repeated four times. - uint8_t colour2pp = 0; + uint8_t colour2bpp = 0; enum class LogicalOperation { Copy = 0b0000, @@ -61,14 +61,9 @@ struct CommandContext { Or = 0b0010, Xor = 0b0011, Not = 0b0100, - - ConditionalCopy = 0b1000, - ConditionalAnd = 0b1001, - ConditionalOr = 0b1010, - ConditionalXor = 0b1011, - ConditionalNot = 0b1100, }; LogicalOperation pixel_operation; + bool test_source; }; struct Command {