summaryrefslogtreecommitdiffstatshomepage
path: root/src/mame/machine/taito68705interface.cpp
blob: 176dbe899b22391b2be2591870b35cc397608ac7 (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
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
// license:BSD-3-Clause
// copyright-holders:Ernesto Corvi, Nicola Salmoria, David Haywood, Vas Crabb
#include "emu.h"
#include "machine/taito68705interface.h"

#include "cpu/z80/z80.h"

/*
   Most Taito 68705s share a similar (often identical) hookup.
   This file encapsulates that.

    used by:
    40love.cpp   - 40love
    bigevglf.cpp - bigevglf
    bking.cpp    - bking3
    bublbobl.cpp - tokio
    buggychl.cpp - buggychl
    flstory.cpp  - flstory
    lkage.cpp    - lkage
    lsasquad.cpp - lsasquad, daikaiju
    matmania.cpp - maniach
    nycaptor.cpp - nycaptor
    renegade.cpp - renegade
    retofinv.cpp - retofinv
    slapfght.cpp - slapfght
    xain.cpp     - xsleena

    and the following with slight changes:
    slapfght.cpp - tigerh (inverted status bits read on port C)
    arkanoid.cpp - arkanoid (latch control on port C, inputs on port B)
    taito_l.cpp - puzznic (latch control on port C)

    not hooked up here, but possible (needs investigating)
    pitnrun.cpp - have more functionality on portB, currently using 'instant timers' for latches
    taitosj.cpp - ^^

    68705 sets in Taito drivers that are NOT suitable for hookup here?
    bublbobl.cpp - bub68705 - this is a bootleg, not an official Taito hookup
    changela.cpp - changela - looks like an ancestor of arkanoid without automatic semaphores
    mexico86.cpp - knightb, mexico86 - bootleg 68705s
    sqix.cpp - hotsmash - kaneko hookup, different from Taito ones.

    there are other drivers (and games in existing drivers) that could hookup here, but currently lack MCU dumps.

*/


namespace {

MACHINE_CONFIG_FRAGMENT( taito68705 )
	MCFG_CPU_ADD("mcu", M68705P5, DERIVED_CLOCK(1, 1))
	MCFG_M68705_PORTC_R_CB(READ8(taito68705_mcu_device, mcu_portc_r))
	MCFG_M68705_PORTA_W_CB(WRITE8(taito68705_mcu_device, mcu_pa_w))
	MCFG_M68705_PORTB_W_CB(WRITE8(taito68705_mcu_device, mcu_portb_w))
MACHINE_CONFIG_END

MACHINE_CONFIG_FRAGMENT( arkanoid_68705p3 )
	MCFG_CPU_ADD("mcu", M68705P3, DERIVED_CLOCK(1, 1))
	MCFG_M68705_PORTB_R_CB(READ8(arkanoid_mcu_device_base, mcu_pb_r))
	MCFG_M68705_PORTC_R_CB(READ8(arkanoid_mcu_device_base, mcu_pc_r))
	MCFG_M68705_PORTA_W_CB(WRITE8(arkanoid_mcu_device_base, mcu_pa_w))
	MCFG_M68705_PORTC_W_CB(WRITE8(arkanoid_mcu_device_base, mcu_pc_w))
MACHINE_CONFIG_END

MACHINE_CONFIG_FRAGMENT( arkanoid_68705p5 )
	MCFG_CPU_ADD("mcu", M68705P5, DERIVED_CLOCK(1, 1))
	MCFG_M68705_PORTB_R_CB(READ8(arkanoid_mcu_device_base, mcu_pb_r))
	MCFG_M68705_PORTC_R_CB(READ8(arkanoid_mcu_device_base, mcu_pc_r))
	MCFG_M68705_PORTA_W_CB(WRITE8(arkanoid_mcu_device_base, mcu_pa_w))
	MCFG_M68705_PORTC_W_CB(WRITE8(arkanoid_mcu_device_base, mcu_pc_w))
MACHINE_CONFIG_END

} // anonymous namespace


DEFINE_DEVICE_TYPE(TAITO68705_MCU,       taito68705_mcu_device,       "taito68705",      "Taito MC68705 MCU Interface")
DEFINE_DEVICE_TYPE(TAITO68705_MCU_TIGER, taito68705_mcu_tiger_device, "taito68705tiger", "Taito MC68705 MCU Interface (Tiger Heli)")
DEFINE_DEVICE_TYPE(ARKANOID_68705P3,     arkanoid_68705p3_device,     "arkanoid68705p3", "Arkanoid MC68705P3 Interface")
DEFINE_DEVICE_TYPE(ARKANOID_68705P5,     arkanoid_68705p5_device,     "arkanoid68705p5", "Arkanoid MC68705P5 Interface")


READ8_MEMBER(taito68705_mcu_device_base::data_r)
{
	// clear MCU semaphore flag and return data
	u8 const result(m_mcu_latch);
	if (!machine().side_effect_disabled())
	{
		m_mcu_flag = false;
		m_semaphore_cb(CLEAR_LINE);
	}
	return result;
}

WRITE8_MEMBER(taito68705_mcu_device_base::data_w)
{
	// set host semaphore flag and latch data
	if (!m_reset_input)
		m_host_flag = true;
	m_host_latch = data;
	if (m_latch_driven)
		m_mcu->pa_w(space, 0, data);
	m_mcu->set_input_line(M68705_IRQ_LINE, m_host_flag ? ASSERT_LINE : CLEAR_LINE);
}

WRITE_LINE_MEMBER(taito68705_mcu_device_base::reset_w)
{
	m_reset_input = ASSERT_LINE == state;
	if (CLEAR_LINE != state)
	{
		m_host_flag = false;
		m_mcu_flag = false;
		m_mcu->set_input_line(M68705_IRQ_LINE, CLEAR_LINE);
	}
	m_mcu->set_input_line(INPUT_LINE_RESET, state);
}

WRITE8_MEMBER(taito68705_mcu_device_base::mcu_pa_w)
{
	m_pa_output = data;
}

taito68705_mcu_device_base::taito68705_mcu_device_base(
		machine_config const &mconfig,
		device_type type,
		char const *tag,
		device_t *owner,
		u32 clock)
	: device_t(mconfig, type, tag, owner, clock)
	, m_mcu(*this, "mcu")
	, m_semaphore_cb(*this)
	, m_latch_driven(false)
	, m_reset_input(false)
	, m_host_flag(false)
	, m_mcu_flag(false)
	, m_host_latch(0xff)
	, m_mcu_latch(0xff)
	, m_pa_output(0xff)
{
}

void taito68705_mcu_device_base::device_start()
{
	m_semaphore_cb.resolve_safe();

	save_item(NAME(m_latch_driven));
	save_item(NAME(m_reset_input));
	save_item(NAME(m_host_flag));
	save_item(NAME(m_mcu_flag));
	save_item(NAME(m_host_latch));
	save_item(NAME(m_mcu_latch));
	save_item(NAME(m_pa_output));

	m_latch_driven = false;
	m_reset_input = false;
	m_host_latch = 0xff;
	m_mcu_latch = 0xff;
	m_pa_output = 0xff;
}

void taito68705_mcu_device_base::device_reset()
{
	m_host_flag = false;
	m_mcu_flag = false;

	m_mcu->set_input_line(M68705_IRQ_LINE, CLEAR_LINE);
	m_semaphore_cb(CLEAR_LINE);
}

void taito68705_mcu_device_base::latch_control(u8 data, u8 &value, unsigned host_bit, unsigned mcu_bit)
{
	// save this here to simulate latch propagation delays
	u8 const old_pa_value(pa_value());

	// rising edge clears the host semaphore flag
	if (BIT(data, host_bit))
	{
		m_latch_driven = false;
		m_mcu->pa_w(m_mcu->space(AS_PROGRAM), 0, 0xff);
		if (!BIT(value, host_bit))
		{
			m_host_flag = false;
			m_mcu->set_input_line(M68705_IRQ_LINE, CLEAR_LINE);
		}
	}
	else
	{
		m_latch_driven = true;
		m_mcu->pa_w(m_mcu->space(AS_PROGRAM), 0, m_host_latch);
	}

	// PB2 sets the MCU semaphore when low
	if (!BIT(data, mcu_bit))
	{
		if (!m_reset_input)
			m_mcu_flag = true;

		// data is latched on falling edge
		if (BIT(value, mcu_bit))
			m_mcu_latch = old_pa_value;
	}

	value = data;
	if (!BIT(data, mcu_bit) && !m_reset_input)
		m_semaphore_cb(ASSERT_LINE);
}


taito68705_mcu_device::taito68705_mcu_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
	: taito68705_mcu_device(mconfig, TAITO68705_MCU, tag, owner, clock)
{
}

taito68705_mcu_device::taito68705_mcu_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock)
	: taito68705_mcu_device_base(mconfig, type, tag, owner, clock)
	, m_aux_strobe_cb(*this)
	, m_pb_output(0xff)
{
}

