nec/pc88va_sgp.cpp: make RMW shifting more reliable, add 1bpp to 1bpp/4bpp OPs

This commit is contained in:
angelosa 2025-03-12 21:16:48 +01:00
parent 044fb3002a
commit 9ed724e2ce
3 changed files with 67 additions and 16 deletions

View File

@ -103,8 +103,8 @@ brk 8Ch AH=02h read calendar clock -> CH = hour, CL = minutes, DH = seconds, DL
#define LOGGFXCTRL(...) LOGMASKED(LOG_GFXCTRL, __VA_ARGS__)
// TODO: verify clocks
#define MASTER_CLOCK XTAL(8'000'000) // may be XTAL(31'948'800) / 4? (based on PC-8801 and PC-9801)
#define FM_CLOCK (XTAL(31'948'800) / 4) // 3993600
#define MASTER_CLOCK (XTAL(31'948'800) / 4) // (based on PC-8801 and PC-9801)
#define FM_CLOCK (XTAL(31'948'800) / 4) // 3993600, / 8 for regular pc88va
@ -1366,6 +1366,7 @@ void pc88va_state::pc88va(machine_config &config)
SPEAKER(config, m_lspeaker).front_left();
SPEAKER(config, m_rspeaker).front_right();
// TODO: YM2203 for vanilla pc88va
// PC-88VA-12 "Sound Board II", YM2608B
YM2608(config, m_opna, FM_CLOCK);
m_opna->set_addrmap(0, &pc88va_state::opna_map);

View File

