summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/bus/isa/eis_hgb107x.cpp
blob: 25b16a38fe3620c1e5e7a93e39d44dded252ed8c (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
// license:BSD-3-Clause
// copyright-holders: Joakim Larsson Edström
/*****************************************************************************

  Ericsson PC Monochrome HR Graphics Board 1070

******************************************************************************/

/* PCB layouts and assembly years from online pictures and physical unit.
 Ericsson   -  marked SPVT02 8301 60 53-10, assembled in 1985 indicated by chip dates
 +--------------------------------------------------------------------------------------+ ___
 |  IC1  IC2   IC3   IC4   IC5 +-IC15--EPROM-+   IC6      IC7      IC8    S1        ||
 |                                 |8363 65 14-80|                                      ||
 | IC9  IC10 IC11  IC12  IC13  IC14|CG 50821 A64 |+------------------++-IC24 EPROM--+   ||
 |                                 +-------------+| CRTC HD46505SP-1 ||10-40VP      |   ||
 | IC16 IC17 IC18  IC19  IC20  IC21     IC22      | IC23 HD68A45SP   ||402 28 A19   | J4|| not
 |                                                +------------------++-------------+   || mounted
 | IC25 IC26 IC27  IC28  IC29  IC30       IC31       IC32      IC33      IC34           ||
 |                                                                                     O-|__
 | IC35 IC36 IC37  IC38  IC39  IC40       IC41       IC42      IC43      IC44           ||  |
 |                                                                                      ||DB15
 | IC45 IC46 IC47  IC48  IC49  IC50       IC51       IC52      IC53      IC54           ||  |
 |                                                                                      ||__|
 | IC55 IC56 IC57  IC58  IC59  IC60       IC61       IC62      IC63      IC64          O-|
 |                                                                               J1A    ||
 | IC65 IC66 IC67 IC68 IC69 IC70 IC71 IC72 +--------------------------------------------+|
 +-----------------------------------------+    |||||||||  |||||||||||||||||||||||||     |
   I85565  A85571 (labels)                                                               |
                                                                                         |

 IC's (from photos)
 ------------------------------------------------------------------------------
 IC1  74F109                              IC26 74F86                                IC51 TMS4416-15NL 4 x 16Kbits DRAM
 IC2  74LS393                             IC27 74LS08                               IC52 74ALS574
 IC3  74F64                               IC28 74F153                               IC53 74LS138
 IC4  74ALS299                            IC29 74LS174                              IC54 74F86
 IC5  74LS375                             IC30 74LS374                              IC55 74F109
 IC6  74LS151                             IC31 74LS374                              IC56 74F32
 IC7  74LS153                             IC32 74ALS574                             IC57 74F109
 IC8  74LS389?                            IC33 74LS08                               IC58 74F00?
 IC9  74F02                               IC34 74LS245                              IC59 74LS244
 IC10 74ALS109                            IC35 74F10?                               IC60 TMS4416-15NL 4 x 16Kbits DRAM
 IC11 Crystal 17.040MHz                   IC36 74LS02                               IC61 TMS4416-15NL 4 x 16Kbits DRAM
 IC12 74F64                               IC37 74LS00                               IC62 74ALS574
 IC13 74ALS299                            IC38 74F374                               IC63 74LS138
 IC14 PAL? 10-70ART40101                  IC39 74LS125                              IC64 74LS245
 IC15 EPROM 8363 65 14-80 CG 50821 A64    IC40 74LS244                              IC65 74LS00
 IC16 Crystal 19.170MHz                   IC41 74LS244                              IC66 74LS02
 IC17 74LS10                              IC42 74LS574                              IC67 74LS51
 IC18 74F08                               IC43 74LS32                               IC68 74LS04
 IC19 74ALS574                            IC44 MC10124 - TTL to MECL converter      IC69 74LS153
 IC20 74LS299                             IC45 74LS109                              IC70 74LS109
 IC21 74LS273                             IC46 74LS00                               IC71 74LS138
 IC22 74ALS574                            IC47 74F194                               IC72 74LS139
 IC23 CRTC HD46505SP,HD68A45SP            IC48 74F04
 IC24 EPROM 2764, 10-40 VP 402 28 A19     IC49 74LS174
 IC25 74ALS109                            IC50 TMS4416-15NL 4 x 16Kbits DRAM

 General description
 -------------------
 The PCB has a 2 bit DIP switch S1 and a DB15 non standard video connector. There is also an unsoldered J4 connector
 above the DB15 but no hole prepared for a connector in the plate. Above the J4 connector there is a two pin PCB connector
 that probably receives the power for the monitor for the DB15 from the PSU.

 Just below IC65 and IC66 there are two labels saying "I 85565" and "A E85571" respectively

 Video cable, card DB15 <---> monitor DB25
 ---------------------------------------------------
  Ericsson       2  +VS             4  Ericsson
  Monochrome     3  VS return       2  Monochrome HR
  HR Graphics   10  +VS            17  Monitors 3111 (Amber) or
  Board 1070    11  VS return      15  3712/3715 (Black & White)
         4  VSYNC           6
        12  VSYNC          19
         5  HSYNC           7
        13  HSYNC          20
         6  High intensity  8
        14  High intensity 21
         7  Video           9
        15  Video          22
                 8  GND            11

  This board is normaly used with an Ericsson monitor due to the non standard connector.
  Trivia: https://www.pinterest.se/pin/203084264425177097/
 */

#include "emu.h"
#include "eis_hgb107x.h"

#include "screen.h"

#define LOG_READ    (1U << 1)
#define LOG_SETUP   (1U << 2)
#define LOG_ROW     (1U << 3)
#define LOG_MODE    (1U << 4)
#define LOG_CHRG    (1U << 5)
#define LOG_STAT    (1U << 6)

//#define VERBOSE (LOG_MODE|LOG_SETUP|LOG_ROW)
//#define LOG_OUTPUT_STREAM std::cout

#include "logmacro.h"

#define LOGR(...)     LOGMASKED(LOG_READ,  __VA_ARGS__)
#define LOGSETUP(...) LOGMASKED(LOG_SETUP, __VA_ARGS__)
#define LOGROW(...)   LOGMASKED(LOG_ROW,   __VA_ARGS__)
#define LOGMODE(...)  LOGMASKED(LOG_MODE,  __VA_ARGS__)
#define LOGCHRG(...)  LOGMASKED(LOG_CHRG,  __VA_ARGS__)
#define LOGSTAT(...)  LOGMASKED(LOG_STAT,  __VA_ARGS__)

#ifdef _MSC_VER
#define FUNCNAME __func__
#else
#define FUNCNAME __PRETTY_FUNCTION__
#endif

#define MC6845_NAME "mc6845"

enum
{
	MDA_TEXT_INTEN = 0,
	MDA_TEXT_BLINK,
	MDA_LOWRES_TEXT_INTEN,
	MDA_LOWRES_TEXT_BLINK
};

#define EPC_MDA_SCREEN "epc_mda_screen" // TODO: use a device finder reference instead

ROM_START( epc )
	ROM_REGION(0x2000,"chargen", 0)
	ROM_LOAD("8363_65_14_80_cg_50821_a64.bin",  0x00000, 0x2000, CRC(be709786) SHA1(38ab26224bbe66bbe2bb2ccac29b41cbf78bdbf8))
	//ROM_LOAD("10_40_vp_402_28_ic_24_a19.bin",  0x00000, 0x2000, CRC(2aa53b92) SHA1(87051a037249eb631d7d2191bc0e925125c60f39))
ROM_END

//**************************************************************************
//  GLOBAL VARIABLES
//**************************************************************************
DEFINE_DEVICE_TYPE(ISA8_EPC_MDA, isa8_epc_mda_device, "isa_epc_mda", "Ericsson PC Monochrome HR Graphics Board 1070")

//-------------------------------------------------
//  device_add_mconfig - add device configuration
//-------------------------------------------------
/* There are two crystals on the board: 19.170Mhz and 17.040MHz  TODO: verify use */
/* Text modes uses 720x400 base resolution and the Graphics modes 320/640x200/400 */
/* This matches the difference between the crystals so we assume this for now     */
void isa8_epc_mda_device::device_add_mconfig(machine_config &config)
{
	screen_device &screen(SCREEN(config, EPC_MDA_SCREEN, SCREEN_TYPE_RASTER));
	screen.set_raw(XTAL(19'170'000) / 4, 720, 0, 720, 400, 0, 400);
	screen.set_screen_update(MC6845_NAME, FUNC(mc6845_device::screen_update));

	HD6845S(config, m_crtc, XTAL(19'170'000) / 16); // clock and divider are guesswork
	m_crtc->set_screen(EPC_MDA_SCREEN);
	m_crtc->set_show_border_area(false);
	m_crtc->set_char_width(8);

	m_crtc->set_update_row_callback(FUNC(isa8_epc_mda_device::crtc_update_row));
	m_crtc->out_hsync_callback().set(FUNC(isa8_epc_mda_device::hsync_changed));
	m_crtc->out_vsync_callback().set(FUNC(isa8_epc_mda_device::vsync_changed));
}

//-------------------------------------------------
//  rom_region - device-specific ROM region
//-------------------------------------------------
const tiny_rom_entry *isa8_epc_mda_device::device_rom_region() const
{
	return ROM_NAME( epc );
}

//**************************************************************************
//  LIVE DEVICE
//**************************************************************************

//-------------------------------------------------
//  isa8_epc_mda_device - constructor
//-------------------------------------------------
isa8_epc_mda_device::isa8_epc_mda_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
	isa8_epc_mda_device(mconfig, ISA8_EPC_MDA, tag, owner, clock)
{
}

isa8_epc_mda_device::isa8_epc_mda_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock) :
	device_t(mconfig, type, tag, owner, clock),
	device_isa8_card_interface(mconfig, *this),
	m_crtc(*this, MC6845_NAME),
	m_soft_chr_gen(nullptr),
	m_s1(*this, "S1"),
	m_color_mode(0),
	m_mode_control2(0),
	m_screen(*this, EPC_MDA_SCREEN),
	m_io_monitor(*this, "MONITOR"),
	m_chargen(*this, "chargen"),
	m_installed(false),
	m_framecnt(0),
	m_mode_control(0),
	m_update_row_type(-1),
	m_chr_gen(nullptr),
	m_vsync(0),
	m_hsync(0),
	m_pixel(0)
{
}