machine_config_constructor taito68705_mcu_device::device_mconfig_additions() const
{
	return MACHINE_CONFIG_NAME(taito68705);
}

void taito68705_mcu_device::device_start()
{
	taito68705_mcu_device_base::device_start();

	m_aux_strobe_cb.resolve_safe();

	save_item(NAME(m_pb_output));

	m_pb_output = 0xff;
}


/*
 *  Port B connections:
 *  parts in [ ] are optional (not used by buggychl)
 *
 *  all bits are logical 1 when read (+5V pullup)
 *
 *  0   n.c.
 *  1   W  IRQ ack and enable latch which holds data from main Z80 memory
 *  2   W  loads latch to Z80
 *  3   W  to Z80 BUSRQ (put it on hold?)
 *  4   W  n.c.
 *  5   W  [selects Z80 memory access direction (0 = write 1 = read)]
 *  6   W  [loads the latch which holds the low 8 bits of the address of
 *               the main Z80 memory location to access]
 *  7   W  [loads the latch which holds the high 8 bits of the address of
 *               the main Z80 memory location to access]
 */


READ8_MEMBER(taito68705_mcu_device::mcu_portc_r)
{
	// PC0 is the host semaphore flag (active high)
	// PC1 is the MCU semaphore flag (active low)
	return (host_flag() ? 0x01 : 0x00) | (mcu_flag() ? 0x00 : 0x02) | 0xfc;
}

