From c33f141c53f8f167a3172768b8a42e895f6dfa19 Mon Sep 17 00:00:00 2001 From: Tauwasser Date: Sat, 22 Jul 2017 18:40:09 +0200 Subject: gameboy: fix SGB VRAM transfers (#2504) * gameboy.xml: remove misleading comment Sachen 4B-003 was recently added Signed-off-by: Tauwasser * gameboy: fix Super Game Boy VRAM transfer A basic implementation of VRAM transfer. It fixes a number of games and removes the SGB border hack. However, it's very likely that the bahvior is much more complex. The old implementation was good enough for the majority of games, so this should suffice until such time when SGB is implemented on top of SNES. The attribute data was resized to 4096 bytes, so a whole VRAM transfer can take place even though only 4050 bytes are used. The idea is that the whole 4096 bytes are _probably_ transferred to WRAM and a game might theoretically upload a small executable and use that data. However, running native SNES code is currently unsupported anyway. Signed-off-by: Tauwasser * gameboy: various code style/comment fixes - return GB_MBC_NONE instead of magic 0 value - add MLT_REQ case in sgb code and mention where it's actually handled - add PAL_PRI to list of known SGB commands (not implemented) - fix two comments Signed-off-by: Tauwasser * gameboy: coding style fixes for gb_lcd Signed-off-by: Tauwasser --- hash/gameboy.xml | 2 - src/devices/bus/gameboy/gb_slot.cpp | 9 +--- src/devices/bus/gameboy/gb_slot.h | 5 -- src/devices/video/gb_lcd.cpp | 97 ++++++++++++++++++++++--------------- src/devices/video/gb_lcd.h | 10 ++-- src/mame/machine/gb.cpp | 68 ++++++++++++-------------- 6 files changed, 94 insertions(+), 97 deletions(-) diff --git a/hash/gameboy.xml b/hash/gameboy.xml index 12513bd76e7..93a0b551437 100644 --- a/hash/gameboy.xml +++ b/hash/gameboy.xml @@ -24963,8 +24963,6 @@ - - 4 in 1 (Euro, 4B-004) 19?? diff --git a/src/devices/bus/gameboy/gb_slot.cpp b/src/devices/bus/gameboy/gb_slot.cpp index 74a6a605a4a..7ce626e67c7 100644 --- a/src/devices/bus/gameboy/gb_slot.cpp +++ b/src/devices/bus/gameboy/gb_slot.cpp @@ -141,7 +141,6 @@ gb_cart_slot_device_base::gb_cart_slot_device_base(const machine_config &mconfig device_t(mconfig, type, tag, owner, clock), device_image_interface(mconfig, *this), device_slot_interface(mconfig, *this), - m_sgb_hack(0), m_type(GB_MBC_UNKNOWN), m_cart(nullptr) { @@ -227,7 +226,7 @@ static int gb_get_pcb_id(const char *slot) return elem.pcb_id; } - return 0; + return GB_MBC_NONE; } static const char *gb_get_slot(int type) @@ -386,12 +385,6 @@ image_init_result gb_cart_slot_device_base::call_load() internal_header_logging(ROM + offset, len); - // Hack to support Donkey Kong Land 2 + 3 in SGB - // For some reason, these store the tile data differently. Hacks will go once it's been figured out - if (strncmp((const char*)(ROM + 0x134), "DONKEYKONGLAND 2", 16) == 0 || - strncmp((const char*)(ROM + 0x134), "DONKEYKONGLAND 3", 16) == 0) - m_sgb_hack = 1; - return image_init_result::PASS; } diff --git a/src/devices/bus/gameboy/gb_slot.h b/src/devices/bus/gameboy/gb_slot.h index c1b786602e6..3ee8d27d4e0 100644 --- a/src/devices/bus/gameboy/gb_slot.h +++ b/src/devices/bus/gameboy/gb_slot.h @@ -127,8 +127,6 @@ public: static int get_cart_type(const uint8_t *ROM, uint32_t len); static bool get_mmm01_candidate(const uint8_t *ROM, uint32_t len); static bool is_mbc1col_game(const uint8_t *ROM, uint32_t len); - // remove me when SGB is properly emulated - int get_sgb_hack() { return m_sgb_hack; } void setup_ram(uint8_t banks); void internal_header_logging(uint8_t *ROM, uint32_t len); @@ -156,9 +154,6 @@ public: protected: gb_cart_slot_device_base(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock); - // Donkey Kong Land 2 + 3 store SGB border tiles differently... this will be hopefully be removed when SGB is properly emulated! - int m_sgb_hack; - int m_type; device_gb_cart_interface* m_cart; }; diff --git a/src/devices/video/gb_lcd.cpp b/src/devices/video/gb_lcd.cpp index 953e0e88165..9a9e9eba62c 100644 --- a/src/devices/video/gb_lcd.cpp +++ b/src/devices/video/gb_lcd.cpp @@ -12,7 +12,7 @@ Improvements to match real hardware Wilbert Pol 2006-2008 Timing is not accurate enough: - - Mode 3 takes 172 cycles (measuered with logic analyzer by costis) + - Mode 3 takes 172 cycles (measured with logic analyzer by costis) The following timing of the first frame when the LCD is turned on, is with no sprites being displayed. If sprites are displayed then the timing of mode @@ -322,7 +322,6 @@ dmg_ppu_device::dmg_ppu_device(const machine_config &mconfig, device_type type, : device_t(mconfig, type, tag, owner, clock) , device_video_interface(mconfig, *this) , m_lr35902(*this, finder_base::DUMMY_TAG) - , m_sgb_border_hack(0) , m_enable_experimental_engine(false) , m_oam_size(0x100) , m_vram_size(vram_size) @@ -1395,19 +1394,8 @@ void sgb_ppu_device::refresh_border() pal = 1; pal <<= 4; - if (m_sgb_border_hack) - { /* A few games do weird stuff */ - uint8_t tileno = map[xidx]; - if (tileno >= 128) tileno = ((64 + tileno) % 128) + 128; - else tileno = (64 + tileno) % 128; - data = tiles[tileno * 32] | (tiles[(tileno * 32) + 1] << 8); - data2 = tiles2[tileno * 32] | (tiles2[(tileno * 32) + 1] << 8); - } - else - { - data = tiles[map[xidx] * 32] | (tiles[(map[xidx] * 32) + 1] << 8); - data2 = tiles2[map[xidx] * 32] | (tiles2[(map[xidx] * 32) + 1] << 8); - } + data = tiles[map[xidx] * 32] | (tiles[(map[xidx] * 32) + 1] << 8); + data2 = tiles2[map[xidx] * 32] | (tiles2[(map[xidx] * 32) + 1] << 8); for (int i = 0; i < 8; i++) { @@ -3508,6 +3496,44 @@ WRITE8_MEMBER(cgb_ppu_device::video_w) // Super Game Boy +/* Super Game Boys transfer VRAM data using the display signals. + * That means not DMG VRAM is copied from 0x8800 to SNES VRAM + * but displayed BG contents. + * Things to consider: LCDC (0xFF40) and SCY/SCX (0xFF42/3) + * - LCD must be on + * - TODO: Window might or might not influence result + * - CHR and BG likely influence result + * - BG must be on + * - BG should not be scrolled, but likely does influence transfer + * - TODO: are BG attributes (hflip, vflip) ignored? + */ +/** + * Copy DMG VRAM data to SGM VRAM + * @param dst Destination Pointer + * @param start Logical Start Tile index inside display area. + * @param num_tiles Number of DMG tiles (0x10u bytes) to copy. + */ +void sgb_ppu_device::sgb_vram_memcpy(uint8_t *dst, uint8_t start, size_t num_tiles) { + + uint16_t bg_ix = (start / 0x14u) * 0x20u + (start % 0x14u); + const uint8_t* const map = m_layer[0].bg_map; + const uint8_t* const tiles = m_layer[0].bg_tiles; + const uint8_t mod = m_gb_tile_no_mod; + + for (size_t i = 0x00u; i < num_tiles && i < 0x100u; ++i) { + + const uint8_t tile_ix = map[bg_ix] ^ mod; + memcpy(dst, &tiles[tile_ix << 4], 0x10u); + dst += 0x10u; + + ++bg_ix; + if ((bg_ix & 0x1Fu) == 0x14u) { + bg_ix += 0x20u - 0x14u; /* advance to next start of line */ + } + + } +} + void sgb_ppu_device::sgb_io_write_pal(int offs, uint8_t *data) { switch (offs) @@ -3819,40 +3845,34 @@ void sgb_ppu_device::sgb_io_write_pal(int offs, uint8_t *data) case 0x10: /* DATA_TRN */ /* Not Implemented */ break; + case 0x11: /* MLT_REQ */ + /* MLT_REQ currently handled inside gb.cpp logic */ + break; case 0x12: /* JUMP */ /* Not Implemented */ break; case 0x13: /* CHR_TRN */ - if (data[1] & 0x1) - memcpy(m_sgb_tile_data.get() + 4096, m_vram.get() + 0x0800, 4096); + if (data[1] & 0x01u) + sgb_vram_memcpy(m_sgb_tile_data.get() + 0x1000u, 0x00u, 0x100u); else - memcpy(m_sgb_tile_data.get(), m_vram.get() + 0x0800, 4096); + sgb_vram_memcpy(m_sgb_tile_data.get(), 0x00u, 0x100u); break; case 0x14: /* PCT_TRN */ { uint16_t col; - if (m_sgb_border_hack) - { - memcpy(m_sgb_tile_map, m_vram.get() + 0x1000, 2048); - for (int i = 0; i < 64; i++) - { - col = (m_vram[0x0800 + (i * 2) + 1 ] << 8) | m_vram[0x0800 + (i * 2)]; - m_sgb_pal[SGB_BORDER_PAL_OFFSET + i] = col; - } - } - else /* Do things normally */ + uint8_t sgb_pal[0x80u]; + + sgb_vram_memcpy(m_sgb_tile_map, 0x00u, 0x80u); + sgb_vram_memcpy(sgb_pal, 0x80u, 0x08u); + for (int i = 0; i < 4 * 16 /* 4 pals at 16 colors each */; i++) { - memcpy(m_sgb_tile_map, m_vram.get() + 0x0800, 2048); - for (int i = 0; i < 64; i++) - { - col = (m_vram[0x1000 + (i * 2) + 1] << 8) | m_vram[0x1000 + (i * 2)]; - m_sgb_pal[SGB_BORDER_PAL_OFFSET + i] = col; - } + col = (sgb_pal[(i * 2) + 1] << 8) | sgb_pal[i * 2]; + m_sgb_pal[SGB_BORDER_PAL_OFFSET + i] = col; } } break; case 0x15: /* ATTR_TRN */ - memcpy(m_sgb_atf_data, m_vram.get() + 0x0800, 4050); + sgb_vram_memcpy(m_sgb_atf_data, 0x00u, 0x100u); break; case 0x16: /* ATTR_SET */ { @@ -3876,11 +3896,10 @@ void sgb_ppu_device::sgb_io_write_pal(int offs, uint8_t *data) m_sgb_window_mask = data[1]; break; case 0x18: /* OBJ_TRN */ - /* Not Implemnted */ + /* Not Implemented */ break; - case 0x19: /* ? */ - /* Called by: dkl,dkl2,dkl3,zeldadx - But I don't know what it is for. */ + case 0x19: /* PAL_PRI */ + /* Called by: dkl,dkl2,dkl3,zeldadx */ /* Not Implemented */ break; case 0x1E: /* Used by bootrom to transfer the gb cart header */ diff --git a/src/devices/video/gb_lcd.h b/src/devices/video/gb_lcd.h index 974e2d76cab..42df9c07e00 100644 --- a/src/devices/video/gb_lcd.h +++ b/src/devices/video/gb_lcd.h @@ -32,9 +32,6 @@ public: virtual DECLARE_READ8_MEMBER(video_r); virtual DECLARE_WRITE8_MEMBER(video_w); - // FIXME: remove it when proper sgb support is added - void set_sgb_hack(bool val) { m_sgb_border_hack = val ? 1 : 0; } - virtual void update_state(); protected: @@ -90,7 +87,7 @@ protected: // state variables bitmap_ind16 m_bitmap; - uint8_t m_sgb_atf_data[4050]; /* (SGB) Attributes files */ + uint8_t m_sgb_atf_data[4096]; /* (SGB) Attributes files 4050 bytes, but it's in WRAM, because 4k is transferred */ uint32_t m_sgb_atf; uint16_t m_sgb_pal_data[4096]; uint8_t m_sgb_pal_map[20][18]; @@ -99,9 +96,6 @@ protected: uint8_t m_sgb_tile_map[2048]; uint8_t m_sgb_window_mask; - // this is temporarily needed for a bunch of games which draw the border differently... - int m_sgb_border_hack; - int m_window_lines_drawn; static constexpr unsigned NR_GB_VID_REGS = 0x40; @@ -262,6 +256,8 @@ protected: virtual void update_sprites() override; virtual void update_scanline(uint32_t cycles_to_go) override; void refresh_border(); + + void sgb_vram_memcpy(uint8_t *dst, uint8_t start, size_t num_tiles); }; diff --git a/src/mame/machine/gb.cpp b/src/mame/machine/gb.cpp index 713f4f4f9d5..0cc70ba6a17 100644 --- a/src/mame/machine/gb.cpp +++ b/src/mame/machine/gb.cpp @@ -190,10 +190,6 @@ MACHINE_START_MEMBER(gb_state,sgb) save_gb_base(); save_sgb_only(); - - if (m_cartslot && m_cartslot->get_sgb_hack()) { - dynamic_cast(m_ppu.target())->set_sgb_hack(true); - } } void gb_state::machine_reset() @@ -323,38 +319,38 @@ WRITE8_MEMBER(gb_state::gb_io2_w) #ifdef MAME_DEBUG static const char *const sgbcmds[32] = { - "PAL01 ", - "PAL23 ", - "PAL03 ", - "PAL12 ", - "ATTR_BLK", - "ATTR_LIN", - "ATTR_DIV", - "ATTR_CHR", - "SOUND ", - "SOU_TRN ", - "PAL_SET ", - "PAL_TRN ", - "ATRC_EN ", - "TEST_EN ", - "ICON_EN ", - "DATA_SND", - "DATA_TRN", - "MLT_REG ", - "JUMP ", - "CHR_TRN ", - "PCT_TRN ", - "ATTR_TRN", - "ATTR_SET", - "MASK_EN ", - "OBJ_TRN ", - "????????", - "????????", - "????????", - "????????", - "????????", - "????????", - "????????" + /* 0x00 */ "PAL01 ", + /* 0x01 */ "PAL23 ", + /* 0x02 */ "PAL03 ", + /* 0x03 */ "PAL12 ", + /* 0x04 */ "ATTR_BLK", + /* 0x05 */ "ATTR_LIN", + /* 0x06 */ "ATTR_DIV", + /* 0x07 */ "ATTR_CHR", + /* 0x08 */ "SOUND ", + /* 0x09 */ "SOU_TRN ", + /* 0x0A */ "PAL_SET ", + /* 0x0B */ "PAL_TRN ", + /* 0x0C */ "ATRC_EN ", + /* 0x0D */ "TEST_EN ", + /* 0x0E */ "ICON_EN ", + /* 0x0F */ "DATA_SND", + /* 0x10 */ "DATA_TRN", + /* 0x11 */ "MLT_REG ", + /* 0x12 */ "JUMP ", + /* 0x13 */ "CHR_TRN ", + /* 0x14 */ "PCT_TRN ", + /* 0x15 */ "ATTR_TRN", + /* 0x16 */ "ATTR_SET", + /* 0x17 */ "MASK_EN ", + /* 0x18 */ "OBJ_TRN ", + /* 0x19 */ "PAL_PRI ", + /* 0x1A */ "????????", + /* 0x1B */ "????????", + /* 0x1C */ "????????", + /* 0x1D */ "????????", + /* 0x1E */ "????????", + /* 0x1F */ "????????" }; #endif -- cgit v1.2.3