SunPlus refactoring checkpoint (nw) (#6793)

This commit is contained in:
David Haywood 2020-06-04 21:09:03 +01:00 committed by GitHub
parent 509a99b6c0
commit 3708071150
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 487 additions and 882 deletions

View File

@ -1538,6 +1538,9 @@ void sunplus_gcm394_base_device::device_reset()
m_system_dma_memtype = 0x0000;
m_unk_timer->adjust(attotime::from_hz(60), 0, attotime::from_hz(60));
m_spg_video->set_video_spaces(this->space(AS_PROGRAM), *m_cs_space, m_csbase);
m_spg_video->reset();
}
void generalplus_gpac800_device::device_reset()
@ -1649,7 +1652,6 @@ uint16_t sunplus_gcm394_base_device::read_space(uint32_t offset)
void sunplus_gcm394_base_device::write_space(uint32_t offset, uint16_t data)
{
address_space& space = this->space(AS_PROGRAM);

View File

@ -8,97 +8,6 @@
**********************************************************************/
/* lots of games, including wrlshunt are not copying tilemap data properly
the analysis below is for wrlshunt, although gormiti could prove to be an easier case to look at
while jak_ths and jak_swc might be more difficult (the latter uses line/bitmap mode, but still
fails to copy the line data)
--
wrlshunt BG Tilemap location note
background tilemap appears to be at 24ad30 - 24af87 (byte address) in RAM == 125698 - 1257c3 (word address)
there are pointers to this
(2879-287a) = 98 56 12 00 (00125698) (main background tilemap data is at this address)
(287b-287c) = 30 5e 12 00 (00125e30) (address for other layer tilemap) (or 'end' of above)
where do we get these copied to registers or used as a source to copy from?
-- callled from here
058F79: call 054e56 (with values above, for tilemap 0)
and
058FB1: call 054e56 (for tilemap 1)
(both of these are at the start of the function at 058F46, which we loop in at the moment, possible main loop for the menu?)
there are other calls in the code, but those are the ones before sprites are uploaded for the menu
--
054E91: r4 = [bp+27] (contains lower part of address)
054E92: ds:[r1++] = r4 -- write 5698 to 2879
054E93: r4 = [bp+28] (contains upper part of address)
054E94: ds:[r1] = r4 -- write 0012 to 287a
(this is a huge function that ends at 55968, also has lots of calls in it)
---
the base for tilemap params being written to RAM is 2879 + 0xe * tilmap number (0,1,2,3)
the code to calculate this offset from base uses 32-bit multiplication and even sign extends the tilemap number before using it, making it
look more complex than it really is!
054E7B: 0B0D 0088 bp = bp + 0088
054E7D: 9800 r4 = [bp+00] -- which tilemap? (0,1,2,3)
054E7E: 2B0D 0088 bp = bp - 0088
054E80: 973C r3 = r4 asr 4 -- sign extend tilemap 16-bit register r4 with r3 forming the upper word (always 0)
054E81: 973B r3 = r3 asr 4
054E82: 973B r3 = r3 asr 4
054E83: 973B r3 = r3 asr 4
054E84: D688 push r3, r3 to [sp] -- push onto stack for use in call below
054E85: D888 push r4, r4 to [sp]
054E86: 964E r3 = 0e -- store 0000 000e as the 32-bit value to multply with
054E87: 9840 r4 = 00
054E88: D890 push r3, r4 to [sp] -- push that onto stack for function call below
054E89: F045 D706 call 05d706 -- returns result in r1,r2
the result of this is then added to the base value of 2879 (which was stored earlier)
an additional offset is then added for each parameter.
this code is repeated multiple times, with slight changes
---
by the time you hit 055098 (which is a switch on tilemap type to disable a tilemap) the following params have been put at
2879 ( tilemap 0 call )
2879 + 0x0e (tilemap 1 call )
tmap0 params
5698 0012 | 5E30 0012 | 0280 01E0 | 0002 0020 0020 0000 0000 0100 0000 0000
125698 | 125e30 | = 640 = 480
tmap1 params
7280 000D | 89F0 000D | 0280 01E0 | 0002 0020 0020 0002 0000 0040 0000 0000
0d7280 | 0d89f0 | = 640 = 480 |
these parameter lists are not read after this? is there some kind of indirect dma mode, or is code not being called that should use them.
plenty more code is called, including more that looks a lot like the above, some use of 707f and at the end of the funciton, code to
write various tilemap registers, including reenabling the tilemap that was disabled around 055098.
--
if you return rand() on 707f reads sometimes you see
[:maincpu] pc:053775: r4 = r4 lsr r3 (5698 0009) : [:maincpu] result 002b (possible unrelated)
(bg tile addressing is also done by tile #, like the sprites, not fixed step like smartfp)
*/
#include "emu.h"
#include "generalplus_gpl16250soc_video.h"
@ -118,20 +27,15 @@ DEFINE_DEVICE_TYPE(GCM394_VIDEO, gcm394_video_device, "gcm394_video", "GeneralPl
gcm394_base_video_device::gcm394_base_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_gfx_interface(mconfig, *this, nullptr),
device_video_interface(mconfig, *this),
m_cpu(*this, finder_base::DUMMY_TAG),
m_screen(*this, finder_base::DUMMY_TAG),
// m_scrollram(*this, "scrollram"),
m_video_irq_cb(*this),
m_palette(*this, "palette"),
m_gfxdecode(*this, "gfxdecode"),
m_space_read_cb(*this),
m_rowscroll(*this, "^rowscroll"),
m_rowzoom(*this, "^rowzoom"),
// m_pal_displaybank_high(0),
// m_pal_sprites(0x100),
// m_pal_back(0x000),
m_alt_extrasprite_hack(0),
m_alt_tile_addressing(0),
m_renderer(*this, "renderer")
@ -295,17 +199,6 @@ void gcm394_base_video_device::decodegfx(const char* tag)
void gcm394_base_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_video_irq_cb.resolve();
m_maxgfxelement = 0;
@ -319,10 +212,6 @@ void gcm394_base_video_device::device_start()
m_screenpos_timer = timer_alloc(TIMER_SCREENPOS);
m_screenpos_timer->adjust(attotime::never);
save_item(NAME(m_screenbuf));
save_item(NAME(m_rgb5_to_rgb8));
save_item(NAME(m_rgb555_to_rgb888));
save_item(NAME(m_page0_addr_lsb));
save_item(NAME(m_page0_addr_msb));
save_item(NAME(m_page1_addr_lsb));
@ -365,10 +254,8 @@ void gcm394_base_video_device::device_start()
save_item(NAME(m_page3_addr_lsb));
save_item(NAME(m_page3_addr_msb));
save_item(NAME(m_spriteram));
save_item(NAME(m_spriteextra));
save_item(NAME(m_paletteram));
save_item(NAME(m_maxgfxelement));
// save_item(NAME(m_pal_displaybank_high));
save_item(NAME(m_alt_tile_addressing));
}
@ -390,16 +277,14 @@ void gcm394_base_video_device::device_reset()
m_tmap1_scroll[i] = 0x0000;
}
for (int i = 0; i < 0x400; i++)
for (int i = 0; i < 0x400*2; i++)
{
m_spriteextra[i] = 0x0000;
m_spriteram[i] = 0x0000;
}
for (int i=0;i<0x100 * 0x10;i++)
m_paletteram[i] = machine().rand()&0x7fff;
m_707f = 0x0000;
m_703a_palettebank = 0x0000;
m_video_irq_enable = 0x0000;
@ -435,546 +320,7 @@ void gcm394_base_video_device::device_reset()
m_page3_addr_lsb = 0;
m_page3_addr_msb = 0;
}
/*************************
* Video Hardware *
*************************/
template<gcm394_base_video_device::blend_enable_t Blend, gcm394_base_video_device::rowscroll_enable_t RowScroll, gcm394_base_video_device::flipx_t FlipX>
void gcm394_base_video_device::draw(const rectangle &cliprect, uint32_t line, uint32_t xoff, uint32_t yoff, uint32_t bitmap_addr, uint32_t tile, int32_t h, int32_t w, uint8_t bpp, uint32_t yflipmask, uint32_t palette_offset, int addressing_mode)
{
uint32_t nc_bpp = ((bpp) + 1) << 1;
// probably don't do this here as this SoC has extended palette for higher bpp modes
//palette_offset >>= nc_bpp;
//palette_offset <<= nc_bpp;
uint32_t bits_per_row = nc_bpp * w / 16;
uint32_t words_per_tile;
if (addressing_mode == 1)
{
words_per_tile = bits_per_row * h;
}
else
{
words_per_tile = 8; // seems to be correct for sprites regardless of size / bpp on smartfp
}
int x_max;
if (m_707f & 0x0010)
{
x_max = 0x400;
}
else
{
x_max = 0x200;
}
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 > cliprect.max_y || yy < 0)
return;
int y_index = yy * m_screen->width();
for (int32_t x = FlipX ? (w - 1) : 0; FlipX ? x >= 0 : x < w; FlipX ? x-- : x++)
{
int xx = xoff + x;
bits <<= nc_bpp;
if (nbits < nc_bpp)
{
uint16_t b = m_space_read_cb((m++)&0x7ffffff); // smartfp suggests either 0x7ffffff mask, or some bits are being set incorrectly, jak_s500 needs over 0x3ffffff at least
b = (b << 8) | (b >> 8);
bits |= b << (nc_bpp - nbits);
nbits += 16;
}
nbits -= nc_bpp;
int pen = bits >> 16;
int current_palette_offset = palette_offset;
uint32_t pal = current_palette_offset + pen;
bits &= 0xffff;
if (RowScroll)
xx -= 0;// (int16_t)m_scrollram[yy & 0x1ff];
xx &= (x_max-1);
if (xx >= (x_max-0x40))
xx -= x_max;
if (xx >= 0 && xx <= cliprect.max_x)
{
int pix_index = xx + y_index;
uint16_t rgb = m_paletteram[pal];
if (!(rgb & 0x8000))
{
if (Blend)
{
/*
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]));
*/
m_screenbuf[pix_index] = m_rgb555_to_rgb888[rgb];
}
else
{
m_screenbuf[pix_index] = m_rgb555_to_rgb888[rgb];
}
}
}
}
}
void gcm394_base_video_device::draw_page(const rectangle &cliprect, uint32_t scanline, int priority, uint32_t bitmap_addr, uint16_t *regs, uint16_t *scroll, int which)
{
uint32_t xscroll = scroll[0];
uint32_t yscroll = scroll[1];
uint32_t attr_reg = regs[0];
uint32_t ctrl_reg = regs[1];
uint32_t tilemap = regs[2];
uint32_t palette_map = regs[3];
address_space &space = m_cpu->space(AS_PROGRAM);
// attr_reg bits
// -Bzz pppp hhww ffbb
//
// B = blend
// zz = depth
// pppp = palette
// ff = flips
// bb = bpp
// hh = height
// ww = width
// ctrl_reg bits
// ---- ---B h--r ewRl
//
// e = enable
// l = bitmape/line mode
// r = rowscroll
// w = wallpaper mode
// R = regset mode
// h = high colour
// B = blend
if (!(ctrl_reg & 0x0008))
{
return;
}
if (((attr_reg & 0x3000) >> 12) != priority)
{
return;
}
if (ctrl_reg & 0x0001) // bitmap mode jak_car2 and jak_s500 use for the ingame race sections, also have a bitmap test in test mode
{
if (0)
{
if (ctrl_reg & 0x0010)
popmessage("bitmap mode %08x with rowscroll\n", bitmap_addr);
else
popmessage("bitmap mode %08x\n", bitmap_addr);
}
// note, in interlace modes it appears every other line is unused? (480 entry table, but with blank values)
// and furthermore the rowscroll and rowzoom tables only have 240 entries, not enough for every line
// the end of the rowscroll table (entries 240-255) contain something else, maybe garbage data as it's offscreen, maybe not
uint32_t linebase = space.read_word(tilemap + scanline); // every other word is unused, but there are only enough entries for 240 lines then, sometimes to do with interlace mode?
uint16_t palette = space.read_word(palette_map + (scanline / 2));
if (scanline & 1)
palette >>= 8;
else
palette &= 0xff;
if (!linebase)
return;
linebase = linebase | (palette << 16);
// this logic works for jak_s500 and the test modes to get the correct base, doesn't seem to work for jak_car2 ingame, maybe data is copied to wrong place?
int gfxbase = (bitmap_addr&0x7ffffff) + (linebase&0x7ffffff);
for (int i = 0; i < 160; i++) // will have to be 320 for jak_car2 ingame, jak_s500 lines are wider than screen, and zoomed
{
uint16_t pix = m_space_read_cb((gfxbase++)&0x7ffffff);
int xx;
int y_index = scanline * m_screen->width();
uint16_t pal;
if ((scanline >= 0) && (scanline < 480))
{
xx = i * 2;
pal = (pix & 0xff) | 0x100;
if (xx >= 0 && xx <= cliprect.max_x)
{
int pix_index = xx + y_index;
uint16_t rgb = m_paletteram[pal];
if (!(rgb & 0x8000))
{
m_screenbuf[pix_index] = m_rgb555_to_rgb888[rgb];
}
}
xx = (i * 2)+1;
pal = (pix >> 8) + 0x100;
if (xx >= 0 && xx <= cliprect.max_x)
{
int pix_index = xx + y_index;
uint16_t rgb = m_paletteram[pal];
if (!(rgb & 0x8000))
{
m_screenbuf[pix_index] = m_rgb555_to_rgb888[rgb];
}
}
}
}
}
else
{
uint32_t tile_h = 8 << ((attr_reg & 0x00c0) >> 6);
uint32_t tile_w = 8 << ((attr_reg & 0x0030) >> 4);
int total_width;
int use_alt_drawmode = m_alt_tile_addressing;
int y_mask = 0;
// just a guess based on this being set on the higher resolution tilemaps we've seen, could be 100% incorrect register
if ((attr_reg >> 15) & 0x1)
{
total_width = 1024;
y_mask = 0x1ff;
// use_alt_drawmode = 1; // probably doesn't control this
}
else
{
total_width = 512;
y_mask = 0xff;
// use_alt_drawmode = 0; // probably doesn't control this
}
uint32_t tile_count_x = total_width / tile_w;
uint32_t bitmap_y = (scanline + yscroll) & y_mask;
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) & y_mask) - 0x10;
uint32_t xx = (tile_w * x0 - xscroll) & (total_width-1);
uint32_t tile = (ctrl_reg & 0x0004) ? space.read_word(tilemap) : space.read_word(tilemap + tile_address);
if (!tile)
continue;
bool blend;
bool row_scroll;
bool flip_x;
uint32_t yflipmask;
uint32_t palette_offset;
blend = (attr_reg & 0x4000 || ctrl_reg & 0x0100);
row_scroll = (ctrl_reg & 0x0010);
if ((ctrl_reg & 0x0002) == 0) // RegSet:0
{
uint16_t palette = (ctrl_reg & 0x0004) ? space.read_word(palette_map) : space.read_word(palette_map + tile_address / 2);
if (x0 & 1)
palette >>= 8;
// 'palette' format
// --ff pppp
//
// f = flip bits
// p = palette
flip_x = palette & 0x10;
yflipmask = (palette & 0x20) ? tile_h - 1 : 0;
palette_offset = (palette & 0x0f) << 4;
}
else // RegSet:1
{
if (m_alt_tile_addressing == 0)
{
// smartfp needs the attribute table to contain extra tile bits even if regset is 1
uint16_t palette = (ctrl_reg & 0x0004) ? space.read_word(palette_map) : space.read_word(palette_map + tile_address / 2);
if (x0 & 1)
palette >>= 8;
// 'palette' format
// -- -ttt
//
// t = extra tile number bits
tile |= (palette & 0x0007) << 16;
}
flip_x = (attr_reg & 0x0004);
yflipmask = attr_reg & 0x0008 ? tile_h - 1 : 0;
palette_offset = (attr_reg & 0x0f00) >> 4;
}
const uint8_t bpp = attr_reg & 0x0003;
// HACKS
// There must be a select bit for the tilemap palettes somewhere, but where?!
// the different games in paccon also expect a variety of different configs here, maybe a good place to look
if (m_703a_palettebank & 1) // this actually seems to be the sprite palette bank enable, but for tkmag220 it gives us an easy way to ignore the logic below
{
if (which == 0) // tilemap 0
{
if (ctrl_reg & 0x0002) // RegSet:1
{
// smartfp has a conflict between the bootlogos and the first screen, it's in regset mode, no obvious difference in registers but needs palette from different places?
// not even m_707f changes here, which makes the m_707f case specific hacks for jak_s500 below very unlikely to actually be related
if ((bpp + 1) * 2 == 4)
if (m_alt_tile_addressing == 0)
palette_offset |= 0x200;
}
}
if (which == 1)
{
// can't do this for jak_s500 logos
// jak_s500 also uses this tilemap in both 4 and 6bpp modes expecting the same palette base, so the hack used for smartfp on tilemap 0 is not applicable here
// m_707f != 0x2d3 for jak_S500 main menu
if ((m_707f != 0x53) && (m_707f != 0x63) && (m_707f != 0x2d3))
palette_offset |= 0x200;
}
// jak_car2 screen transitions use layers 2 and 3 the same way, alternating each frame
if (which == 2)
{
// jak_s500 title screen + loading screen before race
if ((m_707f == 0x2d3) || (m_707f == 0x2db))
palette_offset |= 0x200;
}
}
//palette_offset |= m_pal_back;
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, use_alt_drawmode);
else
draw<BlendOn, RowScrollOn, FlipXOff>(cliprect, tile_scanline, xx, yy, bitmap_addr, tile, tile_h, tile_w, bpp, yflipmask, palette_offset, use_alt_drawmode);
}
else
{
if (flip_x)
draw<BlendOn, RowScrollOff, FlipXOn>(cliprect, tile_scanline, xx, yy, bitmap_addr, tile, tile_h, tile_w, bpp, yflipmask, palette_offset, use_alt_drawmode);
else
draw<BlendOn, RowScrollOff, FlipXOff>(cliprect, tile_scanline, xx, yy, bitmap_addr, tile, tile_h, tile_w, bpp, yflipmask, palette_offset, use_alt_drawmode);
}
}
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, use_alt_drawmode);
else
draw<BlendOff, RowScrollOn, FlipXOff>(cliprect, tile_scanline, xx, yy, bitmap_addr, tile, tile_h, tile_w, bpp, yflipmask, palette_offset, use_alt_drawmode);
}
else
{
if (flip_x)
draw<BlendOff, RowScrollOff, FlipXOn>(cliprect, tile_scanline, xx, yy, bitmap_addr, tile, tile_h, tile_w, bpp, yflipmask, palette_offset, use_alt_drawmode);
else
draw<BlendOff, RowScrollOff, FlipXOff>(cliprect, tile_scanline, xx, yy, bitmap_addr, tile, tile_h, tile_w, bpp, yflipmask, palette_offset, use_alt_drawmode);
}
}
}
}
}
void gcm394_base_video_device::draw_sprite(const rectangle& cliprect, uint32_t scanline, int priority, uint32_t base_addr)
{
uint32_t bitmap_addr = (m_sprite_702d_gfxbase_msb << 16) | m_sprite_7022_gfxbase_lsb;
uint32_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) // this check needs to come before the additional attribute bits are added in? (smartfp title)
{
return;
}
int addressing_mode = 0;
int screenwidth, screenheight, x_max;
if (m_707f & 0x0010)
{
screenwidth = 640;
screenheight = 480;
x_max = 0x400;
}
else
{
screenwidth = 320;
screenheight = 240;
x_max = 0x200;
}
// good for gormiti, smartfp, wrlshunt, paccon, jak_totm, jak_s500, jak_gtg
if ((m_7042_sprite & 0x0010) == 0x10)
addressing_mode = 0; // smartfp, paccon
else
addressing_mode = 1;
if (m_alt_extrasprite_hack == 0)
if (addressing_mode == 0) // smartfp, paccon
tile |= m_spriteextra[base_addr / 4] << 16;
if (m_alt_extrasprite_hack == 1) // jak_prft
tile |= (m_spriteextra[base_addr] & 0x000f) << 16;
if (((attr & 0x3000) >> 12) != priority)
{
return;
}
// attr PBzz pppp hhww ffdd
// P = high palette bit
// b = blend enable
// zz = priority
// pppp = palette
// hh = height
// ww = width
// ff = flips
// dd = depth
const uint32_t h = 8 << ((attr & 0x00c0) >> 6);
const uint32_t w = 8 << ((attr & 0x0030) >> 4);
if (!(m_7042_sprite & 0x0002))
{
x = ((screenwidth / 2) + x) - w / 2;
y = ((screenheight / 2) - y) - (h / 2) + 8;
}
x &= (x_max - 1);
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;
uint8_t bpp;
uint32_t yflipmask;
uint32_t palette_offset;
// different attribute use?
if (screenwidth == 320)
{
if (m_alt_extrasprite_hack == 0)
{
flip_x = (attr & 0x0004);
yflipmask = attr & 0x0008 ? h - 1 : 0;
}
else
{
flip_x = 0;
yflipmask = 0;
}
bpp = attr & 0x0003;
palette_offset = (attr & 0x0f00) >> 4;
}
else
{
flip_x = 0;// (attr & 0x0004);
yflipmask = 0;// attr& 0x0008 ? h - 1 : 0;
bpp = attr & 0x0003;
palette_offset = (attr & 0x0f00) >> 4;
}
if (m_703a_palettebank & 1)
palette_offset |= 0x100;
if (attr & 0x8000)
palette_offset |= 0x200;
if (blend)
{
if (flip_x)
draw<BlendOn, RowScrollOff, FlipXOn>(cliprect, tile_line, x, y, bitmap_addr, tile, h, w, bpp, yflipmask, palette_offset, addressing_mode);
else
draw<BlendOn, RowScrollOff, FlipXOff>(cliprect, tile_line, x, y, bitmap_addr, tile, h, w, bpp, yflipmask, palette_offset, addressing_mode);
}
else
{
if (flip_x)
draw<BlendOff, RowScrollOff, FlipXOn>(cliprect, tile_line, x, y, bitmap_addr, tile, h, w, bpp, yflipmask, palette_offset, addressing_mode);
else
draw<BlendOff, RowScrollOff, FlipXOff>(cliprect, tile_line, x, y, bitmap_addr, tile, h, w, bpp, yflipmask, palette_offset, addressing_mode);
}
}
void gcm394_base_video_device::draw_sprites(const rectangle &cliprect, uint32_t scanline, int priority)
{
// paccon suggests this, does older hardware have similar?
int numsprites = (m_7042_sprite & 0xff00) >> 8;
if (numsprites == 0)
numsprites = 0x100;
for (uint32_t n = 0; n < numsprites; n++)
{
draw_sprite(cliprect, scanline, priority, 4 * n);
}
m_renderer->set_video_spaces(m_cpuspace, m_cs_space, m_csbase);
}
uint32_t gcm394_base_video_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
@ -1021,48 +367,45 @@ uint32_t gcm394_base_video_device::screen_update(screen_device &screen, bitmap_r
}
//const uint16_t bgcol = 0x7c1f; // magenta
const uint16_t bgcol = 0x0000; // black
// const uint16_t bgcol = 0x0000; // black
bool highres;
if (m_707f & 0x0010)
{
highres = true;
m_screen->set_visible_area(0, 640-1, 0, 480-1);
}
else
{
highres = false;
m_screen->set_visible_area(0, 320-1, 0, 240-1);
}
address_space &mem = m_cpu->space(AS_PROGRAM);
const uint32_t page0_addr = (m_page0_addr_msb << 16) | m_page0_addr_lsb;
const uint32_t page1_addr = (m_page1_addr_msb << 16) | m_page1_addr_lsb;
const uint32_t page2_addr = (m_page2_addr_msb << 16) | m_page2_addr_lsb;
const uint32_t page3_addr = (m_page3_addr_msb << 16) | m_page3_addr_lsb;
const uint32_t sprites_addr = (m_sprite_702d_gfxbase_msb << 16) | m_sprite_7022_gfxbase_lsb;
bitmap.fill(0, cliprect);
for (uint32_t scanline = (uint32_t)cliprect.min_y; scanline <= (uint32_t)cliprect.max_y; scanline++)
{
uint32_t* bufferline = &m_screenbuf[scanline * m_screen->width()];
for (int x = 0; x < m_screen->width(); x++)
{
bufferline[x] = m_rgb555_to_rgb888[bgcol];
}
uint32_t* dst = &bitmap.pix32(scanline, cliprect.min_x);
for (int i = 0; i < 4; i++)
{
const int draw_all = 1;
m_renderer->draw_page(true, true, m_alt_tile_addressing ? false : true, m_703a_palettebank, cliprect, dst, scanline, i, page0_addr, m_tmap0_scroll, m_tmap0_regs, mem, m_paletteram, m_rowscroll, 0);
m_renderer->draw_page(true, true, m_alt_tile_addressing ? false : true, m_703a_palettebank, cliprect, dst, scanline, i, page1_addr, m_tmap1_scroll, m_tmap1_regs, mem, m_paletteram, m_rowscroll, 1);
m_renderer->draw_page(true, true, m_alt_tile_addressing ? false : true, m_703a_palettebank, cliprect, dst, scanline, i, page2_addr, m_tmap2_scroll, m_tmap2_regs, mem, m_paletteram, m_rowscroll, 2);
m_renderer->draw_page(true, true, m_alt_tile_addressing ? false : true, m_703a_palettebank, cliprect, dst, scanline, i, page3_addr, m_tmap3_scroll, m_tmap3_regs, mem, m_paletteram, m_rowscroll, 3);
if (1)
{
if ((!(machine().input().code_pressed(KEYCODE_Q))) || draw_all) draw_page(cliprect, scanline, i, (m_page0_addr_lsb | (m_page0_addr_msb<<16)), m_tmap0_regs, m_tmap0_scroll, 0);
if ((!(machine().input().code_pressed(KEYCODE_W))) || draw_all) draw_page(cliprect, scanline, i, (m_page1_addr_lsb | (m_page1_addr_msb<<16)), m_tmap1_regs, m_tmap1_scroll, 1);
if ((!(machine().input().code_pressed(KEYCODE_E))) || draw_all) draw_page(cliprect, scanline, i, (m_page2_addr_lsb | (m_page2_addr_msb<<16)), m_tmap2_regs, m_tmap2_scroll, 2);
if ((!(machine().input().code_pressed(KEYCODE_R))) || draw_all) draw_page(cliprect, scanline, i, (m_page3_addr_lsb | (m_page3_addr_msb<<16)), m_tmap3_regs, m_tmap3_scroll, 3);
}
if ((!(machine().input().code_pressed(KEYCODE_T))) || draw_all) draw_sprites(cliprect, scanline, i);
m_renderer->draw_sprites(true, true, m_alt_extrasprite_hack ? true : false, m_703a_palettebank, highres, cliprect, dst, scanline, i, sprites_addr, mem, m_paletteram, m_spriteram, -1);
}
}
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 + m_screen->width() * y];
memcpy(dest, src, sizeof(uint32_t) * ((cliprect.max_x - cliprect.min_x) + 1));
m_renderer->apply_saturation_and_fade(bitmap, cliprect, scanline);
}
return 0;
@ -1391,6 +734,8 @@ WRITE16_MEMBER(gcm394_base_video_device::sprite_7042_extra_w)
{
LOGMASKED(LOG_GCM394_VIDEO, "%s:gcm394_base_video_device::sprite_7042_extra_w %04x\n", machine().describe_context(), data);
m_7042_sprite = data;
m_renderer->set_video_reg_42(data);
//popmessage("extra modes %04x\n", data);
}
@ -1470,7 +815,7 @@ READ16_MEMBER(gcm394_base_video_device::video_707c_r)
READ16_MEMBER(gcm394_base_video_device::video_707f_r)
{
uint16_t retdata = m_707f;
uint16_t retdata = m_renderer->get_video_reg_7f();
LOGMASKED(LOG_GCM394_VIDEO, "%s:gcm394_base_video_device::video_707f_r (returning %04x)\n", machine().describe_context(), retdata);
return retdata;
}
@ -1496,7 +841,7 @@ WRITE16_MEMBER(gcm394_base_video_device::video_707f_w)
}
m_707f = data;
m_renderer->set_video_reg_7f(data);
//popmessage("707f is %04x\n", data);
}
@ -1558,6 +903,7 @@ WRITE16_MEMBER(gcm394_base_video_device::video_702a_w)
{
LOGMASKED(LOG_GCM394_VIDEO, "%s:gcm394_base_video_device::video_702a_w %04x\n", machine().describe_context(), data);
m_702a = data;
m_renderer->set_video_reg_2a(data);
}
READ16_MEMBER(gcm394_base_video_device::video_curline_r)
@ -1582,15 +928,17 @@ WRITE16_MEMBER(gcm394_base_video_device::video_7030_brightness_w)
{
LOGMASKED(LOG_GCM394_VIDEO, "%s:gcm394_base_video_device::video_7030_brightness_w %04x\n", machine().describe_context(), data);
m_7030_brightness = data;
m_renderer->set_video_reg_30(data);
}
void gcm394_base_video_device::update_raster_split_position()
{
// this might need updating to handle higher res modes
LOGMASKED(LOG_GCM394_VIDEO, "update_raster_split_position: %04x,%04x\n", m_yirqpos, m_xirqpos);
if (m_xirqpos < 300 && m_yirqpos < 240)
if (m_xirqpos < 300 && m_yirqpos < 256)
{
m_screenpos_timer->adjust(m_screen->time_until_pos(m_yirqpos, m_xirqpos));
// where does -19 come from? needed for raster on paccon xevious to fire at correct line for bg scrolling to be seamless
m_screenpos_timer->adjust(m_screen->time_until_pos(m_yirqpos-19, m_xirqpos));
//printf("setting irq timer for y:%d x:%d", m_yirqpos, m_xirqpos);
}
else
@ -1623,6 +971,7 @@ WRITE16_MEMBER(gcm394_base_video_device::video_703c_tvcontrol1_w)
{
LOGMASKED(LOG_GCM394_VIDEO, "%s:gcm394_base_video_device::video_703c_tvcontrol1_w %04x\n", machine().describe_context(), data);
m_703c_tvcontrol1 = data;
m_renderer->set_video_reg_3c(data);
}
READ16_MEMBER(gcm394_base_video_device::video_7051_r)
@ -1668,7 +1017,7 @@ WRITE16_MEMBER(gcm394_base_video_device::spriteram_w)
}
else if (m_707e_spritebank == 0x0001)
{
m_spriteextra[offset] = data;
m_spriteram[offset + 0x400] = data;
}
else
{
@ -1684,7 +1033,7 @@ READ16_MEMBER(gcm394_base_video_device::spriteram_r)
}
else if (m_707e_spritebank == 0x0001)
{
return m_spriteextra[offset];
return m_spriteram[offset + 0x400];
}
else
{
@ -1705,13 +1054,9 @@ WRITE16_MEMBER(gcm394_base_video_device::palette_w)
{
offset |= (m_703a_palettebank & 0x000c) << 6;
m_paletteram[offset] = data;
uint32_t pal = m_rgb555_to_rgb888[data & 0x7fff];
int r = (pal >> 16) & 0xff;
int g = (pal >> 8) & 0xff;
int b = (pal >> 0) & 0xff;
m_palette->set_pen_color(offset, rgb_t(r, g, b));
// for debug
m_palette->set_pen_color(offset, rgb_t((((data >> 15) & 0x1f)<<3), (((data >> 10) & 0x1f)<<3), (((data >> 0) & 0x1f)<<3)));
}
}
@ -1731,16 +1076,19 @@ READ16_MEMBER(gcm394_base_video_device::palette_r)
WRITE16_MEMBER(gcm394_base_video_device::video_701c_w)
{
LOGMASKED(LOG_GCM394_VIDEO, "%s:gcm394_base_video_device::video_701c_w (unknown video reg?) %04x\n", machine().describe_context(), data);
m_renderer->set_video_reg_1c(data);
}
WRITE16_MEMBER(gcm394_base_video_device::video_701d_w)
{
LOGMASKED(LOG_GCM394_VIDEO, "%s:gcm394_base_video_device::video_701d_w (unknown video reg?) %04x\n", machine().describe_context(), data);
m_renderer->set_video_reg_1d(data);
}
WRITE16_MEMBER(gcm394_base_video_device::video_701e_w)
{
LOGMASKED(LOG_GCM394_VIDEO, "%s:gcm394_base_video_device::video_701e_w (unknown video reg?) %04x\n", machine().describe_context(), data);
m_renderer->set_video_reg_1e(data);
}
@ -1787,7 +1135,7 @@ void gcm394_base_video_device::device_timer(emu_timer &timer, device_timer_id id
m_screen->update_partial(m_screen->vpos());
// fire again, jak_dbz pinball needs this
m_screenpos_timer->adjust(m_screen->time_until_pos(m_yirqpos, m_xirqpos));
m_screenpos_timer->adjust(m_screen->time_until_pos(m_yirqpos-19, m_xirqpos));
break;
}
}

