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