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