View File

@ -36,6 +36,8 @@ public:
void set_alt_extrasprite(int alt_extrasprite_hack) { m_alt_extrasprite_hack = alt_extrasprite_hack; }
void set_video_spaces(address_space& cpuspace, address_space& cs_space, int csbase) { m_cpuspace = &cpuspace; m_cs_space = &cs_space; m_csbase = csbase; }
//void set_pal_sprites(int pal_sprites) { m_pal_sprites = pal_sprites; }
//void set_pal_back(int pal_back) { m_pal_back = pal_back; }
@ -147,37 +149,8 @@ protected:
virtual void device_start() override;
virtual void device_reset() override;
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
};
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, uint32_t tile, int32_t h, int32_t w, uint8_t bpp, uint32_t yflipmask, uint32_t palette_offset, int addressing_mode);
void draw_page(const rectangle &cliprect, uint32_t scanline, int priority, uint32_t bitmap_addr, uint16_t *regs, uint16_t *scroll, int which);
void draw_sprites(const rectangle& cliprect, uint32_t scanline, int priority);
void draw_sprite(const rectangle& cliprect, uint32_t scanline, int priority, uint32_t base_addr);
uint32_t m_screenbuf[640 * 480];
uint8_t m_rgb5_to_rgb8[32];
uint32_t m_rgb555_to_rgb888[0x8000];
required_device<unsp_device> m_cpu;
required_device<screen_device> m_screen;
// required_shared_ptr<uint16_t> m_scrollram;
uint16_t m_page0_addr_lsb;
uint16_t m_page0_addr_msb;
@ -242,8 +215,7 @@ protected:
emu_timer *m_screenpos_timer;
uint16_t m_spriteram[0x400];
uint16_t m_spriteextra[0x400];
uint16_t m_spriteram[0x400*2];
uint16_t m_paletteram[0x100*0x10];
required_device<palette_device> m_palette;
@ -263,6 +235,10 @@ protected:
int m_alt_tile_addressing;
required_device<spg_renderer_device> m_renderer;
address_space* m_cpuspace;
address_space* m_cs_space;
int m_csbase;
};
class gcm394_video_device : public gcm394_base_video_device

