nec/pc88va_v.cpp: add display start address, fix bobs display in shinraba, add offset base for split graphics

nec/pc88va_sgp.cpp: handle source negative pitches, avoid out of bounds accesses in rtype
This commit is contained in:
angelosa 2025-03-15 17:15:52 +01:00
parent 6af5a7a8dd
commit 02f860e3e5
6 changed files with 83 additions and 45 deletions

View File

@ -581,6 +581,8 @@ Omake: if sound irqs don't run then needs to press key 0 pad to move on
]]></notes>
<info name="alt_title" value="神羅万象"/>
<info name="usage" value="Hold enter at boot to skip intro, press F2 on title screen to load a game, press F5 for sound test" />
<!-- baddump: non-factory save -->
<part name="flop1" interface="floppy_5_25">
<feature name="part_id" value="Disk A" />
<dataarea name="flop" size="1331888">
@ -591,7 +593,7 @@ Omake: if sound irqs don't run then needs to press key 0 pad to move on
<part name="flop2" interface="floppy_5_25">
<feature name="part_id" value="Disk B" />
<dataarea name="flop" size="1296112">
<rom name="shinra bansho(diskb) (nihon telenet).d88" size="1296112" crc="1ee8acdf" sha1="4e0cab59ec6707f848b28b056040be835e2357ed"/>
<rom name="shinra bansho(diskb) (nihon telenet).d88" size="1296112" crc="1ee8acdf" sha1="4e0cab59ec6707f848b28b056040be835e2357ed" status="baddump" />
</dataarea>
</part>
</software>

View File

@ -44,7 +44,7 @@ TODO:
- Support for PC8801 compatible mode & PC80S31K (floppy interface);
Notes:
- hold F8 at POST to bring software dip settings menu
- hold F8 at POST to bring software dip settings menu, F5 to cycle between pages;
- PC-88VA-91 is a ROM upgrade kit for a PC-88VA -> VA2/VA3.
Has four roms, marked by VAEG as VUROM00.ROM, VUROM08.ROM, VUROM1.ROM, VUDIC.ROM.
@ -632,7 +632,7 @@ void pc88va_state::io_map(address_map &map)
// map(0x0124, 0x0125) ? (related to Transparent Color of Graphic Screen 0)
// map(0x0126, 0x0127) ? (related to Transparent Color of Graphic Screen 1)
map(0x012e, 0x012f).w(FUNC(pc88va_state::text_transpen_w));
// map(0x0130, 0x0137) Picture Mask Parameter (global cliprect, olteus gameplay)
map(0x0130, 0x0137).w(FUNC(pc88va_state::picture_mask_w));
map(0x0142, 0x0142).rw(FUNC(pc88va_state::idp_status_r), FUNC(pc88va_state::idp_command_w)); //Text Controller (IDP) - (R) Status (W) command
map(0x0146, 0x0146).w(FUNC(pc88va_state::idp_param_w)); //Text Controller (IDP) - (R/W) Parameter
map(0x0148, 0x0148).w(FUNC(pc88va_state::text_control_1_w));

View File

