Hyperscan: various updates

* Fixed hang in X-Men.
* Fixed some graphical issues.
* Implemented the TVE framebuffer (used in some homebrew demos).
This commit is contained in:
Sandro Ronco 2022-08-21 14:19:43 +02:00
parent c94ddebb94
commit d42d13b81e
5 changed files with 79 additions and 33 deletions

View File

@ -2,8 +2,6 @@
<!DOCTYPE softwarelist SYSTEM "softwarelist.dtd">
<!--
license:CC0
NOTE: This list is here only to document available dumps and it's not hoocked up with MAME yet.
-->
<softwarelist name="hyperscan" description="HyperScan CD-ROMs">

View File

@ -560,31 +560,34 @@ void score7_cpu_device::op_specialform()
}
break;
case 0x18: // sll
m_gpr[rd] = m_gpr[ra] << (m_gpr[rb] & 0x1f);
r = m_gpr[ra] << (m_gpr[rb] & 0x1f);
if (cu)
{
CHECK_Z(m_gpr[rd]);
CHECK_N(m_gpr[rd]);
CHECK_Z(r);
CHECK_N(r);
SET_C(BIT(m_gpr[ra], 32 - (m_gpr[rb] & 0x1f)));
}
m_gpr[rd] = r;
break;
case 0x1a: // srl
m_gpr[rd] = m_gpr[ra] >> (m_gpr[rb] & 0x1f);
r = m_gpr[ra] >> (m_gpr[rb] & 0x1f);
if (cu)
{
CHECK_Z(m_gpr[rd]);
CHECK_N(m_gpr[rd]);
CHECK_Z(r);
CHECK_N(r);
SET_C(BIT(m_gpr[ra], (m_gpr[rb] & 0x1f) - 1));
}
m_gpr[rd] = r;
break;
case 0x1b: // sra
m_gpr[rd] = sign_extend(m_gpr[ra] >> (m_gpr[rb] & 0x1f), 32 - (m_gpr[rb] & 0x1f));
r = sign_extend(m_gpr[ra] >> (m_gpr[rb] & 0x1f), 32 - (m_gpr[rb] & 0x1f));
if (cu)
{
CHECK_Z(m_gpr[rd]);
CHECK_N(m_gpr[rd]);
CHECK_Z(r);
CHECK_N(r);
SET_C(BIT(m_gpr[ra], (m_gpr[rb] & 0x1f) - 1));
}
m_gpr[rd] = r;
break;
case 0x1c: // ror
unemulated_op("ror");
@ -661,10 +664,14 @@ void score7_cpu_device::op_specialform()
case 0x28: // mfsr
if (rb < 3)
m_gpr[rd] = m_sr[rb];
else
logerror("%s: mfsr accessing sr%d (PC=0x%08x)\n", tag(), rb, m_ppc);
break;
case 0x29: // mtsr
if (rb < 3)
m_sr[rb] = m_gpr[ra];
else
logerror("%s: mtsr accessing sr%d (PC=0x%08x)\n", tag(), rb, m_ppc);
break;
case 0x2a: // t
SET_T(check_condition(rb));
@ -710,31 +717,34 @@ void score7_cpu_device::op_specialform()
unemulated_op("sce");
break;
case 0x38: // slli
m_gpr[rd] = m_gpr[ra] << rb;
r = m_gpr[ra] << rb;
if (cu)
{
CHECK_Z(m_gpr[rd]);
CHECK_N(m_gpr[rd]);
CHECK_Z(r);
CHECK_N(r);
SET_C(BIT(m_gpr[ra], 32 - rb));
}
m_gpr[rd] = r;
break;
case 0x3a: // srli
m_gpr[rd] = m_gpr[ra] >> rb;
r = m_gpr[ra] >> rb;
if (cu)
{
CHECK_Z(m_gpr[rd]);
CHECK_N(m_gpr[rd]);
CHECK_Z(r);
CHECK_N(r);
SET_C(BIT(m_gpr[ra], rb - 1));
}
m_gpr[rd] = r;
break;
case 0x3b: // srai
m_gpr[rd] = sign_extend(m_gpr[ra] >> rb, 32 - rb);
r = sign_extend(m_gpr[ra] >> rb, 32 - rb);
if (cu)
{
CHECK_Z(m_gpr[rd]);
CHECK_N(m_gpr[rd]);
CHECK_Z(r);
CHECK_N(r);
SET_C(BIT(m_gpr[ra], rb - 1));
}
m_gpr[rd] = r;
break;
case 0x3c: // rori
unemulated_op("rori");
@ -1196,11 +1206,12 @@ void score7_cpu_device::op_rform2()
m_gpr[rd] = r;
break;
case 0x02: // neg!
m_gpr[rd] = 0 - m_gpr[ra];
CHECK_Z(m_gpr[rd]);
CHECK_N(m_gpr[rd]);
CHECK_V_SUB(0, m_gpr[ra], m_gpr[rd]);
r = 0 - m_gpr[ra];
CHECK_Z(r);
CHECK_N(r);
CHECK_V_SUB(0, m_gpr[ra], r);
CHECK_C_SUB(0, m_gpr[ra]);
m_gpr[rd] = r;
break;
case 0x03: // cmp!
r = m_gpr[rd] - m_gpr[ra];
@ -1290,9 +1301,12 @@ void score7_cpu_device::op_iform1a()
else
m_gpr[rd] += 1 << (imm5 & 0xf);
// condition flags are invalid after this instruction
// according to the datasheet, the flags are undefined after this instruction, but xmen expects the Z flag to be valid.
CHECK_Z(m_gpr[rd]);
CHECK_N(m_gpr[rd]);
break;
case 0x01: // slli!
SET_C(BIT(m_gpr[rd], 32 - imm5));
m_gpr[rd] <<= imm5;
CHECK_Z(m_gpr[rd]);
CHECK_N(m_gpr[rd]);
@ -1301,6 +1315,7 @@ void score7_cpu_device::op_iform1a()
unemulated_op("sdbbp!");
break;
case 0x03: // srli!
SET_C(BIT(m_gpr[rd], imm5 - 1));
m_gpr[rd] >>= imm5;
CHECK_Z(m_gpr[rd]);
CHECK_N(m_gpr[rd]);

