summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
author David Haywood <28625134+DavidHaywood@users.noreply.github.com>2021-12-14 14:30:33 +0000
committer GitHub <noreply@github.com>2021-12-14 15:30:33 +0100
commitedc0dfb6272720e483be72352629a653492a00bf (patch)
treeb4908f575e8474f9cfcf3f78110da1c07d27afbb
parent45710aacf1c056cc930ec44df934f8f17dc077b7 (diff)
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
-rw-r--r--scripts/target/mame/arcade.lua2
-rw-r--r--src/devices/cpu/mcs51/mcs51.cpp33
-rw-r--r--src/devices/cpu/mcs51/mcs51.h6
-rw-r--r--src/devices/sound/gaelco.cpp15
-rw-r--r--src/devices/sound/gaelco.h7
-rw-r--r--src/mame/drivers/gaelco.cpp120
-rw-r--r--src/mame/drivers/gaelco2.cpp8
-rw-r--r--src/mame/drivers/wrally.cpp6
-rw-r--r--src/mame/includes/gaelco.h7
-rw-r--r--src/mame/includes/gaelcrpt.h5
-rw-r--r--src/mame/includes/wrally.h3
-rw-r--r--src/mame/machine/gaelcrpt.cpp64
-rw-r--r--src/mame/machine/gaelcrpt.h35
-rw-r--r--src/mame/video/gaelco.cpp8
14 files changed, 242 insertions, 77 deletions
diff --git a/scripts/target/mame/arcade.lua b/scripts/target/mame/arcade.lua
index 98d2bf30bd5..399b5912f25 100644
--- a/scripts/target/mame/arcade.lua
+++ b/scripts/target/mame/arcade.lua
@@ -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",
diff --git a/src/devices/cpu/mcs51/mcs51.cpp b/src/devices/cpu/mcs51/mcs51.cpp
index 2e963cec1b7..f9e9afc1470 100644
--- a/src/devices/cpu/mcs51/mcs51.cpp
+++ b/src/devices/cpu/mcs51/mcs51.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 */
diff --git a/src/devices/cpu/mcs51/mcs51.h b/src/devices/cpu/mcs51/mcs51.h
index c3470d075e4..d13ce60ab66 100644
--- a/src/devices/cpu/mcs51/mcs51.h
+++ b/src/devices/cpu/mcs51/mcs51.h
@@ -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;
};
diff --git a/src/devices/sound/gaelco.cpp b/src/devices/sound/gaelco.cpp
index 2fd45bfe6f9..62553b44413 100644
--- a/src/devices/sound/gaelco.cpp
+++ b/src/devices/sound/gaelco.cpp
@@ -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()
diff --git a/src/devices/sound/gaelco.h b/src/devices/sound/gaelco.h
index 2d0180e290f..349a2a1071b 100644
--- a/src/devices/sound/gaelco.h
+++ b/src/devices/sound/gaelco.h
@@ -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)
diff --git a/src/mame/drivers/gaelco.cpp b/src/mame/drivers/gaelco.cpp
index 31247c79bde..55d6a421674 100644
--- a/src/mame/drivers/gaelco.cpp
+++ b/src/mame/drivers/gaelco.cpp
@@ -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
diff --git a/src/mame/drivers/gaelco2.cpp b/src/mame/drivers/gaelco2.cpp
index c0b17c8a2c5..51dc2c9f610 100644
--- a/src/mame/drivers/gaelco2.cpp
+++ b/src/mame/drivers/gaelco2.cpp
@@ -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 )
diff --git a/src/mame/drivers/wrally.cpp b/src/mame/drivers/wrally.cpp
index 86245961faa..c8503826455 100644
--- a/src/mame/drivers/wrally.cpp
+++ b/src/mame/drivers/wrally.cpp
@@ -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);
diff --git a/src/mame/includes/gaelco.h b/src/mame/includes/gaelco.h
index 487188b671a..5d8ce7ad409 100644
--- a/src/mame/includes/gaelco.h
+++ b/src/mame/includes/gaelco.h
@@ -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;
};
diff --git a/src/mame/includes/gaelcrpt.h b/src/mame/includes/gaelcrpt.h
deleted file mode 100644
index e699263d7bd..00000000000
--- a/src/mame/includes/gaelcrpt.h
+++ /dev/null
@@ -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);
diff --git a/src/mame/includes/wrally.h b/src/mame/includes/wrally.h
index ad964279361..ce16874af5e 100644
--- a/src/mame/includes/wrally.h
+++ b/src/mame/includes/wrally.h
@@ -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;
diff --git a/src/mame/machine/gaelcrpt.cpp b/src/mame/machine/gaelcrpt.cpp
index ba7abfa66e6..786baf00c6f 100644
--- a/src/mame/machine/gaelcrpt.cpp
+++ b/src/mame/machine/gaelcrpt.cpp
@@ -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"
+
+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)
+{
+}
+
+
-static int decrypt(int const param1, int const param2, int const enc_prev_word, int const dec_prev_word, int const enc_word)
+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;
+}
diff --git a/src/mame/machine/gaelcrpt.h b/src/mame/machine/gaelcrpt.h
new file mode 100644
index 00000000000..c3d71374a4c
--- /dev/null
+++ b/src/mame/machine/gaelcrpt.h
@@ -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
diff --git a/src/mame/video/gaelco.cpp b/src/mame/video/gaelco.cpp
index 4db6543e04e..4b6fba30585 100644
--- a/src/mame/video/gaelco.cpp
+++ b/src/mame/video/gaelco.cpp
@@ -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.
***************************************************************************/