@ -232,6 +232,11 @@ private:
u8 rop[2];
} m_singleplane;
struct {
u16 top, bottom;
u16 left, right;
} m_picture_mask;
u8 rop_execute(u8 plane_rop, u8 src, u8 dst, u8 pat);
u8 gvram_singleplane_r(offs_t offset);
void gvram_singleplane_w(offs_t offset, u8 data);
@ -247,6 +252,7 @@ private:
void color_mode_w(offs_t offset, u16 data, u16 mem_mask = ~0);
void text_transpen_w(offs_t offset, u16 data, u16 mem_mask = ~0);
void text_control_1_w(u8 data);
void picture_mask_w(offs_t offset, u16 data, u16 mem_mask = ~0);
u8 m_kanji_cg_line = 0;
u8 m_kanji_cg_jis[2]{};
@ -263,12 +269,12 @@ private:
void draw_graphic_layer(bitmap_rgb32 &bitmap, const rectangle &cliprect, u8 which);
void draw_indexed_gfx_1bpp(bitmap_rgb32 &bitmap, const rectangle &cliprect, u32 fb_start_offset, u8 pal_base);
void draw_indexed_gfx_4bpp(bitmap_rgb32 &bitmap, const rectangle &cliprect, u32 fb_start_offset, u32 display_start_offset, u8 pal_base, u16 fb_width, u16 fb_height);
void draw_direct_gfx_8bpp(bitmap_rgb32 &bitmap, const rectangle &cliprect, u32 fb_start_offset, u32 display_start_offset, u16 fb_width, u16 fb_height);
void draw_direct_gfx_rgb565(bitmap_rgb32 &bitmap, const rectangle &cliprect, u32 fb_start_offset, u16 fb_width, u16 fb_height);
void draw_indexed_gfx_4bpp(bitmap_rgb32 &bitmap, const rectangle &cliprect, u32 fb_start_offset, u32 display_start_offset, u16 dsp_start_base, u16 scrollx, u8 pal_base, u16 fb_width, u16 fb_height);
void draw_direct_gfx_8bpp(bitmap_rgb32 &bitmap, const rectangle &cliprect, u32 fb_start_offset, u32 display_start_offset, u16 dsp_start_base, u16 scrollx, u16 fb_width, u16 fb_height);
void draw_direct_gfx_rgb565(bitmap_rgb32 &bitmap, const rectangle &cliprect, u32 fb_start_offset, u32 display_start_offset, u16 scrollx, u16 fb_width, u16 fb_height);
void draw_packed_gfx_4bpp(bitmap_rgb32 &bitmap, const rectangle &cliprect, u32 fb_start_offset, u32 display_start_offset, u8 pal_base, u16 fb_width, u16 fb_height);
void draw_packed_gfx_5bpp(bitmap_rgb32 &bitmap, const rectangle &cliprect, u32 fb_start_offset, u32 display_start_offset, u8 pal_base, u16 fb_width, u16 fb_height);
void draw_packed_gfx_4bpp(bitmap_rgb32 &bitmap, const rectangle &cliprect, u32 fb_start_offset, u32 display_start_offset, u16 scrollx, u8 pal_base, u16 fb_width, u16 fb_height);
void draw_packed_gfx_5bpp(bitmap_rgb32 &bitmap, const rectangle &cliprect, u32 fb_start_offset, u32 display_start_offset, u16 dsp_start_base, u16 scrollx, u8 pal_base, u16 fb_width, u16 fb_height);
uint32_t calc_kanji_rom_addr(uint8_t jis1,uint8_t jis2,int x,int y);
void draw_text(bitmap_rgb32 &bitmap, const rectangle &cliprect);

View File