//-------------------------------------------------
//  device_start - device-specific startup
//-------------------------------------------------

void isa8_epc_mda_device::device_start()
{
	/* Palette for use with the Ericsson Amber Monochrome HR CRT monitor 3111, P3 phospor 602nm 255,183, 0 */
	m_3111_pal[0] = rgb_t(  0,   0,     0); // black
	m_3111_pal[1] = rgb_t(  143, 103,   0); // dim
	m_3111_pal[2] = rgb_t(  191, 137,   0); // normal
	m_3111_pal[3] = rgb_t(  255, 183,   0); // bright

	/* Palette for use with the Ericsson B&W Monochrome HR CRT monitor 3712/3715 */
	m_371x_pal[0] = rgb_t(    0,   0,   0); // black
	m_371x_pal[1] = rgb_t(  143, 143, 143); // dim
	m_371x_pal[2] = rgb_t(  191, 191, 191); // normal
	m_371x_pal[3] = rgb_t(  255, 255, 255); // bright

	/* Init a default palette */
	m_pal = &m_3111_pal; // In case screen starts rendering before device_reset where we read the settings
	m_videoram.resize(0x8000);
	set_isa_device();
	m_installed = false;
	m_hd6845s = subdevice<hd6845s_device>(MC6845_NAME);
}