View File

@ -103,6 +103,8 @@ uint32_t spg2xx_video_device::screen_update(screen_device &screen, bitmap_rgb32
const uint32_t page1_addr = 0x40 * m_video_regs[0x20];
const uint32_t page2_addr = 0x40 * m_video_regs[0x21];
const uint32_t sprite_addr = 0x40 * m_video_regs[0x22];
uint16_t *page1_scroll = m_video_regs + 0x10;
uint16_t *page2_scroll = m_video_regs + 0x16;
uint16_t *page1_regs = m_video_regs + 0x12;
@ -116,9 +118,9 @@ uint32_t spg2xx_video_device::screen_update(screen_device &screen, bitmap_rgb32
for (int i = 0; i < 4; i++)
{
m_renderer->draw_page(cliprect, dst, scanline, i, page1_addr, page1_scroll, page1_regs, mem, m_paletteram, m_scrollram);
m_renderer->draw_page(cliprect, dst, scanline, i, page2_addr, page2_scroll, page2_regs, mem, m_paletteram, m_scrollram);
m_renderer->draw_sprites(cliprect, dst, scanline, i, mem, m_paletteram, m_spriteram, m_sprlimit_read_cb());
m_renderer->draw_page(false, false, false, 0, cliprect, dst, scanline, i, page1_addr, page1_scroll, page1_regs, mem, m_paletteram, m_scrollram, 0);
m_renderer->draw_page(false, false, false, 0, cliprect, dst, scanline, i, page2_addr, page2_scroll, page2_regs, mem, m_paletteram, m_scrollram, 1);
m_renderer->draw_sprites(false, false, false, 0, false, cliprect, dst, scanline, i, sprite_addr, mem, m_paletteram, m_spriteram, m_sprlimit_read_cb());
}
m_renderer->apply_saturation_and_fade(bitmap, cliprect, scanline);
@ -177,7 +179,7 @@ READ16_MEMBER(spg2xx_video_device::video_r)
case 0x22: // Sprite Segment Address
LOGMASKED(LOG_PPU_READS, "video_r: Sprite Segment Address\n");
return m_renderer->get_video_reg_22();
return m_video_regs[offset];
case 0x2a: // Blend Level Control
LOGMASKED(LOG_PPU_READS, "video_r: Blend Level Control\n");
@ -334,7 +336,6 @@ WRITE16_MEMBER(spg2xx_video_device::video_w)
case 0x22: // Sprite Segment Address
LOGMASKED(LOG_PPU_WRITES, "video_w: Sprite Segment Address = %04x\n", data);
m_video_regs[offset] = data;
m_renderer->set_video_reg_22(data);
break;
case 0x2a: // Blend Level Control

View File

@ -7,7 +7,8 @@
DEFINE_DEVICE_TYPE(SPG_RENDERER, spg_renderer_device, "spg_renderer", "SunPlus / GeneralPlus video rendering")
spg_renderer_device::spg_renderer_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_t(mconfig, type, tag, owner, clock),
m_space_read_cb(*this)
{
}
@ -18,6 +19,8 @@ spg_renderer_device::spg_renderer_device(const machine_config &mconfig, const ch
void spg_renderer_device::device_start()
{
m_space_read_cb.resolve_safe(0);
for (uint8_t i = 0; i < 32; i++)
{
m_rgb5_to_rgb8[i] = (i << 3) | (i >> 2);
@ -33,7 +36,6 @@ void spg_renderer_device::device_start()
save_item(NAME(m_video_regs_1d));
save_item(NAME(m_video_regs_1e));
save_item(NAME(m_video_regs_22));
save_item(NAME(m_video_regs_2a));
save_item(NAME(m_video_regs_30));
@ -41,6 +43,8 @@ void spg_renderer_device::device_start()
save_item(NAME(m_video_regs_42));
save_item(NAME(m_video_regs_7f));
save_item(NAME(m_ycmp_table));
}
@ -50,7 +54,6 @@ void spg_renderer_device::device_reset()
m_video_regs_1d = 0x0000;
m_video_regs_1e = 0x0000;
m_video_regs_22 = 0x0000;
m_video_regs_2a = 0x0000;
m_video_regs_30 = 0x0000;
@ -58,6 +61,8 @@ void spg_renderer_device::device_reset()
m_video_regs_42 = 0x0001;
m_video_regs_7f = 0x0000;
for (int i = 0; i < 480; i++)
{
m_ycmp_table[i] = 0xffffffff;
@ -66,14 +71,13 @@ void spg_renderer_device::device_reset()
// Perform a lerp between a and b
inline uint8_t spg_renderer_device::mix_channel(uint8_t bottom, uint8_t top)
inline uint8_t spg_renderer_device::mix_channel(uint8_t bottom, uint8_t top, uint8_t alpha)
{
uint8_t alpha = (m_video_regs_2a & 3) << 6;
return ((256 - alpha) * bottom + alpha * top) >> 8;
}
template<spg_renderer_device::blend_enable_t Blend, spg_renderer_device::flipx_t FlipX>
void spg_renderer_device::draw_tilestrip(const rectangle& cliprect, uint32_t* dst, uint32_t tile_h, uint32_t tile_w, uint32_t tilegfxdata_addr, uint16_t tile, uint32_t tile_scanline, int drawx, bool flip_y, uint32_t palette_offset, const uint32_t nc_bpp, const uint32_t bits_per_row, const uint32_t words_per_tile, address_space &spc, uint16_t* paletteram)
void spg_renderer_device::draw_tilestrip(bool read_from_csspace, uint32_t screenwidth, uint32_t drawwidthmask, const rectangle& cliprect, uint32_t* dst, uint32_t tile_h, uint32_t tile_w, uint32_t tilegfxdata_addr, uint32_t tile, uint32_t tile_scanline, int drawx, bool flip_y, uint32_t palette_offset, const uint32_t nc_bpp, const uint32_t bits_per_row, const uint32_t words_per_tile, address_space &spc, uint16_t* paletteram, uint8_t blendlevel)
{
const uint32_t yflipmask = flip_y ? tile_h - 1 : 0;
uint32_t m = tilegfxdata_addr + words_per_tile * tile + bits_per_row * (tile_scanline ^ yflipmask);
@ -82,23 +86,44 @@ void spg_renderer_device::draw_tilestrip(const rectangle& cliprect, uint32_t* ds
for (int32_t x = FlipX ? (tile_w - 1) : 0; FlipX ? x >= 0 : x < tile_w; FlipX ? x-- : x++)
{
int realdrawpos = (drawx + x) & 0x1ff;
int realdrawpos = (drawx + x) & drawwidthmask;
bits <<= nc_bpp;
if (nbits < nc_bpp)
{
uint16_t b = spc.read_word(m++ & 0x3fffff);
b = (b << 8) | (b >> 8);
bits |= b << (nc_bpp - nbits);
nbits += 16;
if (!read_from_csspace)
{
uint16_t b = spc.read_word(m++ & 0x3fffff);
b = (b << 8) | (b >> 8);
bits |= b << (nc_bpp - nbits);
nbits += 16;
}
else
{
uint16_t b;
const int addr = m & 0x7ffffff;
if (addr < m_csbase)
{
b = m_cpuspace->read_word(addr);
}
else
{
b = m_cs_space->read_word(addr-m_csbase);
}
m++;
b = (b << 8) | (b >> 8);
bits |= b << (nc_bpp - nbits);
nbits += 16;
}
}
nbits -= nc_bpp;
uint32_t pal = palette_offset + (bits >> 16);
bits &= 0xffff;
if (realdrawpos >= 0 && realdrawpos < 320)
if (realdrawpos >= 0 && realdrawpos < screenwidth)
{
uint16_t rgb = paletteram[pal];
@ -106,9 +131,10 @@ void spg_renderer_device::draw_tilestrip(const rectangle& cliprect, uint32_t* ds
{
if (Blend)
{
dst[realdrawpos] = (mix_channel((uint8_t)(dst[realdrawpos] >> 16), m_rgb5_to_rgb8[(rgb >> 10) & 0x1f]) << 16) |
(mix_channel((uint8_t)(dst[realdrawpos] >> 8), m_rgb5_to_rgb8[(rgb >> 5) & 0x1f]) << 8) |
(mix_channel((uint8_t)(dst[realdrawpos] >> 0), m_rgb5_to_rgb8[rgb & 0x1f]));
dst[realdrawpos] = (mix_channel((uint8_t)(dst[realdrawpos] >> 16), m_rgb5_to_rgb8[(rgb >> 10) & 0x1f], blendlevel) << 16) |
(mix_channel((uint8_t)(dst[realdrawpos] >> 8), m_rgb5_to_rgb8[(rgb >> 5) & 0x1f], blendlevel) << 8) |
(mix_channel((uint8_t)(dst[realdrawpos] >> 0), m_rgb5_to_rgb8[(rgb >> 0) & 0x1f], blendlevel) << 0);
}
else
{
@ -120,122 +146,166 @@ void spg_renderer_device::draw_tilestrip(const rectangle& cliprect, uint32_t* ds
}
void spg_renderer_device::draw_linemap(const rectangle& cliprect, uint32_t* dst, uint32_t scanline, int priority, uint32_t tilegfxdata_addr, uint16_t* scrollregs, uint16_t* tilemapregs, address_space &spc, uint16_t* paletteram)
void spg_renderer_device::draw_linemap(bool has_extended_tilemaps, const rectangle& cliprect, uint32_t* dst, uint32_t scanline, int priority, uint32_t tilegfxdata_addr, uint16_t* scrollregs, uint16_t* tilemapregs, address_space &spc, uint16_t* paletteram)
{
if ((scanline < 0) || (scanline >= 240))
return;
uint32_t tilemap = tilemapregs[2];
uint32_t palette_map = tilemapregs[3];
//printf("draw bitmap bases %04x %04x\n", tilemap, palette_map);
//uint32_t xscroll = scrollregs[0];
uint32_t yscroll = scrollregs[1];
int realline = (scanline + yscroll) & 0xff;
uint16_t tile = spc.read_word(tilemap + realline);
uint16_t palette = 0;
//if (!tile)
// continue;
palette = spc.read_word(palette_map + realline / 2);
if (scanline & 1)
palette >>= 8;
else
palette &= 0x00ff;
//const int linewidth = 320 / 2;
int sourcebase = tile | (palette << 16);
uint32_t ctrl = tilemapregs[1];
if (ctrl & 0x80) // HiColor mode (rad_digi)
if (has_extended_tilemaps)
{
for (int i = 0; i < 320; i++)
uint32_t ctrl = tilemapregs[1];
if (0)
{
const uint16_t data = spc.read_word(sourcebase + i);
if (ctrl & 0x0010)
popmessage("bitmap mode %08x with rowscroll\n", tilegfxdata_addr);
else
popmessage("bitmap mode %08x\n", tilegfxdata_addr);
}
if (!(data & 0x8000))
// note, in interlace modes it appears every other line is unused? (480 entry table, but with blank values)
// and furthermore the rowscroll and rowzoom tables only have 240 entries, not enough for every line
// the end of the rowscroll table (entries 240-255) contain something else, maybe garbage data as it's offscreen, maybe not
uint32_t tilemap = tilemapregs[2];
uint32_t palette_map = tilemapregs[3];
uint32_t linebase = spc.read_word(tilemap + scanline); // every other word is unused, but there are only enough entries for 240 lines then, sometimes to do with interlace mode?
uint16_t palette = spc.read_word(palette_map + (scanline / 2));
if (scanline & 1)
palette >>= 8;
else
palette &= 0xff;
if (!linebase)
return;
linebase = linebase | (palette << 16);
// this logic works for jak_s500 and the test modes to get the correct base, doesn't seem to work for jak_car2 ingame, maybe data is copied to wrong place?
int gfxbase = (tilegfxdata_addr&0x7ffffff) + (linebase&0x7ffffff);
for (int i = 0; i < 160; i++) // will have to be 320 for jak_car2 ingame, jak_s500 lines are wider than screen, and zoomed
{
uint16_t pix;
const int addr = gfxbase & 0x7ffffff;
if (addr < m_csbase)
{
dst[i] = m_rgb555_to_rgb888[data & 0x7fff];
pix = m_cpuspace->read_word(addr);
}
else
{
pix = m_cs_space->read_word(addr-m_csbase);
}
gfxbase++;
int xx;
uint16_t pal;
if ((scanline >= 0) && (scanline < 480))
{
xx = i * 2;
pal = (pix & 0xff) | 0x100;
if (xx >= 0 && xx <= cliprect.max_x)
{
uint16_t rgb = paletteram[pal];
if (!(rgb & 0x8000))
{
dst[xx] = m_rgb555_to_rgb888[rgb];
}
}
xx = (i * 2)+1;
pal = (pix >> 8) + 0x100;
if (xx >= 0 && xx <= cliprect.max_x)
{
uint16_t rgb = paletteram[pal];
if (!(rgb & 0x8000))
{
dst[xx] = m_rgb555_to_rgb888[rgb];
}
}
}
}
}
else
else // code used for spg2xx cases
{
for (int i = 0; i < 320 / 2; i++)
{
uint8_t palette_entry;
uint16_t color;
const uint16_t data = spc.read_word(sourcebase + i);
if ((scanline < 0) || (scanline >= 240))
return;
palette_entry = (data & 0x00ff);
color = paletteram[palette_entry];
uint32_t tilemap = tilemapregs[2];
uint32_t palette_map = tilemapregs[3];
if (!(color & 0x8000))
{
dst[(i * 2) + 0] = m_rgb555_to_rgb888[color & 0x7fff];
}
popmessage("draw draw_linemap bases %04x %04x\n", tilemap, palette_map);
palette_entry = (data & 0xff00) >> 8;
color = paletteram[palette_entry];
//uint32_t xscroll = scrollregs[0];
uint32_t yscroll = scrollregs[1];
if (!(color & 0x8000))
{
dst[(i * 2) + 1] = m_rgb555_to_rgb888[color & 0x7fff];
}
}
}
}
int realline = (scanline + yscroll) & 0xff;
bool spg_renderer_device::get_tile_info(uint32_t tilemap_rambase, uint32_t palettemap_rambase, uint32_t x0, uint32_t y0, uint32_t tile_count_x, uint32_t ctrl, uint32_t attr, uint16_t& tile, spg_renderer_device::blend_enable_t& blend, spg_renderer_device::flipx_t& flip_x, bool& flip_y, uint32_t& palette_offset, address_space &spc)
{
uint32_t tile_address = x0 + (tile_count_x * y0);
uint32_t tile = spc.read_word(tilemap + realline);
uint16_t palette = 0;
tile = (ctrl & 0x0004) ? spc.read_word(tilemap_rambase) : spc.read_word(tilemap_rambase + tile_address);
//if (!tile)
// continue;
if (!tile)
return false;
uint32_t tileattr = attr;
uint32_t tilectrl = ctrl;
if ((ctrl & 2) == 0)
{ // -(1) bld(1) flip(2) pal(4)
uint16_t palette = (ctrl & 0x0004) ? spc.read_word(palettemap_rambase) : spc.read_word(palettemap_rambase + tile_address / 2);
if (x0 & 1)
palette = spc.read_word(palette_map + realline / 2);
if (scanline & 1)
palette >>= 8;
else
palette &= 0x00ff;
//const int linewidth = 320 / 2;
int sourcebase = tile | (palette << 16);
tileattr &= ~0x000c;
tileattr |= (palette >> 2) & 0x000c; // flip
uint32_t ctrl = tilemapregs[1];
tileattr &= ~0x0f00;
tileattr |= (palette << 8) & 0x0f00; // palette
if (ctrl & 0x80) // HiColor mode (rad_digi)
{
for (int i = 0; i < 320; i++)
{
const uint16_t data = spc.read_word(sourcebase + i);
tilectrl &= ~0x0100;
tilectrl |= (palette << 2) & 0x0100; // blend
if (!(data & 0x8000))
{
dst[i] = m_rgb555_to_rgb888[data & 0x7fff];
}
}
}
else
{
for (int i = 0; i < 320 / 2; i++)
{
uint8_t palette_entry;
uint16_t color;
const uint16_t data = spc.read_word(sourcebase + i);
palette_entry = (data & 0x00ff);
color = paletteram[palette_entry];
if (!(color & 0x8000))
{
dst[(i * 2) + 0] = m_rgb555_to_rgb888[color & 0x7fff];
}
palette_entry = (data & 0xff00) >> 8;
color = paletteram[palette_entry];
if (!(color & 0x8000))
{
dst[(i * 2) + 1] = m_rgb555_to_rgb888[color & 0x7fff];
}
}
}
}
blend = ((tileattr & 0x4000 || tilectrl & 0x0100)) ? BlendOn : BlendOff;
flip_x = (tileattr & 0x0004) ? FlipXOn : FlipXOff;
flip_y= (tileattr & 0x0008);
palette_offset = (tileattr & 0x0f00) >> 4;
return true;
}
// this builds up a line table for the vcmp effect, this is not correct when step is used
void spg_renderer_device::update_vcmp_table()
{
@ -257,7 +327,7 @@ void spg_renderer_device::update_vcmp_table()
}
else
{
if ((currentline >= 0) && (currentline < 240))
if ((currentline >= 0) && (currentline < 256))
{
m_ycmp_table[i] = currentline;
}
@ -275,33 +345,33 @@ void spg_renderer_device::update_vcmp_table()
}
}
void spg_renderer_device::draw_tilestrip(spg_renderer_device::blend_enable_t blend, spg_renderer_device::flipx_t flip_x, const rectangle& cliprect, uint32_t* dst, uint32_t tile_h, uint32_t tile_w, uint32_t tilegfxdata_addr, uint16_t tile, uint32_t tile_scanline, int drawx, bool flip_y, uint32_t palette_offset, const uint32_t nc_bpp, const uint32_t bits_per_row, const uint32_t words_per_tile, address_space& spc, uint16_t* paletteram)
void spg_renderer_device::draw_tilestrip(bool read_from_csspace, uint32_t screenwidth, uint32_t drawwidthmask, spg_renderer_device::blend_enable_t blend, spg_renderer_device::flipx_t flip_x, const rectangle& cliprect, uint32_t* dst, uint32_t tile_h, uint32_t tile_w, uint32_t tilegfxdata_addr, uint32_t tile, uint32_t tile_scanline, int drawx, bool flip_y, uint32_t palette_offset, const uint32_t nc_bpp, const uint32_t bits_per_row, const uint32_t words_per_tile, address_space& spc, uint16_t* paletteram, uint8_t blendlevel)
{
if (blend)
{
if (flip_x)
{
draw_tilestrip<BlendOn, FlipXOn>(cliprect, dst, tile_h, tile_w, tilegfxdata_addr, tile, tile_scanline, drawx, flip_y, palette_offset, nc_bpp, bits_per_row, words_per_tile, spc, paletteram);
draw_tilestrip<BlendOn, FlipXOn>(read_from_csspace, screenwidth, drawwidthmask, cliprect, dst, tile_h, tile_w, tilegfxdata_addr, tile, tile_scanline, drawx, flip_y, palette_offset, nc_bpp, bits_per_row, words_per_tile, spc, paletteram, blendlevel);
}
else
{
draw_tilestrip<BlendOn, FlipXOff>(cliprect, dst, tile_h, tile_w, tilegfxdata_addr, tile, tile_scanline, drawx, flip_y, palette_offset, nc_bpp, bits_per_row, words_per_tile, spc, paletteram);
draw_tilestrip<BlendOn, FlipXOff>(read_from_csspace, screenwidth, drawwidthmask, cliprect, dst, tile_h, tile_w, tilegfxdata_addr, tile, tile_scanline, drawx, flip_y, palette_offset, nc_bpp, bits_per_row, words_per_tile, spc, paletteram, blendlevel);
}
}
else
{
if (flip_x)
{
draw_tilestrip<BlendOff, FlipXOn>(cliprect, dst, tile_h, tile_w, tilegfxdata_addr, tile, tile_scanline, drawx, flip_y, palette_offset, nc_bpp, bits_per_row, words_per_tile, spc, paletteram);
draw_tilestrip<BlendOff, FlipXOn>(read_from_csspace, screenwidth, drawwidthmask, cliprect, dst, tile_h, tile_w, tilegfxdata_addr, tile, tile_scanline, drawx, flip_y, palette_offset, nc_bpp, bits_per_row, words_per_tile, spc, paletteram, blendlevel);
}
else
{
draw_tilestrip<BlendOff, FlipXOff>(cliprect, dst, tile_h, tile_w, tilegfxdata_addr, tile, tile_scanline, drawx, flip_y, palette_offset, nc_bpp, bits_per_row, words_per_tile, spc, paletteram);
draw_tilestrip<BlendOff, FlipXOff>(read_from_csspace, screenwidth, drawwidthmask, cliprect, dst, tile_h, tile_w, tilegfxdata_addr, tile, tile_scanline, drawx, flip_y, palette_offset, nc_bpp, bits_per_row, words_per_tile, spc, paletteram, blendlevel);
}
}
}
void spg_renderer_device::draw_page(const rectangle& cliprect, uint32_t* dst, uint32_t scanline, int priority, uint32_t tilegfxdata_addr, uint16_t* scrollregs, uint16_t* tilemapregs, address_space& spc, uint16_t* paletteram, uint16_t* scrollram)
void spg_renderer_device::draw_page(bool read_from_csspace, bool has_extended_tilemaps, bool use_alt_tile_addressing, uint32_t palbank, const rectangle& cliprect, uint32_t* dst, uint32_t scanline, int priority, uint32_t tilegfxdata_addr, uint16_t* scrollregs, uint16_t* tilemapregs, address_space& spc, uint16_t* paletteram, uint16_t* scrollram, uint32_t which)
{
const uint32_t attr = tilemapregs[0];
const uint32_t ctrl = tilemapregs[1];
@ -318,7 +388,7 @@ void spg_renderer_device::draw_page(const rectangle& cliprect, uint32_t* dst, ui
if (ctrl & 0x0001) // Bitmap / Linemap mode! (basically screen width tile mode)
{
draw_linemap(cliprect, dst, scanline, priority, tilegfxdata_addr, scrollregs, tilemapregs, spc, paletteram);
draw_linemap(has_extended_tilemaps, cliprect, dst, scanline, priority, tilegfxdata_addr, scrollregs, tilemapregs, spc, paletteram);
return;
}
@ -328,61 +398,186 @@ void spg_renderer_device::draw_page(const rectangle& cliprect, uint32_t* dst, ui
{
if (m_video_regs_1e != 0x0000)
popmessage("vertical compression mode with non-0 step amount %04x offset %04x step %04x\n", m_video_regs_1c, m_video_regs_1d, m_video_regs_1e);
logical_scanline = m_ycmp_table[scanline];
if (logical_scanline == 0xffffffff)
return;
}
uint32_t total_width;
uint32_t y_mask;
uint32_t screenwidth;
uint32_t drawwidthmask;
if (read_from_csspace && ((attr >> 15) & 0x1))
{
// just a guess based on this being set on the higher resolution tilemaps we've seen, could be 100% incorrect register
total_width = 1024;
y_mask = 0x1ff;
screenwidth = 640;
drawwidthmask = 0x400 - 1;
}
else
{
total_width = 512;
y_mask = 0xff;
screenwidth = 320;
drawwidthmask = 0x200 - 1;
}
const uint32_t xscroll = scrollregs[0];
const uint32_t yscroll = scrollregs[1];
const uint32_t tilemap_rambase = tilemapregs[2];
const uint32_t palettemap_rambase = tilemapregs[3];
const uint32_t exattributemap_rambase = tilemapregs[3];
const int tile_width = (attr & 0x0030) >> 4;
const uint32_t tile_h = 8 << ((attr & 0x00c0) >> 6);
const uint32_t tile_w = 8 << (tile_width);
const uint32_t tile_count_x = 512 / tile_w; // all tilemaps are 512 pixels wide
const uint32_t bitmap_y = (logical_scanline + yscroll) & 0xff; // all tilemaps are 256 pixels high
const uint32_t tile_count_x = total_width / tile_w; // tilemaps are 512 or 1024 wide depending on screen mode?
const uint32_t bitmap_y = (logical_scanline + yscroll) & y_mask; // tilemaps are 256 or 512 high depending on screen mode?
const uint32_t y0 = bitmap_y / tile_h;
const uint32_t tile_scanline = bitmap_y % tile_h;
const uint8_t bpp = attr & 0x0003;
const uint32_t nc_bpp = ((bpp)+1) << 1;
const uint32_t bits_per_row = nc_bpp * tile_w / 16;
const uint32_t words_per_tile = bits_per_row * tile_h;
//const uint32_t words_per_tile = bits_per_row * tile_h;
const bool row_scroll = (ctrl & 0x0010);
uint8_t blendlevel = (m_video_regs_2a & 3) << 6;
uint32_t words_per_tile;
// good for gormiti, smartfp, wrlshunt, paccon, jak_totm, jak_s500, jak_gtg
if (has_extended_tilemaps && use_alt_tile_addressing)
{
words_per_tile = 8;
}
else
{
words_per_tile = bits_per_row * tile_h;
}
int realxscroll = xscroll;
if (row_scroll)
{
// Tennis in My Wireless Sports confirms the need to add the scroll value here rather than rowscroll being screen-aligned
realxscroll += (int16_t)scrollram[(logical_scanline+yscroll) & 0xff];
realxscroll += (int16_t)scrollram[(logical_scanline + yscroll) & 0xff];
}
const int upperscrollbits = (realxscroll >> (tile_width + 3));
const int endpos = (320 + tile_w) / tile_w;
const int endpos = (screenwidth + tile_w) / tile_w;
for (uint32_t x0 = 0; x0 < endpos; x0++)
{
spg_renderer_device::blend_enable_t blend;
spg_renderer_device::flipx_t flip_x;
bool flip_y;
uint16_t tile;
uint32_t tile;
uint32_t palette_offset;
if (!get_tile_info(tilemap_rambase, palettemap_rambase, (x0 + upperscrollbits) & (tile_count_x-1) , y0, tile_count_x, ctrl, attr, tile, blend, flip_x, flip_y, palette_offset, spc))
// get tile info
const int realx0 = (x0 + upperscrollbits) & (tile_count_x - 1);
uint32_t tile_address = realx0 + (tile_count_x * y0);
tile = (ctrl & 0x0004) ? spc.read_word(tilemap_rambase) : spc.read_word(tilemap_rambase + tile_address);
if (!tile)
continue;
uint32_t tileattr = attr;
uint32_t tilectrl = ctrl;
if (has_extended_tilemaps && use_alt_tile_addressing)
{
// in this mode what would be the 'palette' bits get used for extra tile bits (even if the usual 'extended table' mode is disabled?)
// used by smartfp
uint16_t exattribute = (ctrl & 0x0004) ? spc.read_word(exattributemap_rambase) : spc.read_word(exattributemap_rambase + tile_address / 2);
if (realx0 & 1)
exattribute >>= 8;
else
exattribute &= 0x00ff;
tile |= (exattribute & 0x07) << 16;
//blendlevel = 0x1f; // hack
}
else if ((ctrl & 2) == 0)
{ // -(1) bld(1) flip(2) pal(4)
uint16_t exattribute = (ctrl & 0x0004) ? spc.read_word(exattributemap_rambase) : spc.read_word(exattributemap_rambase + tile_address / 2);
if (realx0 & 1)
exattribute >>= 8;
else
exattribute &= 0x00ff;
tileattr &= ~0x000c;
tileattr |= (exattribute >> 2) & 0x000c; // flip
tileattr &= ~0x0f00;
tileattr |= (exattribute << 8) & 0x0f00; // palette
tilectrl &= ~0x0100;
tilectrl |= (exattribute << 2) & 0x0100; // blend
}
blend = ((tileattr & 0x4000 || tilectrl & 0x0100)) ? BlendOn : BlendOff;
flip_x = (tileattr & 0x0004) ? FlipXOn : FlipXOff;
flip_y = (tileattr & 0x0008);
palette_offset = (tileattr & 0x0f00) >> 4;
// got tile info
if (1)
{
// HACKS
// There must be a select bit for the tilemap palettes somewhere, but where?!
// the different games in paccon also expect a variety of different configs here, maybe a good place to look
if (palbank & 1) // this actually seems to be the sprite palette bank enable, but for myac220 / tkmag220 (where everything is from a single palette) it gives us an easy way to ignore the logic below
{
if (which == 0) // tilemap 0
{
if (ctrl & 0x0002) // RegSet:1
{
// smartfp has a conflict between the bootlogos and the first screen, it's in regset mode, no obvious difference in registers but needs palette from different places?
// not even m_video_regs_7f changes here, which makes the m_video_regs_7f case specific hacks for jak_s500 below very unlikely to actually be related
if ((bpp + 1) * 2 == 4)
if (use_alt_tile_addressing == true)
palette_offset |= 0x200;
}
}
if (which == 1)
{
// can't do this for jak_s500 logos
// jak_s500 also uses this tilemap in both 4 and 6bpp modes expecting the same palette base, so the hack used for smartfp on tilemap 0 is not applicable here
// m_video_regs_7f != 0x2d3 for jak_S500 main menu
if ((m_video_regs_7f != 0x53) && (m_video_regs_7f != 0x63) && (m_video_regs_7f != 0x2d3))
palette_offset |= 0x200;
}
// jak_car2 screen transitions use layers 2 and 3 the same way, alternating each frame
if (which == 2)
{
// jak_s500 title screen + loading screen before race
if ((m_video_regs_7f == 0x2d3) || (m_video_regs_7f == 0x2db))
palette_offset |= 0x200;
}
}
}
palette_offset >>= nc_bpp;
palette_offset <<= nc_bpp;
const int drawx = (x0 * tile_w) - (realxscroll & (tile_w-1));
draw_tilestrip(blend,flip_x, cliprect, dst, tile_h, tile_w, tilegfxdata_addr, tile, tile_scanline, drawx, flip_y, palette_offset, nc_bpp, bits_per_row, words_per_tile, spc, paletteram);
const int drawx = (x0 * tile_w) - (realxscroll & (tile_w - 1));
draw_tilestrip(read_from_csspace, screenwidth, drawwidthmask, blend, flip_x, cliprect, dst, tile_h, tile_w, tilegfxdata_addr, tile, tile_scanline, drawx, flip_y, palette_offset, nc_bpp, bits_per_row, words_per_tile, spc, paletteram, blendlevel);
}
}
void spg_renderer_device::draw_sprite(const rectangle& cliprect, uint32_t* dst, uint32_t scanline, int priority, uint32_t base_addr, address_space &spc, uint16_t* paletteram, uint16_t* spriteram)
void spg_renderer_device::draw_sprite(bool read_from_csspace, bool has_extended_sprites, bool alt_extrasprite_hack, uint32_t palbank, bool highres, const rectangle& cliprect, uint32_t* dst, uint32_t scanline, int priority, uint32_t spritegfxdata_addr, uint32_t base_addr, address_space &spc, uint16_t* paletteram, uint16_t* spriteram)
{
uint32_t tilegfxdata_addr = 0x40 * m_video_regs_22;
uint16_t tile = spriteram[base_addr + 0];
uint32_t tilegfxdata_addr = spritegfxdata_addr;
uint32_t tile = spriteram[base_addr + 0];
int16_t x = spriteram[base_addr + 1];
int16_t y = spriteram[base_addr + 2];
uint16_t attr = spriteram[base_addr + 3];
@ -397,44 +592,108 @@ void spg_renderer_device::draw_sprite(const rectangle& cliprect, uint32_t* dst,
return;
}
uint32_t screenwidth = 320;
// uint32_t screenheight = 240;
uint32_t screenheight = 256;
uint32_t xmask = 0x1ff;
uint32_t ymask = 0x1ff;
if (highres)
{
screenwidth = 640;
// screenheight = 480;
screenheight = 512;
xmask = 0x3ff;
}
const uint32_t tile_h = 8 << ((attr & 0x00c0) >> 6);
const uint32_t tile_w = 8 << ((attr & 0x0030) >> 4);
if (!(m_video_regs_42 & 0x0002))
{
x = (160 + x) - tile_w / 2;
y = (120 - y) - (tile_h / 2) + 8;
x = ((screenwidth/2) + x) - tile_w / 2;
// y = ((screenheight/2) - y) - (tile_h / 2) + 8;
y = ((screenheight/2) - y) - (tile_h / 2);
}
x &= 0x01ff;
y &= 0x01ff;
x &= xmask;
y &= ymask;
int firstline = y;
int lastline = y + (tile_h - 1);
lastline &= 0x1ff;
lastline &= ymask;
const spg_renderer_device::blend_enable_t blend = (attr & 0x4000) ? BlendOn : BlendOff;
const spg_renderer_device::flipx_t flip_x = (attr & 0x0004) ? FlipXOn : FlipXOff;
spg_renderer_device::flipx_t flip_x = (attr & 0x0004) ? FlipXOn : FlipXOff;
const uint8_t bpp = attr & 0x0003;
const uint32_t nc_bpp = ((bpp)+1) << 1;
const uint32_t bits_per_row = nc_bpp * tile_w / 16;
const uint32_t words_per_tile = bits_per_row * tile_h;
uint8_t blendlevel = (m_video_regs_2a & 3) << 6;
uint32_t words_per_tile;
// good for gormiti, smartfp, wrlshunt, paccon, jak_totm, jak_s500, jak_gtg
if (has_extended_sprites && ((m_video_regs_42 & 0x0010) == 0x10))
{
// paccon and smartfp use this mode
words_per_tile = 8;
if (!alt_extrasprite_hack) // 1 extra word for each sprite
{
// before or after the 0 tile check?
tile |= (spriteram[(base_addr / 4) + 0x400] & 0x01ff) << 16;
blendlevel = ((spriteram[(base_addr / 4) + 0x400] & 0x3e00) >> 9) << 3;
}
else // jak_prft - no /4 to offset in this mode - 4 extra words per sprite instead ? (or is RAM content incorrect for one of these cases?)
{
tile |= spriteram[(base_addr) + 0x400] << 16;
blendlevel = ((spriteram[(base_addr) + 0x400] & 0x3e00) >> 9) << 3;
}
}
else
{
words_per_tile = bits_per_row * tile_h;
}
bool flip_y = (attr & 0x0008);
// various games don't want the flip bits in the usual place, wrlshunt for example, there's probably a bit to control this
// and likewise these bits probably now have a different meaning, so this shouldn't be trusted
if (has_extended_sprites)
{
if (highres || alt_extrasprite_hack)
{
flip_x = FlipXOff;
flip_y = 0;
}
}
uint32_t palette_offset = (attr & 0x0f00) >> 4;
if (has_extended_sprites)
{
// guess, tkmag220 / myac220 don't set this bit and expect all sprite palettes to be from the same bank as background palettes
if (palbank & 1)
palette_offset |= 0x100;
// many other gpl16250 sets have this bit set when they want the upper 256 colours on a per-sprite basis, seems like an extended feature
if (attr & 0x8000)
palette_offset |= 0x200;
}
// the Circuit Racing game in PDC100 needs this or some graphics have bad colours at the edges when turning as it leaves stray lower bits set
palette_offset >>= nc_bpp;
palette_offset <<= nc_bpp;
if (firstline < lastline)
{
int scanx = scanline - firstline;
if ((scanx >= 0) && (scanline <= lastline))
{
draw_tilestrip(blend, flip_x, cliprect, dst, tile_h, tile_w, tilegfxdata_addr, tile, scanx, x, flip_y, palette_offset, nc_bpp, bits_per_row, words_per_tile, spc, paletteram);
draw_tilestrip(read_from_csspace, screenwidth, xmask, blend, flip_x, cliprect, dst, tile_h, tile_w, tilegfxdata_addr, tile, scanx, x, flip_y, palette_offset, nc_bpp, bits_per_row, words_per_tile, spc, paletteram, blendlevel);
}
}
else
@ -446,7 +705,7 @@ void spg_renderer_device::draw_sprite(const rectangle& cliprect, uint32_t* dst,
if ((scanx >= 0) && (scanline <= templastline))
{
draw_tilestrip(blend, flip_x, cliprect, dst, tile_h, tile_w, tilegfxdata_addr, tile, scanx, x, flip_y, palette_offset, nc_bpp, bits_per_row, words_per_tile, spc, paletteram);
draw_tilestrip(read_from_csspace, screenwidth, xmask, blend, flip_x, cliprect, dst, tile_h, tile_w, tilegfxdata_addr, tile, scanx, x, flip_y, palette_offset, nc_bpp, bits_per_row, words_per_tile, spc, paletteram, blendlevel);
}
// clipped against the bottom
tempfirstline = firstline;
@ -455,21 +714,29 @@ void spg_renderer_device::draw_sprite(const rectangle& cliprect, uint32_t* dst,
if ((scanx >= 0) && (scanline <= templastline))
{
draw_tilestrip(blend, flip_x, cliprect, dst, tile_h, tile_w, tilegfxdata_addr, tile, scanx, x, flip_y, palette_offset, nc_bpp, bits_per_row, words_per_tile, spc, paletteram);
draw_tilestrip(read_from_csspace, screenwidth, xmask, blend, flip_x, cliprect, dst, tile_h, tile_w, tilegfxdata_addr, tile, scanx, x, flip_y, palette_offset, nc_bpp, bits_per_row, words_per_tile, spc, paletteram, blendlevel);
}
}
}
void spg_renderer_device::draw_sprites(const rectangle &cliprect, uint32_t* dst, uint32_t scanline, int priority, address_space &spc, uint16_t* paletteram, uint16_t* spriteram, int sprlimit)
void spg_renderer_device::draw_sprites(bool read_from_csspace, bool has_extended_sprites, bool alt_extrasprite_hack, uint32_t palbank, bool highres, const rectangle &cliprect, uint32_t* dst, uint32_t scanline, int priority, uint32_t spritegfxdata_addr, address_space &spc, uint16_t* paletteram, uint16_t* spriteram, int sprlimit)
{
if (!(m_video_regs_42 & 0x0001))
{
return;
}
// paccon suggests this, does older hardware have similar (if so, starting at what point?) or only GPL16250?
if (sprlimit == -1)
{
sprlimit = (m_video_regs_42 & 0xff00) >> 8;
if (sprlimit == 0)
sprlimit = 0x100;
}
for (uint32_t n = 0; n < sprlimit; n++)
{
draw_sprite(cliprect, dst, scanline, priority, 4 * n, spc, paletteram, spriteram);
draw_sprite(read_from_csspace, has_extended_sprites, alt_extrasprite_hack, palbank, highres, cliprect, dst, scanline, priority, spritegfxdata_addr, 4 * n, spc, paletteram, spriteram);
}
}

View File

@ -14,14 +14,14 @@ public:
spg_renderer_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock);
spg_renderer_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
void draw_sprites(const rectangle& cliprect, uint32_t* dst, uint32_t scanline, int priority, address_space& spc, uint16_t* paletteram, uint16_t* spriteram, int sprlimit);
void draw_page(const rectangle& cliprect, uint32_t* dst, uint32_t scanline, int priority, uint32_t tilegfxdata_addr, uint16_t* scrollregs, uint16_t* tilemapregs, address_space& spc, uint16_t* paletteram, uint16_t* scrollram);
void draw_sprites(bool read_from_csspace, bool has_extended_sprites, bool alt_extrasprite_hack, uint32_t palbank, bool highres, const rectangle& cliprect, uint32_t* dst, uint32_t scanline, int priority, uint32_t spritegfxdata_addr, address_space& spc, uint16_t* paletteram, uint16_t* spriteram, int sprlimit);
void draw_page(bool read_from_csspace, bool has_extended_tilemaps, bool use_alt_tile_addressing, uint32_t palbank, const rectangle& cliprect, uint32_t* dst, uint32_t scanline, int priority, uint32_t tilegfxdata_addr, uint16_t* scrollregs, uint16_t* tilemapregs, address_space& spc, uint16_t* paletteram, uint16_t* scrollram, uint32_t which);
void apply_saturation_and_fade(bitmap_rgb32& bitmap, const rectangle& cliprect, int scanline);
void set_video_reg_1c(uint16_t val) { m_video_regs_1c = val; update_vcmp_table(); }
void set_video_reg_1d(uint16_t val) { m_video_regs_1d = val; update_vcmp_table(); }
void set_video_reg_1e(uint16_t val) { m_video_regs_1e = val; update_vcmp_table(); }
void set_video_reg_22(uint16_t val) { m_video_regs_22 = val; }
void set_video_reg_2a(uint16_t val) { m_video_regs_2a = val; }
void set_video_reg_30(uint16_t val) { m_video_regs_30 = val; }
void set_video_reg_3c(uint16_t val) { m_video_regs_3c = val; }
@ -30,12 +30,18 @@ public:
uint16_t get_video_reg_1c(void) { return m_video_regs_1c; }
uint16_t get_video_reg_1d(void) { return m_video_regs_1d; }
uint16_t get_video_reg_1e(void) { return m_video_regs_1e; }
uint16_t get_video_reg_22(void) { return m_video_regs_22; }
uint16_t get_video_reg_2a(void) { return m_video_regs_2a; }
uint16_t get_video_reg_30(void) { return m_video_regs_30; }
uint16_t get_video_reg_3c(void) { return m_video_regs_3c; }
uint16_t get_video_reg_42(void) { return m_video_regs_42; }
// used by some hack logic for the gpl16250 rendering for now
void set_video_reg_7f(uint16_t val) { m_video_regs_7f = val; }
uint16_t get_video_reg_7f(void) { return m_video_regs_7f; }
auto space_read_callback() { return m_space_read_cb.bind(); }
void set_video_spaces(address_space* cpuspace, address_space* cs_space, int csbase) { m_cpuspace = cpuspace; m_cs_space = cs_space; m_csbase = csbase; }
protected:
virtual void device_start() override;
@ -54,22 +60,21 @@ protected:
};
template<spg_renderer_device::blend_enable_t Blend, spg_renderer_device::flipx_t FlipX>
inline void draw_tilestrip(const rectangle& cliprect, uint32_t* dst, uint32_t tile_h, uint32_t tile_w, uint32_t tilegfxdata_addr, uint16_t tile, uint32_t tile_scanline, int drawx, bool flip_y, uint32_t palette_offset, const uint32_t nc_bpp, const uint32_t bits_per_row, const uint32_t words_per_tile, address_space &spc, uint16_t* palette);
inline void draw_tilestrip(bool read_from_csspace, uint32_t screenwidth, uint32_t drawwidthmask, const rectangle& cliprect, uint32_t* dst, uint32_t tile_h, uint32_t tile_w, uint32_t tilegfxdata_addr, uint32_t tile, uint32_t tile_scanline, int drawx, bool flip_y, uint32_t palette_offset, const uint32_t nc_bpp, const uint32_t bits_per_row, const uint32_t words_per_tile, address_space &spc, uint16_t* palette, uint8_t blendlevel);
inline void draw_tilestrip(spg_renderer_device::blend_enable_t blend, spg_renderer_device::flipx_t flip_x, const rectangle& cliprect, uint32_t* dst, uint32_t tile_h, uint32_t tile_w, uint32_t tilegfxdata_addr, uint16_t tile, uint32_t tile_scanline, int drawx, bool flip_y, uint32_t palette_offset, const uint32_t nc_bpp, const uint32_t bits_per_row, const uint32_t words_per_tile, address_space& spc, uint16_t* paletteram);
inline void draw_tilestrip(bool read_from_csspace, uint32_t screenwidth, uint32_t drawwidthmask, spg_renderer_device::blend_enable_t blend, spg_renderer_device::flipx_t flip_x, const rectangle& cliprect, uint32_t* dst, uint32_t tile_h, uint32_t tile_w, uint32_t tilegfxdata_addr, uint32_t tile, uint32_t tile_scanline, int drawx, bool flip_y, uint32_t palette_offset, const uint32_t nc_bpp, const uint32_t bits_per_row, const uint32_t words_per_tile, address_space& spc, uint16_t* paletteram, uint8_t blendlevel);
void draw_sprite(const rectangle& cliprect, uint32_t* dst, uint32_t scanline, int priority, uint32_t base_addr, address_space& spc, uint16_t* paletteram, uint16_t* spriteram);
inline void draw_sprite(bool read_from_csspace, bool has_extended_sprites, bool alt_extrasprite_hack, uint32_t palbank, bool highres, const rectangle& cliprect, uint32_t* dst, uint32_t scanline, int priority, uint32_t spritegfxdata_addr, uint32_t base_addr, address_space& spc, uint16_t* paletteram, uint16_t* spriteram);
inline bool get_tile_info(uint32_t tilemap_rambase, uint32_t palettemap_rambase, uint32_t x0, uint32_t y0, uint32_t tile_count_x, uint32_t ctrl, uint32_t attr, uint16_t& tile, spg_renderer_device::blend_enable_t& blend, spg_renderer_device::flipx_t& flip_x, bool& flip_y, uint32_t& palette_offset, address_space& spc);
inline void draw_linemap(const rectangle& cliprect, uint32_t* dst, uint32_t scanline, int priority, uint32_t tilegfxdata_addr, uint16_t* scrollregs, uint16_t* tilemapregs, address_space& spc, uint16_t* paletteram);
inline void draw_linemap(bool has_extended_tilemaps, const rectangle& cliprect, uint32_t* dst, uint32_t scanline, int priority, uint32_t tilegfxdata_addr, uint16_t* scrollregs, uint16_t* tilemapregs, address_space& spc, uint16_t* paletteram);
uint8_t mix_channel(uint8_t a, uint8_t b);
inline uint8_t mix_channel(uint8_t a, uint8_t b, uint8_t alpha);
uint8_t m_rgb5_to_rgb8[32];
uint32_t m_rgb555_to_rgb888[0x8000];
private:
void update_vcmp_table();
uint16_t m_video_regs_1c;
@ -77,14 +82,20 @@ private:
uint16_t m_video_regs_1e;
uint16_t m_video_regs_2a;
uint16_t m_video_regs_22;
uint16_t m_video_regs_42;
uint16_t m_video_regs_30;
uint16_t m_video_regs_3c;
uint16_t m_video_regs_7f;
uint32_t m_ycmp_table[480];
devcb_read16 m_space_read_cb;
address_space* m_cpuspace;
address_space* m_cs_space;
int m_csbase;
};
DECLARE_DEVICE_TYPE(SPG_RENDERER, spg_renderer_device)