1 // license:BSD-3-Clause
2 // copyright-holders:Curt Coder
3 
4 /*
5 
6     NewBrain
7     Grundy Business Systems Ltd.
8 
9     32K RAM
10     28K ROM
11 
12     Z80 @ 2MHz
13     COP420 @ 2MHz
14 
15     Z80 @ 4MHz (416): INT/NMI=+5V, WAIT=EXTBUSRQ|BUSAKD, RESET=_FDC RESET,
16     NEC 765AC @ 4 MHz (418)
17     MC6850 ACIA (459)
18     Z80CTC (458)
19     ADC0809 (427)
20     DAC0808 (461)
21 
22     Models according to the Software Technical Manual:
23 
24     Model M: 'Page Register', Expansion Port onto Z80 bus, Video, ACIA/CTC, User Port
25     Model A: Expansion Port, Video, no User Port but has software driver serial port - s/w Printer, s/w V24
26     Model V: ACIA/CTC, User Port
27 
28 */
29 
30 /*
31 
32     TODO:
33 
34     - COPINT @ 84Hz instead of 50Hz? (with clock 3240506 is 50Hz)
35     - CLKINT arrives too late and COP reads the VFD data before CPU writes it
36     - VFD does not receive data from main CPU
37     - bitmapped video
38     - accurate video timing
39     - cassette motor control seems to have a COP cpu problem
40     - EIM
41     - floppy
42     - CP/M 2.2 ROMs
43     - localized ROM sets
44     - Micropage ROM/RAM card
45     - Z80 PIO board
46     - peripheral (PI) box
47     - sound card
48 
49 */
50 
51 #include "emu.h"
52 #include "includes/newbrain.h"
53 #include "speaker.h"
54 #include "screen.h"
55 
56 #include "newbrain.lh"
57 #include "newbraina.lh"
58 
59 
60 
61 //**************************************************************************
62 //  MACROS / CONSTANTS
63 //**************************************************************************
64 
65 #define LOG_COP (1 << 1U)
66 #define LOG_VFD (1 << 2U)
67 #define VERBOSE 0
68 #include "logmacro.h"
69 
70 
71 
72 //**************************************************************************
73 //  IMPLEMENTATION
74 //**************************************************************************
75 
76 //-------------------------------------------------
77 //  check_interrupt -
78 //-------------------------------------------------
79 
check_interrupt()80 void newbrain_state::check_interrupt()
81 {
82 	int level = ((!m_clk && !m_clkint) || !m_copint) ? ASSERT_LINE : CLEAR_LINE;
83 
84 	m_maincpu->set_input_line(INPUT_LINE_IRQ0, level);
85 }
86 
87 
88 //-------------------------------------------------
89 //  mreq_r - memory request read
90 //-------------------------------------------------
91 
mreq_r(offs_t offset)92 uint8_t newbrain_state::mreq_r(offs_t offset)
93 {
94 	bool romov = 1, raminh = 0;
95 	int exrm = 0;
96 	uint8_t data = m_exp->mreq_r(offset, 0xff, romov, exrm, raminh);
97 
98 	int rom0 = 1, rom1 = 1, rom2 = 1;
99 	int a15_14_13 = romov ? (offset >> 13) : exrm;
100 	if (!m_pwrup) a15_14_13 = 7;
101 	int a15g = BIT(a15_14_13, 2);
102 
103 	switch (a15_14_13)
104 	{
105 	case 5: rom0 = 0; break;
106 	case 6: rom1 = 0; break;
107 	case 7: rom2 = 0; break;
108 	}
109 
110 	if (!a15g && !raminh)
111 	{
112 		data = m_ram->pointer()[offset];
113 	}
114 
115 	if (!rom0)
116 	{
117 		data = m_rom->base()[0x0000 + (offset & 0x1fff)];
118 	}
119 
120 	if (!rom1)
121 	{
122 		data = m_rom->base()[0x2000 + (offset & 0x1fff)];
123 	}
124 
125 	if (!rom2)
126 	{
127 		data = m_rom->base()[0x4000 + (offset & 0x1fff)];
128 	}
129 
130 	return data;
131 }
132 
133 
134 //-------------------------------------------------
135 //  mreq_w - memory request write
136 //-------------------------------------------------
137 
mreq_w(offs_t offset,uint8_t data)138 void newbrain_state::mreq_w(offs_t offset, uint8_t data)
139 {
140 	bool romov = 1, raminh = 0;
141 	int exrm = 0;
142 	m_exp->mreq_w(offset, data, romov, exrm, raminh);
143 
144 	int a15_14_13 = romov ? (offset >> 13) : exrm;
145 	if (!m_pwrup) a15_14_13 = 7;
146 	int a15g = BIT(a15_14_13, 2);
147 
148 	if (!a15g && !raminh)
149 	{
150 		m_ram->pointer()[offset] = data;
151 	}
152 }
153 
154 
155 //-------------------------------------------------
156 //  iorq_r - I/O request read
157 //-------------------------------------------------
158 
iorq_r(offs_t offset)159 uint8_t newbrain_state::iorq_r(offs_t offset)
160 {
161 	bool prtov = 0;
162 	uint8_t data = m_exp->iorq_r(offset, 0xff, prtov);
163 
164 	if (!prtov)
165 	{
166 		switch ((offset >> 2) & 0x07)
167 		{
168 		case 1: // EXP1
169 			switch (offset & 0x03)
170 			{
171 			case 0: // CLCLK
172 				clclk();
173 				break;
174 
175 			case 2: // COP
176 				data = m_cop->microbus_rd();
177 				break;
178 			}
179 			break;
180 
181 		case 5: // UST
182 			if (BIT(offset, 1))
183 			{
184 				data = ust_b_r();
185 			}
186 			else
187 			{
188 				data = ust_a_r();
189 			}
190 			break;
191 		}
192 	}
193 
194 	return data;
195 }
196 
197 
198 //-------------------------------------------------
199 //  iorq_w - I/O request write
200 //-------------------------------------------------
201 
iorq_w(offs_t offset,uint8_t data)202 void newbrain_state::iorq_w(offs_t offset, uint8_t data)
203 {
204 	bool prtov = 0;
205 	m_exp->iorq_w(offset, 0xff, prtov);
206 
207 	if (!prtov)
208 	{
209 		switch ((offset >> 2) & 0x07)
210 		{
211 		case 1: // EXP1
212 			switch (offset & 0x03)
213 			{
214 			case 0: // CLCLK
215 				clclk();
216 				break;
217 
218 			case 2: // COP
219 				m_cop->microbus_wr(data);
220 				break;
221 
222 			case 3: // ENRG1
223 				enrg_w(data);
224 				break;
225 			}
226 			break;
227 
228 		case 2: // TVL
229 			tvl(data, BIT(offset, 6));
230 			break;
231 
232 		case 3: // TVTL
233 			tvtl_w(data);
234 			break;
235 		}
236 	}
237 }
238 
239 
240 //-------------------------------------------------
241 //  clclk - clear clock interrupt
242 //-------------------------------------------------
243 
clclk()244 void newbrain_state::clclk()
245 {
246 	LOG("%s %s CLCLK\n", machine().time().as_string(), machine().describe_context());
247 
248 	m_clkint = 1;
249 	check_interrupt();
250 }
251 
252 
253 //-------------------------------------------------
254 //  enrg_w -
255 //-------------------------------------------------
256 
enrg_w(uint8_t data)257 void newbrain_state::enrg_w(uint8_t data)
258 {
259 	/*
260 
261 	    bit     signal
262 
263 	    0       _CLK
264 	    1
265 	    2       TVP
266 	    3
267 	    4       _RTSD
268 	    5       DO
269 	    6
270 	    7       PO
271 
272 	*/
273 
274 	LOG("%s %s ENRG %02x\n", machine().time().as_string(), machine().describe_context(), data);
275 
276 	// clock enable
277 	int clk = BIT(data, 0);
278 
279 	if (m_clk != clk) {
280 		m_clk = clk;
281 		check_interrupt();
282 	}
283 
284 	// TV enable
285 	m_tvp = BIT(data, 2);
286 
287 	// V24
288 	m_rs232_v24->write_rts(BIT(data, 4));
289 	m_rs232_v24->write_txd(BIT(data, 5));
290 
291 	// printer
292 	m_rs232_prn->write_txd(BIT(data, 7));
293 }
294 
295 
296 //-------------------------------------------------
297 //  ust_r -
298 //-------------------------------------------------
299 
ust_a_r()300 uint8_t newbrain_state::ust_a_r()
301 {
302 	/*
303 
304 	    bit     signal
305 
306 	    0       +5V
307 	    1       PWRUP
308 	    2
309 	    3
310 	    4
311 	    5       _CLKINT
312 	    6
313 	    7       _COPINT
314 
315 	*/
316 
317 	uint8_t data = 0x5d;
318 
319 	// powered up
320 	data |= m_pwrup << 1;
321 
322 	// interrupts
323 	data |= m_clkint << 5;
324 	data |= m_copint << 7;
325 
326 	return data;
327 }
328 
329 
330 //-------------------------------------------------
331 //  user_r -
332 //-------------------------------------------------
333 
ust_b_r()334 uint8_t newbrain_state::ust_b_r()
335 {
336 	/*
337 
338 	    bit     signal
339 
340 	    0       RDDK
341 	    1       _CTSD
342 	    2
343 	    3
344 	    4
345 	    5       TPIN
346 	    6
347 	    7       _CTSP
348 
349 	*/
350 
351 	uint8_t data = 0x5c;
352 
353 	// V24
354 	data |= m_rs232_v24->rxd_r();
355 	data |= m_rs232_v24->cts_r() << 1;
356 
357 	// tape
358 	data |= tpin() << 5;
359 
360 	// printer
361 	data |= m_rs232_prn->cts_r() << 7;
362 
363 	return data;
364 }
365 
366 
367 //-------------------------------------------------
368 //  cop_in_r -
369 //-------------------------------------------------
370 
cop_in_r()371 uint8_t newbrain_state::cop_in_r()
372 {
373 	/*
374 
375 	    bit     description
376 
377 	    IN0     K8 (CD4076 Q2)
378 	    IN1     _RD
379 	    IN2     _COP
380 	    IN3     _WR
381 
382 	*/
383 
384 	uint8_t data = 0xe;
385 
386 	// keyboard
387 	data |= BIT(m_403_q, 2);
388 
389 	LOGMASKED(LOG_COP, "%s %s IN %01x\n", machine().time().as_string(), machine().describe_context(), data);
390 
391 	return data;
392 }
393 
394 
395 //-------------------------------------------------
396 //  cop_g_r -
397 //-------------------------------------------------
398 
cop_g_r()399 uint8_t newbrain_state::cop_g_r()
400 {
401 	/*
402 
403 	    bit     description
404 
405 	    G0
406 	    G1      K9 (CD4076 Q1)
407 	    G2      K7 (CD4076 Q0)
408 	    G3      K3 (CD4076 Q3)
409 
410 	*/
411 
412 	uint8_t data = 0;
413 
414 	// keyboard
415 	data |= BIT(m_403_q, 1) << 1;
416 	data |= BIT(m_403_q, 0) << 2;
417 	data |= BIT(m_403_q, 3) << 3;
418 
419 	LOGMASKED(LOG_COP, "%s %s G %01x\n", machine().time().as_string(), machine().describe_context(), data);
420 
421 	return data;
422 }
423 
424 
425 //-------------------------------------------------
426 //  cop_g_w -
427 //-------------------------------------------------
428 
429 // m_cop_g1 and m_cop_g3, when activated, have 20 zeros and a 1 in a continuous sequence.
430 // m_cop_k6 randomly alternates between 0 and 1, spending more time at 1.
431 // The outcome is the cassette is unreadable.
432 // Therefore the motors are left permanently on until the above issues can be fixed.
tm()433 void newbrain_state::tm()
434 {
435 //  cassette_state tm1 = (!m_cop_g1 && !m_cop_k6) ? CASSETTE_MOTOR_ENABLED : CASSETTE_MOTOR_DISABLED;
436 //  cassette_state tm2 = (!m_cop_g3 && !m_cop_k6) ? CASSETTE_MOTOR_ENABLED : CASSETTE_MOTOR_DISABLED;
437 
438 //  m_cassette1->change_state(tm1, CASSETTE_MASK_MOTOR);
439 //  m_cassette2->change_state(tm2, CASSETTE_MASK_MOTOR);
440 }
441 
cop_g_w(uint8_t data)442 void newbrain_state::cop_g_w(uint8_t data)
443 {
444 	/*
445 
446 	    bit     description
447 
448 	    G0      _COPINT
449 	    G1      _TM1
450 	    G2
451 	    G3      _TM2
452 
453 	*/
454 
455 	int copint = !BIT(data, 0);
456 
457 	LOGMASKED(LOG_COP, "%s %s COPINT %u\n", machine().time().as_string(), machine().describe_context(), copint);
458 
459 	if (m_copint != copint)
460 	{
461 		m_copint = copint;
462 		check_interrupt();
463 	}
464 
465 	m_cop_g1 = BIT(data, 1);
466 	m_cop_g3 = BIT(data, 3);
467 	tm();
468 }
469 
470 
471 //-------------------------------------------------
472 //  cop_d_w -
473 //-------------------------------------------------
474 
cop_d_w(uint8_t data)475 void newbrain_state::cop_d_w(uint8_t data)
476 {
477 	/*
478 	    bit     description
479 
480 	    D0      inverted to K4 -> CD4024 pin 2 (reset)
481 	    D1      TDO
482 	    D2      inverted to K6 -> CD4024 pin 1 (clock), CD4076 pin 7 (clock), inverted to DS8881 pin 3 (enable)
483 	    D3      not connected
484 
485 	*/
486 
487 	int k4 = !BIT(data, 0);
488 	int k6 = !BIT(data, 2);
489 
490 	LOGMASKED(LOG_COP, "%s %s K4 %u K6 %u\n", machine().time().as_string(), machine().describe_context(), k4, k6);
491 
492 	m_cop_tdo = BIT(data, 1);
493 	m_cassette1->output(m_cop_tdo ? -1.0 : +1.0);
494 	m_cassette2->output(m_cop_tdo ? -1.0 : +1.0);
495 
496 	if (k4) {
497 		m_405_q = 0;
498 
499 		LOGMASKED(LOG_COP, "%s %s keylatch reset\n", machine().time().as_string(), machine().describe_context());
500 	} else if (m_cop_k6 && !k6) {
501 		m_405_q++;
502 		m_405_q &= 0x7f;
503 
504 		LOGMASKED(LOG_COP, "%s %s keylatch %u\n", machine().time().as_string(), machine().describe_context(), m_405_q);
505 	}
506 
507 	if (!m_cop_k6 && k6) {
508 		m_403_d = m_y[m_405_q & 0x0f]->read() & 0x0f;
509 
510 		LOGMASKED(LOG_COP, "%s %s keydata %01x\n", machine().time().as_string(), machine().describe_context(), m_403_d);
511 	}
512 
513 	if (k6) {
514 		m_403_q = m_403_d;
515 	} else {
516 		m_403_q = 0xf;
517 
518 		LOGMASKED(LOG_COP, "%s %s keydata disabled\n", machine().time().as_string(), machine().describe_context());
519 
520 		// COP to VFD serial format, bits 15..0
521 		// A B J I x H G2 C x F G1 E K L M D
522 		uint16_t value = bitswap<16>(m_402_q, 11, 7, 1, 13, 10, 3, 2, 12, 9, 5, 6, 4, 0, 8, 14, 15) & 0x3fff;
523 		m_digits[m_405_q & 0x0f] = value;
524 
525 		LOGMASKED(LOG_VFD, "%s %s vfd segment %u 402.Q %04x data %04x\n", machine().time().as_string(), machine().describe_context(), m_405_q & 0x0f, m_402_q, value);
526 	}
527 
528 	m_cop_k6 = k6;
529 	tm();
530 }
531 
532 
533 //-------------------------------------------------
534 //  k1_w -
535 //-------------------------------------------------
536 
WRITE_LINE_MEMBER(newbrain_state::k1_w)537 WRITE_LINE_MEMBER( newbrain_state::k1_w )
538 {
539 	LOGMASKED(LOG_VFD, "%s %s SO %u\n", machine().time().as_string(), machine().describe_context(), state);
540 
541 	m_cop_so = state;
542 }
543 
544 
545 //-------------------------------------------------
546 //  k2_w -
547 //-------------------------------------------------
548 
WRITE_LINE_MEMBER(newbrain_state::k2_w)549 WRITE_LINE_MEMBER( newbrain_state::k2_w )
550 {
551 	LOGMASKED(LOG_VFD, "%s %s SK %u\n", machine().time().as_string(), machine().describe_context(), state);
552 
553 	if (state)
554 	{
555 		m_402_q <<= 1;
556 		m_402_q = (m_402_q & 0xfffe) | m_cop_so;
557 	}
558 }
559 
560 
561 //-------------------------------------------------
562 //  tdi_r -
563 //-------------------------------------------------
564 
tpin()565 int newbrain_state::tpin()
566 {
567 	return (m_cassette1->input() > +0.04) || (m_cassette2->input() > +0.04);
568 }
569 
READ_LINE_MEMBER(newbrain_state::tdi_r)570 READ_LINE_MEMBER( newbrain_state::tdi_r )
571 {
572 	return tpin() ^ m_cop_tdo;
573 }
574 
575 
576 
577 //**************************************************************************
578 //  ADDRESS MAPS
579 //**************************************************************************
580 
581 //-------------------------------------------------
582 //  ADDRESS_MAP( newbrain_mreq )
583 //-------------------------------------------------
584 
newbrain_mreq(address_map & map)585 void newbrain_state::newbrain_mreq(address_map &map)
586 {
587 	map.unmap_value_high();
588 	map(0x0000, 0xffff).rw(FUNC(newbrain_state::mreq_r), FUNC(newbrain_state::mreq_w));
589 }
590 
591 
592 //-------------------------------------------------
593 //  ADDRESS_MAP( newbrain_iorq )
594 //-------------------------------------------------
595 
newbrain_iorq(address_map & map)596 void newbrain_state::newbrain_iorq(address_map &map)
597 {
598 	map.unmap_value_high();
599 	map(0x0000, 0xffff).rw(FUNC(newbrain_state::iorq_r), FUNC(newbrain_state::iorq_w));
600 }
601 
602 
603 
604 //**************************************************************************
605 //  INPUT PORTS
606 //**************************************************************************
607 
608 //-------------------------------------------------
609 //  INPUT_PORTS( newbrain )
610 //-------------------------------------------------
611 
612 static INPUT_PORTS_START( newbrain )
613 	PORT_START("Y0")
614 	PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_UNUSED )
PORT_CODE(KEYCODE_ESC)615 	PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("STOP") PORT_CODE(KEYCODE_ESC) PORT_CHAR(UCHAR_MAMEKEY(ESC))
616 	PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_UNUSED )
617 	PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_UNUSED )
618 
619 	PORT_START("Y1")
620 	PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME(UTF8_DOWN) PORT_CODE(KEYCODE_DOWN) PORT_CHAR(UCHAR_MAMEKEY(DOWN))
621 	PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME(UTF8_RIGHT) PORT_CODE(KEYCODE_RIGHT) PORT_CHAR(UCHAR_MAMEKEY(RIGHT))
622 	PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME(UTF8_LEFT) PORT_CODE(KEYCODE_LEFT) PORT_CHAR(UCHAR_MAMEKEY(LEFT))
623 	PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME(UTF8_UP) PORT_CODE(KEYCODE_UP) PORT_CHAR(UCHAR_MAMEKEY(UP))
624 
625 	PORT_START("Y2")
626 	PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_U) PORT_CHAR('u') PORT_CHAR('U')
627 	PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_8) PORT_CHAR('8')
628 	PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_7) PORT_CHAR('7') PORT_CHAR('\'')
629 	PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_J) PORT_CHAR('j') PORT_CHAR('J')
630 
631 	PORT_START("Y3")
632 	PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_I) PORT_CHAR('i') PORT_CHAR('I')
633 	PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_9) PORT_CHAR('9')
634 	PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_6) PORT_CHAR('6') PORT_CHAR('&')
635 	PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_N) PORT_CHAR('n') PORT_CHAR('N')
636 
637 	PORT_START("Y4")
638 	PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_Y) PORT_CHAR('y') PORT_CHAR('Y')
639 	PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_0) PORT_CHAR('0')
640 	PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_5) PORT_CHAR('5') PORT_CHAR('%')
641 	PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_M) PORT_CHAR('m') PORT_CHAR('M')
642 
643 	PORT_START("Y5")
644 	PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_O) PORT_CHAR('o') PORT_CHAR('O')
645 	PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_MINUS) PORT_CHAR('(') PORT_CHAR('[')
646 	PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_4) PORT_CHAR('4') PORT_CHAR('$')
647 	PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_COMMA) PORT_CHAR(',') PORT_CHAR('<')
648 
649 	PORT_START("Y6")
650 	PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_L) PORT_CHAR('l') PORT_CHAR('L')
651 	PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_EQUALS) PORT_CHAR(')') PORT_CHAR(']')
652 	PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_3) PORT_CHAR('3') PORT_CHAR('#')
653 	PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_STOP) PORT_CHAR('.') PORT_CHAR('>')
654 
655 	PORT_START("Y7")
656 	PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_COLON) PORT_CHAR(';') PORT_CHAR(':')
657 	PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("* \xC2\xA3") PORT_CODE(KEYCODE_CLOSEBRACE) PORT_CHAR('*') PORT_CHAR(0x00A3)
658 	PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_2) PORT_CHAR('2') PORT_CHAR('"')
659 	PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_B) PORT_CHAR('b') PORT_CHAR('B')
660 
661 	PORT_START("Y8")
662 	PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_H) PORT_CHAR('h') PORT_CHAR('H')
663 	PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("VIDEO TEXT") PORT_CODE(KEYCODE_RALT) PORT_CHAR(UCHAR_MAMEKEY(RALT)) // Vd
664 	PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_1) PORT_CHAR('1') PORT_CHAR('!')
665 	PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_V) PORT_CHAR('v') PORT_CHAR('V')
666 
667 	PORT_START("Y9")
668 	PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_G) PORT_CHAR('g') PORT_CHAR('G')
669 	PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_P) PORT_CHAR('p') PORT_CHAR('P')
670 	PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_T) PORT_CHAR('t') PORT_CHAR('T')
671 	PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_C) PORT_CHAR('c') PORT_CHAR('C')
672 
673 	PORT_START("Y10")
674 	PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_F) PORT_CHAR('f') PORT_CHAR('F')
675 	PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_EQUALS) PORT_CHAR('=') PORT_CHAR('@')
676 	PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_R) PORT_CHAR('r') PORT_CHAR('R')
677 	PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_X) PORT_CHAR('x') PORT_CHAR('X')
678 
679 	PORT_START("Y11")
680 	PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_D) PORT_CHAR('d') PORT_CHAR('D')
681 	PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_OPENBRACE) PORT_CHAR('-') PORT_CHAR('\\')
682 	PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_E) PORT_CHAR('e') PORT_CHAR('E')
683 	PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_Z) PORT_CHAR('z') PORT_CHAR('Z')
684 
685 	PORT_START("Y12")
686 	PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_S) PORT_CHAR('s') PORT_CHAR('S')
687 	PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_QUOTE) PORT_CHAR('+') PORT_CHAR('^')
688 	PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_W) PORT_CHAR('w') PORT_CHAR('W')
689 	PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("INSERT") PORT_CODE(KEYCODE_INSERT) PORT_CHAR(UCHAR_MAMEKEY(INSERT))
690 
691 	PORT_START("Y13")
692 	PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_A) PORT_CHAR('a') PORT_CHAR('A')
693 	PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("NEW LINE") PORT_CODE(KEYCODE_ENTER) PORT_CHAR(13) // NL
694 	PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_Q) PORT_CHAR('q') PORT_CHAR('Q')
695 	PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_K) PORT_CHAR('k') PORT_CHAR('K')
696 
697 	PORT_START("Y14")
698 	PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_SLASH) PORT_CHAR('/') PORT_CHAR('?')
699 	PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_UNUSED )
700 	PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("SPACE") PORT_CODE(KEYCODE_SPACE) PORT_CHAR(' ')
701 	PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("HOME") PORT_CODE(KEYCODE_HOME) PORT_CHAR(UCHAR_MAMEKEY(HOME)) // CH
702 
703 	PORT_START("Y15")
704 	PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("SHIFT") PORT_CODE(KEYCODE_LSHIFT) PORT_CODE(KEYCODE_RSHIFT) PORT_CHAR(UCHAR_SHIFT_1) // SH
705 	PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("GRAPHICS") PORT_CODE(KEYCODE_LALT) PORT_CHAR(UCHAR_MAMEKEY(LALT)) // GR
706 	PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("REPEAT") // RPT
707 	PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("CONTROL") PORT_CODE(KEYCODE_LCONTROL) PORT_CHAR(UCHAR_MAMEKEY(LCONTROL)) // GL
708 INPUT_PORTS_END
709 
710 
711 
712 //**************************************************************************
713 //  MACHINE INITIALIZATION
714 //**************************************************************************
715 
716 int newbrain_state::get_reset_t()
717 {
718 	return RES_K(220) * CAP_U(10) * 1000; // t = R128 * C125 = 2.2s
719 }
720 
get_pwrup_t()721 int newbrain_state::get_pwrup_t()
722 {
723 	return RES_K(560) * CAP_U(10) * 1000; // t = R129 * C127 = 5.6s
724 }
725 
726 
727 //-------------------------------------------------
728 //  machine_start -
729 //-------------------------------------------------
730 
machine_start()731 void newbrain_state::machine_start()
732 {
733 	m_digits.resolve();
734 
735 	// set power up timer
736 	timer_set(attotime::from_usec(get_pwrup_t()), TIMER_ID_PWRUP);
737 
738 	// state saving
739 	save_item(NAME(m_clk));
740 	save_item(NAME(m_tvp));
741 	save_item(NAME(m_pwrup));
742 	save_item(NAME(m_clkint));
743 	save_item(NAME(m_copint));
744 	save_item(NAME(m_cop_so));
745 	save_item(NAME(m_cop_tdo));
746 	save_item(NAME(m_cop_g1));
747 	save_item(NAME(m_cop_g3));
748 	save_item(NAME(m_cop_k6));
749 	save_item(NAME(m_405_q));
750 	save_item(NAME(m_403_q));
751 	save_item(NAME(m_402_q));
752 
753 	// patch COP ROM to read VFD data
754 	//memregion(COP420_TAG)->base()[0x20a] = 0xc6;
755 }
756 
757 
758 //-------------------------------------------------
759 //  machine_reset -
760 //-------------------------------------------------
761 
machine_reset()762 void newbrain_state::machine_reset()
763 {
764 	m_maincpu->reset();
765 	m_cop->reset();
766 
767 	m_maincpu->set_input_line(INPUT_LINE_HALT, ASSERT_LINE);
768 	m_cop->set_input_line(INPUT_LINE_HALT, ASSERT_LINE);
769 
770 	enrg_w(0);
771 
772 	timer_set(attotime::from_usec(get_reset_t()), TIMER_ID_RESET);
773 }
774 
775 
776 //-------------------------------------------------
777 //  device_timer - handler timer events
778 //-------------------------------------------------
779 
device_timer(emu_timer & timer,device_timer_id id,int param,void * ptr)780 void newbrain_state::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
781 {
782 	switch (id)
783 	{
784 	case TIMER_ID_RESET:
785 		LOG("%s %s RESET 1\n", machine().time().as_string(), machine().describe_context());
786 
787 		m_maincpu->set_input_line(INPUT_LINE_HALT, CLEAR_LINE);
788 		m_cop->set_input_line(INPUT_LINE_HALT, CLEAR_LINE);
789 		break;
790 
791 	case TIMER_ID_PWRUP:
792 		LOG("%s %s PWRUP 1\n", machine().time().as_string(), machine().describe_context());
793 
794 		m_pwrup = 1;
795 		break;
796 
797 	case TIMER_ID_CLKINT:
798 		LOG("%s CLKINT\n", machine().time().as_string());
799 
800 		m_clkint = 0;
801 		check_interrupt();
802 		break;
803 	}
804 }
805 
806 
807 
808 //**************************************************************************
809 //  MACHINE DRIVERS
810 //**************************************************************************
811 
812 //-------------------------------------------------
813 //  machine_config( newbrain )
814 //-------------------------------------------------
815 
newbrain(machine_config & config)816 void newbrain_state::newbrain(machine_config &config)
817 {
818 	// basic system hardware
819 	Z80(config, m_maincpu, XTAL(16'000'000)/4);
820 	m_maincpu->set_addrmap(AS_PROGRAM, &newbrain_state::newbrain_mreq);
821 	m_maincpu->set_addrmap(AS_IO, &newbrain_state::newbrain_iorq);
822 
823 	COP420(config, m_cop, XTAL(16'000'000)/4);
824 	m_cop->set_config(COP400_CKI_DIVISOR_16, COP400_CKO_OSCILLATOR_OUTPUT, true);
825 	m_cop->read_g().set(FUNC(newbrain_state::cop_g_r));
826 	m_cop->write_g().set(FUNC(newbrain_state::cop_g_w));
827 	m_cop->write_d().set(FUNC(newbrain_state::cop_d_w));
828 	m_cop->read_in().set(FUNC(newbrain_state::cop_in_r));
829 	m_cop->write_so().set(FUNC(newbrain_state::k1_w));
830 	m_cop->write_sk().set(FUNC(newbrain_state::k2_w));
831 	m_cop->read_si().set(FUNC(newbrain_state::tdi_r));
832 
833 	// video hardware
834 	newbrain_video(config);
835 
836 	// devices
837 	NEWBRAIN_EXPANSION_SLOT(config, m_exp, XTAL(16'000'000)/4, newbrain_expansion_cards, "eim");
838 
839 	SPEAKER(config, "mono").front_center();
840 
841 	CASSETTE(config, m_cassette1);
842 	m_cassette1->set_default_state(CASSETTE_STOPPED | CASSETTE_MOTOR_ENABLED | CASSETTE_SPEAKER_ENABLED);
843 	m_cassette1->add_route(ALL_OUTPUTS, "mono", 0.05);
844 
845 	CASSETTE(config, m_cassette2);
846 	m_cassette2->set_default_state(CASSETTE_STOPPED | CASSETTE_MOTOR_ENABLED | CASSETTE_SPEAKER_ENABLED);
847 	m_cassette2->add_route(ALL_OUTPUTS, "mono", 0.05);
848 
849 	RS232_PORT(config, RS232_V24_TAG, default_rs232_devices, nullptr);
850 	RS232_PORT(config, RS232_PRN_TAG, default_rs232_devices, nullptr);
851 
852 	// internal ram
853 	RAM(config, RAM_TAG).set_default_size("32K");
854 }
855 
856 
857 //-------------------------------------------------
858 //  machine_config( newbrain_ad )
859 //-------------------------------------------------
860 
newbrain_ad(machine_config & config)861 void newbrain_state::newbrain_ad(machine_config &config)
862 {
863 	newbrain(config);
864 	config.set_default_layout(layout_newbrain);
865 }
866 
867 
868 //-------------------------------------------------
869 //  machine_config( newbrain_a )
870 //-------------------------------------------------
871 
newbrain_a(machine_config & config)872 void newbrain_state::newbrain_a(machine_config &config)
873 {
874 	newbrain(config);
875 	config.set_default_layout(layout_newbraina);
876 }
877 
878 
879 //-------------------------------------------------
880 //  machine_config( newbrain_md )
881 //-------------------------------------------------
882 
newbrain_md(machine_config & config)883 void newbrain_state::newbrain_md(machine_config &config)
884 {
885 	newbrain(config);
886 	config.set_default_layout(layout_newbrain);
887 }
888 
889 
890 
891 //**************************************************************************
892 //  ROMS
893 //**************************************************************************
894 
895 //-------------------------------------------------
896 //  ROM( newbrain )
897 //-------------------------------------------------
898 
899 ROM_START( newbrain )
900 	ROM_REGION( 0x6000, Z80_TAG, 0 )
901 	ROM_DEFAULT_BIOS( "rom20" )
902 
903 	ROM_SYSTEM_BIOS( 0, "issue1", "Issue 1 (v?)" )
904 	ROMX_LOAD( "aben.ic6",     0x0000, 0x2000, CRC(308f1f72) SHA1(a6fd9945a3dca47636887da2125fde3f9b1d4e25), ROM_BIOS(0) )
905 	ROMX_LOAD( "cd iss 1.ic7", 0x2000, 0x2000, CRC(6b4d9429) SHA1(ef688be4e75aced61f487c928258c8932a0ae00a), ROM_BIOS(0) )
906 	ROMX_LOAD( "ef iss 1.ic8", 0x4000, 0x2000, CRC(20dd0b49) SHA1(74b517ca223cefb588e9f49e72ff2d4f1627efc6), ROM_BIOS(0) )
907 
908 	ROM_SYSTEM_BIOS( 1, "issue2", "Issue 2 (v1.9)" )
909 	ROMX_LOAD( "aben19.ic6",   0x0000, 0x2000, CRC(d0283eb1) SHA1(351d248e69a77fa552c2584049006911fb381ff0), ROM_BIOS(1) )
910 	ROMX_LOAD( "cdi2.ic7",     0x2000, 0x2000, CRC(6b4d9429) SHA1(ef688be4e75aced61f487c928258c8932a0ae00a), ROM_BIOS(1) )
911 	ROMX_LOAD( "ef iss 1.ic8", 0x4000, 0x2000, CRC(20dd0b49) SHA1(74b517ca223cefb588e9f49e72ff2d4f1627efc6), ROM_BIOS(1) )
912 
913 	ROM_SYSTEM_BIOS( 2, "issue3", "Issue 3 (v1.91)" )
914 	ROMX_LOAD( "aben191.ic6",  0x0000, 0x2000, CRC(b7be8d89) SHA1(cce8d0ae7aa40245907ea38b7956c62d039d45b7), ROM_BIOS(2) )
915 	ROMX_LOAD( "cdi3.ic7",     0x2000, 0x2000, CRC(6b4d9429) SHA1(ef688be4e75aced61f487c928258c8932a0ae00a), ROM_BIOS(2) )
916 	ROMX_LOAD( "ef iss 1.ic8", 0x4000, 0x2000, CRC(20dd0b49) SHA1(74b517ca223cefb588e9f49e72ff2d4f1627efc6), ROM_BIOS(2) )
917 
918 	ROM_SYSTEM_BIOS( 3, "series2", "Series 2 (v?)" )
919 	ROMX_LOAD( "abs2.ic6",     0x0000, 0x2000, CRC(9a042acb) SHA1(80d83a2ea3089504aa68b6cf978d80d296cd9bda), ROM_BIOS(3) )
920 	ROMX_LOAD( "cds2.ic7",     0x2000, 0x2000, CRC(6b4d9429) SHA1(ef688be4e75aced61f487c928258c8932a0ae00a), ROM_BIOS(3) )
921 	ROMX_LOAD( "efs2.ic8",     0x4000, 0x2000, CRC(b222d798) SHA1(c0c816b4d4135b762f2c5f1b24209d0096f22e56), ROM_BIOS(3) )
922 
923 	ROM_SYSTEM_BIOS( 4, "rom20", "? (v2.0)" )
924 	ROMX_LOAD( "aben20.rom",   0x0000, 0x2000, CRC(3d76d0c8) SHA1(753b4530a518ad832e4b81c4e5430355ba3f62e0), ROM_BIOS(4) )
925 	ROMX_LOAD( "cd20tci.rom",  0x2000, 0x4000, CRC(f65b2350) SHA1(1ada7fbf207809537ec1ffb69808524300622ada), ROM_BIOS(4) )
926 
927 	ROM_REGION( 0x400, COP420_TAG, 0 )
928 	ROM_LOAD( "cop420-guw.ic419", 0x000, 0x400, CRC(a1388ee7) SHA1(5822e16aa794545600bf7a9dbee2ef467ca2a3e0) ) // COP420-GUW/N
929 
930 	ROM_REGION( 0x1000, "chargen", 0 )
931 	ROM_LOAD( "char eprom iss 1.ic453", 0x0000, 0x1000, CRC(6a38b7a2) SHA1(29f3e672fc41792ac2f2b405e571d79235193561) ) // 8248R7
932 ROM_END
933 
934 
935 //-------------------------------------------------
936 //  ROM( newbraina )
937 //-------------------------------------------------
938 
939 #define rom_newbraina rom_newbrain
940 
941 
942 //-------------------------------------------------
943 //  ROM( newbrainmd )
944 //-------------------------------------------------
945 
946 ROM_START( newbrainmd )
947 	ROM_REGION( 0x10000, Z80_TAG, 0 )
948 	ROM_LOAD( "cdmd.rom", 0x2000, 0x2000, CRC(6b4d9429) SHA1(ef688be4e75aced61f487c928258c8932a0ae00a) )
949 	ROM_LOAD( "efmd.rom", 0x4000, 0x2000, CRC(20dd0b49) SHA1(74b517ca223cefb588e9f49e72ff2d4f1627efc6) )
950 
951 	ROM_REGION( 0x400, COP420_TAG, 0 )
952 	ROM_LOAD( "cop420-guw.ic419", 0x000, 0x400, CRC(a1388ee7) SHA1(5822e16aa794545600bf7a9dbee2ef467ca2a3e0) ) // COP420-GUW/N
953 
954 	ROM_REGION( 0x1000, "chargen", 0 )
955 	ROM_LOAD( "char eprom iss 1.ic453", 0x0000, 0x1000, CRC(6a38b7a2) SHA1(29f3e672fc41792ac2f2b405e571d79235193561) ) // 8248R7
956 ROM_END
957 
958 
959 
960 //**************************************************************************
961 //  SYSTEM DRIVERS
962 //**************************************************************************
963 
964 //    YEAR  NAME        PARENT    COMPAT  MACHINE      INPUT     CLASS           INIT        COMPANY                        FULLNAME       FLAGS
965 COMP( 1981, newbrain,   0,        0,      newbrain_ad, newbrain, newbrain_state, empty_init, "Grundy Business Systems Ltd", "NewBrain AD", MACHINE_NOT_WORKING | MACHINE_SUPPORTS_SAVE | MACHINE_NO_SOUND )
966 COMP( 1981, newbraina,  newbrain, 0,      newbrain_a,  newbrain, newbrain_state, empty_init, "Grundy Business Systems Ltd", "NewBrain A",  MACHINE_NOT_WORKING | MACHINE_SUPPORTS_SAVE | MACHINE_NO_SOUND )
967 COMP( 1981, newbrainmd, newbrain, 0,      newbrain_md, newbrain, newbrain_state, empty_init, "Grundy Business Systems Ltd", "NewBrain MD", MACHINE_NOT_WORKING | MACHINE_SUPPORTS_SAVE | MACHINE_NO_SOUND )
968