WRITE8_MEMBER(taito68705_mcu_device::mcu_portb_w)
{
	// some games have additional peripherals strobed on falling edge
	u8 const old_pa_value(pa_value());
	u8 const aux_strobes((mem_mask & ~data & m_pb_output) >> 2);

	// rising edge on PB1 clears the host semaphore flag
	// PB2 sets the MCU semaphore when low
	latch_control(data, m_pb_output, 1, 2);

	// callbacks for other peripherals
	for (unsigned i = 0; i < 6; ++i)
	{
		if (BIT(aux_strobes, i))
			m_aux_strobe_cb(i, old_pa_value, 0xff);
	}
}


/* The Tiger Heli interface has some extensions, handle them here */

taito68705_mcu_tiger_device::taito68705_mcu_tiger_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
	: taito68705_mcu_device(mconfig, TAITO68705_MCU_TIGER, tag, owner, clock)
{
}

READ8_MEMBER(taito68705_mcu_tiger_device::mcu_portc_r)
{
	// Tiger Heli has these status bits inverted MCU-side
	return taito68705_mcu_device::mcu_portc_r(space, offset, mem_mask) ^ 0x03;
}


// Arkanoid/Puzznic (latch control on PC2 and PC3 instead of PB1 and PB2)

READ8_MEMBER(arkanoid_mcu_device_base::mcu_pb_r)
{
	return m_portb_r_cb(space, offset, mem_mask);
}

READ8_MEMBER(arkanoid_mcu_device_base::mcu_pc_r)
{
	// PC0 is the host semaphore flag (active high)
	// PC1 is the MCU semaphore flag (active low)
	return (host_flag() ? 0x01 : 0x00) | (mcu_flag() ? 0x00 : 0x02) | 0xfc;
}

WRITE8_MEMBER(arkanoid_mcu_device_base::mcu_pc_w)
{
	// rising edge on PC2 clears the host semaphore flag
	// PC3 sets the MCU semaphore when low
	latch_control(data, m_pc_output, 2, 3);
}

arkanoid_mcu_device_base::arkanoid_mcu_device_base(
		machine_config const &mconfig,
		device_type type,
		char const *tag,
		device_t *owner,
		u32 clock)
	: taito68705_mcu_device_base(mconfig, type, tag, owner, clock)
	, m_portb_r_cb(*this)
	, m_pc_output(0xff)
{
}

void arkanoid_mcu_device_base::device_start()
{
	taito68705_mcu_device_base::device_start();

	m_portb_r_cb.resolve_safe(0xff);

	save_item(NAME(m_pc_output));

	m_pc_output = 0xff;
}


arkanoid_68705p3_device::arkanoid_68705p3_device(
		machine_config const &mconfig,
		char const *tag,
		device_t *owner,
		u32 clock)
	: arkanoid_mcu_device_base(mconfig, ARKANOID_68705P3, tag, owner, clock)
{
}

machine_config_constructor arkanoid_68705p3_device::device_mconfig_additions() const
{
	return MACHINE_CONFIG_NAME(arkanoid_68705p3);
}


arkanoid_68705p5_device::arkanoid_68705p5_device(
		machine_config const &mconfig,
		char const *tag,
		device_t *owner,
		u32 clock)
	: arkanoid_mcu_device_base(mconfig, ARKANOID_68705P5, tag, owner, clock)
{
}

machine_config_constructor arkanoid_68705p5_device::device_mconfig_additions() const
{
	return MACHINE_CONFIG_NAME(arkanoid_68705p5);
}