1 // license:BSD-3-Clause
2 // copyright-holders: Joakim Larsson Edström
3 /*****************************************************************************
4 
5   Ericsson PC Monochrome HR Graphics Board 1070
6 
7 ******************************************************************************/
8 
9 /* PCB layouts and assembly years from online pictures and physical unit.
10  Ericsson   -  marked SPVT02 8301 60 53-10, assembled in 1985 indicated by chip dates
11  +--------------------------------------------------------------------------------------+ ___
12  |  IC1  IC2   IC3   IC4   IC5 +-IC15--EPROM-+   IC6      IC7      IC8    S1        ||
13  |                                 |8363 65 14-80|                                      ||
14  | IC9  IC10 IC11  IC12  IC13  IC14|CG 50821 A64 |+------------------++-IC24 EPROM--+   ||
15  |                                 +-------------+| CRTC HD46505SP-1 ||10-40VP      |   ||
16  | IC16 IC17 IC18  IC19  IC20  IC21     IC22      | IC23 HD68A45SP   ||402 28 A19   | J4|| not
17  |                                                +------------------++-------------+   || mounted
18  | IC25 IC26 IC27  IC28  IC29  IC30       IC31       IC32      IC33      IC34           ||
19  |                                                                                     O-|__
20  | IC35 IC36 IC37  IC38  IC39  IC40       IC41       IC42      IC43      IC44           ||  |
21  |                                                                                      ||DB15
22  | IC45 IC46 IC47  IC48  IC49  IC50       IC51       IC52      IC53      IC54           ||  |
23  |                                                                                      ||__|
24  | IC55 IC56 IC57  IC58  IC59  IC60       IC61       IC62      IC63      IC64          O-|
25  |                                                                               J1A    ||
26  | IC65 IC66 IC67 IC68 IC69 IC70 IC71 IC72 +--------------------------------------------+|
27  +-----------------------------------------+    |||||||||  |||||||||||||||||||||||||     |
28    I85565  A85571 (labels)                                                               |
29                                                                                          |
30 
31  IC's (from photos)
32  ------------------------------------------------------------------------------
33  IC1  74F109                              IC26 74F86                                IC51 TMS4416-15NL 4 x 16Kbits DRAM
34  IC2  74LS393                             IC27 74LS08                               IC52 74ALS574
35  IC3  74F64                               IC28 74F153                               IC53 74LS138
36  IC4  74ALS299                            IC29 74LS174                              IC54 74F86
37  IC5  74LS375                             IC30 74LS374                              IC55 74F109
38  IC6  74LS151                             IC31 74LS374                              IC56 74F32
39  IC7  74LS153                             IC32 74ALS574                             IC57 74F109
40  IC8  74LS389?                            IC33 74LS08                               IC58 74F00?
41  IC9  74F02                               IC34 74LS245                              IC59 74LS244
42  IC10 74ALS109                            IC35 74F10?                               IC60 TMS4416-15NL 4 x 16Kbits DRAM
43  IC11 Crystal 17.040MHz                   IC36 74LS02                               IC61 TMS4416-15NL 4 x 16Kbits DRAM
44  IC12 74F64                               IC37 74LS00                               IC62 74ALS574
45  IC13 74ALS299                            IC38 74F374                               IC63 74LS138
46  IC14 PAL? 10-70ART40101                  IC39 74LS125                              IC64 74LS245
47  IC15 EPROM 8363 65 14-80 CG 50821 A64    IC40 74LS244                              IC65 74LS00
48  IC16 Crystal 19.170MHz                   IC41 74LS244                              IC66 74LS02
49  IC17 74LS10                              IC42 74LS574                              IC67 74LS51
50  IC18 74F08                               IC43 74LS32                               IC68 74LS04
51  IC19 74ALS574                            IC44 MC10124 - TTL to MECL converter      IC69 74LS153
52  IC20 74LS299                             IC45 74LS109                              IC70 74LS109
53  IC21 74LS273                             IC46 74LS00                               IC71 74LS138
54  IC22 74ALS574                            IC47 74F194                               IC72 74LS139
55  IC23 CRTC HD46505SP,HD68A45SP            IC48 74F04
56  IC24 EPROM 2764, 10-40 VP 402 28 A19     IC49 74LS174
57  IC25 74ALS109                            IC50 TMS4416-15NL 4 x 16Kbits DRAM
58 
59  General description
60  -------------------
61  The PCB has a 2 bit DIP switch S1 and a DB15 non standard video connector. There is also an unsoldered J4 connector
62  above the DB15 but no hole prepared for a connector in the plate. Above the J4 connector there is a two pin PCB connector
63  that probably receives the power for the monitor for the DB15 from the PSU.
64 
65  Just below IC65 and IC66 there are two labels saying "I 85565" and "A E85571" respectively
66 
67  Video cable, card DB15 <---> monitor DB25
68  ---------------------------------------------------
69   Ericsson       2  +VS             4  Ericsson
70   Monochrome     3  VS return       2  Monochrome HR
71   HR Graphics   10  +VS            17  Monitors 3111 (Amber) or
72   Board 1070    11  VS return      15  3712/3715 (Black & White)
73          4  VSYNC           6
74         12  VSYNC          19
75          5  HSYNC           7
76         13  HSYNC          20
77          6  High intensity  8
78         14  High intensity 21
79          7  Video           9
80         15  Video          22
81                  8  GND            11
82 
83   This board is normaly used with an Ericsson monitor due to the non standard connector.
84   Trivia: https://www.pinterest.se/pin/203084264425177097/
85  */
86 
87 #include "emu.h"
88 #include "eis_hgb107x.h"
89 
90 #include "screen.h"
91 
92 #define LOG_READ    (1U << 1)
93 #define LOG_SETUP   (1U << 2)
94 #define LOG_ROW     (1U << 3)
95 #define LOG_MODE    (1U << 4)
96 #define LOG_CHRG    (1U << 5)
97 #define LOG_STAT    (1U << 6)
98 
99 //#define VERBOSE (LOG_MODE|LOG_SETUP|LOG_ROW)
100 //#define LOG_OUTPUT_STREAM std::cout
101 
102 #include "logmacro.h"
103 
104 #define LOGR(...)     LOGMASKED(LOG_READ,  __VA_ARGS__)
105 #define LOGSETUP(...) LOGMASKED(LOG_SETUP, __VA_ARGS__)
106 #define LOGROW(...)   LOGMASKED(LOG_ROW,   __VA_ARGS__)
107 #define LOGMODE(...)  LOGMASKED(LOG_MODE,  __VA_ARGS__)
108 #define LOGCHRG(...)  LOGMASKED(LOG_CHRG,  __VA_ARGS__)
109 #define LOGSTAT(...)  LOGMASKED(LOG_STAT,  __VA_ARGS__)
110 
111 #ifdef _MSC_VER
112 #define FUNCNAME __func__
113 #else
114 #define FUNCNAME __PRETTY_FUNCTION__
115 #endif
116 
117 #define MC6845_NAME "mc6845"
118 
119 enum
120 {
121 	MDA_TEXT_INTEN = 0,
122 	MDA_TEXT_BLINK,
123 	MDA_LOWRES_TEXT_INTEN,
124 	MDA_LOWRES_TEXT_BLINK
125 };
126 
127 #define EPC_MDA_SCREEN "epc_mda_screen" // TODO: use a device finder reference instead
128 
129 ROM_START( epc )
130 	ROM_REGION(0x2000,"chargen", 0)
CRC(be709786)131 	ROM_LOAD("8363_65_14_80_cg_50821_a64.bin",  0x00000, 0x2000, CRC(be709786) SHA1(38ab26224bbe66bbe2bb2ccac29b41cbf78bdbf8))
132 	//ROM_LOAD("10_40_vp_402_28_ic_24_a19.bin",  0x00000, 0x2000, CRC(2aa53b92) SHA1(87051a037249eb631d7d2191bc0e925125c60f39))
133 ROM_END
134 
135 //**************************************************************************
136 //  GLOBAL VARIABLES
137 //**************************************************************************
138 DEFINE_DEVICE_TYPE(ISA8_EPC_MDA, isa8_epc_mda_device, "isa_epc_mda", "Ericsson PC Monochrome HR Graphics Board 1070")
139 
140 //-------------------------------------------------
141 //  device_add_mconfig - add device configuration
142 //-------------------------------------------------
143 /* There are two crystals on the board: 19.170Mhz and 17.040MHz  TODO: verify use */
144 /* Text modes uses 720x400 base resolution and the Graphics modes 320/640x200/400 */
145 /* This matches the difference between the crystals so we assume this for now     */
146 void isa8_epc_mda_device::device_add_mconfig(machine_config &config)
147 {
148 	screen_device &screen(SCREEN(config, EPC_MDA_SCREEN, SCREEN_TYPE_RASTER));
149 	screen.set_raw(XTAL(19'170'000) / 4, 720, 0, 720, 400, 0, 400);
150 	screen.set_screen_update(MC6845_NAME, FUNC(mc6845_device::screen_update));
151 
152 	HD6845S(config, m_crtc, XTAL(19'170'000) / 16); // clock and divider are guesswork
153 	m_crtc->set_screen(EPC_MDA_SCREEN);
154 	m_crtc->set_show_border_area(false);
155 	m_crtc->set_char_width(8);
156 
157 	m_crtc->set_update_row_callback(FUNC(isa8_epc_mda_device::crtc_update_row));
158 	m_crtc->out_hsync_callback().set(FUNC(isa8_epc_mda_device::hsync_changed));
159 	m_crtc->out_vsync_callback().set(FUNC(isa8_epc_mda_device::vsync_changed));
160 }
161 
162 //-------------------------------------------------
163 //  rom_region - device-specific ROM region
164 //-------------------------------------------------
device_rom_region() const165 const tiny_rom_entry *isa8_epc_mda_device::device_rom_region() const
166 {
167 	return ROM_NAME( epc );
168 }
169 
170 //**************************************************************************
171 //  LIVE DEVICE
172 //**************************************************************************
173 
174 //-------------------------------------------------
175 //  isa8_epc_mda_device - constructor
176 //-------------------------------------------------
isa8_epc_mda_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)177 isa8_epc_mda_device::isa8_epc_mda_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
178 	isa8_epc_mda_device(mconfig, ISA8_EPC_MDA, tag, owner, clock)
179 {
180 }
181 
isa8_epc_mda_device(const machine_config & mconfig,device_type type,const char * tag,device_t * owner,uint32_t clock)182 isa8_epc_mda_device::isa8_epc_mda_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock) :
183 	device_t(mconfig, type, tag, owner, clock),
184 	device_isa8_card_interface(mconfig, *this),
185 	m_crtc(*this, MC6845_NAME),
186 	m_soft_chr_gen(nullptr),
187 	m_s1(*this, "S1"),
188 	m_color_mode(0),
189 	m_mode_control2(0),
190 	m_screen(*this, EPC_MDA_SCREEN),
191 	m_io_monitor(*this, "MONITOR"),
192 	m_chargen(*this, "chargen"),
193 	m_installed(false),
194 	m_framecnt(0),
195 	m_mode_control(0),
196 	m_update_row_type(-1),
197 	m_chr_gen(nullptr),
198 	m_vsync(0),
199 	m_hsync(0),
200 	m_pixel(0)
201 {
202 }
203 
204 //-------------------------------------------------
205 //  device_start - device-specific startup
206 //-------------------------------------------------
207 
device_start()208 void isa8_epc_mda_device::device_start()
209 {
210 	/* Palette for use with the Ericsson Amber Monochrome HR CRT monitor 3111, P3 phospor 602nm 255,183, 0 */
211 	m_3111_pal[0] = rgb_t(  0,   0,     0); // black
212 	m_3111_pal[1] = rgb_t(  143, 103,   0); // dim
213 	m_3111_pal[2] = rgb_t(  191, 137,   0); // normal
214 	m_3111_pal[3] = rgb_t(  255, 183,   0); // bright
215 
216 	/* Palette for use with the Ericsson B&W Monochrome HR CRT monitor 3712/3715 */
217 	m_371x_pal[0] = rgb_t(    0,   0,   0); // black
218 	m_371x_pal[1] = rgb_t(  143, 143, 143); // dim
219 	m_371x_pal[2] = rgb_t(  191, 191, 191); // normal
220 	m_371x_pal[3] = rgb_t(  255, 255, 255); // bright
221 
222 	/* Init a default palette */
223 	m_pal = &m_3111_pal; // In case screen starts rendering before device_reset where we read the settings
224 	m_videoram.resize(0x8000);
225 	set_isa_device();
226 	m_installed = false;
227 	m_hd6845s = subdevice<hd6845s_device>(MC6845_NAME);
228 }
229 
device_reset()230 void isa8_epc_mda_device::device_reset()
231 {
232 	m_framecnt = 0;
233 	m_mode_control = 0;
234 	m_vsync = 0;
235 	m_hsync = 0;
236 	m_pixel = 0;
237 
238 	m_color_mode = m_s1->read();
239 	LOGSETUP("%s: m_color_mode:%02x\n", FUNCNAME, m_color_mode);
240 	m_pal = (m_io_monitor-> read() & 1) == 1 ? &m_371x_pal : &m_3111_pal;
241 	m_vmode = 0;
242 
243 	if (m_installed == false)
244 	{
245 		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)));
246 		m_isa->install_bank(0xb0000, 0xb7fff, "bank_epc", &m_videoram[0]); // Monochrome emulation mode VRAM address
247 
248 		// This check allows a color monitor adapter to be installed at this address range if color emulation is disabled
249 		if (m_color_mode & 1)
250 		{
251 			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)));
252 			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
253 		}
254 		m_installed = true;
255 	}
256 }
257 
258 /*
259  * Register Address table from the manual
260  * Ericsson name          MDA mode   CGA mode  Standard name
261  *-------------------------------------------------------------------------------
262  * 6845 Address Registers 0x3b4      0x3d4     wo CRT Index reg
263  * 6845 Data Registers    0x3b5      0x3d5     wo CRT Data reg
264  * Mode Register 1        0x3b8      0x3d8     rw MDA/CGA mode reg (bit 0,1 & 4 incompatible)
265  * Mode Register 2        0x3bf      0x3df     rw CRT/CPU page reg (incompatible w PCjr only)
266  * Status Register        0x3ba      0x3da     r  CGA/MDA status reg (incompatible)
267  *                                              w EGA/VGA feature ccontrol reg (not used by this board)
268  */
io_write(offs_t offset,uint8_t data)269 void isa8_epc_mda_device::io_write(offs_t offset, uint8_t data)
270 {
271 	LOG("%s: %04x <- %02x\n", FUNCNAME, offset, data);
272 	switch( offset )
273 	{
274 		case 0x04:
275 			//LOGSETUP(" - HD6845S address write\n");
276 			m_hd6845s->address_w( data );
277 			break;
278 		case 0x05:
279 			//LOGSETUP(" - HD6845S register write\n");
280 			m_hd6845s->register_w( data );
281 			break;
282 		case 0x08: // Mode 1 reg
283 			LOGMODE(" - Mode register 1 write: %02x\n", data);
284 			LOGMODE("   MSB attribute: %s\n", (data & 0x20) == 0 ? "intensity" : "blink");
285 			LOGMODE("   Horizontal px: %s\n", (data & 0x10) == 0 ? "320/LR" : "640/HR");
286 			LOGMODE("   Video        : %s\n", (data & 0x08) == 0 ? "Disabled" : "Enabled");
287 			LOGMODE("   Mode         : %s\n", (data & 0x02) == 0 ? "Text" : "Graphics");
288 			LOGMODE("   Text columns : %d\n", (data & 0x01) == 0 ? 40 : 80);
289 			m_mode_control = data;
290 			m_vmode &= ~(VM_GRAPH | VM_COLS80 | VM_HOR640);
291 			m_vmode |= ((m_mode_control & 0x01) ? VM_COLS80 : 0);
292 			m_vmode |= ((m_mode_control & 0x02) ? VM_GRAPH  : 0);
293 			m_vmode |= ((m_mode_control & 0x10) ? VM_HOR640 : 0);
294 			m_update_row_type = ((data & 0x20) == 0 ? MDA_LOWRES_TEXT_INTEN : MDA_LOWRES_TEXT_BLINK);
295 			{
296 				rectangle rect(0, get_xres() - 1, 0, get_yres() -1);
297 				m_screen->configure(get_xres(), get_yres(), rect, HZ_TO_ATTOSECONDS(50));
298 			}
299 			LOGMODE("Video Mode:%02x\n\n", m_vmode);
300 			break;
301 		case 0x0f: // Mode 2 reg
302 			LOGMODE(" - Mode register 2 write: %02x\n", data);
303 			LOGMODE("   Vertical px  : %s\n", (data & MR2_VER400) == 0 ? "200" : "400");
304 			LOGMODE("   Character set: %s\n", (data & MR2_CHRSET) == 0 ? "0" : "1");
305 			LOGMODE("   Emulated     : %s\n", (data & MR2_COLEMU) == 0 ? "Color" : "Monochrome");
306 			m_mode_control2 = data;
307 			m_vmode &= ~(VM_MONO | VM_VER400);
308 			m_vmode |= ((m_mode_control2 & 0x04) ? VM_MONO   : 0);
309 			m_vmode |= ((m_mode_control2 & 0x80) ? VM_VER400 : 0);
310 			{
311 				rectangle rect(0, get_xres() - 1, 0, get_yres() -1);
312 				m_screen->configure(get_xres(), get_yres(), rect, HZ_TO_ATTOSECONDS(50));
313 			}
314 			LOGMODE("Video Mode:%02x\n\n", m_vmode);
315 			break;
316 		default:
317 			LOG("EPC MDA: io_write at wrong offset:%02x\n", offset);
318 	}
319 }
320 
io_read(offs_t offset)321 uint8_t isa8_epc_mda_device::io_read(offs_t offset)
322 {
323 	LOG("%s: %04x <- ???\n", FUNCNAME, offset);
324 	int data = 0xff;
325 	switch( offset )
326 	{
327 		case 0x04:
328 			LOGR(" - hd6845s address read\n");
329 			break;
330 		case 0x05:
331 			LOGR(" - hd6845s register read\n");
332 			data = m_hd6845s->register_r();
333 			break;
334 		case 0x08: // Mode 1 reg
335 			data = m_mode_control;
336 			LOGMODE(" - Mode register 1 read: %02x\n", data);
337 			break;
338 		case 0x0a: // Status reg: b7-6=00 board ID; b3 vert retrace; b0 horiz retrace; b5,4,2,1 unused
339 			data = (m_vsync != 0 ? 0x08 : 0x00) | (m_hsync != 0 ? 0x01 : 0x00);
340 			LOGSTAT(" - Status register read: %02x\n", data);
341 			break;
342 		case 0x0f: // Mode 2 reg
343 			data = m_mode_control2;
344 			LOGMODE(" - Mode register 2 read: %02x\n", data);
345 			break;
346 		default:
347 			LOG("EPC MDA: io_read at wrong offset:%02x\n", offset);
348 			logerror("EPC MDA: io_read at wrong offset:%02x\n", offset);
349 	}
350 	LOG(" !!!: %04x <- %02x\n", offset, data);
351 	return data;
352 }
353 
WRITE_LINE_MEMBER(isa8_epc_mda_device::hsync_changed)354 WRITE_LINE_MEMBER( isa8_epc_mda_device::hsync_changed )
355 {
356 	m_hsync = state ? 1 : 0;
357 }
358 
359 
WRITE_LINE_MEMBER(isa8_epc_mda_device::vsync_changed)360 WRITE_LINE_MEMBER( isa8_epc_mda_device::vsync_changed )
361 {
362 	m_vsync = state ? 0x80 : 0;
363 	if ( state )
364 	{
365 		m_framecnt++;
366 	}
367 }
368 
369 
370 /*
371  *  rW  MDA mode control register (see #P138)
372  */
mode_control_w(uint8_t data)373 void isa8_epc_mda_device::mode_control_w(uint8_t data)
374 {
375 	m_mode_control = data;
376 
377 	switch( m_mode_control & 0x2a )
378 	{
379 	case 0x08:
380 		m_update_row_type = MDA_TEXT_INTEN;
381 		break;
382 	case 0x28:
383 		m_update_row_type = MDA_TEXT_BLINK;
384 		break;
385 	default:
386 		m_update_row_type = -1;
387 	}
388 }
389 
390 
391 /*  R-  CRT status register (see #P139)
392  *      (EGA/VGA) input status 1 register
393  *      7    HGC vertical sync in progress
394  *      6-4  adapter 000  hercules
395  *                   001  hercules+
396  *                   101  hercules InColor
397  *                   else unknown
398  *      3    pixel stream (0 black, 1 white)
399  *      2-1  reserved
400  *      0    horizontal drive enable
401  */
status_r()402 uint8_t isa8_epc_mda_device::status_r()
403 {
404 	// Faking pixel stream here
405 	if (!machine().side_effects_disabled())
406 		m_pixel++;
407 
408 	return 0xF0 | (m_pixel & 0x08) | m_hsync;
409 }
410 
get_xres()411 inline int isa8_epc_mda_device::get_xres()
412 {
413 	return (m_vmode & VM_GRAPH) ? ( (m_vmode & VM_HOR640) ? 640 : 320 ) : 720;
414 }
415 
get_yres()416 inline int isa8_epc_mda_device::get_yres()
417 {
418 	return (m_vmode & VM_GRAPH) ? ( (m_vmode & VM_VER400) ? 400 : 200 ) : 400;
419 }
420 
MC6845_UPDATE_ROW(isa8_epc_mda_device::crtc_update_row)421 MC6845_UPDATE_ROW(isa8_epc_mda_device::crtc_update_row)
422 {
423 	// Get som debug data from a couple of rows now and then
424 	if ( y < (16 * 0 + 0x20) && (m_framecnt & 0xff) == 0 )
425 	{
426 		LOGROW("%11.6f %s\n - y:%d chr_base:%d ra:%d ma:%d x_count:%d\n", machine().time().as_double(), FUNCNAME,
427 			   y, y % 16, ra, ma, x_count);
428 	}
429 
430 	// Video Off handling
431 	if ((m_mode_control & MR1_VIDEO) == 0)
432 	{
433 		for (int i = 0; i < get_xres(); i++)
434 		{
435 			bitmap.pix(y, i) = rgb_t::black();
436 		}
437 	}
438 
439 	// Graphic modes using only pixeldata, soft fonts are 8x8 or 8x16 but this is transparant to the code
440 	else if ((m_vmode & VM_GRAPH) != 0)
441 	{
442 		logerror("EPC MDA: graphic modes not supported yet\n");
443 	}
444 
445 	// Text modes using one of two 9x16 fonts in character rom
446 	else
447 	{
448 		uint32_t  *p = &bitmap.pix(y);
449 		uint16_t  chr_base = ra;
450 
451 		// Adjust row pointer if in monochrome text mode as we insert two scanlines per row of characters (see below)
452 		if (m_vmode & VM_MONO)
453 		{
454 			p = &bitmap.pix((y / 14) * 16 + y % 14);
455 		}
456 
457 		// Loop over each character in a row
458 		for ( int i = 0; i < x_count; i++ )
459 		{
460 			uint16_t offset = ( ( ma + i ) << 1 ) & 0x0FFF;
461 			uint8_t chr = m_videoram[ offset ];
462 			uint8_t attr = m_videoram[ offset + 1 ];
463 			uint8_t data = m_chargen[ ((m_mode_control2 & MR2_CHRSET) ? 0x1000 : 0) + chr_base + chr * 16];
464 
465 			// Default to light text on dark background
466 			uint8_t fg = 2;
467 			uint8_t bg = 0;
468 
469 			if (y == 0 && i == 0) LOGCHRG(" - Offset: %04x Chr: '%c'[%02x] Attr: %02x Chr_base: %04x\n", offset, chr, chr, attr, chr_base);
470 
471 			// Prepare some special monochrome emulation cases
472 			if ( m_vmode & VM_MONO)
473 			{
474 				// Handle invisible characters
475 				if ( (attr & (ATTR_FOREG | ATTR_BACKG)) == 0 )
476 				{
477 					data = 0x00;
478 				}
479 				// Handle reversed characters
480 				else if ( (attr & (ATTR_BACKG)) == ATTR_BACKG )
481 				{
482 					fg = 0;
483 					bg = 2;
484 				}
485 			}
486 			else // prepare some special color emulation cases
487 			{
488 				// Handle invisible characters
489 				if ( (attr & (ATTR_FOREG)) == ((attr & ATTR_BACKG) >> 4))
490 				{
491 					data = 0x00;
492 				}
493 				// Handle reversed characters
494 				else if ( (attr & ATTR_BACKG) == ATTR_BACKG ||
495 					  (attr & ATTR_FOREG) == 0 )
496 				{
497 					fg = 0;
498 					bg = 2;
499 				}
500 			}
501 
502 			// Handle intense foreground
503 			if ((attr & ATTR_INTEN) != 0 && fg == 2)
504 			{
505 				fg = 3;
506 			}
507 
508 			// Handle intense background if blinking is disabled
509 			if ((m_mode_control & MR1_BLINK) == 0 &&
510 				(attr & ATTR_BLINK) != 0 && bg == 2)
511 			{
512 				bg = 3;
513 			}
514 
515 			// Handle cursor and blinks
516 			if ( i == (cursor_x))
517 			{
518 				if ( m_framecnt & 0x08 )
519 				{
520 					data = 0xFF;
521 				}
522 			}
523 			else
524 			{
525 				if ( (m_mode_control & MR1_BLINK) &&
526 					 ( attr & ATTR_BLINK ) && ( m_framecnt & 0x10 ) )
527 				{
528 					data = 0x00;
529 				}
530 			}
531 
532 			*p = (*m_pal)[( data & 0x80 ) ? fg : bg]; p++;
533 			*p = (*m_pal)[( data & 0x40 ) ? fg : bg]; p++;
534 			*p = (*m_pal)[( data & 0x20 ) ? fg : bg]; p++;
535 			*p = (*m_pal)[( data & 0x10 ) ? fg : bg]; p++;
536 			*p = (*m_pal)[( data & 0x08 ) ? fg : bg]; p++;
537 			*p = (*m_pal)[( data & 0x04 ) ? fg : bg]; p++;
538 			*p = (*m_pal)[( data & 0x02 ) ? fg : bg]; p++;
539 			*p = (*m_pal)[( data & 0x01 ) ? fg : bg]; p++;
540 			if (chr >= 0xc0 && chr <= 0xdf)
541 				*p = (*m_pal)[( data & 0x01 ) ? fg : bg]; // 9th pixel col is a copy of col 8
542 			else
543 				*p = (*m_pal)[bg];                        // 9th pixel col is just background
544 			p++;
545 
546 			// Insert two extra scanlines in monochrome text mode to get 400 lines and support underline, needs verification on actual hardware.
547 			// The technical manual says that the character box is 9x16 pixels in 80x25 character mode which equals 720x400 resolution but the
548 			// CRTC calls back for only 350 lines. Assumption is that there is hardware adding these lines and that handles underlining. In color
549 			// emulation text mode all 400 lines are called for in 80x25 and this mode does not support underlining according to the technical manual
550 			if ( ra == 13 && (m_vmode & VM_MONO) )
551 			{
552 				uint16_t row = ra + (y / 14) * 16; // Calculate correct row number including the extra 2 lines per each row of characters
553 				for ( int j = 0; j < 9; j++)
554 				{
555 					if (chr >= 0xb3 && chr <= 0xdf) // Handle the meta graphics characters
556 					{
557 						bitmap.pix(row + 1, j + i * 9) = (*m_pal)[( data & (0x80 >> j) ) || (j == 8 && (data & 0x01)) ? fg : bg];
558 						bitmap.pix(row + 2, j + i * 9) = (*m_pal)[( data & (0x80 >> j) ) || (j == 8 && (data & 0x01)) ? fg : bg];
559 					}
560 					else
561 					{
562 						// Handle underline
563 						bitmap.pix(row + 1, j + i * 9) =(*m_pal)[( attr & ATTR_FOREG ) == ATTR_ULINE ? fg : bg];
564 						bitmap.pix(row + 2, j + i * 9) = (*m_pal)[bg];
565 					}
566 				}
567 			}
568 		}
569 	}
570 }
571 
572 //--------------------------------------------------------------------
573 //  Port definitions
574 //--------------------------------------------------------------------
575 static INPUT_PORTS_START( epc_mda )
576 	PORT_START( "S1" )
577 	PORT_DIPNAME( 0x01, 0x00, "Color emulation") PORT_DIPLOCATION("S1:1")
578 	PORT_DIPSETTING( 0x00, "Disabled" )
579 	PORT_DIPSETTING( 0x01, "Enabled" )
580 	PORT_DIPUNUSED_DIPLOC(0x02, 0x02, "S1:2")
581 
582 	PORT_START( "MONITOR" )
583 	PORT_CONFNAME( 0x01, 0x00, "Ericsson Monochrome HR Monitors") PORT_CHANGED_MEMBER( DEVICE_SELF, isa8_epc_mda_device, monitor_changed, 0 )
584 	PORT_CONFSETTING(    0x00, "Amber 3111")
585 	PORT_CONFSETTING(    0x01, "B&W 3712/3715")
586 INPUT_PORTS_END
587 
INPUT_CHANGED_MEMBER(isa8_epc_mda_device::monitor_changed)588 INPUT_CHANGED_MEMBER( isa8_epc_mda_device::monitor_changed )
589 {
590 	if ((m_io_monitor->read() & 1) == 1)
591 	{
592 		m_pal = &m_371x_pal;
593 	}
594 	else
595 	{
596 		m_pal = &m_3111_pal;
597 	}
598 }
599 
device_input_ports() const600 ioport_constructor isa8_epc_mda_device::device_input_ports() const
601 {
602 	return INPUT_PORTS_NAME( epc_mda );
603 }
604