void isa8_epc_mda_device::device_reset()
{
	m_framecnt = 0;
	m_mode_control = 0;
	m_vsync = 0;
	m_hsync = 0;
	m_pixel = 0;

	m_color_mode = m_s1->read();
	LOGSETUP("%s: m_color_mode:%02x\n", FUNCNAME, m_color_mode);
	m_pal = (m_io_monitor-> read() & 1) == 1 ? &m_371x_pal : &m_3111_pal;
	m_vmode = 0;

	if (m_installed == false)
	{
		m_isa->install_device(0x3b0, 0x3bf, read8sm_delegate(*this, FUNC(isa8_epc_mda_device::io_read)), write8sm_delegate(*this, FUNC(isa8_epc_mda_device::io_write)));
		m_isa->install_bank(0xb0000, 0xb7fff, "bank_epc", &m_videoram[0]); // Monochrome emulation mode VRAM address

		// This check allows a color monitor adapter to be installed at this address range if color emulation is disabled
		if (m_color_mode & 1)
		{
			m_isa->install_device(0x3d0, 0x3df, read8sm_delegate(*this, FUNC(isa8_epc_mda_device::io_read)), write8sm_delegate(*this, FUNC(isa8_epc_mda_device::io_write)));
			m_isa->install_bank(0xb8000, 0xbffff, "bank_epc", &m_videoram[0]); // Color emulation mode VRAM address, but same 32KB areas as there are only this amount on the board
		}
		m_installed = true;
	}
}

