diff --git a/Components/9918/9918.cpp b/Components/9918/9918.cpp index 51a0c6c06..f45ae1306 100644 --- a/Components/9918/9918.cpp +++ b/Components/9918/9918.cpp @@ -560,25 +560,23 @@ void TMS9918::set_register(int address, uint8_t value) { break; case 2: - pattern_name_address_ = static_cast((low_write_ & 0xf) << 10); + pattern_name_address_ = size_t((low_write_ & 0xf) << 10) | 0x3ff; break; case 3: - colour_table_address_ = static_cast(low_write_ << 6); + colour_table_address_ = size_t(low_write_ << 6) | 0x1f; break; case 4: - pattern_generator_table_address_ = static_cast((low_write_ & 0x07) << 11); + pattern_generator_table_address_ = size_t((low_write_ & 0x07) << 11) | 0x7ff; break; case 5: - sprite_attribute_table_address_ = static_cast((low_write_ & 0x7f) << 7); - if(is_sega_vdp(personality_)) sprite_attribute_table_address_ |= 0x7f; + sprite_attribute_table_address_ = size_t((low_write_ & 0x7f) << 7) | 0x7f; break; case 6: - sprite_generator_table_address_ = static_cast((low_write_ & 0x07) << 11); - if(is_sega_vdp(personality_)) sprite_generator_table_address_ |= 0x7ff; + sprite_generator_table_address_ = size_t((low_write_ & 0x07) << 11) | 0x7ff; break; case 7: @@ -605,14 +603,15 @@ void TMS9918::set_register(int address, uint8_t value) { break; default: - printf("%d to %d\n", low_write_, value); + printf("Unknown TMS write: %d to %d\n", low_write_, value); break; } } else { - // This is a write to the RAM pointer. + // This is an access via the RAM pointer. ram_pointer_ = static_cast(low_write_ | (value << 8)); if(!(value & 0x40)) { - // Officially a 'read' set, so perform lookahead. + // A read request is enqueued upon setting the address; conversely a write + // won't be enqueued unless and until some actual data is supplied. queued_access_ = MemoryAccess::Read; } master_system_.cram_is_selected = false; @@ -788,14 +787,21 @@ void Base::draw_sms(int start, int end) { pattern = *reinterpret_cast(sprite_set_.active_sprites[c].image); for(int ox = x; ox < x+8; ox++) { if(ox >= 0 && ox < 256) { - pixel_origin_[ox] = - master_system_.colour_ram[ + if( ((pattern_index[3] & 0x80) >> 4) | ((pattern_index[2] & 0x80) >> 5) | ((pattern_index[1] & 0x80) >> 6) | - ((pattern_index[0] & 0x80) >> 7) | - 0x10 - ]; + ((pattern_index[0] & 0x80) >> 7) + ) { + pixel_origin_[ox] = + master_system_.colour_ram[ + ((pattern_index[3] & 0x80) >> 4) | + ((pattern_index[2] & 0x80) >> 5) | + ((pattern_index[1] & 0x80) >> 6) | + ((pattern_index[0] & 0x80) >> 7) | + 0x10 + ]; + } } pattern <<= 1; } diff --git a/Components/9918/Implementation/9918Base.hpp b/Components/9918/Implementation/9918Base.hpp index 6cf2ecefb..992ae5026 100644 --- a/Components/9918/Implementation/9918Base.hpp +++ b/Components/9918/Implementation/9918Base.hpp @@ -276,8 +276,6 @@ class Base { void do_external_slot() { - // TODO: write or read a value if one is queued and ready to read/write. - // (and, later: update the command engine, if this is an MSX2). switch(queued_access_) { default: return; @@ -427,8 +425,8 @@ class Base { fetch_columns_4(location, column); \ fetch_columns_4(location+12, column+4); - const size_t row_base = pattern_name_address_ + static_cast(row_ >> 3) * 40; - const size_t row_offset = pattern_generator_table_address_ + (row_ & 7); + const size_t row_base = pattern_name_address_ & static_cast(row_ >> 3) * 40; + const size_t row_offset = pattern_generator_table_address_ & (row_ & 7); switch(start) { default: @@ -610,13 +608,13 @@ class Base { posit_sprite(sprite, ram_[sprite_attribute_table_address_ & (sprite | 0x3f00)], row_); \ posit_sprite(sprite+1, ram_[sprite_attribute_table_address_ & ((sprite + 1) | 0x3f00)], row_); \ -#define fetch_tile_name(column) {\ +#define fetch_tile_name(column, row_info) {\ const size_t scrolled_column = (column - horizontal_offset) & 0x1f;\ - const size_t address = pattern_address_base + (scrolled_column << 1); \ + const size_t address = row_info.pattern_address_base + (scrolled_column << 1); \ master_system_.names[column].flags = ram_[address+1]; \ master_system_.names[column].offset = static_cast( \ (((master_system_.names[column].flags&1) << 8) | ram_[address]) << 5 \ - ) + sub_row[(master_system_.names[column].flags&4) >> 2]; \ + ) + row_info.sub_row[(master_system_.names[column].flags&4) >> 2]; \ } #define fetch_tile(column) \ @@ -625,36 +623,52 @@ class Base { master_system_.tile_graphics[column][2] = ram_[master_system_.names[column].offset+2]; \ master_system_.tile_graphics[column][3] = ram_[master_system_.names[column].offset+3]; -#define background_fetch_block(location, column, sprite) \ - slot(location): fetch_tile_name(column) \ +#define background_fetch_block(location, column, sprite, row_info) \ + slot(location): fetch_tile_name(column, row_info) \ external_slot(location+1); \ slot(location+2): \ slot(location+3): \ slot(location+4): \ fetch_tile(column) \ - fetch_tile_name(column+1) \ + fetch_tile_name(column+1, row_info) \ sprite_y_read(location+5, sprite); \ slot(location+6): \ slot(location+7): \ slot(location+8): \ fetch_tile(column+1) \ - fetch_tile_name(column+2) \ + fetch_tile_name(column+2, row_info) \ sprite_y_read(location+9, sprite+2); \ slot(location+10): \ slot(location+11): \ slot(location+12): \ fetch_tile(column+2) \ - fetch_tile_name(column+3) \ + fetch_tile_name(column+3, row_info) \ sprite_y_read(location+13, sprite+4); \ slot(location+14): \ slot(location+15): fetch_tile(column+3) - const int scrolled_row = (row_ + master_system_.vertical_scroll) % 224; - - const size_t pattern_address_base = (pattern_name_address_ | size_t(0x3ff)) & static_cast(((scrolled_row & ~7) << 3) | 0x3800); - const size_t sub_row[2] = {static_cast((scrolled_row & 7) << 2), 28 ^ static_cast((scrolled_row & 7) << 2)}; + // Determine the coarse horizontal scrolling offset; this isn't applied on the first two lines if the programmer has requested it. const int horizontal_offset = (row_ >= 16 || !master_system_.horizontal_scroll_lock) ? (master_system_.horizontal_scroll >> 3) : 0; + // Determine row info for the screen both (i) if vertical scrolling is applied; and (ii) if it isn't. + // The programmer can opt out of applying vertical scrolling to the right-hand portion of the display. + const int scrolled_row = (row_ + master_system_.vertical_scroll) % 224; + struct RowInfo { + size_t pattern_address_base; + size_t sub_row[2]; + }; + const RowInfo scrolled_row_info = { + pattern_name_address_ & static_cast(((scrolled_row & ~7) << 3) | 0x3800), + {static_cast((scrolled_row & 7) << 2), 28 ^ static_cast((scrolled_row & 7) << 2)} + }; + RowInfo row_info; + if(master_system_.vertical_scroll_lock) { + row_info.pattern_address_base = pattern_name_address_ & static_cast(((row_ & ~7) << 3) | 0x3800); + row_info.sub_row[0] = size_t((row_ & 7) << 2); + row_info.sub_row[1] = 28 ^ size_t((row_ & 7) << 2); + } else row_info = scrolled_row_info; + + // ... and do the actual fetching, which follows this routine: switch(start) { default: external_slots_4(0); @@ -682,14 +696,14 @@ class Base { sprite_y_read(41, 12); sprite_y_read(42, 14); - background_fetch_block(43, 0, 16); - background_fetch_block(59, 4, 22); - background_fetch_block(75, 8, 28); - background_fetch_block(91, 12, 34); - background_fetch_block(107, 16, 40); - background_fetch_block(123, 20, 46); - background_fetch_block(139, 24, 52); // TODO: this and the next one should ignore master_system_.vertical_scroll. - background_fetch_block(156, 28, 58); + background_fetch_block(43, 0, 16, scrolled_row_info); + background_fetch_block(59, 4, 22, scrolled_row_info); + background_fetch_block(75, 8, 28, scrolled_row_info); + background_fetch_block(91, 12, 34, scrolled_row_info); + background_fetch_block(107, 16, 40, scrolled_row_info); + background_fetch_block(123, 20, 46, scrolled_row_info); + background_fetch_block(139, 24, 52, row_info); + background_fetch_block(156, 28, 58, row_info); return; }