1 // license:BSD-3-Clause
2 // copyright-holders:Mike Harris, Aaron Giles
3 /***************************************************************************
4 
5     Namco 06XX
6 
7     This chip is used as an interface to up to 4 other custom chips.
8     It signals IRQs to the custom MCUs when writes happen, and generates
9     NMIs to the controlling CPU to drive reads based on a clock.
10 
11     It uses a clock divider that's used to pulse the NMI and custom chip select
12     lines.
13 
14     The control register controls chip as such: the low 4 bits are chip selects
15     (active high), the 5th bit is read/!write, and the upper 3 bits are the
16     clock divide.
17 
18     SD0-SD7 are data I/O lines connecting to the controlling CPU
19     SEL selects either control (1) or data (0), usually connected to
20         an address line of the controlling CPU
21     /NMI is an NMI signal line for the controlling CPU
22 
23     ID0-ID7 are data I/O lines connecting to the other custom chips
24     /IO1-/IO4 are IRQ signal lines for each custom chip
25 
26                    +------+
27                 [1]|1   28|Vcc
28                 ID7|2   27|SD7
29                 ID6|3   26|SD6
30                 ID5|4   25|SD5
31                 ID4|5   24|SD4
32                 ID3|6   23|SD3
33                 ID2|7   22|SD2
34                 ID1|8   21|SD1
35                 ID0|9   20|SD0
36                /IO1|10  19|/NMI
37                /IO2|11  18|/CS
38                /IO3|12  17|CLOCK
39                /IO4|13  16|R/W
40                 GND|14  15|SEL
41                    +------+
42 
43     [1] on polepos, galaga, xevious, and bosco: connected to K3 of the 51xx
44         on bosco and xevious, connected to R8 of the 50xx
45 
46     Note that Xevious has a potential race condition at 0xE9. It checks if
47     the control register is 0x10 (chip disabled), then 4 instructions later
48     acts on that check. If an NMI occurs between, it can crash.
49 
50 
51     06XX interface:
52     ---------------
53     Galaga                  51XX  ----  ----  54XX
54     Bosconian (CPU board)   51XX  ----  50XX  54XX
55     Bosconian (Video board) 50XX  52XX  ----  ----
56     Xevious                 51XX  ----  50XX  54XX
57     Dig Dug                 51XX  53XX  ----  ----
58     Pole Position / PP II   51XX  53XX  52XX  54XX
59 
60 
61     Galaga writes:
62         control = 10(000), data = FF at startup
63         control = 71(011), read 3, control = 10
64         control = A1(101), write 4, control = 10
65         control = A8(101), write 12, control = 10
66 
67     Xevious writes:
68         control = 10 at startup
69         control = A1(101), write 6, control = 10
70         control = 71(011), read 3, control = 10
71         control = 64(011), write 1, control = 10
72         control = 74(011), read 4, control = 10
73         control = 68(011), write 7, control = 10
74 
75     Dig Dug writes:
76         control = 10(000), data = 10 at startup
77         control = A1(101), write 3, control = 10
78         control = 71(011), read 3, control = 10
79         control = D2(110), read 2, control = 10
80 
81     Bosco writes:
82         control = 10(000), data = FF at startup
83         control = C8(110), write 17, control = 10
84         control = 61(011), write 1, control = 10
85         control = 71(011), read 3, control = 10
86         control = 94(100), read 4, control = 10
87         control = 64(011), write 1, control = 10
88         control = 84(100), write 5, control = 10
89 
90 
91         control = 34(001), write 1, control = 10
92 
93 ***************************************************************************/
94 
95 #include "emu.h"
96 #include "machine/namco06.h"
97 
98 #define VERBOSE 0
99 #include "logmacro.h"
100 
101 
TIMER_CALLBACK_MEMBER(namco_06xx_device::nmi_generate)102 TIMER_CALLBACK_MEMBER( namco_06xx_device::nmi_generate )
103 {
104 	// This timer runs at twice the clock, since we do work on both the
105 	// rising and falling edge.
106 	//
107 	// During reads, the first NMI pulse is supressed to give the chip a
108 	// cycle to write.
109 	//
110 	// If the control register is written while CS is asserted, RW won't be
111 	// changed until the next rising edge.
112 
113 	if (m_rw_change && m_next_timer_state)
114 	{
115 		if (!m_rw_stretch)
116 		{
117 			m_rw[0](0, BIT(m_control, 4));
118 			m_rw[1](0, BIT(m_control, 4));
119 			m_rw[2](0, BIT(m_control, 4));
120 			m_rw[3](0, BIT(m_control, 4));
121 			m_rw_change = false;
122 		}
123 	}
124 
125 	if (m_next_timer_state && !m_nmi_stretch )
126 	{
127 		set_nmi(ASSERT_LINE);
128 	}
129 	else
130 	{
131 		set_nmi(CLEAR_LINE);
132 	}
133 
134 	m_chipsel[0](0, BIT(m_control, 0) && m_next_timer_state);
135 	m_chipsel[1](0, BIT(m_control, 1) && m_next_timer_state);
136 	m_chipsel[2](0, BIT(m_control, 2) && m_next_timer_state);
137 	m_chipsel[3](0, BIT(m_control, 3) && m_next_timer_state);
138 
139 	m_next_timer_state = !m_next_timer_state;
140 	m_nmi_stretch = false;
141 	m_rw_stretch = false;
142 }
143 
data_r(offs_t offset)144 uint8_t namco_06xx_device::data_r(offs_t offset)
145 {
146 	uint8_t result = 0xff;
147 
148 	if (!BIT(m_control, 4))
149 	{
150 		logerror("%s: 06XX '%s' read in write mode %02x\n",machine().describe_context(),tag(),m_control);
151 		return 0;
152 	}
153 
154 	if (BIT(m_control, 0)) result &= m_read[0](0);
155 	if (BIT(m_control, 1)) result &= m_read[1](0);
156 	if (BIT(m_control, 2)) result &= m_read[2](0);
157 	if (BIT(m_control, 3)) result &= m_read[3](0);
158 
159 	return result;
160 }
161 
162 
data_w(offs_t offset,uint8_t data)163 void namco_06xx_device::data_w(offs_t offset, uint8_t data)
164 {
165 	if (BIT(m_control, 4))
166 	{
167 		logerror("%s: 06XX '%s' write in read mode %02x\n",machine().describe_context(),tag(),m_control);
168 		return;
169 	}
170 	if (BIT(m_control, 0)) m_write[0](0, data);
171 	if (BIT(m_control, 1)) m_write[1](0, data);
172 	if (BIT(m_control, 2)) m_write[2](0, data);
173 	if (BIT(m_control, 3)) m_write[3](0, data);
174 }
175 
176 
ctrl_r()177 uint8_t namco_06xx_device::ctrl_r()
178 {
179 	return m_control;
180 }
181 
ctrl_w(uint8_t data)182 void namco_06xx_device::ctrl_w(uint8_t data)
183 {
184 	m_control = data;
185 
186 	// The upper 3 control bits are the clock divider.
187 	if ((m_control & 0xe0) == 0)
188 	{
189 		m_nmi_timer->adjust(attotime::never);
190 		set_nmi(CLEAR_LINE);
191 		m_chipsel[0](0, CLEAR_LINE);
192 		m_chipsel[1](0, CLEAR_LINE);
193 		m_chipsel[2](0, CLEAR_LINE);
194 		m_chipsel[3](0, CLEAR_LINE);
195 		// Setting this to true makes the next RW change not stretch.
196 		m_next_timer_state = true;
197 	}
198 	else
199 	{
200 		m_rw_stretch = !m_next_timer_state;
201 		m_rw_change = true;
202 		m_next_timer_state = true;
203 		m_nmi_stretch = BIT(m_control, 4);
204 		// NMI is cleared immediately if its to be stretched.
205 		if (m_nmi_stretch) set_nmi(CLEAR_LINE);
206 
207 		uint8_t num_shifts = (m_control & 0xe0) >> 5;
208 		uint8_t divisor = 1 << num_shifts;
209 		// The next change should happen on the next clock falling edge.
210 		// Xevious' race causes this to bootloopsif it isn't 0.
211 		m_nmi_timer->adjust(attotime::zero, 0, attotime::from_hz(clock() / divisor) / 2);
212 	}
213 }
214 
215 
set_nmi(int state)216 void namco_06xx_device::set_nmi(int state)
217 {
218 	if (!m_nmicpu->suspended(SUSPEND_REASON_HALT | SUSPEND_REASON_RESET | SUSPEND_REASON_DISABLE))
219 	{
220 		m_nmicpu->set_input_line(INPUT_LINE_NMI, state);
221 	}
222 }
223 
224 
225 DEFINE_DEVICE_TYPE(NAMCO_06XX, namco_06xx_device, "namco06", "Namco 06xx")
226 
namco_06xx_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)227 namco_06xx_device::namco_06xx_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
228 	: device_t(mconfig, NAMCO_06XX, tag, owner, clock)
229 	, m_control(0)
230 	, m_next_timer_state(false)
231 	, m_nmi_stretch(false)
232 	, m_rw_stretch(false)
233 	, m_rw_change(false)
234 	, m_nmicpu(*this, finder_base::DUMMY_TAG)
235 	, m_chipsel(*this)
236 	, m_rw(*this)
237 	, m_read(*this)
238 	, m_write(*this)
239 {
240 }
241 
242 //-------------------------------------------------
243 //  device_start - device-specific startup
244 //-------------------------------------------------
245 
device_start()246 void namco_06xx_device::device_start()
247 {
248 	m_chipsel.resolve_all_safe();
249 	m_rw.resolve_all_safe();
250 	m_read.resolve_all_safe(0xff);
251 	m_write.resolve_all_safe();
252 
253 	/* allocate a timer */
254 	m_nmi_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(namco_06xx_device::nmi_generate),this));
255 
256 	save_item(NAME(m_control));
257 	save_item(NAME(m_next_timer_state));
258 	save_item(NAME(m_nmi_stretch));
259 	save_item(NAME(m_rw_stretch));
260 	save_item(NAME(m_rw_change));
261 }
262 
263 //-------------------------------------------------
264 //  device_reset - device-specific reset
265 //-------------------------------------------------
266 
device_reset()267 void namco_06xx_device::device_reset()
268 {
269 	m_control = 0;
270 }
271