/*
 * Register Address table from the manual
 * Ericsson name          MDA mode   CGA mode  Standard name
 *-------------------------------------------------------------------------------
 * 6845 Address Registers 0x3b4      0x3d4     wo CRT Index reg
 * 6845 Data Registers    0x3b5      0x3d5     wo CRT Data reg
 * Mode Register 1        0x3b8      0x3d8     rw MDA/CGA mode reg (bit 0,1 & 4 incompatible)
 * Mode Register 2        0x3bf      0x3df     rw CRT/CPU page reg (incompatible w PCjr only)
 * Status Register        0x3ba      0x3da     r  CGA/MDA status reg (incompatible)
 *                                              w EGA/VGA feature ccontrol reg (not used by this board)
 */
void isa8_epc_mda_device::io_write(offs_t offset, uint8_t data)
{
	LOG("%s: %04x <- %02x\n", FUNCNAME, offset, data);
	switch( offset )
	{
		case 0x04:
			//LOGSETUP(" - HD6845S address write\n");
			m_hd6845s->address_w( data );
			break;
		case 0x05:
			//LOGSETUP(" - HD6845S register write\n");
			m_hd6845s->register_w( data );
			break;
		case 0x08: // Mode 1 reg
			LOGMODE(" - Mode register 1 write: %02x\n", data);
			LOGMODE("   MSB attribute: %s\n", (data & 0x20) == 0 ? "intensity" : "blink");
			LOGMODE("   Horizontal px: %s\n", (data & 0x10) == 0 ? "320/LR" : "640/HR");
			LOGMODE("   Video        : %s\n", (data & 0x08) == 0 ? "Disabled" : "Enabled");
			LOGMODE("   Mode         : %s\n", (data & 0x02) == 0 ? "Text" : "Graphics");
			LOGMODE("   Text columns : %d\n", (data & 0x01) == 0 ? 40 : 80);
			m_mode_control = data;
			m_vmode &= ~(VM_GRAPH | VM_COLS80 | VM_HOR640);
			m_vmode |= ((m_mode_control & 0x01) ? VM_COLS80 : 0);
			m_vmode |= ((m_mode_control & 0x02) ? VM_GRAPH  : 0);
			m_vmode |= ((m_mode_control & 0x10) ? VM_HOR640 : 0);
			m_update_row_type = ((data & 0x20) == 0 ? MDA_LOWRES_TEXT_INTEN : MDA_LOWRES_TEXT_BLINK);
			{
				rectangle rect(0, get_xres() - 1, 0, get_yres() -1);
				m_screen->configure(get_xres(), get_yres(), rect, HZ_TO_ATTOSECONDS(50));
			}
			LOGMODE("Video Mode:%02x\n\n", m_vmode);
			break;
		case 0x0f: // Mode 2 reg
			LOGMODE(" - Mode register 2 write: %02x\n", data);
			LOGMODE("   Vertical px  : %s\n", (data & MR2_VER400) == 0 ? "200" : "400");
			LOGMODE("   Character set: %s\n", (data & MR2_CHRSET) == 0 ? "0" : "1");
			LOGMODE("   Emulated     : %s\n", (data & MR2_COLEMU) == 0 ? "Color" : "Monochrome");
			m_mode_control2 = data;
			m_vmode &= ~(VM_MONO | VM_VER400);
			m_vmode |= ((m_mode_control2 & 0x04) ? VM_MONO   : 0);
			m_vmode |= ((m_mode_control2 & 0x80) ? VM_VER400 : 0);
			{
				rectangle rect(0, get_xres() - 1, 0, get_yres() -1);
				m_screen->configure(get_xres(), get_yres(), rect, HZ_TO_ATTOSECONDS(50));
			}
			LOGMODE("Video Mode:%02x\n\n", m_vmode);
			break;
		default:
			LOG("EPC MDA: io_write at wrong offset:%02x\n", offset);
	}
}