@ -190,11 +190,11 @@ void pc88va_sgp_device::start_exec()
ptr->hsize = m_data->read_word(vdp_pointer + 4) & 0x0fff;
ptr->vsize = m_data->read_word(vdp_pointer + 6) & 0x0fff;
// NOTE: & 0xfffc causes pitch issues in boomer intro/title text, shinraba gameplay
ptr->fb_pitch = m_data->read_word(vdp_pointer + 8) & 0xfffe;
ptr->fb_pitch = (s16)(m_data->read_word(vdp_pointer + 8) & 0xfffe);
ptr->address = (m_data->read_word(vdp_pointer + 10) & 0xfffe)
| (m_data->read_word(vdp_pointer + 12) << 16);
LOGCOMMAND("SGP: (PC=%08x) SET %s %02x|H %4u|V %4u|Pitch %5u| address %08x\n"
LOGCOMMAND("SGP: (PC=%08x) SET %s %02x|H %4u|V %4u|Pitch %5d| address %08x\n"
, vdp_pointer
, mode ? "DESTINATION" : "SOURCE "
, param1
@ -246,7 +246,7 @@ void pc88va_sgp_device::start_exec()
// in pixels
const u16 h_size = m_data->read_word(vdp_pointer + 6);
const u16 v_size = m_data->read_word(vdp_pointer + 8);
const u16 fb_pitch = m_data->read_word(vdp_pointer + 10) & 0xfffe;
const s16 fb_pitch = m_data->read_word(vdp_pointer + 10) & 0xfffe;
const u32 src_address = (m_data->read_word(vdp_pointer + 12) & 0xfffe)
| (m_data->read_word(vdp_pointer + 14) << 16);
@ -398,14 +398,14 @@ void pc88va_sgp_device::execute_blit(u16 draw_mode, bool is_patblt)
{
const u8 logical_op = draw_mode & 0xf;
const u8 tp_mod = (draw_mode >> 8) & 0x3;
// const bool hd = !!BIT(draw_mode, 10);
const bool hd = !!BIT(draw_mode, 10);
// TODO: rtype gameplay enables VD
// const bool vd = !!BIT(draw_mode, 11);
// const bool sf = !!BIT(draw_mode, 12);
const bool vd = !!BIT(draw_mode, 11);
const bool sf = !!BIT(draw_mode, 12);
if (draw_mode & 0xfc00)
if (hd || vd || sf)
{
popmessage("SGP: Warning draw_mode = %04x (HD %d VD %d SF %d)", draw_mode, BIT(draw_mode, 10), BIT(draw_mode, 11), BIT(draw_mode, 12));
popmessage("SGP: Warning draw_mode = %04x (HD %d VD %d SF %d)", draw_mode, hd, vd, sf);
}
// boomer title screen just sets the same h/v size, irrelevant

View File

@ -37,7 +37,7 @@ private:
u8 pixel_mode = 0;
u16 hsize = 0;
u16 vsize = 0;
u16 fb_pitch = 0;
s16 fb_pitch = 0;
u32 address = 0;
};

View File

@ -761,9 +761,13 @@ void pc88va_state::draw_graphic_layer(bitmap_rgb32 &bitmap, const rectangle &cli
// (almost likely an HW quirk, described in the docs)
// also animefrm swaps this with layer 2 (main canvas)
const u32 fsa = (layer_n == layer_fixed) ? 0x20000
: (fb_strip_regs[0x00 / 2] & 0xfffc) | ((fb_strip_regs[0x02 / 2] & 0x3) << 16) >> 1;
: (fb_strip_regs[0x00 / 2] & 0xfffc) | ((fb_strip_regs[0x02 / 2] & 0x3) << 16);
u16 fbl = (fb_strip_regs[0x06 / 2] & 0x3ff) + 1;
// shinraba relies on this for Graphic B, assume same behaviour of upd7220 pc98:madoum*
if (fbl == 1)
fbl = 0x400;
const u16 fbl = (fb_strip_regs[0x06 / 2] & 0x3ff) + 1;
const u8 x_dot_offs = fb_strip_regs[0x08 / 2];
const u16 ofx = fb_strip_regs[0x0a / 2] & 0x7fc;
const u16 ofy = fb_strip_regs[0x0c / 2] & 0x3ff;
@ -773,7 +777,7 @@ void pc88va_state::draw_graphic_layer(bitmap_rgb32 &bitmap, const rectangle &cli
LOGFB("%d %08x FSA|\n\t%d FBW | %d FBL |\n\t %d OFX (%d dot)| %d OFY|\n\t %08x DSA|\n\t %04x (%d) DSH | %04x (%d) DSP\n"
, layer_n
, fsa << 1
, fsa
, fbw
, fbl
, ofx
@ -794,13 +798,18 @@ void pc88va_state::draw_graphic_layer(bitmap_rgb32 &bitmap, const rectangle &cli
rectangle fb_cliprect(cliprect.min_x, cliprect.max_x, dsp, dsp + fbl - 1);
split_cliprect &= fb_cliprect;
if (split_cliprect.empty())
continue;
// TODO: picture mask
if (!m_dm)
{
switch(gfx_ctrl & 3)
{
case 1: draw_packed_gfx_4bpp(m_graphic_bitmap[which], split_cliprect, fsa, dsa, layer_pal_bank, fbw, fbl); break;
case 1: draw_packed_gfx_4bpp(m_graphic_bitmap[which], split_cliprect, fsa, dsa, ofx, layer_pal_bank, fbw, fbl); break;
default:
popmessage("pc88va_v.cpp: unhandled %d GFX mode DM = 0", which);
popmessage("pc88va_v.cpp: unhandled %d GFX mode DM = 0 (Multiplane)", which);
break;
}
}
@ -809,18 +818,18 @@ void pc88va_state::draw_graphic_layer(bitmap_rgb32 &bitmap, const rectangle &cli
switch(gfx_ctrl & 3)
{
//case 0: draw_indexed_gfx_1bpp(bitmap, cliprect, dsa, layer_pal_bank); break;
case 1: draw_indexed_gfx_4bpp(m_graphic_bitmap[which], split_cliprect, fsa, dsa, layer_pal_bank, fbw, fbl); break;
case 1: draw_indexed_gfx_4bpp(m_graphic_bitmap[which], split_cliprect, fsa, dsa, dsp, ofx, layer_pal_bank, fbw, fbl); break;
case 2:
if (m_pltm == 7)
if (is_5bpp)
{
draw_packed_gfx_5bpp(m_graphic_bitmap[which], split_cliprect, fsa, dsa, layer_pal_bank, fbw, fbl);
draw_packed_gfx_5bpp(m_graphic_bitmap[which], split_cliprect, fsa, dsa, dsp, ofx, layer_pal_bank, fbw, fbl);
}
else
draw_direct_gfx_8bpp(m_graphic_bitmap[which], split_cliprect, fsa, dsa, fbw, fbl);
draw_direct_gfx_8bpp(m_graphic_bitmap[which], split_cliprect, fsa, dsa, dsp, ofx, fbw, fbl);
break;
case 3: draw_direct_gfx_rgb565(m_graphic_bitmap[which], split_cliprect, fsa, fbw, fbl); break;
case 3: draw_direct_gfx_rgb565(m_graphic_bitmap[which], split_cliprect, fsa, dsa, ofx, fbw, fbl); break;
default:
popmessage("pc88va_v.cpp: unhandled %d GFX mode DM = 1", which);
popmessage("pc88va_v.cpp: unhandled %d GFX mode DM = 1 (Singleplane)", which);
break;
}
}
@ -835,6 +844,7 @@ void pc88va_state::draw_graphic_layer(bitmap_rgb32 &bitmap, const rectangle &cli
);
}
// TODO: incomplete
void pc88va_state::draw_indexed_gfx_1bpp(bitmap_rgb32 &bitmap, const rectangle &cliprect, u32 fb_start_offset, u8 pal_base)
{
for(int y = cliprect.min_y; y <= cliprect.max_y; y++)
@ -844,7 +854,7 @@ void pc88va_state::draw_indexed_gfx_1bpp(bitmap_rgb32 &bitmap, const rectangle &
for(int x = cliprect.min_x; x <= cliprect.max_x; x += 8)
{
u16 x_char = (x >> 3);
u32 bitmap_offset = line_offset + x_char;
u32 bitmap_offset = (line_offset + x_char) & 0x3ffff;
for (int xi = 0; xi < 8; xi ++)
{
@ -858,21 +868,23 @@ void pc88va_state::draw_indexed_gfx_1bpp(bitmap_rgb32 &bitmap, const rectangle &
}
}
void pc88va_state::draw_indexed_gfx_4bpp(bitmap_rgb32 &bitmap, const rectangle &cliprect, u32 fb_start_offset, u32 display_start_offset, u8 pal_base, u16 fb_width, u16 fb_height)
void pc88va_state::draw_indexed_gfx_4bpp(bitmap_rgb32 &bitmap, const rectangle &cliprect, u32 fb_start_offset, u32 display_start_offset, u16 dsp_start_base, u16 scrollx, u8 pal_base, u16 fb_width, u16 fb_height)
{
// const u16 y_min = std::max(cliprect.min_y, y_start);
// const u16 y_max = std::min(cliprect.max_y, y_min + fb_height);
//printf("%d %d %d %08x %d\n", y_min, y_max, fb_width, start_offset, fb_height);
const u32 base_address = (fb_start_offset & 0x20000) | (display_start_offset & 0x1ffff);
for(int y = cliprect.min_y; y <= cliprect.max_y; y++)
{
const u32 line_offset = ((y * fb_width) + fb_start_offset) & 0x3ffff;
const u32 line_offset = (((y - dsp_start_base) * fb_width) + base_address) & 0x3ffff;
for(int x = cliprect.min_x; x <= cliprect.max_x; x += 2)
{
u16 x_char = (x >> 1);
u32 bitmap_offset = line_offset + x_char;
u32 bitmap_offset = (line_offset + x_char - (scrollx >> 6)) & 0x3ffff;
for (int xi = 0; xi < 2; xi ++)
{
@ -885,20 +897,21 @@ void pc88va_state::draw_indexed_gfx_4bpp(bitmap_rgb32 &bitmap, const rectangle &
}
}
void pc88va_state::draw_packed_gfx_5bpp(bitmap_rgb32 &bitmap, const rectangle &cliprect, u32 fb_start_offset, u32 display_start_offset, u8 pal_base, u16 fb_width, u16 fb_height)
void pc88va_state::draw_packed_gfx_5bpp(bitmap_rgb32 &bitmap, const rectangle &cliprect, u32 fb_start_offset, u32 display_start_offset, u16 dsp_start_base, u16 scrollx, u8 pal_base, u16 fb_width, u16 fb_height)
{
// const u16 y_min = std::max(cliprect.min_y, y_start);
// const u16 y_max = std::min(cliprect.max_y, y_min + fb_height);
//printf("%d %d %d %08x %d\n", y_min, y_max, fb_width, start_offset, fb_height);
const u32 base_address = (fb_start_offset & 0x20000) | (display_start_offset & 0x1ffff);
for(int y = cliprect.min_y; y <= cliprect.max_y; y++)
{
const u32 line_offset = ((y * fb_width) + fb_start_offset) & 0x3ffff;
const u32 line_offset = (((y - dsp_start_base) * fb_width) + base_address) & 0x3ffff;
for(int x = cliprect.min_x; x <= cliprect.max_x; x++)
{
u32 bitmap_offset = line_offset + x;
u32 bitmap_offset = (line_offset + x - (scrollx >> 6)) & 0x3ffff;
u8 color = m_gvram[bitmap_offset] & 0x1f;
@ -908,18 +921,19 @@ void pc88va_state::draw_packed_gfx_5bpp(bitmap_rgb32 &bitmap, const rectangle &c
}
}
void pc88va_state::draw_direct_gfx_8bpp(bitmap_rgb32 &bitmap, const rectangle &cliprect, u32 fb_start_offset, u32 display_start_offset, u16 fb_width, u16 fb_height)
void pc88va_state::draw_direct_gfx_8bpp(bitmap_rgb32 &bitmap, const rectangle &cliprect, u32 fb_start_offset, u32 display_start_offset, u16 dsp_start_base, u16 scrollx, u16 fb_width, u16 fb_height)
{
// const u16 y_min = std::max(cliprect.min_y, y_start);
// const u16 y_max = std::min(cliprect.max_y, y_min + fb_height);
const u32 base_address = (fb_start_offset & 0x20000) | (display_start_offset & 0x1ffff);
for(int y = cliprect.min_y; y <= cliprect.max_y; y++)
{
const u32 line_offset = ((y * fb_width) + fb_start_offset) & 0x3ffff;
const u32 line_offset = (((y - dsp_start_base) * fb_width) + base_address) & 0x3ffff;
for(int x = cliprect.min_x; x <= cliprect.max_x; x++)
{
u32 bitmap_offset = (line_offset + x) & 0x3ffff;
u32 bitmap_offset = (line_offset + x - (scrollx >> 6)) & 0x3ffff;
uint32_t color = (m_gvram[bitmap_offset] & 0xff);
@ -936,19 +950,20 @@ void pc88va_state::draw_direct_gfx_8bpp(bitmap_rgb32 &bitmap, const rectangle &c
}
}
void pc88va_state::draw_direct_gfx_rgb565(bitmap_rgb32 &bitmap, const rectangle &cliprect, u32 fb_start_offset, u16 fb_width, u16 fb_height)
void pc88va_state::draw_direct_gfx_rgb565(bitmap_rgb32 &bitmap, const rectangle &cliprect, u32 fb_start_offset, u32 display_start_offset, u16 scrollx, u16 fb_width, u16 fb_height)
{
// const u16 y_min = std::max(cliprect.min_y, y_start);
// const u16 y_max = std::min(cliprect.max_y, y_min + fb_height);
const u32 base_address = (display_start_offset & 0x3ffff);
for(int y = cliprect.min_y; y <= cliprect.max_y; y++)
{
// pc88vad requires halved pitch for first screen
const u32 line_offset = ((y * fb_width >> 1) + fb_start_offset) & 0x3ffff;
const u32 line_offset = ((y * fb_width >> 1) + base_address) & 0x3ffff;
for(int x = cliprect.min_x; x <= cliprect.max_x; x++)
{
u32 bitmap_offset = (line_offset + x) << 1;
u32 bitmap_offset = ((line_offset + x - (scrollx >> 1)) << 1) & 0x3ffff;
uint16_t color = (m_gvram[bitmap_offset] & 0xff) | (m_gvram[bitmap_offset + 1] << 8);
@ -963,20 +978,22 @@ void pc88va_state::draw_direct_gfx_rgb565(bitmap_rgb32 &bitmap, const rectangle
}
}
// famista, probably all inufuto games
void pc88va_state::draw_packed_gfx_4bpp(bitmap_rgb32 &bitmap, const rectangle &cliprect, u32 fb_start_offset, u32 display_start_offset, u8 pal_base, u16 fb_width, u16 fb_height)
// famista, all inufuto games
void pc88va_state::draw_packed_gfx_4bpp(bitmap_rgb32 &bitmap, const rectangle &cliprect, u32 fb_start_offset, u32 display_start_offset, u16 scrollx, u8 pal_base, u16 fb_width, u16 fb_height)
{
// const u16 y_min = std::max(cliprect.min_y, y_start);
// const u16 y_max = std::min(cliprect.max_y, y_min + fb_height);
const u32 base_offset = display_start_offset >> 2;
for(int y = cliprect.min_y; y <= cliprect.max_y; y++)
{
const u32 line_offset = ((y * (fb_width >> 2)) + fb_start_offset) & 0x0ffff;
const u32 line_offset = ((y * (fb_width >> 2)) + base_offset) & 0x0ffff;
for(int x = cliprect.min_x; x <= cliprect.max_x; x += 8)
{
u16 x_char = (x >> 3);
u32 bitmap_offset = (line_offset + x_char + (display_start_offset >> 2)) & 0x0ffff;
u32 bitmap_offset = (line_offset + x_char - (scrollx >> 2)) & 0x0ffff;
for (int xi = 0; xi < 8; xi ++)
{
@ -1659,6 +1676,19 @@ void pc88va_state::text_transpen_w(offs_t offset, u16 data, u16 mem_mask)
popmessage("text transpen > 15 (%04x)", m_text_transpen);
}
void pc88va_state::picture_mask_w(offs_t offset, u16 data, u16 mem_mask)
{
switch(offset)
{
case 0: COMBINE_DATA(&m_picture_mask.left); m_picture_mask.left &= 0x3ff; break;
case 1: COMBINE_DATA(&m_picture_mask.right); m_picture_mask.right &= 0x3ff; break;
case 2: COMBINE_DATA(&m_picture_mask.top); m_picture_mask.top &= 0xff; break;
case 3: COMBINE_DATA(&m_picture_mask.bottom); m_picture_mask.bottom &= 0xff; break;
}
// popmessage("x0 %d y0 %d - x1 %d y1 %d", m_picture_mask.left, m_picture_mask.top, m_picture_mask.right, m_picture_mask.bottom);
}
/*
* $14c-$14f Kanji CG ports
* Alt method for access kanji ROM for drawing to graphic layers