mirror of
https://github.com/holub/mame
synced 2025-04-16 13:34:55 +03:00
Research into thoop and squash 'refresh rate' protection [Victor Fernandez (City Game), Peter Ferrie, David Haywood] (#8916)
* Research into thoop and squash 'refrsh rate' protection [Victor Fernandez (City Game), Peter Ferrie, David Haywood] - prevents freeze when dying in stage 4 of Thunder Hoop, and bad text on continue in Squash
This commit is contained in:
parent
45710aacf1
commit
edc0dfb627
@ -2032,7 +2032,7 @@ files {
|
||||
MAME_DIR .. "src/mame/includes/gaelco.h",
|
||||
MAME_DIR .. "src/mame/video/gaelco.cpp",
|
||||
MAME_DIR .. "src/mame/machine/gaelcrpt.cpp",
|
||||
MAME_DIR .. "src/mame/includes/gaelcrpt.h",
|
||||
MAME_DIR .. "src/mame/machine/gaelcrpt.h",
|
||||
MAME_DIR .. "src/mame/drivers/gaelco2.cpp",
|
||||
MAME_DIR .. "src/mame/includes/gaelco2.h",
|
||||
MAME_DIR .. "src/mame/machine/gaelco2.cpp",
|
||||
|
@ -2059,8 +2059,13 @@ void mcs51_cpu_device::execute_run()
|
||||
|
||||
/* decrement the timed access window */
|
||||
if (m_features & FEATURE_DS5002FP)
|
||||
{
|
||||
m_ds5002fp.ta_window = (m_ds5002fp.ta_window ? (m_ds5002fp.ta_window - 1) : 0x00);
|
||||
|
||||
if (m_ds5002fp.rnr_delay > 0)
|
||||
m_ds5002fp.rnr_delay-=m_inst_cycles;
|
||||
}
|
||||
|
||||
/* If the chip entered in idle mode, end the loop */
|
||||
if ((m_features & FEATURE_CMOS) && GET_IDL)
|
||||
return;
|
||||
@ -2182,6 +2187,7 @@ void mcs51_cpu_device::device_start()
|
||||
save_item(NAME(m_irq_active) );
|
||||
save_item(NAME(m_ds5002fp.previous_ta) );
|
||||
save_item(NAME(m_ds5002fp.ta_window) );
|
||||
save_item(NAME(m_ds5002fp.rnr_delay) );
|
||||
save_item(NAME(m_ds5002fp.range) );
|
||||
save_item(NAME(m_uart.data_out));
|
||||
save_item(NAME(m_uart.bits_to_send));
|
||||
@ -2326,6 +2332,7 @@ void mcs51_cpu_device::device_reset()
|
||||
m_ds5002fp.previous_ta = 0;
|
||||
m_ds5002fp.ta_window = 0;
|
||||
m_ds5002fp.range = (GET_RG1 << 1) | GET_RG0;
|
||||
m_ds5002fp.rnr_delay = 160;
|
||||
}
|
||||
|
||||
m_uart.data_out = 0;
|
||||
@ -2469,6 +2476,26 @@ void ds5002fp_device::sfr_write(size_t offset, uint8_t data)
|
||||
m_data.write_byte((size_t) offset | 0x100, data);
|
||||
}
|
||||
|
||||
|
||||
uint8_t ds5002fp_device::handle_rnr()
|
||||
{
|
||||
if (m_ds5002fp.rnr_delay <= 0)
|
||||
{
|
||||
m_ds5002fp.rnr_delay = 160; // delay before another random number can be read
|
||||
return machine().rand();
|
||||
}
|
||||
else
|
||||
return 0x00;
|
||||
}
|
||||
|
||||
bool ds5002fp_device::is_rnr_ready()
|
||||
{
|
||||
if (m_ds5002fp.rnr_delay <= 0)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
uint8_t ds5002fp_device::sfr_read(size_t offset)
|
||||
{
|
||||
switch (offset)
|
||||
@ -2478,8 +2505,10 @@ uint8_t ds5002fp_device::sfr_read(size_t offset)
|
||||
case ADDR_CRCH: DS5_LOGR(CRCH, data); break;
|
||||
case ADDR_MCON: DS5_LOGR(MCON, data); break;
|
||||
case ADDR_TA: DS5_LOGR(TA, data); break;
|
||||
case ADDR_RNR: DS5_LOGR(RNR, data); break;
|
||||
case ADDR_RPCTL: DS5_LOGR(RPCTL, data); return 0x80; break; /* touchgo stalls unless bit 7 is set, why? documentation is unclear */
|
||||
case ADDR_RNR: DS5_LOGR(RNR, data);
|
||||
return handle_rnr();
|
||||
case ADDR_RPCTL: DS5_LOGR(RPCTL, data); /* touchgo stalls unless bit 7 is set, RNR status (Random Number status) */
|
||||
return (is_rnr_ready() ? 0x80 : 0x00); /* falling through to sfr_read for the remaining bits stops high score data loading? */
|
||||
case ADDR_RPS: DS5_LOGR(RPS, data); break;
|
||||
case ADDR_PCON:
|
||||
SET_PFW(0); /* reset PFW flag */
|
||||
|
@ -158,7 +158,7 @@ protected:
|
||||
/* Serial Port TX/RX Callbacks */
|
||||
devcb_write8 m_serial_tx_cb; //Call back function when sending data out of serial port
|
||||
devcb_read8 m_serial_rx_cb; //Call back function to retrieve data when receiving serial port data
|
||||
|
||||
|
||||
/* DS5002FP */
|
||||
struct {
|
||||
uint8_t previous_ta; /* Previous Timed Access value */
|
||||
@ -168,6 +168,7 @@ protected:
|
||||
uint8_t mcon; /* bootstrap loader MCON register */
|
||||
uint8_t rpctl; /* bootstrap loader RPCTL register */
|
||||
uint8_t crc; /* bootstrap loader CRC register */
|
||||
int32_t rnr_delay; /* delay before new random number available */
|
||||
} m_ds5002fp;
|
||||
|
||||
// for the debugger
|
||||
@ -604,6 +605,9 @@ protected:
|
||||
virtual void sfr_write(size_t offset, uint8_t data) override;
|
||||
virtual uint8_t sfr_read(size_t offset) override;
|
||||
|
||||
uint8_t handle_rnr();
|
||||
bool is_rnr_ready();
|
||||
|
||||
private:
|
||||
optional_memory_region m_region;
|
||||
};
|
||||
|
@ -281,12 +281,27 @@ void gaelco_gae1_device::device_start()
|
||||
|
||||
if (LOG_WAVE)
|
||||
wavraw = util::wav_open("gae1_snd.wav", rate, 2);
|
||||
|
||||
for (int ch = 0; ch < NUM_CHANNELS; ch++)
|
||||
{
|
||||
save_item(NAME(m_channel[ch].active), ch);
|
||||
save_item(NAME(m_channel[ch].loop), ch);
|
||||
save_item(NAME(m_channel[ch].chunkNum), ch);
|
||||
}
|
||||
|
||||
save_item(NAME(m_sndregs));
|
||||
}
|
||||
|
||||
void gaelco_gae1_device::device_reset()
|
||||
{
|
||||
for (int ch = 0; ch < NUM_CHANNELS; ch++)
|
||||
{
|
||||
m_channel[ch].active = 0;
|
||||
m_channel[ch].loop = 0;
|
||||
m_channel[ch].chunkNum = 0;
|
||||
}
|
||||
|
||||
std::fill(std::begin(m_sndregs), std::end(m_sndregs), 0.0);
|
||||
}
|
||||
|
||||
void gaelco_gae1_device::device_stop()
|
||||
|
@ -60,13 +60,16 @@ private:
|
||||
};
|
||||
|
||||
sound_stream *m_stream; /* our stream */
|
||||
int m_banks[4]; /* start of each ROM bank */
|
||||
sound_channel m_channel[NUM_CHANNELS]; /* 7 stereo channels */
|
||||
|
||||
// live
|
||||
sound_channel m_channel[NUM_CHANNELS]; /* 7 stereo channels */
|
||||
uint16_t m_sndregs[0x38];
|
||||
|
||||
// Table for converting from 8 to 16 bits with volume control
|
||||
int16_t m_volume_table[VOLUME_LEVELS][256];
|
||||
|
||||
// config
|
||||
int m_banks[4]; /* start of each ROM bank */
|
||||
};
|
||||
|
||||
DECLARE_DEVICE_TYPE(GAELCO_GAE1, gaelco_gae1_device)
|
||||
|
@ -14,28 +14,84 @@ Year Game PCB NOTES
|
||||
1992 Squash REF 922804/1 Encrypted Video RAM
|
||||
1992 Thunder Hoop REF 922804/1 Encrypted Video RAM
|
||||
1995 Biomechanical Toy REF 922804/2 Unprotected
|
||||
1996 Maniac Square REF 922804/2 Prototype
|
||||
|
||||
TODO: Figure out why Thunder Hoop crashes if you die on Level 4
|
||||
This can be bypassed by killing yourself at the same time as
|
||||
the Level 3 boss dies, suggesting the end stage animation is
|
||||
somehow corrupting the game state. Could this be a bug in
|
||||
the supported revision of the game? It doesn't depend on
|
||||
CPU clock, vblank timing, there are no unmapped reads or
|
||||
writes of significance. Could it be related to a dipswitch
|
||||
setting?
|
||||
1992 Maniac Square REF 922804/2 Prototype
|
||||
|
||||
Priorities for all games - the games don't make extensive
|
||||
enough use of the priority scheme to properly draw any
|
||||
conclusions.
|
||||
|
||||
-------------------------------------------------------------
|
||||
Note about 57.42 'FRAMERATE_922804' screen refresh
|
||||
frequency and protection checks.
|
||||
|
||||
In thoop there's a timing loop at 0x49e-4ac. It's
|
||||
counting frames between interrupt-triggers.
|
||||
|
||||
0x49e writes the count to 0xffdb62.
|
||||
|
||||
While fighting the second-stage boss, when the pink
|
||||
things fly out, 0x8970 is called. 0x8988 fetches
|
||||
from 0xffdb62. If the value is > 0xdd1 (via 0x898a)
|
||||
or < 0xdb1 (via 0x8992), then 0x89ac sets 0xffdc45
|
||||
to 5.
|
||||
|
||||
At 60hz the value returned is 0xd29, which causes
|
||||
the fail condition to trigger. Values >=57.3 or
|
||||
<=57.7 give a result within the required range. The
|
||||
failure is not obvious at this point.
|
||||
|
||||
While fighting the third boss, 0xc2e8 is called.
|
||||
After passing checks to know exactly when to trigger
|
||||
(specifically, after the boss is defeated and the
|
||||
power-up animation is finishes), 0xc350 checks if
|
||||
0xffdc45 is 5. If it is, then we reach 0xc368, which
|
||||
0xc368 sets 0xffe08e to 0x27. Again the failure is
|
||||
not obvious at this point.
|
||||
|
||||
0xffe08e is checked during player respawn after
|
||||
losing a life or continuing at 0x16d00, with an
|
||||
explicit compare against 0x27, if this condition is
|
||||
met, then the game will intentionally corrupt memory
|
||||
and crash.
|
||||
|
||||
Many of these checks are done with obfuscated code
|
||||
to hide the target addresses eg.
|
||||
|
||||
writing 0x27 to 0xffe08e
|
||||
00C35C: lea $ffc92b.l, A4
|
||||
00C362: adda.l #$1763, A4
|
||||
00C368: move.b #$27, (A4)
|
||||
|
||||
This makes it more difficult to find where the checks
|
||||
are being performed as an additional layer of
|
||||
security
|
||||
|
||||
Squash has a similar timing loop, but with the
|
||||
expected values adjusted due to the different 68000
|
||||
clock on the otherwise identical Squash PCB (10Mhz on
|
||||
Squash vs. 12Mhz on Thunder Hoop) In the case of
|
||||
Squash the most obvious sign of failure is bad
|
||||
'Insert Coin' sprites at the bottom of the screen
|
||||
after a continue.
|
||||
|
||||
A refresh rate of 57.42, while not yet accurately
|
||||
measured, allows a video of thoop to stay in sync with
|
||||
MAME over a 10 minute period.
|
||||
|
||||
No checks have been observed in Biomechanical Toy,
|
||||
the Maniac Square prototype, or the Last KM prototype.
|
||||
|
||||
Big Karnak runs on a different board type and does fail
|
||||
if the CPU clock is set to 10Mhz rather than 12Mhz, it
|
||||
also has additional checks which may still fail and
|
||||
need more extensive research to determine exactly what
|
||||
is being timed.
|
||||
|
||||
***************************************************************************/
|
||||
|
||||
#include "emu.h"
|
||||
#include "includes/gaelco.h"
|
||||
|
||||
#include "includes/gaelcrpt.h"
|
||||
|
||||
#include "cpu/m6809/m6809.h"
|
||||
#include "cpu/m68000/m68000.h"
|
||||
#include "sound/okim6295.h"
|
||||
@ -88,7 +144,7 @@ void gaelco_state::irqack_w(uint16_t data)
|
||||
void gaelco_state::vram_encrypted_w(offs_t offset, uint16_t data, uint16_t mem_mask)
|
||||
{
|
||||
// osd_printf_debug("vram_encrypted_w!!\n");
|
||||
data = gaelco_decrypt(*m_maincpu, offset, data, 0x0f, 0x4228);
|
||||
data = m_vramcrypt->gaelco_decrypt(*m_maincpu, offset, data);
|
||||
vram_w(offset, data, mem_mask);
|
||||
}
|
||||
|
||||
@ -96,23 +152,7 @@ void gaelco_state::vram_encrypted_w(offs_t offset, uint16_t data, uint16_t mem_m
|
||||
void gaelco_state::encrypted_w(offs_t offset, uint16_t data, uint16_t mem_mask)
|
||||
{
|
||||
// osd_printf_debug("encrypted_w!!\n");
|
||||
data = gaelco_decrypt(*m_maincpu, offset, data, 0x0f, 0x4228);
|
||||
COMBINE_DATA(&m_screenram[offset]);
|
||||
}
|
||||
|
||||
/*********** Thunder Hoop Encryption Related Code ******************/
|
||||
|
||||
void gaelco_state::thoop_vram_encrypted_w(offs_t offset, uint16_t data, uint16_t mem_mask)
|
||||
{
|
||||
// osd_printf_debug("vram_encrypted_w!!\n");
|
||||
data = gaelco_decrypt(*m_maincpu, offset, data, 0x0e, 0x4228);
|
||||
vram_w(offset, data, mem_mask);
|
||||
}
|
||||
|
||||
void gaelco_state::thoop_encrypted_w(offs_t offset, uint16_t data, uint16_t mem_mask)
|
||||
{
|
||||
// osd_printf_debug("encrypted_w!!\n");
|
||||
data = gaelco_decrypt(*m_maincpu, offset, data, 0x0e, 0x4228);
|
||||
data = m_vramcrypt->gaelco_decrypt(*m_maincpu, offset, data);
|
||||
COMBINE_DATA(&m_screenram[offset]);
|
||||
}
|
||||
|
||||
@ -191,8 +231,8 @@ void gaelco_state::squash_map(address_map &map)
|
||||
void gaelco_state::thoop_map(address_map &map)
|
||||
{
|
||||
map(0x000000, 0x0fffff).rom(); // ROM
|
||||
map(0x100000, 0x101fff).ram().w(FUNC(gaelco_state::thoop_vram_encrypted_w)).share("videoram"); // Video RAM
|
||||
map(0x102000, 0x103fff).ram().w(FUNC(gaelco_state::thoop_encrypted_w)).share("screenram"); // Screen RAM
|
||||
map(0x100000, 0x101fff).ram().w(FUNC(gaelco_state::vram_encrypted_w)).share("videoram"); // Video RAM
|
||||
map(0x102000, 0x103fff).ram().w(FUNC(gaelco_state::encrypted_w)).share("screenram"); // Screen RAM
|
||||
map(0x108000, 0x108007).writeonly().share("vregs"); // Video Registers
|
||||
map(0x10800c, 0x10800d).w(FUNC(gaelco_state::irqack_w)); // INT 6 ACK/Watchdog timer
|
||||
map(0x200000, 0x2007ff).ram().w(m_palette, FUNC(palette_device::write16)).share("palette"); // Palette
|
||||
@ -707,7 +747,7 @@ void gaelco_state::maniacsq(machine_config &config)
|
||||
|
||||
// Video hardware
|
||||
screen_device &screen(SCREEN(config, "screen", SCREEN_TYPE_RASTER));
|
||||
screen.set_refresh_hz(60);
|
||||
screen.set_refresh_hz(FRAMERATE_922804);
|
||||
screen.set_vblank_time(ATTOSECONDS_IN_USEC(2500) /* not accurate */);
|
||||
screen.set_size(32*16, 32*16);
|
||||
screen.set_visarea(0, 320-1, 16, 256-1);
|
||||
@ -736,6 +776,9 @@ void gaelco_state::squash(machine_config &config)
|
||||
|
||||
config.set_maximum_quantum(attotime::from_hz(600));
|
||||
|
||||
GAELCO_VRAM_ENCRYPTION(config, m_vramcrypt);
|
||||
m_vramcrypt->set_params(0x0f, 0x4228);
|
||||
|
||||
LS259(config, m_outlatch); // B8
|
||||
m_outlatch->q_out_cb<0>().set(FUNC(gaelco_state::coin1_lockout_w)).invert();
|
||||
m_outlatch->q_out_cb<1>().set(FUNC(gaelco_state::coin2_lockout_w)).invert();
|
||||
@ -745,7 +788,7 @@ void gaelco_state::squash(machine_config &config)
|
||||
|
||||
// Video hardware
|
||||
screen_device &screen(SCREEN(config, "screen", SCREEN_TYPE_RASTER));
|
||||
screen.set_refresh_hz(58);
|
||||
screen.set_refresh_hz(FRAMERATE_922804);
|
||||
screen.set_vblank_time(ATTOSECONDS_IN_USEC(2500) /* not accurate */);
|
||||
screen.set_size(32*16, 32*16);
|
||||
screen.set_visarea(0, 320-1, 16, 256-1);
|
||||
@ -774,6 +817,9 @@ void gaelco_state::thoop(machine_config &config)
|
||||
|
||||
config.set_maximum_quantum(attotime::from_hz(600));
|
||||
|
||||
GAELCO_VRAM_ENCRYPTION(config, m_vramcrypt);
|
||||
m_vramcrypt->set_params(0x0e, 0x4228);
|
||||
|
||||
LS259(config, m_outlatch); // B8
|
||||
m_outlatch->q_out_cb<0>().set(FUNC(gaelco_state::coin1_lockout_w)); // not inverted
|
||||
m_outlatch->q_out_cb<1>().set(FUNC(gaelco_state::coin2_lockout_w)); // not inverted
|
||||
@ -783,7 +829,7 @@ void gaelco_state::thoop(machine_config &config)
|
||||
|
||||
// Video hardware
|
||||
screen_device &screen(SCREEN(config, "screen", SCREEN_TYPE_RASTER));
|
||||
screen.set_refresh_hz(60);
|
||||
screen.set_refresh_hz(FRAMERATE_922804);
|
||||
screen.set_vblank_time(ATTOSECONDS_IN_USEC(2500) /* not accurate */);
|
||||
screen.set_size(32*16, 32*16);
|
||||
screen.set_visarea(0, 320-1, 16, 256-1);
|
||||
@ -1184,6 +1230,6 @@ GAME( 1995, biomtoyb, biomtoy, maniacsq, biomtoy, gaelco_state, empty_init, RO
|
||||
GAME( 1994, biomtoyc, biomtoy, maniacsq, biomtoyc, gaelco_state, empty_init, ROT0, "Gaelco", "Biomechanical Toy (Ver. 1.0.1870)", MACHINE_SUPPORTS_SAVE )
|
||||
GAME( 1994, bioplayc, biomtoy, maniacsq, bioplayc, gaelco_state, empty_init, ROT0, "Gaelco", "Bioplaything Cop (Ver. 1.0.1823, prototype)", MACHINE_SUPPORTS_SAVE | MACHINE_IMPERFECT_SOUND ) // copyright based on Ver. 1.0.1870
|
||||
GAME( 1992, maniacsp, 0, maniacsq, maniacsq, gaelco_state, empty_init, ROT0, "Gaelco", "Maniac Square (prototype)", MACHINE_SUPPORTS_SAVE ) // The prototype version was an earlier project, said to be from 1992, game was rewritten in 1996
|
||||
GAME( 1995, lastkm, 0, maniacsq, lastkm, gaelco_state, empty_init, ROT0, "Gaelco", "Last KM (Ver 1.0.0275)", MACHINE_SUPPORTS_SAVE ) // used on 'Salter' exercise bikes
|
||||
GAME( 1995, lastkm, 0, maniacsq, lastkm, gaelco_state, empty_init, ROT0, "Gaelco", "Last KM (Ver 1.0.0275, prototype)", MACHINE_SUPPORTS_SAVE ) // Similar 'bike controller' idea to the Salter gym equipment Gaelco developed, but in game form
|
||||
GAME( 1992, squash, 0, squash, squash, gaelco_state, empty_init, ROT0, "Gaelco", "Squash (Ver. 1.0)", MACHINE_SUPPORTS_SAVE )
|
||||
GAME( 1992, thoop, 0, thoop, thoop, gaelco_state, empty_init, ROT0, "Gaelco", "Thunder Hoop (Ver. 1, Checksum 02A09F7D)", MACHINE_SUPPORTS_SAVE | MACHINE_NOT_WORKING ) // could be other versions, still Ver. 1 but different checksum listed on boot
|
||||
GAME( 1992, thoop, 0, thoop, thoop, gaelco_state, empty_init, ROT0, "Gaelco", "Thunder Hoop (Ver. 1, Checksum 02A09F7D)", MACHINE_SUPPORTS_SAVE ) // could be other versions, still Ver. 1 but different checksum listed on boot
|
||||
|
@ -2722,10 +2722,10 @@ GAME( 1994, aligatorun, aligator, alighunt, alighunt, gaelco2_state, i
|
||||
GAME( 1994, aligatoruna, aligator, alighunt, alighunt, gaelco2_state, init_alighunt, ROT0, "Gaelco", "Alligator Hunt (unprotected, set 2)", 0 ) // strange version, starts on space stages, but clearly a recompile not a trivial hack of the above, show version maybe?
|
||||
GAME( 1994, aligatorp, aligator, alighunt_d5002fp, alighunt, gaelco2_state, empty_init, ROT0, "Gaelco", "Alligator Hunt (protected, prototype?)", MACHINE_NOT_WORKING ) // requires different protection program / data
|
||||
|
||||
GAME( 1995, touchgo, 0, touchgo_d5002fp, touchgo, gaelco2_state, init_touchgo, ROT0, "Gaelco", "Touch & Go (World)", MACHINE_IMPERFECT_SOUND )
|
||||
GAME( 1995, touchgon, touchgo, touchgo_d5002fp, touchgo, gaelco2_state, init_touchgo, ROT0, "Gaelco", "Touch & Go (Non North America)", MACHINE_IMPERFECT_SOUND )
|
||||
GAME( 1995, touchgoe, touchgo, touchgo_d5002fp, touchgo, gaelco2_state, init_touchgo, ROT0, "Gaelco", "Touch & Go (earlier revision)", MACHINE_IMPERFECT_SOUND )
|
||||
GAME( 1995, touchgok, touchgo, touchgo, touchgo, gaelco2_state, init_touchgo, ROT0, "Gaelco", "Touch & Go (Korea, unprotected)", MACHINE_IMPERFECT_SOUND ) // doesn't say 'Korea' but was sourced there, shows 2 copyright lines like the 'earlier revision'
|
||||
GAME( 1995, touchgo, 0, touchgo_d5002fp, touchgo, gaelco2_state, init_touchgo, ROT0, "Gaelco", "Touch & Go (World)", 0 )
|
||||
GAME( 1995, touchgon, touchgo, touchgo_d5002fp, touchgo, gaelco2_state, init_touchgo, ROT0, "Gaelco", "Touch & Go (Non North America)", 0 )
|
||||
GAME( 1995, touchgoe, touchgo, touchgo_d5002fp, touchgo, gaelco2_state, init_touchgo, ROT0, "Gaelco", "Touch & Go (earlier revision)", 0 )
|
||||
GAME( 1995, touchgok, touchgo, touchgo, touchgo, gaelco2_state, init_touchgo, ROT0, "Gaelco", "Touch & Go (Korea, unprotected)", 0 ) // doesn't say 'Korea' but was sourced there, shows 2 copyright lines like the 'earlier revision'
|
||||
|
||||
GAME( 1995, wrally2, 0, wrally2, wrally2, wrally2_state, init_wrally2, ROT0, "Gaelco", "World Rally 2: Twin Racing (mask ROM version)", 0 )
|
||||
GAME( 1995, wrally2a, wrally2, wrally2, wrally2, wrally2_state, empty_init, ROT0, "Gaelco", "World Rally 2: Twin Racing (EPROM version)", 0 )
|
||||
|
@ -126,7 +126,6 @@ The PCB has a layout that can either use the 4 rom set of I7, I9, I11 & I13 or l
|
||||
|
||||
#include "emu.h"
|
||||
#include "includes/wrally.h"
|
||||
#include "includes/gaelcrpt.h"
|
||||
|
||||
#include "machine/gaelco_ds5002fp.h"
|
||||
|
||||
@ -167,7 +166,7 @@ uint8_t wrally_state::shareram_r(offs_t offset)
|
||||
|
||||
void wrally_state::vram_w(offs_t offset, uint16_t data, uint16_t mem_mask)
|
||||
{
|
||||
data = gaelco_decrypt(*m_maincpu, offset, data, 0x1f, 0x522a);
|
||||
data = m_vramcrypt->gaelco_decrypt(*m_maincpu, offset, data);
|
||||
COMBINE_DATA(&m_videoram[offset]);
|
||||
|
||||
m_tilemap[(offset & 0x1fff) >> 12]->mark_tile_dirty(((offset << 1) & 0x1fff) >> 2);
|
||||
@ -376,6 +375,9 @@ void wrally_state::wrally(machine_config &config)
|
||||
ds5002.set_addrmap(0, &wrally_state::mcu_hostmem_map);
|
||||
config.set_perfect_quantum("gaelco_ds5002fp:mcu");
|
||||
|
||||
GAELCO_VRAM_ENCRYPTION(config, m_vramcrypt);
|
||||
m_vramcrypt->set_params(0x1f, 0x522a);
|
||||
|
||||
// Video hardware
|
||||
screen_device &screen(SCREEN(config, "screen", SCREEN_TYPE_RASTER));
|
||||
screen.set_refresh_hz(60);
|
||||
|
@ -8,6 +8,7 @@
|
||||
|
||||
#include "machine/gen_latch.h"
|
||||
#include "machine/74259.h"
|
||||
#include "machine/gaelcrpt.h"
|
||||
#include "emupal.h"
|
||||
#include "tilemap.h"
|
||||
|
||||
@ -19,6 +20,7 @@ public:
|
||||
m_maincpu(*this, "maincpu"),
|
||||
m_gfxdecode(*this, "gfxdecode"),
|
||||
m_palette(*this, "palette"),
|
||||
m_vramcrypt(*this, "vramcrypt"),
|
||||
m_audiocpu(*this, "audiocpu"),
|
||||
m_soundlatch(*this, "soundlatch"),
|
||||
m_outlatch(*this, "outlatch"),
|
||||
@ -40,6 +42,7 @@ private:
|
||||
required_device<cpu_device> m_maincpu;
|
||||
required_device<gfxdecode_device> m_gfxdecode;
|
||||
required_device<palette_device> m_palette;
|
||||
optional_device<gaelco_vram_encryption_device> m_vramcrypt;
|
||||
optional_device<cpu_device> m_audiocpu;
|
||||
optional_device<generic_latch_8_device> m_soundlatch;
|
||||
optional_device<ls259_device> m_outlatch;
|
||||
@ -61,8 +64,6 @@ private:
|
||||
void oki_bankswitch_w(uint8_t data);
|
||||
void vram_encrypted_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0);
|
||||
void encrypted_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0);
|
||||
void thoop_vram_encrypted_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0);
|
||||
void thoop_encrypted_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0);
|
||||
void vram_w(offs_t offset, u16 data, u16 mem_mask);
|
||||
void irqack_w(uint16_t data);
|
||||
|
||||
@ -87,4 +88,6 @@ private:
|
||||
|
||||
/* per-game configuration */
|
||||
uint8_t m_sprite_palette_force_high;
|
||||
|
||||
static constexpr double FRAMERATE_922804 = 57.42;
|
||||
};
|
||||
|
@ -1,5 +0,0 @@
|
||||
// license:BSD-3-Clause
|
||||
// copyright-holders:Manuel Abadia
|
||||
/*----------- defined in machine/gaelcrpt.cpp -----------*/
|
||||
|
||||
uint16_t gaelco_decrypt(cpu_device &cpu, int offset, int data, int param1, int param2);
|
@ -6,6 +6,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "machine/74259.h"
|
||||
#include "machine/gaelcrpt.h"
|
||||
#include "video/gaelco_wrally_sprites.h"
|
||||
#include "emupal.h"
|
||||
#include "tilemap.h"
|
||||
@ -21,6 +22,7 @@ public:
|
||||
m_palette(*this, "palette"),
|
||||
m_sprites(*this, "sprites"),
|
||||
m_okibank(*this, "okibank"),
|
||||
m_vramcrypt(*this, "vramcrypt"),
|
||||
m_videoram(*this, "videoram"),
|
||||
m_vregs(*this, "vregs"),
|
||||
m_spriteram(*this, "spriteram"),
|
||||
@ -66,6 +68,7 @@ private:
|
||||
required_device<palette_device> m_palette;
|
||||
required_device<gaelco_wrally_sprites_device> m_sprites;
|
||||
required_memory_bank m_okibank;
|
||||
required_device<gaelco_vram_encryption_device> m_vramcrypt;
|
||||
|
||||
required_shared_ptr<uint16_t> m_videoram;
|
||||
required_shared_ptr<uint16_t> m_vregs;
|
||||
|
@ -6,12 +6,27 @@ Gaelco video RAM encryption
|
||||
|
||||
Thanks to GAELCO SA for information on the algorithm.
|
||||
|
||||
TODO: the device must be able to know a 32-bit write was from the same
|
||||
opcode WITHOUT looking at the host program counter.
|
||||
|
||||
*/
|
||||
|
||||
#include "emu.h"
|
||||
#include "includes/gaelcrpt.h"
|
||||
#include "gaelcrpt.h"
|
||||
|
||||
static int decrypt(int const param1, int const param2, int const enc_prev_word, int const dec_prev_word, int const enc_word)
|
||||
DEFINE_DEVICE_TYPE(GAELCO_VRAM_ENCRYPTION, gaelco_vram_encryption_device, "gaelco_vram_crypt", "Gaelco VRAM Encryption")
|
||||
|
||||
|
||||
gaelco_vram_encryption_device::gaelco_vram_encryption_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
|
||||
: device_t(mconfig, GAELCO_VRAM_ENCRYPTION, tag, owner, clock),
|
||||
m_param1(0),
|
||||
m_param2(0)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
int gaelco_vram_encryption_device::decrypt(int const enc_prev_word, int const dec_prev_word, int const enc_word)
|
||||
{
|
||||
int const swap = (BIT(dec_prev_word, 8) << 1) | BIT(dec_prev_word, 7);
|
||||
int const type = (BIT(dec_prev_word,12) << 1) | BIT(dec_prev_word, 2);
|
||||
@ -26,7 +41,7 @@ static int decrypt(int const param1, int const param2, int const enc_prev_word,
|
||||
case 3: res = bitswap<16>(enc_word, 3, 8, 1,13,14, 4,15, 0,10, 2, 7,12, 6,11, 9, 5); break;
|
||||
}
|
||||
|
||||
res ^= param2;
|
||||
res ^= m_param2;
|
||||
|
||||
switch (type)
|
||||
{
|
||||
@ -67,11 +82,11 @@ static int decrypt(int const param1, int const param2, int const enc_prev_word,
|
||||
break;
|
||||
}
|
||||
|
||||
k ^= param1;
|
||||
k ^= m_param1;
|
||||
|
||||
res = (res & 0xffc0) | ((res + k) & 0x003f);
|
||||
|
||||
res ^= param1;
|
||||
res ^= m_param1;
|
||||
|
||||
switch (type)
|
||||
{
|
||||
@ -109,46 +124,57 @@ static int decrypt(int const param1, int const param2, int const enc_prev_word,
|
||||
break;
|
||||
}
|
||||
|
||||
k ^= param1;
|
||||
k ^= m_param1;
|
||||
|
||||
res = (res & 0x003f) |
|
||||
((res + (k << 6)) & 0x07c0) |
|
||||
((res + (k << 11)) & 0xf800);
|
||||
|
||||
res ^= (param1 << 6) | (param1 << 11);
|
||||
res ^= (m_param1 << 6) | (m_param1 << 11);
|
||||
|
||||
return bitswap<16>(res, 2,6,0,11,14,12,7,10,5,4,8,3,9,1,13,15);
|
||||
}
|
||||
|
||||
|
||||
|
||||
uint16_t gaelco_decrypt(cpu_device &cpu, int offset, int data, int param1, int param2)
|
||||
uint16_t gaelco_vram_encryption_device::gaelco_decrypt(cpu_device &cpu, int offset, int data)
|
||||
{
|
||||
static int lastpc, lastoffset, lastencword, lastdecword;
|
||||
|
||||
int thispc = cpu.pc();
|
||||
// int savedata = data;
|
||||
|
||||
/* check if 2nd half of 32 bit */
|
||||
if(lastpc == thispc && offset == lastoffset + 1)
|
||||
if(m_lastpc == thispc && offset == m_lastoffset + 1)
|
||||
{
|
||||
lastpc = 0;
|
||||
data = decrypt(param1, param2, lastencword, lastdecword, data);
|
||||
m_lastpc = 0;
|
||||
data = decrypt(m_lastencword, m_lastdecword, data);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* code as 1st word */
|
||||
|
||||
lastpc = thispc;
|
||||
lastoffset = offset;
|
||||
lastencword = data;
|
||||
m_lastpc = thispc;
|
||||
m_lastoffset = offset;
|
||||
m_lastencword = data;
|
||||
|
||||
/* high word returned */
|
||||
data = decrypt(param1, param2, 0, 0, data);
|
||||
data = decrypt(0, 0, data);
|
||||
|
||||
lastdecword = data;
|
||||
m_lastdecword = data;
|
||||
|
||||
// logerror("%s : data1 = %4x > %4x @ %8x\n",machine().describe_context(),savedata,data,lastoffset);
|
||||
// logerror("%s : data1 = %4x > %4x @ %8x\n",machine().describe_context(),savedata,data,m_lastoffset);
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
void gaelco_vram_encryption_device::device_start()
|
||||
{
|
||||
save_item(NAME(m_lastpc));
|
||||
save_item(NAME(m_lastoffset));
|
||||
save_item(NAME(m_lastencword));
|
||||
save_item(NAME(m_lastdecword));
|
||||
}
|
||||
|
||||
void gaelco_vram_encryption_device::device_reset()
|
||||
{
|
||||
m_lastpc = m_lastoffset = m_lastencword = m_lastdecword = -1;
|
||||
}
|
||||
|
35
src/mame/machine/gaelcrpt.h
Normal file
35
src/mame/machine/gaelcrpt.h
Normal file
@ -0,0 +1,35 @@
|
||||
// license:BSD-3-Clause
|
||||
// copyright-holders:Manuel Abadia
|
||||
|
||||
#ifndef MAME_MACHINE_GAELCRPT_H
|
||||
#define MAME_MACHINE_GAELCRPT_H
|
||||
|
||||
#pragma once
|
||||
|
||||
DECLARE_DEVICE_TYPE(GAELCO_VRAM_ENCRYPTION, gaelco_vram_encryption_device)
|
||||
|
||||
|
||||
class gaelco_vram_encryption_device : public device_t
|
||||
{
|
||||
public:
|
||||
// construction/destruction
|
||||
gaelco_vram_encryption_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0);
|
||||
void set_params(uint8_t param1, uint16_t param2) { m_param1 = param1; m_param2 = param2; }
|
||||
|
||||
uint16_t gaelco_decrypt(cpu_device &cpu, int offset, int data);
|
||||
|
||||
protected:
|
||||
virtual void device_start() override;
|
||||
virtual void device_reset() override;
|
||||
|
||||
private:
|
||||
int decrypt(int const enc_prev_word, int const dec_prev_word, int const enc_word);
|
||||
|
||||
int32_t m_lastpc, m_lastoffset, m_lastencword, m_lastdecword;
|
||||
|
||||
// config
|
||||
uint8_t m_param1;
|
||||
uint16_t m_param2;
|
||||
};
|
||||
|
||||
#endif // MAME_MACHINE_GAELCRPT_H
|
@ -8,8 +8,12 @@
|
||||
|
||||
TODO:
|
||||
verify priority implementations
|
||||
understand bad sprites in Squash after the continue screen, these do not
|
||||
occur on real hardware.
|
||||
|
||||
NOTE:
|
||||
if Squash fails a protection check it will leave bad 'Insert Coin' text
|
||||
on the screen after a continue, this is not a sprite emulation bug, the
|
||||
machine expects a 68k clock of around 10Mhz and a refresh of around 57.4
|
||||
to pass the protection, see notes in main driver file.
|
||||
|
||||
***************************************************************************/
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user