gameboy: fix SGB VRAM transfers (#2504)

* gameboy.xml: remove misleading comment

Sachen 4B-003 was recently added

Signed-off-by: Tauwasser <tauwasser@tauwasser.eu>

* 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 <tauwasser@tauwasser.eu>

* 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 <tauwasser@tauwasser.eu>

* gameboy: coding style fixes for gb_lcd

Signed-off-by: Tauwasser <tauwasser@tauwasser.eu>
This commit is contained in:
Tauwasser 2017-07-22 18:40:09 +02:00 committed by ajrhacker
parent 42a9427f18
commit c33f141c53
6 changed files with 94 additions and 97 deletions

View File

@ -24963,8 +24963,6 @@
</part>
</software>
<!-- 4in1_003 missing -->
<software name="4in1_004">
<description>4 in 1 (Euro, 4B-004)</description>
<year>19??</year>

View File

@ -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;
}

View File

@ -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;
};

View File

@ -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);
}
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)
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() + 0x1000, 2048);
for (int i = 0; i < 64; i++)
{
col = (m_vram[0x0800 + (i * 2) + 1 ] << 8) | m_vram[0x0800 + (i * 2)];
col = (sgb_pal[(i * 2) + 1] << 8) | sgb_pal[i * 2];
m_sgb_pal[SGB_BORDER_PAL_OFFSET + i] = col;
}
}
else /* Do things normally */
{
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;
}
}
}
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 */

View File

@ -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);
};

View File

@ -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<sgb_ppu_device*>(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