kangaroo: hook up protection mcu,

mb88xx: increment timer when taking irq cycles
This commit is contained in:
hap 2024-12-03 01:52:23 +01:00
parent a50e1f8792
commit bfb725374d
7 changed files with 214 additions and 171 deletions

View File

@ -63,8 +63,6 @@ DEFINE_DEVICE_TYPE(MB8844, mb8844_cpu_device, "mb8844", "Fujitsu MB8844")
#define UPDATE_CF(v) m_cf = ((v & 0x10) == 0) ? 0 : 1
#define UPDATE_ZF(v) m_zf = (v != 0) ? 0 : 1
#define CYCLES(x) do { m_icount -= (x); } while (0)
#define GETPC() (((int)m_PA << 6) + m_PC)
#define GETEA() ((m_X << 4) + m_Y)
@ -217,7 +215,8 @@ void mb88_cpu_device::device_start()
save_item(NAME(m_ctr));
save_item(NAME(m_SB));
save_item(NAME(m_SBcount));
save_item(NAME(m_pending_interrupt));
save_item(NAME(m_o_output));
save_item(NAME(m_pending_irq));
save_item(NAME(m_in_irq));
state_add(MB88_PC, "PC", m_PC).formatstr("%02X");
@ -322,7 +321,7 @@ void mb88_cpu_device::device_reset()
m_TP = 0;
m_SB = 0;
m_SBcount = 0;
m_pending_interrupt = 0;
m_pending_irq = 0;
m_in_irq = 0;
}
@ -347,7 +346,7 @@ TIMER_CALLBACK_MEMBER(mb88_cpu_device::serial_timer)
if (m_SBcount >= 4)
{
m_sf = 1;
m_pending_interrupt |= INT_CAUSE_SERIAL;
m_pending_irq |= INT_CAUSE_SERIAL;
}
}
}
@ -380,13 +379,13 @@ void mb88_cpu_device::execute_set_input(int inputnum, int state)
// Note this is a logical level, the actual pin is high-to-low voltage triggered.
if ((m_pio & INT_CAUSE_EXTERNAL) && !m_if && state != CLEAR_LINE)
{
m_pending_interrupt |= INT_CAUSE_EXTERNAL;
m_pending_irq |= INT_CAUSE_EXTERNAL;
}
m_if = state != CLEAR_LINE;
}
void mb88_cpu_device::update_pio_enable(u8 newpio)
void mb88_cpu_device::pio_enable(u8 newpio)
{
// if the serial state has changed, configure the timer
if ((m_pio ^ newpio) & 0x30)
@ -396,7 +395,7 @@ void mb88_cpu_device::update_pio_enable(u8 newpio)
else if ((newpio & 0x30) == 0x20)
m_serial->adjust(attotime::from_hz(clock() / SERIAL_PRESCALE), 0, attotime::from_hz(clock() / SERIAL_PRESCALE));
else
fatalerror("mb88xx: update_pio_enable set serial enable to unsupported value %02X\n", newpio & 0x30);
fatalerror("mb88xx: pio_enable set serial enable to unsupported value %02X\n", newpio & 0x30);
}
m_pio = newpio;
@ -411,14 +410,15 @@ void mb88_cpu_device::increment_timer()
if (m_TH == 0)
{
m_vf = 1;
m_pending_interrupt |= INT_CAUSE_TIMER;
m_pending_irq |= INT_CAUSE_TIMER;
}
}
}
void mb88_cpu_device::update_pio(int cycles)
void mb88_cpu_device::burn_cycles(int cycles)
{
// TODO: improve/validate serial and timer support
m_icount -= cycles;
// internal clock enable
if (m_pio & 0x80)
@ -432,7 +432,7 @@ void mb88_cpu_device::update_pio(int cycles)
}
// process pending interrupts
if (!m_in_irq && m_pending_interrupt & m_pio)
if (!m_in_irq && m_pending_irq & m_pio)
{
m_in_irq = true;
u16 intpc = GETPC();
@ -444,18 +444,18 @@ void mb88_cpu_device::update_pio(int cycles)
m_SI = (m_SI + 1) & 3;
// the datasheet doesn't mention interrupt vectors but the Arabian MCU program expects the following
if (m_pending_interrupt & m_pio & INT_CAUSE_EXTERNAL)
if (m_pending_irq & m_pio & INT_CAUSE_EXTERNAL)
{
// if we have a live external source, call the irqcallback
standard_irq_callback(0, intpc);
m_PC = 0x02;
}
else if (m_pending_interrupt & m_pio & INT_CAUSE_TIMER)
else if (m_pending_irq & m_pio & INT_CAUSE_TIMER)
{
standard_irq_callback(1, intpc);
m_PC = 0x04;
}
else if (m_pending_interrupt & m_pio & INT_CAUSE_SERIAL)
else if (m_pending_irq & m_pio & INT_CAUSE_SERIAL)
{
standard_irq_callback(2, intpc);
m_PC = 0x06;
@ -463,9 +463,9 @@ void mb88_cpu_device::update_pio(int cycles)
m_PA = 0x00;
m_st = 1;
m_pending_interrupt = 0;
m_pending_irq = 0;
CYCLES(3); // ?
burn_cycles(3); // ?
}
}
@ -842,21 +842,21 @@ void mb88_cpu_device::execute_run()
case 0x3d: // jpa imm ZCS:..x
m_PA = READOP(GETPC()) & 0x1f;
m_PC = m_A * 4;
oc = 2;
oc++;
m_st = 1;
break;
case 0x3e: // en imm ZCS:...
update_pio_enable(m_pio | READOP(GETPC()));
pio_enable(m_pio | READOP(GETPC()));
INCPC();
oc = 2;
oc++;
m_st = 1;
break;
case 0x3f: // dis imm ZCS:...
update_pio_enable(m_pio & ~(READOP(GETPC())));
pio_enable(m_pio & ~(READOP(GETPC())));
INCPC();
oc = 2;
oc++;
m_st = 1;
break;
@ -910,7 +910,7 @@ void mb88_cpu_device::execute_run()
case 0x64: case 0x65: case 0x66: case 0x67: // call imm ZCS:..x
arg = READOP(GETPC());
INCPC();
oc = 2;
oc++;
if (TEST_ST())
{
m_SP[m_SI] = GETPC();
@ -925,7 +925,7 @@ void mb88_cpu_device::execute_run()
case 0x6c: case 0x6d: case 0x6e: case 0x6f: // jpl imm ZCS:..x
arg = READOP(GETPC());
INCPC();
oc = 2;
oc++;
if (TEST_ST())
{
m_PC = arg & 0x3f;
@ -993,10 +993,7 @@ void mb88_cpu_device::execute_run()
break;
}
// update cycle counts
CYCLES(oc);
// update interrupts, serial and timer flags
update_pio(oc);
// update cycle count, also update interrupts, serial and timer flags
burn_cycles(oc);
}
}