@ -8,7 +8,7 @@ Unknown part number, used as GPU for PC88VA
TODO:
- timing details;
- unemulated CLS, LINE and SCAN;
- unemulated CLS, LINE, SCAN;
- Uneven src/dst sizes or color depths (mostly for PATBLT);
- specifics about what exactly happens in work area when either SGP runs or is idle;
- famista: during gameplay it BITBLT same source to destination 0x00037076
@ -209,10 +209,10 @@ void pc88va_sgp_device::start_exec()
}
case 0x0006:
{
const u16 color_code = m_data->read_word(vdp_pointer + 2);
m_color_code = m_data->read_word(vdp_pointer + 2);
LOGCOMMAND("SGP: (PC=%08x) SET COLOR %04x\n"
, vdp_pointer
, color_code
, m_color_code
);
next_pc += 2;
break;
@ -363,6 +363,7 @@ bool pc88va_sgp_device::tpmod_1_src(u16 src, u16 dst) { return src != 0; }
bool pc88va_sgp_device::tpmod_2_dst(u16 src, u16 dst) { return dst == 0; }
bool pc88va_sgp_device::tpmod_3_never(u16 src, u16 dst) { return false; }
/*
* ---x ---- ---- ---- SF (0) shift source according to destination position
* ---- x--- ---- ---- VD vertical transfer direction (1) negative (0) positive
@ -420,8 +421,7 @@ void pc88va_sgp_device::execute_blit(u16 draw_mode, bool is_patblt)
return;
}
// TODO: pceva2tb:SKYBD.BAT wants a 1bpp to 4bpp translation
if (m_src.pixel_mode == 0 || m_src.pixel_mode != m_dst.pixel_mode)
if (m_src.pixel_mode != m_dst.pixel_mode && m_src.pixel_mode != 0 && m_dst.pixel_mode != 1)
{
static const char *const pixel_mode[] = { "1bpp", "4bpp", "8bpp", "rgb565" };
@ -434,24 +434,71 @@ void pc88va_sgp_device::execute_blit(u16 draw_mode, bool is_patblt)
u32 src_address = m_src.address + (yi * m_src.fb_pitch);
u32 dst_address = m_dst.address + (yi * m_dst.fb_pitch);
// TODO: should fetch on demand, depending on color mode/start dot etc.
// TODO: should fetch on demand, depending on m_dst.pixel_mode etc.
// m_src.start_dot is used by famista (pitcher throws)
for (int xi = 0; xi < m_src.hsize; xi ++)
{
switch(m_src.pixel_mode)
{
// 1bpp
case 0:
{
const u32 src_offset = src_address + ((xi + m_src.start_dot) >> 3);
const u8 src_nibble = ((xi + m_src.start_dot) ^ 7) & 7;
// famista, before expanding (1bpp -> 1bpp)
if (m_dst.pixel_mode == 0)
{
const u32 dst_offset = dst_address + ((xi + m_dst.start_dot) >> 3);
const u8 dst_nibble = ((xi + m_dst.start_dot) ^ 7) & 7;
u8 src = (m_data->read_byte(src_offset) >> src_nibble) & 0x1;
u8 result = m_data->read_byte(dst_offset);
u8 dst = (result >> dst_nibble) & 0x1;
if ((this->*tpmod_table[tp_mod])(src, dst))
{
result &= ~(1 << dst_nibble);
result |= ((this->*rop_table[logical_op])(src, dst) & 1) << dst_nibble;
m_data->write_byte(dst_offset, result);
}
}
else if (m_dst.pixel_mode == 1) // famista and pceva2tb:SKYBD.BAT (1bpp -> 4bpp)
{
const u32 dst_offset = dst_address + ((xi + m_dst.start_dot) >> 1);
const u8 dst_nibble = (((xi + m_dst.start_dot) ^ 1) & 1) * 4;
u8 src = (m_data->read_byte(src_offset) >> src_nibble) & 0x1;
u8 result = m_data->read_byte(dst_offset);
u8 dst = (result >> dst_nibble) & 0xf;
if ((this->*tpmod_table[tp_mod])(src, dst))
{
result &= dst_nibble ? 0x0f : 0xf0;
result |= ((this->*rop_table[logical_op])(src, dst) ? m_color_code & 0xf : 0) << dst_nibble;
m_data->write_byte(dst_offset, result);
}
}
break;
}
// 4bpp (shinraba)
case 1:
{
const u8 nibble = xi & 1;
const u32 dst_offset = dst_address + ((xi + m_dst.start_dot) >> 1);
const u32 src_offset = src_address + ((xi + m_src.start_dot) >> 1);
const u8 src_nibble = (((xi + m_src.start_dot) ^ 1) & 1) * 4;
u8 src = (m_data->read_byte(src_address + (xi >> 1)) >> (nibble * 4)) & 0xf;
u8 dst = m_data->read_byte(dst_offset);
u8 result = dst & (nibble ? 0x0f : 0xf0);
const u32 dst_offset = dst_address + ((xi + m_dst.start_dot) >> 1);
const u8 dst_nibble = (((xi + m_dst.start_dot) ^ 1) & 1) * 4;
u8 src = (m_data->read_byte(src_offset) >> src_nibble) & 0xf;
u8 result = m_data->read_byte(dst_offset);
u8 dst = (result >> dst_nibble) & 0xf;
if ((this->*tpmod_table[tp_mod])(src, dst))
{
result |= (this->*rop_table[logical_op])(src, dst) << (nibble * 4);
result &= dst_nibble ? 0x0f : 0xf0;
result |= (this->*rop_table[logical_op])(src, dst) << dst_nibble;
m_data->write_byte(dst_offset, result);
}
@ -461,9 +508,10 @@ void pc88va_sgp_device::execute_blit(u16 draw_mode, bool is_patblt)
// 8bpp (tetris)
case 2:
{
const u32 src_offset = src_address + (xi + m_src.start_dot);
const u32 dst_offset = dst_address + (xi + m_dst.start_dot);
u8 src = m_data->read_byte(src_address + xi) & 0xff;
u8 src = m_data->read_byte(src_offset) & 0xff;
u8 dst = m_data->read_byte(dst_offset) & 0xff;
u8 result = dst;
@ -479,9 +527,10 @@ void pc88va_sgp_device::execute_blit(u16 draw_mode, bool is_patblt)
// RGB565 (ballbrkr title)
case 3:
{
const u32 src_offset = src_address + ((xi + m_src.start_dot) << 1);
const u32 dst_offset = dst_address + ((xi + m_dst.start_dot) << 1);
u16 src = m_data->read_word(src_address + (xi << 1)) & 0xffff;
u16 src = m_data->read_word(src_offset) & 0xffff;
u16 dst = m_data->read_word(dst_offset) & 0xffff;
u16 result = dst;

View File

@ -30,6 +30,7 @@ private:
u16 m_vdp_address[2]{};
u32 m_work_address = 0;
u16 m_color_code;
struct BufferArea {
u8 start_dot = 0;