uint8_t isa8_epc_mda_device::io_read(offs_t offset)
{
	LOG("%s: %04x <- ???\n", FUNCNAME, offset);
	int data = 0xff;
	switch( offset )
	{
		case 0x04:
			LOGR(" - hd6845s address read\n");
			break;
		case 0x05:
			LOGR(" - hd6845s register read\n");
			data = m_hd6845s->register_r();
			break;
		case 0x08: // Mode 1 reg
			data = m_mode_control;
			LOGMODE(" - Mode register 1 read: %02x\n", data);
			break;
		case 0x0a: // Status reg: b7-6=00 board ID; b3 vert retrace; b0 horiz retrace; b5,4,2,1 unused
			data = (m_vsync != 0 ? 0x08 : 0x00) | (m_hsync != 0 ? 0x01 : 0x00);
			LOGSTAT(" - Status register read: %02x\n", data);
			break;
		case 0x0f: // Mode 2 reg
			data = m_mode_control2;
			LOGMODE(" - Mode register 2 read: %02x\n", data);
			break;
		default:
			LOG("EPC MDA: io_read at wrong offset:%02x\n", offset);
			logerror("EPC MDA: io_read at wrong offset:%02x\n", offset);
	}
	LOG(" !!!: %04x <- %02x\n", offset, data);
	return data;
}

WRITE_LINE_MEMBER( isa8_epc_mda_device::hsync_changed )
{
	m_hsync = state ? 1 : 0;
}


WRITE_LINE_MEMBER( isa8_epc_mda_device::vsync_changed )
{
	m_vsync = state ? 0x80 : 0;
	if ( state )
	{
		m_framecnt++;
	}
}


/*
 *  rW  MDA mode control register (see #P138)
 */
void isa8_epc_mda_device::mode_control_w(uint8_t data)
{
	m_mode_control = data;

	switch( m_mode_control & 0x2a )
	{
	case 0x08:
		m_update_row_type = MDA_TEXT_INTEN;
		break;
	case 0x28:
		m_update_row_type = MDA_TEXT_BLINK;
		break;
	default:
		m_update_row_type = -1;
	}
}


/*  R-  CRT status register (see #P139)
 *      (EGA/VGA) input status 1 register
 *      7    HGC vertical sync in progress
 *      6-4  adapter 000  hercules
 *                   001  hercules+
 *                   101  hercules InColor
 *                   else unknown
 *      3    pixel stream (0 black, 1 white)
 *      2-1  reserved
 *      0    horizontal drive enable
 */
uint8_t isa8_epc_mda_device::status_r()
{
	// Faking pixel stream here
	if (!machine().side_effects_disabled())
		m_pixel++;

	return 0xF0 | (m_pixel & 0x08) | m_hsync;
}

