1 // license:BSD-3-Clause
2 // copyright-holders:Barry Rodewald
3 /*
4  *  Western Digital WD7600 PC system chipset
5  *
6  *  WD76C10 - system control
7  *  WD76C20 - FDC, RTC, Bus interface
8  *  WD76C30 - 1 parallel and 2 serial ports
9  *
10  *  Created on: 5/05/2014
11  *
12  *  TODO:  pretty much everything
13  */
14 
15 #include "emu.h"
16 #include "machine/wd7600.h"
17 
18 #define VERBOSE 1
19 #include "logmacro.h"
20 
21 
22 DEFINE_DEVICE_TYPE(WD7600, wd7600_device, "wd7600", "Western Digital WD7600 chipset")
23 
device_add_mconfig(machine_config & config)24 void wd7600_device::device_add_mconfig(machine_config & config)
25 {
26 	AM9517A(config, m_dma1, 0);
27 	m_dma1->out_hreq_callback().set(m_dma2, FUNC(am9517a_device::dreq0_w));
28 	m_dma1->out_eop_callback().set(FUNC(wd7600_device::dma1_eop_w));
29 	m_dma1->in_memr_callback().set(FUNC(wd7600_device::dma_read_byte));
30 	m_dma1->out_memw_callback().set(FUNC(wd7600_device::dma_write_byte));
31 	m_dma1->in_ior_callback<0>().set(FUNC(wd7600_device::dma1_ior0_r));
32 	m_dma1->in_ior_callback<1>().set(FUNC(wd7600_device::dma1_ior1_r));
33 	m_dma1->in_ior_callback<2>().set(FUNC(wd7600_device::dma1_ior2_r));
34 	m_dma1->in_ior_callback<3>().set(FUNC(wd7600_device::dma1_ior3_r));
35 	m_dma1->out_iow_callback<0>().set(FUNC(wd7600_device::dma1_iow0_w));
36 	m_dma1->out_iow_callback<1>().set(FUNC(wd7600_device::dma1_iow1_w));
37 	m_dma1->out_iow_callback<2>().set(FUNC(wd7600_device::dma1_iow2_w));
38 	m_dma1->out_iow_callback<3>().set(FUNC(wd7600_device::dma1_iow3_w));
39 	m_dma1->out_dack_callback<0>().set(FUNC(wd7600_device::dma1_dack0_w));
40 	m_dma1->out_dack_callback<1>().set(FUNC(wd7600_device::dma1_dack1_w));
41 	m_dma1->out_dack_callback<2>().set(FUNC(wd7600_device::dma1_dack2_w));
42 	m_dma1->out_dack_callback<3>().set(FUNC(wd7600_device::dma1_dack3_w));
43 
44 	AM9517A(config, m_dma2, 0);
45 	m_dma2->out_hreq_callback().set(FUNC(wd7600_device::dma2_hreq_w));
46 	m_dma2->in_memr_callback().set(FUNC(wd7600_device::dma_read_word));
47 	m_dma2->out_memw_callback().set(FUNC(wd7600_device::dma_write_word));
48 	m_dma2->in_ior_callback<1>().set(FUNC(wd7600_device::dma2_ior1_r));
49 	m_dma2->in_ior_callback<2>().set(FUNC(wd7600_device::dma2_ior2_r));
50 	m_dma2->in_ior_callback<3>().set(FUNC(wd7600_device::dma2_ior3_r));
51 	m_dma2->out_iow_callback<1>().set(FUNC(wd7600_device::dma2_iow1_w));
52 	m_dma2->out_iow_callback<2>().set(FUNC(wd7600_device::dma2_iow2_w));
53 	m_dma2->out_iow_callback<3>().set(FUNC(wd7600_device::dma2_iow3_w));
54 	m_dma2->out_dack_callback<0>().set(FUNC(wd7600_device::dma2_dack0_w));
55 	m_dma2->out_dack_callback<1>().set(FUNC(wd7600_device::dma2_dack1_w));
56 	m_dma2->out_dack_callback<2>().set(FUNC(wd7600_device::dma2_dack2_w));
57 	m_dma2->out_dack_callback<3>().set(FUNC(wd7600_device::dma2_dack3_w));
58 
59 	PIC8259(config, m_pic1, 0);
60 	m_pic1->out_int_callback().set(FUNC(wd7600_device::pic1_int_w));
61 	m_pic1->in_sp_callback().set_constant(1);
62 	m_pic1->read_slave_ack_callback().set(FUNC(wd7600_device::pic1_slave_ack_r));
63 
64 	PIC8259(config, m_pic2, 0);
65 	m_pic2->out_int_callback().set(m_pic1, FUNC(pic8259_device::ir2_w));
66 	m_pic2->in_sp_callback().set_constant(0);
67 
68 	PIT8254(config, m_ctc, 0);
69 	m_ctc->set_clk<0>(XTAL(14'318'181) / 12.0);
70 	m_ctc->out_handler<0>().set(m_pic1, FUNC(pic8259_device::ir0_w));
71 	m_ctc->set_clk<1>(XTAL(14'318'181) / 12.0);
72 	m_ctc->out_handler<1>().set(FUNC(wd7600_device::ctc_out1_w));
73 	m_ctc->set_clk<2>(XTAL(14'318'181) / 12.0);
74 	m_ctc->out_handler<2>().set(FUNC(wd7600_device::ctc_out2_w));
75 
76 	DS12885(config, m_rtc);
77 	m_rtc->irq().set(m_pic2, FUNC(pic8259_device::ir0_w));
78 	m_rtc->set_century_index(0x32);
79 }
80 
81 
wd7600_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)82 wd7600_device::wd7600_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
83 	device_t(mconfig, WD7600, tag, owner, clock),
84 	m_read_ior(*this),
85 	m_write_iow(*this),
86 	m_write_tc(*this),
87 	m_write_hold(*this),
88 	m_write_nmi(*this),
89 	m_write_intr(*this),
90 	m_write_cpureset(*this),
91 	m_write_a20m(*this),
92 	m_write_spkr(*this),
93 	m_dma1(*this, "dma1"),
94 	m_dma2(*this, "dma2"),
95 	m_pic1(*this, "intc1"),
96 	m_pic2(*this, "intc2"),
97 	m_ctc(*this, "ctc"),
98 	m_rtc(*this, "rtc"),
99 	m_cpu(*this, finder_base::DUMMY_TAG),
100 	m_keybc(*this, finder_base::DUMMY_TAG),
101 	m_ram(*this, finder_base::DUMMY_TAG),
102 	m_bios(*this, finder_base::DUMMY_TAG),
103 	m_isa(*this, finder_base::DUMMY_TAG),
104 	m_portb(0x0f),
105 	m_iochck(1),
106 	m_nmi_mask(1),
107 	m_alt_a20(0),
108 	m_ext_gatea20(0),
109 	m_kbrst(1),
110 	m_refresh_toggle(0),
111 	m_dma_eop(0),
112 	m_dma_high_byte(0xff),
113 	m_dma_channel(-1)
114 {
115 }
116 
117 
device_start()118 void wd7600_device::device_start()
119 {
120 	// make sure the ram device is already running
121 	if (!m_ram->started())
122 		throw device_missing_dependencies();
123 
124 	// resolve callbacks
125 	m_read_ior.resolve_safe(0);
126 	m_write_iow.resolve_safe();
127 	m_write_tc.resolve_safe();
128 	m_write_hold.resolve_safe();
129 	m_write_nmi.resolve_safe();
130 	m_write_intr.resolve_safe();
131 	m_write_cpureset.resolve_safe();
132 	m_write_a20m.resolve_safe();
133 	m_write_spkr.resolve_safe();
134 
135 	m_space = &m_cpu->space(AS_PROGRAM);
136 	m_space_io = &m_cpu->space(AS_IO);
137 
138 	// install base memory
139 	m_space->install_ram(0x000000, 0x09ffff, m_ram->pointer());
140 	m_space->install_ram(0x0d0000, 0x0effff, m_ram->pointer() + 0xd0000);
141 
142 	// install extended memory
143 	if (m_ram->size() > 0x100000)
144 		m_space->install_ram(0x100000, m_ram->size() - 1, m_ram->pointer() + 0x100000);
145 
146 	// install video BIOS (we should use the VGA BIOS at the beginning of the system BIOS ROM, but that gives a
147 	// blank display (but still runs))
148 	//m_space->install_rom(0x000c0000, 0x000cffff, &m_bios[0x00000]);
149 	m_space->install_rom(0x000c0000, 0x000cffff, m_isa);
150 
151 	// install BIOS ROM at cpu initial pc
152 	m_space->install_rom(0x000f0000, 0x000fffff, &m_bios[0x10000]);
153 	if(m_space->addrmask() == 0xffffffff)  // 32-bit address space only
154 		m_space->install_rom(0xffff0000, 0xffffffff, &m_bios[0x10000]);
155 	else
156 		m_space->install_rom(0x00ff0000, 0x00ffffff, &m_bios[0x10000]);
157 
158 	// install i/o accesses
159 	if (m_space_io->data_width() == 16)
160 	{
161 		// FIXME: are all these address ranges correct?
162 		m_space_io->install_readwrite_handler(0x0000, 0x000f, read8sm_delegate(*m_dma1, FUNC(am9517a_device::read)), write8sm_delegate(*m_dma1, FUNC(am9517a_device::write)), 0xffff);
163 		m_space_io->install_readwrite_handler(0x0020, 0x003f, read8sm_delegate(*m_pic1, FUNC(pic8259_device::read)), write8sm_delegate(*m_pic1, FUNC(pic8259_device::write)), 0xffff);
164 		m_space_io->install_readwrite_handler(0x0040, 0x0043, read8sm_delegate(*m_ctc, FUNC(pit8254_device::read)), write8sm_delegate(*m_ctc, FUNC(pit8254_device::write)), 0xffff);
165 		m_space_io->install_readwrite_handler(0x0060, 0x0061, read8smo_delegate(*this, FUNC(wd7600_device::keyb_data_r)), write8smo_delegate(*this, FUNC(wd7600_device::keyb_data_w)), 0x00ff);
166 		m_space_io->install_readwrite_handler(0x0060, 0x0061, read8smo_delegate(*this, FUNC(wd7600_device::portb_r)), write8smo_delegate(*this, FUNC(wd7600_device::portb_w)), 0xff00);
167 		m_space_io->install_readwrite_handler(0x0064, 0x0065, read8smo_delegate(*this, FUNC(wd7600_device::keyb_status_r)), write8smo_delegate(*this, FUNC(wd7600_device::keyb_cmd_w)), 0x00ff);
168 		m_space_io->install_readwrite_handler(0x0070, 0x007f, read8sm_delegate(*m_rtc, FUNC(mc146818_device::read)), write8sm_delegate(*this, FUNC(wd7600_device::rtc_w)), 0xffff);
169 		m_space_io->install_readwrite_handler(0x0080, 0x008f, read8sm_delegate(*this, FUNC(wd7600_device::dma_page_r)), write8sm_delegate(*this, FUNC(wd7600_device::dma_page_w)), 0xffff);
170 		m_space_io->install_readwrite_handler(0x0092, 0x0093, read8smo_delegate(*this, FUNC(wd7600_device::a20_reset_r)), write8smo_delegate(*this, FUNC(wd7600_device::a20_reset_w)), 0x00ff);
171 		m_space_io->install_readwrite_handler(0x00a0, 0x00a3, read8sm_delegate(*m_pic2, FUNC(pic8259_device::read)), write8sm_delegate(*m_pic2, FUNC(pic8259_device::write)), 0xffff);
172 		m_space_io->install_readwrite_handler(0x00c0, 0x00df, read8sm_delegate(*m_dma2, FUNC(am9517a_device::read)), write8sm_delegate(*m_dma2, FUNC(am9517a_device::write)), 0x00ff);
173 		m_space_io->install_readwrite_handler(0x2072, 0x2073, read16smo_delegate(*this, FUNC(wd7600_device::refresh_r)), write16smo_delegate(*this, FUNC(wd7600_device::refresh_w)));
174 		m_space_io->install_readwrite_handler(0x2872, 0x2873, read16smo_delegate(*this, FUNC(wd7600_device::chipsel_r)), write16smo_delegate(*this, FUNC(wd7600_device::chipsel_w)));
175 		m_space_io->install_readwrite_handler(0x3872, 0x3873, read16smo_delegate(*this, FUNC(wd7600_device::mem_ctrl_r)), write16smo_delegate(*this, FUNC(wd7600_device::mem_ctrl_w)));
176 		m_space_io->install_readwrite_handler(0x4872, 0x4873, read16s_delegate(*this, FUNC(wd7600_device::bank_01_start_r)), write16s_delegate(*this, FUNC(wd7600_device::bank_01_start_w)));
177 		m_space_io->install_readwrite_handler(0x5072, 0x5073, read16s_delegate(*this, FUNC(wd7600_device::bank_23_start_r)), write16s_delegate(*this, FUNC(wd7600_device::bank_23_start_w)));
178 		m_space_io->install_readwrite_handler(0x5872, 0x5873, read16smo_delegate(*this, FUNC(wd7600_device::split_addr_r)), write16smo_delegate(*this, FUNC(wd7600_device::split_addr_w)));
179 		m_space_io->install_readwrite_handler(0x9872, 0x9873, read16smo_delegate(*this, FUNC(wd7600_device::diag_r)), write16smo_delegate(*this, FUNC(wd7600_device::diag_w)));
180 	}
181 	else
182 	{
183 		assert(m_space_io->data_width() == 32);
184 		m_space_io->install_readwrite_handler(0x0000, 0x000f, read8sm_delegate(*m_dma1, FUNC(am9517a_device::read)), write8sm_delegate(*m_dma1, FUNC(am9517a_device::write)), 0xffffffff);
185 		m_space_io->install_readwrite_handler(0x0020, 0x003f, read8sm_delegate(*m_pic1, FUNC(pic8259_device::read)), write8sm_delegate(*m_pic1, FUNC(pic8259_device::write)), 0x0000ffff);
186 		m_space_io->install_readwrite_handler(0x0040, 0x0043, read8sm_delegate(*m_ctc, FUNC(pit8254_device::read)), write8sm_delegate(*m_ctc, FUNC(pit8254_device::write)), 0xffffffff);
187 		m_space_io->install_readwrite_handler(0x0060, 0x0063, read8smo_delegate(*this, FUNC(wd7600_device::keyb_data_r)), write8smo_delegate(*this, FUNC(wd7600_device::keyb_data_w)), 0x000000ff);
188 		m_space_io->install_readwrite_handler(0x0060, 0x0063, read8smo_delegate(*this, FUNC(wd7600_device::portb_r)), write8smo_delegate(*this, FUNC(wd7600_device::portb_w)), 0x0000ff00);
189 		m_space_io->install_readwrite_handler(0x0064, 0x0067, read8smo_delegate(*this, FUNC(wd7600_device::keyb_status_r)), write8smo_delegate(*this, FUNC(wd7600_device::keyb_cmd_w)), 0x000000ff);
190 		m_space_io->install_readwrite_handler(0x0070, 0x007f, read8sm_delegate(*m_rtc, FUNC(mc146818_device::read)), write8sm_delegate(*this, FUNC(wd7600_device::rtc_w)), 0x0000ffff);
191 		m_space_io->install_readwrite_handler(0x0080, 0x008f, read8sm_delegate(*this, FUNC(wd7600_device::dma_page_r)), write8sm_delegate(*this, FUNC(wd7600_device::dma_page_w)), 0xffffffff);
192 		m_space_io->install_readwrite_handler(0x0090, 0x0093, read8smo_delegate(*this, FUNC(wd7600_device::a20_reset_r)), write8smo_delegate(*this, FUNC(wd7600_device::a20_reset_w)), 0x00ff0000);
193 		m_space_io->install_readwrite_handler(0x00a0, 0x00a3, read8sm_delegate(*m_pic2, FUNC(pic8259_device::read)), write8sm_delegate(*m_pic2, FUNC(pic8259_device::write)), 0x0000ffff);
194 		m_space_io->install_readwrite_handler(0x00c0, 0x00df, read8sm_delegate(*m_dma2, FUNC(am9517a_device::read)), write8sm_delegate(*m_dma2, FUNC(am9517a_device::write)), 0x00ff00ff);
195 		m_space_io->install_readwrite_handler(0x2070, 0x2073, read16smo_delegate(*this, FUNC(wd7600_device::refresh_r)), write16smo_delegate(*this, FUNC(wd7600_device::refresh_w)), 0xffff0000);
196 		m_space_io->install_readwrite_handler(0x2870, 0x2873, read16smo_delegate(*this, FUNC(wd7600_device::chipsel_r)), write16smo_delegate(*this, FUNC(wd7600_device::chipsel_w)), 0xffff0000);
197 		m_space_io->install_readwrite_handler(0x3870, 0x3873, read16smo_delegate(*this, FUNC(wd7600_device::mem_ctrl_r)), write16smo_delegate(*this, FUNC(wd7600_device::mem_ctrl_w)), 0xffff0000);
198 		m_space_io->install_readwrite_handler(0x4870, 0x4873, read16s_delegate(*this, FUNC(wd7600_device::bank_01_start_r)), write16s_delegate(*this, FUNC(wd7600_device::bank_01_start_w)), 0xffff0000);
199 		m_space_io->install_readwrite_handler(0x5070, 0x5073, read16s_delegate(*this, FUNC(wd7600_device::bank_23_start_r)), write16s_delegate(*this, FUNC(wd7600_device::bank_23_start_w)), 0xffff0000);
200 		m_space_io->install_readwrite_handler(0x5870, 0x5873, read16smo_delegate(*this, FUNC(wd7600_device::split_addr_r)), write16smo_delegate(*this, FUNC(wd7600_device::split_addr_w)), 0xffff0000);
201 		m_space_io->install_readwrite_handler(0x9870, 0x9873, read16smo_delegate(*this, FUNC(wd7600_device::diag_r)), write16smo_delegate(*this, FUNC(wd7600_device::diag_w)), 0xffff0000);
202 	}
203 }
204 
device_reset()205 void wd7600_device::device_reset()
206 {
207 	m_split_start = 0;
208 	m_chip_sel = 0;
209 	m_refresh_ctrl = 0;
210 	m_memory_ctrl = 0;
211 	m_diagnostic = 0xe080;
212 
213 	for(auto & elem : m_bank_start)
214 		elem = 0;
215 
216 	// initialize dma controller clocks
217 	m_dma1->set_unscaled_clock(clock());
218 	m_dma2->set_unscaled_clock(clock());
219 }
220 
221 
WRITE_LINE_MEMBER(wd7600_device::iochck_w)222 WRITE_LINE_MEMBER( wd7600_device::iochck_w )
223 {
224 	if (BIT(m_portb, 3) == 0)
225 	{
226 		if (m_iochck && state == 0)
227 		{
228 			// set channel check latch
229 			m_portb |= 1 << 6;
230 			nmi();
231 		}
232 
233 		m_iochck = state;
234 	}
235 }
236 
nmi()237 void wd7600_device::nmi()
238 {
239 	if (m_nmi_mask & BIT(m_portb, 6))
240 	{
241 		m_write_nmi(1);
242 		m_write_nmi(0);
243 	}
244 }
245 
a20m()246 void wd7600_device::a20m()
247 {
248 	// TODO: ignore keyboard A20 signal if set in Diagnostic register (0x9872)
249 	m_write_a20m(m_alt_a20 | m_ext_gatea20);
250 }
251 
keyboard_gatea20(int state)252 void wd7600_device::keyboard_gatea20(int state)
253 {
254 	m_ext_gatea20 = state;
255 	a20m();
256 }
257 
rtc_w(offs_t offset,uint8_t data)258 void wd7600_device::rtc_w(offs_t offset, uint8_t data)
259 {
260 	if (offset == 0)
261 	{
262 		m_nmi_mask = !BIT(data, 7);
263 		data &= 0x7f;
264 	}
265 
266 	m_rtc->write(offset, data);
267 }
268 
pic1_slave_ack_r(offs_t offset)269 uint8_t wd7600_device::pic1_slave_ack_r(offs_t offset)
270 {
271 	if (offset == 2) // IRQ 2
272 		return m_pic2->acknowledge();
273 
274 	return 0x00;
275 }
276 
277 // Timer outputs
WRITE_LINE_MEMBER(wd7600_device::ctc_out1_w)278 WRITE_LINE_MEMBER( wd7600_device::ctc_out1_w )
279 {
280 	m_refresh_toggle ^= state;
281 	m_portb = (m_portb & 0xef) | (m_refresh_toggle << 4);
282 }
283 
WRITE_LINE_MEMBER(wd7600_device::ctc_out2_w)284 WRITE_LINE_MEMBER( wd7600_device::ctc_out2_w )
285 {
286 	m_write_spkr(!(state));
287 	m_portb = (m_portb & 0xdf) | (state << 5);
288 }
289 
290 // Keyboard
keyb_data_w(uint8_t data)291 void wd7600_device::keyb_data_w(uint8_t data)
292 {
293 //  LOG("WD7600: keyboard data write %02x\n", data);
294 	m_keybc->data_w(data);
295 }
296 
keyb_data_r()297 uint8_t wd7600_device::keyb_data_r()
298 {
299 	uint8_t ret = m_keybc->data_r();
300 //  LOG("WD7600: keyboard data read %02x\n", ret);
301 	return ret;
302 }
303 
keyb_cmd_w(uint8_t data)304 void wd7600_device::keyb_cmd_w(uint8_t data)
305 {
306 //  LOG("WD7600: keyboard command %02x\n", data);
307 	m_keybc->command_w(data);
308 }
309 
keyb_status_r()310 uint8_t wd7600_device::keyb_status_r()
311 {
312 	return m_keybc->status_r();
313 }
314 
portb_r()315 uint8_t wd7600_device::portb_r()
316 {
317 	return m_portb;
318 }
319 
portb_w(uint8_t data)320 void wd7600_device::portb_w(uint8_t data)
321 {
322 	m_portb = (m_portb & 0xf0) | (data & 0x0f);
323 
324 	// bit 5 forced to 1 if timer disabled
325 	if (!BIT(m_portb, 0))
326 		m_portb |= 1 << 5;
327 
328 	m_ctc->write_gate2(BIT(m_portb, 0));
329 
330 	m_write_spkr(!BIT(m_portb, 1));
331 
332 	// clear channel check latch?
333 	if (BIT(m_portb, 3))
334 		m_portb &= 0xbf;
335 }
336 
337 // DMA controllers
page_offset()338 offs_t wd7600_device::page_offset()
339 {
340 	switch (m_dma_channel)
341 	{
342 		case 0: return (offs_t) m_dma_page[0x07] << 16;
343 		case 1: return (offs_t) m_dma_page[0x03] << 16;
344 		case 2: return (offs_t) m_dma_page[0x01] << 16;
345 		case 3: return (offs_t) m_dma_page[0x02] << 16;
346 		case 5: return (offs_t) m_dma_page[0x0b] << 16;
347 		case 6: return (offs_t) m_dma_page[0x09] << 16;
348 		case 7: return (offs_t) m_dma_page[0x0a] << 16;
349 	}
350 
351 	// should never get here
352 	return 0xff0000;
353 }
354 
dma_read_byte(offs_t offset)355 uint8_t wd7600_device::dma_read_byte(offs_t offset)
356 {
357 	if (m_dma_channel == -1)
358 		return 0xff;
359 
360 	return m_space->read_byte(page_offset() + offset);
361 }
362 
dma_write_byte(offs_t offset,uint8_t data)363 void wd7600_device::dma_write_byte(offs_t offset, uint8_t data)
364 {
365 	if (m_dma_channel == -1)
366 		return;
367 
368 	m_space->write_byte(page_offset() + offset, data);
369 }
370 
dma_read_word(offs_t offset)371 uint8_t wd7600_device::dma_read_word(offs_t offset)
372 {
373 	if (m_dma_channel == -1)
374 		return 0xff;
375 
376 	uint16_t result = m_space->read_word((page_offset() & 0xfe0000) | (offset << 1));
377 	m_dma_high_byte = result >> 8;
378 
379 	return result;
380 }
381 
dma_write_word(offs_t offset,uint8_t data)382 void wd7600_device::dma_write_word(offs_t offset, uint8_t data)
383 {
384 	if (m_dma_channel == -1)
385 		return;
386 
387 	m_space->write_word((page_offset() & 0xfe0000) | (offset << 1), (m_dma_high_byte << 8) | data);
388 }
389 
WRITE_LINE_MEMBER(wd7600_device::dma2_dack0_w)390 WRITE_LINE_MEMBER( wd7600_device::dma2_dack0_w )
391 {
392 	m_dma1->hack_w(state ? 0 : 1); // inverted?
393 }
394 
WRITE_LINE_MEMBER(wd7600_device::dma1_eop_w)395 WRITE_LINE_MEMBER( wd7600_device::dma1_eop_w )
396 {
397 	m_dma_eop = state;
398 	if (m_dma_channel != -1)
399 		m_write_tc(m_dma_channel, state, 0xff);
400 }
401 
set_dma_channel(int channel,bool state)402 void wd7600_device::set_dma_channel(int channel, bool state)
403 {
404 	//m_write_dack(channel, state);
405 
406 	if (!state)
407 	{
408 		m_dma_channel = channel;
409 		if (m_dma_eop)
410 			m_write_tc(channel, 1, 0xff);
411 	}
412 	else
413 	{
414 		if (m_dma_channel == channel)
415 		{
416 			m_dma_channel = -1;
417 			if (m_dma_eop)
418 				m_write_tc(channel, 0, 0xff);
419 		}
420 	}
421 }
422 
WRITE_LINE_MEMBER(wd7600_device::gatea20_w)423 WRITE_LINE_MEMBER( wd7600_device::gatea20_w )
424 {
425 	keyboard_gatea20(state);
426 }
427 
WRITE_LINE_MEMBER(wd7600_device::kbrst_w)428 WRITE_LINE_MEMBER( wd7600_device::kbrst_w )
429 {
430 	// convert to active low signal (gets inverted in at_keybc.c)
431 	state = (state == ASSERT_LINE ? 0 : 1);
432 
433 	// detect transition
434 	if (m_kbrst == 1 && state == 0)
435 	{
436 		m_write_cpureset(1);
437 		m_write_cpureset(0);
438 	}
439 
440 	m_kbrst = state;
441 }
442 
a20_reset_w(uint8_t data)443 void wd7600_device::a20_reset_w(uint8_t data)
444 {
445 	m_alt_a20 = BIT(data,1);
446 	a20m();
447 	// TODO: proper timing.  Reset occurs 128 cycles after changing to a 1, and lasts for 16 cycles
448 	if(BIT(data,0))
449 	{
450 		m_write_cpureset(1);
451 		m_write_cpureset(0);
452 		LOG("WD7600: System reset\n");
453 	}
454 }
455 
a20_reset_r()456 uint8_t wd7600_device::a20_reset_r()
457 {
458 	uint8_t ret = 0;
459 	if(m_alt_a20)
460 		ret |= 0x02;
461 	return ret;
462 }
463 
464 // port 0x2072 - Refresh Control, and serial/parallel port address select
refresh_r()465 uint16_t wd7600_device::refresh_r()
466 {
467 	return m_refresh_ctrl;
468 }
469 
refresh_w(uint16_t data)470 void wd7600_device::refresh_w(uint16_t data)
471 {
472 	// TODO: select serial/parallel I/O port location
473 	m_refresh_ctrl = data;
474 	LOG("WD7600: Refresh Control write %04x\n", data);
475 }
476 
477 // port 0x2872 - chip select
chipsel_r()478 uint16_t wd7600_device::chipsel_r()
479 {
480 	return m_chip_sel;
481 }
482 
chipsel_w(uint16_t data)483 void wd7600_device::chipsel_w(uint16_t data)
484 {
485 	m_chip_sel = data;
486 	LOG("WD7600: Chip Select write %04x\n", data);
487 }
488 
489 // port 0x3872 - Memory Control
mem_ctrl_r()490 uint16_t wd7600_device::mem_ctrl_r()
491 {
492 	return m_memory_ctrl;
493 }
494 
mem_ctrl_w(uint16_t data)495 void wd7600_device::mem_ctrl_w(uint16_t data)
496 {
497 	m_memory_ctrl = data;
498 	LOG("WD7600: Memory Control write %04x\n", data);
499 }
500 
501 // port 0x4872 - Bank 0 and 1 start address
bank_01_start_r(offs_t offset,uint16_t mem_mask)502 uint16_t wd7600_device::bank_01_start_r(offs_t offset, uint16_t mem_mask)
503 {
504 	return (m_bank_start[1] << 8) | m_bank_start[0];
505 }
506 
bank_01_start_w(offs_t offset,uint16_t data,uint16_t mem_mask)507 void wd7600_device::bank_01_start_w(offs_t offset, uint16_t data, uint16_t mem_mask)
508 {
509 	if(ACCESSING_BITS_0_7)
510 	{
511 		m_bank_start[0] = data & 0xff;
512 		LOG("WD7600: Bank 0 start address %08x\n", m_bank_start[0] << 16);
513 	}
514 	if(ACCESSING_BITS_8_15)
515 	{
516 		m_bank_start[1] = (data & 0xff00) >> 8;
517 		LOG("WD7600: Bank 1 start address %08x\n", m_bank_start[1] << 16);
518 	}
519 }
520 
521 // port 0x5072 - Bank 2 and 3 start address
bank_23_start_r(offs_t offset,uint16_t mem_mask)522 uint16_t wd7600_device::bank_23_start_r(offs_t offset, uint16_t mem_mask)
523 {
524 	return (m_bank_start[3] << 8) | m_bank_start[2];
525 }
526 
bank_23_start_w(offs_t offset,uint16_t data,uint16_t mem_mask)527 void wd7600_device::bank_23_start_w(offs_t offset, uint16_t data, uint16_t mem_mask)
528 {
529 	if(ACCESSING_BITS_0_7)
530 	{
531 		m_bank_start[2] = data & 0xff;
532 		LOG("WD7600: Bank 2 start address %08x\n", m_bank_start[2] << 16);
533 	}
534 	if(ACCESSING_BITS_8_15)
535 	{
536 		m_bank_start[3] = (data & 0xff00) >> 8;
537 		LOG("WD7600: Bank 3 start address %08x\n", m_bank_start[3] << 16);
538 	}
539 }
540 
541 // port 0x5872 - split starting address (used for BIOS shadowing)
split_addr_r()542 uint16_t wd7600_device::split_addr_r()
543 {
544 	return m_split_start;
545 }
546 
split_addr_w(uint16_t data)547 void wd7600_device::split_addr_w(uint16_t data)
548 {
549 	m_split_start = data;
550 	LOG("WD7600: Split start address write %04x\n", data);
551 }
552 
553 // port 0x9872 - Diagnostic
diag_r()554 uint16_t wd7600_device::diag_r()
555 {
556 	return m_diagnostic | 0xe080;
557 }
558 
diag_w(uint16_t data)559 void wd7600_device::diag_w(uint16_t data)
560 {
561 	m_diagnostic = data;
562 	LOG("WD7600: Diagnostic write %04x\n", data);
563 }
564