View File

@ -117,7 +117,7 @@ protected:
// device_execute_interface overrides
virtual u32 execute_min_cycles() const noexcept override { return 1; }
virtual u32 execute_max_cycles() const noexcept override { return 3; }
virtual u32 execute_max_cycles() const noexcept override { return 2+3; } // includes interrupt
virtual void execute_run() override;
virtual void execute_set_input(int inputnum, int state) override;
virtual u64 execute_clocks_to_cycles(u64 clocks) const noexcept override { return (clocks + 6 - 1) / 6; }
@ -181,7 +181,7 @@ private:
devcb_write_line m_write_so;
// IRQ handling
u8 m_pending_interrupt;
u8 m_pending_irq;
bool m_in_irq;
memory_access<11, 0, 0, ENDIANNESS_BIG>::cache m_cache;
@ -196,9 +196,9 @@ private:
TIMER_CALLBACK_MEMBER(serial_timer);
void write_pla(u8 index);
void update_pio_enable(u8 newpio);
void pio_enable(u8 newpio);
void increment_timer();
void update_pio(int cycles);
void burn_cycles(int cycles);
};

View File

@ -1627,11 +1627,11 @@ void coinmstr_state::init_coinmstr()
* Game Drivers *
*************************/
// YEAR NAME PARENT MACHINE INPUT STATE INIT ROT COMPANY FULLNAME FLAGS
GAME( 1985, quizmstr, 0, quizmstr, quizmstr, coinmstr_state, init_coinmstr, ROT0, "Loewen Spielautomaten", "Quizmaster (German)", MACHINE_UNEMULATED_PROTECTION )
GAME( 1987, trailblz, 0, trailblz, trailblz, coinmstr_state, init_coinmstr, ROT0, "Coinmaster", "Trail Blazer", MACHINE_UNEMULATED_PROTECTION | MACHINE_NOT_WORKING ) // or Trail Blazer 2 ?
GAME( 1989, supnudg2, 0, supnudg2, supnudg2, coinmstr_state, init_coinmstr, ROT0, "Coinmaster", "Super Nudger II - P173 (Version 5.21)", MACHINE_UNEMULATED_PROTECTION | MACHINE_NOT_WORKING )
GAME( 1990, pokeroul, 0, pokeroul, pokeroul, coinmstr_state, empty_init, ROT0, "Coinmaster", "Poker Roulette (Version 8.22)", MACHINE_NOT_WORKING )
GAME( 1985, jpcoin, 0, jpcoin, jpcoin, coinmstr_state, empty_init, ROT0, "Coinmaster", "Joker Poker (Coinmaster set 1)", 0 )
GAME( 1990, jpcoin2, 0, jpcoin, jpcoin, coinmstr_state, empty_init, ROT0, "Coinmaster", "Joker Poker (Coinmaster, Amusement Only)", 0 )
GAME( 1988, jpjcoin, 0, jpjcoin, jpcoin, coinmstr_state, empty_init, ROT0, "<unknown>", "Jackpot Joker Poker (Version 88V 01)", 0 )
// YEAR NAME PARENT MACHINE INPUT STATE INIT ROT COMPANY FULLNAME FLAGS
GAME( 1985, quizmstr, 0, quizmstr, quizmstr, coinmstr_state, init_coinmstr, ROT0, u8"wen Spielautomaten", "Quizmaster (German)", MACHINE_UNEMULATED_PROTECTION )
GAME( 1987, trailblz, 0, trailblz, trailblz, coinmstr_state, init_coinmstr, ROT0, "Coinmaster", "Trail Blazer", MACHINE_UNEMULATED_PROTECTION | MACHINE_NOT_WORKING ) // or Trail Blazer 2 ?
GAME( 1989, supnudg2, 0, supnudg2, supnudg2, coinmstr_state, init_coinmstr, ROT0, "Coinmaster", "Super Nudger II - P173 (Version 5.21)", MACHINE_UNEMULATED_PROTECTION | MACHINE_NOT_WORKING )
GAME( 1990, pokeroul, 0, pokeroul, pokeroul, coinmstr_state, empty_init, ROT0, "Coinmaster", "Poker Roulette (Version 8.22)", MACHINE_NOT_WORKING )
GAME( 1985, jpcoin, 0, jpcoin, jpcoin, coinmstr_state, empty_init, ROT0, "Coinmaster", "Joker Poker (Coinmaster set 1)", 0 )
GAME( 1990, jpcoin2, 0, jpcoin, jpcoin, coinmstr_state, empty_init, ROT0, "Coinmaster", "Joker Poker (Coinmaster, Amusement Only)", 0 )
GAME( 1988, jpjcoin, 0, jpjcoin, jpcoin, coinmstr_state, empty_init, ROT0, "<unknown>", "Jackpot Joker Poker (Version 88V 01)", 0 )

View File

