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
|
/***************************************************************************
IREM "M72" sound hardware
All games have a YM2151 for music, and most of them also samples. Samples
are not handled consistently by all the games, some use a high frequency NMI
handler to push them through a DAC, others use external hardware.
In the following table, the NMI column indicates with a No the games whose
NMI handler only consists of RETN. R-Type is an exception, it doesn't have
a valid NMI handler at all.
Game Year ID string NMI
-------------------------------------- ---- ------------ ---
R-Type 1987 - (earlier version, no samples)
Battle Chopper / Mr. Heli 1987 Rev 2.20 Yes
Vigilante 1988 Rev 2.20 Yes
Ninja Spirit 1988 Rev 2.20 Yes
Image Fight 1988 Rev 2.20 Yes
Legend of Hero Tonma 1989 Rev 2.20 Yes
X Multiply 1989 Rev 2.20 Yes
Dragon Breed 1989 Rev 2.20 Yes
Kickle Cubicle 1988 Rev 2.21 Yes
Shisensho 1989 Rev 2.21 Yes
R-Type II 1989 Rev 2.21 Yes
Major Title 1990 Rev 2.21 Yes
Air Duel 1990 Rev 3.14 M72 No
Daiku no Gensan 1990 Rev 3.14 M81 Yes
Daiku no Gensan (M72) 1990 Rev 3.15 M72 No
Hammerin' Harry 1990 Rev 3.15 M81 Yes
Ken-Go 1991 Rev 3.15 M81 Yes
Pound for Pound 1990 Rev 3.15 M83 No
Cosmic Cop 1991 Rev 3.15 M81 Yes
Gallop - Armed Police Unit 1991 Rev 3.15 M72 No
Hasamu 1991 Rev 3.15 M81 Yes
Bomber Man 1991 Rev 3.15 M81 Yes
Bomber Man World (Japan) 1992 Rev 3.31 M81 Yes
Bomber Man World (World) / Atomic Punk 1992 Rev 3.31 M99 No
Quiz F-1 1,2finish 1992 Rev 3.33 M81 Yes
Risky Challenge 1993 Rev 3.34 M81 Yes
Shisensho II 1993 Rev 3.34 M81 Yes
***************************************************************************/
#include "driver.h"
#include "sound/dac.h"
#include "m72.h"
/*
The sound CPU runs in interrup mode 0. IRQ is shared by two sources: the
YM2151 (bit 4 of the vector), and the main CPU (bit 5).
Since the vector can be changed from different contexts (the YM2151 timer
callback, the main CPU context, and the sound CPU context), it's important
to accurately arbitrate the changes to avoid out-of-order execution. We do
that by handling all vector changes in a single timer callback.
*/
enum
{
VECTOR_INIT,
YM2151_ASSERT,
YM2151_CLEAR,
Z80_ASSERT,
Z80_CLEAR
};
static UINT8 irqvector;
static UINT32 sample_addr;
static TIMER_CALLBACK( setvector_callback )
{
switch(param)
{
case VECTOR_INIT:
irqvector = 0xff;
break;
case YM2151_ASSERT:
irqvector &= 0xef;
break;
case YM2151_CLEAR:
irqvector |= 0x10;
break;
case Z80_ASSERT:
irqvector &= 0xdf;
break;
case Z80_CLEAR:
irqvector |= 0x20;
break;
}
if (irqvector == 0)
logerror("You didn't call m72_init_sound()\n");
cpunum_set_input_line_vector(1,0,irqvector);
if (irqvector == 0xff) /* no IRQs pending */
cpunum_set_input_line(1,0,CLEAR_LINE);
else /* IRQ pending */
cpunum_set_input_line(1,0,ASSERT_LINE);
}
MACHINE_RESET( m72_sound )
{
setvector_callback(machine, NULL, VECTOR_INIT);
state_save_register_global(irqvector);
state_save_register_global(sample_addr);
}
void m72_ym2151_irq_handler(int irq)
{
if (irq)
timer_call_after_resynch(NULL, YM2151_ASSERT,setvector_callback);
else
timer_call_after_resynch(NULL, YM2151_CLEAR,setvector_callback);
}
WRITE16_HANDLER( m72_sound_command_w )
{
if (ACCESSING_LSB)
{
soundlatch_w(offset,data);
timer_call_after_resynch(NULL, Z80_ASSERT,setvector_callback);
}
}
WRITE8_HANDLER( m72_sound_command_byte_w )
{
soundlatch_w(offset,data);
timer_call_after_resynch(NULL, Z80_ASSERT,setvector_callback);
}
WRITE8_HANDLER( m72_sound_irq_ack_w )
{
timer_call_after_resynch(NULL, Z80_CLEAR,setvector_callback);
}
void m72_set_sample_start(int start)
{
sample_addr = start;
}
WRITE8_HANDLER( vigilant_sample_addr_w )
{
if (offset == 1)
sample_addr = (sample_addr & 0x00ff) | ((data << 8) & 0xff00);
else
sample_addr = (sample_addr & 0xff00) | ((data << 0) & 0x00ff);
}
WRITE8_HANDLER( shisen_sample_addr_w )
{
sample_addr >>= 2;
if (offset == 1)
sample_addr = (sample_addr & 0x00ff) | ((data << 8) & 0xff00);
else
sample_addr = (sample_addr & 0xff00) | ((data << 0) & 0x00ff);
sample_addr <<= 2;
}
WRITE8_HANDLER( rtype2_sample_addr_w )
{
sample_addr >>= 5;
if (offset == 1)
sample_addr = (sample_addr & 0x00ff) | ((data << 8) & 0xff00);
else
sample_addr = (sample_addr & 0xff00) | ((data << 0) & 0x00ff);
sample_addr <<= 5;
}
WRITE8_HANDLER( poundfor_sample_addr_w )
{
/* poundfor writes both sample start and sample END - a first for Irem...
we don't handle the end written here, 00 marks the sample end as usual. */
if (offset > 1) return;
sample_addr >>= 4;
if (offset == 1)
sample_addr = (sample_addr & 0x00ff) | ((data << 8) & 0xff00);
else
sample_addr = (sample_addr & 0xff00) | ((data << 0) & 0x00ff);
sample_addr <<= 4;
}
READ8_HANDLER( m72_sample_r )
{
return memory_region(REGION_SOUND1)[sample_addr];
}
WRITE8_HANDLER( m72_sample_w )
{
DAC_signed_data_w(0,data);
sample_addr = (sample_addr + 1) & (memory_region_length(REGION_SOUND1) - 1);
}
|