diff options
Diffstat (limited to 'src/devices/machine/spg110.cpp')
-rw-r--r-- | src/devices/machine/spg110.cpp | 387 |
1 files changed, 241 insertions, 146 deletions
diff --git a/src/devices/machine/spg110.cpp b/src/devices/machine/spg110.cpp index 4762a0c01cc..01ec544d52b 100644 --- a/src/devices/machine/spg110.cpp +++ b/src/devices/machine/spg110.cpp @@ -5,7 +5,9 @@ SunPlus SPG110-series SoC peripheral emulation 0032xx looks like it could be the same as 003dxx on spg2xx - but the video seems quite different? + but the video seems to have differences, and data + is fetched from private buffers filled by DMA instead of + main space? tile attributes different? palette format different **********************************************************************/ @@ -21,36 +23,136 @@ spg110_device::spg110_device(const machine_config &mconfig, device_type type, co m_cpu(*this, finder_base::DUMMY_TAG), m_palette(*this, "palette"), m_gfxdecode(*this, "gfxdecode"), - m_bg_videoram(*this, "bg_videoram"), - m_fg_videoram(*this, "fg_videoram"), - m_bg_attrram(*this, "bg_attrram"), - m_fg_attrram(*this, "fg_attrram"), m_palram(*this, "palram") { } -WRITE16_MEMBER(spg110_device::bg_videoram_w) +template<spg110_device::flipx_t FlipX> +void spg110_device::blit(const rectangle &cliprect, uint32_t line, uint32_t xoff, uint32_t yoff, uint32_t attr, uint32_t ctrl, uint32_t bitmap_addr, uint16_t tile) { - COMBINE_DATA(&m_bg_videoram[offset]); - m_bg_tilemap->mark_tile_dirty(offset); -} + address_space &space = m_cpu->space(AS_PROGRAM); -WRITE16_MEMBER(spg110_device::fg_videoram_w) -{ - COMBINE_DATA(&m_fg_videoram[offset]); - m_fg_tilemap->mark_tile_dirty(offset); -} + int32_t h = 8 << ((attr & PAGE_TILE_HEIGHT_MASK) >> PAGE_TILE_HEIGHT_SHIFT); + int32_t w = 8 << ((attr & PAGE_TILE_WIDTH_MASK) >> PAGE_TILE_WIDTH_SHIFT); -WRITE16_MEMBER(spg110_device::bg_attrram_w) -{ - COMBINE_DATA(&m_bg_attrram[offset]); - m_bg_tilemap->mark_tile_dirty(offset/2); + uint32_t yflipmask = attr & TILE_Y_FLIP ? h - 1 : 0; + + uint32_t nc = ((attr & 0x0003) + 1) << 1; + + uint32_t palette_offset = (attr & 0x0f00) >> 4; + + palette_offset >>= nc; + palette_offset <<= nc; + + uint32_t bits_per_row = nc * w / 16; + uint32_t words_per_tile = bits_per_row * h; + uint32_t m = bitmap_addr + words_per_tile * tile + bits_per_row * (line ^ yflipmask); + uint32_t bits = 0; + uint32_t nbits = 0; + uint32_t y = line; + + int yy = (yoff + y) & 0x1ff; + if (yy >= 0x01c0) + yy -= 0x0200; + + if (yy > 240 || yy < 0) + return; + + int y_index = yy * 320; + + for (int32_t x = FlipX ? (w - 1) : 0; FlipX ? x >= 0 : x < w; FlipX ? x-- : x++) + { + int xx = xoff + x; + + bits <<= nc; + + if (nbits < nc) + { + uint16_t b = space.read_word(m++ & 0x3fffff); + //b = (b << 8) | (b >> 8); + bits |= b << (nc - nbits); + nbits += 16; + } + nbits -= nc; + + uint32_t pal = palette_offset + (bits >> 16); + bits &= 0xffff; + + xx &= 0x01ff; + if (xx >= 0x01c0) + xx -= 0x0200; + + if (xx >= 0 && xx < 320) + { + // TODO, this is completely wrong for this palette system + int pix_index = xx + y_index; + uint16_t rawpal = m_palram[pal]; + const pen_t *pens = m_palette->pens(); + uint32_t paldata = pens[pal]; + + if (!(rawpal & 0x8000)) + { + m_screenbuf[pix_index] = paldata; + } + } + } } -WRITE16_MEMBER(spg110_device::fg_attrram_w) +void spg110_device::blit_page(const rectangle &cliprect, uint32_t scanline, int depth, uint32_t bitmap_addr, uint16_t *regs) { - COMBINE_DATA(&m_fg_attrram[offset]); - m_fg_tilemap->mark_tile_dirty(offset/2); + uint32_t xscroll = regs[0]; + uint32_t yscroll = regs[1]; + uint32_t attr = regs[2]; + uint32_t ctrl = regs[3]; + uint32_t tilemap = regs[4]; + uint32_t palette_map = regs[5]; + address_space &space2 = this->space(0); + + if (!(ctrl & PAGE_ENABLE_MASK)) + { + return; + } + + if (((attr & PAGE_DEPTH_FLAG_MASK) >> PAGE_DEPTH_FLAG_SHIFT) != depth) + { + return; + } + + uint32_t tile_h = 8 << ((attr & PAGE_TILE_HEIGHT_MASK) >> PAGE_TILE_HEIGHT_SHIFT); + uint32_t tile_w = 8 << ((attr & PAGE_TILE_WIDTH_MASK) >> PAGE_TILE_WIDTH_SHIFT); + + uint32_t tile_count_x = 512 / tile_w; + + uint32_t bitmap_y = (scanline + yscroll) & 0xff; + uint32_t y0 = bitmap_y / tile_h; + uint32_t tile_scanline = bitmap_y % tile_h; + uint32_t tile_address = tile_count_x * y0; + + for (uint32_t x0 = 0; x0 < tile_count_x; x0++, tile_address++) + { + uint32_t yy = ((tile_h * y0 - yscroll + 0x10) & 0xff) - 0x10; + uint32_t xx = (tile_w * x0 - xscroll) & 0x1ff; + uint16_t tile = (ctrl & PAGE_WALLPAPER_MASK) ? space2.read_word(tilemap*2) : space2.read_word((tilemap + tile_address)*2); + uint16_t palette = 0; + + if (!tile) + continue; + + palette = space2.read_word(palette_map + tile_address / 2); + if (x0 & 1) + palette = (palette & 0xff00) >> 8; + else + palette = (palette & 0x00ff); + + + bool flip_x = 0;//(tileattr & TILE_X_FLIP); + + if (flip_x) + blit<FlipXOn>(cliprect, tile_scanline, xx, yy, attr, ctrl, bitmap_addr, tile); + else + blit<FlipXOff>(cliprect, tile_scanline, xx, yy, attr, ctrl, bitmap_addr, tile); + + } } @@ -166,18 +268,7 @@ WRITE16_MEMBER(spg110_device::spg110_3221_w) WRITE16_MEMBER(spg110_device::spg110_3223_w) { } WRITE16_MEMBER(spg110_device::spg110_3225_w) { } -WRITE16_MEMBER(spg110_device::spg110_bg_scrollx_w) { COMBINE_DATA(&m_bg_scrollx); } -WRITE16_MEMBER(spg110_device::spg110_bg_scrolly_w) { COMBINE_DATA(&m_bg_scrolly); } -WRITE16_MEMBER(spg110_device::spg110_2012_w) { } -WRITE16_MEMBER(spg110_device::spg110_2013_w) { } -WRITE16_MEMBER(spg110_device::spg110_2014_w) { } -WRITE16_MEMBER(spg110_device::spg110_2015_w) { } -WRITE16_MEMBER(spg110_device::spg110_2016_w) { } -WRITE16_MEMBER(spg110_device::spg110_2017_w) { } -WRITE16_MEMBER(spg110_device::spg110_2018_w) { } -WRITE16_MEMBER(spg110_device::spg110_2019_w) { } -WRITE16_MEMBER(spg110_device::spg110_201a_w) { } -WRITE16_MEMBER(spg110_device::spg110_201b_w) { } + WRITE16_MEMBER(spg110_device::spg110_201c_w) { } WRITE16_MEMBER(spg110_device::spg110_2020_w) { } WRITE16_MEMBER(spg110_device::spg110_2042_w) { } @@ -218,66 +309,44 @@ WRITE16_MEMBER(spg110_device::spg110_205d_w) { } WRITE16_MEMBER(spg110_device::spg110_205e_w) { } WRITE16_MEMBER(spg110_device::spg110_205f_w) { } -WRITE16_MEMBER(spg110_device::spg110_2061_w) { COMBINE_DATA(&m_2061_outer); } -WRITE16_MEMBER(spg110_device::spg110_2064_w) { COMBINE_DATA(&m_2064_outer); } -WRITE16_MEMBER(spg110_device::spg110_2067_w) { COMBINE_DATA(&m_2067_outer); } -WRITE16_MEMBER(spg110_device::spg110_2068_w) { COMBINE_DATA(&m_2068_outer); } - -WRITE16_MEMBER(spg110_device::spg110_2060_w) { COMBINE_DATA(&m_2060_inner); } -WRITE16_MEMBER(spg110_device::spg110_2066_w) { COMBINE_DATA(&m_2066_inner); } +WRITE16_MEMBER(spg110_device::dma_unk_2061_w) { COMBINE_DATA(&m_dma_unk_2061); } +WRITE16_MEMBER(spg110_device::dma_dst_step_w) { COMBINE_DATA(&m_dma_dst_step); } +WRITE16_MEMBER(spg110_device::dma_unk_2067_w) { COMBINE_DATA(&m_dma_unk_2067); } +WRITE16_MEMBER(spg110_device::dma_src_step_w) { COMBINE_DATA(&m_dma_src_step); } +WRITE16_MEMBER(spg110_device::dma_dst_w) { COMBINE_DATA(&m_dma_dst); } +WRITE16_MEMBER(spg110_device::dma_src_w) { COMBINE_DATA(&m_dma_src); } -WRITE16_MEMBER(spg110_device::spg110_2062_w) +WRITE16_MEMBER(spg110_device::dma_len_trigger_w) { -// int length = (data - 1) & 0xff; int length = data & 0x1fff; // this is presumably a counter that underflows to 0x1fff, because that's what the wait loop waits for? - logerror("%s: trigger (%04x) with values (written outer) %04x %04x %04x %04x | (written inner) %04x (ram source?) %04x\n", machine().describe_context(), data, m_2061_outer, m_2064_outer, m_2067_outer, m_2068_outer, m_2060_inner, m_2066_inner); + logerror("%s: (trigger len) %04x with values (unk) %04x (dststep) %04x (unk) %04x (src step) %04x | (dst) %04x (src) %04x\n", machine().describe_context(), data, m_dma_unk_2061, m_dma_dst_step, m_dma_unk_2067, m_dma_src_step, m_dma_dst, m_dma_src); - int source = m_2066_inner; - int dest = m_2060_inner; + if ((m_dma_unk_2061!=0x0000) || (m_dma_unk_2067 != 0x0000)) + fatalerror("unknown DMA params are not zero!\n"); + + int source = m_dma_src; + int dest = m_dma_dst; - // maybe - /* - if (!(m_2068_outer & 1)) - { - length = length * 4; - } - */ - //logerror("[ "); for (int i = 0; i < length; i++) { - if (m_2068_outer & 1) - { - address_space &mem = m_cpu->space(AS_PROGRAM); - uint16_t val = mem.read_word(m_2066_inner + i); + address_space &mem = m_cpu->space(AS_PROGRAM); + uint16_t val = mem.read_word(source); - this->space(0).write_word(dest * 2, val, 0xffff); - } - else // guess, it needs to clear layers somehow - { - // is there a fill mode to fill other values? - this->space(0).write_word(dest * 2, 0x0000, 0xffff); - } - - source++; - // m_2064_outer is usually 1, but sometimes 0x20/0x40 - dest+=m_2064_outer; - - // logerror("%04x, ", val); + this->space(0).write_word(dest * 2, val, 0xffff); + + source+=m_dma_src_step; + dest+=m_dma_dst_step; } - // logerror(" ]\n"); } -READ16_MEMBER(spg110_device::spg110_2062_r) +READ16_MEMBER(spg110_device::dma_len_status_r) { return 0x1fff; // DMA related? } - -READ16_MEMBER(spg110_device::spg110_2013_r) { return 0x0000; } -READ16_MEMBER(spg110_device::spg110_2019_r) { return 0x0000; } READ16_MEMBER(spg110_device::spg110_2037_r) { return 0x0000; } READ16_MEMBER(spg110_device::spg110_2042_r) { return 0x0000; } @@ -308,24 +377,70 @@ WRITE16_MEMBER(spg110_device::spg110_310d_w) { } READ16_MEMBER(spg110_device::spg110_310f_r) { return 0x0000; } +READ16_MEMBER(spg110_device::tmap0_regs_r) { return tmap0_regs[offset]; } +READ16_MEMBER(spg110_device::tmap1_regs_r) { return tmap1_regs[offset]; } + +void spg110_device::tilemap_write_regs(int which, uint16_t* regs, int regno, uint16_t data) +{ + switch (regno) + { + case 0x0: // Page X scroll + logerror("video_w: Page %d X Scroll = %04x\n", which, data & 0x01ff); + regs[regno] = data & 0x01ff; + break; + + case 0x1: // Page Y scroll + logerror("video_w: Page %d Y Scroll = %04x\n", which, data & 0x00ff); + regs[regno] = data & 0x00ff; + break; + + case 0x2: // Page Attributes + // 'depth' (aka z value) can't be depth here as it is on spg2xx, or the scores in attract will be behind the table, it really seems to be per attribute bit instead + + logerror("video_w: Page %d Attributes = %04x (Depth:%d, Palette:%d, VSize:%d, HSize:%d, FlipY:%d, FlipX:%d, BPP:%d)\n", which, data + , (data >> 12) & 3, (data >> 8) & 15, 8 << ((data >> 6) & 3), 8 << ((data >> 4) & 3), BIT(data, 3), BIT(data, 2), 2 * ((data & 3) + 1)); + regs[regno] = data; + break; + + case 0x3: // Page Control + logerror("video_w: Page %d Control = %04x (Blend:%d, HiColor:%d, RowScroll:%d, Enable:%d, Wallpaper:%d, RegSet:%d, Bitmap:%d)\n", which, data + , BIT(data, 8), BIT(data, 7), BIT(data, 4), BIT(data, 3), BIT(data, 2), BIT(data, 1), BIT(data, 0)); + regs[regno] = data; + break; + + case 0x4: // Page Tile Address + logerror("video_w: Page %d Tile Address = %04x\n", which, data); + regs[regno] = data; + break; + + case 0x5: // Page Attribute Address + logerror("video_w: Page %d Attribute Address = %04x\n", which, data); + regs[regno] = data; + break; + } +} + + +WRITE16_MEMBER(spg110_device::tmap0_regs_w) +{ + tilemap_write_regs(0, tmap0_regs,offset,data); +} + + +WRITE16_MEMBER(spg110_device::tmap1_regs_w) +{ + tilemap_write_regs(1, tmap1_regs,offset,data); +} + void spg110_device::map(address_map &map) { map(0x000000, 0x000fff).ram(); // vregs are at 2000? - map(0x002010, 0x002010).w(FUNC(spg110_device::spg110_bg_scrollx_w)); - map(0x002011, 0x002011).w(FUNC(spg110_device::spg110_bg_scrolly_w)); - map(0x002012, 0x002012).w(FUNC(spg110_device::spg110_2012_w)); - map(0x002013, 0x002013).rw(FUNC(spg110_device::spg110_2013_r),FUNC(spg110_device::spg110_2013_w)); - map(0x002014, 0x002014).w(FUNC(spg110_device::spg110_2014_w)); - map(0x002015, 0x002015).w(FUNC(spg110_device::spg110_2015_w)); - map(0x002016, 0x002016).w(FUNC(spg110_device::spg110_2016_w)); - map(0x002017, 0x002017).w(FUNC(spg110_device::spg110_2017_w)); - map(0x002018, 0x002018).w(FUNC(spg110_device::spg110_2018_w)); - map(0x002019, 0x002019).rw(FUNC(spg110_device::spg110_2019_r), FUNC(spg110_device::spg110_2019_w)); - map(0x00201a, 0x00201a).w(FUNC(spg110_device::spg110_201a_w)); - map(0x00201b, 0x00201b).w(FUNC(spg110_device::spg110_201b_w)); + map(0x002010, 0x002015).rw(FUNC(spg110_device::tmap0_regs_r), FUNC(spg110_device::tmap0_regs_w)); + map(0x002016, 0x00201b).rw(FUNC(spg110_device::tmap1_regs_r), FUNC(spg110_device::tmap1_regs_w)); + map(0x00201c, 0x00201c).w(FUNC(spg110_device::spg110_201c_w)); map(0x002020, 0x002020).w(FUNC(spg110_device::spg110_2020_w)); @@ -372,14 +487,14 @@ void spg110_device::map(address_map &map) //map(0x002010, 0x00205f).ram(); // everything (dma? and interrupt flag?!) - map(0x002060, 0x002060).w(FUNC(spg110_device::spg110_2060_w)); - map(0x002061, 0x002061).w(FUNC(spg110_device::spg110_2061_w)); - map(0x002062, 0x002062).rw(FUNC(spg110_device::spg110_2062_r),FUNC(spg110_device::spg110_2062_w)); + map(0x002060, 0x002060).w(FUNC(spg110_device::dma_dst_w)); + map(0x002061, 0x002061).w(FUNC(spg110_device::dma_unk_2061_w)); + map(0x002062, 0x002062).rw(FUNC(spg110_device::dma_len_status_r),FUNC(spg110_device::dma_len_trigger_w)); map(0x002063, 0x002063).rw(FUNC(spg110_device::spg110_2063_r),FUNC(spg110_device::spg110_2063_w)); // this looks like interrupt stuff and is checked in the irq like an irq source, but why in the middle of what otherwise look like some kind of DMA? - map(0x002064, 0x002064).w(FUNC(spg110_device::spg110_2064_w)); - map(0x002066, 0x002066).w(FUNC(spg110_device::spg110_2066_w)); - map(0x002067, 0x002067).w(FUNC(spg110_device::spg110_2067_w)); - map(0x002068, 0x002068).w(FUNC(spg110_device::spg110_2068_w)); + map(0x002064, 0x002064).w(FUNC(spg110_device::dma_dst_step_w)); + map(0x002066, 0x002066).w(FUNC(spg110_device::dma_src_w)); + map(0x002067, 0x002067).w(FUNC(spg110_device::dma_unk_2067_w)); + map(0x002068, 0x002068).w(FUNC(spg110_device::dma_src_step_w)); map(0x002200, 0x0022ff).ram(); // looks like per-pen brightness or similar? strange because palette isn't memory mapped here @@ -428,10 +543,7 @@ void spg110_device::map(address_map &map) void spg110_device::map_video(address_map &map) { // are these addresses hardcoded, or can they move (in which case tilemap system isn't really suitable) - map(0x00000, 0x00fff).ram().w(FUNC(spg110_device::bg_videoram_w)).share("bg_videoram"); - map(0x01000, 0x017ff).ram().w(FUNC(spg110_device::bg_attrram_w)).share("bg_attrram"); - map(0x01800, 0x027ff).ram().w(FUNC(spg110_device::fg_videoram_w)).share("fg_videoram"); - map(0x02800, 0x02fff).ram().w(FUNC(spg110_device::fg_attrram_w)).share("fg_attrram"); + map(0x00000, 0x03fff).ram(); // 2fff? map(0x04000, 0x04fff).ram(); // seems to be 3 blocks, almost certainly spritelist @@ -447,46 +559,17 @@ TIMER_CALLBACK_MEMBER(spg110_device::test_timer) } */ -TILE_GET_INFO_MEMBER(spg110_device::get_bg_tile_info) -{ - int tileno = m_bg_videoram[tile_index]; - - int attr = m_bg_attrram[tile_index/2]; - if (tile_index&1) attr = (attr & 0xff00)>>8; - else attr = attr & 0x00ff; - - SET_TILE_INFO_MEMBER(3, tileno, 0, 0); - tileinfo.category = (attr >> 4) & 0x0f; // very likely wrong, complete guess - -} - -TILE_GET_INFO_MEMBER(spg110_device::get_fg_tile_info) -{ - int tileno = m_fg_videoram[tile_index]; - - int attr = m_fg_attrram[tile_index/2]; - if (tile_index&1) attr = (attr & 0xff00)>>8; - else attr = attr & 0x00ff; - int pal = attr & 0x0f; - - SET_TILE_INFO_MEMBER(0, tileno, pal, 0); - tileinfo.category = (attr >> 4) & 0x0f; // very likely wrong, complete guess -} void spg110_device::device_start() { // m_test_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(spg110_device::test_timer), this)); - m_bg_tilemap = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(FUNC(spg110_device::get_bg_tile_info),this), TILEMAP_SCAN_ROWS, 8, 8, 64, 32); - m_fg_tilemap = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(FUNC(spg110_device::get_fg_tile_info),this), TILEMAP_SCAN_ROWS, 8, 8, 64, 32); - m_fg_tilemap->set_transparent_pen(0); - - save_item(NAME(m_2068_outer)); - save_item(NAME(m_2064_outer)); - save_item(NAME(m_2061_outer)); - save_item(NAME(m_2067_outer)); - save_item(NAME(m_2060_inner)); - save_item(NAME(m_2066_inner)); + save_item(NAME(m_dma_src_step)); + save_item(NAME(m_dma_dst_step)); + save_item(NAME(m_dma_unk_2061)); + save_item(NAME(m_dma_unk_2067)); + save_item(NAME(m_dma_dst)); + save_item(NAME(m_dma_src)); save_item(NAME(m_bg_scrollx)); save_item(NAME(m_bg_scrolly)); save_item(NAME(m_2036_scroll)); @@ -494,12 +577,12 @@ void spg110_device::device_start() void spg110_device::device_reset() { - m_2068_outer = 0; - m_2064_outer = 0; - m_2061_outer = 0; - m_2067_outer = 0; - m_2060_inner = 0; - m_2066_inner = 0; + m_dma_src_step = 0; + m_dma_dst_step = 0; + m_dma_unk_2061 = 0; + m_dma_unk_2067 = 0; + m_dma_dst = 0; + m_dma_src = 0; m_bg_scrollx = 0; m_bg_scrolly = 0; m_2036_scroll = 0; @@ -551,18 +634,30 @@ uint32_t spg110_device::screen_update(screen_device &screen, bitmap_rgb32 &bitma m_palette->set_pen_color(index, r_real, g_real, b_real); } - m_bg_tilemap->set_scrollx(0, m_bg_scrollx); - m_bg_tilemap->set_scrolly(0, m_bg_scrolly); + memset(&m_screenbuf[320 * cliprect.min_y], 0, 4 * 320 * ((cliprect.max_y - cliprect.min_y) + 1)); - m_fg_tilemap->set_scrollx(0, 8); // where does this come from? + const uint32_t page1_addr = 0;//0x40 * m_video_regs[0x20]; + const uint32_t page2_addr = 0;//0x40 * m_video_regs[0x21]; + uint16_t *page1_regs = tmap0_regs; + uint16_t *page2_regs = tmap1_regs; - // what is 2036 used for, also looks like scrolling, maybe some sprite offset? or zoom? (reference videos suggest maybe start logo text zooms?) + for (uint32_t scanline = (uint32_t)cliprect.min_y; scanline <= (uint32_t)cliprect.max_y; scanline++) + { + for (int i = 0; i < 4; i++) + { + blit_page(cliprect, scanline, i, page2_addr, page2_regs); + blit_page(cliprect, scanline, i, page1_addr, page1_regs); + //blit_sprites(cliprect, scanline, i); + } + } - for (int pri = 0; pri < 0x10; pri++) // priority is probably not correct, this is just using a random tile attribute with single use case + for (int y = cliprect.min_y; y <= cliprect.max_y; y++) { - m_bg_tilemap->draw(screen, bitmap, cliprect, pri, pri, 0); - m_fg_tilemap->draw(screen, bitmap, cliprect, pri, pri, 0); + uint32_t *dest = &bitmap.pix32(y, cliprect.min_x); + uint32_t *src = &m_screenbuf[cliprect.min_x + 320 * y]; + memcpy(dest, src, sizeof(uint32_t) * ((cliprect.max_x - cliprect.min_x) + 1)); } + return 0; } |