summaryrefslogtreecommitdiffstats
path: root/src/mame/machine/mpu4_characteriser_pal_bwb.cpp
blob: 7d374e1063e9aba918293af30f66a2b5cf8b0805 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
// license:BSD-3-Clause
// copyright-holders:David Haywood, James Wallace

/*
BwB Characteriser (CHR)

The BwB method of protection is considerably different to the Barcrest one, with any
incorrect behaviour manifesting in ridiculously large payouts. The hardware is the
same, however the main weakness of the software has been eliminated.

In fact, the software seems deliberately designed to mislead, but is (fortunately for
us) prone to similar weaknesses that allow a per game solution.

Project Amber performed a source analysis (available on request) which appears to make things work.
Said weaknesses (A Cheats Guide according to Project Amber)

The common initialisation sequence is "00 04 04 0C 0C 1C 14 2C 5C 2C"
                                        0  1  2  3  4  5  6  7  8


Using debug search for the first read from said string (best to find it first).

 - in m4blsbys this string is at 0x17383 in ROM, which is banked into memory at 0x7383
 - this is first accessed by the code at 50c3, a CMPA $0138,X opcode, where X is 0x724B (0x724B + 0x138 = 0x7383)


At this point, the X index on the CPU is at the magic number address.

The subsequent calls for each can be found based on the magic address

           (0) = ( (BWBMagicAddress))
           (1) = ( (BWBMagicAddress + 1))
           (2) = ( (BWBMagicAddress + 2))
           (3) = ( (BWBMagicAddress + 4))
           (4) = ( (BWBMagicAddress - 5))
           (5) = ( (BWBMagicAddress - 4))
           (6) = ( (BWBMagicAddress - 3))
           (7) = ( (BWBMagicAddress - 2))
           (8) = ( (BWBMagicAddress - 1))

These return the standard init sequence as above.

For ease of understanding, we use three tables, one holding the common responses
and two holding the appropriate call and response pairs for the two stages of operation
*/

#include "emu.h"

#include "mpu4_characteriser_pal_bwb.h"

DEFINE_DEVICE_TYPE(MPU4_CHARACTERISER_PAL_BWB, mpu4_characteriser_pal_bwb, "mpu4chrpal_bwb", "BWB MPU4 Characteriser PAL")

mpu4_characteriser_pal_bwb::mpu4_characteriser_pal_bwb(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
	: mpu4_characteriser_pal_bwb(mconfig, MPU4_CHARACTERISER_PAL_BWB, tag, owner, clock)
{
}

mpu4_characteriser_pal_bwb::mpu4_characteriser_pal_bwb(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock) :
	device_t(mconfig, type, tag, owner, clock)
{
}

void mpu4_characteriser_pal_bwb::device_start()
{
}

void mpu4_characteriser_pal_bwb::device_reset()
{
}

void mpu4_characteriser_pal_bwb::write(offs_t offset, uint8_t data)
{
	m_call = data;
	logerror("%s Characteriser write offset %02x data %02x\n", machine().describe_context(), offset, data);
	m_initval_ready = true;

	if (m_chr_counter > 35)
	{
		m_chr_counter = 36;
	}
	else
	{
		m_chr_counter++;
	}

	if (m_call == ((m_otherkey >> 16) & 0xff))
		m_bwb_return = 0;

	if ((m_call == m_commonkey) || (m_call == ((m_otherkey >> 16) & 0xff)) || (m_call == ((m_otherkey >> 8) & 0xff)) || (m_call == ((m_otherkey >> 0) & 0xff)))
	{
		if (m_bwb_return < 16)
		{
			m_chr_value = bwb_chr_table_common[m_bwb_return];
		}

		m_bwb_return++;
	}
	else
	{
		m_chr_value = machine().rand();
		m_bwb_return = 0;
	}
}

uint8_t mpu4_characteriser_pal_bwb::read(offs_t offset)
{
	logerror("%s Characteriser read offset %02x\n", machine().describe_context(), offset);

	if ((offset == 0) && m_initval_ready)
	{
		m_initval_ready = false;

		switch (m_chr_counter)
		{
		case 7:
		case 14:
		case 21:
		case 28:
		case 35:
			logerror("m_call %02x\n", m_call);

			// it is unclear what we actually need to return here for normal operation
			return machine().rand();

		default:
			return m_chr_value;
		}

	}
	else
	{
		return m_chr_value;
	}
}