mirror of
https://github.com/holub/mame
synced 2025-10-04 16:34:53 +03:00
spg110: tweaks for jak_capb, improves rendering, identifies several things (#4816)
* spg110: jak_capb misc guesses (nw) * misc priority stuff (nw) * tweaks (nw) * more tweaks (nw) * small spg2xx refactor (nw) * some spg2xx refactoring (nw) * (nw) * tidy (nw) * these have all been moved out into modules (nw) * sprite work in progress (nw) * (nw) * spg110: shift some stuff around and split into files here too * (nw) * (nw) * (nw) * sprite improvements
This commit is contained in:
parent
f1abceb70c
commit
9873d6afaa
@ -2626,8 +2626,14 @@ if (MACHINES["SPG2XX"]~=null) then
|
||||
MAME_DIR .. "src/devices/machine/spg2xx_audio.h",
|
||||
MAME_DIR .. "src/devices/machine/spg2xx_io.cpp",
|
||||
MAME_DIR .. "src/devices/machine/spg2xx_io.h",
|
||||
MAME_DIR .. "src/devices/machine/spg2xx_sysdma.cpp",
|
||||
MAME_DIR .. "src/devices/machine/spg2xx_sysdma.h",
|
||||
MAME_DIR .. "src/devices/machine/spg2xx_video.cpp",
|
||||
MAME_DIR .. "src/devices/machine/spg2xx_video.h",
|
||||
MAME_DIR .. "src/devices/machine/spg110.cpp",
|
||||
MAME_DIR .. "src/devices/machine/spg110.h",
|
||||
MAME_DIR .. "src/devices/machine/spg110_video.cpp",
|
||||
MAME_DIR .. "src/devices/machine/spg110_video.h",
|
||||
}
|
||||
end
|
||||
|
||||
|
@ -18,14 +18,10 @@ DEFINE_DEVICE_TYPE(SPG110, spg110_device, "spg110", "SPG110 System-on-a-Chip")
|
||||
|
||||
spg110_device::spg110_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock)
|
||||
: device_t(mconfig, type, tag, owner, clock)
|
||||
, device_memory_interface(mconfig, *this)
|
||||
, m_space_config("spg110", ENDIANNESS_BIG, 16, 32, 0, address_map_constructor(FUNC(spg110_device::map_video), this))
|
||||
, m_cpu(*this, finder_base::DUMMY_TAG)
|
||||
, m_screen(*this, finder_base::DUMMY_TAG)
|
||||
, m_palette(*this, "palette")
|
||||
, m_gfxdecode(*this, "gfxdecode")
|
||||
, m_palram(*this, "palram")
|
||||
, m_spg_io(*this, "spg_io")
|
||||
, m_spg_video(*this, "spg_video")
|
||||
, m_porta_out(*this)
|
||||
, m_portb_out(*this)
|
||||
, m_portc_out(*this)
|
||||
@ -37,188 +33,13 @@ spg110_device::spg110_device(const machine_config &mconfig, device_type type, co
|
||||
{
|
||||
}
|
||||
|
||||
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)
|
||||
|
||||
spg110_device::spg110_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
|
||||
: spg110_device(mconfig, SPG110, tag, owner, clock)
|
||||
{
|
||||
address_space &space = m_cpu->space(AS_PROGRAM);
|
||||
|
||||
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);
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void spg110_device::blit_page(const rectangle &cliprect, uint32_t scanline, int depth, uint32_t bitmap_addr, uint16_t *regs)
|
||||
{
|
||||
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);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* correct, 4bpp gfxs */
|
||||
static const gfx_layout charlayout =
|
||||
{
|
||||
8,8,
|
||||
RGN_FRAC(1,1),
|
||||
4,
|
||||
{ STEP4(0,1) },
|
||||
{ 0*4,1*4,2*4,3*4,4*4,5*4,6*4,7*4 },
|
||||
{ STEP8(0,4*8) },
|
||||
8*8*4
|
||||
};
|
||||
|
||||
static const gfx_layout charlayout6 =
|
||||
{
|
||||
8,8,
|
||||
RGN_FRAC(1,1),
|
||||
6,
|
||||
{ 0,1,2,3,4,5 },
|
||||
{ STEP8(0,6) },
|
||||
{ STEP8(0,6*8) },
|
||||
8*8*6
|
||||
};
|
||||
|
||||
static const gfx_layout char16layout =
|
||||
{
|
||||
16,16,
|
||||
RGN_FRAC(1,1),
|
||||
4,
|
||||
{ STEP4(0,1) },
|
||||
{ 0*4,1*4,2*4,3*4,4*4,5*4,6*4,7*4, 8*4,9*4,10*4,11*4,12*4,13*4,14*4,15*4 },
|
||||
{ STEP16(0,4*16) },
|
||||
16*16*4
|
||||
};
|
||||
|
||||
static const gfx_layout char32layout =
|
||||
{
|
||||
32,32,
|
||||
RGN_FRAC(1,1),
|
||||
4,
|
||||
{ STEP4(0,1) },
|
||||
{ STEP32(0,4) },
|
||||
{ STEP32(0,4*32) },
|
||||
32*32*4
|
||||
};
|
||||
|
||||
|
||||
|
||||
static GFXDECODE_START( gfx )
|
||||
GFXDECODE_ENTRY( ":maincpu", 0, charlayout, 0, 16 )
|
||||
GFXDECODE_ENTRY( ":maincpu", 0, char16layout, 0, 16 )
|
||||
GFXDECODE_ENTRY( ":maincpu", 0, char32layout, 0, 16 )
|
||||
GFXDECODE_ENTRY( ":maincpu", 0, charlayout6, 0, 16 ) // correct for lots of the tiles inc. startup text
|
||||
GFXDECODE_END
|
||||
|
||||
void spg110_device::configure_spg_io(spg2xx_io_device* io)
|
||||
{
|
||||
@ -241,129 +62,12 @@ void spg110_device::configure_spg_io(spg2xx_io_device* io)
|
||||
|
||||
void spg110_device::device_add_mconfig(machine_config &config)
|
||||
{
|
||||
// PALETTE(config, m_palette).set_format(palette_device::xRGB_555, 0x100);
|
||||
// PALETTE(config, m_palette).set_format(palette_device::RGB_565, 0x100);
|
||||
// PALETTE(config, m_palette).set_format(palette_device::IRGB_4444, 0x100);
|
||||
// PALETTE(config, m_palette).set_format(palette_device::RGBI_4444, 0x100);
|
||||
// PALETTE(config, m_palette).set_format(palette_device::xRGB_555, 0x100);
|
||||
PALETTE(config, m_palette, palette_device::BLACK, 256);
|
||||
|
||||
GFXDECODE(config, m_gfxdecode, m_palette, gfx);
|
||||
|
||||
SPG24X_IO(config, m_spg_io, DERIVED_CLOCK(1, 1), m_cpu, m_screen);
|
||||
configure_spg_io(m_spg_io);
|
||||
|
||||
SPG110_VIDEO(config, m_spg_video, DERIVED_CLOCK(1, 1), m_cpu, m_screen);
|
||||
}
|
||||
|
||||
|
||||
device_memory_interface::space_config_vector spg110_device::memory_space_config() const
|
||||
{
|
||||
return space_config_vector {
|
||||
std::make_pair(0, &m_space_config)
|
||||
};
|
||||
}
|
||||
|
||||
spg110_device::spg110_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
|
||||
: spg110_device(mconfig, SPG110, tag, owner, clock)
|
||||
{
|
||||
}
|
||||
|
||||
// irq source or similar?
|
||||
READ16_MEMBER(spg110_device::spg110_2063_r)
|
||||
{
|
||||
// checks for bits 0x20 and 0x08 in the IRQ function (all IRQs point to the same place)
|
||||
return 0x0008;
|
||||
}
|
||||
|
||||
WRITE16_MEMBER(spg110_device::spg110_2063_w)
|
||||
{
|
||||
// writes 0x28, probably clears the IRQ / IRQ sources? 0x63 is the same offset for this in spg2xx but bits used seem to be different
|
||||
m_cpu->set_state_unsynced(UNSP_IRQ0_LINE, CLEAR_LINE);
|
||||
}
|
||||
|
||||
|
||||
WRITE16_MEMBER(spg110_device::spg110_201c_w) { }
|
||||
WRITE16_MEMBER(spg110_device::spg110_2020_w) { }
|
||||
WRITE16_MEMBER(spg110_device::spg110_2042_w) { }
|
||||
WRITE16_MEMBER(spg110_device::spg110_2031_w) { }
|
||||
WRITE16_MEMBER(spg110_device::spg110_2032_w) { }
|
||||
WRITE16_MEMBER(spg110_device::spg110_2033_w) { }
|
||||
WRITE16_MEMBER(spg110_device::spg110_2034_w) { }
|
||||
WRITE16_MEMBER(spg110_device::spg110_2035_w) { }
|
||||
WRITE16_MEMBER(spg110_device::spg110_2036_w) { COMBINE_DATA(&m_2036_scroll); }
|
||||
WRITE16_MEMBER(spg110_device::spg110_2039_w) { }
|
||||
WRITE16_MEMBER(spg110_device::spg110_2037_w) { }
|
||||
WRITE16_MEMBER(spg110_device::spg110_203c_w) { }
|
||||
WRITE16_MEMBER(spg110_device::spg110_203d_w) { }
|
||||
WRITE16_MEMBER(spg110_device::spg110_2045_w) { }
|
||||
|
||||
|
||||
WRITE16_MEMBER(spg110_device::spg110_2028_w) { }
|
||||
WRITE16_MEMBER(spg110_device::spg110_2029_w) { }
|
||||
|
||||
READ16_MEMBER(spg110_device::spg110_2028_r) { return 0x0000; }
|
||||
READ16_MEMBER(spg110_device::spg110_2029_r) { return 0x0000; }
|
||||
|
||||
|
||||
WRITE16_MEMBER(spg110_device::spg110_2050_w) { }
|
||||
WRITE16_MEMBER(spg110_device::spg110_2051_w) { }
|
||||
WRITE16_MEMBER(spg110_device::spg110_2052_w) { }
|
||||
WRITE16_MEMBER(spg110_device::spg110_2053_w) { }
|
||||
WRITE16_MEMBER(spg110_device::spg110_2054_w) { }
|
||||
WRITE16_MEMBER(spg110_device::spg110_2055_w) { }
|
||||
WRITE16_MEMBER(spg110_device::spg110_2056_w) { }
|
||||
WRITE16_MEMBER(spg110_device::spg110_2057_w) { }
|
||||
WRITE16_MEMBER(spg110_device::spg110_2058_w) { }
|
||||
WRITE16_MEMBER(spg110_device::spg110_2059_w) { }
|
||||
WRITE16_MEMBER(spg110_device::spg110_205a_w) { }
|
||||
WRITE16_MEMBER(spg110_device::spg110_205b_w) { }
|
||||
WRITE16_MEMBER(spg110_device::spg110_205c_w) { }
|
||||
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::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::dma_len_trigger_w)
|
||||
{
|
||||
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 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);
|
||||
|
||||
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;
|
||||
|
||||
for (int i = 0; i < length; 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);
|
||||
|
||||
source+=m_dma_src_step;
|
||||
dest+=m_dma_dst_step;
|
||||
}
|
||||
}
|
||||
|
||||
READ16_MEMBER(spg110_device::dma_len_status_r)
|
||||
{
|
||||
return 0x1fff; // DMA related?
|
||||
}
|
||||
|
||||
READ16_MEMBER(spg110_device::spg110_2037_r) { return 0x0000; }
|
||||
READ16_MEMBER(spg110_device::spg110_2042_r) { return 0x0000; }
|
||||
|
||||
|
||||
WRITE16_MEMBER(spg110_device::spg110_3100_w) { }
|
||||
WRITE16_MEMBER(spg110_device::spg110_3101_w) { }
|
||||
WRITE16_MEMBER(spg110_device::spg110_3102_w) { }
|
||||
@ -379,128 +83,58 @@ 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, 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(0x002010, 0x002015).rw(m_spg_video, FUNC(spg110_video_device::tmap0_regs_r), FUNC(spg110_video_device::tmap0_regs_w));
|
||||
map(0x002016, 0x00201b).rw(m_spg_video, FUNC(spg110_video_device::tmap1_regs_r), FUNC(spg110_video_device::tmap1_regs_w));
|
||||
|
||||
map(0x00201c, 0x00201c).w(FUNC(spg110_device::spg110_201c_w));
|
||||
#if 0 // more vregs?
|
||||
map(0x00201c, 0x00201c).w(m_spg_video, FUNC(spg110_video_device::spg110_201c_w));
|
||||
|
||||
map(0x002020, 0x002020).w(FUNC(spg110_device::spg110_2020_w));
|
||||
map(0x002020, 0x002020).w(m_spg_video, FUNC(spg110_video_device::spg110_2020_w));
|
||||
|
||||
map(0x002028, 0x002028).rw(FUNC(spg110_device::spg110_2028_r), FUNC(spg110_device::spg110_2028_w));
|
||||
map(0x002029, 0x002029).rw(FUNC(spg110_device::spg110_2029_r), FUNC(spg110_device::spg110_2029_w));
|
||||
map(0x002028, 0x002028).rw(m_spg_video, FUNC(spg110_video_device::spg110_2028_r), FUNC(spg110_video_device::spg110_2028_w));
|
||||
map(0x002029, 0x002029).rw(m_spg_video, FUNC(spg110_video_device::spg110_2029_r), FUNC(spg110_video_device::spg110_2029_w));
|
||||
|
||||
map(0x002031, 0x002031).w(FUNC(spg110_device::spg110_2031_w)); // sometimes 14a?
|
||||
map(0x002032, 0x002032).w(FUNC(spg110_device::spg110_2032_w)); // always 14a?
|
||||
map(0x002033, 0x002033).w(FUNC(spg110_device::spg110_2033_w));
|
||||
map(0x002034, 0x002034).w(FUNC(spg110_device::spg110_2034_w));
|
||||
map(0x002035, 0x002035).w(FUNC(spg110_device::spg110_2035_w));
|
||||
map(0x002036, 0x002036).w(FUNC(spg110_device::spg110_2036_w)); // possible scroll register?
|
||||
map(0x002037, 0x002037).rw(FUNC(spg110_device::spg110_2037_r), FUNC(spg110_device::spg110_2037_w));
|
||||
map(0x002031, 0x002031).w(m_spg_video, FUNC(spg110_video_device::spg110_2031_w)); // sometimes 14a?
|
||||
map(0x002032, 0x002032).w(m_spg_video, FUNC(spg110_video_device::spg110_2032_w)); // always 14a?
|
||||
map(0x002033, 0x002033).w(m_spg_video, FUNC(spg110_video_device::spg110_2033_w));
|
||||
map(0x002034, 0x002034).w(m_spg_video, FUNC(spg110_video_device::spg110_2034_w));
|
||||
map(0x002035, 0x002035).w(m_spg_video, FUNC(spg110_video_device::spg110_2035_w));
|
||||
map(0x002036, 0x002036).w(m_spg_video, FUNC(spg110_video_device::spg110_2036_w)); // possible scroll register?
|
||||
map(0x002037, 0x002037).rw(m_spg_video, FUNC(spg110_video_device::spg110_2037_r), FUNC(spg110_video_device::spg110_2037_w));
|
||||
|
||||
map(0x002039, 0x002039).w(FUNC(spg110_device::spg110_2039_w));
|
||||
map(0x002039, 0x002039).w(m_spg_video, FUNC(spg110_video_device::spg110_2039_w));
|
||||
|
||||
map(0x00203c, 0x00203c).w(FUNC(spg110_device::spg110_203c_w));
|
||||
map(0x00203c, 0x00203c).w(m_spg_video, FUNC(spg110_video_device::spg110_203c_w));
|
||||
|
||||
map(0x00203d, 0x00203d).w(FUNC(spg110_device::spg110_203d_w)); // possible scroll register?
|
||||
map(0x00203d, 0x00203d).w(m_spg_video, FUNC(spg110_video_device::spg110_203d_w)); // possible scroll register?
|
||||
|
||||
map(0x002042, 0x002042).rw(FUNC(spg110_device::spg110_2042_r),FUNC(spg110_device::spg110_2042_w));
|
||||
map(0x002042, 0x002042).rw(m_spg_video, FUNC(spg110_video_device::spg110_2042_r),FUNC(spg110_video_device::spg110_2042_w));
|
||||
|
||||
map(0x002045, 0x002045).w(FUNC(spg110_device::spg110_2045_w));
|
||||
map(0x002045, 0x002045).w(m_spg_video, FUNC(spg110_video_device::spg110_2045_w));
|
||||
#endif
|
||||
|
||||
// seems to be 16 entries for.. something?
|
||||
map(0x002050, 0x002050).w(FUNC(spg110_device::spg110_2050_w));
|
||||
map(0x002051, 0x002051).w(FUNC(spg110_device::spg110_2051_w));
|
||||
map(0x002052, 0x002052).w(FUNC(spg110_device::spg110_2052_w));
|
||||
map(0x002053, 0x002053).w(FUNC(spg110_device::spg110_2053_w));
|
||||
map(0x002054, 0x002054).w(FUNC(spg110_device::spg110_2054_w));
|
||||
map(0x002055, 0x002055).w(FUNC(spg110_device::spg110_2055_w));
|
||||
map(0x002056, 0x002056).w(FUNC(spg110_device::spg110_2056_w));
|
||||
map(0x002057, 0x002057).w(FUNC(spg110_device::spg110_2057_w));
|
||||
map(0x002058, 0x002058).w(FUNC(spg110_device::spg110_2058_w));
|
||||
map(0x002059, 0x002059).w(FUNC(spg110_device::spg110_2059_w));
|
||||
map(0x00205a, 0x00205a).w(FUNC(spg110_device::spg110_205a_w));
|
||||
map(0x00205b, 0x00205b).w(FUNC(spg110_device::spg110_205b_w));
|
||||
map(0x00205c, 0x00205c).w(FUNC(spg110_device::spg110_205c_w));
|
||||
map(0x00205d, 0x00205d).w(FUNC(spg110_device::spg110_205d_w));
|
||||
map(0x00205e, 0x00205e).w(FUNC(spg110_device::spg110_205e_w));
|
||||
map(0x00205f, 0x00205f).w(FUNC(spg110_device::spg110_205f_w));
|
||||
|
||||
//map(0x002010, 0x00205f).ram();
|
||||
// seems to be 16 entries for.. something? on jak_capb these seem connected to the palette DMA operations, 0x2050 for 0x8000, 0x2051 for 0x8020, 0x2052 for 0x8040 etc. maybe 1 bit per pen?
|
||||
map(0x002050, 0x00205f).ram().w(m_spg_video, FUNC(spg110_video_device::spg110_205x_w)).share("spg_video:palctrlram");
|
||||
|
||||
// everything (dma? and interrupt flag?!)
|
||||
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::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(0x002060, 0x002060).w(m_spg_video, FUNC(spg110_video_device::dma_dst_w));
|
||||
map(0x002061, 0x002061).w(m_spg_video, FUNC(spg110_video_device::dma_unk_2061_w));
|
||||
map(0x002062, 0x002062).rw(m_spg_video, FUNC(spg110_video_device::dma_len_status_r),FUNC(spg110_video_device::dma_len_trigger_w));
|
||||
map(0x002063, 0x002063).rw(m_spg_video, FUNC(spg110_video_device::spg110_2063_r),FUNC(spg110_video_device::spg110_2063_w)); // Video IRQ source / ack (3 different things checked here instead of 2 on spg2xx?)
|
||||
map(0x002064, 0x002064).w(m_spg_video, FUNC(spg110_video_device::dma_dst_step_w));
|
||||
map(0x002066, 0x002066).w(m_spg_video, FUNC(spg110_video_device::dma_src_w));
|
||||
map(0x002067, 0x002067).w(m_spg_video, FUNC(spg110_video_device::dma_unk_2067_w));
|
||||
map(0x002068, 0x002068).w(m_spg_video, FUNC(spg110_video_device::dma_src_step_w));
|
||||
|
||||
map(0x002200, 0x0022ff).ram(); // looks like per-pen brightness or similar? strange because palette isn't memory mapped here
|
||||
map(0x002200, 0x0022ff).ram(); // looks like per-pen brightness or similar? strange because palette isn't memory mapped here (maybe rowscroll?)
|
||||
|
||||
map(0x003000, 0x00307f).ram(); // sound registers? seems to be 8 long entries, only uses up to 0x7f?
|
||||
#if 1 // sound registers? seems to be 8 long entries, only uses up to 0x7f? (register mapping seems similar to spg2xx, maybe with less channels?)
|
||||
map(0x003000, 0x00307f).ram();
|
||||
map(0x003080, 0x0030ff).ram();
|
||||
|
||||
map(0x003100, 0x003100).w(FUNC(spg110_device::spg110_3100_w));
|
||||
@ -519,46 +153,15 @@ void spg110_device::map(address_map &map)
|
||||
map(0x00310d, 0x00310d).w(FUNC(spg110_device::spg110_310d_w));
|
||||
|
||||
map(0x00310f, 0x00310f).r(FUNC(spg110_device::spg110_310f_r));
|
||||
#endif
|
||||
|
||||
// 0032xx looks like it could be the same as 003d00 on spg2xx
|
||||
map(0x003200, 0x00322f).rw(m_spg_io, FUNC(spg2xx_io_device::io_r), FUNC(spg2xx_io_device::io_w));
|
||||
}
|
||||
|
||||
// this seems to be a different, non-cpu mapped space only accessible via the DMA?
|
||||
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, 0x03fff).ram(); // 2fff?
|
||||
|
||||
map(0x04000, 0x04fff).ram(); // seems to be 3 blocks, almost certainly spritelist
|
||||
|
||||
// map(0x08000, 0x081ff).ram().w(m_palette, FUNC(palette_device::write16)).share("palette"); // probably? format unknown tho
|
||||
map(0x08000, 0x081ff).ram().share("palram");
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
TIMER_CALLBACK_MEMBER(spg110_device::test_timer)
|
||||
{
|
||||
//
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
|
||||
void spg110_device::device_start()
|
||||
{
|
||||
// m_test_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(spg110_device::test_timer), this));
|
||||
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));
|
||||
|
||||
m_porta_out.resolve_safe();
|
||||
m_portb_out.resolve_safe();
|
||||
m_portc_out.resolve_safe();
|
||||
@ -573,97 +176,5 @@ void spg110_device::device_start()
|
||||
|
||||
void spg110_device::device_reset()
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
double spg110_device::hue2rgb(double p, double q, double t)
|
||||
{
|
||||
if (t < 0) t += 1;
|
||||
if (t > 1) t -= 1;
|
||||
if (t < 1 / 6.0f) return p + (q - p) * 6 * t;
|
||||
if (t < 1 / 2.0f) return q;
|
||||
if (t < 2 / 3.0f) return p + (q - p) * (2 / 3.0f - t) * 6;
|
||||
return p;
|
||||
}
|
||||
|
||||
uint32_t spg110_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
|
||||
{
|
||||
// Palette, this is still wrong!
|
||||
int offs = 0;
|
||||
for (int index = 0;index < 256; index++)
|
||||
{
|
||||
uint16_t dat = m_palram[offs++];
|
||||
|
||||
// llll lsss sshh hhhh
|
||||
int l_raw = (dat & 0xf800) >> 11;
|
||||
int sl_raw = (dat & 0x07c0) >> 6;
|
||||
int h_raw = (dat & 0x003f) >> 0;
|
||||
|
||||
double l = (double)l_raw / 31.0f;
|
||||
double s = (double)sl_raw / 31.0f;
|
||||
double h = (double)h_raw / 47.0f;
|
||||
|
||||
double r, g, b;
|
||||
|
||||
if (s == 0) {
|
||||
r = g = b = l; // greyscale
|
||||
} else {
|
||||
double q = l < 0.5f ? l * (1 + s) : l + s - l * s;
|
||||
double p = 2 * l - q;
|
||||
r = hue2rgb(p, q, h + 1/3.0f);
|
||||
g = hue2rgb(p, q, h);
|
||||
b = hue2rgb(p, q, h - 1/3.0f);
|
||||
}
|
||||
|
||||
int r_real = r * 255.0f;
|
||||
int g_real = g * 255.0f;
|
||||
int b_real = b * 255.0f;
|
||||
|
||||
m_palette->set_pen_color(index, r_real, g_real, b_real);
|
||||
}
|
||||
|
||||
memset(&m_screenbuf[320 * cliprect.min_y], 0, 4 * 320 * ((cliprect.max_y - cliprect.min_y) + 1));
|
||||
|
||||
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;
|
||||
|
||||
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 y = cliprect.min_y; y <= cliprect.max_y; y++)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
WRITE_LINE_MEMBER(spg110_device::vblank)
|
||||
{
|
||||
if (!state)
|
||||
{
|
||||
m_cpu->set_state_unsynced(UNSP_IRQ0_LINE, ASSERT_LINE);
|
||||
// m_test_timer->adjust(attotime::from_usec(100), 0);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
@ -10,9 +10,9 @@
|
||||
#include "cpu/unsp/unsp.h"
|
||||
#include "emupal.h"
|
||||
#include "spg2xx_io.h"
|
||||
#include "spg110_video.h"
|
||||
|
||||
|
||||
class spg110_device : public device_t, public device_memory_interface
|
||||
class spg110_device : public device_t
|
||||
|
||||
{
|
||||
public:
|
||||
@ -28,11 +28,6 @@ public:
|
||||
}
|
||||
|
||||
void map(address_map &map);
|
||||
void map_video(address_map &map);
|
||||
|
||||
double hue2rgb(double p, double q, double t);
|
||||
uint32_t screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect);
|
||||
DECLARE_WRITE_LINE_MEMBER(vblank);
|
||||
|
||||
auto porta_out() { return m_porta_out.bind(); }
|
||||
auto portb_out() { return m_portb_out.bind(); }
|
||||
@ -45,107 +40,22 @@ public:
|
||||
|
||||
auto chip_select() { return m_chip_sel.bind(); }
|
||||
|
||||
uint32_t screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect) { return m_spg_video->screen_update(screen,bitmap,cliprect); }
|
||||
DECLARE_WRITE_LINE_MEMBER(vblank) { m_spg_video->vblank(state); }
|
||||
|
||||
protected:
|
||||
virtual void device_start() override;
|
||||
virtual void device_reset() override;
|
||||
|
||||
virtual void device_add_mconfig(machine_config &config) override;
|
||||
|
||||
virtual space_config_vector memory_space_config() const override;
|
||||
|
||||
address_space_config m_space_config;
|
||||
|
||||
private:
|
||||
enum
|
||||
{
|
||||
PAGE_ENABLE_MASK = 0x0008,
|
||||
PAGE_WALLPAPER_MASK = 0x0004,
|
||||
|
||||
PAGE_DEPTH_FLAG_MASK = 0x3000,
|
||||
PAGE_DEPTH_FLAG_SHIFT = 12,
|
||||
PAGE_TILE_HEIGHT_MASK = 0x00c0,
|
||||
PAGE_TILE_HEIGHT_SHIFT = 6,
|
||||
PAGE_TILE_WIDTH_MASK = 0x0030,
|
||||
PAGE_TILE_WIDTH_SHIFT = 4,
|
||||
|
||||
TILE_X_FLIP = 0x0004,
|
||||
TILE_Y_FLIP = 0x0008
|
||||
};
|
||||
|
||||
enum flipx_t : bool
|
||||
{
|
||||
FlipXOff = false,
|
||||
FlipXOn = true
|
||||
};
|
||||
|
||||
required_device<unsp_device> m_cpu;
|
||||
required_device<screen_device> m_screen;
|
||||
required_device<palette_device> m_palette;
|
||||
required_device<gfxdecode_device> m_gfxdecode;
|
||||
required_shared_ptr<uint16_t> m_palram;
|
||||
|
||||
required_device<spg2xx_io_device> m_spg_io;
|
||||
|
||||
//TIMER_CALLBACK_MEMBER(test_timer);
|
||||
//emu_timer *m_test_timer;
|
||||
|
||||
|
||||
DECLARE_WRITE16_MEMBER(spg110_201c_w);
|
||||
DECLARE_WRITE16_MEMBER(spg110_2020_w);
|
||||
|
||||
DECLARE_WRITE16_MEMBER(spg110_2028_w);
|
||||
DECLARE_WRITE16_MEMBER(spg110_2029_w);
|
||||
|
||||
DECLARE_READ16_MEMBER(spg110_2028_r);
|
||||
DECLARE_READ16_MEMBER(spg110_2029_r);
|
||||
|
||||
DECLARE_WRITE16_MEMBER(spg110_2031_w);
|
||||
DECLARE_WRITE16_MEMBER(spg110_2032_w);
|
||||
DECLARE_WRITE16_MEMBER(spg110_2033_w);
|
||||
DECLARE_WRITE16_MEMBER(spg110_2034_w);
|
||||
DECLARE_WRITE16_MEMBER(spg110_2035_w);
|
||||
DECLARE_WRITE16_MEMBER(spg110_2036_w);
|
||||
DECLARE_WRITE16_MEMBER(spg110_2037_w);
|
||||
DECLARE_WRITE16_MEMBER(spg110_2039_w);
|
||||
|
||||
DECLARE_WRITE16_MEMBER(spg110_203c_w);
|
||||
DECLARE_WRITE16_MEMBER(spg110_203d_w);
|
||||
|
||||
DECLARE_WRITE16_MEMBER(spg110_2042_w);
|
||||
|
||||
DECLARE_WRITE16_MEMBER(spg110_2045_w);
|
||||
|
||||
DECLARE_WRITE16_MEMBER(spg110_2050_w);
|
||||
DECLARE_WRITE16_MEMBER(spg110_2051_w);
|
||||
DECLARE_WRITE16_MEMBER(spg110_2052_w);
|
||||
DECLARE_WRITE16_MEMBER(spg110_2053_w);
|
||||
DECLARE_WRITE16_MEMBER(spg110_2054_w);
|
||||
DECLARE_WRITE16_MEMBER(spg110_2055_w);
|
||||
DECLARE_WRITE16_MEMBER(spg110_2056_w);
|
||||
DECLARE_WRITE16_MEMBER(spg110_2057_w);
|
||||
DECLARE_WRITE16_MEMBER(spg110_2058_w);
|
||||
DECLARE_WRITE16_MEMBER(spg110_2059_w);
|
||||
DECLARE_WRITE16_MEMBER(spg110_205a_w);
|
||||
DECLARE_WRITE16_MEMBER(spg110_205b_w);
|
||||
DECLARE_WRITE16_MEMBER(spg110_205c_w);
|
||||
DECLARE_WRITE16_MEMBER(spg110_205d_w);
|
||||
DECLARE_WRITE16_MEMBER(spg110_205e_w);
|
||||
DECLARE_WRITE16_MEMBER(spg110_205f_w);
|
||||
|
||||
|
||||
DECLARE_READ16_MEMBER(spg110_2037_r);
|
||||
DECLARE_READ16_MEMBER(spg110_2042_r);
|
||||
|
||||
DECLARE_WRITE16_MEMBER(dma_dst_w);
|
||||
DECLARE_WRITE16_MEMBER(dma_unk_2061_w);
|
||||
DECLARE_WRITE16_MEMBER(dma_len_trigger_w);
|
||||
DECLARE_WRITE16_MEMBER(spg110_2063_w);
|
||||
DECLARE_WRITE16_MEMBER(dma_dst_step_w);
|
||||
DECLARE_WRITE16_MEMBER(dma_src_w);
|
||||
DECLARE_WRITE16_MEMBER(dma_unk_2067_w);
|
||||
DECLARE_WRITE16_MEMBER(dma_src_step_w);
|
||||
|
||||
DECLARE_READ16_MEMBER(dma_len_status_r);
|
||||
DECLARE_READ16_MEMBER(spg110_2063_r);
|
||||
required_device<spg110_video_device> m_spg_video;
|
||||
|
||||
DECLARE_WRITE16_MEMBER(spg110_3100_w);
|
||||
|
||||
@ -164,33 +74,6 @@ private:
|
||||
|
||||
DECLARE_READ16_MEMBER(spg110_310f_r);
|
||||
|
||||
DECLARE_READ16_MEMBER(tmap0_regs_r);
|
||||
DECLARE_READ16_MEMBER(tmap1_regs_r);
|
||||
DECLARE_WRITE16_MEMBER(tmap0_regs_w);
|
||||
DECLARE_WRITE16_MEMBER(tmap1_regs_w);
|
||||
|
||||
uint16_t tmap0_regs[0x6];
|
||||
uint16_t tmap1_regs[0x6];
|
||||
|
||||
uint16_t m_dma_src_step;
|
||||
uint16_t m_dma_dst_step;
|
||||
uint16_t m_dma_unk_2061;
|
||||
uint16_t m_dma_unk_2067;
|
||||
|
||||
uint16_t m_dma_dst;
|
||||
uint16_t m_dma_src;
|
||||
|
||||
uint16_t m_bg_scrollx;
|
||||
uint16_t m_bg_scrolly;
|
||||
uint16_t m_2036_scroll;
|
||||
|
||||
void tilemap_write_regs(int which, uint16_t* regs, int regno, uint16_t data);
|
||||
|
||||
template<flipx_t FlipX>
|
||||
void 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);
|
||||
void blit_page(const rectangle &cliprect, uint32_t scanline, int depth, uint32_t bitmap_addr, uint16_t *regs);
|
||||
uint32_t m_screenbuf[320 * 240];
|
||||
|
||||
devcb_write16 m_porta_out;
|
||||
devcb_write16 m_portb_out;
|
||||
devcb_write16 m_portc_out;
|
||||
@ -202,15 +85,15 @@ private:
|
||||
|
||||
devcb_write8 m_chip_sel;
|
||||
|
||||
DECLARE_READ16_MEMBER(porta_r) { return m_porta_in(); };
|
||||
DECLARE_READ16_MEMBER(portb_r) { return m_portb_in(); };
|
||||
DECLARE_READ16_MEMBER(portc_r) { return m_portc_in(); };
|
||||
DECLARE_WRITE16_MEMBER(porta_w) { m_porta_out(offset, data, mem_mask); };
|
||||
DECLARE_WRITE16_MEMBER(portb_w) { m_portb_out(offset, data, mem_mask); };
|
||||
DECLARE_WRITE16_MEMBER(portc_w) { m_portc_out(offset, data, mem_mask); };
|
||||
template <size_t Line> DECLARE_READ16_MEMBER(adc_r) { return m_adc_in[Line](); };
|
||||
DECLARE_WRITE8_MEMBER(cs_w) { m_chip_sel(offset, data, mem_mask); };
|
||||
DECLARE_READ16_MEMBER(get_pal_r) { return 0; /*m_pal_flag;*/ };
|
||||
DECLARE_READ16_MEMBER(porta_r) { return m_porta_in(); }
|
||||
DECLARE_READ16_MEMBER(portb_r) { return m_portb_in(); }
|
||||
DECLARE_READ16_MEMBER(portc_r) { return m_portc_in(); }
|
||||
DECLARE_WRITE16_MEMBER(porta_w) { m_porta_out(offset, data, mem_mask); }
|
||||
DECLARE_WRITE16_MEMBER(portb_w) { m_portb_out(offset, data, mem_mask); }
|
||||
DECLARE_WRITE16_MEMBER(portc_w) { m_portc_out(offset, data, mem_mask); }
|
||||
template <size_t Line> DECLARE_READ16_MEMBER(adc_r) { return m_adc_in[Line](); }
|
||||
DECLARE_WRITE8_MEMBER(cs_w) { m_chip_sel(offset, data, mem_mask); }
|
||||
DECLARE_READ16_MEMBER(get_pal_r) { return 0; /*m_pal_flag;*/ }
|
||||
void configure_spg_io(spg2xx_io_device* io);
|
||||
|
||||
};
|
||||
|
587
src/devices/machine/spg110_video.cpp
Normal file
587
src/devices/machine/spg110_video.cpp
Normal file
@ -0,0 +1,587 @@
|
||||
// license:BSD-3-Clause
|
||||
// copyright-holders:David Haywood
|
||||
|
||||
#include "emu.h"
|
||||
#include "spg110_video.h"
|
||||
|
||||
DEFINE_DEVICE_TYPE(SPG110_VIDEO, spg110_video_device, "spg110_video", "SPG110 System-on-a-Chip (Video)")
|
||||
|
||||
spg110_video_device::spg110_video_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock)
|
||||
: device_t(mconfig, type, tag, owner, clock)
|
||||
, device_memory_interface(mconfig, *this)
|
||||
, m_space_config("spg110_video", ENDIANNESS_BIG, 16, 32, 0, address_map_constructor(FUNC(spg110_video_device::map_video), this))
|
||||
, m_cpu(*this, finder_base::DUMMY_TAG)
|
||||
, m_screen(*this, finder_base::DUMMY_TAG)
|
||||
, m_palette(*this, "palette")
|
||||
, m_gfxdecode(*this, "gfxdecode")
|
||||
, m_palram(*this, "palram")
|
||||
, m_palctrlram(*this, "palctrlram")
|
||||
, m_sprtileno(*this, "sprtileno")
|
||||
, m_sprattr1(*this, "sprattr1")
|
||||
, m_sprattr2(*this, "sprattr2")
|
||||
{
|
||||
}
|
||||
|
||||
spg110_video_device::spg110_video_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
|
||||
: spg110_video_device(mconfig, SPG110_VIDEO, tag, owner, clock)
|
||||
{
|
||||
}
|
||||
|
||||
template<spg110_video_device::flipx_t FlipX>
|
||||
void spg110_video_device::draw(const rectangle &cliprect, uint32_t line, uint32_t xoff, uint32_t yoff, uint32_t ctrl, uint32_t bitmap_addr, uint16_t tile, uint8_t pal, int32_t h, int32_t w, uint8_t bpp)
|
||||
{
|
||||
address_space &space = m_cpu->space(AS_PROGRAM);
|
||||
|
||||
uint32_t yflipmask = 0; //attr & TILE_Y_FLIP ? h - 1 : 0;
|
||||
|
||||
uint32_t nc = (bpp + 1) << 1;
|
||||
|
||||
uint32_t palette_offset = pal;
|
||||
|
||||
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];
|
||||
|
||||
int penword = (pal >> 4) & 0xf;
|
||||
int penbit = (pal & 0xf);
|
||||
int trans = m_palctrlswapped[penword] & (1 << penbit);
|
||||
|
||||
if (!trans)
|
||||
{
|
||||
m_screenbuf[pix_index] = paldata;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void spg110_video_device::draw_page(const rectangle &cliprect, uint32_t scanline, int priority, uint32_t bitmap_addr, uint16_t *regs)
|
||||
{
|
||||
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_PRIORITY_FLAG_MASK) >> PAGE_PRIORITY_FLAG_SHIFT) != priority)
|
||||
// {
|
||||
// return;
|
||||
// }
|
||||
|
||||
uint8_t bpp = attr & 0x03;
|
||||
|
||||
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 extra_attribute = 0;
|
||||
|
||||
if (!tile)
|
||||
continue;
|
||||
|
||||
extra_attribute = space2.read_word((palette_map*2) + tile_address);
|
||||
if (x0 & 1)
|
||||
extra_attribute = (extra_attribute & 0xff00) >> 8;
|
||||
else
|
||||
extra_attribute = (extra_attribute & 0x00ff);
|
||||
|
||||
uint8_t pal = extra_attribute & 0x0f;
|
||||
uint8_t pri = (extra_attribute & 0x30)>>4;
|
||||
|
||||
if (pri == priority)
|
||||
{
|
||||
bool flip_x = 0;//(tileattr & TILE_X_FLIP);
|
||||
|
||||
if (flip_x)
|
||||
draw<FlipXOn>(cliprect, tile_scanline, xx, yy, ctrl, bitmap_addr, tile, pal, tile_h, tile_w, bpp);
|
||||
else
|
||||
draw<FlipXOff>(cliprect, tile_scanline, xx, yy, ctrl, bitmap_addr, tile, pal, tile_h, tile_w, bpp);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void spg110_video_device::draw_sprite(const rectangle &cliprect, uint32_t scanline, int priority, uint32_t base_addr)
|
||||
{
|
||||
uint32_t bitmap_addr = 0;//0x40 * m_video_regs[0x22];
|
||||
uint16_t tile = m_sprtileno[base_addr];
|
||||
uint16_t attr1 = m_sprattr1[base_addr];
|
||||
uint16_t attr2 = m_sprattr2[base_addr];
|
||||
|
||||
int x = (attr1 >> 8) & 0xff;
|
||||
int y = (attr1) & 0xff;
|
||||
uint8_t pri = (attr2 & 0x3000)>>12;
|
||||
|
||||
// m_sprtileno tttt tttt tttt tttt t = tile number (all bits?)
|
||||
// m_sprattr1 xxxx xxxx yyyy yyyy x = low x bits, y = low y bits
|
||||
// m_sprattr2 -Xzz pppp hhww --bb X = high x bit z = priority, p = palette h = height w = width b = bpp
|
||||
|
||||
|
||||
if (!(attr2 & 0x4000))
|
||||
x+= 0x100;
|
||||
|
||||
if (!tile)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// if ((priority==0) && (scanline==128)) printf("%02x, drawing sprite %04x %04x %04x\n", base_addr, tile, attr1, attr2);
|
||||
|
||||
// if (((attr & PAGE_PRIORITY_FLAG_MASK) >> PAGE_PRIORITY_FLAG_SHIFT) != priority)
|
||||
// {
|
||||
// return;
|
||||
// }
|
||||
|
||||
const uint32_t h = 8 << ((attr2 & PAGE_TILE_HEIGHT_MASK) >> PAGE_TILE_HEIGHT_SHIFT);
|
||||
const uint32_t w = 8 << ((attr2 & PAGE_TILE_WIDTH_MASK) >> PAGE_TILE_WIDTH_SHIFT);
|
||||
|
||||
// if (!(m_video_regs[0x42] & SPRITE_COORD_TL_MASK))
|
||||
// {
|
||||
// x = (160 + x) - w / 2;
|
||||
// y = (120 - y) - (h / 2) + 8;
|
||||
// }
|
||||
|
||||
y = 0xff - y;
|
||||
x = x - 128;
|
||||
|
||||
x &= 0x01ff;
|
||||
y &= 0x01ff;
|
||||
|
||||
uint32_t tile_line = ((scanline - y)) % h;
|
||||
int16_t test_y = (y + tile_line) & 0x1ff;
|
||||
if (test_y >= 0x01c0)
|
||||
test_y -= 0x0200;
|
||||
|
||||
if (test_y != scanline)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
//bool blend = (attr & 0x4000);
|
||||
bool flip_x = 0;//(attr & TILE_X_FLIP);
|
||||
const uint8_t bpp = attr2 & 0x0003;
|
||||
//const uint32_t yflipmask = attr & TILE_Y_FLIP ? h - 1 : 0;
|
||||
const uint32_t palette_offset = (attr2 & 0x0f00) >> 8;
|
||||
|
||||
if (pri == priority)
|
||||
{
|
||||
if (flip_x)
|
||||
draw<FlipXOn>(cliprect, tile_line, x, y, 0, bitmap_addr, tile, palette_offset, h, w, bpp);
|
||||
else
|
||||
draw<FlipXOff>(cliprect, tile_line, x, y, 0, bitmap_addr, tile, palette_offset, h, w, bpp);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void spg110_video_device::draw_sprites(const rectangle &cliprect, uint32_t scanline, int priority)
|
||||
{
|
||||
//if (!(m_video_regs[0x42] & SPRITE_ENABLE_MASK))
|
||||
//{
|
||||
// return;
|
||||
//}
|
||||
|
||||
for (uint32_t n = 0; n < 256; n++)
|
||||
{
|
||||
draw_sprite(cliprect, scanline, priority, n);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* correct, 4bpp gfxs */
|
||||
static const gfx_layout charlayout =
|
||||
{
|
||||
8,8,
|
||||
RGN_FRAC(1,1),
|
||||
4,
|
||||
{ STEP4(0,1) },
|
||||
{ 0*4,1*4,2*4,3*4,4*4,5*4,6*4,7*4 },
|
||||
{ STEP8(0,4*8) },
|
||||
8*8*4
|
||||
};
|
||||
|
||||
static const gfx_layout charlayout6 =
|
||||
{
|
||||
8,8,
|
||||
RGN_FRAC(1,1),
|
||||
6,
|
||||
{ 0,1,2,3,4,5 },
|
||||
{ STEP8(0,6) },
|
||||
{ STEP8(0,6*8) },
|
||||
8*8*6
|
||||
};
|
||||
|
||||
static const gfx_layout char16layout =
|
||||
{
|
||||
16,16,
|
||||
RGN_FRAC(1,1),
|
||||
4,
|
||||
{ STEP4(0,1) },
|
||||
{ 0*4,1*4,2*4,3*4,4*4,5*4,6*4,7*4, 8*4,9*4,10*4,11*4,12*4,13*4,14*4,15*4 },
|
||||
{ STEP16(0,4*16) },
|
||||
16*16*4
|
||||
};
|
||||
|
||||
static const gfx_layout char32layout =
|
||||
{
|
||||
32,32,
|
||||
RGN_FRAC(1,1),
|
||||
4,
|
||||
{ STEP4(0,1) },
|
||||
{ STEP32(0,4) },
|
||||
{ STEP32(0,4*32) },
|
||||
32*32*4
|
||||
};
|
||||
|
||||
|
||||
|
||||
static GFXDECODE_START( gfx )
|
||||
GFXDECODE_ENTRY( ":maincpu", 0, charlayout, 0, 16 )
|
||||
GFXDECODE_ENTRY( ":maincpu", 0, char16layout, 0, 16 )
|
||||
GFXDECODE_ENTRY( ":maincpu", 0, char32layout, 0, 16 )
|
||||
GFXDECODE_ENTRY( ":maincpu", 0, charlayout6, 0, 16 ) // correct for lots of the tiles inc. startup text
|
||||
GFXDECODE_END
|
||||
|
||||
|
||||
void spg110_video_device::device_add_mconfig(machine_config &config)
|
||||
{
|
||||
PALETTE(config, m_palette, palette_device::BLACK, 256);
|
||||
|
||||
GFXDECODE(config, m_gfxdecode, m_palette, gfx);
|
||||
}
|
||||
|
||||
|
||||
device_memory_interface::space_config_vector spg110_video_device::memory_space_config() const
|
||||
{
|
||||
return space_config_vector {
|
||||
std::make_pair(0, &m_space_config)
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
// irq source or similar?
|
||||
READ16_MEMBER(spg110_video_device::spg110_2063_r)
|
||||
{
|
||||
// checks for bits 0x20 and 0x08 in the IRQ function (all IRQs point to the same place)
|
||||
return 0x0008;
|
||||
}
|
||||
|
||||
WRITE16_MEMBER(spg110_video_device::spg110_2063_w)
|
||||
{
|
||||
// writes 0x28, probably clears the IRQ / IRQ sources? 0x63 is the same offset for this in spg2xx but bits used seem to be different
|
||||
m_cpu->set_state_unsynced(UNSP_IRQ0_LINE, CLEAR_LINE);
|
||||
}
|
||||
|
||||
|
||||
WRITE16_MEMBER(spg110_video_device::spg110_201c_w) { }
|
||||
WRITE16_MEMBER(spg110_video_device::spg110_2020_w) { }
|
||||
WRITE16_MEMBER(spg110_video_device::spg110_2042_w) { }
|
||||
WRITE16_MEMBER(spg110_video_device::spg110_2031_w) { }
|
||||
WRITE16_MEMBER(spg110_video_device::spg110_2032_w) { }
|
||||
WRITE16_MEMBER(spg110_video_device::spg110_2033_w) { }
|
||||
WRITE16_MEMBER(spg110_video_device::spg110_2034_w) { }
|
||||
WRITE16_MEMBER(spg110_video_device::spg110_2035_w) { }
|
||||
WRITE16_MEMBER(spg110_video_device::spg110_2036_w) { COMBINE_DATA(&m_2036_scroll); }
|
||||
WRITE16_MEMBER(spg110_video_device::spg110_2039_w) { }
|
||||
WRITE16_MEMBER(spg110_video_device::spg110_2037_w) { }
|
||||
WRITE16_MEMBER(spg110_video_device::spg110_203c_w) { }
|
||||
WRITE16_MEMBER(spg110_video_device::spg110_203d_w) { }
|
||||
WRITE16_MEMBER(spg110_video_device::spg110_2045_w) { }
|
||||
|
||||
|
||||
WRITE16_MEMBER(spg110_video_device::spg110_2028_w) { }
|
||||
WRITE16_MEMBER(spg110_video_device::spg110_2029_w) { }
|
||||
|
||||
READ16_MEMBER(spg110_video_device::spg110_2028_r) { return 0x0000; }
|
||||
READ16_MEMBER(spg110_video_device::spg110_2029_r) { return 0x0000; }
|
||||
|
||||
|
||||
WRITE16_MEMBER(spg110_video_device::spg110_205x_w)
|
||||
{
|
||||
COMBINE_DATA(&m_palctrlram[offset]);
|
||||
|
||||
uint16_t temp = m_palctrlram[offset];
|
||||
|
||||
// 0x0010 to 0x0001 - complete guess that this could be pen transparency
|
||||
m_palctrlswapped[offset] = bitswap<16>(temp, 11, 10, 9, 8, 15, 14, 13, 12, 3, 2, 1, 0, 7, 6, 5, 4);
|
||||
}
|
||||
|
||||
|
||||
WRITE16_MEMBER(spg110_video_device::dma_unk_2061_w) { COMBINE_DATA(&m_dma_unk_2061); }
|
||||
WRITE16_MEMBER(spg110_video_device::dma_dst_step_w) { COMBINE_DATA(&m_dma_dst_step); }
|
||||
WRITE16_MEMBER(spg110_video_device::dma_unk_2067_w) { COMBINE_DATA(&m_dma_unk_2067); }
|
||||
WRITE16_MEMBER(spg110_video_device::dma_src_step_w) { COMBINE_DATA(&m_dma_src_step); }
|
||||
|
||||
WRITE16_MEMBER(spg110_video_device::dma_dst_w) { COMBINE_DATA(&m_dma_dst); }
|
||||
WRITE16_MEMBER(spg110_video_device::dma_src_w) { COMBINE_DATA(&m_dma_src); }
|
||||
|
||||
WRITE16_MEMBER(spg110_video_device::dma_len_trigger_w)
|
||||
{
|
||||
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 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);
|
||||
|
||||
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;
|
||||
|
||||
for (int i = 0; i < length; 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);
|
||||
|
||||
source+=m_dma_src_step;
|
||||
dest+=m_dma_dst_step;
|
||||
}
|
||||
}
|
||||
|
||||
READ16_MEMBER(spg110_video_device::dma_len_status_r)
|
||||
{
|
||||
return 0x1fff; // DMA related?
|
||||
}
|
||||
|
||||
READ16_MEMBER(spg110_video_device::spg110_2037_r) { return 0x0000; }
|
||||
READ16_MEMBER(spg110_video_device::spg110_2042_r) { return 0x0000; }
|
||||
|
||||
READ16_MEMBER(spg110_video_device::tmap0_regs_r) { return tmap0_regs[offset]; }
|
||||
READ16_MEMBER(spg110_video_device::tmap1_regs_r) { return tmap1_regs[offset]; }
|
||||
|
||||
void spg110_video_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
|
||||
// 'priority' can't be priority 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 (Priority:%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_video_device::tmap0_regs_w)
|
||||
{
|
||||
tilemap_write_regs(0, tmap0_regs,offset,data);
|
||||
}
|
||||
|
||||
|
||||
WRITE16_MEMBER(spg110_video_device::tmap1_regs_w)
|
||||
{
|
||||
tilemap_write_regs(1, tmap1_regs,offset,data);
|
||||
}
|
||||
|
||||
// this seems to be a different, non-cpu mapped space only accessible via the DMA?
|
||||
void spg110_video_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, 0x03fff).ram(); // 2fff?
|
||||
|
||||
map(0x04000, 0x041ff).ram().share("sprtileno"); // seems to be 3 blocks, almost certainly spritelist
|
||||
map(0x04200, 0x043ff).ram().share("sprattr1");
|
||||
map(0x04400, 0x045ff).ram().share("sprattr2");
|
||||
|
||||
map(0x08000, 0x081ff).ram().share("palram"); // palette format unknown
|
||||
}
|
||||
|
||||
void spg110_video_device::device_start()
|
||||
{
|
||||
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));
|
||||
}
|
||||
|
||||
void spg110_video_device::device_reset()
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
double spg110_video_device::hue2rgb(double p, double q, double t)
|
||||
{
|
||||
if (t < 0) t += 1;
|
||||
if (t > 1) t -= 1;
|
||||
if (t < 1 / 6.0f) return p + (q - p) * 6 * t;
|
||||
if (t < 1 / 2.0f) return q;
|
||||
if (t < 2 / 3.0f) return p + (q - p) * (2 / 3.0f - t) * 6;
|
||||
return p;
|
||||
}
|
||||
|
||||
uint32_t spg110_video_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
|
||||
{
|
||||
// Palette, this is still wrong!
|
||||
int offs = 0;
|
||||
for (int index = 0;index < 256; index++)
|
||||
{
|
||||
uint16_t dat = m_palram[offs++];
|
||||
|
||||
// llll lsss sshh hhhh
|
||||
int l_raw = (dat & 0xf800) >> 11;
|
||||
int sl_raw = (dat & 0x07c0) >> 6;
|
||||
int h_raw = (dat & 0x003f) >> 0;
|
||||
|
||||
double l = (double)l_raw / 31.0f;
|
||||
double s = (double)sl_raw / 31.0f;
|
||||
double h = (double)h_raw / 47.0f;
|
||||
|
||||
double r, g, b;
|
||||
|
||||
if (s == 0) {
|
||||
r = g = b = l; // greyscale
|
||||
} else {
|
||||
double q = l < 0.5f ? l * (1 + s) : l + s - l * s;
|
||||
double p = 2 * l - q;
|
||||
r = hue2rgb(p, q, h + 1/3.0f);
|
||||
g = hue2rgb(p, q, h);
|
||||
b = hue2rgb(p, q, h - 1/3.0f);
|
||||
}
|
||||
|
||||
int r_real = r * 255.0f;
|
||||
int g_real = g * 255.0f;
|
||||
int b_real = b * 255.0f;
|
||||
|
||||
m_palette->set_pen_color(index, r_real, g_real, b_real);
|
||||
}
|
||||
|
||||
memset(&m_screenbuf[320 * cliprect.min_y], 0, 4 * 320 * ((cliprect.max_y - cliprect.min_y) + 1));
|
||||
|
||||
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;
|
||||
|
||||
for (uint32_t scanline = (uint32_t)cliprect.min_y; scanline <= (uint32_t)cliprect.max_y; scanline++)
|
||||
{
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
draw_page(cliprect, scanline, i, page2_addr, page2_regs);
|
||||
draw_page(cliprect, scanline, i, page1_addr, page1_regs);
|
||||
draw_sprites(cliprect, scanline, i);
|
||||
}
|
||||
}
|
||||
|
||||
for (int y = cliprect.min_y; y <= cliprect.max_y; y++)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
WRITE_LINE_MEMBER(spg110_video_device::vblank)
|
||||
{
|
||||
if (!state)
|
||||
{
|
||||
m_cpu->set_state_unsynced(UNSP_IRQ0_LINE, ASSERT_LINE);
|
||||
}
|
||||
return;
|
||||
}
|
159
src/devices/machine/spg110_video.h
Normal file
159
src/devices/machine/spg110_video.h
Normal file
@ -0,0 +1,159 @@
|
||||
// license:BSD-3-Clause
|
||||
// copyright-holders:David Haywood
|
||||
|
||||
#ifndef MAME_MACHINE_SPG110_VIDEO_H
|
||||
#define MAME_MACHINE_SPG110_VIDEO_H
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "cpu/unsp/unsp.h"
|
||||
#include "emupal.h"
|
||||
#include "screen.h"
|
||||
|
||||
|
||||
class spg110_video_device : public device_t, public device_memory_interface
|
||||
|
||||
{
|
||||
public:
|
||||
spg110_video_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock);
|
||||
spg110_video_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
|
||||
|
||||
template <typename T, typename U>
|
||||
spg110_video_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock, T &&cpu_tag, U &&screen_tag)
|
||||
: spg110_video_device(mconfig, tag, owner, clock)
|
||||
{
|
||||
m_cpu.set_tag(std::forward<T>(cpu_tag));
|
||||
m_screen.set_tag(std::forward<U>(screen_tag));
|
||||
}
|
||||
|
||||
void map_video(address_map &map);
|
||||
|
||||
double hue2rgb(double p, double q, double t);
|
||||
uint32_t screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect);
|
||||
DECLARE_WRITE_LINE_MEMBER(vblank);
|
||||
|
||||
DECLARE_WRITE16_MEMBER(spg110_201c_w);
|
||||
DECLARE_WRITE16_MEMBER(spg110_2020_w);
|
||||
|
||||
DECLARE_WRITE16_MEMBER(spg110_2028_w);
|
||||
DECLARE_WRITE16_MEMBER(spg110_2029_w);
|
||||
|
||||
DECLARE_READ16_MEMBER(spg110_2028_r);
|
||||
DECLARE_READ16_MEMBER(spg110_2029_r);
|
||||
|
||||
DECLARE_WRITE16_MEMBER(spg110_2031_w);
|
||||
DECLARE_WRITE16_MEMBER(spg110_2032_w);
|
||||
DECLARE_WRITE16_MEMBER(spg110_2033_w);
|
||||
DECLARE_WRITE16_MEMBER(spg110_2034_w);
|
||||
DECLARE_WRITE16_MEMBER(spg110_2035_w);
|
||||
DECLARE_WRITE16_MEMBER(spg110_2036_w);
|
||||
DECLARE_WRITE16_MEMBER(spg110_2037_w);
|
||||
DECLARE_WRITE16_MEMBER(spg110_2039_w);
|
||||
|
||||
DECLARE_WRITE16_MEMBER(spg110_203c_w);
|
||||
DECLARE_WRITE16_MEMBER(spg110_203d_w);
|
||||
|
||||
DECLARE_WRITE16_MEMBER(spg110_2042_w);
|
||||
|
||||
DECLARE_WRITE16_MEMBER(spg110_2045_w);
|
||||
|
||||
DECLARE_WRITE16_MEMBER(spg110_205x_w);
|
||||
|
||||
|
||||
DECLARE_READ16_MEMBER(spg110_2037_r);
|
||||
DECLARE_READ16_MEMBER(spg110_2042_r);
|
||||
|
||||
DECLARE_WRITE16_MEMBER(dma_dst_w);
|
||||
DECLARE_WRITE16_MEMBER(dma_unk_2061_w);
|
||||
DECLARE_WRITE16_MEMBER(dma_len_trigger_w);
|
||||
DECLARE_WRITE16_MEMBER(spg110_2063_w);
|
||||
DECLARE_WRITE16_MEMBER(dma_dst_step_w);
|
||||
DECLARE_WRITE16_MEMBER(dma_src_w);
|
||||
DECLARE_WRITE16_MEMBER(dma_unk_2067_w);
|
||||
DECLARE_WRITE16_MEMBER(dma_src_step_w);
|
||||
|
||||
DECLARE_READ16_MEMBER(dma_len_status_r);
|
||||
DECLARE_READ16_MEMBER(spg110_2063_r);
|
||||
|
||||
DECLARE_READ16_MEMBER(tmap0_regs_r);
|
||||
DECLARE_READ16_MEMBER(tmap1_regs_r);
|
||||
DECLARE_WRITE16_MEMBER(tmap0_regs_w);
|
||||
DECLARE_WRITE16_MEMBER(tmap1_regs_w);
|
||||
|
||||
protected:
|
||||
virtual void device_start() override;
|
||||
virtual void device_reset() override;
|
||||
|
||||
virtual void device_add_mconfig(machine_config &config) override;
|
||||
|
||||
virtual space_config_vector memory_space_config() const override;
|
||||
|
||||
address_space_config m_space_config;
|
||||
|
||||
private:
|
||||
enum
|
||||
{
|
||||
PAGE_ENABLE_MASK = 0x0008,
|
||||
PAGE_WALLPAPER_MASK = 0x0004,
|
||||
|
||||
PAGE_PRIORITY_FLAG_MASK = 0x3000,
|
||||
PAGE_PRIORITY_FLAG_SHIFT = 12,
|
||||
PAGE_TILE_HEIGHT_MASK = 0x00c0,
|
||||
PAGE_TILE_HEIGHT_SHIFT = 6,
|
||||
PAGE_TILE_WIDTH_MASK = 0x0030,
|
||||
PAGE_TILE_WIDTH_SHIFT = 4,
|
||||
|
||||
TILE_X_FLIP = 0x0004,
|
||||
TILE_Y_FLIP = 0x0008
|
||||
};
|
||||
|
||||
enum flipx_t : bool
|
||||
{
|
||||
FlipXOff = false,
|
||||
FlipXOn = true
|
||||
};
|
||||
|
||||
required_device<unsp_device> m_cpu;
|
||||
required_device<screen_device> m_screen;
|
||||
required_device<palette_device> m_palette;
|
||||
required_device<gfxdecode_device> m_gfxdecode;
|
||||
required_shared_ptr<uint16_t> m_palram;
|
||||
required_shared_ptr<uint16_t> m_palctrlram;
|
||||
required_shared_ptr<uint16_t> m_sprtileno;
|
||||
required_shared_ptr<uint16_t> m_sprattr1;
|
||||
required_shared_ptr<uint16_t> m_sprattr2;
|
||||
|
||||
|
||||
uint16_t m_palctrlswapped[0x10];
|
||||
|
||||
|
||||
|
||||
uint16_t tmap0_regs[0x6];
|
||||
uint16_t tmap1_regs[0x6];
|
||||
|
||||
uint16_t m_dma_src_step;
|
||||
uint16_t m_dma_dst_step;
|
||||
uint16_t m_dma_unk_2061;
|
||||
uint16_t m_dma_unk_2067;
|
||||
|
||||
uint16_t m_dma_dst;
|
||||
uint16_t m_dma_src;
|
||||
|
||||
uint16_t m_bg_scrollx;
|
||||
uint16_t m_bg_scrolly;
|
||||
uint16_t m_2036_scroll;
|
||||
|
||||
void tilemap_write_regs(int which, uint16_t* regs, int regno, uint16_t data);
|
||||
|
||||
template<flipx_t FlipX>
|
||||
void draw(const rectangle &cliprect, uint32_t line, uint32_t xoff, uint32_t yoff, uint32_t ctrl, uint32_t bitmap_addr, uint16_t tile, uint8_t pal, int32_t h, int32_t w, uint8_t bpp);
|
||||
void draw_page(const rectangle &cliprect, uint32_t scanline, int priority, uint32_t bitmap_addr, uint16_t *regs);
|
||||
void draw_sprite(const rectangle &cliprect, uint32_t scanline, int priority, uint32_t base_addr);
|
||||
void draw_sprites(const rectangle &cliprect, uint32_t scanline, int priority);
|
||||
|
||||
uint32_t m_screenbuf[320 * 240];
|
||||
};
|
||||
|
||||
DECLARE_DEVICE_TYPE(SPG110_VIDEO, spg110_video_device)
|
||||
|
||||
#endif // MAME_MACHINE_SPG110_VIDEO_H
|
@ -17,30 +17,14 @@
|
||||
DEFINE_DEVICE_TYPE(SPG24X, spg24x_device, "spg24x", "SPG240-series System-on-a-Chip")
|
||||
DEFINE_DEVICE_TYPE(SPG28X, spg28x_device, "spg28x", "SPG280-series System-on-a-Chip")
|
||||
|
||||
#define LOG_UNKNOWN_IO (1U << 3)
|
||||
#define LOG_IRQS (1U << 4)
|
||||
#define LOG_VLINES (1U << 5)
|
||||
#define LOG_DMA (1U << 9)
|
||||
#define LOG_PPU_READS (1U << 22)
|
||||
#define LOG_PPU_WRITES (1U << 23)
|
||||
#define LOG_UNKNOWN_PPU (1U << 24)
|
||||
#define LOG_IO (LOG_IRQS | LOG_DMA | LOG_UNKNOWN_IO)
|
||||
#define LOG_PPU (LOG_PPU_READS | LOG_PPU_WRITES | LOG_UNKNOWN_PPU)
|
||||
#define LOG_ALL (LOG_IO | LOG_PPU | LOG_VLINES )
|
||||
|
||||
#define VERBOSE (0)
|
||||
#include "logmacro.h"
|
||||
|
||||
#define SPG_DEBUG_VIDEO (0)
|
||||
|
||||
#define VIDEO_IRQ_ENABLE m_video_regs[0x62]
|
||||
#define VIDEO_IRQ_STATUS m_video_regs[0x63]
|
||||
|
||||
spg2xx_device::spg2xx_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock)
|
||||
: device_t(mconfig, type, tag, owner, clock)
|
||||
, device_mixer_interface(mconfig, *this, 2)
|
||||
, m_spg_audio(*this, "spgaudio")
|
||||
, m_spg_io(*this, "spgio")
|
||||
, m_spg_sysdma(*this, "spgsysdma")
|
||||
, m_spg_video(*this, "spgvideo")
|
||||
, m_rowscrolloffset(15)
|
||||
, m_porta_out(*this)
|
||||
, m_portb_out(*this)
|
||||
@ -55,9 +39,6 @@ spg2xx_device::spg2xx_device(const machine_config &mconfig, device_type type, co
|
||||
, m_chip_sel(*this)
|
||||
, m_cpu(*this, finder_base::DUMMY_TAG)
|
||||
, m_screen(*this, finder_base::DUMMY_TAG)
|
||||
, m_scrollram(*this, "scrollram")
|
||||
, m_paletteram(*this, "paletteram")
|
||||
, m_spriteram(*this, "spriteram")
|
||||
{
|
||||
}
|
||||
|
||||
@ -74,30 +55,20 @@ spg28x_device::spg28x_device(const machine_config &mconfig, const char *tag, dev
|
||||
void spg2xx_device::map(address_map &map)
|
||||
{
|
||||
map(0x000000, 0x0027ff).ram();
|
||||
map(0x002800, 0x0028ff).rw(FUNC(spg2xx_device::video_r), FUNC(spg2xx_device::video_w));
|
||||
map(0x002900, 0x002aff).ram().share("scrollram");
|
||||
map(0x002b00, 0x002bff).ram().share("paletteram");
|
||||
map(0x002c00, 0x002fff).ram().share("spriteram");
|
||||
map(0x002800, 0x0028ff).rw(m_spg_video, FUNC(spg2xx_video_device::video_r), FUNC(spg2xx_video_device::video_w));
|
||||
map(0x002900, 0x002aff).ram().share("spgvideo:scrollram");
|
||||
map(0x002b00, 0x002bff).ram().share("spgvideo:paletteram");
|
||||
map(0x002c00, 0x002fff).ram().share("spgvideo:spriteram");
|
||||
map(0x003000, 0x0031ff).rw(m_spg_audio, FUNC(spg2xx_audio_device::audio_r), FUNC(spg2xx_audio_device::audio_w));
|
||||
map(0x003200, 0x0033ff).rw(m_spg_audio, FUNC(spg2xx_audio_device::audio_phase_r), FUNC(spg2xx_audio_device::audio_phase_w));
|
||||
map(0x003400, 0x0037ff).rw(m_spg_audio, FUNC(spg2xx_audio_device::audio_ctrl_r), FUNC(spg2xx_audio_device::audio_ctrl_w));
|
||||
map(0x003d00, 0x003d2f).rw(m_spg_io, FUNC(spg2xx_io_device::io_r), FUNC(spg2xx_io_device::io_w));
|
||||
map(0x003d30, 0x003dff).rw(m_spg_io, FUNC(spg2xx_io_device::io_extended_r), FUNC(spg2xx_io_device::io_extended_w));
|
||||
map(0x003e00, 0x003e03).rw(FUNC(spg2xx_device::dma_r), FUNC(spg2xx_device::dma_w));
|
||||
map(0x003e00, 0x003e03).rw(m_spg_sysdma, FUNC(spg2xx_sysdma_device::dma_r), FUNC(spg2xx_sysdma_device::dma_w));
|
||||
}
|
||||
|
||||
void spg2xx_device::device_start()
|
||||
{
|
||||
for (uint8_t i = 0; i < 32; i++)
|
||||
{
|
||||
m_rgb5_to_rgb8[i] = (i << 3) | (i >> 2);
|
||||
}
|
||||
for (uint16_t i = 0; i < 0x8000; i++)
|
||||
{
|
||||
m_rgb555_to_rgb888[i] = (m_rgb5_to_rgb8[(i >> 10) & 0x1f] << 16) |
|
||||
(m_rgb5_to_rgb8[(i >> 5) & 0x1f] << 8) |
|
||||
(m_rgb5_to_rgb8[(i >> 0) & 0x1f] << 0);
|
||||
}
|
||||
m_porta_out.resolve_safe();
|
||||
m_portb_out.resolve_safe();
|
||||
m_portc_out.resolve_safe();
|
||||
@ -111,47 +82,17 @@ void spg2xx_device::device_start()
|
||||
m_uart_tx.resolve_safe();
|
||||
m_chip_sel.resolve_safe();
|
||||
|
||||
m_screenpos_timer = timer_alloc(TIMER_SCREENPOS);
|
||||
m_screenpos_timer->adjust(attotime::never);
|
||||
|
||||
save_item(NAME(m_hide_page0));
|
||||
save_item(NAME(m_hide_page1));
|
||||
save_item(NAME(m_hide_sprites));
|
||||
save_item(NAME(m_debug_sprites));
|
||||
save_item(NAME(m_debug_blit));
|
||||
save_item(NAME(m_debug_palette));
|
||||
save_item(NAME(m_sprite_index_to_debug));
|
||||
|
||||
save_item(NAME(m_dma_regs));
|
||||
|
||||
save_item(NAME(m_video_regs));
|
||||
save_item(NAME(m_sprite_limit));
|
||||
save_item(NAME(m_pal_flag));
|
||||
}
|
||||
|
||||
void spg2xx_device::device_reset()
|
||||
{
|
||||
memset(m_video_regs, 0, 0x100 * sizeof(uint16_t));
|
||||
memset(m_dma_regs, 0, 0x4 * sizeof(uint16_t));
|
||||
|
||||
m_video_regs[0x36] = 0xffff;
|
||||
m_video_regs[0x37] = 0xffff;
|
||||
m_video_regs[0x3c] = 0x0020;
|
||||
m_video_regs[0x42] = 0x0001;
|
||||
|
||||
m_hide_page0 = false;
|
||||
m_hide_page1 = false;
|
||||
m_hide_sprites = false;
|
||||
m_debug_sprites = false;
|
||||
m_debug_blit = false;
|
||||
m_debug_palette = false;
|
||||
m_sprite_index_to_debug = 0;
|
||||
}
|
||||
|
||||
|
||||
WRITE_LINE_MEMBER(spg2xx_device::audioirq_w)
|
||||
WRITE_LINE_MEMBER(spg2xx_device::videoirq_w)
|
||||
{
|
||||
m_cpu->set_state_unsynced(UNSP_IRQ4_LINE, state);
|
||||
m_cpu->set_state_unsynced(UNSP_IRQ0_LINE, state);
|
||||
}
|
||||
|
||||
WRITE_LINE_MEMBER(spg2xx_device::timerirq_w)
|
||||
@ -164,6 +105,11 @@ WRITE_LINE_MEMBER(spg2xx_device::uartirq_w)
|
||||
m_cpu->set_state_unsynced(UNSP_IRQ3_LINE, state);
|
||||
}
|
||||
|
||||
WRITE_LINE_MEMBER(spg2xx_device::audioirq_w)
|
||||
{
|
||||
m_cpu->set_state_unsynced(UNSP_IRQ4_LINE, state);
|
||||
}
|
||||
|
||||
WRITE_LINE_MEMBER(spg2xx_device::extirq_w)
|
||||
{
|
||||
m_cpu->set_state_unsynced(UNSP_IRQ5_LINE, state);
|
||||
@ -187,824 +133,6 @@ READ16_MEMBER(spg2xx_device::space_r)
|
||||
return cpuspace.read_word(offset);
|
||||
}
|
||||
|
||||
/*************************
|
||||
* Video Hardware *
|
||||
*************************/
|
||||
|
||||
// Perform a lerp between a and b
|
||||
inline uint8_t spg2xx_device::mix_channel(uint8_t bottom, uint8_t top)
|
||||
{
|
||||
uint8_t alpha = (m_video_regs[0x2a] & 3) << 6;
|
||||
return ((256 - alpha) * bottom + alpha * top) >> 8;
|
||||
}
|
||||
|
||||
template<spg2xx_device::blend_enable_t Blend, spg2xx_device::rowscroll_enable_t RowScroll, spg2xx_device::flipx_t FlipX>
|
||||
void spg2xx_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)
|
||||
{
|
||||
address_space &space = m_cpu->space(AS_PROGRAM);
|
||||
|
||||
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);
|
||||
|
||||
uint32_t yflipmask = attr & TILE_Y_FLIP ? h - 1 : 0;
|
||||
|
||||
uint32_t nc = ((attr & 0x0003) + 1) << 1;
|
||||
|
||||
uint32_t palette_offset = (attr & 0x0f00) >> 4;
|
||||
if (SPG_DEBUG_VIDEO && m_debug_blit)
|
||||
{
|
||||
printf("s:%d line:%d xy:%08x,%08x attr:%08x ctrl:%08x bitmap_addr:%08x tile:%04x\n", cliprect.min_x, line, xoff, yoff, attr, ctrl, bitmap_addr, tile);
|
||||
printf("hw:%d,%d f:%d,%d yfm:%d ncols:%d pobs:%02x ", w, h, (attr & TILE_X_FLIP) ? 1 : 0, (attr & TILE_Y_FLIP) ? 1 : 0, yflipmask, nc, palette_offset);
|
||||
}
|
||||
palette_offset >>= nc;
|
||||
palette_offset <<= nc;
|
||||
if (SPG_DEBUG_VIDEO && m_debug_blit)
|
||||
{
|
||||
printf("poas:%02x\n", palette_offset);
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
if (SPG_DEBUG_VIDEO && m_debug_blit)
|
||||
printf("%3d:\n", yy);
|
||||
|
||||
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 (SPG_DEBUG_VIDEO && m_debug_blit)
|
||||
printf(" %08x:%d ", bits, nbits);
|
||||
if (nbits < nc)
|
||||
{
|
||||
uint16_t b = space.read_word(m++ & 0x3fffff);
|
||||
b = (b << 8) | (b >> 8);
|
||||
bits |= b << (nc - nbits);
|
||||
nbits += 16;
|
||||
if (SPG_DEBUG_VIDEO && m_debug_blit)
|
||||
printf("(%04x:%08x:%d) ", b, bits, nbits);
|
||||
}
|
||||
nbits -= nc;
|
||||
|
||||
uint32_t pal = palette_offset + (bits >> 16);
|
||||
if (SPG_DEBUG_VIDEO && m_debug_blit)
|
||||
printf("%02x:%02x:%04x ", bits >> 16, pal, bits & 0xffff);
|
||||
bits &= 0xffff;
|
||||
|
||||
if (RowScroll)
|
||||
xx -= (int16_t)m_scrollram[(yy + m_rowscrolloffset) & 0x1ff];
|
||||
|
||||
xx &= 0x01ff;
|
||||
if (xx >= 0x01c0)
|
||||
xx -= 0x0200;
|
||||
|
||||
if (xx >= 0 && xx < 320)
|
||||
{
|
||||
int pix_index = xx + y_index;
|
||||
|
||||
uint16_t rgb = m_paletteram[pal];
|
||||
if (SPG_DEBUG_VIDEO && m_debug_blit)
|
||||
printf("rgb:%04x ", rgb);
|
||||
|
||||
if (!(rgb & 0x8000))
|
||||
{
|
||||
if (Blend)
|
||||
{
|
||||
if (SPG_DEBUG_VIDEO && m_debug_blit)
|
||||
printf("M\n");
|
||||
m_screenbuf[pix_index] = (mix_channel((uint8_t)(m_screenbuf[pix_index] >> 16), m_rgb5_to_rgb8[(rgb >> 10) & 0x1f]) << 16) |
|
||||
(mix_channel((uint8_t)(m_screenbuf[pix_index] >> 8), m_rgb5_to_rgb8[(rgb >> 5) & 0x1f]) << 8) |
|
||||
(mix_channel((uint8_t)(m_screenbuf[pix_index] >> 0), m_rgb5_to_rgb8[rgb & 0x1f]));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (SPG_DEBUG_VIDEO && m_debug_blit)
|
||||
printf("S\n");
|
||||
m_screenbuf[pix_index] = m_rgb555_to_rgb888[rgb];
|
||||
}
|
||||
}
|
||||
else if (SPG_DEBUG_VIDEO && m_debug_blit)
|
||||
{
|
||||
printf("X\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void spg2xx_device::blit_page(const rectangle &cliprect, uint32_t scanline, int depth, uint32_t bitmap_addr, uint16_t *regs)
|
||||
{
|
||||
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 &space = m_cpu->space(AS_PROGRAM);
|
||||
|
||||
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;
|
||||
if (SPG_DEBUG_VIDEO && machine().input().code_pressed(KEYCODE_H))
|
||||
printf("s:%3d | baddr:%08x | yscr:%3d | bity:%3d | y0:%2d | ts:%2d\n", scanline, bitmap_addr, yscroll, bitmap_y, y0, tile_scanline);
|
||||
|
||||
if (SPG_DEBUG_VIDEO && machine().input().code_pressed(KEYCODE_EQUALS))
|
||||
m_debug_blit = true;
|
||||
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) ? space.read_word(tilemap) : space.read_word(tilemap + tile_address);
|
||||
uint16_t palette = 0;
|
||||
|
||||
if (!tile)
|
||||
continue;
|
||||
|
||||
palette = (ctrl & PAGE_WALLPAPER_MASK) ? space.read_word(palette_map) : space.read_word(palette_map + tile_address / 2);
|
||||
if (x0 & 1)
|
||||
palette >>= 8;
|
||||
|
||||
uint32_t tileattr = attr;
|
||||
uint32_t tilectrl = ctrl;
|
||||
if ((ctrl & 2) == 0)
|
||||
{ // -(1) bld(1) flip(2) pal(4)
|
||||
tileattr &= ~0x000c;
|
||||
tileattr |= (palette >> 2) & 0x000c; // flip
|
||||
|
||||
tileattr &= ~0x0f00;
|
||||
tileattr |= (palette << 8) & 0x0f00; // palette
|
||||
|
||||
tilectrl &= ~0x0100;
|
||||
tilectrl |= (palette << 2) & 0x0100; // blend
|
||||
}
|
||||
|
||||
bool blend = (tileattr & 0x4000 || tilectrl & 0x0100);
|
||||
bool row_scroll = (tilectrl & 0x0010);
|
||||
bool flip_x = (tileattr & TILE_X_FLIP);
|
||||
|
||||
if (blend)
|
||||
{
|
||||
if (row_scroll)
|
||||
{
|
||||
if (flip_x)
|
||||
blit<BlendOn, RowScrollOn, FlipXOn>(cliprect, tile_scanline, xx, yy, tileattr, tilectrl, bitmap_addr, tile);
|
||||
else
|
||||
blit<BlendOn, RowScrollOn, FlipXOff>(cliprect, tile_scanline, xx, yy, tileattr, tilectrl, bitmap_addr, tile);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (flip_x)
|
||||
blit<BlendOn, RowScrollOff, FlipXOn>(cliprect, tile_scanline, xx, yy, tileattr, tilectrl, bitmap_addr, tile);
|
||||
else
|
||||
blit<BlendOn, RowScrollOff, FlipXOff>(cliprect, tile_scanline, xx, yy, tileattr, tilectrl, bitmap_addr, tile);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (row_scroll)
|
||||
{
|
||||
if (flip_x)
|
||||
blit<BlendOff, RowScrollOn, FlipXOn>(cliprect, tile_scanline, xx, yy, tileattr, tilectrl, bitmap_addr, tile);
|
||||
else
|
||||
blit<BlendOff, RowScrollOn, FlipXOff>(cliprect, tile_scanline, xx, yy, tileattr, tilectrl, bitmap_addr, tile);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (flip_x)
|
||||
blit<BlendOff, RowScrollOff, FlipXOn>(cliprect, tile_scanline, xx, yy, tileattr, tilectrl, bitmap_addr, tile);
|
||||
else
|
||||
blit<BlendOff, RowScrollOff, FlipXOff>(cliprect, tile_scanline, xx, yy, tileattr, tilectrl, bitmap_addr, tile);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (SPG_DEBUG_VIDEO && machine().input().code_pressed(KEYCODE_EQUALS))
|
||||
m_debug_blit = false;
|
||||
}
|
||||
|
||||
void spg2xx_device::blit_sprite(const rectangle &cliprect, uint32_t scanline, int depth, uint32_t base_addr)
|
||||
{
|
||||
uint32_t bitmap_addr = 0x40 * m_video_regs[0x22];
|
||||
uint16_t tile = m_spriteram[base_addr + 0];
|
||||
int16_t x = m_spriteram[base_addr + 1];
|
||||
int16_t y = m_spriteram[base_addr + 2];
|
||||
uint16_t attr = m_spriteram[base_addr + 3];
|
||||
|
||||
if (!tile)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (((attr & PAGE_DEPTH_FLAG_MASK) >> PAGE_DEPTH_FLAG_SHIFT) != depth)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
const uint32_t h = 8 << ((attr & PAGE_TILE_HEIGHT_MASK) >> PAGE_TILE_HEIGHT_SHIFT);
|
||||
const uint32_t w = 8 << ((attr & PAGE_TILE_WIDTH_MASK) >> PAGE_TILE_WIDTH_SHIFT);
|
||||
|
||||
if (!(m_video_regs[0x42] & SPRITE_COORD_TL_MASK))
|
||||
{
|
||||
x = (160 + x) - w / 2;
|
||||
y = (120 - y) - (h / 2) + 8;
|
||||
}
|
||||
|
||||
x &= 0x01ff;
|
||||
y &= 0x01ff;
|
||||
|
||||
uint32_t tile_line = ((scanline - y) + 0x200) % h;
|
||||
int16_t test_y = (y + tile_line) & 0x1ff;
|
||||
if (test_y >= 0x01c0)
|
||||
test_y -= 0x0200;
|
||||
|
||||
if (test_y != scanline)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
bool blend = (attr & 0x4000);
|
||||
bool flip_x = (attr & TILE_X_FLIP);
|
||||
|
||||
#if SPG_DEBUG_VIDEO
|
||||
if (m_debug_sprites && machine().input().code_pressed(KEYCODE_MINUS))
|
||||
m_debug_blit = true;
|
||||
if (blend)
|
||||
{
|
||||
if (flip_x)
|
||||
blit<BlendOn, RowScrollOff, FlipXOn>(cliprect, tile_line, x, y, attr, 0, bitmap_addr, tile);
|
||||
else
|
||||
blit<BlendOn, RowScrollOff, FlipXOff>(cliprect, tile_line, x, y, attr, 0, bitmap_addr, tile);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (flip_x)
|
||||
blit<BlendOff, RowScrollOff, FlipXOn>(cliprect, tile_line, x, y, attr, 0, bitmap_addr, tile);
|
||||
else
|
||||
blit<BlendOff, RowScrollOff, FlipXOff>(cliprect, tile_line, x, y, attr, 0, bitmap_addr, tile);
|
||||
}
|
||||
m_debug_blit = false;
|
||||
#else
|
||||
if (blend)
|
||||
{
|
||||
if (flip_x)
|
||||
blit<BlendOn, RowScrollOff, FlipXOn>(cliprect, tile_line, x, y, attr, 0, bitmap_addr, tile);
|
||||
else
|
||||
blit<BlendOn, RowScrollOff, FlipXOff>(cliprect, tile_line, x, y, attr, 0, bitmap_addr, tile);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (flip_x)
|
||||
blit<BlendOff, RowScrollOff, FlipXOn>(cliprect, tile_line, x, y, attr, 0, bitmap_addr, tile);
|
||||
else
|
||||
blit<BlendOff, RowScrollOff, FlipXOff>(cliprect, tile_line, x, y, attr, 0, bitmap_addr, tile);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void spg2xx_device::blit_sprites(const rectangle &cliprect, uint32_t scanline, int depth)
|
||||
{
|
||||
if (!(m_video_regs[0x42] & SPRITE_ENABLE_MASK))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
#if SPG_DEBUG_VIDEO
|
||||
if (!m_debug_sprites)
|
||||
{
|
||||
#endif
|
||||
for (uint32_t n = 0; n < m_sprite_limit; n++)
|
||||
{
|
||||
blit_sprite(cliprect, scanline, depth, 4 * n);
|
||||
}
|
||||
#if SPG_DEBUG_VIDEO
|
||||
}
|
||||
else
|
||||
{
|
||||
blit_sprite(cliprect, scanline, depth, 4 * m_sprite_index_to_debug);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void spg2xx_device::apply_saturation(const rectangle &cliprect)
|
||||
{
|
||||
static const float s_u8_to_float = 1.0f / 255.0f;
|
||||
static const float s_gray_r = 0.299f;
|
||||
static const float s_gray_g = 0.587f;
|
||||
static const float s_gray_b = 0.114f;
|
||||
const float sat_adjust = (0xff - (m_video_regs[0x3c] & 0x00ff)) / (float)(0xff - 0x20);
|
||||
for (int y = cliprect.min_y; y <= cliprect.max_y; y++)
|
||||
{
|
||||
uint32_t *src = &m_screenbuf[cliprect.min_x + 320 * y];
|
||||
for (int x = cliprect.min_x; x <= cliprect.max_x; x++)
|
||||
{
|
||||
const uint32_t src_rgb = *src;
|
||||
const float src_r = (uint8_t)(src_rgb >> 16) * s_u8_to_float;
|
||||
const float src_g = (uint8_t)(src_rgb >> 8) * s_u8_to_float;
|
||||
const float src_b = (uint8_t)(src_rgb >> 0) * s_u8_to_float;
|
||||
const float luma = src_r * s_gray_r + src_g * s_gray_g + src_b * s_gray_b;
|
||||
const float adjusted_r = luma + (src_r - luma) * sat_adjust;
|
||||
const float adjusted_g = luma + (src_g - luma) * sat_adjust;
|
||||
const float adjusted_b = luma + (src_b - luma) * sat_adjust;
|
||||
const int integer_r = (int)floor(adjusted_r * 255.0f);
|
||||
const int integer_g = (int)floor(adjusted_g * 255.0f);
|
||||
const int integer_b = (int)floor(adjusted_b * 255.0f);
|
||||
*src++ = (integer_r > 255 ? 0xff0000 : (integer_r < 0 ? 0 : ((uint8_t)integer_r << 16))) |
|
||||
(integer_g > 255 ? 0x00ff00 : (integer_g < 0 ? 0 : ((uint8_t)integer_g << 8))) |
|
||||
(integer_b > 255 ? 0x0000ff : (integer_b < 0 ? 0 : (uint8_t)integer_b));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void spg2xx_device::apply_fade(const rectangle &cliprect)
|
||||
{
|
||||
const uint16_t fade_offset = m_video_regs[0x30];
|
||||
for (int y = cliprect.min_y; y <= cliprect.max_y; y++)
|
||||
{
|
||||
uint32_t *src = &m_screenbuf[cliprect.min_x + 320 * y];
|
||||
for (int x = cliprect.min_x; x <= cliprect.max_x; x++)
|
||||
{
|
||||
const uint32_t src_rgb = *src;
|
||||
const uint8_t src_r = (src_rgb >> 16) & 0xff;
|
||||
const uint8_t src_g = (src_rgb >> 8) & 0xff;
|
||||
const uint8_t src_b = (src_rgb >> 0) & 0xff;
|
||||
const uint8_t r = src_r - fade_offset;
|
||||
const uint8_t g = src_g - fade_offset;
|
||||
const uint8_t b = src_b - fade_offset;
|
||||
*src++ = (r > src_r ? 0 : (r << 16)) |
|
||||
(g > src_g ? 0 : (g << 8)) |
|
||||
(b > src_b ? 0 : (b << 0));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t spg2xx_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
|
||||
{
|
||||
memset(&m_screenbuf[320 * cliprect.min_y], 0, 4 * 320 * ((cliprect.max_y - cliprect.min_y) + 1));
|
||||
|
||||
const uint32_t page1_addr = 0x40 * m_video_regs[0x20];
|
||||
const uint32_t page2_addr = 0x40 * m_video_regs[0x21];
|
||||
uint16_t *page1_regs = m_video_regs + 0x10;
|
||||
uint16_t *page2_regs = m_video_regs + 0x16;
|
||||
|
||||
for (uint32_t scanline = (uint32_t)cliprect.min_y; scanline <= (uint32_t)cliprect.max_y; scanline++)
|
||||
{
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
if (!SPG_DEBUG_VIDEO || !m_hide_page0)
|
||||
blit_page(cliprect, scanline, i, page1_addr, page1_regs);
|
||||
if (!SPG_DEBUG_VIDEO || !m_hide_page1)
|
||||
blit_page(cliprect, scanline, i, page2_addr, page2_regs);
|
||||
if (!SPG_DEBUG_VIDEO || !m_hide_sprites)
|
||||
blit_sprites(cliprect, scanline, i);
|
||||
}
|
||||
}
|
||||
|
||||
if ((m_video_regs[0x3c] & 0x00ff) != 0x0020)
|
||||
{
|
||||
apply_saturation(cliprect);
|
||||
}
|
||||
|
||||
if (m_video_regs[0x30] != 0)
|
||||
{
|
||||
apply_fade(cliprect);
|
||||
}
|
||||
|
||||
for (int y = cliprect.min_y; y <= cliprect.max_y; y++)
|
||||
{
|
||||
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));
|
||||
}
|
||||
|
||||
if (SPG_DEBUG_VIDEO && m_debug_palette)
|
||||
{
|
||||
for (int y = cliprect.min_y; y <= cliprect.max_y && y < 128; y++)
|
||||
{
|
||||
const uint16_t high_nybble = (y / 8) << 4;
|
||||
uint32_t *dest = &bitmap.pix32(y, cliprect.min_x);
|
||||
for (int x = cliprect.min_x; x <= cliprect.max_x && x < 256; x++)
|
||||
{
|
||||
const uint16_t low_nybble = x / 16;
|
||||
const uint16_t palette_entry = high_nybble | low_nybble;
|
||||
const uint16_t color = m_paletteram[palette_entry];
|
||||
if (!(color & 0x8000))
|
||||
{
|
||||
*dest = m_rgb555_to_rgb888[color & 0x7fff];
|
||||
}
|
||||
dest++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void spg2xx_device::do_sprite_dma(uint32_t len)
|
||||
{
|
||||
address_space &mem = m_cpu->space(AS_PROGRAM);
|
||||
|
||||
uint32_t src = m_video_regs[0x70] & 0x3fff;
|
||||
uint32_t dst = m_video_regs[0x71];
|
||||
|
||||
for (uint32_t j = 0; j < len; j++)
|
||||
{
|
||||
m_spriteram[(dst + j) & 0x3ff] = mem.read_word(src + j);
|
||||
}
|
||||
|
||||
m_video_regs[0x72] = 0;
|
||||
if (VIDEO_IRQ_ENABLE & 4)
|
||||
{
|
||||
const uint16_t old = VIDEO_IRQ_STATUS;
|
||||
VIDEO_IRQ_STATUS |= 4;
|
||||
const uint16_t changed = old ^ (VIDEO_IRQ_ENABLE & VIDEO_IRQ_STATUS);
|
||||
if (changed)
|
||||
check_video_irq();
|
||||
}
|
||||
}
|
||||
|
||||
READ16_MEMBER(spg2xx_device::video_r)
|
||||
{
|
||||
switch (offset)
|
||||
{
|
||||
case 0x38: // Current Line
|
||||
LOGMASKED(LOG_VLINES, "video_r: Current Line: %04x\n", m_screen->vpos());
|
||||
return m_screen->vpos();
|
||||
|
||||
case 0x62: // Video IRQ Enable
|
||||
LOGMASKED(LOG_IRQS, "video_r: Video IRQ Enable: %04x\n", VIDEO_IRQ_ENABLE);
|
||||
return VIDEO_IRQ_ENABLE;
|
||||
|
||||
case 0x63: // Video IRQ Status
|
||||
LOGMASKED(LOG_IRQS, "video_r: Video IRQ Status: %04x\n", VIDEO_IRQ_STATUS);
|
||||
return VIDEO_IRQ_STATUS;
|
||||
|
||||
default:
|
||||
LOGMASKED(LOG_UNKNOWN_PPU, "video_r: Unknown register %04x = %04x\n", 0x2800 + offset, m_video_regs[offset]);
|
||||
break;
|
||||
}
|
||||
return m_video_regs[offset];
|
||||
}
|
||||
|
||||
WRITE16_MEMBER(spg2xx_device::video_w)
|
||||
{
|
||||
switch (offset)
|
||||
{
|
||||
case 0x10: // Page 1 X scroll
|
||||
LOGMASKED(LOG_PPU_WRITES, "video_w: Page 1 X Scroll = %04x\n", data & 0x01ff);
|
||||
m_video_regs[offset] = data & 0x01ff;
|
||||
break;
|
||||
|
||||
case 0x11: // Page 1 Y scroll
|
||||
LOGMASKED(LOG_PPU_WRITES, "video_w: Page 1 Y Scroll = %04x\n", data & 0x00ff);
|
||||
m_video_regs[offset] = data & 0x00ff;
|
||||
break;
|
||||
|
||||
case 0x12: // Page 1 Attributes
|
||||
LOGMASKED(LOG_PPU_WRITES, "video_w: Page 1 Attributes = %04x (Depth:%d, Palette:%d, VSize:%d, HSize:%d, FlipY:%d, FlipX:%d, BPP:%d)\n", 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));
|
||||
m_video_regs[offset] = data;
|
||||
break;
|
||||
|
||||
case 0x13: // Page 1 Control
|
||||
LOGMASKED(LOG_PPU_WRITES, "video_w: Page 1 Control = %04x (Blend:%d, HiColor:%d, RowScroll:%d, Enable:%d, Wallpaper:%d, RegSet:%d, Bitmap:%d)\n", data
|
||||
, BIT(data, 8), BIT(data, 7), BIT(data, 4), BIT(data, 3), BIT(data, 2), BIT(data, 1), BIT(data, 0));
|
||||
m_video_regs[offset] = data;
|
||||
break;
|
||||
|
||||
case 0x14: // Page 1 Tile Address
|
||||
LOGMASKED(LOG_PPU_WRITES, "video_w: Page 1 Tile Address = %04x\n", data & 0x1fff);
|
||||
m_video_regs[offset] = data;
|
||||
break;
|
||||
|
||||
case 0x15: // Page 1 Attribute Address
|
||||
LOGMASKED(LOG_PPU_WRITES, "video_w: Page 1 Attribute Address = %04x\n", data & 0x1fff);
|
||||
m_video_regs[offset] = data;
|
||||
break;
|
||||
|
||||
case 0x16: // Page 2 X scroll
|
||||
LOGMASKED(LOG_PPU_WRITES, "video_w: Page 2 X Scroll = %04x\n", data & 0x01ff);
|
||||
m_video_regs[offset] = data & 0x01ff;
|
||||
break;
|
||||
|
||||
case 0x17: // Page 2 Y scroll
|
||||
LOGMASKED(LOG_PPU_WRITES, "video_w: Page 2 Y Scroll: %04x = %04x\n", 0x2800 | offset, data & 0x00ff);
|
||||
m_video_regs[offset] = data & 0x00ff;
|
||||
break;
|
||||
|
||||
case 0x18: // Page 2 Attributes
|
||||
LOGMASKED(LOG_PPU_WRITES, "video_w: Page 2 Attributes = %04x (Depth:%d, Palette:%d, VSize:%d, HSize:%d, FlipY:%d, FlipX:%d, BPP:%d)\n", 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));
|
||||
m_video_regs[offset] = data;
|
||||
break;
|
||||
|
||||
case 0x19: // Page 2 Control
|
||||
LOGMASKED(LOG_PPU_WRITES, "video_w: Page 2 Control = %04x (Blend:%d, HiColor:%d, RowScroll:%d, Enable:%d, Wallpaper:%d, RegSet:%d, Bitmap:%d)\n", data
|
||||
, BIT(data, 8), BIT(data, 7), BIT(data, 4), BIT(data, 3), BIT(data, 2), BIT(data, 1), BIT(data, 0));
|
||||
m_video_regs[offset] = data;
|
||||
break;
|
||||
|
||||
case 0x1a: // Page 2 Tile Address
|
||||
LOGMASKED(LOG_PPU_WRITES, "video_w: Page 2 Tile Address = %04x\n", data & 0x1fff);
|
||||
m_video_regs[offset] = data;
|
||||
break;
|
||||
|
||||
case 0x1b: // Page 2 Attribute Address
|
||||
LOGMASKED(LOG_PPU_WRITES, "video_w: Page 2 Attribute Address = %04x\n", data & 0x1fff);
|
||||
m_video_regs[offset] = data;
|
||||
break;
|
||||
|
||||
case 0x20: // Page 1 Segment Address
|
||||
LOGMASKED(LOG_PPU_WRITES, "video_w: Page 1 Segment Address = %04x\n", data);
|
||||
m_video_regs[offset] = data;
|
||||
break;
|
||||
|
||||
case 0x21: // Page 2 Segment Address
|
||||
LOGMASKED(LOG_PPU_WRITES, "video_w: Page 2 Segment Address = %04x\n", data);
|
||||
m_video_regs[offset] = data;
|
||||
break;
|
||||
|
||||
case 0x22: // Sprite Segment Address
|
||||
LOGMASKED(LOG_PPU_WRITES, "video_w: Sprite Segment Address = %04x\n", data);
|
||||
m_video_regs[offset] = data;
|
||||
break;
|
||||
|
||||
case 0x2a: // Blend Level Control
|
||||
LOGMASKED(LOG_PPU_WRITES, "video_w: Blend Level Control = %04x\n", data & 0x0003);
|
||||
m_video_regs[offset] = data & 0x0003;
|
||||
break;
|
||||
|
||||
case 0x30: // Fade Effect Control
|
||||
LOGMASKED(LOG_PPU_WRITES, "video_w: Fade Effect Control = %04x\n", data & 0x00ff);
|
||||
m_video_regs[offset] = data & 0x00ff;
|
||||
break;
|
||||
|
||||
case 0x36: // IRQ pos V
|
||||
case 0x37: // IRQ pos H
|
||||
m_video_regs[offset] = data & 0x01ff;
|
||||
LOGMASKED(LOG_IRQS, "video_w: Video IRQ Position: %04x,%04x (%04x)\n", m_video_regs[0x37], m_video_regs[0x36], 0x2800 | offset);
|
||||
if (m_video_regs[0x37] < 160 && m_video_regs[0x36] < 240)
|
||||
m_screenpos_timer->adjust(m_screen->time_until_pos(m_video_regs[0x36], m_video_regs[0x37] << 1));
|
||||
else
|
||||
m_screenpos_timer->adjust(attotime::never);
|
||||
break;
|
||||
|
||||
case 0x39: // Latch 1st Line Pen Pulse
|
||||
LOGMASKED(LOG_PPU_WRITES, "video_w: Latch 1st Line Pen Pulse = %04x\n", data & 0x0001);
|
||||
m_video_regs[offset] = data & 0x0001;
|
||||
break;
|
||||
|
||||
case 0x3c: // TV Control 1
|
||||
LOGMASKED(LOG_PPU_WRITES, "video_w: TV Control 1 = %04x (Hue:%02x, Saturation:%02x)\n", data, data >> 8, data & 0x00ff);
|
||||
m_video_regs[offset] = data;
|
||||
break;
|
||||
|
||||
case 0x3d: // TV Control 2
|
||||
{
|
||||
static const char* const s_lpf_mode[4] = { "LPF1", "LPF2", "All", "Edge" };
|
||||
LOGMASKED(LOG_PPU_WRITES, "video_w: TV Control 2 = %04x (LPFMode:%s, Enable:%d, Interlace:%d)\n", data & 0x000f
|
||||
, s_lpf_mode[(data >> 2) & 3], BIT(data, 1), BIT(data, 0));
|
||||
m_video_regs[offset] = data & 0x000f;
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x3e: // Light Pen Y Position
|
||||
LOGMASKED(LOG_PPU_WRITES, "video_w: Light Pen Y (read only) = %04x\n", data & 0x01ff);
|
||||
break;
|
||||
|
||||
case 0x3f: // Light Pen YXPosition
|
||||
LOGMASKED(LOG_PPU_WRITES, "video_w: Light Pen X (read only) = %04x\n", data & 0x01ff);
|
||||
break;
|
||||
|
||||
case 0x42: // Sprite Control
|
||||
LOGMASKED(LOG_PPU_WRITES, "video_w: Sprite Control = %04x (TopLeft:%d, Enable:%d)\n", data & 0x0003, BIT(data, 1), BIT(data, 0));
|
||||
m_video_regs[offset] = data & 0x0003;
|
||||
break;
|
||||
|
||||
case 0x62: // Video IRQ Enable
|
||||
{
|
||||
LOGMASKED(LOG_IRQS, "video_w: Video IRQ Enable = %04x (DMA:%d, Timing:%d, Blanking:%d)\n", data & 0x0007, BIT(data, 2), BIT(data, 1), BIT(data, 0));
|
||||
const uint16_t old = VIDEO_IRQ_ENABLE & VIDEO_IRQ_STATUS;
|
||||
VIDEO_IRQ_ENABLE = data & 0x0007;
|
||||
const uint16_t changed = old ^ (VIDEO_IRQ_ENABLE & VIDEO_IRQ_STATUS);
|
||||
if (changed)
|
||||
check_video_irq();
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x63: // Video IRQ Acknowledge
|
||||
{
|
||||
LOGMASKED(LOG_IRQS, "video_w: Video IRQ Acknowledge = %04x\n", data);
|
||||
const uint16_t old = VIDEO_IRQ_ENABLE & VIDEO_IRQ_STATUS;
|
||||
VIDEO_IRQ_STATUS &= ~data;
|
||||
const uint16_t changed = old ^ (VIDEO_IRQ_ENABLE & VIDEO_IRQ_STATUS);
|
||||
if (changed)
|
||||
check_video_irq();
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x70: // Sprite DMA Source
|
||||
LOGMASKED(LOG_DMA, "video_w: Sprite DMA Source = %04x\n", data & 0x3fff);
|
||||
m_video_regs[offset] = data & 0x3fff;
|
||||
break;
|
||||
|
||||
case 0x71: // Sprite DMA Dest
|
||||
LOGMASKED(LOG_DMA, "video_w: Sprite DMA Dest = %04x\n", data & 0x03ff);
|
||||
m_video_regs[offset] = data & 0x03ff;
|
||||
break;
|
||||
|
||||
case 0x72: // Sprite DMA Length
|
||||
{
|
||||
LOGMASKED(LOG_DMA, "video_w: Sprite DMA Length = %04x\n", data & 0x03ff);
|
||||
uint16_t length = data & 0x3ff;
|
||||
do_sprite_dma(length ? length : 0x400);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
LOGMASKED(LOG_UNKNOWN_PPU, "video_w: Unknown register %04x = %04x\n", 0x2800 + offset, data);
|
||||
m_video_regs[offset] = data;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
WRITE_LINE_MEMBER(spg2xx_device::vblank)
|
||||
{
|
||||
if (!state)
|
||||
{
|
||||
VIDEO_IRQ_STATUS &= ~1;
|
||||
LOGMASKED(LOG_IRQS, "Setting video IRQ status to %04x\n", VIDEO_IRQ_STATUS);
|
||||
check_video_irq();
|
||||
return;
|
||||
}
|
||||
|
||||
#if SPG_DEBUG_VIDEO
|
||||
if (machine().input().code_pressed_once(KEYCODE_5))
|
||||
m_hide_page0 = !m_hide_page0;
|
||||
if (machine().input().code_pressed_once(KEYCODE_6))
|
||||
m_hide_page1 = !m_hide_page1;
|
||||
if (machine().input().code_pressed_once(KEYCODE_7))
|
||||
m_hide_sprites = !m_hide_sprites;
|
||||
if (machine().input().code_pressed_once(KEYCODE_8))
|
||||
m_debug_sprites = !m_debug_sprites;
|
||||
if (machine().input().code_pressed_once(KEYCODE_9))
|
||||
m_sprite_index_to_debug--;
|
||||
if (machine().input().code_pressed_once(KEYCODE_0))
|
||||
m_sprite_index_to_debug++;
|
||||
if (machine().input().code_pressed_once(KEYCODE_L))
|
||||
m_debug_palette = !m_debug_palette;
|
||||
#endif
|
||||
|
||||
if (VIDEO_IRQ_ENABLE & 1)
|
||||
{
|
||||
VIDEO_IRQ_STATUS |= 1;
|
||||
LOGMASKED(LOG_IRQS, "Setting video IRQ status to %04x\n", VIDEO_IRQ_STATUS);
|
||||
check_video_irq();
|
||||
}
|
||||
}
|
||||
|
||||
void spg2xx_device::check_video_irq()
|
||||
{
|
||||
LOGMASKED(LOG_IRQS, "%ssserting IRQ0 (%04x, %04x)\n", (VIDEO_IRQ_STATUS & VIDEO_IRQ_ENABLE) ? "A" : "Dea", VIDEO_IRQ_STATUS, VIDEO_IRQ_ENABLE);
|
||||
m_cpu->set_state_unsynced(UNSP_IRQ0_LINE, (VIDEO_IRQ_STATUS & VIDEO_IRQ_ENABLE) ? ASSERT_LINE : CLEAR_LINE);
|
||||
}
|
||||
|
||||
|
||||
/*************************
|
||||
* Machine Hardware *
|
||||
*************************/
|
||||
|
||||
READ16_MEMBER(spg2xx_device::dma_r)
|
||||
{
|
||||
uint16_t val = m_dma_regs[offset];
|
||||
switch (offset)
|
||||
{
|
||||
|
||||
case 0x000: // DMA Source (L)
|
||||
LOGMASKED(LOG_DMA, "dma_r: DMA Source (lo) = %04x\n", val);
|
||||
break;
|
||||
|
||||
case 0x001: // DMA Source (H)
|
||||
LOGMASKED(LOG_DMA, "dma_r: DMA Source (hi) = %04x\n", val);
|
||||
break;
|
||||
|
||||
case 0x002: // DMA Length
|
||||
LOGMASKED(LOG_DMA, "dma_r: DMA Length = %04x\n", 0);
|
||||
val = 0;
|
||||
break;
|
||||
|
||||
case 0x003: // DMA Destination
|
||||
LOGMASKED(LOG_DMA, "dma_r: DMA Dest = %04x\n", val);
|
||||
break;
|
||||
|
||||
default:
|
||||
LOGMASKED(LOG_UNKNOWN_IO, "dma_r: Unknown register %04x\n", 0x3d00 + offset);
|
||||
break;
|
||||
}
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
|
||||
WRITE16_MEMBER(spg2xx_device::dma_w)
|
||||
{
|
||||
switch (offset)
|
||||
{
|
||||
case 0x000: // DMA Source (lo)
|
||||
LOGMASKED(LOG_DMA, "dma_w: DMA Source (lo) = %04x\n", data);
|
||||
m_dma_regs[offset] = data;
|
||||
break;
|
||||
|
||||
case 0x001: // DMA Source (hi)
|
||||
LOGMASKED(LOG_DMA, "dma_w: DMA Source (hi) = %04x\n", data);
|
||||
m_dma_regs[offset] = data;
|
||||
break;
|
||||
|
||||
case 0x002: // DMA Length
|
||||
LOGMASKED(LOG_DMA, "dma_w: DMA Length = %04x\n", data);
|
||||
if (!(data & 0xc000)) // jak_dora writes 0xffff here which ends up trashing registers etc. why? such writes can't be valid
|
||||
do_cpu_dma(data);
|
||||
break;
|
||||
|
||||
case 0x003: // DMA Destination
|
||||
LOGMASKED(LOG_DMA, "dma_w: DMA Dest = %04x\n", data);
|
||||
m_dma_regs[offset] = data;
|
||||
break;
|
||||
|
||||
default:
|
||||
LOGMASKED(LOG_UNKNOWN_IO, "dma_w: Unknown register %04x = %04x\n", 0x3d00 + offset, data);
|
||||
m_dma_regs[offset] = data;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void spg2xx_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
|
||||
{
|
||||
switch (id)
|
||||
{
|
||||
case TIMER_SCREENPOS:
|
||||
{
|
||||
if (VIDEO_IRQ_ENABLE & 2)
|
||||
{
|
||||
VIDEO_IRQ_STATUS |= 2;
|
||||
check_video_irq();
|
||||
}
|
||||
m_screen->update_partial(m_screen->vpos());
|
||||
|
||||
// fire again, jak_dbz pinball needs this
|
||||
m_screenpos_timer->adjust(m_screen->time_until_pos(m_video_regs[0x36], m_video_regs[0x37] << 1));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void spg2xx_device::do_cpu_dma(uint32_t len)
|
||||
{
|
||||
address_space &mem = m_cpu->space(AS_PROGRAM);
|
||||
|
||||
uint32_t src = ((m_dma_regs[0x001] & 0x3f) << 16) | m_dma_regs[0x000];
|
||||
uint32_t dst = m_dma_regs[0x003] & 0x3fff;
|
||||
|
||||
for (uint32_t j = 0; j < len; j++)
|
||||
{
|
||||
mem.write_word((dst + j) & 0x3fff, mem.read_word(src + j));
|
||||
}
|
||||
|
||||
src += len;
|
||||
m_dma_regs[0x000] = (uint16_t)src;
|
||||
m_dma_regs[0x001] = (src >> 16) & 0x3f;
|
||||
m_dma_regs[0x002] = 0;
|
||||
m_dma_regs[0x003] = (dst + len) & 0x3fff;
|
||||
}
|
||||
|
||||
void spg2xx_device::configure_spg_io(spg2xx_io_device* io)
|
||||
{
|
||||
io->porta_in().set(FUNC(spg2xx_device::porta_r));
|
||||
@ -1019,7 +147,7 @@ void spg2xx_device::configure_spg_io(spg2xx_io_device* io)
|
||||
io->eeprom_r().set(FUNC(spg2xx_device::eepromx_r));
|
||||
io->uart_tx().set(FUNC(spg2xx_device::tx_w));
|
||||
io->chip_select().set(FUNC(spg2xx_device::cs_w));
|
||||
io->pal_read_callback().set(FUNC(spg2xx_device::get_pal_r));
|
||||
io->pal_read_callback().set(FUNC(spg2xx_device::get_pal_ntsc));
|
||||
io->write_timer_irq_callback().set(FUNC(spg2xx_device::timerirq_w));
|
||||
io->write_uart_adc_irq_callback().set(FUNC(spg2xx_device::uartirq_w));
|
||||
io->write_external_irq_callback().set(FUNC(spg2xx_device::extirq_w));
|
||||
@ -1038,6 +166,13 @@ void spg24x_device::device_add_mconfig(machine_config &config)
|
||||
|
||||
SPG24X_IO(config, m_spg_io, DERIVED_CLOCK(1, 1), m_cpu, m_screen);
|
||||
configure_spg_io(m_spg_io);
|
||||
|
||||
SPG2XX_SYSDMA(config, m_spg_sysdma, DERIVED_CLOCK(1, 1), m_cpu);
|
||||
|
||||
SPG24X_VIDEO(config, m_spg_video, DERIVED_CLOCK(1, 1), m_cpu, m_screen);
|
||||
m_spg_video->sprlimit_read_callback().set(FUNC(spg24x_device::get_sprlimit));
|
||||
m_spg_video->rowscrolloffset_read_callback().set(FUNC(spg24x_device::get_rowscrolloffset));
|
||||
m_spg_video->write_video_irq_callback().set(FUNC(spg24x_device::videoirq_w));
|
||||
}
|
||||
|
||||
void spg28x_device::device_add_mconfig(machine_config &config)
|
||||
@ -1051,4 +186,11 @@ void spg28x_device::device_add_mconfig(machine_config &config)
|
||||
|
||||
SPG28X_IO(config, m_spg_io, DERIVED_CLOCK(1, 1), m_cpu, m_screen);
|
||||
configure_spg_io(m_spg_io);
|
||||
|
||||
SPG2XX_SYSDMA(config, m_spg_sysdma, DERIVED_CLOCK(1, 1), m_cpu);
|
||||
|
||||
SPG24X_VIDEO(config, m_spg_video, DERIVED_CLOCK(1, 1), m_cpu, m_screen);
|
||||
m_spg_video->sprlimit_read_callback().set(FUNC(spg28x_device::get_sprlimit));
|
||||
m_spg_video->rowscrolloffset_read_callback().set(FUNC(spg28x_device::get_rowscrolloffset));
|
||||
m_spg_video->write_video_irq_callback().set(FUNC(spg28x_device::videoirq_w));
|
||||
}
|
||||
|
@ -37,6 +37,8 @@
|
||||
#include "cpu/unsp/unsp.h"
|
||||
#include "spg2xx_audio.h"
|
||||
#include "spg2xx_io.h"
|
||||
#include "spg2xx_sysdma.h"
|
||||
#include "spg2xx_video.h"
|
||||
#include "screen.h"
|
||||
|
||||
class spg2xx_device : public device_t, public device_mixer_interface
|
||||
@ -65,14 +67,16 @@ public:
|
||||
|
||||
auto chip_select() { return m_chip_sel.bind(); }
|
||||
|
||||
uint32_t screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect);
|
||||
DECLARE_WRITE_LINE_MEMBER(vblank);
|
||||
|
||||
required_device<spg2xx_audio_device> m_spg_audio;
|
||||
required_device<spg2xx_io_device> m_spg_io;
|
||||
required_device<spg2xx_sysdma_device> m_spg_sysdma;
|
||||
required_device<spg2xx_video_device> m_spg_video;
|
||||
|
||||
void extint_w(int channel, bool state) { m_spg_io->extint_w(channel, state); };
|
||||
void uart_rx(uint8_t data) { m_spg_io->uart_rx(data); };
|
||||
void extint_w(int channel, bool state) { m_spg_io->extint_w(channel, state); }
|
||||
void uart_rx(uint8_t data) { m_spg_io->uart_rx(data); }
|
||||
|
||||
DECLARE_WRITE_LINE_MEMBER(vblank) { m_spg_video->vblank(state); }
|
||||
uint32_t screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect) { return m_spg_video->screen_update(screen, bitmap, cliprect); }
|
||||
|
||||
protected:
|
||||
spg2xx_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock, const uint32_t sprite_limit)
|
||||
@ -81,30 +85,7 @@ protected:
|
||||
m_sprite_limit = sprite_limit;
|
||||
}
|
||||
|
||||
enum
|
||||
{
|
||||
PAGE_ENABLE_MASK = 0x0008,
|
||||
PAGE_WALLPAPER_MASK = 0x0004,
|
||||
|
||||
SPRITE_ENABLE_MASK = 0x0001,
|
||||
SPRITE_COORD_TL_MASK = 0x0002,
|
||||
|
||||
PAGE_DEPTH_FLAG_MASK = 0x3000,
|
||||
PAGE_DEPTH_FLAG_SHIFT = 12,
|
||||
PAGE_TILE_HEIGHT_MASK = 0x00c0,
|
||||
PAGE_TILE_HEIGHT_SHIFT = 6,
|
||||
PAGE_TILE_WIDTH_MASK = 0x0030,
|
||||
PAGE_TILE_WIDTH_SHIFT = 4,
|
||||
TILE_X_FLIP = 0x0004,
|
||||
TILE_Y_FLIP = 0x0008
|
||||
};
|
||||
|
||||
DECLARE_READ16_MEMBER(video_r);
|
||||
DECLARE_WRITE16_MEMBER(video_w);
|
||||
|
||||
DECLARE_READ16_MEMBER(dma_r);
|
||||
DECLARE_WRITE16_MEMBER(dma_w);
|
||||
|
||||
DECLARE_WRITE_LINE_MEMBER(videoirq_w);
|
||||
DECLARE_WRITE_LINE_MEMBER(audioirq_w);
|
||||
DECLARE_WRITE_LINE_MEMBER(timerirq_w);
|
||||
DECLARE_WRITE_LINE_MEMBER(uartirq_w);
|
||||
@ -114,68 +95,18 @@ protected:
|
||||
|
||||
DECLARE_READ16_MEMBER(space_r);
|
||||
|
||||
inline void check_video_irq();
|
||||
|
||||
void spg2xx_map(address_map &map);
|
||||
|
||||
static const device_timer_id TIMER_SCREENPOS = 2;
|
||||
|
||||
|
||||
virtual void device_start() override;
|
||||
virtual void device_reset() override;
|
||||
virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
|
||||
|
||||
void do_cpu_dma(uint32_t len);
|
||||
|
||||
void do_sprite_dma(uint32_t len);
|
||||
|
||||
enum blend_enable_t : bool
|
||||
{
|
||||
BlendOff = false,
|
||||
BlendOn = true
|
||||
};
|
||||
|
||||
enum rowscroll_enable_t : bool
|
||||
{
|
||||
RowScrollOff = false,
|
||||
RowScrollOn = true
|
||||
};
|
||||
|
||||
enum flipx_t : bool
|
||||
{
|
||||
FlipXOff = false,
|
||||
FlipXOn = true
|
||||
};
|
||||
|
||||
void apply_saturation(const rectangle &cliprect);
|
||||
void apply_fade(const rectangle &cliprect);
|
||||
|
||||
template<blend_enable_t Blend, rowscroll_enable_t RowScroll, flipx_t FlipX>
|
||||
void 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);
|
||||
void blit_page(const rectangle &cliprect, uint32_t scanline, int depth, uint32_t bitmap_addr, uint16_t *regs);
|
||||
void blit_sprite(const rectangle &cliprect, uint32_t scanline, int depth, uint32_t base_addr);
|
||||
void blit_sprites(const rectangle &cliprect, uint32_t scanline, int depth);
|
||||
|
||||
uint8_t mix_channel(uint8_t a, uint8_t b);
|
||||
|
||||
uint32_t m_screenbuf[320 * 240];
|
||||
uint8_t m_rgb5_to_rgb8[32];
|
||||
uint32_t m_rgb555_to_rgb888[0x8000];
|
||||
|
||||
bool m_hide_page0;
|
||||
bool m_hide_page1;
|
||||
bool m_hide_sprites;
|
||||
bool m_debug_sprites;
|
||||
bool m_debug_blit;
|
||||
bool m_debug_palette;
|
||||
uint8_t m_sprite_index_to_debug;
|
||||
|
||||
uint16_t m_dma_regs[0x4];
|
||||
|
||||
uint16_t m_video_regs[0x100];
|
||||
uint32_t m_sprite_limit;
|
||||
int m_rowscrolloffset; // auto racing in 'zone60' minigames needs this to be 15, the JAKKS games (Star Wars Revenge of the sith - Gunship Battle, Wheel of Fortune, Namco Ms. Pac-Man 5-in-1 Pole Position) need it to be 0, where does it come from?
|
||||
// TODO: these are fixed values, put them in relevant devices?
|
||||
uint16_t m_sprite_limit;
|
||||
uint16_t m_rowscrolloffset; // auto racing in 'zone60' minigames needs this to be 15, the JAKKS games (Star Wars Revenge of the sith - Gunship Battle, Wheel of Fortune, Namco Ms. Pac-Man 5-in-1 Pole Position) need it to be 0, where does it come from?
|
||||
uint16_t m_pal_flag;
|
||||
DECLARE_READ16_MEMBER(get_sprlimit) { return m_sprite_limit; }
|
||||
DECLARE_READ16_MEMBER(get_rowscrolloffset) { return m_rowscrolloffset; }
|
||||
DECLARE_READ16_MEMBER(get_pal_ntsc) { return m_pal_flag; }
|
||||
|
||||
devcb_write16 m_porta_out;
|
||||
devcb_write16 m_portb_out;
|
||||
@ -197,27 +128,22 @@ protected:
|
||||
|
||||
required_device<unsp_device> m_cpu;
|
||||
required_device<screen_device> m_screen;
|
||||
required_shared_ptr<uint16_t> m_scrollram;
|
||||
required_shared_ptr<uint16_t> m_paletteram;
|
||||
required_shared_ptr<uint16_t> m_spriteram;
|
||||
|
||||
void configure_spg_io(spg2xx_io_device* io);
|
||||
|
||||
DECLARE_READ16_MEMBER(porta_r) { return m_porta_in(); };
|
||||
DECLARE_READ16_MEMBER(portb_r) { return m_portb_in(); };
|
||||
DECLARE_READ16_MEMBER(portc_r) { return m_portc_in(); };
|
||||
DECLARE_WRITE16_MEMBER(porta_w) { m_porta_out(offset, data, mem_mask); };
|
||||
DECLARE_WRITE16_MEMBER(portb_w) { m_portb_out(offset, data, mem_mask); };
|
||||
DECLARE_WRITE16_MEMBER(portc_w) { m_portc_out(offset, data, mem_mask); };
|
||||
template <size_t Line> DECLARE_READ16_MEMBER(adc_r) { return m_adc_in[Line](); };
|
||||
DECLARE_READ16_MEMBER(porta_r) { return m_porta_in(); }
|
||||
DECLARE_READ16_MEMBER(portb_r) { return m_portb_in(); }
|
||||
DECLARE_READ16_MEMBER(portc_r) { return m_portc_in(); }
|
||||
DECLARE_WRITE16_MEMBER(porta_w) { m_porta_out(offset, data, mem_mask); }
|
||||
DECLARE_WRITE16_MEMBER(portb_w) { m_portb_out(offset, data, mem_mask); }
|
||||
DECLARE_WRITE16_MEMBER(portc_w) { m_portc_out(offset, data, mem_mask); }
|
||||
template <size_t Line> DECLARE_READ16_MEMBER(adc_r) { return m_adc_in[Line](); }
|
||||
|
||||
DECLARE_WRITE8_MEMBER(eepromx_w) { m_eeprom_w(offset, data, mem_mask); };
|
||||
DECLARE_WRITE8_MEMBER(eepromx_w) { m_eeprom_w(offset, data, mem_mask); }
|
||||
DECLARE_READ8_MEMBER(eepromx_r) { return m_eeprom_r(); };
|
||||
|
||||
DECLARE_WRITE8_MEMBER(tx_w) { m_uart_tx(offset, data, mem_mask); };
|
||||
DECLARE_WRITE8_MEMBER(cs_w) { m_chip_sel(offset, data, mem_mask); };
|
||||
DECLARE_READ16_MEMBER(get_pal_r) { return m_pal_flag; };
|
||||
|
||||
DECLARE_WRITE8_MEMBER(tx_w) { m_uart_tx(offset, data, mem_mask); }
|
||||
DECLARE_WRITE8_MEMBER(cs_w) { m_chip_sel(offset, data, mem_mask); }
|
||||
};
|
||||
|
||||
class spg24x_device : public spg2xx_device
|
||||
|
@ -27,7 +27,7 @@ DEFINE_DEVICE_TYPE(SPG28X_IO, spg28x_io_device, "spg28x_io", "SPG280-series Syst
|
||||
#define LOG_EXT_MEM (1U << 27)
|
||||
#define LOG_EXTINT (1U << 28)
|
||||
#define LOG_IO (LOG_IO_READS | LOG_IO_WRITES | LOG_IRQS | LOG_GPIO | LOG_UART | LOG_I2C | LOG_TIMERS | LOG_EXTINT | LOG_UNKNOWN_IO)
|
||||
#define LOG_ALL (LOG_IO | LOG_VLINES | LOG_SEGMENT | LOG_FIQ)
|
||||
#define LOG_ALL (LOG_IO | LOG_VLINES | LOG_SEGMENT | LOG_WATCHDOG | LOG_FIQ | LOG_SIO | LOG_EXT_MEM)
|
||||
|
||||
#define VERBOSE (0)
|
||||
#include "logmacro.h"
|
||||
|
117
src/devices/machine/spg2xx_sysdma.cpp
Normal file
117
src/devices/machine/spg2xx_sysdma.cpp
Normal file
@ -0,0 +1,117 @@
|
||||
// license:BSD-3-Clause
|
||||
// copyright-holders:Ryan Holtz
|
||||
/*****************************************************************************
|
||||
|
||||
SunPlus SPG2xx-series SoC peripheral emulation (System DMA)
|
||||
|
||||
**********************************************************************/
|
||||
|
||||
#include "emu.h"
|
||||
#include "spg2xx_sysdma.h"
|
||||
|
||||
DEFINE_DEVICE_TYPE(SPG2XX_SYSDMA, spg2xx_sysdma_device, "spg2xx_sysdma", "SPG240-series System-on-a-Chip System DMA")
|
||||
|
||||
#define LOG_DMA (1U << 9)
|
||||
#define LOG_ALL (LOG_DMA)
|
||||
|
||||
#define VERBOSE (0)
|
||||
#include "logmacro.h"
|
||||
|
||||
|
||||
|
||||
spg2xx_sysdma_device::spg2xx_sysdma_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
|
||||
: device_t(mconfig, SPG2XX_SYSDMA, tag, owner, clock)
|
||||
, m_cpu(*this, finder_base::DUMMY_TAG)
|
||||
{
|
||||
}
|
||||
|
||||
void spg2xx_sysdma_device::device_start()
|
||||
{
|
||||
save_item(NAME(m_dma_regs));
|
||||
}
|
||||
|
||||
void spg2xx_sysdma_device::device_reset()
|
||||
{
|
||||
memset(m_dma_regs, 0, 0x4 * sizeof(uint16_t));
|
||||
}
|
||||
|
||||
/*************************
|
||||
* Machine Hardware *
|
||||
*************************/
|
||||
|
||||
READ16_MEMBER(spg2xx_sysdma_device::dma_r)
|
||||
{
|
||||
offset &= 0x3;
|
||||
|
||||
uint16_t val = m_dma_regs[offset];
|
||||
switch (offset)
|
||||
{
|
||||
|
||||
case 0x000: // DMA Source (L)
|
||||
LOGMASKED(LOG_DMA, "dma_r: DMA Source (lo) = %04x\n", val);
|
||||
break;
|
||||
|
||||
case 0x001: // DMA Source (H)
|
||||
LOGMASKED(LOG_DMA, "dma_r: DMA Source (hi) = %04x\n", val);
|
||||
break;
|
||||
|
||||
case 0x002: // DMA Length
|
||||
LOGMASKED(LOG_DMA, "dma_r: DMA Length = %04x\n", 0);
|
||||
val = 0;
|
||||
break;
|
||||
|
||||
case 0x003: // DMA Destination
|
||||
LOGMASKED(LOG_DMA, "dma_r: DMA Dest = %04x\n", val);
|
||||
break;
|
||||
}
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
WRITE16_MEMBER(spg2xx_sysdma_device::dma_w)
|
||||
{
|
||||
offset &= 0x3;
|
||||
|
||||
switch (offset)
|
||||
{
|
||||
case 0x000: // DMA Source (lo)
|
||||
LOGMASKED(LOG_DMA, "dma_w: DMA Source (lo) = %04x\n", data);
|
||||
m_dma_regs[offset] = data;
|
||||
break;
|
||||
|
||||
case 0x001: // DMA Source (hi)
|
||||
LOGMASKED(LOG_DMA, "dma_w: DMA Source (hi) = %04x\n", data);
|
||||
m_dma_regs[offset] = data;
|
||||
break;
|
||||
|
||||
case 0x002: // DMA Length
|
||||
LOGMASKED(LOG_DMA, "dma_w: DMA Length = %04x\n", data);
|
||||
if (!(data & 0xc000)) // jak_dora writes 0xffff here which ends up trashing registers etc. why? such writes can't be valid
|
||||
do_cpu_dma(data);
|
||||
break;
|
||||
|
||||
case 0x003: // DMA Destination
|
||||
LOGMASKED(LOG_DMA, "dma_w: DMA Dest = %04x\n", data);
|
||||
m_dma_regs[offset] = data;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void spg2xx_sysdma_device::do_cpu_dma(uint32_t len)
|
||||
{
|
||||
address_space &mem = m_cpu->space(AS_PROGRAM);
|
||||
|
||||
uint32_t src = ((m_dma_regs[0x001] & 0x3f) << 16) | m_dma_regs[0x000];
|
||||
uint32_t dst = m_dma_regs[0x003] & 0x3fff;
|
||||
|
||||
for (uint32_t j = 0; j < len; j++)
|
||||
{
|
||||
mem.write_word((dst + j) & 0x3fff, mem.read_word(src + j));
|
||||
}
|
||||
|
||||
src += len;
|
||||
m_dma_regs[0x000] = (uint16_t)src;
|
||||
m_dma_regs[0x001] = (src >> 16) & 0x3f;
|
||||
m_dma_regs[0x002] = 0;
|
||||
m_dma_regs[0x003] = (dst + len) & 0x3fff;
|
||||
}
|
46
src/devices/machine/spg2xx_sysdma.h
Normal file
46
src/devices/machine/spg2xx_sysdma.h
Normal file
@ -0,0 +1,46 @@
|
||||
// license:BSD-3-Clause
|
||||
// copyright-holders:Ryan Holtz
|
||||
/*****************************************************************************
|
||||
|
||||
SunPlus SPG2xx-series SoC peripheral emulation (System DMA)
|
||||
|
||||
**********************************************************************/
|
||||
|
||||
#ifndef MAME_MACHINE_SPG2XX_SYSDMA_H
|
||||
#define MAME_MACHINE_SPG2XX_SYSDMA_H
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "cpu/unsp/unsp.h"
|
||||
|
||||
DECLARE_DEVICE_TYPE(SPG2XX_SYSDMA, spg2xx_sysdma_device)
|
||||
|
||||
|
||||
class spg2xx_sysdma_device : public device_t
|
||||
{
|
||||
public:
|
||||
template <typename T>
|
||||
spg2xx_sysdma_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock, T &&cpu_tag)
|
||||
: spg2xx_sysdma_device(mconfig, tag, owner, clock)
|
||||
{
|
||||
m_cpu.set_tag(std::forward<T>(cpu_tag));
|
||||
}
|
||||
|
||||
spg2xx_sysdma_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
|
||||
DECLARE_READ16_MEMBER(dma_r);
|
||||
DECLARE_WRITE16_MEMBER(dma_w);
|
||||
|
||||
protected:
|
||||
virtual void device_start() override;
|
||||
virtual void device_reset() override;
|
||||
|
||||
private:
|
||||
void do_cpu_dma(uint32_t len);
|
||||
|
||||
uint16_t m_dma_regs[0x4];
|
||||
|
||||
required_device<unsp_device> m_cpu;
|
||||
};
|
||||
|
||||
|
||||
#endif // MAME_MACHINE_SPG2XX_SYSDMA_H
|
828
src/devices/machine/spg2xx_video.cpp
Normal file
828
src/devices/machine/spg2xx_video.cpp
Normal file
@ -0,0 +1,828 @@
|
||||
// license:BSD-3-Clause
|
||||
// copyright-holders:Ryan Holtz
|
||||
/*****************************************************************************
|
||||
|
||||
SunPlus SPG2xx-series SoC peripheral emulation (Video)
|
||||
|
||||
**********************************************************************/
|
||||
|
||||
#include "emu.h"
|
||||
#include "spg2xx_video.h"
|
||||
|
||||
DEFINE_DEVICE_TYPE(SPG24X_VIDEO, spg24x_video_device, "spg24x_video", "SPG240-series System-on-a-Chip (Video)")
|
||||
|
||||
#define LOG_IRQS (1U << 4)
|
||||
#define LOG_VLINES (1U << 5)
|
||||
#define LOG_DMA (1U << 9)
|
||||
#define LOG_PPU_READS (1U << 22)
|
||||
#define LOG_PPU_WRITES (1U << 23)
|
||||
#define LOG_UNKNOWN_PPU (1U << 24)
|
||||
#define LOG_PPU (LOG_PPU_READS | LOG_PPU_WRITES | LOG_UNKNOWN_PPU)
|
||||
#define LOG_ALL (LOG_IRQS | LOG_PPU | LOG_VLINES | LOG_DMA )
|
||||
|
||||
#define VERBOSE (0)
|
||||
#include "logmacro.h"
|
||||
|
||||
#define SPG_DEBUG_VIDEO (0)
|
||||
|
||||
#define VIDEO_IRQ_ENABLE m_video_regs[0x62]
|
||||
#define VIDEO_IRQ_STATUS m_video_regs[0x63]
|
||||
|
||||
spg2xx_video_device::spg2xx_video_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock)
|
||||
: device_t(mconfig, type, tag, owner, clock)
|
||||
, m_sprlimit_read_cb(*this)
|
||||
, m_rowscrolloffset_read_cb(*this)
|
||||
, m_cpu(*this, finder_base::DUMMY_TAG)
|
||||
, m_screen(*this, finder_base::DUMMY_TAG)
|
||||
, m_scrollram(*this, "scrollram")
|
||||
, m_paletteram(*this, "paletteram")
|
||||
, m_spriteram(*this, "spriteram")
|
||||
, m_video_irq_cb(*this)
|
||||
{
|
||||
}
|
||||
|
||||
spg24x_video_device::spg24x_video_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
|
||||
: spg2xx_video_device(mconfig, SPG24X_VIDEO, tag, owner, clock)
|
||||
{
|
||||
}
|
||||
|
||||
void spg2xx_video_device::device_start()
|
||||
{
|
||||
for (uint8_t i = 0; i < 32; i++)
|
||||
{
|
||||
m_rgb5_to_rgb8[i] = (i << 3) | (i >> 2);
|
||||
}
|
||||
for (uint16_t i = 0; i < 0x8000; i++)
|
||||
{
|
||||
m_rgb555_to_rgb888[i] = (m_rgb5_to_rgb8[(i >> 10) & 0x1f] << 16) |
|
||||
(m_rgb5_to_rgb8[(i >> 5) & 0x1f] << 8) |
|
||||
(m_rgb5_to_rgb8[(i >> 0) & 0x1f] << 0);
|
||||
}
|
||||
|
||||
m_screenpos_timer = timer_alloc(TIMER_SCREENPOS);
|
||||
m_screenpos_timer->adjust(attotime::never);
|
||||
|
||||
save_item(NAME(m_hide_page0));
|
||||
save_item(NAME(m_hide_page1));
|
||||
save_item(NAME(m_hide_sprites));
|
||||
save_item(NAME(m_debug_sprites));
|
||||
save_item(NAME(m_debug_blit));
|
||||
save_item(NAME(m_debug_palette));
|
||||
save_item(NAME(m_sprite_index_to_debug));
|
||||
|
||||
save_item(NAME(m_video_regs));
|
||||
|
||||
m_sprlimit_read_cb.resolve_safe(0);
|
||||
m_rowscrolloffset_read_cb.resolve_safe(0);
|
||||
|
||||
m_video_irq_cb.resolve();
|
||||
|
||||
}
|
||||
|
||||
void spg2xx_video_device::device_reset()
|
||||
{
|
||||
memset(m_video_regs, 0, 0x100 * sizeof(uint16_t));
|
||||
|
||||
m_video_regs[0x36] = 0xffff;
|
||||
m_video_regs[0x37] = 0xffff;
|
||||
m_video_regs[0x3c] = 0x0020;
|
||||
m_video_regs[0x42] = 0x0001;
|
||||
|
||||
m_hide_page0 = false;
|
||||
m_hide_page1 = false;
|
||||
m_hide_sprites = false;
|
||||
m_debug_sprites = false;
|
||||
m_debug_blit = false;
|
||||
m_debug_palette = false;
|
||||
m_sprite_index_to_debug = 0;
|
||||
}
|
||||
|
||||
/*************************
|
||||
* Video Hardware *
|
||||
*************************/
|
||||
|
||||
// Perform a lerp between a and b
|
||||
inline uint8_t spg2xx_video_device::mix_channel(uint8_t bottom, uint8_t top)
|
||||
{
|
||||
uint8_t alpha = (m_video_regs[0x2a] & 3) << 6;
|
||||
return ((256 - alpha) * bottom + alpha * top) >> 8;
|
||||
}
|
||||
|
||||
template<spg2xx_video_device::blend_enable_t Blend, spg2xx_video_device::rowscroll_enable_t RowScroll, spg2xx_video_device::flipx_t FlipX>
|
||||
void spg2xx_video_device::draw(const rectangle &cliprect, uint32_t line, uint32_t xoff, uint32_t yoff, uint32_t bitmap_addr, uint16_t tile, int32_t h, int32_t w, uint8_t bpp, uint32_t yflipmask, uint32_t palette_offset)
|
||||
{
|
||||
address_space &space = m_cpu->space(AS_PROGRAM);
|
||||
|
||||
uint32_t nc_bpp = ((bpp) + 1) << 1;
|
||||
|
||||
if (SPG_DEBUG_VIDEO && m_debug_blit)
|
||||
{
|
||||
printf("s:%d line:%d xy:%08x,%08x bitmap_addr:%08x tile:%04x\n", cliprect.min_x, line, xoff, yoff, bitmap_addr, tile);
|
||||
printf("hw:%d,%d yfm:%d nc_bppols:%d pobs:%02x ", w, h, yflipmask, nc_bpp, palette_offset);
|
||||
}
|
||||
palette_offset >>= nc_bpp;
|
||||
palette_offset <<= nc_bpp;
|
||||
if (SPG_DEBUG_VIDEO && m_debug_blit)
|
||||
{
|
||||
printf("poas:%02x\n", palette_offset);
|
||||
}
|
||||
|
||||
uint32_t bits_per_row = nc_bpp * 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;
|
||||
|
||||
if (SPG_DEBUG_VIDEO && m_debug_blit)
|
||||
printf("%3d:\n", yy);
|
||||
|
||||
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_bpp;
|
||||
if (SPG_DEBUG_VIDEO && m_debug_blit)
|
||||
printf(" %08x:%d ", bits, nbits);
|
||||
if (nbits < nc_bpp)
|
||||
{
|
||||
uint16_t b = space.read_word(m++ & 0x3fffff);
|
||||
b = (b << 8) | (b >> 8);
|
||||
bits |= b << (nc_bpp - nbits);
|
||||
nbits += 16;
|
||||
if (SPG_DEBUG_VIDEO && m_debug_blit)
|
||||
printf("(%04x:%08x:%d) ", b, bits, nbits);
|
||||
}
|
||||
nbits -= nc_bpp;
|
||||
|
||||
uint32_t pal = palette_offset + (bits >> 16);
|
||||
if (SPG_DEBUG_VIDEO && m_debug_blit)
|
||||
printf("%02x:%02x:%04x ", bits >> 16, pal, bits & 0xffff);
|
||||
bits &= 0xffff;
|
||||
|
||||
if (RowScroll)
|
||||
xx -= (int16_t)m_scrollram[(yy + m_rowscrolloffset_read_cb()) & 0x1ff];
|
||||
|
||||
xx &= 0x01ff;
|
||||
if (xx >= 0x01c0)
|
||||
xx -= 0x0200;
|
||||
|
||||
if (xx >= 0 && xx < 320)
|
||||
{
|
||||
int pix_index = xx + y_index;
|
||||
|
||||
uint16_t rgb = m_paletteram[pal];
|
||||
if (SPG_DEBUG_VIDEO && m_debug_blit)
|
||||
printf("rgb:%04x ", rgb);
|
||||
|
||||
if (!(rgb & 0x8000))
|
||||
{
|
||||
if (Blend)
|
||||
{
|
||||
if (SPG_DEBUG_VIDEO && m_debug_blit)
|
||||
printf("M\n");
|
||||
m_screenbuf[pix_index] = (mix_channel((uint8_t)(m_screenbuf[pix_index] >> 16), m_rgb5_to_rgb8[(rgb >> 10) & 0x1f]) << 16) |
|
||||
(mix_channel((uint8_t)(m_screenbuf[pix_index] >> 8), m_rgb5_to_rgb8[(rgb >> 5) & 0x1f]) << 8) |
|
||||
(mix_channel((uint8_t)(m_screenbuf[pix_index] >> 0), m_rgb5_to_rgb8[rgb & 0x1f]));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (SPG_DEBUG_VIDEO && m_debug_blit)
|
||||
printf("S\n");
|
||||
m_screenbuf[pix_index] = m_rgb555_to_rgb888[rgb];
|
||||
}
|
||||
}
|
||||
else if (SPG_DEBUG_VIDEO && m_debug_blit)
|
||||
{
|
||||
printf("X\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void spg2xx_video_device::draw_page(const rectangle &cliprect, uint32_t scanline, int priority, uint32_t bitmap_addr, uint16_t *regs)
|
||||
{
|
||||
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 &space = m_cpu->space(AS_PROGRAM);
|
||||
|
||||
if (!(ctrl & PAGE_ENABLE_MASK))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (((attr & PAGE_PRIORITY_FLAG_MASK) >> PAGE_PRIORITY_FLAG_SHIFT) != priority)
|
||||
{
|
||||
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;
|
||||
if (SPG_DEBUG_VIDEO && machine().input().code_pressed(KEYCODE_H))
|
||||
printf("s:%3d | baddr:%08x | yscr:%3d | bity:%3d | y0:%2d | ts:%2d\n", scanline, bitmap_addr, yscroll, bitmap_y, y0, tile_scanline);
|
||||
|
||||
if (SPG_DEBUG_VIDEO && machine().input().code_pressed(KEYCODE_EQUALS))
|
||||
m_debug_blit = true;
|
||||
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) ? space.read_word(tilemap) : space.read_word(tilemap + tile_address);
|
||||
uint16_t palette = 0;
|
||||
|
||||
if (!tile)
|
||||
continue;
|
||||
|
||||
palette = (ctrl & PAGE_WALLPAPER_MASK) ? space.read_word(palette_map) : space.read_word(palette_map + tile_address / 2);
|
||||
if (x0 & 1)
|
||||
palette >>= 8;
|
||||
|
||||
uint32_t tileattr = attr;
|
||||
uint32_t tilectrl = ctrl;
|
||||
if ((ctrl & 2) == 0)
|
||||
{ // -(1) bld(1) flip(2) pal(4)
|
||||
tileattr &= ~0x000c;
|
||||
tileattr |= (palette >> 2) & 0x000c; // flip
|
||||
|
||||
tileattr &= ~0x0f00;
|
||||
tileattr |= (palette << 8) & 0x0f00; // palette
|
||||
|
||||
tilectrl &= ~0x0100;
|
||||
tilectrl |= (palette << 2) & 0x0100; // blend
|
||||
}
|
||||
|
||||
const bool blend = (tileattr & 0x4000 || tilectrl & 0x0100);
|
||||
const bool row_scroll = (tilectrl & 0x0010);
|
||||
const bool flip_x = (tileattr & TILE_X_FLIP);
|
||||
const uint32_t yflipmask = tileattr & TILE_Y_FLIP ? tile_h - 1 : 0;
|
||||
const uint32_t palette_offset = (tileattr & 0x0f00) >> 4;
|
||||
|
||||
const uint8_t bpp = tileattr & 0x0003;
|
||||
|
||||
if (blend)
|
||||
{
|
||||
if (row_scroll)
|
||||
{
|
||||
if (flip_x)
|
||||
draw<BlendOn, RowScrollOn, FlipXOn>(cliprect, tile_scanline, xx, yy, bitmap_addr, tile, tile_h, tile_w, bpp, yflipmask, palette_offset);
|
||||
else
|
||||
draw<BlendOn, RowScrollOn, FlipXOff>(cliprect, tile_scanline, xx, yy, bitmap_addr, tile, tile_h, tile_w, bpp, yflipmask, palette_offset);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (flip_x)
|
||||
draw<BlendOn, RowScrollOff, FlipXOn>(cliprect, tile_scanline, xx, yy, bitmap_addr, tile, tile_h, tile_w, bpp, yflipmask, palette_offset);
|
||||
else
|
||||
draw<BlendOn, RowScrollOff, FlipXOff>(cliprect, tile_scanline, xx, yy, bitmap_addr, tile, tile_h, tile_w, bpp, yflipmask, palette_offset);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (row_scroll)
|
||||
{
|
||||
if (flip_x)
|
||||
draw<BlendOff, RowScrollOn, FlipXOn>(cliprect, tile_scanline, xx, yy, bitmap_addr, tile, tile_h, tile_w, bpp, yflipmask, palette_offset);
|
||||
else
|
||||
draw<BlendOff, RowScrollOn, FlipXOff>(cliprect, tile_scanline, xx, yy, bitmap_addr, tile, tile_h, tile_w, bpp, yflipmask, palette_offset);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (flip_x)
|
||||
draw<BlendOff, RowScrollOff, FlipXOn>(cliprect, tile_scanline, xx, yy, bitmap_addr, tile, tile_h, tile_w, bpp, yflipmask, palette_offset);
|
||||
else
|
||||
draw<BlendOff, RowScrollOff, FlipXOff>(cliprect, tile_scanline, xx, yy, bitmap_addr, tile, tile_h, tile_w, bpp, yflipmask, palette_offset);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (SPG_DEBUG_VIDEO && machine().input().code_pressed(KEYCODE_EQUALS))
|
||||
m_debug_blit = false;
|
||||
}
|
||||
|
||||
void spg2xx_video_device::draw_sprite(const rectangle &cliprect, uint32_t scanline, int priority, uint32_t base_addr)
|
||||
{
|
||||
uint32_t bitmap_addr = 0x40 * m_video_regs[0x22];
|
||||
uint16_t tile = m_spriteram[base_addr + 0];
|
||||
int16_t x = m_spriteram[base_addr + 1];
|
||||
int16_t y = m_spriteram[base_addr + 2];
|
||||
uint16_t attr = m_spriteram[base_addr + 3];
|
||||
|
||||
if (!tile)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (((attr & PAGE_PRIORITY_FLAG_MASK) >> PAGE_PRIORITY_FLAG_SHIFT) != priority)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
const uint32_t h = 8 << ((attr & PAGE_TILE_HEIGHT_MASK) >> PAGE_TILE_HEIGHT_SHIFT);
|
||||
const uint32_t w = 8 << ((attr & PAGE_TILE_WIDTH_MASK) >> PAGE_TILE_WIDTH_SHIFT);
|
||||
|
||||
if (!(m_video_regs[0x42] & SPRITE_COORD_TL_MASK))
|
||||
{
|
||||
x = (160 + x) - w / 2;
|
||||
y = (120 - y) - (h / 2) + 8;
|
||||
}
|
||||
|
||||
x &= 0x01ff;
|
||||
y &= 0x01ff;
|
||||
|
||||
uint32_t tile_line = ((scanline - y) + 0x200) % h;
|
||||
int16_t test_y = (y + tile_line) & 0x1ff;
|
||||
if (test_y >= 0x01c0)
|
||||
test_y -= 0x0200;
|
||||
|
||||
if (test_y != scanline)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
bool blend = (attr & 0x4000);
|
||||
bool flip_x = (attr & TILE_X_FLIP);
|
||||
const uint8_t bpp = attr & 0x0003;
|
||||
const uint32_t yflipmask = attr & TILE_Y_FLIP ? h - 1 : 0;
|
||||
const uint32_t palette_offset = (attr & 0x0f00) >> 4;
|
||||
|
||||
#if SPG_DEBUG_VIDEO
|
||||
if (m_debug_sprites && machine().input().code_pressed(KEYCODE_MINUS))
|
||||
m_debug_blit = true;
|
||||
if (blend)
|
||||
{
|
||||
if (flip_x)
|
||||
draw<BlendOn, RowScrollOff, FlipXOn>(cliprect, tile_line, x, y, bitmap_addr, tile, h, w, bpp, yflipmask, palette_offset);
|
||||
else
|
||||
draw<BlendOn, RowScrollOff, FlipXOff>(cliprect, tile_line, x, y, bitmap_addr, tile, h, w, bpp, yflipmask, palette_offset);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (flip_x)
|
||||
draw<BlendOff, RowScrollOff, FlipXOn>(cliprect, tile_line, x, y, bitmap_addr, tile, h, w, bpp, yflipmask, palette_offset);
|
||||
else
|
||||
draw<BlendOff, RowScrollOff, FlipXOff>(cliprect, tile_line, x, y, bitmap_addr, tile, h, w, bpp, yflipmask, palette_offset);
|
||||
}
|
||||
m_debug_blit = false;
|
||||
#else
|
||||
if (blend)
|
||||
{
|
||||
if (flip_x)
|
||||
draw<BlendOn, RowScrollOff, FlipXOn>(cliprect, tile_line, x, y, bitmap_addr, tile, h, w, bpp, yflipmask, palette_offset);
|
||||
else
|
||||
draw<BlendOn, RowScrollOff, FlipXOff>(cliprect, tile_line, x, y, bitmap_addr, tile, h, w, bpp, yflipmask, palette_offset);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (flip_x)
|
||||
draw<BlendOff, RowScrollOff, FlipXOn>(cliprect, tile_line, x, y, bitmap_addr, tile, h, w, bpp, yflipmask, palette_offset);
|
||||
else
|
||||
draw<BlendOff, RowScrollOff, FlipXOff>(cliprect, tile_line, x, y, bitmap_addr, tile, h, w, bpp, yflipmask, palette_offset);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void spg2xx_video_device::draw_sprites(const rectangle &cliprect, uint32_t scanline, int priority)
|
||||
{
|
||||
if (!(m_video_regs[0x42] & SPRITE_ENABLE_MASK))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
#if SPG_DEBUG_VIDEO
|
||||
if (!m_debug_sprites)
|
||||
{
|
||||
#endif
|
||||
for (uint32_t n = 0; n < m_sprlimit_read_cb(); n++)
|
||||
{
|
||||
draw_sprite(cliprect, scanline, priority, 4 * n);
|
||||
}
|
||||
#if SPG_DEBUG_VIDEO
|
||||
}
|
||||
else
|
||||
{
|
||||
draw_sprite(cliprect, scanline, priority, 4 * m_sprite_index_to_debug);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void spg2xx_video_device::apply_saturation(const rectangle &cliprect)
|
||||
{
|
||||
static const float s_u8_to_float = 1.0f / 255.0f;
|
||||
static const float s_gray_r = 0.299f;
|
||||
static const float s_gray_g = 0.587f;
|
||||
static const float s_gray_b = 0.114f;
|
||||
const float sat_adjust = (0xff - (m_video_regs[0x3c] & 0x00ff)) / (float)(0xff - 0x20);
|
||||
for (int y = cliprect.min_y; y <= cliprect.max_y; y++)
|
||||
{
|
||||
uint32_t *src = &m_screenbuf[cliprect.min_x + 320 * y];
|
||||
for (int x = cliprect.min_x; x <= cliprect.max_x; x++)
|
||||
{
|
||||
const uint32_t src_rgb = *src;
|
||||
const float src_r = (uint8_t)(src_rgb >> 16) * s_u8_to_float;
|
||||
const float src_g = (uint8_t)(src_rgb >> 8) * s_u8_to_float;
|
||||
const float src_b = (uint8_t)(src_rgb >> 0) * s_u8_to_float;
|
||||
const float luma = src_r * s_gray_r + src_g * s_gray_g + src_b * s_gray_b;
|
||||
const float adjusted_r = luma + (src_r - luma) * sat_adjust;
|
||||
const float adjusted_g = luma + (src_g - luma) * sat_adjust;
|
||||
const float adjusted_b = luma + (src_b - luma) * sat_adjust;
|
||||
const int integer_r = (int)floor(adjusted_r * 255.0f);
|
||||
const int integer_g = (int)floor(adjusted_g * 255.0f);
|
||||
const int integer_b = (int)floor(adjusted_b * 255.0f);
|
||||
*src++ = (integer_r > 255 ? 0xff0000 : (integer_r < 0 ? 0 : ((uint8_t)integer_r << 16))) |
|
||||
(integer_g > 255 ? 0x00ff00 : (integer_g < 0 ? 0 : ((uint8_t)integer_g << 8))) |
|
||||
(integer_b > 255 ? 0x0000ff : (integer_b < 0 ? 0 : (uint8_t)integer_b));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void spg2xx_video_device::apply_fade(const rectangle &cliprect)
|
||||
{
|
||||
const uint16_t fade_offset = m_video_regs[0x30];
|
||||
for (int y = cliprect.min_y; y <= cliprect.max_y; y++)
|
||||
{
|
||||
uint32_t *src = &m_screenbuf[cliprect.min_x + 320 * y];
|
||||
for (int x = cliprect.min_x; x <= cliprect.max_x; x++)
|
||||
{
|
||||
const uint32_t src_rgb = *src;
|
||||
const uint8_t src_r = (src_rgb >> 16) & 0xff;
|
||||
const uint8_t src_g = (src_rgb >> 8) & 0xff;
|
||||
const uint8_t src_b = (src_rgb >> 0) & 0xff;
|
||||
const uint8_t r = src_r - fade_offset;
|
||||
const uint8_t g = src_g - fade_offset;
|
||||
const uint8_t b = src_b - fade_offset;
|
||||
*src++ = (r > src_r ? 0 : (r << 16)) |
|
||||
(g > src_g ? 0 : (g << 8)) |
|
||||
(b > src_b ? 0 : (b << 0));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t spg2xx_video_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
|
||||
{
|
||||
memset(&m_screenbuf[320 * cliprect.min_y], 0, 4 * 320 * ((cliprect.max_y - cliprect.min_y) + 1));
|
||||
|
||||
const uint32_t page1_addr = 0x40 * m_video_regs[0x20];
|
||||
const uint32_t page2_addr = 0x40 * m_video_regs[0x21];
|
||||
uint16_t *page1_regs = m_video_regs + 0x10;
|
||||
uint16_t *page2_regs = m_video_regs + 0x16;
|
||||
|
||||
for (uint32_t scanline = (uint32_t)cliprect.min_y; scanline <= (uint32_t)cliprect.max_y; scanline++)
|
||||
{
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
if (!SPG_DEBUG_VIDEO || !m_hide_page0)
|
||||
draw_page(cliprect, scanline, i, page1_addr, page1_regs);
|
||||
if (!SPG_DEBUG_VIDEO || !m_hide_page1)
|
||||
draw_page(cliprect, scanline, i, page2_addr, page2_regs);
|
||||
if (!SPG_DEBUG_VIDEO || !m_hide_sprites)
|
||||
draw_sprites(cliprect, scanline, i);
|
||||
}
|
||||
}
|
||||
|
||||
if ((m_video_regs[0x3c] & 0x00ff) != 0x0020)
|
||||
{
|
||||
apply_saturation(cliprect);
|
||||
}
|
||||
|
||||
if (m_video_regs[0x30] != 0)
|
||||
{
|
||||
apply_fade(cliprect);
|
||||
}
|
||||
|
||||
for (int y = cliprect.min_y; y <= cliprect.max_y; y++)
|
||||
{
|
||||
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));
|
||||
}
|
||||
|
||||
if (SPG_DEBUG_VIDEO && m_debug_palette)
|
||||
{
|
||||
for (int y = cliprect.min_y; y <= cliprect.max_y && y < 128; y++)
|
||||
{
|
||||
const uint16_t high_nybble = (y / 8) << 4;
|
||||
uint32_t *dest = &bitmap.pix32(y, cliprect.min_x);
|
||||
for (int x = cliprect.min_x; x <= cliprect.max_x && x < 256; x++)
|
||||
{
|
||||
const uint16_t low_nybble = x / 16;
|
||||
const uint16_t palette_entry = high_nybble | low_nybble;
|
||||
const uint16_t color = m_paletteram[palette_entry];
|
||||
if (!(color & 0x8000))
|
||||
{
|
||||
*dest = m_rgb555_to_rgb888[color & 0x7fff];
|
||||
}
|
||||
dest++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void spg2xx_video_device::do_sprite_dma(uint32_t len)
|
||||
{
|
||||
address_space &mem = m_cpu->space(AS_PROGRAM);
|
||||
|
||||
uint32_t src = m_video_regs[0x70] & 0x3fff;
|
||||
uint32_t dst = m_video_regs[0x71];
|
||||
|
||||
for (uint32_t j = 0; j < len; j++)
|
||||
{
|
||||
m_spriteram[(dst + j) & 0x3ff] = mem.read_word(src + j);
|
||||
}
|
||||
|
||||
m_video_regs[0x72] = 0;
|
||||
if (VIDEO_IRQ_ENABLE & 4)
|
||||
{
|
||||
const uint16_t old = VIDEO_IRQ_STATUS;
|
||||
VIDEO_IRQ_STATUS |= 4;
|
||||
const uint16_t changed = old ^ (VIDEO_IRQ_ENABLE & VIDEO_IRQ_STATUS);
|
||||
if (changed)
|
||||
check_video_irq();
|
||||
}
|
||||
}
|
||||
|
||||
READ16_MEMBER(spg2xx_video_device::video_r)
|
||||
{
|
||||
switch (offset)
|
||||
{
|
||||
case 0x38: // Current Line
|
||||
LOGMASKED(LOG_VLINES, "video_r: Current Line: %04x\n", m_screen->vpos());
|
||||
return m_screen->vpos();
|
||||
|
||||
case 0x62: // Video IRQ Enable
|
||||
LOGMASKED(LOG_IRQS, "video_r: Video IRQ Enable: %04x\n", VIDEO_IRQ_ENABLE);
|
||||
return VIDEO_IRQ_ENABLE;
|
||||
|
||||
case 0x63: // Video IRQ Status
|
||||
LOGMASKED(LOG_IRQS, "video_r: Video IRQ Status: %04x\n", VIDEO_IRQ_STATUS);
|
||||
return VIDEO_IRQ_STATUS;
|
||||
|
||||
default:
|
||||
LOGMASKED(LOG_UNKNOWN_PPU, "video_r: Unknown register %04x = %04x\n", 0x2800 + offset, m_video_regs[offset]);
|
||||
break;
|
||||
}
|
||||
return m_video_regs[offset];
|
||||
}
|
||||
|
||||
WRITE16_MEMBER(spg2xx_video_device::video_w)
|
||||
{
|
||||
switch (offset)
|
||||
{
|
||||
case 0x10: // Page 1 X scroll
|
||||
LOGMASKED(LOG_PPU_WRITES, "video_w: Page 1 X Scroll = %04x\n", data & 0x01ff);
|
||||
m_video_regs[offset] = data & 0x01ff;
|
||||
break;
|
||||
|
||||
case 0x11: // Page 1 Y scroll
|
||||
LOGMASKED(LOG_PPU_WRITES, "video_w: Page 1 Y Scroll = %04x\n", data & 0x00ff);
|
||||
m_video_regs[offset] = data & 0x00ff;
|
||||
break;
|
||||
|
||||
case 0x12: // Page 1 Attributes
|
||||
LOGMASKED(LOG_PPU_WRITES, "video_w: Page 1 Attributes = %04x (Depth:%d, Palette:%d, VSize:%d, HSize:%d, FlipY:%d, FlipX:%d, BPP:%d)\n", 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));
|
||||
m_video_regs[offset] = data;
|
||||
break;
|
||||
|
||||
case 0x13: // Page 1 Control
|
||||
LOGMASKED(LOG_PPU_WRITES, "video_w: Page 1 Control = %04x (Blend:%d, HiColor:%d, RowScroll:%d, Enable:%d, Wallpaper:%d, RegSet:%d, Bitmap:%d)\n", data
|
||||
, BIT(data, 8), BIT(data, 7), BIT(data, 4), BIT(data, 3), BIT(data, 2), BIT(data, 1), BIT(data, 0));
|
||||
m_video_regs[offset] = data;
|
||||
break;
|
||||
|
||||
case 0x14: // Page 1 Tile Address
|
||||
LOGMASKED(LOG_PPU_WRITES, "video_w: Page 1 Tile Address = %04x\n", data & 0x1fff);
|
||||
m_video_regs[offset] = data;
|
||||
break;
|
||||
|
||||
case 0x15: // Page 1 Attribute Address
|
||||
LOGMASKED(LOG_PPU_WRITES, "video_w: Page 1 Attribute Address = %04x\n", data & 0x1fff);
|
||||
m_video_regs[offset] = data;
|
||||
break;
|
||||
|
||||
case 0x16: // Page 2 X scroll
|
||||
LOGMASKED(LOG_PPU_WRITES, "video_w: Page 2 X Scroll = %04x\n", data & 0x01ff);
|
||||
m_video_regs[offset] = data & 0x01ff;
|
||||
break;
|
||||
|
||||
case 0x17: // Page 2 Y scroll
|
||||
LOGMASKED(LOG_PPU_WRITES, "video_w: Page 2 Y Scroll: %04x = %04x\n", 0x2800 | offset, data & 0x00ff);
|
||||
m_video_regs[offset] = data & 0x00ff;
|
||||
break;
|
||||
|
||||
case 0x18: // Page 2 Attributes
|
||||
LOGMASKED(LOG_PPU_WRITES, "video_w: Page 2 Attributes = %04x (Depth:%d, Palette:%d, VSize:%d, HSize:%d, FlipY:%d, FlipX:%d, BPP:%d)\n", 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));
|
||||
m_video_regs[offset] = data;
|
||||
break;
|
||||
|
||||
case 0x19: // Page 2 Control
|
||||
LOGMASKED(LOG_PPU_WRITES, "video_w: Page 2 Control = %04x (Blend:%d, HiColor:%d, RowScroll:%d, Enable:%d, Wallpaper:%d, RegSet:%d, Bitmap:%d)\n", data
|
||||
, BIT(data, 8), BIT(data, 7), BIT(data, 4), BIT(data, 3), BIT(data, 2), BIT(data, 1), BIT(data, 0));
|
||||
m_video_regs[offset] = data;
|
||||
break;
|
||||
|
||||
case 0x1a: // Page 2 Tile Address
|
||||
LOGMASKED(LOG_PPU_WRITES, "video_w: Page 2 Tile Address = %04x\n", data & 0x1fff);
|
||||
m_video_regs[offset] = data;
|
||||
break;
|
||||
|
||||
case 0x1b: // Page 2 Attribute Address
|
||||
LOGMASKED(LOG_PPU_WRITES, "video_w: Page 2 Attribute Address = %04x\n", data & 0x1fff);
|
||||
m_video_regs[offset] = data;
|
||||
break;
|
||||
|
||||
case 0x20: // Page 1 Segment Address
|
||||
LOGMASKED(LOG_PPU_WRITES, "video_w: Page 1 Segment Address = %04x\n", data);
|
||||
m_video_regs[offset] = data;
|
||||
break;
|
||||
|
||||
case 0x21: // Page 2 Segment Address
|
||||
LOGMASKED(LOG_PPU_WRITES, "video_w: Page 2 Segment Address = %04x\n", data);
|
||||
m_video_regs[offset] = data;
|
||||
break;
|
||||
|
||||
case 0x22: // Sprite Segment Address
|
||||
LOGMASKED(LOG_PPU_WRITES, "video_w: Sprite Segment Address = %04x\n", data);
|
||||
m_video_regs[offset] = data;
|
||||
break;
|
||||
|
||||
case 0x2a: // Blend Level Control
|
||||
LOGMASKED(LOG_PPU_WRITES, "video_w: Blend Level Control = %04x\n", data & 0x0003);
|
||||
m_video_regs[offset] = data & 0x0003;
|
||||
break;
|
||||
|
||||
case 0x30: // Fade Effect Control
|
||||
LOGMASKED(LOG_PPU_WRITES, "video_w: Fade Effect Control = %04x\n", data & 0x00ff);
|
||||
m_video_regs[offset] = data & 0x00ff;
|
||||
break;
|
||||
|
||||
case 0x36: // IRQ pos V
|
||||
case 0x37: // IRQ pos H
|
||||
m_video_regs[offset] = data & 0x01ff;
|
||||
LOGMASKED(LOG_IRQS, "video_w: Video IRQ Position: %04x,%04x (%04x)\n", m_video_regs[0x37], m_video_regs[0x36], 0x2800 | offset);
|
||||
if (m_video_regs[0x37] < 160 && m_video_regs[0x36] < 240)
|
||||
m_screenpos_timer->adjust(m_screen->time_until_pos(m_video_regs[0x36], m_video_regs[0x37] << 1));
|
||||
else
|
||||
m_screenpos_timer->adjust(attotime::never);
|
||||
break;
|
||||
|
||||
case 0x39: // Latch 1st Line Pen Pulse
|
||||
LOGMASKED(LOG_PPU_WRITES, "video_w: Latch 1st Line Pen Pulse = %04x\n", data & 0x0001);
|
||||
m_video_regs[offset] = data & 0x0001;
|
||||
break;
|
||||
|
||||
case 0x3c: // TV Control 1
|
||||
LOGMASKED(LOG_PPU_WRITES, "video_w: TV Control 1 = %04x (Hue:%02x, Saturation:%02x)\n", data, data >> 8, data & 0x00ff);
|
||||
m_video_regs[offset] = data;
|
||||
break;
|
||||
|
||||
case 0x3d: // TV Control 2
|
||||
{
|
||||
static const char* const s_lpf_mode[4] = { "LPF1", "LPF2", "All", "Edge" };
|
||||
LOGMASKED(LOG_PPU_WRITES, "video_w: TV Control 2 = %04x (LPFMode:%s, Enable:%d, Interlace:%d)\n", data & 0x000f
|
||||
, s_lpf_mode[(data >> 2) & 3], BIT(data, 1), BIT(data, 0));
|
||||
m_video_regs[offset] = data & 0x000f;
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x3e: // Light Pen Y Position
|
||||
LOGMASKED(LOG_PPU_WRITES, "video_w: Light Pen Y (read only) = %04x\n", data & 0x01ff);
|
||||
break;
|
||||
|
||||
case 0x3f: // Light Pen YXPosition
|
||||
LOGMASKED(LOG_PPU_WRITES, "video_w: Light Pen X (read only) = %04x\n", data & 0x01ff);
|
||||
break;
|
||||
|
||||
case 0x42: // Sprite Control
|
||||
LOGMASKED(LOG_PPU_WRITES, "video_w: Sprite Control = %04x (TopLeft:%d, Enable:%d)\n", data & 0x0003, BIT(data, 1), BIT(data, 0));
|
||||
m_video_regs[offset] = data & 0x0003;
|
||||
break;
|
||||
|
||||
case 0x62: // Video IRQ Enable
|
||||
{
|
||||
LOGMASKED(LOG_IRQS, "video_w: Video IRQ Enable = %04x (DMA:%d, Timing:%d, Blanking:%d)\n", data & 0x0007, BIT(data, 2), BIT(data, 1), BIT(data, 0));
|
||||
const uint16_t old = VIDEO_IRQ_ENABLE & VIDEO_IRQ_STATUS;
|
||||
VIDEO_IRQ_ENABLE = data & 0x0007;
|
||||
const uint16_t changed = old ^ (VIDEO_IRQ_ENABLE & VIDEO_IRQ_STATUS);
|
||||
if (changed)
|
||||
check_video_irq();
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x63: // Video IRQ Acknowledge
|
||||
{
|
||||
LOGMASKED(LOG_IRQS, "video_w: Video IRQ Acknowledge = %04x\n", data);
|
||||
const uint16_t old = VIDEO_IRQ_ENABLE & VIDEO_IRQ_STATUS;
|
||||
VIDEO_IRQ_STATUS &= ~data;
|
||||
const uint16_t changed = old ^ (VIDEO_IRQ_ENABLE & VIDEO_IRQ_STATUS);
|
||||
if (changed)
|
||||
check_video_irq();
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x70: // Sprite DMA Source
|
||||
LOGMASKED(LOG_DMA, "video_w: Sprite DMA Source = %04x\n", data & 0x3fff);
|
||||
m_video_regs[offset] = data & 0x3fff;
|
||||
break;
|
||||
|
||||
case 0x71: // Sprite DMA Dest
|
||||
LOGMASKED(LOG_DMA, "video_w: Sprite DMA Dest = %04x\n", data & 0x03ff);
|
||||
m_video_regs[offset] = data & 0x03ff;
|
||||
break;
|
||||
|
||||
case 0x72: // Sprite DMA Length
|
||||
{
|
||||
LOGMASKED(LOG_DMA, "video_w: Sprite DMA Length = %04x\n", data & 0x03ff);
|
||||
uint16_t length = data & 0x3ff;
|
||||
do_sprite_dma(length ? length : 0x400);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
LOGMASKED(LOG_UNKNOWN_PPU, "video_w: Unknown register %04x = %04x\n", 0x2800 + offset, data);
|
||||
m_video_regs[offset] = data;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
WRITE_LINE_MEMBER(spg2xx_video_device::vblank)
|
||||
{
|
||||
if (!state)
|
||||
{
|
||||
VIDEO_IRQ_STATUS &= ~1;
|
||||
LOGMASKED(LOG_IRQS, "Setting video IRQ status to %04x\n", VIDEO_IRQ_STATUS);
|
||||
check_video_irq();
|
||||
return;
|
||||
}
|
||||
|
||||
#if SPG_DEBUG_VIDEO
|
||||
if (machine().input().code_pressed_once(KEYCODE_5))
|
||||
m_hide_page0 = !m_hide_page0;
|
||||
if (machine().input().code_pressed_once(KEYCODE_6))
|
||||
m_hide_page1 = !m_hide_page1;
|
||||
if (machine().input().code_pressed_once(KEYCODE_7))
|
||||
m_hide_sprites = !m_hide_sprites;
|
||||
if (machine().input().code_pressed_once(KEYCODE_8))
|
||||
m_debug_sprites = !m_debug_sprites;
|
||||
if (machine().input().code_pressed_once(KEYCODE_9))
|
||||
m_sprite_index_to_debug--;
|
||||
if (machine().input().code_pressed_once(KEYCODE_0))
|
||||
m_sprite_index_to_debug++;
|
||||
if (machine().input().code_pressed_once(KEYCODE_L))
|
||||
m_debug_palette = !m_debug_palette;
|
||||
#endif
|
||||
|
||||
if (VIDEO_IRQ_ENABLE & 1)
|
||||
{
|
||||
VIDEO_IRQ_STATUS |= 1;
|
||||
LOGMASKED(LOG_IRQS, "Setting video IRQ status to %04x\n", VIDEO_IRQ_STATUS);
|
||||
check_video_irq();
|
||||
}
|
||||
}
|
||||
|
||||
void spg2xx_video_device::check_video_irq()
|
||||
{
|
||||
LOGMASKED(LOG_IRQS, "%ssserting IRQ0 (%04x, %04x)\n", (VIDEO_IRQ_STATUS & VIDEO_IRQ_ENABLE) ? "A" : "Dea", VIDEO_IRQ_STATUS, VIDEO_IRQ_ENABLE);
|
||||
m_video_irq_cb((VIDEO_IRQ_STATUS & VIDEO_IRQ_ENABLE) ? ASSERT_LINE : CLEAR_LINE);
|
||||
}
|
||||
|
||||
void spg2xx_video_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
|
||||
{
|
||||
switch (id)
|
||||
{
|
||||
case TIMER_SCREENPOS:
|
||||
{
|
||||
if (VIDEO_IRQ_ENABLE & 2)
|
||||
{
|
||||
VIDEO_IRQ_STATUS |= 2;
|
||||
check_video_irq();
|
||||
}
|
||||
m_screen->update_partial(m_screen->vpos());
|
||||
|
||||
// fire again, jak_dbz pinball needs this
|
||||
m_screenpos_timer->adjust(m_screen->time_until_pos(m_video_regs[0x36], m_video_regs[0x37] << 1));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
137
src/devices/machine/spg2xx_video.h
Normal file
137
src/devices/machine/spg2xx_video.h
Normal file
@ -0,0 +1,137 @@
|
||||
// license:BSD-3-Clause
|
||||
// copyright-holders:Ryan Holtz
|
||||
/*****************************************************************************
|
||||
|
||||
SunPlus SPG2xx-series SoC peripheral emulation (Video)
|
||||
|
||||
**********************************************************************/
|
||||
|
||||
#ifndef MAME_MACHINE_SPG2XX_VIDEO_H
|
||||
#define MAME_MACHINE_SPG2XX_VIDEO_H
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "cpu/unsp/unsp.h"
|
||||
#include "screen.h"
|
||||
|
||||
class spg2xx_video_device : public device_t
|
||||
{
|
||||
public:
|
||||
spg2xx_video_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock);
|
||||
|
||||
uint32_t screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect);
|
||||
DECLARE_WRITE_LINE_MEMBER(vblank);
|
||||
|
||||
DECLARE_READ16_MEMBER(video_r);
|
||||
DECLARE_WRITE16_MEMBER(video_w);
|
||||
|
||||
auto sprlimit_read_callback() { return m_sprlimit_read_cb.bind(); };
|
||||
auto rowscrolloffset_read_callback() { return m_rowscrolloffset_read_cb.bind(); };
|
||||
|
||||
auto write_video_irq_callback() { return m_video_irq_cb.bind(); };
|
||||
|
||||
protected:
|
||||
|
||||
enum
|
||||
{
|
||||
PAGE_ENABLE_MASK = 0x0008,
|
||||
PAGE_WALLPAPER_MASK = 0x0004,
|
||||
|
||||
SPRITE_ENABLE_MASK = 0x0001,
|
||||
SPRITE_COORD_TL_MASK = 0x0002,
|
||||
|
||||
PAGE_PRIORITY_FLAG_MASK = 0x3000,
|
||||
PAGE_PRIORITY_FLAG_SHIFT = 12,
|
||||
PAGE_TILE_HEIGHT_MASK = 0x00c0,
|
||||
PAGE_TILE_HEIGHT_SHIFT = 6,
|
||||
PAGE_TILE_WIDTH_MASK = 0x0030,
|
||||
PAGE_TILE_WIDTH_SHIFT = 4,
|
||||
TILE_X_FLIP = 0x0004,
|
||||
TILE_Y_FLIP = 0x0008
|
||||
};
|
||||
|
||||
|
||||
inline void check_video_irq();
|
||||
|
||||
static const device_timer_id TIMER_SCREENPOS = 2;
|
||||
|
||||
virtual void device_start() override;
|
||||
virtual void device_reset() override;
|
||||
virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
|
||||
|
||||
void do_sprite_dma(uint32_t len);
|
||||
|
||||
enum blend_enable_t : bool
|
||||
{
|
||||
BlendOff = false,
|
||||
BlendOn = true
|
||||
};
|
||||
|
||||
enum rowscroll_enable_t : bool
|
||||
{
|
||||
RowScrollOff = false,
|
||||
RowScrollOn = true
|
||||
};
|
||||
|
||||
enum flipx_t : bool
|
||||
{
|
||||
FlipXOff = false,
|
||||
FlipXOn = true
|
||||
};
|
||||
|
||||
void apply_saturation(const rectangle &cliprect);
|
||||
void apply_fade(const rectangle &cliprect);
|
||||
|
||||
template<blend_enable_t Blend, rowscroll_enable_t RowScroll, flipx_t FlipX>
|
||||
void draw(const rectangle &cliprect, uint32_t line, uint32_t xoff, uint32_t yoff, uint32_t bitmap_addr, uint16_t tile, int32_t h, int32_t w, uint8_t bpp, uint32_t yflipmask, uint32_t palette_offset);
|
||||
void draw_page(const rectangle &cliprect, uint32_t scanline, int priority, uint32_t bitmap_addr, uint16_t *regs);
|
||||
void draw_sprite(const rectangle &cliprect, uint32_t scanline, int priority, uint32_t base_addr);
|
||||
void draw_sprites(const rectangle &cliprect, uint32_t scanline, int priority);
|
||||
|
||||
uint8_t mix_channel(uint8_t a, uint8_t b);
|
||||
|
||||
uint32_t m_screenbuf[320 * 240];
|
||||
uint8_t m_rgb5_to_rgb8[32];
|
||||
uint32_t m_rgb555_to_rgb888[0x8000];
|
||||
|
||||
bool m_hide_page0;
|
||||
bool m_hide_page1;
|
||||
bool m_hide_sprites;
|
||||
bool m_debug_sprites;
|
||||
bool m_debug_blit;
|
||||
bool m_debug_palette;
|
||||
uint8_t m_sprite_index_to_debug;
|
||||
|
||||
uint16_t m_video_regs[0x100];
|
||||
|
||||
devcb_read16 m_sprlimit_read_cb;
|
||||
devcb_read16 m_rowscrolloffset_read_cb;
|
||||
|
||||
emu_timer *m_screenpos_timer;
|
||||
|
||||
required_device<unsp_device> m_cpu;
|
||||
required_device<screen_device> m_screen;
|
||||
required_shared_ptr<uint16_t> m_scrollram;
|
||||
required_shared_ptr<uint16_t> m_paletteram;
|
||||
required_shared_ptr<uint16_t> m_spriteram;
|
||||
|
||||
devcb_write_line m_video_irq_cb;
|
||||
};
|
||||
|
||||
class spg24x_video_device : public spg2xx_video_device
|
||||
{
|
||||
public:
|
||||
template <typename T, typename U>
|
||||
spg24x_video_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock, T &&cpu_tag, U &&screen_tag)
|
||||
: spg24x_video_device(mconfig, tag, owner, clock)
|
||||
{
|
||||
m_cpu.set_tag(std::forward<T>(cpu_tag));
|
||||
m_screen.set_tag(std::forward<U>(screen_tag));
|
||||
}
|
||||
|
||||
spg24x_video_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
|
||||
};
|
||||
|
||||
DECLARE_DEVICE_TYPE(SPG24X_VIDEO, spg24x_video_device)
|
||||
|
||||
#endif // MAME_MACHINE_SPG2XX_VIDEO_H
|
@ -47,7 +47,7 @@ protected:
|
||||
|
||||
void spg110_game_state::mem_map(address_map &map)
|
||||
{
|
||||
map(0x004000, 0x0fffff).rom().region("maincpu", 0x8000);
|
||||
map(0x004000, 0x3fffff).rom().region("maincpu", 0x8000);
|
||||
map(0x000000, 0x003fff).m(m_spg, FUNC(spg110_device::map));
|
||||
}
|
||||
|
||||
@ -198,7 +198,7 @@ static INPUT_PORTS_START( jak_capb )
|
||||
PORT_BIT( 0xffff, IP_ACTIVE_HIGH, IPT_UNUSED )
|
||||
|
||||
PORT_START("JOYY")
|
||||
PORT_BIT(0x0fff, 0x0000, IPT_AD_STICK_Y) PORT_SENSITIVITY(100) PORT_KEYDELTA(100) PORT_MINMAX(0x00,0x0fff) PORT_NAME("Plunger")
|
||||
PORT_BIT(0x0fff, 0x0000, IPT_PEDAL ) PORT_SENSITIVITY(100) PORT_KEYDELTA(100) PORT_MINMAX(0x00,0x0fff) PORT_NAME("Plunger")
|
||||
INPUT_PORTS_END
|
||||
|
||||
static INPUT_PORTS_START( jak_spdmo )
|
||||
@ -384,7 +384,7 @@ void spg110_game_state::spg110_base(machine_config &config)
|
||||
}
|
||||
|
||||
ROM_START( jak_capb )
|
||||
ROM_REGION( 0x200000, "maincpu", ROMREGION_ERASE00 )
|
||||
ROM_REGION( 0x800000, "maincpu", ROMREGION_ERASE00 )
|
||||
ROM_LOAD16_WORD_SWAP( "classicarcadepinball.bin", 0x000000, 0x200000, CRC(b643dab0) SHA1(f57d546758ba442e28b5f0f48b3819b2fc2eb7f7) )
|
||||
ROM_END
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user