@ -111,7 +111,7 @@ private:
void mcu_port_r1_w(uint8_t data);
void mcu_port_r2_w(uint8_t data);
void mcu_port_r3_w(uint8_t data);
uint8_t mcu_portk_r();
uint8_t mcu_port_k_r();
void mcu_port_o_w(uint8_t data);
void mcu_port_p_w(uint8_t data);
void blitter_w(offs_t offset, uint8_t data);
@ -591,7 +591,7 @@ void arabian_state::mcu_port_r3_w(uint8_t data)
m_mcu_port_r[3] = data & 0x0f;
}
uint8_t arabian_state::mcu_portk_r()
uint8_t arabian_state::mcu_port_k_r()
{
uint8_t val = 0xf;
@ -790,16 +790,16 @@ void arabian_state::arabian(machine_config &config)
m_maincpu->set_vblank_int("screen", FUNC(arabian_state::irq0_line_hold));
MB8841(config, m_mcu, MAIN_OSC / 3 / 2);
m_mcu->read_k().set(FUNC(arabian_state::mcu_portk_r));
m_mcu->read_k().set(FUNC(arabian_state::mcu_port_k_r));
m_mcu->write_o().set(FUNC(arabian_state::mcu_port_o_w));
m_mcu->write_p().set(FUNC(arabian_state::mcu_port_p_w));
m_mcu->read_r<0>().set(FUNC(arabian_state::mcu_port_r0_r));
m_mcu->write_r<0>().set(FUNC(arabian_state::mcu_port_r0_w));
m_mcu->read_r<1>().set(FUNC(arabian_state::mcu_port_r1_r));
m_mcu->write_r<1>().set(FUNC(arabian_state::mcu_port_r1_w));
m_mcu->read_r<2>().set(FUNC(arabian_state::mcu_port_r2_r));
m_mcu->write_r<2>().set(FUNC(arabian_state::mcu_port_r2_w));
m_mcu->read_r<3>().set(FUNC(arabian_state::mcu_port_r3_r));
m_mcu->write_r<0>().set(FUNC(arabian_state::mcu_port_r0_w));
m_mcu->write_r<1>().set(FUNC(arabian_state::mcu_port_r1_w));
m_mcu->write_r<2>().set(FUNC(arabian_state::mcu_port_r2_w));
m_mcu->write_r<3>().set(FUNC(arabian_state::mcu_port_r3_w));
config.set_maximum_quantum(attotime::from_hz(6000));

View File

@ -150,9 +150,9 @@
To enter test mode in Funky Fish, keep the service coin pressed while
resetting
TODO:
- There is a custom MB8841 microcontroller on the original Kangaroo board which
is not emulated. This MIGHT cause some problems, but we don't know of any.
Not counting the boot NMI trigger, apparently the only thing Kangaroo's
protection MCU does is acting like a timer to determine the intervals
of the big ape enemy appearing.
***************************************************************************/
@ -170,10 +170,10 @@
namespace {
class kangaroo_state : public driver_device
class kangaroo_base_state : public driver_device
{
public:
kangaroo_state(const machine_config &mconfig, device_type type, const char *tag) :
kangaroo_base_state(const machine_config &mconfig, device_type type, const char *tag) :
driver_device(mconfig, type, tag),
m_maincpu(*this, "maincpu"),
m_audiocpu(*this, "audiocpu"),
@ -184,11 +184,12 @@ public:
m_blitrom(*this, "blitter")
{ }
void nomcu(machine_config &config);
void fnkyfish(machine_config &config);
void kangaroob(machine_config &config);
protected:
virtual void machine_start() override ATTR_COLD;
virtual void machine_reset() override ATTR_COLD;
DECLARE_MACHINE_RESET(kangaroob);
virtual void main_map(address_map &map) ATTR_COLD;
@ -216,30 +217,37 @@ protected:
};
class kangaroo_mcu_state : public kangaroo_state
class kangaroo_mcu_state : public kangaroo_base_state
{
public:
kangaroo_mcu_state(const machine_config &mconfig, device_type type, const char *tag) :
kangaroo_state(mconfig, type, tag),
m_mcu(*this, "mcu")
kangaroo_base_state(mconfig, type, tag),
m_mcu(*this, "mcu"),
m_protrom(*this, "prot")
{ }
void mcu(machine_config &config);
void kangaroo(machine_config &config);
protected:
virtual void machine_start() override ATTR_COLD;
virtual void machine_reset() override ATTR_COLD;
virtual void main_map(address_map &map) override ATTR_COLD;
private:
required_device<mb8841_cpu_device> m_mcu;
required_region_ptr<uint8_t> m_protrom;
// MCU simulation (for now)
uint8_t m_mcu_clock = 0U;
uint8_t m_main_data = 0;
uint16_t m_protrom_address = 0;
uint8_t m_mcu_port_r[4] = { };
uint8_t mcu_sim_r();
void mcu_sim_w(uint8_t data);
uint8_t mcu_r();
void mcu_w(uint8_t data);
uint8_t mcu_port_k_r();
void mcu_port_o_w(uint8_t data);
template<int N> uint8_t mcu_port_r_r();
template<int N> void mcu_port_r_w(uint8_t data);
};
@ -250,7 +258,7 @@ private:
*
*************************************/
void kangaroo_state::videoram_write(uint16_t offset, uint8_t data, uint8_t mask)
void kangaroo_base_state::videoram_write(uint16_t offset, uint8_t data, uint8_t mask)
{
// data contains 4 2-bit values packed as DCBADCBA; expand these into 4 8-bit values
uint32_t expdata = 0;
@ -275,7 +283,7 @@ void kangaroo_state::videoram_write(uint16_t offset, uint8_t data, uint8_t mask)
}
void kangaroo_state::videoram_w(offs_t offset, uint8_t data)
void kangaroo_base_state::videoram_w(offs_t offset, uint8_t data)
{
videoram_write(offset, data, m_video_control[8]);
}
@ -288,7 +296,7 @@ void kangaroo_state::videoram_w(offs_t offset, uint8_t data)
*
*************************************/
void kangaroo_state::video_control_w(offs_t offset, uint8_t data)
void kangaroo_base_state::video_control_w(offs_t offset, uint8_t data)
{
m_video_control[offset] = data;
@ -312,7 +320,7 @@ void kangaroo_state::video_control_w(offs_t offset, uint8_t data)
*
*************************************/
void kangaroo_state::blitter_execute()
void kangaroo_base_state::blitter_execute()
{
uint32_t gfxhalfsize = m_blitrom.bytes() / 2;
uint16_t src = m_video_control[0] + 256 * m_video_control[1];
@ -347,7 +355,7 @@ void kangaroo_state::blitter_execute()
*
*************************************/
uint32_t kangaroo_state::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
uint32_t kangaroo_base_state::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
{
uint8_t scrolly = m_video_control[6];
uint8_t scrollx = m_video_control[7];
@ -414,7 +422,7 @@ uint32_t kangaroo_state::screen_update(screen_device &screen, bitmap_rgb32 &bitm
*
*************************************/
void kangaroo_state::machine_start()
void kangaroo_base_state::machine_start()
{
m_blitbank->configure_entries(0, 2, memregion("blitter")->base(), 0x2000);
}
@ -422,53 +430,77 @@ void kangaroo_state::machine_start()
void kangaroo_mcu_state::machine_start()
{
kangaroo_state::machine_start();
kangaroo_base_state::machine_start();
save_item(NAME(m_mcu_clock));
save_item(NAME(m_main_data));
save_item(NAME(m_protrom_address));
save_item(NAME(m_mcu_port_r));
}
void kangaroo_state::machine_reset()
MACHINE_RESET_MEMBER(kangaroo_base_state, kangaroob)
{
/* I think there is a bug in the startup checks of the game. At the very
beginning, during the RAM check, it goes one byte too far, and ends up
trying to write, and re-read, location dfff. To the best of my knowledge,
that is a ROM address, so the test fails and the code keeps jumping back
at 0000.
However, a NMI causes a successful reset. Maybe the hardware generates a
NMI shortly after power on, therefore masking the bug? The NMI is generated
by the MB8841 custom microcontroller, so this could be a way to disguise
the copy protection.
Anyway, what I do here is just immediately generate the NMI, so the game
properly starts. */
// The MCU triggers an NMI to make the game boot. The bootleg does not have an MCU,
// but still expects an NMI somehow, otherwise it gets stuck at the RAM check.
m_maincpu->pulse_input_line(INPUT_LINE_NMI, attotime::zero);
}
void kangaroo_mcu_state::machine_reset()
{
kangaroo_state::machine_reset();
m_mcu_clock = 0;
}
/*************************************
*
* Custom CPU RAM snooping
* Protection MCU
*
*************************************/
// The security chip is a MB8841 with 2K internal ROM. Currently it's unknown what it really does, this just seems to do the trick -V-
uint8_t kangaroo_mcu_state::mcu_sim_r()
uint8_t kangaroo_mcu_state::mcu_r()
{
return ++m_mcu_clock & 0x0f;
// data from MCU port R0-R3
return m_mcu_port_r[0];
}
void kangaroo_mcu_state::mcu_sim_w(uint8_t data)
void kangaroo_mcu_state::mcu_w(uint8_t data)
{
m_main_data = data;
}
uint8_t kangaroo_mcu_state::mcu_port_k_r()
{
uint8_t data = 0xf;
// maincpu data with R8
if (m_mcu_port_r[2] & 1)
data &= m_main_data;
// ROM data with R12
if (~m_mcu_port_r[3] & 1)
data &= m_protrom[m_protrom_address];
return data;
}
void kangaroo_mcu_state::mcu_port_o_w(uint8_t data)
{
// ROM address A0-A7
m_protrom_address = (m_protrom_address & 0x100) | data;
}
template<int N>
uint8_t kangaroo_mcu_state::mcu_port_r_r()
{
return m_mcu_port_r[N];
}
template<int N>
void kangaroo_mcu_state::mcu_port_r_w(uint8_t data)
{
m_mcu_port_r[N] = data;
// R13: ROM address A8 (A9,A10 to GND)
m_protrom_address = (m_protrom_address & 0xff) | BIT(m_mcu_port_r[3], 1) << 8;
// R15: trigger NMI on maincpu
m_maincpu->set_input_line(INPUT_LINE_NMI, BIT(m_mcu_port_r[3], 3) ? ASSERT_LINE : CLEAR_LINE);
}
@ -479,7 +511,7 @@ void kangaroo_mcu_state::mcu_sim_w(uint8_t data)
*
*************************************/
void kangaroo_state::coin_counter_w(uint8_t data)
void kangaroo_base_state::coin_counter_w(uint8_t data)
{
machine().bookkeeping().coin_counter_w(0, data & 1);
machine().bookkeeping().coin_counter_w(1, data & 2);
@ -493,23 +525,23 @@ void kangaroo_state::coin_counter_w(uint8_t data)
*
*************************************/
void kangaroo_state::main_map(address_map &map)
void kangaroo_base_state::main_map(address_map &map)
{
map(0x0000, 0x5fff).rom();
map(0x8000, 0xbfff).w(FUNC(kangaroo_state::videoram_w));
map(0x8000, 0xbfff).w(FUNC(kangaroo_base_state::videoram_w));
map(0xc000, 0xdfff).bankr(m_blitbank);
map(0xe000, 0xe3ff).ram();
map(0xe400, 0xe400).mirror(0x03ff).portr("DSW0");
map(0xe800, 0xe80a).mirror(0x03f0).w(FUNC(kangaroo_state::video_control_w)).share(m_video_control);
map(0xe800, 0xe80a).mirror(0x03f0).w(FUNC(kangaroo_base_state::video_control_w)).share(m_video_control);
map(0xec00, 0xec00).mirror(0x00ff).portr("IN0").w("soundlatch", FUNC(generic_latch_8_device::write));
map(0xed00, 0xed00).mirror(0x00ff).portr("IN1").w(FUNC(kangaroo_state::coin_counter_w));
map(0xed00, 0xed00).mirror(0x00ff).portr("IN1").w(FUNC(kangaroo_base_state::coin_counter_w));
map(0xee00, 0xee00).mirror(0x00ff).portr("IN2");
}
void kangaroo_mcu_state::main_map(address_map &map)
{
kangaroo_state::main_map(map);
map(0xef00, 0xefff).rw(FUNC(kangaroo_mcu_state::mcu_sim_r), FUNC(kangaroo_mcu_state::mcu_sim_w));
kangaroo_base_state::main_map(map);
map(0xef00, 0xef00).mirror(0x00ff).rw(FUNC(kangaroo_mcu_state::mcu_r), FUNC(kangaroo_mcu_state::mcu_w));
}
@ -519,7 +551,7 @@ void kangaroo_mcu_state::main_map(address_map &map)
*
*************************************/
void kangaroo_state::sound_map(address_map &map)
void kangaroo_base_state::sound_map(address_map &map)
{
map(0x0000, 0x0fff).rom().region("audiocpu", 0);
map(0x4000, 0x43ff).mirror(0x0c00).ram();
@ -664,23 +696,23 @@ INPUT_PORTS_END
*
*************************************/
void kangaroo_state::nomcu(machine_config &config)
void kangaroo_base_state::fnkyfish(machine_config &config)
{
// basic machine hardware
Z80(config, m_maincpu, 10_MHz_XTAL / 4);
m_maincpu->set_addrmap(AS_PROGRAM, &kangaroo_state::main_map);
m_maincpu->set_vblank_int("screen", FUNC(kangaroo_state::irq0_line_hold));
m_maincpu->set_addrmap(AS_PROGRAM, &kangaroo_base_state::main_map);
m_maincpu->set_vblank_int("screen", FUNC(kangaroo_base_state::irq0_line_hold));
Z80(config, m_audiocpu, 10_MHz_XTAL / 8);
m_audiocpu->set_addrmap(AS_PROGRAM, &kangaroo_state::sound_map);
m_audiocpu->set_addrmap(AS_IO, &kangaroo_state::sound_map); // yes, this is identical
m_audiocpu->set_vblank_int("screen", FUNC(kangaroo_state::irq0_line_hold));
Z80(config, m_audiocpu, 10_MHz_XTAL / 4);
m_audiocpu->set_addrmap(AS_PROGRAM, &kangaroo_base_state::sound_map);
m_audiocpu->set_addrmap(AS_IO, &kangaroo_base_state::sound_map); // yes, this is identical
m_audiocpu->set_vblank_int("screen", FUNC(kangaroo_base_state::irq0_line_hold));
// video hardware
screen_device &screen(SCREEN(config, "screen", SCREEN_TYPE_RASTER));
screen.set_video_attributes(VIDEO_UPDATE_SCANLINE);
screen.set_raw(10_MHz_XTAL, 320*2, 0*2, 256*2, 260, 8, 248);
screen.set_screen_update(FUNC(kangaroo_state::screen_update));
screen.set_screen_update(FUNC(kangaroo_base_state::screen_update));
PALETTE(config, m_palette, palette_device::BGR_3BIT);
@ -693,14 +725,31 @@ void kangaroo_state::nomcu(machine_config &config)
}
void kangaroo_mcu_state::mcu(machine_config &config)
void kangaroo_mcu_state::kangaroo(machine_config &config)
{
nomcu(config);
fnkyfish(config);
// basic machine hardware
MB8841(config, m_mcu, 10_MHz_XTAL / 4 / 2);
MB8841(config, m_mcu, 10_MHz_XTAL / 4);
m_mcu->read_k().set(FUNC(kangaroo_mcu_state::mcu_port_k_r));
m_mcu->write_o().set(FUNC(kangaroo_mcu_state::mcu_port_o_w));
m_mcu->read_r<0>().set(FUNC(kangaroo_mcu_state::mcu_port_r_r<0>));
m_mcu->read_r<1>().set(FUNC(kangaroo_mcu_state::mcu_port_r_r<1>));
m_mcu->read_r<2>().set(FUNC(kangaroo_mcu_state::mcu_port_r_r<2>));
m_mcu->read_r<3>().set(FUNC(kangaroo_mcu_state::mcu_port_r_r<3>));
m_mcu->write_r<0>().set(FUNC(kangaroo_mcu_state::mcu_port_r_w<0>));
m_mcu->write_r<1>().set(FUNC(kangaroo_mcu_state::mcu_port_r_w<1>));
m_mcu->write_r<2>().set(FUNC(kangaroo_mcu_state::mcu_port_r_w<2>));
m_mcu->write_r<3>().set(FUNC(kangaroo_mcu_state::mcu_port_r_w<3>));
config.set_perfect_quantum(m_mcu);
}
void kangaroo_base_state::kangaroob(machine_config &config)
{
fnkyfish(config);
MCFG_MACHINE_RESET_OVERRIDE(kangaroo_base_state, kangaroob)
}
/*************************************
@ -742,7 +791,7 @@ ROM_START( kangaroo )
ROM_REGION( 0x0800, "mcu", 0 ) // internal ROM from the 8841 custom MCU
ROM_LOAD( "mb8841_477m.ic29", 0x0000, 0x0800, CRC(04ca58ee) SHA1(cc46a268a5d915c313476f44c44f92ed94c2b4a0) )
ROM_REGION( 0x0800, "user1", 0 ) // data for the 8841 custom MCU
ROM_REGION( 0x0800, "prot", 0 ) // data for the 8841 custom MCU
ROM_LOAD( "tvg_82.12", 0x0000, 0x0800, CRC(57766f69) SHA1(94a7a557d8325799523d5e1a88653a9a3fbe34f9) ) // IC28
ROM_REGION( 0x4000, "blitter", 0 ) // On TVG-1-VIDEO-B board
@ -752,7 +801,6 @@ ROM_START( kangaroo )
ROM_LOAD( "tvg_86.v3", 0x3000, 0x1000, CRC(9e6a599f) SHA1(76b4eddb4efcd8189d8cc5962d8497e82885f212) ) // IC53
ROM_END
ROM_START( kangarooa )
ROM_REGION( 0x6000, "maincpu", 0 )
ROM_LOAD( "136008-101.ic7", 0x0000, 0x1000, CRC(0d18c581) SHA1(0e0f89d644b79e887c53e5294783843ca7e875ba) )
@ -768,7 +816,7 @@ ROM_START( kangarooa )
ROM_REGION( 0x0800, "mcu", 0 ) // internal ROM from the 8841 custom MCU
ROM_LOAD( "mb8841_477m.ic29", 0x0000, 0x0800, CRC(04ca58ee) SHA1(cc46a268a5d915c313476f44c44f92ed94c2b4a0) )
ROM_REGION( 0x0800, "user1", 0 ) // data for the 8841 custom MCU
ROM_REGION( 0x0800, "prot", 0 ) // data for the 8841 custom MCU
ROM_LOAD( "136008-112.ic28", 0x0000, 0x0800, CRC(57766f69) SHA1(94a7a557d8325799523d5e1a88653a9a3fbe34f9) )
ROM_REGION( 0x4000, "blitter", 0 )
@ -778,6 +826,30 @@ ROM_START( kangarooa )
ROM_LOAD( "136008-111.ic53", 0x3000, 0x1000, CRC(9e6a599f) SHA1(76b4eddb4efcd8189d8cc5962d8497e82885f212) )
ROM_END
ROM_START( kangarool ) // runs on earlier revision TVG-1-CPU-A + TVG-1-VIDEO-A PCBs
ROM_REGION( 0x6000, "maincpu", 0 ) // only ic17 differs from the parent
ROM_LOAD( "tvg_75.ic7", 0x0000, 0x1000, CRC(0d18c581) SHA1(0e0f89d644b79e887c53e5294783843ca7e875ba) )
ROM_LOAD( "tvg_76.ic8", 0x1000, 0x1000, CRC(5978d37a) SHA1(684c1092de4a0927a03752903c86c3bbe99e868a) )
ROM_LOAD( "tvg_77.ic9", 0x2000, 0x1000, CRC(522d1097) SHA1(09fe627a46d32df2e098d9fad7757f9d61bef41f) )
ROM_LOAD( "tvg_78.ic10", 0x3000, 0x1000, CRC(063da970) SHA1(582ff21dd46c651f07a4846e0f8a7544a5891988) )
ROM_LOAD( "tvg_79.ic16", 0x4000, 0x1000, CRC(9e5cf8ca) SHA1(015387f038c5670f88c9b22453d074bd9b2a129d) )
ROM_LOAD( "tvg_80.ic17", 0x5000, 0x1000, CRC(62df0271) SHA1(4043d90d33ff04729077be7956d30bf82add103c) )
ROM_REGION( 0x1000, "audiocpu", 0 )
ROM_LOAD( "tvg_81.ic24", 0x0000, 0x1000, CRC(fb449bfd) SHA1(f593a0339f47e121736a927587132aeb52704557) )
ROM_REGION( 0x0800, "mcu", 0 ) // internal ROM from the 8841 custom MCU
ROM_LOAD( "mb8841_477m.ic29", 0x0000, 0x0800, CRC(04ca58ee) SHA1(cc46a268a5d915c313476f44c44f92ed94c2b4a0) )
ROM_REGION( 0x0800, "prot", 0 ) // data for the 8841 custom MCU
ROM_LOAD( "tvg_82.ic28", 0x0000, 0x0800, CRC(57766f69) SHA1(94a7a557d8325799523d5e1a88653a9a3fbe34f9) )
ROM_REGION( 0x4000, "blitter", 0 )
ROM_LOAD( "tvg_83.ic76", 0x0000, 0x1000, CRC(c0446ca6) SHA1(fca6ba565051337c0198c93b7b8477632e0dd0b6) )
ROM_LOAD( "tvg_85.ic77", 0x1000, 0x1000, CRC(72c52695) SHA1(87f4715fbb7d509bd9cc4e71e2afb0d475bbac13) )
ROM_LOAD( "tvg_84.ic52", 0x2000, 0x1000, CRC(e4cb26c2) SHA1(5016db9d48fdcfb757618659d063b90862eb0e90) )
ROM_LOAD( "tvg_86.ic53", 0x3000, 0x1000, CRC(9e6a599f) SHA1(76b4eddb4efcd8189d8cc5962d8497e82885f212) )
ROM_END
ROM_START( kangaroob )
ROM_REGION( 0x6000, "maincpu", 0 )
@ -800,32 +872,6 @@ ROM_START( kangaroob )
ROM_LOAD( "k9.ic53", 0x3000, 0x1000, CRC(9e6a599f) SHA1(76b4eddb4efcd8189d8cc5962d8497e82885f212) )
ROM_END
ROM_START( kangarool ) // runs on earlier revision TVG-1-CPU-A + TVG-1-VIDEO-A PCBs
ROM_REGION( 0x6000, "maincpu", 0 ) // only ic17 differs from the parent
ROM_LOAD( "tvg_75.ic7", 0x0000, 0x1000, CRC(0d18c581) SHA1(0e0f89d644b79e887c53e5294783843ca7e875ba) )
ROM_LOAD( "tvg_76.ic8", 0x1000, 0x1000, CRC(5978d37a) SHA1(684c1092de4a0927a03752903c86c3bbe99e868a) )
ROM_LOAD( "tvg_77.ic9", 0x2000, 0x1000, CRC(522d1097) SHA1(09fe627a46d32df2e098d9fad7757f9d61bef41f) )
ROM_LOAD( "tvg_78.ic10", 0x3000, 0x1000, CRC(063da970) SHA1(582ff21dd46c651f07a4846e0f8a7544a5891988) )
ROM_LOAD( "tvg_79.ic16", 0x4000, 0x1000, CRC(9e5cf8ca) SHA1(015387f038c5670f88c9b22453d074bd9b2a129d) )
ROM_LOAD( "tvg_80.ic17", 0x5000, 0x1000, CRC(62df0271) SHA1(4043d90d33ff04729077be7956d30bf82add103c) )
ROM_REGION( 0x1000, "audiocpu", 0 )
ROM_LOAD( "tvg_81.ic24", 0x0000, 0x1000, CRC(fb449bfd) SHA1(f593a0339f47e121736a927587132aeb52704557) )
ROM_REGION( 0x0800, "mcu", 0 ) // internal ROM from the 8841 custom MCU
ROM_LOAD( "mb8841_477m.ic29", 0x0000, 0x0800, CRC(04ca58ee) SHA1(cc46a268a5d915c313476f44c44f92ed94c2b4a0) )
ROM_REGION( 0x0800, "user1", 0 ) // data for the 8841 custom MCU
ROM_LOAD( "tvg_82.ic28", 0x0000, 0x0800, CRC(57766f69) SHA1(94a7a557d8325799523d5e1a88653a9a3fbe34f9) )
ROM_REGION( 0x4000, "blitter", 0 )
ROM_LOAD( "tvg_83.ic76", 0x0000, 0x1000, CRC(c0446ca6) SHA1(fca6ba565051337c0198c93b7b8477632e0dd0b6) )
ROM_LOAD( "tvg_85.ic77", 0x1000, 0x1000, CRC(72c52695) SHA1(87f4715fbb7d509bd9cc4e71e2afb0d475bbac13) )
ROM_LOAD( "tvg_84.ic52", 0x2000, 0x1000, CRC(e4cb26c2) SHA1(5016db9d48fdcfb757618659d063b90862eb0e90) )
ROM_LOAD( "tvg_86.ic53", 0x3000, 0x1000, CRC(9e6a599f) SHA1(76b4eddb4efcd8189d8cc5962d8497e82885f212) )
ROM_END
} // anonymous namespace
@ -835,8 +881,8 @@ ROM_END
*
*************************************/
GAME( 1981, fnkyfish, 0, nomcu, fnkyfish, kangaroo_state, empty_init, ROT90, "Sun Electronics", "Funky Fish", MACHINE_SUPPORTS_SAVE )
GAME( 1982, kangaroo, 0, mcu, kangaroo, kangaroo_mcu_state, empty_init, ROT90, "Sun Electronics", "Kangaroo", MACHINE_SUPPORTS_SAVE )
GAME( 1982, kangarooa, kangaroo, mcu, kangaroo, kangaroo_mcu_state, empty_init, ROT90, "Sun Electronics (Atari license)", "Kangaroo (Atari)", MACHINE_SUPPORTS_SAVE )
GAME( 1982, kangaroob, kangaroo, nomcu, kangaroo, kangaroo_state, empty_init, ROT90, "bootleg", "Kangaroo (bootleg)", MACHINE_SUPPORTS_SAVE )
GAME( 1982, kangarool, kangaroo, mcu, kangaroo, kangaroo_mcu_state, empty_init, ROT90, "Sun Electronics (Loewen-Automaten license)", "Kangaroo (Loewen-Automaten)", MACHINE_SUPPORTS_SAVE )
GAME( 1981, fnkyfish, 0, fnkyfish, fnkyfish, kangaroo_base_state, empty_init, ROT90, "Sun Electronics", "Funky Fish", MACHINE_SUPPORTS_SAVE )
GAME( 1982, kangaroo, 0, kangaroo, kangaroo, kangaroo_mcu_state, empty_init, ROT90, "Sun Electronics", "Kangaroo", MACHINE_SUPPORTS_SAVE )
GAME( 1982, kangarooa, kangaroo, kangaroo, kangaroo, kangaroo_mcu_state, empty_init, ROT90, "Sun Electronics (Atari license)", "Kangaroo (Atari)", MACHINE_SUPPORTS_SAVE )
GAME( 1982, kangarool, kangaroo, kangaroo, kangaroo, kangaroo_mcu_state, empty_init, ROT90, u8"Sun Electronics (Löwen-Automaten license)", u8"Kangaroo (Löwen-Automaten)", MACHINE_SUPPORTS_SAVE )
GAME( 1982, kangaroob, kangaroo, kangaroob, kangaroo, kangaroo_base_state, empty_init, ROT90, "bootleg", "Kangaroo (bootleg)", MACHINE_SUPPORTS_SAVE )

View File

@ -64,6 +64,7 @@ public:
, m_screen(*this, "screen")
, m_gfxdecode(*this, "gfxdecode")
, m_palette(*this, "palette")
, m_protrom(*this, "prot")
, m_spriteram(*this, "spriteram")
, m_videoram(*this, "videoram")
, m_xscroll(*this, "xscroll")
@ -132,6 +133,7 @@ private:
required_device<palette_device> m_palette;
/* memory pointers */
optional_region_ptr<uint8_t> m_protrom;
required_shared_ptr<uint8_t> m_spriteram;
required_shared_ptr<uint8_t> m_videoram;
required_shared_ptr<uint8_t> m_xscroll;
@ -370,8 +372,6 @@ TIMER_DEVICE_CALLBACK_MEMBER(markham_state::strnskil_scanline)
uint8_t markham_state::banbam_protection_r()
{
const uint8_t *prot_rom = (const uint8_t *)memregion("mcu_rom")->base();
const uint8_t init = m_packet_buffer[0] & 0x0f;
uint8_t comm = m_packet_buffer[1] & 0xf0;
uint8_t arg = m_packet_buffer[1] & 0x0f;
@ -387,11 +387,11 @@ uint8_t markham_state::banbam_protection_r()
{
case 0x30:
// palette/gfx select
arg = prot_rom[0x799 + (arg * 4)];
arg = m_protrom[0x799 + (arg * 4)];
break;
case 0x40:
// palette/gfx select
arg = prot_rom[0x7C5 + (arg * 4)];
arg = m_protrom[0x7c5 + (arg * 4)];
break;
case 0x60:
// enemy wave timer trigger
@ -892,16 +892,16 @@ void markham_state::banbam(machine_config &config)
m_maincpu->set_addrmap(AS_PROGRAM, &markham_state::banbam_master_map);
MB8841(config, m_mcu, CPU_CLOCK/2); /* 4.000MHz */
// m_mcu->read_k().set(FUNC(markham_state::mcu_portk_r));
// m_mcu->read_k().set(FUNC(markham_state::mcu_port_k_r));
// m_mcu->write_o().set(FUNC(markham_state::mcu_port_o_w));
// m_mcu->write_p().set(FUNC(markham_state::mcu_port_p_w));
// m_mcu->read_r<0>().set(FUNC(markham_state::mcu_port_r0_r));
// m_mcu->write_r<0>().set(FUNC(markham_state::mcu_port_r0_w));
// m_mcu->read_r<1>().set(FUNC(markham_state::mcu_port_r1_r));
// m_mcu->write_r<1>().set(FUNC(markham_state::mcu_port_r1_w));
// m_mcu->read_r<2>().set(FUNC(markham_state::mcu_port_r2_r));
// m_mcu->write_r<2>().set(FUNC(markham_state::mcu_port_r2_w));
// m_mcu->read_r<3>().set(FUNC(markham_state::mcu_port_r3_r));
// m_mcu->write_r<0>().set(FUNC(markham_state::mcu_port_r0_w));
// m_mcu->write_r<1>().set(FUNC(markham_state::mcu_port_r1_w));
// m_mcu->write_r<2>().set(FUNC(markham_state::mcu_port_r2_w));
// m_mcu->write_r<3>().set(FUNC(markham_state::mcu_port_r3_w));
m_mcu->set_disable();
}
@ -1013,6 +1013,12 @@ ROM_START( banbam )
ROM_REGION( 0x10000, "subcpu", 0 ) /* sub CPU */
ROM_LOAD( "ban-rom1.ic2", 0x0000, 0x2000, CRC(e36009f6) SHA1(72c485e8c19fbfc9c850094cfd87f1055154c0c5) )
ROM_REGION(0x800, "mcu", 0) /* Fujitsu MB8841 4-Bit MCU internal ROM */
ROM_LOAD( "sun-8212.ic3", 0x000, 0x800, CRC(8869611e) SHA1(c6443f3bcb0cdb4d7b1b19afcbfe339c300f36aa) )
ROM_REGION( 0x2000, "prot", 0 ) /* protection, data used with Fujitsu MB8841 4-Bit MCU */
ROM_LOAD( "ban-rom12.ic2", 0x0000, 0x2000, CRC(044bb2f6) SHA1(829b2152740061e0506c7504885d8404fb8fe360) )
ROM_REGION( 0x6000, "gfx1", 0 ) /* sprite */
ROM_LOAD( "ban-rom6.ic90", 0x0000, 0x2000, CRC(41fc44df) SHA1(1c4f21cdc423078fab58370d5245a13292bf7fe6) )
ROM_LOAD( "ban-rom7.ic92", 0x2000, 0x2000, CRC(8b429c5b) SHA1(505796eac2c8dd84f9ed29a6227b3243f81ec072) )
@ -1032,12 +1038,6 @@ ROM_START( banbam )
ROM_REGION( 0x0100, "scroll_prom", 0 ) /* scroll control PROM */
ROM_LOAD( "16-6.59", 0x0000, 0x0100, CRC(ec4faf5b) SHA1(7ebbf50807d04105ebadec91bded069408e399ba) ) /* Prom type 24s10 */
ROM_REGION( 0x2000, "mcu_rom", 0 ) /* protection, data used with Fujitsu MB8841 4-Bit MCU */
ROM_LOAD( "ban-rom12.ic2", 0x0000, 0x2000, CRC(044bb2f6) SHA1(829b2152740061e0506c7504885d8404fb8fe360) )
ROM_REGION(0x800, "mcu", 0) /* Fujitsu MB8841 4-Bit MCU internal ROM */
ROM_LOAD( "sun-8212.ic3", 0x000, 0x800, CRC(8869611e) SHA1(c6443f3bcb0cdb4d7b1b19afcbfe339c300f36aa) )
ROM_END
ROM_START( pettanp )
@ -1051,6 +1051,12 @@ ROM_START( pettanp )
ROM_REGION( 0x10000, "subcpu", 0 ) /* sub CPU */
ROM_LOAD( "tvg1-16.2", 0x0000, 0x2000, CRC(e36009f6) SHA1(72c485e8c19fbfc9c850094cfd87f1055154c0c5) )
ROM_REGION(0x800, "mcu", 0) /* Fujitsu MB8841 4-Bit MCU internal ROM */
ROM_LOAD( "sun-8212.ic3", 0x000, 0x800, NO_DUMP ) // very much likely to be same as banbam and arabian
ROM_REGION( 0x1000, "prot", 0 ) /* protection data used with Fujitsu MB8841 4-Bit MCU */
ROM_LOAD( "tvg12-16.2", 0x0000, 0x1000, CRC(3abc6ba8) SHA1(15e0b0f9d068f6094e2be4f4f1dea0ff6e85686b) )
ROM_REGION( 0x6000, "gfx1", 0 ) /* sprite */
ROM_LOAD( "tvg6-16.90", 0x0000, 0x2000, CRC(6905d9d5) SHA1(586bf72bab5ab6e3e319c925decc16d7f3711af1) )
ROM_LOAD( "tvg7-16.92", 0x2000, 0x2000, CRC(40d02bfd) SHA1(2f6ca8197048318f7900b56169aba4c9fdf48693) )
@ -1070,12 +1076,6 @@ ROM_START( pettanp )
ROM_REGION( 0x0100, "scroll_prom", 0 ) /* scroll control PROM */
ROM_LOAD( "16-6.59", 0x0000, 0x0100, CRC(ec4faf5b) SHA1(7ebbf50807d04105ebadec91bded069408e399ba) ) /* Prom type 24s10 */
ROM_REGION( 0x1000, "mcu_rom", 0 ) /* protection data used with Fujitsu MB8841 4-Bit MCU */
ROM_LOAD( "tvg12-16.2", 0x0000, 0x1000, CRC(3abc6ba8) SHA1(15e0b0f9d068f6094e2be4f4f1dea0ff6e85686b) )
ROM_REGION(0x800, "mcu", 0) /* Fujitsu MB8841 4-Bit MCU internal ROM */
ROM_LOAD( "sun-8212.ic3", 0x000, 0x800, NO_DUMP ) // very much likely to be same as banbam and arabian
ROM_END
} // anonymous namespace

View File

@ -544,7 +544,7 @@ static const dasm_table_entry dasm_table[] =
{ "m740", le, 0, []() -> util::disasm_interface * { return new m740_disassembler(&m740_unidasm); } },
{ "mb86233", le, -2, []() -> util::disasm_interface * { return new mb86233_disassembler; } },
{ "mb86235", le, -3, []() -> util::disasm_interface * { return new mb86235_disassembler; } },
{ "mb88", le, 0, []() -> util::disasm_interface * { return new mb88_disassembler; } },
{ "mb88xx", le, 0, []() -> util::disasm_interface * { return new mb88_disassembler; } },
{ "mc88100", be, 0, []() -> util::disasm_interface * { return new mc88100_disassembler; } },
{ "mc88110", be, 0, []() -> util::disasm_interface * { return new mc88110_disassembler; } },
{ "mcs48", le, 0, []() -> util::disasm_interface * { return new mcs48_disassembler(false, false); } },