inline int isa8_epc_mda_device::get_xres()
{
	return (m_vmode & VM_GRAPH) ? ( (m_vmode & VM_HOR640) ? 640 : 320 ) : 720;
}

inline int isa8_epc_mda_device::get_yres()
{
	return (m_vmode & VM_GRAPH) ? ( (m_vmode & VM_VER400) ? 400 : 200 ) : 400;
}

MC6845_UPDATE_ROW(isa8_epc_mda_device::crtc_update_row)
{
	// Get som debug data from a couple of rows now and then
	if ( y < (16 * 0 + 0x20) && (m_framecnt & 0xff) == 0 )
	{
		LOGROW("%11.6f %s\n - y:%d chr_base:%d ra:%d ma:%d x_count:%d\n", machine().time().as_double(), FUNCNAME,
			   y, y % 16, ra, ma, x_count);
	}

	// Video Off handling
	if ((m_mode_control & MR1_VIDEO) == 0)
	{
		for (int i = 0; i < get_xres(); i++)
		{
			bitmap.pix(y, i) = rgb_t::black();
		}
	}

	// Graphic modes using only pixeldata, soft fonts are 8x8 or 8x16 but this is transparant to the code
	else if ((m_vmode & VM_GRAPH) != 0)
	{
		logerror("EPC MDA: graphic modes not supported yet\n");
	}

	// Text modes using one of two 9x16 fonts in character rom
	else
	{
		uint32_t  *p = &bitmap.pix(y);
		uint16_t  chr_base = ra;

		// Adjust row pointer if in monochrome text mode as we insert two scanlines per row of characters (see below)
		if (m_vmode & VM_MONO)
		{
			p = &bitmap.pix((y / 14) * 16 + y % 14);
		}

		// Loop over each character in a row
		for ( int i = 0; i < x_count; i++ )
		{
			uint16_t offset = ( ( ma + i ) << 1 ) & 0x0FFF;
			uint8_t chr = m_videoram[ offset ];
			uint8_t attr = m_videoram[ offset + 1 ];
			uint8_t data = m_chargen[ ((m_mode_control2 & MR2_CHRSET) ? 0x1000 : 0) + chr_base + chr * 16];

			// Default to light text on dark background
			uint8_t fg = 2;
			uint8_t bg = 0;

			if (y == 0 && i == 0) LOGCHRG(" - Offset: %04x Chr: '%c'[%02x] Attr: %02x Chr_base: %04x\n", offset, chr, chr, attr, chr_base);

			// Prepare some special monochrome emulation cases
			if ( m_vmode & VM_MONO)
			{
				// Handle invisible characters
				if ( (attr & (ATTR_FOREG | ATTR_BACKG)) == 0 )
				{
					data = 0x00;
				}
				// Handle reversed characters
				else if ( (attr & (ATTR_BACKG)) == ATTR_BACKG )
				{
					fg = 0;
					bg = 2;
				}
			}
			else // prepare some special color emulation cases
			{
				// Handle invisible characters
				if ( (attr & (ATTR_FOREG)) == ((attr & ATTR_BACKG) >> 4))
				{
					data = 0x00;
				}
				// Handle reversed characters
				else if ( (attr & ATTR_BACKG) == ATTR_BACKG ||
					  (attr & ATTR_FOREG) == 0 )
				{
					fg = 0;
					bg = 2;
				}
			}

			// Handle intense foreground
			if ((attr & ATTR_INTEN) != 0 && fg == 2)
			{
				fg = 3;
			}

			// Handle intense background if blinking is disabled
			if ((m_mode_control & MR1_BLINK) == 0 &&
				(attr & ATTR_BLINK) != 0 && bg == 2)
			{
				bg = 3;
			}

			// Handle cursor and blinks
			if ( i == (cursor_x))
			{
				if ( m_framecnt & 0x08 )
				{
					data = 0xFF;
				}
			}
			else
			{
				if ( (m_mode_control & MR1_BLINK) &&
					 ( attr & ATTR_BLINK ) && ( m_framecnt & 0x10 ) )
				{
					data = 0x00;
				}
			}

			*p = (*m_pal)[( data & 0x80 ) ? fg : bg]; p++;
			*p = (*m_pal)[( data & 0x40 ) ? fg : bg]; p++;
			*p = (*m_pal)[( data & 0x20 ) ? fg : bg]; p++;
			*p = (*m_pal)[( data & 0x10 ) ? fg : bg]; p++;
			*p = (*m_pal)[( data & 0x08 ) ? fg : bg]; p++;
			*p = (*m_pal)[( data & 0x04 ) ? fg : bg]; p++;
			*p = (*m_pal)[( data & 0x02 ) ? fg : bg]; p++;
			*p = (*m_pal)[( data & 0x01 ) ? fg : bg]; p++;
			if (chr >= 0xc0 && chr <= 0xdf)
				*p = (*m_pal)[( data & 0x01 ) ? fg : bg]; // 9th pixel col is a copy of col 8
			else
				*p = (*m_pal)[bg];                        // 9th pixel col is just background
			p++;

			// Insert two extra scanlines in monochrome text mode to get 400 lines and support underline, needs verification on actual hardware.
			// The technical manual says that the character box is 9x16 pixels in 80x25 character mode which equals 720x400 resolution but the
			// CRTC calls back for only 350 lines. Assumption is that there is hardware adding these lines and that handles underlining. In color
			// emulation text mode all 400 lines are called for in 80x25 and this mode does not support underlining according to the technical manual
			if ( ra == 13 && (m_vmode & VM_MONO) )
			{
				uint16_t row = ra + (y / 14) * 16; // Calculate correct row number including the extra 2 lines per each row of characters
				for ( int j = 0; j < 9; j++)
				{
					if (chr >= 0xb3 && chr <= 0xdf) // Handle the meta graphics characters
					{
						bitmap.pix(row + 1, j + i * 9) = (*m_pal)[( data & (0x80 >> j) ) || (j == 8 && (data & 0x01)) ? fg : bg];
						bitmap.pix(row + 2, j + i * 9) = (*m_pal)[( data & (0x80 >> j) ) || (j == 8 && (data & 0x01)) ? fg : bg];
					}
					else
					{
						// Handle underline
						bitmap.pix(row + 1, j + i * 9) =(*m_pal)[( attr & ATTR_FOREG ) == ATTR_ULINE ? fg : bg];
						bitmap.pix(row + 2, j + i * 9) = (*m_pal)[bg];
					}
				}
			}
		}
	}
}