View File

@ -125,7 +125,7 @@ void score7_disassembler::disasm32(std::ostream &stream, offs_t pc, uint32_t opc
util::stream_format(stream, "j%s 0x%08x", GET_J_LK(opcode) ? "l": "", (pc & 0xfc000000) | (GET_J_DISP24(opcode) << 1));
break;
case 0x03: // RIX-form-1
util::stream_format(stream, "%s r%d, [R%d, %d]+", m_rix1_op[GET_RIX_FUNC3(opcode)], GET_RIX_RD(opcode), GET_RIX_RA(opcode), sign_extend(GET_RIX_IMM12(opcode), 12));
util::stream_format(stream, "%s r%d, [r%d, %d]+", m_rix1_op[GET_RIX_FUNC3(opcode)], GET_RIX_RD(opcode), GET_RIX_RA(opcode), sign_extend(GET_RIX_IMM12(opcode), 12));
break;
case 0x04:
util::stream_format(stream, "b%s%s 0x%08x", m_cond[GET_BC_BC(opcode) & 0x0f], GET_BC_LK(opcode) ? "l": "", pc + (sign_extend(GET_BC_DISP19(opcode), 19) << 1));
@ -158,7 +158,7 @@ void score7_disassembler::disasm32(std::ostream &stream, offs_t pc, uint32_t opc
}
break;
case 0x07: // RIX-form-2
util::stream_format(stream, "%s r%d, [R%d]+, %d", m_rix2_op[GET_RIX_FUNC3(opcode)], GET_RIX_RD(opcode), GET_RIX_RA(opcode), sign_extend(GET_RIX_IMM12(opcode), 12));
util::stream_format(stream, "%s r%d, [r%d]+, %d", m_rix2_op[GET_RIX_FUNC3(opcode)], GET_RIX_RD(opcode), GET_RIX_RA(opcode), sign_extend(GET_RIX_IMM12(opcode), 12));
break;
case 0x08:
util::stream_format(stream, "addri%s r%d, r%d, %d", GET_RI_CU(opcode) ? ".c": "", GET_RI_RD(opcode), GET_RI_RA(opcode), sign_extend(GET_RI_IMM14(opcode), 14));
@ -234,7 +234,10 @@ void score7_disassembler::disasm16(std::ostream &stream, offs_t pc, uint16_t opc
util::stream_format(stream, "ldiu! r%d, 0x%02x", GET_I2_RD(opcode), GET_I2_IMM8(opcode));
break;
case 0x06: // I-form-1a
util::stream_format(stream, "%s! r%d, %d", m_i1a_op[GET_I16_FUNC3(opcode)], GET_I16_RD(opcode), GET_I16_IMM5(opcode));
if (GET_I16_FUNC3(opcode) == 0)
util::stream_format(stream, "%s! r%d, %d", (GET_I16_IMM5(opcode) & 0x10) ? "subei" : "addei", GET_I16_RD(opcode), GET_I16_IMM5(opcode) & 0x0f);
else
util::stream_format(stream, "%s! r%d, %d", m_i1a_op[GET_I16_FUNC3(opcode)], GET_I16_RD(opcode), GET_I16_IMM5(opcode));
break;
case 0x07: // I-form-1b
switch(GET_I16_FUNC3(opcode))

View File

@ -335,14 +335,14 @@ inline rgb_t spg290_ppu_device::blend_colors(const rgb_t &c0, const rgb_t &c1, u
if (m_blend_mode & 1)
{
int r = (c0.r() * level / 63) - (c1.r() * (63 - level) / 63);
int g = (c0.b() * level / 63) - (c1.b() * (63 - level) / 63);
int g = (c0.g() * level / 63) - (c1.g() * (63 - level) / 63);
int b = (c0.b() * level / 63) - (c1.b() * (63 - level) / 63);
return rgb_t(r, g, b);
}
else
{
int r = (c0.r() * level / 63) + (c1.r() * (63 - level) / 63);
int g = (c0.b() * level / 63) + (c1.b() * (63 - level) / 63);
int g = (c0.g() * level / 63) + (c1.g() * (63 - level) / 63);
int b = (c0.b() * level / 63) + (c1.b() * (63 - level) / 63);
return rgb_t(r, g, b);
}
@ -382,7 +382,7 @@ void spg290_ppu_device::blit_sprite(bitmap_rgb32 &bitmap, const rectangle &clipr
uint8_t bit_pixel = ((attribute & 3) + 1) << 1;
uint8_t sprite_flip = (attribute >> 2) & 0x03;
uint16_t pen_bank = ((attribute >> 8) & 0x1f) * 0x10;
uint8_t blend = (attribute & 0x8000) ? (attribute >> 26) & 0x3f : 0;
uint8_t blend = (attribute & 0x8000) ? 0x3f - ((attribute >> 26) & 0x3f) : 0;
uint8_t pixel_word = 32 / bit_pixel;
uint8_t pixel_byte = 8 / bit_pixel;
uint8_t word_line = sprite_hsize / pixel_word;

View File

@ -9,7 +9,6 @@
HyperScan TODO:
- Various graphics glitches
- Sound
- X-Men hangs after the first match
- USB
Hyperscan has a hidden test menu that can be accessed with a specific inputs sequence:
@ -133,6 +132,9 @@ private:
uint16_t m_tve_control = 0;
uint8_t m_tve_fade_offset = 0;
uint16_t m_timers_clk_sel = 0;
uint8_t m_tve_buffer_ctrl = 3 ;
uint32_t m_tv_start_addr[3] = { 0 };
uint16_t m_gpio_out = 0;
};
@ -176,6 +178,8 @@ private:
void spg29x_game_state::timers_clk_sel_w(offs_t offset, uint32_t data, uint32_t mem_mask)
{
COMBINE_DATA(&m_timers_clk_sel);
auto clock = 27_MHz_XTAL / ((data & 0xff) + 1);
uint32_t mask = 0x100;
@ -239,6 +243,23 @@ uint32_t spg29x_game_state::spg290_screen_update(screen_device &screen, bitmap_r
{
m_ppu->screen_update(screen, bitmap, cliprect);
// TVE frame buffer
if (m_tve_buffer_ctrl < 3)
{
auto &space = m_maincpu->space(AS_PROGRAM);
const bool interlaced = m_tve_control & 1;
for (int y = cliprect.min_y; y <= cliprect.max_y; y += (interlaced ? 1 : 2))
for (int x = cliprect.min_x; x <= cliprect.max_x; x++)
{
const uint16_t rgb = space.read_word(m_tv_start_addr[m_tve_buffer_ctrl] + (y * cliprect.width() + x) * 2);
const rgb_t pix = rgb_t(pal5bit(rgb >> 11), pal6bit(rgb >> 5), pal5bit(rgb >> 0));
bitmap.pix(y, x) = pix;
if (!interlaced && cliprect.contains(x, y + 1))
bitmap.pix(y + 1, x) = pix;
}
}
if (m_tve_fade_offset)
{
int fade_offset = 255 - m_tve_fade_offset;
@ -260,9 +281,12 @@ void spg29x_game_state::spg290_mem(address_map &map)
map(0x08030000, 0x08030003).w(FUNC(spg29x_game_state::tve_control_w)).lr32(NAME([this](uint32_t data) { return m_tve_control; }));
map(0x0803000c, 0x0803000f).lw32(NAME([this](uint32_t data) { m_tve_fade_offset = data & 0xff; }));
map(0x08070000, 0x0807000b).lr32(NAME([this](offs_t offset) { return m_tv_start_addr[offset]; }));
map(0x08070000, 0x0807000b).lw32(NAME([this](offs_t offset, uint32_t data, uint32_t mem_mask) { COMBINE_DATA(&m_tv_start_addr[offset]); }));
map(0x08090020, 0x08090023).lw32(NAME([this](uint32_t data) { m_tve_buffer_ctrl = data & 3; }));
map(0x0807006c, 0x0807006f).lr32(NAME([]() { return 0x01;})); // MUI Status: SDRAM is in the self-refresh mode
//map(0x08150000, 0x08150000).lw8(NAME([this](uint8_t data) { printf("%c", data); })); // UART
map(0x082100e4, 0x082100e7).w(FUNC(spg29x_game_state::timers_clk_sel_w)); // Timer Source Clock Selection
map(0x082100e4, 0x082100e7).w(FUNC(spg29x_game_state::timers_clk_sel_w)).lr32(NAME([this]() { return m_timers_clk_sel; })); // Timer Source Clock Selection
map(0x08240000, 0x0824000f).noprw();
//map(0x08000000, 0x0800ffff); // CSI
@ -338,6 +362,9 @@ void spg29x_game_state::machine_start()
save_item(NAME(m_tve_control));
save_item(NAME(m_tve_fade_offset));
save_item(NAME(m_timers_clk_sel));
save_item(NAME(m_tve_buffer_ctrl));
save_item(NAME(m_tv_start_addr));
save_item(NAME(m_gpio_out));
}
@ -345,6 +372,9 @@ void spg29x_game_state::machine_reset()
{
m_tve_control = 0;
m_tve_fade_offset = 0;
m_timers_clk_sel = 0;
m_tve_buffer_ctrl = 3;
m_tv_start_addr[0] = m_tv_start_addr[1] = m_tv_start_addr[2] = 0;
m_gpio_out = 0;
// disable JTAG