diff --git a/Components/9918/Implementation/9918.cpp b/Components/9918/Implementation/9918.cpp index 510b5ed1c..ca23f1272 100644 --- a/Components/9918/Implementation/9918.cpp +++ b/Components/9918/Implementation/9918.cpp @@ -488,7 +488,7 @@ void TMS9918::run_for(const HalfCycles cycles) { this->asked_for_write_area_ = true; this->pixel_origin_ = this->pixel_target_ = reinterpret_cast( - this->crt_.begin_data(line_buffer.pixel_count) + this->crt_.begin_data(size_t(line_buffer.pixel_count)) ); } @@ -507,7 +507,7 @@ void TMS9918::run_for(const HalfCycles cycles) { if(end == line_buffer.next_border_column) { const int length = line_buffer.next_border_column - line_buffer.first_pixel_output_column; - this->crt_.output_data(from_internal(length), line_buffer.pixel_count); + this->crt_.output_data(from_internal(length), size_t(line_buffer.pixel_count)); this->pixel_origin_ = this->pixel_target_ = nullptr; this->asked_for_write_area_ = false; } @@ -645,32 +645,11 @@ void Base::commit_register(int reg, uint8_t value) { if(sprites_magnified_) sprite_height_ <<= 1; break; - case 2: - pattern_name_address_ = size_t((value & 0xf) << 10) | 0x3ff; - break; - - case 3: - colour_table_address_ = - (colour_table_address_ & ~0x3fc0) | - (value << 6) | - 0x3f; - break; - - case 4: - pattern_generator_table_address_ = size_t((value & 0x07) << 11) | 0x7ff; - // TODO: don't mask off so many bits for, at least, the Yamahas. - break; - - case 5: - sprite_attribute_table_address_ = - (sprite_attribute_table_address_ & ~0x3d80) | - ((value << 7) & 0x3f80) | - 0x7f; - break; - - case 6: - sprite_generator_table_address_ = size_t((value & 0x07) << 11) | 0x7ff; - break; + case 2: install_field<10>(pattern_name_address_, value); break; + case 3: install_field<6>(colour_table_address_, value); break; + case 4: install_field<11>(pattern_generator_table_address_, value); break; + case 5: install_field<7>(sprite_attribute_table_address_, value); break; + case 6: install_field<11>(sprite_generator_table_address_, value); break; case 7: text_colour_ = value >> 4; @@ -755,11 +734,6 @@ void Base::commit_register(int reg, uint8_t value) { LOG("Screen mode: " << int(current_screen_mode())); break; - case 2: - // Retain extra addressing bits. - pattern_name_address_ = size_t((value & 0x7f) << 10) | 0x3ff; - break; - case 8: LOG("TODO: Yamaha VRAM organisation, sprite disable, etc; " << PADHEX(2) << +value); // b7: "1 = input on colour bus, enable mouse; 1 = output on colour bus, disable mouse" [documentation clearly in error] @@ -781,19 +755,11 @@ void Base::commit_register(int reg, uint8_t value) { // b0: 1 = [dot clock] DLCLK is input; 0 = DLCLK is output break; - case 10: - colour_table_address_ = - (colour_table_address_ & ~0x1c000) | - ((value << 14) & 0x1c000); - // b0–b2: A14–A16 of the colour table. - break; + // b0–b2: A14–A16 of the colour table. + case 10: install_field<14>(colour_table_address_, value); break; - case 11: - sprite_attribute_table_address_ = - (sprite_attribute_table_address_ & ~0x18000) | - ((value << 15) & 0x18000); - // b0–b1: A15–A16 of the sprite table. - break; + // b0–b1: A15–A16 of the sprite table. + case 11: install_field<15>(sprite_attribute_table_address_, value); break; case 12: LOG("TODO: Yamaha text and background blink colour; " << PADHEX(2) << +value); @@ -806,9 +772,7 @@ void Base::commit_register(int reg, uint8_t value) { // b4–b7: display time for even page. break; - case 14: - ram_pointer_ = (ram_pointer_ & ~0x1c000) | ((value << 14) & 0x1c000); - break; + case 14: install_field<14>(ram_pointer_, value); break; case 15: Storage::selected_status_ = value & 0xf; @@ -863,8 +827,8 @@ void Base::commit_register(int reg, uint8_t value) { case 44: Storage::command_context_.colour = value; - Storage::command_context_.colour4bpp = (value & 0xf) | (value << 4); - Storage::command_context_.colour2bpp = (value & 0x3) | ((value & 0x3) << 2) | ((value & 0x3) << 4) | ((value & 0x3) << 6); + Storage::command_context_.colour4bpp = uint8_t((value & 0xf) | (value << 4)); + Storage::command_context_.colour2bpp = uint8_t((value & 0x3) | ((value & 0x3) << 2) | ((value & 0x3) << 4) | ((value & 0x3) << 6)); // Check whether a command was blocked on this. if( @@ -948,13 +912,12 @@ void Base::write_register(uint8_t value) { write_phase_ = true; // The initial write should half update the access pointer. - ram_pointer_ = (ram_pointer_ & ~0xff) | low_write_; + install_field<0>(ram_pointer_, value); return; } // The RAM pointer is always set on a second write, regardless of - // whether the caller is intending to enqueue a VDP operation. - ram_pointer_ = (ram_pointer_ & ~0x3f00) | ((value << 8) & 0x3f00); + // whether the caller is intending to enqueue a VDP operation. install_field<8, 0x3f>(ram_pointer_, value); write_phase_ = false; if(value & 0x80) { diff --git a/Components/9918/Implementation/9918Base.hpp b/Components/9918/Implementation/9918Base.hpp index 8d5b36309..0b11a9987 100644 --- a/Components/9918/Implementation/9918Base.hpp +++ b/Components/9918/Implementation/9918Base.hpp @@ -86,7 +86,7 @@ struct LineBuffer { */ int first_pixel_output_column = 94; int next_border_column = 334; - size_t pixel_count = 256; + int pixel_count = 256; // An active sprite is one that has been selected for composition onto // this line. @@ -121,11 +121,15 @@ template struct Storage { }; template <> struct Storage { + using AddressT = uint16_t; + void begin_line(ScreenMode, bool, bool) {} }; // Yamaha-specific storage. template struct Storage> { + using AddressT = uint32_t; + int selected_status_ = 0; int indirect_register_ = 0; @@ -351,6 +355,8 @@ template struct Storage struct Storage> { + using AddressT = uint16_t; + // The SMS VDP has a programmer-set colour palette, with a dedicated patch of RAM. But the RAM is only exactly // fast enough for the pixel clock. So when the programmer writes to it, that causes a one-pixel glitch; there // isn't the bandwidth for the read both write to occur simultaneously. The following buffer therefore keeps @@ -379,10 +385,10 @@ template struct Storage struct Base: public Storage { Outputs::CRT::CRT crt_; TVStandard tv_standard_ = TVStandard::NTSC; + using AddressT = typename Storage::AddressT; + + /// Mutates @c target such that @c source & @c source_mask replaces the bits that currently start + /// at @c shift bits from least significant. Subsequently ensures @c target is constrained by the + /// applicable @c memory_mask. + template void install_field(AddressT &target, uint8_t source) { + constexpr auto mask = AddressT(~(source_mask << shift)); + target = ( + (target & mask) | + AddressT((source & source_mask) << shift) + ) & memory_mask(personality); + } // Personality-specific metrics and converters. ClockConverter clock_converter_; @@ -440,7 +458,7 @@ template struct Base: public Storage { std::array ram_; // State of the DRAM/CRAM-access mechanism. - size_t ram_pointer_ = 0; + AddressT ram_pointer_ = 0; uint8_t read_ahead_buffer_ = 0; MemoryAccess queued_access_ = MemoryAccess::None; int minimum_access_column_ = 0; @@ -463,11 +481,11 @@ template struct Base: public Storage { int sprite_height_ = 8; // Programmer-specified addresses. - size_t pattern_name_address_ = 0; // i.e. address of the tile map. - size_t colour_table_address_ = 0; // address of the colour map (if applicable). - size_t pattern_generator_table_address_ = 0; // address of the tile contents. - size_t sprite_attribute_table_address_ = 0; // address of the sprite list. - size_t sprite_generator_table_address_ = 0; // address of the sprite contents. + AddressT pattern_name_address_ = memory_mask(personality); // Address of the tile map. + AddressT colour_table_address_ = memory_mask(personality); // Address of the colour map (if applicable). + AddressT pattern_generator_table_address_ = memory_mask(personality); // Address of the tile contents. + AddressT sprite_attribute_table_address_ = memory_mask(personality); // Address of the sprite list. + AddressT sprite_generator_table_address_ = memory_mask(personality); // Address of the sprite contents. // Default colours. uint8_t text_colour_ = 0; @@ -588,29 +606,33 @@ template struct Base: public Storage { return ScreenMode::Blank; } - uint32_t command_address() const { + AddressT command_address() const { if constexpr (is_yamaha_vdp(personality)) { switch(this->screen_mode_) { default: case ScreenMode::YamahaGraphics4: // 256 pixels @ 4bpp - return + return AddressT( (Storage::command_->location.v[0] >> 1) + - (Storage::command_->location.v[1] << 7); + (Storage::command_->location.v[1] << 7) + ); case ScreenMode::YamahaGraphics5: // 512 pixels @ 2bpp - return + return AddressT( (Storage::command_->location.v[0] >> 2) + - (Storage::command_->location.v[1] << 7); + (Storage::command_->location.v[1] << 7) + ); case ScreenMode::YamahaGraphics6: // 512 pixels @ 4bpp - return + return AddressT( (Storage::command_->location.v[0] >> 1) + - (Storage::command_->location.v[1] << 8); + (Storage::command_->location.v[1] << 8) + ); case ScreenMode::YamahaGraphics7: // 256 pixels @ 8bpp - return + return AddressT( (Storage::command_->location.v[0] >> 0) + - (Storage::command_->location.v[1] << 8); + (Storage::command_->location.v[1] << 8) + ); } } else { return 0; @@ -720,7 +742,7 @@ template struct Base: public Storage { return; } - size_t address = ram_pointer_; + AddressT address = ram_pointer_; ++ram_pointer_; if constexpr (is_yamaha_vdp(personality)) { diff --git a/Components/9918/Implementation/Fetch.hpp b/Components/9918/Implementation/Fetch.hpp index 18b55f1c0..b2a3d1f8b 100644 --- a/Components/9918/Implementation/Fetch.hpp +++ b/Components/9918/Implementation/Fetch.hpp @@ -469,7 +469,7 @@ template void Base::fetch_sms(LineBuffer &line_buffer template template void Base::fetch_yamaha([[maybe_unused]] LineBuffer &line_buffer, [[maybe_unused]] int y, int end) { - const int rotated_name_ = pattern_name_address_ >> 1; + const AddressT rotated_name_ = pattern_name_address_ >> 1; const uint8_t *const ram2 = &ram_[65536]; while(Storage::next_event_->offset < end) { @@ -488,10 +488,10 @@ template void Base::fetch_yamaha([[maybe_unused]] const int start = (y << 7) | column | 0x1'8000; - line_buffer.bitmap[column + 0] = ram_[pattern_name_address_ & (start + 0)]; - line_buffer.bitmap[column + 1] = ram_[pattern_name_address_ & (start + 1)]; - line_buffer.bitmap[column + 2] = ram_[pattern_name_address_ & (start + 2)]; - line_buffer.bitmap[column + 3] = ram_[pattern_name_address_ & (start + 3)]; + line_buffer.bitmap[column + 0] = ram_[pattern_name_address_ & AddressT(start + 0)]; + line_buffer.bitmap[column + 1] = ram_[pattern_name_address_ & AddressT(start + 1)]; + line_buffer.bitmap[column + 2] = ram_[pattern_name_address_ & AddressT(start + 2)]; + line_buffer.bitmap[column + 3] = ram_[pattern_name_address_ & AddressT(start + 3)]; } break; case ScreenMode::YamahaGraphics6: @@ -502,14 +502,14 @@ template void Base::fetch_yamaha([[maybe_unused]] const int start = (y << 7) | column | 0x1'8000; // Fetch from alternate banks. - line_buffer.bitmap[column + 0] = ram_[rotated_name_ & (start + 0)]; - line_buffer.bitmap[column + 1] = ram2[rotated_name_ & (start + 0)]; - line_buffer.bitmap[column + 2] = ram_[rotated_name_ & (start + 1)]; - line_buffer.bitmap[column + 3] = ram2[rotated_name_ & (start + 1)]; - line_buffer.bitmap[column + 4] = ram_[rotated_name_ & (start + 2)]; - line_buffer.bitmap[column + 5] = ram2[rotated_name_ & (start + 2)]; - line_buffer.bitmap[column + 6] = ram_[rotated_name_ & (start + 3)]; - line_buffer.bitmap[column + 7] = ram2[rotated_name_ & (start + 3)]; + line_buffer.bitmap[column + 0] = ram_[rotated_name_ & AddressT(start + 0)]; + line_buffer.bitmap[column + 1] = ram2[rotated_name_ & AddressT(start + 0)]; + line_buffer.bitmap[column + 2] = ram_[rotated_name_ & AddressT(start + 1)]; + line_buffer.bitmap[column + 3] = ram2[rotated_name_ & AddressT(start + 1)]; + line_buffer.bitmap[column + 4] = ram_[rotated_name_ & AddressT(start + 2)]; + line_buffer.bitmap[column + 5] = ram2[rotated_name_ & AddressT(start + 2)]; + line_buffer.bitmap[column + 6] = ram_[rotated_name_ & AddressT(start + 3)]; + line_buffer.bitmap[column + 7] = ram2[rotated_name_ & AddressT(start + 3)]; } break; default: