summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
-rw-r--r--src/mame/nec/pc88va_sgp.cpp152
-rw-r--r--src/mame/nec/pc88va_sgp.h30
2 files changed, 132 insertions, 50 deletions
diff --git a/src/mame/nec/pc88va_sgp.cpp b/src/mame/nec/pc88va_sgp.cpp
index 9ff1e812b3e..d8f7670e103 100644
--- a/src/mame/nec/pc88va_sgp.cpp
+++ b/src/mame/nec/pc88va_sgp.cpp
@@ -7,10 +7,12 @@ NEC SGP (スーパーグラフィックプロセッサ / Super Graphic Processor
Unknown part number, used as GPU for PC88VA
TODO:
-- timing details
-- specifics about what exactly happens in work area when either SGP runs or is idle.
+- timing details;
+- unemulated CLS, LINE and 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
- with tp_mode = 3 and pitch = 0 (!?);
+ with tp_mode = 3, uneven color depths (src 1bpp, dst 4bpp) and pitch = 0, assume disabled;
- rtype: during gameplay it does transfers with Pitch = 0xfff0, alias for negative draw?
- basic fires a VABOT on loading;
@@ -21,7 +23,6 @@ TODO:
//#include <iostream>
-
#define LOG_COMMAND (1U << 1)
#define VERBOSE (LOG_GENERAL)
@@ -88,7 +89,7 @@ void pc88va_sgp_device::vdp_address_w(offs_t offset, u16 data, u16 mem_mask)
void pc88va_sgp_device::control_w(u8 data)
{
if (data)
- popmessage("SGP warning write %02x", data);
+ popmessage("SGP: control_w write %02x", data);
}
/*
@@ -96,6 +97,11 @@ void pc88va_sgp_device::control_w(u8 data)
*/
u8 pc88va_sgp_device::status_r()
{
+// crude debug single-stepping
+// if (machine().input().code_pressed(KEYCODE_S))
+// return 0;
+// if (!machine().input().code_pressed_once(KEYCODE_A))
+// return 1;
return 0;
}
@@ -183,7 +189,8 @@ void pc88va_sgp_device::start_exec()
ptr->pixel_mode = (param1 & 0x03);
ptr->hsize = m_data->read_word(vdp_pointer + 4) & 0x0fff;
ptr->vsize = m_data->read_word(vdp_pointer + 6) & 0x0fff;
- ptr->fb_pitch = m_data->read_word(vdp_pointer + 8) & 0xfffc;
+ // NOTE: & 0xfffc causes pitch issues in boomer intro/title text, shinraba gameplay
+ ptr->fb_pitch = 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);
@@ -223,7 +230,7 @@ void pc88va_sgp_device::start_exec()
, cmd_mode ? "PATBLT" : "BITBLT"
, draw_mode
);
- cmd_blit(draw_mode, cmd_mode);
+ execute_blit(draw_mode, cmd_mode);
next_pc += 2;
break;
@@ -239,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) & 0xfffc;
+ const u16 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);
@@ -303,9 +310,58 @@ void pc88va_sgp_device::start_exec()
}
/****************************************
- * Commands
+ * Blitting
***************************************/
+const pc88va_sgp_device::rop_func pc88va_sgp_device::rop_table[16] =
+{
+ &pc88va_sgp_device::rop_0_fill_0,
+ &pc88va_sgp_device::rop_1_s_and_d,
+ &pc88va_sgp_device::rop_2_ns_and_d,
+ &pc88va_sgp_device::rop_3_d,
+ &pc88va_sgp_device::rop_4_s_and_nd,
+ &pc88va_sgp_device::rop_5_s,
+ &pc88va_sgp_device::rop_6_s_xor_d,
+ &pc88va_sgp_device::rop_7_s_or_d,
+ &pc88va_sgp_device::rop_8_ns_or_d,
+ &pc88va_sgp_device::rop_9_n_s_xor_d,
+ &pc88va_sgp_device::rop_A_n_s,
+ &pc88va_sgp_device::rop_B_n_s_or_d,
+ &pc88va_sgp_device::rop_C_nd,
+ &pc88va_sgp_device::rop_D_s_or_nd,
+ &pc88va_sgp_device::rop_E_n_s_and_d,
+ &pc88va_sgp_device::rop_F_fill_1,
+};
+
+u16 pc88va_sgp_device::rop_0_fill_0(u16 src, u16 dst) { return 0; }
+u16 pc88va_sgp_device::rop_1_s_and_d(u16 src, u16 dst) { return src & dst; }
+u16 pc88va_sgp_device::rop_2_ns_and_d(u16 src, u16 dst) { return (~src) & dst; }
+u16 pc88va_sgp_device::rop_3_d(u16 src, u16 dst) { return dst; }
+u16 pc88va_sgp_device::rop_4_s_and_nd(u16 src, u16 dst) { return src & (~dst); }
+u16 pc88va_sgp_device::rop_5_s(u16 src, u16 dst) { return src; }
+u16 pc88va_sgp_device::rop_6_s_xor_d(u16 src, u16 dst) { return src ^ dst; }
+u16 pc88va_sgp_device::rop_7_s_or_d(u16 src, u16 dst) { return src | dst; }
+u16 pc88va_sgp_device::rop_8_ns_or_d(u16 src, u16 dst) { return ~(src | dst); }
+u16 pc88va_sgp_device::rop_9_n_s_xor_d(u16 src, u16 dst) { return ~(src ^ dst); }
+u16 pc88va_sgp_device::rop_A_n_s(u16 src, u16 dst) { return ~src; }
+u16 pc88va_sgp_device::rop_B_n_s_or_d(u16 src, u16 dst) { return (~src) | dst; }
+u16 pc88va_sgp_device::rop_C_nd(u16 src, u16 dst) { return ~dst; }
+u16 pc88va_sgp_device::rop_D_s_or_nd(u16 src, u16 dst) { return src | (~dst); }
+u16 pc88va_sgp_device::rop_E_n_s_and_d(u16 src, u16 dst) { return ~(src & dst); }
+u16 pc88va_sgp_device::rop_F_fill_1(u16 src, u16 dst) { return 0xffff; }
+
+const pc88va_sgp_device::tpmod_func pc88va_sgp_device::tpmod_table[4] =
+{
+ &pc88va_sgp_device::tpmod_0_always,
+ &pc88va_sgp_device::tpmod_1_src,
+ &pc88va_sgp_device::tpmod_2_dst,
+ &pc88va_sgp_device::tpmod_3_never
+};
+
+bool pc88va_sgp_device::tpmod_0_always(u16 src, u16 dst) { return true; }
+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
@@ -315,7 +371,7 @@ void pc88va_sgp_device::start_exec()
* ---- --00 ---- ---- transfer source as-is
* ---- --01 ---- ---- do not transfer if source is 0 (transparent pen)
* ---- --10 ---- ---- transfer only if destination is 0
- * ---- --11 ---- ---- <undocumented>
+ * ---- --11 ---- ---- <undocumented, assume never>
* ---- ---- ---- xxxx LOGICAL OP
* ---- ---- ---- 0000 0
* ---- ---- ---- 0001 Src AND Dst
@@ -323,8 +379,8 @@ void pc88va_sgp_device::start_exec()
* ---- ---- ---- 0011 NOP
* ---- ---- ---- 0100 Src AND /Dst
* ---- ---- ---- 0101 Src
- * ---- ---- ---- 0110 Src XOR Dst
- * ---- ---- ---- 0111 Src OR Dst
+ * ---- ---- ---- 0110 Src XOR Dst (ballbrkr)
+ * ---- ---- ---- 0111 Src OR Dst (boomer)
* ---- ---- ---- 1000 /(Src OR Dst)
* ---- ---- ---- 1001 /(Src XOR Dst)
* ---- ---- ---- 1010 /Src
@@ -337,10 +393,19 @@ void pc88va_sgp_device::start_exec()
* PATBLT is identical to BITBLT except it repeats source copy
* if it exceeds the clipping range.
*/
-void pc88va_sgp_device::cmd_blit(u16 draw_mode, bool is_patblt)
+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);
+ // TODO: rtype gameplay enables VD
+// const bool vd = !!BIT(draw_mode, 11);
+// const bool sf = !!BIT(draw_mode, 12);
+
+ if (draw_mode & 0xfc00)
+ {
+ popmessage("SGP: draw_mode = %04x (HD %d VD %d SF %d)", draw_mode, BIT(draw_mode, 10), BIT(draw_mode, 11), BIT(draw_mode, 12));
+ }
// TODO: boomer title screen
if (is_patblt == true)
@@ -349,19 +414,6 @@ void pc88va_sgp_device::cmd_blit(u16 draw_mode, bool is_patblt)
// return;
}
- // ballbrkr: 6
- if (logical_op != 5)
- {
- LOG("BITBLT logical_op == %d\n", logical_op);
- return;
- }
-
- if (tp_mod > 1)
- {
- LOG("BITBLT tp_mod == %d\n", tp_mod);
- return;
- }
-
if (m_src.hsize != m_dst.hsize || m_src.vsize != m_dst.vsize)
{
LOG("BITBLT non-even sizes (%d x %d) x (%d x %d)\n", m_src.hsize, m_src.vsize, m_dst.hsize, m_dst.vsize);
@@ -374,48 +426,52 @@ void pc88va_sgp_device::cmd_blit(u16 draw_mode, bool is_patblt)
return;
}
- const u8 hsize_shift = m_src.pixel_mode == 1 ? 1 : 0;
+ //static const u8 shift_table = { 3, 1, 0, -1 };
+ //const u8 hsize_shift = m_src.pixel_mode == 1 ? 1 : 0;
for (int yi = 0; yi < m_src.vsize; yi ++)
{
u32 src_address = m_src.address + (yi * m_src.fb_pitch);
u32 dst_address = m_dst.address + (yi * m_dst.fb_pitch);
- for (int xi = 0; xi < (m_src.hsize >> hsize_shift); xi ++)
+ // TODO: should fetch on demand, depending on what's the color mode/the start dot etc.
+ for (int xi = 0; xi < m_src.hsize; xi ++)
{
- // TODO: not very efficient, we need a cleaner per-pixel RMW phase
- const u8 src_dot = m_data->read_byte(src_address);
- const u8 dst_dot = m_data->read_byte(dst_address);
- u8 result = 0;
-
switch(m_src.pixel_mode)
{
// 4bpp (shinraba)
case 1:
- for (int pixi = 0; pixi < 2; pixi ++)
+ {
+ const u8 nibble = xi & 1;
+ u8 src = (m_data->read_byte(src_address + (xi >> 1)) >> (nibble * 4)) & 0xf;
+ u8 dst = m_data->read_byte(dst_address + (xi >> 1));
+ u8 result = dst & (nibble ? 0x0f : 0xf0);
+
+ if ((this->*tpmod_table[tp_mod])(src, dst))
{
- u8 cur_pixel = (src_dot & 0xf);
- if (cur_pixel || tp_mod == 0)
- result |= (src_dot & 0xf) << (pixi * 4);
- else
- result |= (dst_dot & 0xf) << (pixi * 4);
+ result |= (this->*rop_table[logical_op])(src, dst) << (nibble * 4);
+ m_data->write_byte(dst_address + (xi >> 1), result);
}
+
break;
+ }
// 8bpp (tetris)
case 2:
- u8 cur_pixel = (src_dot & 0xff);
- if (cur_pixel || tp_mod == 0)
- result |= (cur_pixel & 0xff);
- else
- result |= (dst_dot & 0xff);
+ {
+ u8 src = m_data->read_byte(src_address + xi) & 0xff;
+ u8 dst = m_data->read_byte(dst_address + xi) & 0xff;
+ u8 result = dst;
+
+ if ((this->*tpmod_table[tp_mod])(src, dst))
+ {
+ result = (this->*rop_table[logical_op])(src, dst);
+ m_data->write_byte(dst_address + xi, result);
+ }
break;
+ }
}
-
- m_data->write_byte(dst_address, result);
- src_address ++;
- dst_address ++;
}
}
}
diff --git a/src/mame/nec/pc88va_sgp.h b/src/mame/nec/pc88va_sgp.h
index 1ef011f72b0..24a53cc6f95 100644
--- a/src/mame/nec/pc88va_sgp.h
+++ b/src/mame/nec/pc88va_sgp.h
@@ -49,8 +49,34 @@ private:
void start_exec();
- // commands
- void cmd_blit(u16 draw_mode, bool is_patblt);
+ void execute_blit(u16 draw_mode, bool is_patblt);
+
+ typedef u16 (pc88va_sgp_device::*rop_func)(u16 src, u16 dst);
+
+ static const rop_func rop_table[16];
+ u16 rop_0_fill_0(u16 src, u16 dst);
+ u16 rop_1_s_and_d(u16 src, u16 dst);
+ u16 rop_2_ns_and_d(u16 src, u16 dst);
+ u16 rop_3_d(u16 src, u16 dst);
+ u16 rop_4_s_and_nd(u16 src, u16 dst);
+ u16 rop_5_s(u16 src, u16 dst);
+ u16 rop_6_s_xor_d(u16 src, u16 dst);
+ u16 rop_7_s_or_d(u16 src, u16 dst);
+ u16 rop_8_ns_or_d(u16 src, u16 dst);
+ u16 rop_9_n_s_xor_d(u16 src, u16 dst);
+ u16 rop_A_n_s(u16 src, u16 dst);
+ u16 rop_B_n_s_or_d(u16 src, u16 dst);
+ u16 rop_C_nd(u16 src, u16 dst);
+ u16 rop_D_s_or_nd(u16 src, u16 dst);
+ u16 rop_E_n_s_and_d(u16 src, u16 dst);
+ u16 rop_F_fill_1(u16 src, u16 dst);
+
+ typedef bool (pc88va_sgp_device::*tpmod_func)(u16 src, u16 dst);
+ static const tpmod_func tpmod_table[4];
+ bool tpmod_0_always(u16 src, u16 dst);
+ bool tpmod_1_src(u16 src, u16 dst);
+ bool tpmod_2_dst(u16 src, u16 dst);
+ bool tpmod_3_never(u16 src, u16 dst);
};