1 // license:BSD-3-Clause
2 // copyright-holders:Barry Rodewald
3 /*
4 
5     Convergent NGen series
6 
7     10-11-14 - Skeleton driver
8 
9     Interrupts based on patents:
10     level 1 - SIO
11     level 3 - timer (from PIT, presumably channel 0? Patent says "channel 3")
12     level 4 - "interrupt detector" - keyboard, printer, RTC
13     level 7 - floppy/hard disk
14 
15     DMA channels:
16     channel 0 - communications (RS-232)
17     channel 1 - X-Bus expansion modules (except disk and graphics)
18     channel 2 - graphics?
19     channel 3 - hard disk
20     On the CP-001/B26 channels 4 on are handled by the 80186.
21     channel 4 - floppy disk
22 
23     To get to "menu mode", press Space quickly after reset (might need good timing)
24     The bootstrap ROM version number is displayed, along with "B,D,L,M,P,T:"
25     You can press one of these keys for the following tests:
26     B: Bootstrap
27        Loads the system image file (from disk or master workstation)
28     D: Dump
29        RAM contents are dumped to a local disk drive or master workstation
30     L: Load
31        Loads the system image file, then enters the Panel Debugger.  Exiting the Panel
32        Debugger will continue execution of the system image
33     M: Memory Test
34        Continuously performs the Memory Test until the system is reset.
35     P: Panel Debugger
36        Enters the Panel Debugger
37     T: Type of Operating System
38        Gives an "OS:" prompt, at which you can enter the number of the system image to
39        load at the master workstation.
40 
41     Panel Debugger:
42     - Open/Modify RAM
43     Enter an address (seg:off) followed by a forward-slash, the contents of this word will
44     appear, you can enter a value to set it to, or just press Next (default: Enter) to leave
45     it as is.  It will then go on to the next word.  Pressing Return (scan code unknown
46     currently) will return to the debugger prompt.
47     - Open/Modify Register
48     Enter the register only, and the contents will appear, you can leave it or alter it (you
49     must enter all digits (eg: 0A03 if you're modifying DX) then press Return.
50     - I/O to or from a port
51     Input: Address (segment is ignored, and not required) followed by I, a byte is read from
52     the port defined by the offset, and the byte is displayed.
53     Output: Address followed by O, you are now prompted with an '='.  Enter the byte to send
54     to the port, and press Return.
55     - Set Haltpoint:
56     Enter an address (seg:off) followed by H.  Sets a haltpoint at the specified address.  Does
57     not work for ROM addresses.  Only one allowed at a time.  Haltpoint info is stored at
58     0000:01F0.  Uses a software interrupt (INT 7C), rather than INT 3.
59 
60     To start or continue from the current address, enter P.
61     To start from a specific address, enter the address (seg:off) followed by a G.
62 */
63 
64 #include "emu.h"
65 #include "bus/rs232/rs232.h"
66 #include "cpu/i386/i386.h"
67 #include "cpu/i86/i186.h"
68 #include "imagedev/floppy.h"
69 #include "imagedev/harddriv.h"
70 #include "machine/am9517a.h"
71 #include "machine/clock.h"
72 #include "machine/i8251.h"
73 #include "machine/ngen_kb.h"
74 #include "machine/pic8259.h"
75 #include "machine/pit8253.h"
76 #include "machine/wd2010.h"
77 #include "machine/wd_fdc.h"
78 #include "machine/z80sio.h"
79 #include "video/mc6845.h"
80 #include "memarray.h"
81 #include "screen.h"
82 
83 
84 class ngen_state : public driver_device
85 {
86 public:
ngen_state(const machine_config & mconfig,device_type type,const char * tag)87 	ngen_state(const machine_config &mconfig, device_type type, const char *tag) :
88 		driver_device(mconfig, type, tag),
89 		m_maincpu(*this,"maincpu"),
90 		m_i386cpu(*this,"i386cpu"),
91 		m_crtc(*this,"crtc"),
92 		m_viduart(*this,"videouart"),
93 		m_iouart(*this,"iouart"),
94 		m_dmac(*this,"dmac"),
95 		m_pic(*this,"pic"),
96 		m_pit(*this,"pit"),
97 		m_hdc(*this,"hdc"),
98 		m_fdc(*this,"fdc"),
99 		m_fdc_timer(*this,"fdc_timer"),
100 		m_hdc_timer(*this,"hdc_timer"),
101 		m_disk_rom(*this,"disk"),
102 		m_fd0(*this,"fdc:0"),
103 		m_hd_buffer(*this,"hd_buffer_ram")
104 	{
105 	}
106 
107 	void ngen(machine_config &config);
108 
109 protected:
110 	uint8_t hd_buffer_r(offs_t offset);
111 	void hd_buffer_w(offs_t offset, uint8_t data);
112 
113 	DECLARE_WRITE_LINE_MEMBER(pit_out0_w);
114 	DECLARE_WRITE_LINE_MEMBER(pit_out1_w);
115 	DECLARE_WRITE_LINE_MEMBER(pit_out2_w);
116 
117 	DECLARE_WRITE_LINE_MEMBER(dma_hrq_changed);
118 	DECLARE_WRITE_LINE_MEMBER(dma_eop_changed);
119 	DECLARE_WRITE_LINE_MEMBER(dack0_w);
120 	DECLARE_WRITE_LINE_MEMBER(dack1_w);
121 	DECLARE_WRITE_LINE_MEMBER(dack2_w);
122 	DECLARE_WRITE_LINE_MEMBER(dack3_w);
123 	uint8_t dma_read_word(offs_t offset);
124 	void dma_write_word(offs_t offset, uint8_t data);
125 	// TODO: sort out what devices use which channels
dma_0_dack_r()126 	uint8_t dma_0_dack_r() { uint16_t ret = 0xffff; m_dma_high_byte = ret & 0xff00; return ret; }
dma_1_dack_r()127 	uint8_t dma_1_dack_r() { uint16_t ret = 0xffff; m_dma_high_byte = ret & 0xff00; return ret; }
dma_2_dack_r()128 	uint8_t dma_2_dack_r() { uint16_t ret = 0xffff; m_dma_high_byte = ret & 0xff00; return ret; }
129 	uint8_t dma_3_dack_r();
dma_0_dack_w(uint8_t data)130 	void dma_0_dack_w(uint8_t data) { popmessage("IOW0: data %02x",data); }
dma_1_dack_w(uint8_t data)131 	void dma_1_dack_w(uint8_t data) { }
dma_2_dack_w(uint8_t data)132 	void dma_2_dack_w(uint8_t data) { }
dma_3_dack_w(uint8_t data)133 	void dma_3_dack_w(uint8_t data) { popmessage("IOW3: data %02x",data); }
134 
135 	MC6845_UPDATE_ROW(crtc_update_row);
136 
137 	DECLARE_WRITE_LINE_MEMBER(timer_clk_out);
138 
139 	DECLARE_WRITE_LINE_MEMBER(fdc_irq_w);
140 
141 	void ngen386_io(address_map &map);
142 	void ngen386_mem(address_map &map);
143 	void ngen386i_mem(address_map &map);
144 
145 	optional_device<i80186_cpu_device> m_maincpu;
146 	optional_device<i386_device> m_i386cpu;
147 	required_device<mc6845_device> m_crtc;
148 	required_device<i8251_device> m_viduart;
149 	required_device<upd7201_device> m_iouart;
150 	required_device<am9517a_device> m_dmac;
151 	required_device<pic8259_device> m_pic;
152 	required_device<pit8254_device> m_pit;
153 	optional_device<wd2010_device> m_hdc;
154 	optional_device<wd2797_device> m_fdc;
155 	optional_device<pit8253_device> m_fdc_timer;
156 	optional_device<pit8253_device> m_hdc_timer;
157 
158 private:
159 	void cpu_peripheral_cb(offs_t offset, uint16_t data, uint16_t mem_mask = ~0);
160 	void peripheral_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0);
161 	uint16_t peripheral_r(offs_t offset, uint16_t mem_mask = ~0);
162 	void xbus_w(uint16_t data);
163 	uint16_t xbus_r();
164 
165 	DECLARE_WRITE_LINE_MEMBER(cpu_timer_w);
166 
167 	void hfd_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0);
168 	uint16_t hfd_r(offs_t offset, uint16_t mem_mask = ~0);
169 	DECLARE_WRITE_LINE_MEMBER(fdc_drq_w);
170 	void fdc_control_w(uint8_t data);
171 	uint8_t irq_cb();
172 	void hdc_control_w(uint8_t data);
173 	void disk_addr_ext(uint8_t data);
174 
175 	uint16_t b38_keyboard_r(offs_t offset, uint16_t mem_mask = ~0);
176 	void b38_keyboard_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0);
177 	uint16_t b38_crtc_r(offs_t offset, uint16_t mem_mask = ~0);
178 	void b38_crtc_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0);
179 	void ngen_io(address_map &map);
180 	void ngen_mem(address_map &map);
181 
182 	virtual void machine_reset() override;
183 	virtual void machine_start() override;
184 
185 	optional_memory_region m_disk_rom;
186 	memory_array m_vram;
187 	memory_array m_fontram;
188 	optional_device<floppy_connector> m_fd0;
189 	optional_shared_ptr<uint8_t> m_hd_buffer;
190 
191 	void set_dma_channel(int channel, int state);
192 
193 	uint8_t m_xbus_current;  // currently selected X-Bus module
194 	uint16_t m_peripheral;
195 	uint16_t m_upper;
196 	uint16_t m_middle;
197 	uint16_t m_port00;
198 	uint16_t m_periph141;
199 	uint8_t m_dma_offset[4];
200 	int8_t m_dma_channel;
201 	uint16_t m_dma_high_byte;
202 	uint16_t m_control;
203 	uint16_t m_disk_rom_ptr;
204 	uint8_t m_hdc_control;
205 	uint8_t m_disk_page;
206 };
207 
208 class ngen386_state : public ngen_state
209 {
210 public:
ngen386_state(const machine_config & mconfig,device_type type,const char * tag)211 	ngen386_state(const machine_config &mconfig, device_type type, const char *tag)
212 		: ngen_state(mconfig, type, tag)
213 		{}
214 		void ngen386(machine_config &config);
215 		void _386i(machine_config &config);
216 private:
217 };
218 
WRITE_LINE_MEMBER(ngen_state::pit_out0_w)219 WRITE_LINE_MEMBER(ngen_state::pit_out0_w)
220 {
221 	m_pic->ir3_w(state);  // Timer interrupt
222 	popmessage("PIT Timer 0 state %i\n",state);
223 }
224 
WRITE_LINE_MEMBER(ngen_state::pit_out1_w)225 WRITE_LINE_MEMBER(ngen_state::pit_out1_w)
226 {
227 	popmessage("PIT Timer 1 state %i\n",state);
228 	m_iouart->rxcb_w(state);
229 	m_iouart->txcb_w(state);  // channels in the correct order?
230 }
231 
WRITE_LINE_MEMBER(ngen_state::pit_out2_w)232 WRITE_LINE_MEMBER(ngen_state::pit_out2_w)
233 {
234 	m_iouart->rxca_w(state);
235 	m_iouart->txca_w(state);
236 	popmessage("PIT Timer 2 state %i\n",state);
237 }
238 
WRITE_LINE_MEMBER(ngen_state::cpu_timer_w)239 WRITE_LINE_MEMBER(ngen_state::cpu_timer_w)
240 {
241 	if(state != 0)
242 		popmessage("80186 Timer 0 state %i\n",state);
243 	m_pic->ir5_w(state);
244 }
245 
WRITE_LINE_MEMBER(ngen_state::timer_clk_out)246 WRITE_LINE_MEMBER(ngen_state::timer_clk_out)
247 {
248 	m_viduart->write_rxc(state);  // Keyboard UART Rx/Tx clocks
249 	m_viduart->write_txc(state);
250 	// 80186 timer pins also?  EXT bit is enabled for BTOS PIT test.
251 	if(m_maincpu)
252 	{
253 		m_maincpu->tmrin0_w(state);
254 		//m_maincpu->tmrin1_w(state);
255 	}
256 }
257 
cpu_peripheral_cb(offs_t offset,uint16_t data,uint16_t mem_mask)258 void ngen_state::cpu_peripheral_cb(offs_t offset, uint16_t data, uint16_t mem_mask)
259 {
260 	uint32_t addr;
261 
262 	switch(offset)
263 	{
264 	case 0:  // upper memory
265 		m_upper = data;
266 		break;
267 	case 2:  // peripheral
268 		m_peripheral = data;
269 		addr = (m_peripheral & 0xffc0) << 4;
270 		if(m_middle & 0x0040)
271 		{
272 			m_maincpu->space(AS_PROGRAM).install_readwrite_handler(addr, addr + 0x3ff, read16s_delegate(*this, FUNC(ngen_state::peripheral_r)), write16s_delegate(*this, FUNC(ngen_state::peripheral_w)));
273 			logerror("Mapped peripherals to memory 0x%08x\n",addr);
274 		}
275 		else
276 		{
277 			addr &= 0xffff;
278 			m_maincpu->space(AS_IO).install_readwrite_handler(addr, addr + 0x3ff, read16s_delegate(*this, FUNC(ngen_state::peripheral_r)), write16s_delegate(*this, FUNC(ngen_state::peripheral_w)));
279 			logerror("Mapped peripherals to I/O 0x%04x\n",addr);
280 		}
281 		break;
282 	case 4:
283 		m_middle = data;
284 		break;
285 	}
286 }
287 
288 // 80186 peripheral space
289 // Largely guesswork at this stage
peripheral_w(offs_t offset,uint16_t data,uint16_t mem_mask)290 void ngen_state::peripheral_w(offs_t offset, uint16_t data, uint16_t mem_mask)
291 {
292 	switch(offset)
293 	{
294 	case 0x00:
295 	case 0x01:
296 	case 0x02:
297 	case 0x03:
298 	case 0x04:
299 	case 0x05:
300 	case 0x06:
301 	case 0x07:
302 	case 0x08:
303 	case 0x09:
304 	case 0x0a:
305 	case 0x0b:
306 	case 0x0c:
307 	case 0x0d:
308 	case 0x0e:
309 	case 0x0f:
310 		if(ACCESSING_BITS_0_7)
311 			m_dmac->write(offset,data & 0xff);
312 		break;
313 	case 0x80: // DMA page offset?
314 	case 0x81:
315 	case 0x82:
316 	case 0x83:
317 		if(ACCESSING_BITS_0_7)
318 			m_dma_offset[offset-0x80] = data & 0xff;
319 		break;
320 	case 0xc0:  // X-Bus modules reset
321 		m_xbus_current = 0;
322 		break;
323 	case 0x10c:
324 		if(ACCESSING_BITS_0_7)
325 			m_pic->write(0,data & 0xff);
326 		break;
327 	case 0x10d:
328 		if(ACCESSING_BITS_0_7)
329 			m_pic->write(1,data & 0xff);
330 		break;
331 	case 0x110:
332 	case 0x111:
333 	case 0x112:
334 	case 0x113:
335 		if(ACCESSING_BITS_0_7)
336 			m_pit->write(offset-0x110,data & 0xff);
337 		break;
338 	case 0x141:
339 		// bit 1 enables speaker?
340 		COMBINE_DATA(&m_periph141);
341 		break;
342 	case 0x144:
343 		if(ACCESSING_BITS_0_7)
344 			m_crtc->address_w(data & 0xff);
345 		break;
346 	case 0x145:
347 		if(ACCESSING_BITS_0_7)
348 			m_crtc->register_w(data & 0xff);
349 		break;
350 	case 0x146:
351 	case 0x147:
352 		if(ACCESSING_BITS_0_7)
353 			m_viduart->write(offset & 1, data & 0xff);
354 		break;
355 	case 0x1a0:  // serial?
356 		logerror("Serial(?) 0x1a0 write offset %04x data %04x mask %04x\n",offset,data,mem_mask);
357 		break;
358 	default:
359 		logerror("Unknown 80186 peripheral write offset %04x data %04x mask %04x\n",offset,data,mem_mask);
360 	}
361 }
362 
peripheral_r(offs_t offset,uint16_t mem_mask)363 uint16_t ngen_state::peripheral_r(offs_t offset, uint16_t mem_mask)
364 {
365 	uint16_t ret = 0xffff;
366 	switch(offset)
367 	{
368 	case 0x00:
369 	case 0x01:
370 	case 0x02:
371 	case 0x03:
372 	case 0x04:
373 	case 0x05:
374 	case 0x06:
375 	case 0x07:
376 	case 0x08:
377 	case 0x09:
378 	case 0x0a:
379 	case 0x0b:
380 	case 0x0c:
381 	case 0x0d:
382 	case 0x0e:
383 	case 0x0f:
384 		if(ACCESSING_BITS_0_7)
385 			ret = m_dmac->read(offset);
386 		logerror("DMA read offset %04x mask %04x returning %04x\n",offset,mem_mask,ret);
387 		break;
388 	case 0x80: // DMA page offset?
389 	case 0x81:
390 	case 0x82:
391 	case 0x83:
392 		if(ACCESSING_BITS_0_7)
393 			ret = m_dma_offset[offset-0x80] & 0xff;
394 		break;
395 	case 0x10c:
396 		if(ACCESSING_BITS_0_7)
397 			ret = m_pic->read(0);
398 		break;
399 	case 0x10d:
400 		if(ACCESSING_BITS_0_7)
401 			ret = m_pic->read(1);
402 		break;
403 	case 0x110:
404 	case 0x111:
405 	case 0x112:
406 	case 0x113:
407 		if(ACCESSING_BITS_0_7)
408 			ret = m_pit->read(offset-0x110);
409 		break;
410 	case 0x141:
411 		ret = m_periph141;
412 		break;
413 	case 0x144:
414 		if(ACCESSING_BITS_0_7)
415 			ret = m_crtc->status_r();
416 		break;
417 	case 0x145:
418 		if(ACCESSING_BITS_0_7)
419 			ret = m_crtc->register_r();
420 		break;
421 	case 0x146:
422 	case 0x147:  // keyboard UART
423 		// status expects bit 0 to be set (UART transmit ready)
424 		if(ACCESSING_BITS_0_7)
425 			ret = m_viduart->read(offset & 1);
426 		break;
427 	case 0x1a0:  // I/O control register?
428 		ret = m_control;  // end of DMA transfer? (maybe a per-channel EOP?) Bit 6 is set during a transfer?
429 		break;
430 //  default:
431 //      logerror("Unknown 80186 peripheral read offset %04x mask %04x returning %04x\n",offset,mem_mask,ret);
432 	}
433 	return ret;
434 }
435 
436 // X-bus module select
437 // The bootstrap ROM creates a table at 0:FC9h, with a count, followed by the module IDs of each
438 // expansion module.  The base I/O address for the currently selected module is set by writing to
439 // this register (bits 0-7 are ignored)
440 // TODO: make expansion modules slot devices
xbus_w(uint16_t data)441 void ngen_state::xbus_w(uint16_t data)
442 {
443 	uint16_t addr = (data & 0x00ff) << 8;
444 	cpu_device* cpu;
445 
446 	if(m_maincpu)
447 		cpu = m_maincpu;
448 	else
449 		cpu = m_i386cpu;
450 	address_space& io = cpu->space(AS_IO);
451 	switch(m_xbus_current)
452 	{
453 		case 0x00:  // Floppy/Hard disk module
454 			io.install_readwrite_handler(addr,addr+0xff, read16s_delegate(*this, FUNC(ngen_state::hfd_r)), write16s_delegate(*this, FUNC(ngen_state::hfd_w)), 0xffffffff);
455 			break;
456 		default:
457 			cpu->pulse_input_line(INPUT_LINE_NMI, attotime::zero);  // reached end of the modules
458 			break;
459 	}
460 	if(addr != 0)
461 		logerror("SYS: X-Bus module %i address set %04x\n",m_xbus_current+1,addr);
462 	m_xbus_current++;
463 }
464 
465 // returns X-bus module ID and info in the low byte (can indicate if the device is bootable, has a boot ROM (needs to be written to RAM via DMA), or if it supports a non-80186 CPU)
466 // bit 6, I think, indicates a bootable device
467 // Known module IDs:
468 //  0x1070 - Floppy/Hard disk module
469 //  0x3141 - QIC Tape module
xbus_r()470 uint16_t ngen_state::xbus_r()
471 {
472 	uint16_t ret = 0xffff;
473 
474 	switch(m_xbus_current)
475 	{
476 		case 0x00:
477 			ret = 0x1070;  // Floppy/Hard disk module
478 			break;
479 		default:
480 			if(m_maincpu)
481 				m_maincpu->pulse_input_line(INPUT_LINE_NMI, attotime::zero);  // reached the end of the modules
482 			else
483 				m_i386cpu->pulse_input_line(INPUT_LINE_NMI, attotime::zero);
484 			ret = 0x0080;
485 			break;
486 	}
487 	return ret;
488 }
489 
490 
491 // Floppy/Hard disk module
hfd_w(offs_t offset,uint16_t data,uint16_t mem_mask)492 void ngen_state::hfd_w(offs_t offset, uint16_t data, uint16_t mem_mask)
493 {
494 	switch(offset)
495 	{
496 		case 0x00:
497 		case 0x01:
498 		case 0x02:
499 			if(ACCESSING_BITS_0_7)
500 				m_fdc->write(offset,data & 0xff);
501 			break;
502 		case 0x03:
503 			if(ACCESSING_BITS_0_7)
504 			{
505 				m_fdc->write(offset,data & 0xff);
506 				m_fdc_timer->write_clk0(1);
507 				m_fdc_timer->write_clk0(0);  // Data register access clocks the FDC's PIT channel 0
508 			}
509 			break;
510 		case 0x04:
511 			if(ACCESSING_BITS_0_7)
512 				fdc_control_w(data & 0xff);
513 			break;
514 		case 0x05:
515 			if(ACCESSING_BITS_0_7)
516 				hdc_control_w(data & 0xff);
517 			break;
518 		case 0x07:
519 			if(ACCESSING_BITS_0_7)
520 				disk_addr_ext(data & 0xff);
521 			break;
522 		case 0x08:
523 		case 0x09:
524 		case 0x0a:
525 		case 0x0b:
526 			if(ACCESSING_BITS_0_7)
527 				m_fdc_timer->write(offset-0x08,data & 0xff);
528 			break;
529 		case 0x10:
530 		case 0x11:
531 		case 0x12:
532 		case 0x13:
533 		case 0x14:
534 		case 0x15:
535 		case 0x16:
536 		case 0x17:
537 			if(ACCESSING_BITS_0_7)
538 				m_hdc->write(offset-0x10,data & 0xff);
539 			logerror("WD1010 register %i write %02x mask %04x\n",offset-0x10,data & 0xff,mem_mask);
540 			break;
541 		case 0x18:
542 		case 0x19:
543 		case 0x1a:
544 		case 0x1b:
545 			if(ACCESSING_BITS_0_7)
546 				m_hdc_timer->write(offset-0x18,data & 0xff);
547 			break;
548 	}
549 }
550 
hfd_r(offs_t offset,uint16_t mem_mask)551 uint16_t ngen_state::hfd_r(offs_t offset, uint16_t mem_mask)
552 {
553 	uint16_t ret = 0xffff;
554 
555 	switch(offset)
556 	{
557 		case 0x00:
558 		case 0x01:
559 		case 0x02:
560 			if(ACCESSING_BITS_0_7)
561 				ret = m_fdc->read(offset);
562 			break;
563 		case 0x03:
564 			if(ACCESSING_BITS_0_7)
565 			{
566 				ret = m_fdc->read(offset);
567 				m_fdc_timer->write_clk0(1);
568 				m_fdc_timer->write_clk0(0);  // Data register access clocks the FDC's PIT channel 0
569 			}
570 			break;
571 		case 0x08:
572 		case 0x09:
573 		case 0x0a:
574 		case 0x0b:
575 			if(ACCESSING_BITS_0_7)
576 				ret = m_fdc_timer->read(offset-0x08);
577 			break;
578 		case 0x10:
579 		case 0x11:
580 		case 0x12:
581 		case 0x13:
582 		case 0x14:
583 		case 0x15:
584 		case 0x16:
585 		case 0x17:
586 			if(ACCESSING_BITS_0_7)
587 				ret = m_hdc->read(offset-0x10);
588 			logerror("WD1010 register %i read, mask %04x\n",offset-0x10,mem_mask);
589 			break;
590 		case 0x18:
591 		case 0x19:
592 		case 0x1a:
593 		case 0x1b:
594 			if(ACCESSING_BITS_0_7)
595 				ret = m_hdc_timer->read(offset-0x18);
596 			break;
597 	}
598 
599 	return ret;
600 }
601 
WRITE_LINE_MEMBER(ngen_state::fdc_irq_w)602 WRITE_LINE_MEMBER(ngen_state::fdc_irq_w)
603 {
604 	m_pic->ir7_w(state);
605 }
606 
WRITE_LINE_MEMBER(ngen_state::fdc_drq_w)607 WRITE_LINE_MEMBER(ngen_state::fdc_drq_w)
608 {
609 	m_dmac->dreq3_w(state);
610 }
611 
612 // Floppy disk control register
613 // Bit 0 - enable drive and LED
614 // Bit 2 - floppy motor
615 // Bit 5 - side select
616 // Bit 6 - 1 = 2Mhz for seek, 0 = 1MHz for read/write
617 // Bit 7 - FDC reset
fdc_control_w(uint8_t data)618 void ngen_state::fdc_control_w(uint8_t data)
619 {
620 	m_fdc->set_floppy(m_fd0->get_device());
621 	m_fd0->get_device()->mon_w(!BIT(data, 2));
622 	m_fd0->get_device()->ss_w(BIT(data, 5));
623 	m_fdc->mr_w(BIT(data, 7));
624 }
625 
626 // Hard disk control register
627 // bit 0 - Drive select 0 - selects module hard disk
628 // bit 1 - Drive select 1 - selects expansion module hard disk (if available)
629 // bit 2 - enable DMA transfer of module ROM contents to X-Bus master memory
630 // bits 3-5 - select head / expansion module head
631 // bit 6 - write enable, must be set to write to a hard disk
632 // bit 7 - HDC reset
hdc_control_w(uint8_t data)633 void ngen_state::hdc_control_w(uint8_t data)
634 {
635 	m_hdc_control = data;
636 	if(m_hdc_control & 0x04)
637 	{
638 		m_disk_rom_ptr = 0;
639 		popmessage("HDD: DMA ROM transfer start\n");
640 		m_dmac->dreq3_w(1);
641 		//m_dmac->dreq3_w(0);
642 	}
643 }
644 
645 // page of system RAM to access
646 // bit 7 = disables read/write signals to the WD1010
disk_addr_ext(uint8_t data)647 void ngen_state::disk_addr_ext(uint8_t data)
648 {
649 	m_disk_page = data & 0x7f;
650 }
651 
hd_buffer_r(offs_t offset)652 uint8_t ngen_state::hd_buffer_r(offs_t offset)
653 {
654 	return m_hd_buffer[offset];
655 }
656 
hd_buffer_w(offs_t offset,uint8_t data)657 void ngen_state::hd_buffer_w(offs_t offset, uint8_t data)
658 {
659 	m_hd_buffer[offset] = data;
660 }
661 
WRITE_LINE_MEMBER(ngen_state::dma_hrq_changed)662 WRITE_LINE_MEMBER( ngen_state::dma_hrq_changed )
663 {
664 	if(m_maincpu)
665 		m_maincpu->set_input_line(INPUT_LINE_HALT, state ? ASSERT_LINE : CLEAR_LINE);
666 	else
667 		m_i386cpu->set_input_line(INPUT_LINE_HALT, state ? ASSERT_LINE : CLEAR_LINE);
668 }
669 
WRITE_LINE_MEMBER(ngen_state::dma_eop_changed)670 WRITE_LINE_MEMBER( ngen_state::dma_eop_changed )
671 {
672 	if(m_dma_channel == 0)
673 	{
674 		if(state)
675 			m_control |= 0x02;
676 		else
677 			m_control &= ~0x02;
678 	}
679 	if(m_dma_channel == 3)
680 	{
681 		if(state)
682 		{
683 			if(m_hdc_control & 0x04) // ROM transfer
684 				m_hdc_control &= ~0x04;  // switch it off when done
685 		}
686 	}
687 }
688 
set_dma_channel(int channel,int state)689 void ngen_state::set_dma_channel(int channel, int state)
690 {
691 	if(!state)
692 		m_dma_channel = channel;
693 	else if(m_dma_channel == channel)
694 		m_dma_channel = -1;
695 }
696 
WRITE_LINE_MEMBER(ngen_state::dack0_w)697 WRITE_LINE_MEMBER( ngen_state::dack0_w ) { set_dma_channel(0, state); }
WRITE_LINE_MEMBER(ngen_state::dack1_w)698 WRITE_LINE_MEMBER( ngen_state::dack1_w ) { set_dma_channel(1, state); }
WRITE_LINE_MEMBER(ngen_state::dack2_w)699 WRITE_LINE_MEMBER( ngen_state::dack2_w ) { set_dma_channel(2, state); }
WRITE_LINE_MEMBER(ngen_state::dack3_w)700 WRITE_LINE_MEMBER( ngen_state::dack3_w ) { set_dma_channel(3, state); }
701 
dma_3_dack_r()702 uint8_t ngen_state::dma_3_dack_r()
703 {
704 	uint16_t ret = 0xffff;
705 
706 	if((m_hdc_control & 0x04) && m_disk_rom)
707 	{
708 		ret = m_disk_rom->base()[m_disk_rom_ptr++] << 8;
709 		printf("DMA3 DACK: returning %02x\n",ret);
710 		if(m_disk_rom_ptr < 0x1000)
711 		{
712 			m_dmac->dreq3_w(1);
713 			//m_dmac->dreq3_w(0);
714 		}
715 	}
716 	m_dma_high_byte = ret & 0xff00;
717 	return ret;
718 }
719 
dma_read_word(offs_t offset)720 uint8_t ngen_state::dma_read_word(offs_t offset)
721 {
722 	cpu_device* cpu;
723 	uint16_t result;
724 
725 	if(m_maincpu)
726 		cpu = m_maincpu;
727 	else
728 		cpu = m_i386cpu;
729 	address_space& prog_space = cpu->space(AS_PROGRAM); // get the right address space
730 
731 	if(m_dma_channel == -1)
732 		return 0xff;
733 	offs_t page_offset = ((offs_t) m_dma_offset[m_dma_channel]) << 16;
734 
735 	result = prog_space.read_word((page_offset & 0xfe0000) | (offset << 1));
736 	m_dma_high_byte = result & 0xFF00;
737 	popmessage("DMA byte address %06x read %04x\n", (page_offset & 0xfe0000) | (offset << 1),result);
738 	return result & 0xff;
739 }
740 
741 
dma_write_word(offs_t offset,uint8_t data)742 void ngen_state::dma_write_word(offs_t offset, uint8_t data)
743 {
744 	cpu_device* cpu;
745 
746 	if(m_maincpu)
747 		cpu = m_maincpu;
748 	else
749 		cpu = m_i386cpu;
750 	address_space& prog_space = cpu->space(AS_PROGRAM); // get the right address space
751 
752 	if(m_dma_channel == -1)
753 		return;
754 	offs_t page_offset = ((offs_t) m_dma_offset[m_dma_channel]) << 16;
755 
756 	prog_space.write_word((page_offset & 0xfe0000) | (offset << 1), data);
757 	popmessage("DMA byte address %06x write %04x\n", (page_offset & 0xfe0000) | (offset << 1), m_dma_high_byte | data);
758 }
759 
760 
MC6845_UPDATE_ROW(ngen_state::crtc_update_row)761 MC6845_UPDATE_ROW( ngen_state::crtc_update_row )
762 {
763 	uint16_t addr = ma;
764 
765 	for(int x=0;x<bitmap.width();x+=9)
766 	{
767 		uint8_t ch = m_vram.read16(addr++) & 0xff;
768 		for(int z=0;z<9;z++)
769 		{
770 			if(BIT(m_fontram.read16(ch*16+ra),8-z))
771 				bitmap.pix(y,x+z) = rgb_t(0,0xff,0);
772 			else
773 				bitmap.pix(y,x+z) = rgb_t(0,0,0);
774 		}
775 	}
776 }
777 
irq_cb()778 uint8_t ngen_state::irq_cb()
779 {
780 	return m_pic->acknowledge();
781 }
782 
b38_keyboard_r(offs_t offset,uint16_t mem_mask)783 uint16_t ngen_state::b38_keyboard_r(offs_t offset, uint16_t mem_mask)
784 {
785 	uint8_t ret = 0;
786 	switch(offset)
787 	{
788 	case 0:
789 	case 1:  // keyboard UART
790 		// status expects bit 0 to be set (UART transmit ready)
791 		if(ACCESSING_BITS_0_7)
792 			ret = m_viduart->read(offset & 1);
793 		break;
794 	}
795 	return ret;
796 }
797 
b38_keyboard_w(offs_t offset,uint16_t data,uint16_t mem_mask)798 void ngen_state::b38_keyboard_w(offs_t offset, uint16_t data, uint16_t mem_mask)
799 {
800 	switch(offset)
801 	{
802 	case 0:
803 	case 1:
804 		if(ACCESSING_BITS_0_7)
805 			m_viduart->write(offset & 1, data & 0xff);
806 		break;
807 	}
808 }
809 
b38_crtc_r(offs_t offset,uint16_t mem_mask)810 uint16_t ngen_state::b38_crtc_r(offs_t offset, uint16_t mem_mask)
811 {
812 	uint8_t ret = 0;
813 	switch(offset)
814 	{
815 	case 0:
816 		if(ACCESSING_BITS_0_7)
817 			ret = m_crtc->register_r();
818 		break;
819 	case 1:
820 		if(ACCESSING_BITS_0_7)
821 			ret = m_viduart->data_r();
822 		break;
823 	}
824 	return ret;
825 }
826 
b38_crtc_w(offs_t offset,uint16_t data,uint16_t mem_mask)827 void ngen_state::b38_crtc_w(offs_t offset, uint16_t data, uint16_t mem_mask)
828 {
829 	switch(offset)
830 	{
831 	case 0:
832 		if(ACCESSING_BITS_0_7)
833 			m_crtc->address_w(data & 0xff);
834 		break;
835 	case 1:
836 		if(ACCESSING_BITS_0_7)
837 			m_crtc->register_w(data & 0xff);
838 		break;
839 	}
840 }
841 
machine_start()842 void ngen_state::machine_start()
843 {
844 	memory_share* vidshare = memshare("vram");
845 	memory_share* fontshare = memshare("fontram");
846 	m_hd_buffer.allocate(1024*8);  // 8kB buffer RAM for HD controller
847 	if(vidshare == nullptr || fontshare == nullptr)
848 		fatalerror("VRAM not found\n");
849 	m_vram.set(*vidshare,2);
850 	m_fontram.set(*fontshare,2);
851 }
852 
machine_reset()853 void ngen_state::machine_reset()
854 {
855 	m_port00 = 0;
856 	m_control = 0;
857 	m_xbus_current = 0;
858 	m_viduart->write_dsr(0);
859 	m_viduart->write_cts(0);
860 	m_fd0->get_device()->set_rpm(300);
861 }
862 
863 // boot ROMs from modules are not mapped anywhere, instead, they have to send the code from the boot ROM via DMA
ngen_mem(address_map & map)864 void ngen_state::ngen_mem(address_map &map)
865 {
866 	map(0x00000, 0xf7fff).ram();
867 	map(0xf8000, 0xf9fff).ram().share("vram");
868 	map(0xfa000, 0xfbfff).ram().share("fontram");
869 	map(0xfc000, 0xfcfff).ram();
870 	map(0xfe000, 0xfffff).rom().region("bios", 0);
871 }
872 
ngen_io(address_map & map)873 void ngen_state::ngen_io(address_map &map)
874 {
875 	map(0x0000, 0x0001).rw(FUNC(ngen_state::xbus_r), FUNC(ngen_state::xbus_w));
876 
877 	// Floppy/Hard disk module
878 //  map(0x0100, 0x0107).rw("fdc", FUNC(wd2797_t::read), FUNC(wd2797_t::write)).umask16(0x00ff);  // a guess for now
879 //  map(0x0108, 0x0108).w(FUNC(ngen_state::fdc_control_w));
880 //  map(0x010a, 0x010a).w(FUNC(ngen_state::hdc_control_w));
881 //  map(0x010e, 0x010e).w(FUNC(ngen_state::disk_addr_ext));  // X-Bus extended address register
882 //  map(0x0110, 0x0117).rw("fdc_timer", FUNC(pit8253_device::read), FUNC(pit8253_device::write)).umask16(0x00ff);
883 	// 0x0120-0x012f - WD1010 Winchester disk controller (unemulated)
884 //  map(0x0130, 0x0137).rw("hdc_timer", FUNC(pit8253_device::read), FUNC(pit8253_device::write)).umask16(0x00ff);
885 
886 }
887 
ngen386_mem(address_map & map)888 void ngen_state::ngen386_mem(address_map &map)
889 {
890 	map(0x00000000, 0x000f7fff).ram();
891 	map(0x000f8000, 0x000f9fff).ram().share("vram");
892 	map(0x000fa000, 0x000fbfff).ram().share("fontram");
893 	map(0x000fc000, 0x000fcfff).ram();
894 	map(0x000fe000, 0x000fffff).rom().region("bios", 0);
895 	map(0x00100000, 0x00ffffff).ram();  // some extra RAM
896 	map(0xffffe000, 0xffffffff).rom().region("bios", 0);
897 }
898 
ngen386i_mem(address_map & map)899 void ngen_state::ngen386i_mem(address_map &map)
900 {
901 	map(0x00000000, 0x000f7fff).ram();
902 	map(0x000f8000, 0x000f9fff).ram().share("vram");
903 	map(0x000fa000, 0x000fbfff).ram().share("fontram");
904 	map(0x000fc000, 0x000fffff).rom().region("bios", 0);
905 	map(0x00100000, 0x00ffffff).ram();  // some extra RAM
906 	map(0xffffc000, 0xffffffff).rom().region("bios", 0);
907 }
908 
ngen386_io(address_map & map)909 void ngen_state::ngen386_io(address_map &map)
910 {
911 	map(0x0000, 0x0001).rw(FUNC(ngen_state::xbus_r), FUNC(ngen_state::xbus_w));
912 //  map(0xf800, 0xfeff).rw(FUNC(ngen_state::peripheral_r), FUNC(ngen_state::peripheral_w));
913 	map(0xfd08, 0xfd0b).rw(FUNC(ngen_state::b38_crtc_r), FUNC(ngen_state::b38_crtc_w));
914 	map(0xfd0c, 0xfd0f).rw(FUNC(ngen_state::b38_keyboard_r), FUNC(ngen_state::b38_keyboard_w));
915 }
916 
INPUT_PORTS_START(ngen)917 static INPUT_PORTS_START( ngen )
918 INPUT_PORTS_END
919 
920 static void keyboard(device_slot_interface &device)
921 {
922 	device.option_add("ngen", NGEN_KEYBOARD);
923 }
924 
ngen_floppies(device_slot_interface & device)925 static void ngen_floppies(device_slot_interface &device)
926 {
927 	device.option_add("525qd", FLOPPY_525_QD);
928 }
929 
ngen(machine_config & config)930 void ngen_state::ngen(machine_config &config)
931 {
932 	// basic machine hardware
933 	I80186(config, m_maincpu, 16_MHz_XTAL);
934 	m_maincpu->set_addrmap(AS_PROGRAM, &ngen_state::ngen_mem);
935 	m_maincpu->set_addrmap(AS_IO, &ngen_state::ngen_io);
936 	m_maincpu->chip_select_callback().set(FUNC(ngen_state::cpu_peripheral_cb));
937 	m_maincpu->tmrout0_handler().set(FUNC(ngen_state::cpu_timer_w));
938 	m_maincpu->read_slave_ack_callback().set(FUNC(ngen_state::irq_cb));
939 
940 	PIC8259(config, m_pic, 0);
941 	m_pic->out_int_callback().set(m_maincpu, FUNC(i80186_cpu_device::int0_w));
942 
943 	PIT8254(config, m_pit, 0);
944 	m_pit->set_clk<0>(78120/4);  // 19.53kHz, /4 of the CPU timer output?
945 	m_pit->out_handler<0>().set(FUNC(ngen_state::pit_out0_w));  // RS232 channel B baud rate
946 	m_pit->set_clk<1>(14.7456_MHz_XTAL / 12);  // correct? - based on patent
947 	m_pit->out_handler<1>().set(FUNC(ngen_state::pit_out1_w));  // RS232 channel A baud rate
948 	m_pit->set_clk<2>(14.7456_MHz_XTAL / 12);
949 	m_pit->out_handler<2>().set(FUNC(ngen_state::pit_out2_w));
950 
951 	AM9517A(config, m_dmac, 14.7456_MHz_XTAL / 3);  // NEC D8237A, divisor unknown
952 	m_dmac->out_hreq_callback().set(FUNC(ngen_state::dma_hrq_changed));
953 	m_dmac->out_eop_callback().set(FUNC(ngen_state::dma_eop_changed));
954 	m_dmac->in_memr_callback().set(FUNC(ngen_state::dma_read_word));  // DMA is always 16-bit
955 	m_dmac->out_memw_callback().set(FUNC(ngen_state::dma_write_word));
956 	m_dmac->out_dack_callback<0>().set(FUNC(ngen_state::dack0_w));
957 	m_dmac->out_dack_callback<1>().set(FUNC(ngen_state::dack1_w));
958 	m_dmac->out_dack_callback<2>().set(FUNC(ngen_state::dack2_w));
959 	m_dmac->out_dack_callback<3>().set(FUNC(ngen_state::dack3_w));
960 	m_dmac->in_ior_callback<0>().set(FUNC(ngen_state::dma_0_dack_r));
961 	m_dmac->in_ior_callback<1>().set(FUNC(ngen_state::dma_1_dack_r));
962 	m_dmac->in_ior_callback<2>().set(FUNC(ngen_state::dma_2_dack_r));
963 	m_dmac->in_ior_callback<3>().set(FUNC(ngen_state::dma_3_dack_r));
964 	m_dmac->out_iow_callback<0>().set(FUNC(ngen_state::dma_0_dack_w));
965 	m_dmac->out_iow_callback<1>().set(FUNC(ngen_state::dma_1_dack_w));
966 	m_dmac->out_iow_callback<2>().set(FUNC(ngen_state::dma_2_dack_w));
967 	m_dmac->out_iow_callback<3>().set(FUNC(ngen_state::dma_3_dack_w));
968 
969 	// I/O board
970 	UPD7201(config, m_iouart, 0); // clocked by PIT channel 2?
971 	m_iouart->out_txda_callback().set("rs232_a", FUNC(rs232_port_device::write_txd));
972 	m_iouart->out_txdb_callback().set("rs232_b", FUNC(rs232_port_device::write_txd));
973 	m_iouart->out_dtra_callback().set("rs232_a", FUNC(rs232_port_device::write_dtr));
974 	m_iouart->out_dtrb_callback().set("rs232_b", FUNC(rs232_port_device::write_dtr));
975 	m_iouart->out_rtsa_callback().set("rs232_a", FUNC(rs232_port_device::write_rts));
976 	m_iouart->out_rtsb_callback().set("rs232_b", FUNC(rs232_port_device::write_rts));
977 
978 	rs232_port_device &rs232a(RS232_PORT(config, "rs232_a", default_rs232_devices, nullptr));
979 	rs232a.rxd_handler().set(m_iouart, FUNC(upd7201_device::rxa_w));
980 	rs232a.cts_handler().set(m_iouart, FUNC(upd7201_device::ctsa_w));
981 	rs232a.dcd_handler().set(m_iouart, FUNC(upd7201_device::dcda_w));
982 	rs232a.ri_handler().set(m_iouart, FUNC(upd7201_device::synca_w));
983 
984 	rs232_port_device &rs232b(RS232_PORT(config, "rs232_b", default_rs232_devices, nullptr));
985 	rs232b.rxd_handler().set(m_iouart, FUNC(upd7201_device::rxb_w));
986 	rs232b.cts_handler().set(m_iouart, FUNC(upd7201_device::ctsb_w));
987 	rs232b.dcd_handler().set(m_iouart, FUNC(upd7201_device::dcdb_w));
988 	rs232b.ri_handler().set(m_iouart, FUNC(upd7201_device::syncb_w));
989 
990 	// TODO: SCN2652 MPCC (not implemented), used for RS-422 cluster communications?
991 
992 	// video board
993 	screen_device &screen(SCREEN(config, "screen", SCREEN_TYPE_RASTER));
994 	screen.set_size(720, 348);
995 	screen.set_visarea(0, 719, 0, 347);
996 	screen.set_refresh_hz(60);
997 	screen.set_screen_update("crtc", FUNC(mc6845_device::screen_update));
998 
999 	MC6845(config, m_crtc, 19980000 / 9);  // divisor unknown -- /9 gives 60Hz output, so likely correct
1000 	m_crtc->set_screen("screen");
1001 	m_crtc->set_show_border_area(false);
1002 	m_crtc->set_char_width(9);
1003 	m_crtc->set_update_row_callback(FUNC(ngen_state::crtc_update_row));
1004 
1005 	// keyboard UART (patent says i8251 is used for keyboard communications, it is located on the video board)
1006 	I8251(config, m_viduart, 0);  // main clock unknown, Rx/Tx clocks are 19.53kHz
1007 //  m_viduart->txempty_handler().set(m_pic, FUNC(pic8259_device::ir4_w));
1008 	m_viduart->txd_handler().set("keyboard", FUNC(rs232_port_device::write_txd));
1009 	rs232_port_device &kbd(RS232_PORT(config, "keyboard", keyboard, "ngen"));
1010 	kbd.rxd_handler().set(m_viduart, FUNC(i8251_device::write_rxd));
1011 
1012 	CLOCK(config, "refresh_clock", 19200*16).signal_handler().set(FUNC(ngen_state::timer_clk_out)); // should be 19530Hz
1013 
1014 	// floppy disk / hard disk module (WD2797 FDC, WD1010 HDC, plus an 8253 timer for each)
1015 	WD2797(config, m_fdc, 20_MHz_XTAL / 20);
1016 	m_fdc->intrq_wr_callback().set(FUNC(ngen_state::fdc_irq_w));
1017 	m_fdc->drq_wr_callback().set(m_maincpu, FUNC(i80186_cpu_device::drq1_w));
1018 	m_fdc->set_force_ready(true);
1019 
1020 	PIT8253(config, m_fdc_timer, 0);
1021 	m_fdc_timer->set_clk<0>(0);
1022 	m_fdc_timer->out_handler<0>().set(m_pic, FUNC(pic8259_device::ir5_w));  // clocked on FDC data register access
1023 	m_fdc_timer->set_clk<1>(20_MHz_XTAL / 20);
1024 //  m_fdc_timer->out_handler<1>().set(m_pic, FUNC(pic8259_device::ir5_w));  // 1MHz
1025 	m_fdc_timer->set_clk<2>(20_MHz_XTAL / 20);
1026 //  m_fdc_timer->out_handler<2>().set(m_pic, FUNC(pic8259_device::ir5_w));
1027 
1028 	// TODO: WD1010 HDC (not implemented), use WD2010 for now
1029 	WD2010(config, m_hdc, 20_MHz_XTAL / 4);
1030 	m_hdc->out_intrq_callback().set(m_pic, FUNC(pic8259_device::ir2_w));
1031 	m_hdc->in_bcs_callback().set(FUNC(ngen_state::hd_buffer_r));
1032 	m_hdc->out_bcs_callback().set(FUNC(ngen_state::hd_buffer_w));
1033 	m_hdc->in_drdy_callback().set_constant(1);
1034 	m_hdc->in_index_callback().set_constant(1);
1035 	m_hdc->in_wf_callback().set_constant(1);
1036 	m_hdc->in_tk000_callback().set_constant(1);
1037 	m_hdc->in_sc_callback().set_constant(1);
1038 
1039 	PIT8253(config, m_hdc_timer, 0);
1040 	m_hdc_timer->set_clk<2>(20_MHz_XTAL / 10);  // 2MHz
1041 
1042 	FLOPPY_CONNECTOR(config, "fdc:0", ngen_floppies, "525qd", floppy_image_device::default_floppy_formats);
1043 	HARDDISK(config, "hard0", 0);
1044 }
1045 
ngen386(machine_config & config)1046 void ngen386_state::ngen386(machine_config &config)
1047 {
1048 	I386(config, m_i386cpu, 50_MHz_XTAL / 2);
1049 	m_i386cpu->set_addrmap(AS_PROGRAM, &ngen386_state::ngen386_mem);
1050 	m_i386cpu->set_addrmap(AS_IO, &ngen386_state::ngen386_io);
1051 	m_i386cpu->set_irq_acknowledge_callback("pic", FUNC(pic8259_device::inta_cb));
1052 
1053 	PIC8259(config, m_pic, 0);
1054 	m_pic->out_int_callback().set_inputline(m_i386cpu, 0);
1055 
1056 	PIT8254(config, m_pit, 0);
1057 	m_pit->set_clk<0>(78120/4);  // 19.53kHz, /4 of the CPU timer output?
1058 	m_pit->out_handler<0>().set(FUNC(ngen386_state::pit_out0_w));  // RS232 channel B baud rate
1059 	m_pit->set_clk<1>(14.7456_MHz_XTAL / 12);  // correct? - based on patent
1060 	m_pit->out_handler<1>().set(FUNC(ngen386_state::pit_out1_w));  // RS232 channel A baud rate
1061 	m_pit->set_clk<2>(14.7456_MHz_XTAL / 12);
1062 	m_pit->out_handler<2>().set(FUNC(ngen386_state::pit_out2_w));
1063 
1064 	AM9517A(config, m_dmac, 14.7456_MHz_XTAL / 3);  // NEC D8237A, divisor unknown
1065 	m_dmac->out_hreq_callback().set(FUNC(ngen386_state::dma_hrq_changed));
1066 	m_dmac->out_eop_callback().set(FUNC(ngen386_state::dma_eop_changed));
1067 	m_dmac->in_memr_callback().set(FUNC(ngen386_state::dma_read_word));  // DMA is always 16-bit
1068 	m_dmac->out_memw_callback().set(FUNC(ngen386_state::dma_write_word));
1069 	m_dmac->out_dack_callback<0>().set(FUNC(ngen386_state::dack0_w));
1070 	m_dmac->out_dack_callback<1>().set(FUNC(ngen386_state::dack1_w));
1071 	m_dmac->out_dack_callback<2>().set(FUNC(ngen386_state::dack2_w));
1072 	m_dmac->out_dack_callback<3>().set(FUNC(ngen386_state::dack3_w));
1073 	m_dmac->in_ior_callback<0>().set(FUNC(ngen386_state::dma_0_dack_r));
1074 	m_dmac->in_ior_callback<1>().set(FUNC(ngen386_state::dma_1_dack_r));
1075 	m_dmac->in_ior_callback<2>().set(FUNC(ngen386_state::dma_2_dack_r));
1076 	m_dmac->in_ior_callback<3>().set(FUNC(ngen386_state::dma_3_dack_r));
1077 	m_dmac->out_iow_callback<0>().set(FUNC(ngen386_state::dma_0_dack_w));
1078 	m_dmac->out_iow_callback<1>().set(FUNC(ngen386_state::dma_1_dack_w));
1079 	m_dmac->out_iow_callback<2>().set(FUNC(ngen386_state::dma_2_dack_w));
1080 	m_dmac->out_iow_callback<3>().set(FUNC(ngen386_state::dma_3_dack_w));
1081 
1082 	// I/O board
1083 	UPD7201(config, m_iouart, 0); // clocked by PIT channel 2?
1084 	m_iouart->out_txda_callback().set("rs232_a", FUNC(rs232_port_device::write_txd));
1085 	m_iouart->out_txdb_callback().set("rs232_b", FUNC(rs232_port_device::write_txd));
1086 	m_iouart->out_dtra_callback().set("rs232_a", FUNC(rs232_port_device::write_dtr));
1087 	m_iouart->out_dtrb_callback().set("rs232_b", FUNC(rs232_port_device::write_dtr));
1088 	m_iouart->out_rtsa_callback().set("rs232_a", FUNC(rs232_port_device::write_rts));
1089 	m_iouart->out_rtsb_callback().set("rs232_b", FUNC(rs232_port_device::write_rts));
1090 
1091 	rs232_port_device &rs232a(RS232_PORT(config, "rs232_a", default_rs232_devices, nullptr));
1092 	rs232a.rxd_handler().set(m_iouart, FUNC(upd7201_device::rxa_w));
1093 	rs232a.cts_handler().set(m_iouart, FUNC(upd7201_device::ctsa_w));
1094 	rs232a.dcd_handler().set(m_iouart, FUNC(upd7201_device::dcda_w));
1095 	rs232a.ri_handler().set(m_iouart, FUNC(upd7201_device::synca_w));
1096 
1097 	rs232_port_device &rs232b(RS232_PORT(config, "rs232_b", default_rs232_devices, nullptr));
1098 	rs232b.rxd_handler().set(m_iouart, FUNC(upd7201_device::rxb_w));
1099 	rs232b.cts_handler().set(m_iouart, FUNC(upd7201_device::ctsb_w));
1100 	rs232b.dcd_handler().set(m_iouart, FUNC(upd7201_device::dcdb_w));
1101 	rs232b.ri_handler().set(m_iouart, FUNC(upd7201_device::syncb_w));
1102 
1103 	// TODO: SCN2652 MPCC (not implemented), used for RS-422 cluster communications?
1104 
1105 	// video board
1106 	screen_device &screen(SCREEN(config, "screen", SCREEN_TYPE_RASTER));
1107 	screen.set_size(720, 348);
1108 	screen.set_visarea(0, 719, 0, 347);
1109 	screen.set_refresh_hz(60);
1110 	screen.set_screen_update("crtc", FUNC(mc6845_device::screen_update));
1111 
1112 	MC6845(config, m_crtc, 19980000 / 9);  // divisor unknown -- /9 gives 60Hz output, so likely correct
1113 	m_crtc->set_screen("screen");
1114 	m_crtc->set_show_border_area(false);
1115 	m_crtc->set_char_width(9);
1116 	m_crtc->set_update_row_callback(FUNC(ngen386_state::crtc_update_row));
1117 
1118 	// keyboard UART (patent says i8251 is used for keyboard communications, it is located on the video board)
1119 	I8251(config, m_viduart, 0);  // main clock unknown, Rx/Tx clocks are 19.53kHz
1120 //  m_viduart->txempty_handler().set("pic", FUNC(pic8259_device::ir4_w));
1121 	m_viduart->txd_handler().set("keyboard", FUNC(rs232_port_device::write_txd));
1122 	rs232_port_device &kbd(RS232_PORT(config, "keyboard", keyboard, "ngen"));
1123 	kbd.rxd_handler().set(m_viduart, FUNC(i8251_device::write_rxd));
1124 
1125 	CLOCK(config, "refresh_clock", 19200*16).signal_handler().set(FUNC(ngen386_state::timer_clk_out)); // should be 19530Hz
1126 
1127 	// floppy disk / hard disk module (WD2797 FDC, WD1010 HDC, plus an 8253 timer for each)
1128 	WD2797(config, m_fdc, 20_MHz_XTAL / 20);
1129 	m_fdc->intrq_wr_callback().set(FUNC(ngen386_state::fdc_irq_w));
1130 	//m_fdc->drq_wr_callback().set(m_i386cpu, FUNC(i80186_cpu_device_device::drq1_w));
1131 	m_fdc->set_force_ready(true);
1132 
1133 	PIT8253(config, m_fdc_timer, 0);
1134 	m_fdc_timer->set_clk<0>(0);
1135 	m_fdc_timer->out_handler<0>().set(m_pic, FUNC(pic8259_device::ir5_w));  // clocked on FDC data register access
1136 	m_fdc_timer->set_clk<1>(20_MHz_XTAL / 20);
1137 //  m_fdc_timer->out_handler<1>().set(m_pic, FUNC(pic8259_device::ir5_w));  // 1MHz
1138 	m_fdc_timer->set_clk<2>(20_MHz_XTAL / 20);
1139 //  m_fdc_timer->out_handler<2>().set(m_pic, FUNC(pic8259_device::ir5_w));
1140 
1141 	// TODO: WD1010 HDC (not implemented), use WD2010 for now
1142 	WD2010(config, m_hdc, 20_MHz_XTAL / 4);
1143 	m_hdc->out_intrq_callback().set(m_pic, FUNC(pic8259_device::ir2_w));
1144 	m_hdc->in_bcs_callback().set(FUNC(ngen386_state::hd_buffer_r));
1145 	m_hdc->out_bcs_callback().set(FUNC(ngen386_state::hd_buffer_w));
1146 	m_hdc->in_drdy_callback().set_constant(1);
1147 	m_hdc->in_index_callback().set_constant(1);
1148 	m_hdc->in_wf_callback().set_constant(1);
1149 	m_hdc->in_tk000_callback().set_constant(1);
1150 	m_hdc->in_sc_callback().set_constant(1);
1151 
1152 	PIT8253(config, m_hdc_timer, 0);
1153 	m_hdc_timer->set_clk<2>(20_MHz_XTAL / 10);  // 2MHz
1154 
1155 	FLOPPY_CONNECTOR(config, "fdc:0", ngen_floppies, "525qd", floppy_image_device::default_floppy_formats);
1156 	HARDDISK(config, "hard0", 0);
1157 }
1158 
_386i(machine_config & config)1159 void ngen386_state::_386i(machine_config &config)
1160 {
1161 	ngen386(config);
1162 	m_i386cpu->set_addrmap(AS_PROGRAM, &ngen386_state::ngen386i_mem);
1163 }
1164 
1165 ROM_START( ngen )
1166 	ROM_REGION16_LE( 0x2000, "bios", 0)
1167 	ROM_LOAD16_BYTE( "72-00414_80186_cpu.bin",  0x000000, 0x001000, CRC(e1387a03) SHA1(ddca4eba67fbf8b731a8009c14f6b40edcbc3279) )  // bootstrap ROM v8.4
1168 	ROM_LOAD16_BYTE( "72-00415_80186_cpu.bin",  0x000001, 0x001000, CRC(a6dde7d9) SHA1(b4d15c1bce31460ab5b92ff43a68c15ac5485816) )
1169 
1170 	ROM_REGION16_LE( 0x2000, "vram", ROMREGION_ERASE00 )
1171 	ROM_REGION16_LE( 0x2000, "fontram", ROMREGION_ERASE00 )
1172 
1173 	ROM_REGION( 0x1000, "disk", 0)
1174 	ROM_LOAD( "72-00422_10mb_disk.bin", 0x000000, 0x001000,  CRC(f5b046b6) SHA1(b303c6f6aa40504016de9826879bc316e44389aa) )
1175 
1176 	ROM_REGION( 0x20, "disk_prom", 0)
1177 	ROM_LOAD( "72-00422_10mb_disk_15d.bin", 0x000000, 0x000020,  CRC(121ee494) SHA1(9a8d3c336cc7378a71f9d48c99f88515eb236fbf) )
1178 ROM_END
1179 
1180 // not sure just how similar these systems are to the 80186 model, but are here at the moment to document the dumps
1181 ROM_START( ngenb38 )
1182 	ROM_REGION32_LE( 0x2000, "bios", 0)
1183 	ROM_LOAD16_BYTE( "72-168_fpc_386_cpu.bin",  0x000000, 0x001000, CRC(250a3b68) SHA1(49c070514bac264fa4892f284f7d2c852ae6605d) )
1184 	ROM_LOAD16_BYTE( "72-167_fpc_386_cpu.bin",  0x000001, 0x001000, CRC(4010cc4e) SHA1(74a3024d605569056484d08b63f19fbf8eaf31c6) )
1185 
1186 	ROM_REGION16_LE( 0x2000, "vram", ROMREGION_ERASE00 )
1187 	ROM_REGION16_LE( 0x2000, "fontram", ROMREGION_ERASE00 )
1188 ROM_END
1189 
1190 ROM_START( 386i )
1191 	ROM_REGION32_LE( 0x4000, "bios", 0)
1192 	ROM_LOAD16_BYTE( "72-1561o_386i_cpu.bin",  0x000000, 0x002000, CRC(b5efd768) SHA1(8b250d47d9c6eb82e1afaeb2244d8c4134ecbc47) )
1193 	ROM_LOAD16_BYTE( "72-1562e_386i_cpu.bin",  0x000001, 0x002000, CRC(002d0d3a) SHA1(31de8592999377db9251acbeff348390a2d2602a) )
1194 
1195 	ROM_REGION16_LE( 0x2000, "vram", ROMREGION_ERASE00 )
1196 	ROM_REGION16_LE( 0x2000, "fontram", ROMREGION_ERASE00 )
1197 
1198 	ROM_REGION( 0x2000, "video", 0)
1199 	ROM_LOAD( "72-1630_gc-104_vga.bin",  0x000000, 0x002000, CRC(4e4d8ebe) SHA1(50c96ccb4d0bd1beb2d1aee0d18b2c462d25fc8f) )
1200 ROM_END
1201 
1202 
1203 COMP( 1983, ngen,    0,    0, ngen,    ngen, ngen_state,    empty_init, "Convergent Technologies",  "NGEN CP-001", MACHINE_IS_SKELETON )
1204 COMP( 1991, ngenb38, ngen, 0, ngen386, ngen, ngen386_state, empty_init, "Financial Products Corp.", "B28/38",      MACHINE_IS_SKELETON )
1205 COMP( 1990, 386i,    ngen, 0, _386i,   ngen, ngen386_state, empty_init, "Convergent Technologies",  "386i",        MACHINE_IS_SKELETON )
1206