//--------------------------------------------------------------------
//  Port definitions
//--------------------------------------------------------------------
static INPUT_PORTS_START( epc_mda )
	PORT_START( "S1" )
	PORT_DIPNAME( 0x01, 0x00, "Color emulation") PORT_DIPLOCATION("S1:1")
	PORT_DIPSETTING( 0x00, "Disabled" )
	PORT_DIPSETTING( 0x01, "Enabled" )
	PORT_DIPUNUSED_DIPLOC(0x02, 0x02, "S1:2")

	PORT_START( "MONITOR" )
	PORT_CONFNAME( 0x01, 0x00, "Ericsson Monochrome HR Monitors") PORT_CHANGED_MEMBER( DEVICE_SELF, isa8_epc_mda_device, monitor_changed, 0 )
	PORT_CONFSETTING(    0x00, "Amber 3111")
	PORT_CONFSETTING(    0x01, "B&W 3712/3715")
INPUT_PORTS_END

INPUT_CHANGED_MEMBER( isa8_epc_mda_device::monitor_changed )
{
	if ((m_io_monitor->read() & 1) == 1)
	{
		m_pal = &m_371x_pal;
	}
	else
	{
		m_pal = &m_3111_pal;
	}
}

ioport_constructor isa8_epc_mda_device::device_input_ports() const
{
	return INPUT_PORTS_NAME( epc_mda );
}