summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
author Joakim Larsson Edström <joakimlarsson42@gmail.com>2019-10-11 21:59:27 +0200
committer GitHub <noreply@github.com>2019-10-11 21:59:27 +0200
commit6e98146ef430c6203b294fa3a740357a7baf3699 (patch)
treed455b6ca51102e0576d651a381a5258a77788dc3
parent96c9d86f0ac3c8d6c519bdd6614f160608333884 (diff)
parent7261e08a8b7574510e76568557b470fa72205019 (diff)
Merge pull request #5686 from JoakimLarsson/epc_3
Rebase and completion of split out of epc driver and addition of graphics card
-rw-r--r--scripts/target/mame/mess.lua8
-rw-r--r--src/devices/bus/isa/ega.cpp60
-rw-r--r--src/devices/bus/isa/isa_cards.cpp2
-rw-r--r--src/devices/bus/isa/mda.cpp607
-rw-r--r--src/devices/bus/isa/mda.h82
-rw-r--r--src/devices/cpu/m6800/m6801.cpp50
-rw-r--r--src/devices/machine/i8251.cpp96
-rw-r--r--src/devices/machine/pit8253.cpp44
-rw-r--r--src/devices/video/mc6845.cpp47
-rw-r--r--src/devices/video/mc6845.h1
-rw-r--r--src/emu/xtal.cpp1
-rw-r--r--src/mame/drivers/eispc.cpp959
-rw-r--r--src/mame/drivers/pc.cpp52
-rw-r--r--src/mame/machine/eispc_kb.cpp412
-rw-r--r--src/mame/machine/eispc_kb.h43
-rw-r--r--src/mame/mame.lst4
-rw-r--r--src/mame/mess.flt1
17 files changed, 2232 insertions, 237 deletions
diff --git a/scripts/target/mame/mess.lua b/scripts/target/mame/mess.lua
index f84d84642cb..3d9b9c01448 100644
--- a/scripts/target/mame/mess.lua
+++ b/scripts/target/mame/mess.lua
@@ -1119,6 +1119,7 @@ function linkProjects_mame_mess(_target, _subtarget)
"entex",
"epoch",
"epson",
+ "ericsson",
"exidy",
"fairch",
"fairlight",
@@ -2182,6 +2183,13 @@ files {
MAME_DIR .. "src/mame/machine/qx10kbd.h",
}
+createMESSProjects(_target, _subtarget, "ericsson")
+files {
+ MAME_DIR .. "src/mame/drivers/eispc.cpp",
+ MAME_DIR .. "src/mame/machine/eispc_kb.cpp",
+ MAME_DIR .. "src/mame/machine/eispc_kb.h",
+}
+
createMESSProjects(_target, _subtarget, "exidy")
files {
MAME_DIR .. "src/mame/machine/sorcerer.cpp",
diff --git a/src/devices/bus/isa/ega.cpp b/src/devices/bus/isa/ega.cpp
index 5da3c263384..32175304f20 100644
--- a/src/devices/bus/isa/ega.cpp
+++ b/src/devices/bus/isa/ega.cpp
@@ -448,22 +448,31 @@ located at I/O port 0x3CE, and a data register located at I/O port 0x3CF.
#include "screen.h"
+#define LOG_READ (1U << 1)
+#define LOG_SETUP (1U << 2)
+#define LOG_MODE (1U << 3)
-#define VERBOSE_EGA 1
+//#define VERBOSE (LOG_GENERAL | LOG_SETUP | LOG_MODE)
+//#define LOG_OUTPUT_STREAM std::cout
+
+#include "logmacro.h"
+
+#define LOGR(...) LOGMASKED(LOG_READ, __VA_ARGS__)
+#define LOGSETUP(...) LOGMASKED(LOG_SETUP, __VA_ARGS__)
+#define LOGMODE(...) LOGMASKED(LOG_MODE, __VA_ARGS__)
+
+#ifdef _MSC_VER
+#define FUNCNAME __func__
+#else
+#define FUNCNAME __PRETTY_FUNCTION__
+#endif
#define EGA_SCREEN_NAME "ega_screen"
#define EGA_CRTC_NAME "crtc_ega_ega"
-
#define EGA_MODE_GRAPHICS 1
#define EGA_MODE_TEXT 2
-
-/*
- Prototypes
-*/
-
-
ROM_START( ega )
ROM_REGION(0x4000, "user1", 0)
ROM_DEFAULT_BIOS("ega")
@@ -776,7 +785,7 @@ CRTC_EGA_ROW_UPDATE( isa8_ega_device::pc_ega_graphics )
{
uint16_t *p = &bitmap.pix16(y);
-// logerror( "pc_ega_graphics: y = %d, x_count = %d, ma = %d, ra = %d\n", y, x_count, ma, ra );
+ LOG("%s: y = %d, x_count = %d, ma = %d, ra = %d\n", FUNCNAME, y, x_count, ma, ra );
if ( m_graphics_controller.data[5] & 0x10 )
{
@@ -838,7 +847,7 @@ CRTC_EGA_ROW_UPDATE( isa8_ega_device::pc_ega_text )
uint16_t *p = &bitmap.pix16(y);
int i;
-// logerror( "pc_ega_text: y = %d, x_count = %d, ma = %d, ra = %d\n", y, x_count, ma, ra );
+ LOG("%s: y = %d, x_count = %d, ma = %d, ra = %d\n", FUNCNAME, y, x_count, ma, ra );
for ( i = 0; i < x_count; i++ )
{
@@ -901,10 +910,7 @@ void isa8_ega_device::change_mode()
! ( m_sequencer.data[0x04] & 0x01 ) &&
( m_graphics_controller.data[0x06] & 0x01 ) )
{
- if ( VERBOSE_EGA )
- {
- logerror("change_mode(): Switch to graphics mode\n");
- }
+ LOGMODE("%s: Switch to graphics mode\n", FUNCNAME);
m_video_mode = EGA_MODE_GRAPHICS;
}
@@ -914,10 +920,7 @@ void isa8_ega_device::change_mode()
( m_sequencer.data[0x04] & 0x01 ) &&
! ( m_graphics_controller.data[0x06] & 0x01 ) )
{
- if ( VERBOSE_EGA )
- {
- logerror("chnage_mode(): Switching to text mode\n");
- }
+ LOGMODE("%s: Switching to text mode\n", FUNCNAME);
m_video_mode = EGA_MODE_TEXT;
@@ -1195,10 +1198,7 @@ READ8_MEMBER( isa8_ega_device::pc_ega8_3X0_r )
WRITE8_MEMBER( isa8_ega_device::pc_ega8_3X0_w )
{
- if ( VERBOSE_EGA )
- {
-// logerror("pc_ega_3X0_w: offset = %02x, data = %02x\n", offset, data );
- }
+ LOGSETUP("%s: offset = %02x, data = %02x\n", FUNCNAME, offset, data );
switch ( offset )
{
@@ -1263,10 +1263,7 @@ READ8_MEMBER(isa8_ega_device::pc_ega8_3c0_r )
{
int data = 0xff;
- if ( VERBOSE_EGA )
- {
-// logerror("pc_ega_3c0_r: offset = %02x\n", offset );
- }
+ LOGR("%s: offset = %02x\n", FUNCNAME, offset );
switch ( offset )
{
@@ -1322,10 +1319,7 @@ WRITE8_MEMBER(isa8_ega_device::pc_ega8_3c0_w )
};
int index;
- if ( VERBOSE_EGA )
- {
-// logerror("pc_ega_3c0_w: offset = %02x, data = %02x\n", offset, data );
- }
+ LOGSETUP("%s: offset = %02x, data = %02x\n", FUNCNAME, offset, data );
switch ( offset )
{
@@ -1339,7 +1333,7 @@ WRITE8_MEMBER(isa8_ega_device::pc_ega8_3c0_w )
{
index = m_attribute.index & 0x1F;
- logerror("AR%02X = 0x%02x\n", index, data );
+ LOGSETUP(" - AR%02X = 0x%02x\n", index, data );
/* Clear unused bits */
m_attribute.data[ index ] = data & ar_reg_mask[ index ];
@@ -1368,7 +1362,7 @@ WRITE8_MEMBER(isa8_ega_device::pc_ega8_3c0_w )
case 5:
index = m_sequencer.index & 0x07;
- logerror("SR%02X = 0x%02x\n", index & 0x07, data );
+ LOGSETUP(" - SR%02X = 0x%02x\n", index & 0x07, data );
/* Clear unused bits */
m_sequencer.data[ index ] = data & sr_reg_mask[ index ];
@@ -1390,7 +1384,7 @@ WRITE8_MEMBER(isa8_ega_device::pc_ega8_3c0_w )
case 15:
index = m_graphics_controller.index & 0x0F;
- logerror("GR%02X = 0x%02x\n", index, data );
+ LOGSETUP(" - GR%02X = 0x%02x\n", index, data );
/* Clear unused bits */
m_graphics_controller.data[ index ] = data & gr_reg_mask[ index ];
diff --git a/src/devices/bus/isa/isa_cards.cpp b/src/devices/bus/isa/isa_cards.cpp
index c97866bdf5e..4c0a41f430d 100644
--- a/src/devices/bus/isa/isa_cards.cpp
+++ b/src/devices/bus/isa/isa_cards.cpp
@@ -126,6 +126,7 @@ void pc_isa8_cards(device_slot_interface &device)
device.option_add("chessmdr", ISA8_CHESSMDR);
device.option_add("chessmsr", ISA8_CHESSMSR);
device.option_add("finalchs", ISA8_FINALCHS);
+ device.option_add("epc_mda", ISA8_EPC_MDA);
}
void pc_isa16_cards(device_slot_interface &device)
@@ -166,6 +167,7 @@ void pc_isa16_cards(device_slot_interface &device)
device.option_add("chessmdr", ISA8_CHESSMDR);
device.option_add("chessmsr", ISA8_CHESSMSR);
device.option_add("finalchs", ISA8_FINALCHS);
+ device.option_add("epc_mda", ISA8_EPC_MDA);
// 16-bit
device.option_add("ide", ISA16_IDE);
device.option_add("ne2000", NE2000);
diff --git a/src/devices/bus/isa/mda.cpp b/src/devices/bus/isa/mda.cpp
index 823ff040676..f660b48a1dd 100644
--- a/src/devices/bus/isa/mda.cpp
+++ b/src/devices/bus/isa/mda.cpp
@@ -12,6 +12,31 @@
#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 MDA_SCREEN_NAME "mda_screen"
#define MC6845_NAME "mc6845"
@@ -19,20 +44,7 @@
Hercules video card
*/
#define HERCULES_SCREEN_NAME "hercules_screen"
-
-#define VERBOSE_MDA 0 /* MDA (Monochrome Display Adapter) */
-
-#define MDA_CLOCK 16.257_MHz_XTAL
-
-#define MDA_LOG(N,M,A) \
- do { \
- if(VERBOSE_MDA>=N) \
- { \
- if( M ) \
- logerror("%11.6f: %-24s",machine().time().as_double(),(char*)M ); \
- logerror A; \
- } \
- } while (0)
+#define MDA_CLOCK XTAL(16'257'000)
static const unsigned char mda_palette[4][3] =
{
@@ -84,7 +96,7 @@ static GFXDECODE_START( gfx_pcmda )
GFXDECODE_END
-WRITE_LINE_MEMBER(isa8_mda_device::pc_cpu_line)
+WRITE_LINE_MEMBER( isa8_mda_device::pc_cpu_line )
{
m_isa->irq7_w(state);
}
@@ -211,7 +223,6 @@ void isa8_mda_device::device_reset()
The character cell size is 9x15. Column 9 is column 8 repeated for
character codes 176 to 223.
***************************************************************************/
-
MC6845_UPDATE_ROW( isa8_mda_device::mda_text_inten_update_row )
{
const rgb_t *palette = m_palette->palette()->entry_list_raw();
@@ -219,7 +230,7 @@ MC6845_UPDATE_ROW( isa8_mda_device::mda_text_inten_update_row )
uint16_t chr_base = ( ra & 0x08 ) ? 0x800 | ( ra & 0x07 ) : ra;
int i;
- if ( y == 0 ) MDA_LOG(1,"mda_text_inten_update_row",("\n"));
+ if ( y == 0 ) LOGROW("%11.6f: %-24s\n", machine().time().as_double(), FUNCNAME);
for ( i = 0; i < x_count; i++ )
{
uint16_t offset = ( ( ma + i ) << 1 ) & 0x0FFF;
@@ -292,7 +303,7 @@ MC6845_UPDATE_ROW( isa8_mda_device::mda_text_blink_update_row )
uint16_t chr_base = ( ra & 0x08 ) ? 0x800 | ( ra & 0x07 ) : ra;
int i;
- if ( y == 0 ) MDA_LOG(1,"mda_text_blink_update_row",("\n"));
+ if ( y == 0 ) LOGROW("%11.6f: %-24s\n", machine().time().as_double(), FUNCNAME);
for ( i = 0; i < x_count; i++ )
{
uint16_t offset = ( ( ma + i ) << 1 ) & 0x0FFF;
@@ -360,7 +371,6 @@ MC6845_UPDATE_ROW( isa8_mda_device::mda_text_blink_update_row )
}
}
-
MC6845_UPDATE_ROW( isa8_mda_device::crtc_update_row )
{
if (m_update_row_type == -1)
@@ -443,7 +453,7 @@ WRITE8_MEMBER( isa8_mda_device::mode_control_w )
* 2-1 reserved
* 0 horizontal drive enable
*/
-READ8_MEMBER( isa8_mda_device::status_r)
+READ8_MEMBER( isa8_mda_device::status_r )
{
// Faking pixel stream here
m_pixel++;
@@ -458,42 +468,42 @@ READ8_MEMBER( isa8_mda_device::status_r)
* monochrome display adapter
*
*************************************************************************/
-WRITE8_MEMBER( isa8_mda_device::io_write)
+WRITE8_MEMBER( isa8_mda_device::io_write )
{
switch( offset )
{
- case 0: case 2: case 4: case 6:
+ case 0x00: case 0x02: case 0x04: case 0x06:
m_crtc->address_w(data);
break;
- case 1: case 3: case 5: case 7:
+ case 0x01: case 0x03: case 0x05: case 0x07:
m_crtc->register_w(data);
break;
- case 8:
+ case 0x08:
mode_control_w(space, offset, data);
break;
- case 12: case 13: case 14:
- m_lpt->write(space, offset - 12, data);
+ case 0x0c: case 0x0d: case 0x0e:
+ m_lpt->write(space, offset - 0x0c, data);
break;
}
}
-READ8_MEMBER( isa8_mda_device::io_read)
+READ8_MEMBER( isa8_mda_device::io_read )
{
int data = 0xff;
switch( offset )
{
- case 0: case 2: case 4: case 6:
+ case 0x00: case 0x02: case 0x04: case 0x06:
/* return last written mc6845 address value here? */
break;
- case 1: case 3: case 5: case 7:
+ case 0x01: case 0x03: case 0x05: case 0x07:
data = m_crtc->register_r();
break;
- case 10:
+ case 0x0a:
data = status_r(space, offset);
break;
- /* 12, 13, 14 are the LPT ports */
- case 12: case 13: case 14:
- data = m_lpt->read(space, offset - 12);
+ /* LPT ports */
+ case 0x0c: case 0x0d: case 0x0e:
+ data = m_lpt->read(space, offset - 0x0c);
break;
}
return data;
@@ -624,7 +634,7 @@ MC6845_UPDATE_ROW( isa8_hercules_device::hercules_gfx_update_row )
uint32_t *p = &bitmap.pix32(y);
uint16_t gfx_base = ( ( m_mode_control & 0x80 ) ? 0x8000 : 0x0000 ) | ( ( ra & 0x03 ) << 13 );
int i;
- if ( y == 0 ) MDA_LOG(1,"hercules_gfx_update_row",("\n"));
+ if ( y == 0 ) LOGROW("%11.6f: %-24s\n", machine().time().as_double(), FUNCNAME);
for ( i = 0; i < x_count; i++ )
{
uint8_t data = m_videoram[ gfx_base + ( ( ma + i ) << 1 ) ];
@@ -681,19 +691,19 @@ WRITE8_MEMBER( isa8_hercules_device::io_write )
{
switch( offset )
{
- case 0: case 2: case 4: case 6:
+ case 0x00: case 0x02: case 0x04: case 0x06:
m_crtc->address_w(data);
break;
- case 1: case 3: case 5: case 7:
+ case 0x01: case 0x03: case 0x05: case 0x07:
m_crtc->register_w(data);
break;
- case 8:
+ case 0x08:
mode_control_w(space, offset, data);
break;
- case 12: case 13: case 14:
+ case 0x0c: case 0x0d: case 0x0e:
m_lpt->write(space, offset - 12, data);
break;
- case 15:
+ case 0x0f:
m_configuration_switch = data;
break;
}
@@ -725,18 +735,18 @@ READ8_MEMBER( isa8_hercules_device::io_read )
int data = 0xff;
switch( offset )
{
- case 0: case 2: case 4: case 6:
+ case 0x00: case 0x02: case 0x04: case 0x06:
/* return last written mc6845 address value here? */
break;
- case 1: case 3: case 5: case 7:
+ case 0x01: case 0x03: case 0x05: case 0x07:
data = m_crtc->register_r();
break;
- case 10:
+ case 0x0a:
data = status_r(space, offset);
break;
- /* 12, 13, 14 are the LPT ports */
- case 12: case 13: case 14:
- data = m_lpt->read(space, offset - 12);
+ /* LPT ports */
+ case 0xc: case 0xd: case 0xe:
+ data = m_lpt->read(space, offset - 0x0c);
break;
}
return data;
@@ -809,7 +819,7 @@ MC6845_UPDATE_ROW( isa8_ec1840_0002_device::mda_lowres_text_inten_update_row )
uint16_t chr_base = ra;
int i;
- if ( y == 0 ) MDA_LOG(1,"mda_lowres_text_inten_update_row",("\n"));
+ if ( y == 0 ) LOGROW("%11.6f: %-24s\n", machine().time().as_double(), FUNCNAME);
for ( i = 0; i < x_count; i++ )
{
uint16_t offset = ( ( ma + i ) << 1 ) & 0x0FFF;
@@ -873,7 +883,7 @@ MC6845_UPDATE_ROW( isa8_ec1840_0002_device::mda_lowres_text_blink_update_row )
uint16_t chr_base = ra;
int i;
- if ( y == 0 ) MDA_LOG(1,"mda_lowres_text_blink_update_row",("\n"));
+ if ( y == 0 ) LOGROW("%11.6f: %-24s\n", machine().time().as_double(), FUNCNAME);
for ( i = 0; i < x_count; i++ )
{
uint16_t offset = ( ( ma + i ) << 1 ) & 0x0FFF;
@@ -965,3 +975,506 @@ MC6845_UPDATE_ROW( isa8_ec1840_0002_device::crtc_update_row )
break;
}
}
+
+/*****************************************************************************
+
+ 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/
+ */
+
+#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(h46505_device::screen_update));
+ screen.set_screen_update(MC6845_NAME, FUNC(mc6845_device::screen_update));
+
+ PALETTE(config, m_palette).set_entries(4);
+
+ 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), this);
+ 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));
+
+ //MCFG_GFXDECODE_ADD("gfxdecode", "palette", pcepc)
+}
+
+//-------------------------------------------------
+// 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_mda_device(mconfig, ISA8_EPC_MDA, tag, owner, clock),
+ 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)
+{
+}
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void isa8_epc_mda_device::device_start()
+{
+ if (m_palette != nullptr && !m_palette->started())
+ throw device_missing_dependencies();
+
+ /* 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_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, read8_delegate( FUNC(isa8_epc_mda_device::io_read), this ), write8_delegate( FUNC(isa8_epc_mda_device::io_write), this ) );
+ 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, read8_delegate( FUNC(isa8_epc_mda_device::io_read), this ), write8_delegate( FUNC(isa8_epc_mda_device::io_write), this ) );
+ 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)
+ */
+WRITE8_MEMBER(isa8_epc_mda_device::io_write )
+{
+ 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);
+ }
+}
+
+READ8_MEMBER( isa8_epc_mda_device::io_read )
+{
+ 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;
+}
+
+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)
+{
+ uint32_t *p = &bitmap.pix32(y);
+ uint16_t chr_base = ra;
+ int i;
+
+ // 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.pix32(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
+ {
+ // 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.pix32((y / 14) * 16 + y % 14);
+ }
+
+ // Loop over each character in a row
+ for ( 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.pix32(row + 1, j + i * 9) = (*m_pal)[( data & (0x80 >> j) ) || (j == 8 && (data & 0x01)) ? fg : bg];
+ bitmap.pix32(row + 2, j + i * 9) = (*m_pal)[( data & (0x80 >> j) ) || (j == 8 && (data & 0x01)) ? fg : bg];
+ }
+ else
+ {
+ // Handle underline
+ bitmap.pix32(row + 1, j + i * 9) =(*m_pal)[( attr & ATTR_FOREG ) == ATTR_ULINE ? fg : bg];
+ bitmap.pix32(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 );
+}
diff --git a/src/devices/bus/isa/mda.h b/src/devices/bus/isa/mda.h
index c8b259f1fb3..9959f3a6094 100644
--- a/src/devices/bus/isa/mda.h
+++ b/src/devices/bus/isa/mda.h
@@ -137,4 +137,86 @@ private:
// device type definition
DECLARE_DEVICE_TYPE(ISA8_EC1840_0002, isa8_ec1840_0002_device)
+// ======================> isa8_epc_mda_device
+
+class isa8_epc_mda_device :
+ public isa8_mda_device
+{
+public:
+ // construction/destruction
+ isa8_epc_mda_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+
+ virtual DECLARE_READ8_MEMBER(io_read) override;
+ virtual DECLARE_WRITE8_MEMBER(io_write) override;
+
+ /* Monitor */
+ DECLARE_INPUT_CHANGED_MEMBER(monitor_changed);
+
+protected:
+ // device-level overrides
+ virtual void device_start() override;
+ virtual void device_reset() override;
+
+ // optional information overrides
+ virtual void device_add_mconfig(machine_config &config) override;
+ virtual const tiny_rom_entry *device_rom_region() const override;
+ virtual ioport_constructor device_input_ports() const override;
+
+private:
+ inline int get_xres();
+ inline int get_yres();
+ //virtual DECLARE_WRITE8_MEMBER(mode_control_w) override;
+
+ enum {
+ VM_COLS80 = 0x01,
+ VM_GRAPH = 0x02,
+ VM_HOR640 = 0x04,
+ VM_MONO = 0x08,
+ VM_VER400 = 0x10
+ };
+
+ enum {
+ MR1_COLS80 = 0x01,
+ MR1_GRAPH = 0x02,
+ MR1_VIDEO = 0x08,
+ MR1_HOR640 = 0x10,
+ MR1_BLINK = 0x20
+ };
+
+ enum {
+ MR2_COLEMU = 0x04,
+ MR2_CHRSET = 0x40,
+ MR2_VER400 = 0x80
+ };
+
+ enum {
+ ATTR_BLINK = 0x80,
+ ATTR_BACKG = 0x70,
+ ATTR_INTEN = 0x08,
+ ATTR_FOREG = 0x07,
+ ATTR_ULINE = 0x01,
+ };
+ virtual MC6845_UPDATE_ROW( crtc_update_row ) override;
+ //MC6845_UPDATE_ROW( mda_lowres_text_inten_update_row );
+ //MC6845_UPDATE_ROW( mda_lowres_text_blink_update_row );
+
+ std::unique_ptr<uint8_t[]> m_soft_chr_gen;
+ required_ioport m_s1;
+ uint8_t m_color_mode;
+ uint8_t m_mode_control2;
+ required_device<screen_device> m_screen;
+ required_ioport m_io_monitor;
+ required_region_ptr<uint8_t> m_chargen;
+
+ uint8_t m_vmode;
+ rgb_t (*m_pal)[4];
+ rgb_t m_3111_pal[4];
+ rgb_t m_371x_pal[4];
+ bool m_installed;
+ hd6845s_device *m_hd6845s;
+};
+
+// device type definition
+DECLARE_DEVICE_TYPE(ISA8_EPC_MDA, isa8_epc_mda_device)
+
#endif // MAME_BUS_ISA_MDA_H
diff --git a/src/devices/cpu/m6800/m6801.cpp b/src/devices/cpu/m6800/m6801.cpp
index 0bb7a8945ed..3cafae3e1e8 100644
--- a/src/devices/cpu/m6800/m6801.cpp
+++ b/src/devices/cpu/m6800/m6801.cpp
@@ -10,8 +10,10 @@
#define LOG_RX (1U << 3)
#define LOG_RXTICK (1U << 4)
#define LOG_PORT (1U << 5)
+#define LOG_SER (1U << 6)
-//#define VERBOSE (LOG_GENERAL | LOG_TX | LOG_RX | LOG_PORT)
+//#define VERBOSE (LOG_SER)
+//#define LOG_OUTPUT_STREAM std::cout
//#define LOG_OUTPUT_STREAM std::cerr
#include "logmacro.h"
@@ -20,6 +22,7 @@
#define LOGRX(...) LOGMASKED(LOG_RX, __VA_ARGS__)
#define LOGRXTICK(...) LOGMASKED(LOG_RXTICK, __VA_ARGS__)
#define LOGPORT(...) LOGMASKED(LOG_PORT, __VA_ARGS__)
+#define LOGSER(...) LOGMASKED(LOG_SER, __VA_ARGS__)
#define CT m_counter.w.l
@@ -413,11 +416,13 @@ void m6801_cpu_device::set_rmcr(uint8_t data)
switch ((m_rmcr & M6801_RMCR_CC_MASK) >> 2)
{
case 0:
+ LOGSER("6801: Using external serial clock: false\n");
m_sci_timer->enable(false);
m_use_ext_serclock = false;
break;
case 3: // external clock
+ LOGSER("6801: Using external serial clock: true\n");
m_use_ext_serclock = true;
m_sci_timer->enable(false);
break;
@@ -427,7 +432,7 @@ void m6801_cpu_device::set_rmcr(uint8_t data)
{
int divisor = M6801_RMCR_SS[m_rmcr & M6801_RMCR_SS_MASK];
attotime period = cycles_to_attotime(divisor);
-
+ LOGSER("6801: Setting serial rate, Divisor: %d Hz: %d\n", divisor, period.as_hz());
m_sci_timer->adjust(period, 0, period);
m_use_ext_serclock = false;
}
@@ -442,10 +447,12 @@ int m6801_cpu_device::m6800_rx()
void m6801_cpu_device::serial_transmit()
{
- LOGTXTICK("Tx Tick\n");
+ LOGTXTICK("6801 Tx Tick presenting: %d\n", m_tx);
if (m_trcsr & M6801_TRCSR_TE)
{
+ int old_m_tx = m_tx; // Detect line change
+
// force Port 2 bit 4 as output
m_port_ddr[1] |= M6801_PORT2_IO4;
@@ -486,7 +493,7 @@ void m6801_cpu_device::serial_transmit()
m_txbits++;
- LOGTX("Transmit START Data %02x\n", m_tsr);
+ LOGTX("6801 Transmit START Data %02x\n", m_tsr);
}
break;
@@ -498,7 +505,7 @@ void m6801_cpu_device::serial_transmit()
m_txbits = M6801_SERIAL_START;
- LOGTX("Transmit STOP\n");
+ LOGTX("6801 Transmit STOP\n");
break;
default:
@@ -508,7 +515,7 @@ void m6801_cpu_device::serial_transmit()
// shift transmit register
m_tsr >>= 1;
- LOGTX("Transmit Bit %u: %u\n", m_txbits, m_tx);
+ LOGTX("6801 Tx Present Bit %u: %u\n", m_txbits, m_tx);
m_txbits++;
break;
@@ -516,7 +523,10 @@ void m6801_cpu_device::serial_transmit()
break;
}
- m_out_sertx_func((m_tx == 1) ? ASSERT_LINE : CLEAR_LINE);
+ if (old_m_tx != m_tx) // call callback only if line has changed
+ {
+ m_out_sertx_func((m_tx == 1) ? ASSERT_LINE : CLEAR_LINE);
+ }
m_port2_written = 1;
write_port2();
}
@@ -524,7 +534,7 @@ void m6801_cpu_device::serial_transmit()
void m6801_cpu_device::serial_receive()
{
- LOGRXTICK("Rx Tick TRCSR %02x bits %u check %02x\n", m_trcsr, m_rxbits, m_trcsr & M6801_TRCSR_RE);
+ LOGRXTICK("6801 Rx Tick TRCSR %02x bits %u check %02x\n", m_trcsr, m_rxbits, m_trcsr & M6801_TRCSR_RE);
if (m_trcsr & M6801_TRCSR_RE)
{
@@ -535,11 +545,11 @@ void m6801_cpu_device::serial_receive()
{
m_rxbits++;
- LOGRX("Received WAKE UP bit %u\n", m_rxbits);
+ LOGRX("6801 Received WAKE UP bit %u\n", m_rxbits);
if (m_rxbits == 10)
{
- LOGRX("Receiver Wake Up\n");
+ LOGRX("6801 Receiver Wake Up\n");
m_trcsr &= ~M6801_TRCSR_WU;
m_rxbits = M6801_SERIAL_START;
@@ -547,7 +557,7 @@ void m6801_cpu_device::serial_receive()
}
else
{
- LOGRX("Receiver Wake Up interrupted\n");
+ LOGRX("6801 Receiver Wake Up interrupted\n");
m_rxbits = M6801_SERIAL_START;
}
@@ -563,21 +573,21 @@ void m6801_cpu_device::serial_receive()
// start bit found
m_rxbits++;
- LOGRX("Received START bit\n");
+ LOGRX("6801 Received START bit\n");
}
break;
case M6801_SERIAL_STOP:
if (m6800_rx() == 1)
{
- LOGRX("Received STOP bit\n");
+ LOGRX("6801 Received STOP bit\n");
if (m_trcsr & M6801_TRCSR_RDRF)
{
// overrun error
m_trcsr |= M6801_TRCSR_ORFE;
- LOGRX("Receive Overrun Error\n");
+ LOGRX("6801 Receive Overrun Error\n");
CHECK_IRQ_LINES();
}
@@ -588,7 +598,7 @@ void m6801_cpu_device::serial_receive()
// transfer data into receive register
m_rdr = m_rsr;
- LOGRX("Receive Data Register: %02x\n", m_rdr);
+ LOGRX("6801 Receive Data Register: %02x\n", m_rdr);
// set RDRF flag
m_trcsr |= M6801_TRCSR_RDRF;
@@ -609,7 +619,7 @@ void m6801_cpu_device::serial_receive()
m_trcsr |= M6801_TRCSR_ORFE;
m_trcsr &= ~M6801_TRCSR_RDRF;
- LOGRX("Receive Framing Error\n");
+ LOGRX("6801 Receive Framing Error\n");
CHECK_IRQ_LINES();
}
@@ -624,7 +634,7 @@ void m6801_cpu_device::serial_receive()
// receive bit into register
m_rsr |= (m6800_rx() << 7);
- LOGRX("Received DATA bit %u: %u\n", m_rxbits, BIT(m_rsr, 7));
+ LOGRX("6801 RX sampled DATA bit %u: %u\n", m_rxbits, BIT(m_rsr, 7));
m_rxbits++;
break;
@@ -1192,13 +1202,13 @@ WRITE8_MEMBER( m6801_cpu_device::m6801_io_w )
break;
case IO_RMCR:
- LOG("Rate and Mode Control Register: %02x\n", data);
+ LOGSER("Rate and Mode Control Register: %02x\n", data);
set_rmcr(data);
break;
case IO_TRCSR:
- LOG("Transmit/Receive Control and Status Register: %02x\n", data);
+ LOGSER("Transmit/Receive Control and Status Register: %02x\n", data);
if ((data & M6801_TRCSR_TE) && !(m_trcsr & M6801_TRCSR_TE))
{
@@ -1216,7 +1226,7 @@ WRITE8_MEMBER( m6801_cpu_device::m6801_io_w )
break;
case IO_TDR:
- LOGTX("Transmit Data Register: %02x\n", data);
+ LOGSER("6801 Transmit Data Register: $%02x/%d\n", data, data);
if (m_trcsr_read_tdre)
{
diff --git a/src/devices/machine/i8251.cpp b/src/devices/machine/i8251.cpp
index 1712796e64d..5c1638acffd 100644
--- a/src/devices/machine/i8251.cpp
+++ b/src/devices/machine/i8251.cpp
@@ -23,9 +23,20 @@ To Do:
#include "emu.h"
#include "i8251.h"
-//#define VERBOSE 1
+#define LOG_STAT (1U << 1)
+#define LOG_COM (1U << 2)
+#define LOG_MODE (1U << 3)
+#define LOG_BITS (1U << 4)
+
+//#define VERBOSE (LOG_BITS|LOG_GENERAL)
+//#define LOG_OUTPUT_STREAM std::cout
+
#include "logmacro.h"
+#define LOGSTAT(...) LOGMASKED(LOG_STAT, __VA_ARGS__)
+#define LOGCOM(...) LOGMASKED(LOG_COM, __VA_ARGS__)
+#define LOGMODE(...) LOGMASKED(LOG_MODE, __VA_ARGS__)
+#define LOGBITS(...) LOGMASKED(LOG_BITS, __VA_ARGS__)
//**************************************************************************
// DEVICE DEFINITIONS
@@ -153,6 +164,7 @@ void i8251_device::receive_clock()
//logerror("I8251\n");
/* get bit received from other side and update receive register */
+ //LOGBITS("8251: Rx Sampled %d\n", m_rxd);
receive_register_update_bit(m_rxd);
if (is_receive_register_synchronized())
m_rxc_count = sync ? m_br_factor : (3 * m_br_factor / 2);
@@ -316,7 +328,9 @@ bool i8251_device::is_tx_enabled() const
void i8251_device::check_for_tx_start()
{
if (is_tx_enabled() && (m_status & (I8251_STATUS_TX_EMPTY | I8251_STATUS_TX_READY)) == I8251_STATUS_TX_EMPTY)
+ {
start_tx();
+ }
}
/*-------------------------------------------------
@@ -357,6 +371,7 @@ void i8251_device::transmit_clock()
if (!is_transmit_register_empty())
{
uint8_t data = transmit_register_get_data_bit();
+ LOGBITS("8251: Tx Present a %d\n", data);
m_txd_handler(data);
}
}
@@ -454,6 +469,7 @@ void i8251_device::device_reset()
/* no character to read by cpu */
/* transmitter is ready and is empty */
m_status = I8251_STATUS_TX_EMPTY | I8251_STATUS_TX_READY;
+ LOGSTAT("status is reset to %02x\n", m_status);
m_mode_byte = 0;
m_command = 0;
m_rx_data = 0;
@@ -478,67 +494,26 @@ void i8251_device::device_reset()
void i8251_device::command_w(uint8_t data)
{
/* command */
- LOG("I8251: Command byte\n");
-
m_command = data;
- LOG("Command byte: %02x\n", data);
-
- if (BIT(data, 7))
- LOG("hunt mode\n");
-
- if (BIT(data, 5))
- LOG("/rts set to 0\n");
- else
- LOG("/rts set to 1\n");
-
- if (BIT(data, 2))
- LOG("receive enable\n");
- else
- LOG("receive disable\n");
-
- if (BIT(data, 1))
- LOG("/dtr set to 0\n");
- else
- LOG("/dtr set to 1\n");
-
- if (BIT(data, 0))
- LOG("transmit enable\n");
- else
- LOG("transmit disable\n");
-
-
- /* bit 7:
- 0 = normal operation
- 1 = hunt mode
- bit 6:
- 0 = normal operation
- 1 = internal reset
- bit 5:
- 0 = /RTS set to 1
- 1 = /RTS set to 0
- bit 4:
- 0 = normal operation
- 1 = reset error flag
- bit 3:
- 0 = normal operation
- 1 = send break character
- bit 2:
- 0 = receive disable
- 1 = receive enable
- bit 1:
- 0 = /DTR set to 1
- 1 = /DTR set to 0
- bit 0:
- 0 = transmit disable
- 1 = transmit enable
- */
+ LOG("I8251: Command byte: %02x\n", data);
+ LOGCOM(" Tx enable: %d\n", data & 0x01 ? 1 : 0); // bit 0: 0 = transmit disable 1 = transmit enable
+ LOGCOM(" DTR : %d\n", data & 0x02 ? 1 : 0); // bit 1: 0 = /DTR set to 1 1 = /DTR set to 0
+ LOGCOM(" Rx enable: %d\n", data & 0x04 ? 1 : 0); // bit 2: 0 = receive disable 1 = receive enable
+ LOGCOM(" Send BRK : %d\n", data & 0x08 ? 1 : 0); // bit 3: 0 = normal operation 1 = send break character
+ LOGCOM(" Err reset: %d\n", data & 0x10 ? 1 : 0); // bit 4: 0 = normal operation 1 = reset error flag
+ LOGCOM(" RTS : %d\n", data & 0x20 ? 1 : 0); // bit 5: 0 = /RTS set to 1 1 = /RTS set to 0
+ LOGCOM(" Reset : %d\n", data & 0x40 ? 1 : 0); // bit 6: 0 = normal operation 1 = internal reset
+ LOGCOM(" Hunt mode: %d\n", data & 0x80 ? 1 : 0); // bit 7: 0 = normal operation 1 = hunt mode
m_rts_handler(!BIT(data, 5));
m_dtr_handler(!BIT(data, 1));
if (BIT(data, 4))
+ {
+ LOGSTAT("status errors are reset\n");
m_status &= ~(I8251_STATUS_PARITY_ERROR | I8251_STATUS_OVERRUN_ERROR | I8251_STATUS_FRAMING_ERROR);
+ }
if (BIT(data, 6))
{
@@ -596,7 +571,6 @@ void i8251_device::mode_w(uint8_t data)
3 = x64
Synchronous
-
bit 7: Number of sync characters
0 = 1 character
1 = 2 character
@@ -746,6 +720,7 @@ uint8_t i8251_device::status_r()
// Syndet always goes off after status read
update_syndet(false);
+
return status;
}
@@ -763,6 +738,7 @@ void i8251_device::data_w(uint8_t data)
/* writing clears */
m_status &=~I8251_STATUS_TX_READY;
+ LOGSTAT("8251: status cleared TX_READY by data_w\n");
update_tx_ready();
// Store state of tx enable when writing to DB buffer
@@ -788,11 +764,17 @@ void i8251_device::receive_character(uint8_t ch)
m_rx_data = ch;
+ LOGSTAT("status RX READY test %02x\n", m_status);
/* char has not been read and another has arrived! */
if (m_status & I8251_STATUS_RX_READY)
+ {
m_status |= I8251_STATUS_OVERRUN_ERROR;
+ LOGSTAT("status overrun set\n");
+ }
+ LOGSTAT("status pre RX READY set %02x\n", m_status);
m_status |= I8251_STATUS_RX_READY;
+ LOGSTAT("status post RX READY set %02x\n", m_status);
update_rx_ready();
}
@@ -810,6 +792,7 @@ uint8_t i8251_device::data_r()
if (!machine().side_effects_disabled())
{
m_status &= ~I8251_STATUS_RX_READY;
+ LOGSTAT("status RX_READY cleared\n");
update_rx_ready();
}
return m_rx_data;
@@ -836,7 +819,8 @@ void i8251_device::write(offs_t offset, uint8_t data)
WRITE_LINE_MEMBER(i8251_device::write_rxd)
{
m_rxd = state;
-// device_serial_interface::rx_w(state);
+ LOGBITS("8251: Presented a %d\n", m_rxd);
+ // device_serial_interface::rx_w(state);
}
WRITE_LINE_MEMBER(i8251_device::write_cts)
diff --git a/src/devices/machine/pit8253.cpp b/src/devices/machine/pit8253.cpp
index 28173bad237..ddf63ff00fb 100644
--- a/src/devices/machine/pit8253.cpp
+++ b/src/devices/machine/pit8253.cpp
@@ -30,10 +30,16 @@
***************************************************************************/
-#define VERBOSE 0
+#define LOG_1 (1U << 1)
+#define LOG_2 (1U << 2)
-#define LOG1(msg) do { if (VERBOSE >= 1) logerror msg; } while (0)
-#define LOG2(msg) do { if (VERBOSE >= 2) logerror msg; } while (0)
+//#define VERBOSE (LOG_1 | LOG_2)
+//#define LOG_OUTPUT_STREAM std::cout
+
+#include "logmacro.h"
+
+#define LOG1(...) LOGMASKED(LOG_1, __VA_ARGS__)
+#define LOG2(...) LOGMASKED(LOG_2, __VA_ARGS__)
DEFINE_DEVICE_TYPE(PIT_COUNTER, pit_counter_device, "pit_counter", "PIT Counter")
DEFINE_DEVICE_TYPE(PIT8253, pit8253_device, "pit8253", "Intel 8253 PIT")
@@ -288,7 +294,7 @@ void pit_counter_device::set_output(int output)
if (output != m_output)
{
m_output = output;
- LOG2(("set_output(): %s\n", output ? "low to high" : "high to low"));
+ LOG2("set_output() timer %d: %s\n", m_index, output ? "low to high" : "high to low");
downcast<pit8253_device *>(owner())->m_out_handler[m_index](output);
}
@@ -305,8 +311,8 @@ void pit_counter_device::simulate(int64_t elapsed_cycles)
static const uint32_t CYCLES_NEVER = (0xffffffff);
uint32_t cycles_to_output = 0;
- LOG2(("simulate(): simulating %d cycles in mode %d, bcd = %d, phase = %d, gate = %d, output %d, value = 0x%04x\n",
- (int)elapsed_cycles, mode, bcd, m_phase, m_gate, m_output, m_value));
+ LOG2("simulate(): simulating %d cycles in mode %d, bcd = %d, phase = %d, gate = %d, output %d, value = 0x%04x\n",
+ (int)elapsed_cycles, mode, bcd, m_phase, m_gate, m_output, m_value);
switch (mode)
{
@@ -688,8 +694,8 @@ void pit_counter_device::simulate(int64_t elapsed_cycles)
m_updatetimer->adjust(next_fire_time - machine().time());
}
- LOG2(("simulate(): simulating %d cycles in mode %d, bcd = %d, phase = %d, gate = %d, output %d, value = 0x%04x, cycles_to_output = %04x\n",
- (int)elapsed_cycles, mode, bcd, m_phase, m_gate, m_output, m_value, cycles_to_output));
+ LOG2("simulate(): simulating %d cycles in mode %d, bcd = %d, phase = %d, gate = %d, output %d, value = 0x%04x, cycles_to_output = %04x\n",
+ (int)elapsed_cycles, mode, bcd, m_phase, m_gate, m_output, m_value, cycles_to_output);
}
/* This brings timer "timer" up to date */
@@ -701,7 +707,7 @@ void pit_counter_device::update()
attotime elapsed_time = now - m_last_updated;
int64_t elapsed_cycles = elapsed_time.as_double() * m_clockin;
- LOG2(("update(): %d elapsed_cycles\n", elapsed_cycles));
+ LOG2("update(): %d elapsed_cycles\n", elapsed_cycles);
if (m_clockin)
m_last_updated += elapsed_cycles * attotime::from_hz(m_clockin);
@@ -799,7 +805,7 @@ uint8_t pit_counter_device::read()
}
}
- LOG2(("read(): data=0x%02x\n", data));
+ LOG2("read(): data=0x%02x\n", data);
return data;
}
@@ -807,7 +813,7 @@ uint8_t pit8253_device::read(offs_t offset)
{
offset &= 3;
- LOG2(("read(): offset %d\n", offset));
+ LOG2("read(): offset %d\n", offset);
if (offset == 3)
{
@@ -824,7 +830,7 @@ uint8_t pit8253_device::read(offs_t offset)
void pit_counter_device::load_count(uint16_t newcount)
{
int mode = CTRL_MODE(m_control);
- LOG1(("load_count(): %04x\n", newcount));
+ LOG1("load_count(): %04x\n", newcount);
if (newcount == 1)
{
@@ -910,7 +916,7 @@ void pit8253_device::readback_command(uint8_t data)
void pit8254_device::readback_command(uint8_t data)
{
- LOG1(("write(): readback %02x\n", data & 0x3f));
+ LOG1("write(): readback %02x\n", data & 0x3f);
/* Bit 0 of data must be 0. Todo: find out what the hardware does if it isn't. */
int read_command = (data >> 4) & 3;
@@ -930,7 +936,7 @@ void pit_counter_device::control_w(uint8_t data)
if (CTRL_ACCESS(data) == 0)
{
- LOG1(("write(): readback\n"));
+ LOG1("write(): readback\n");
/* Latch current timer value */
/* Experimentally verified: this command does not affect the mode control register */
@@ -938,7 +944,7 @@ void pit_counter_device::control_w(uint8_t data)
}
else
{
- LOG1(("write(): bytes=%d mode=%d bcd=%d\n", (data >> 4) & 3, (data >> 1) & 7, data & 1));
+ LOG1("write(): bytes=%d mode=%d bcd=%d\n", (data >> 4) & 3, (data >> 1) & 7, data & 1);
m_control = (data & 0x3f);
m_null_count = 1;
@@ -1021,7 +1027,7 @@ void pit8253_device::write(offs_t offset, uint8_t data)
{
offset &= 3;
- LOG2(("write(): offset=%d data=0x%02x\n", offset, data));
+ LOG2("write(): offset=%d data=0x%02x\n", offset, data);
if (offset == 3)
{
@@ -1038,7 +1044,7 @@ void pit8253_device::write(offs_t offset, uint8_t data)
void pit_counter_device::gate_w(int state)
{
- LOG2(("gate_w(): state=%d\n", state));
+ LOG2("gate_w(): state=%d\n", state);
if (state != m_gate)
{
@@ -1059,7 +1065,7 @@ void pit_counter_device::gate_w(int state)
void pit_counter_device::set_clockin(double new_clockin)
{
- LOG2(("set_clockin(): clockin = %f\n", new_clockin));
+ LOG2("set_clockin(): clockin = %f\n", new_clockin);
update();
m_clockin = new_clockin;
@@ -1069,7 +1075,7 @@ void pit_counter_device::set_clockin(double new_clockin)
void pit_counter_device::set_clock_signal(int state)
{
- LOG2(("set_clock_signal(): state = %d\n", state));
+ LOG2("set_clock_signal(): state = %d\n", state);
/* Trigger on low to high transition */
if (!m_clock_signal && state)
diff --git a/src/devices/video/mc6845.cpp b/src/devices/video/mc6845.cpp
index 1c0862f1564..4ce9ed843a3 100644
--- a/src/devices/video/mc6845.cpp
+++ b/src/devices/video/mc6845.cpp
@@ -45,12 +45,18 @@
#include "screen.h"
-#define LOG_REGS (1 << 0U)
-#define LOG_CONFIG (1 << 1U)
-#define VERBOSE (0)
+#define LOG_SETUP (1 << 1U)
+#define LOG_REGS (1 << 2U)
+#define LOG_CONF (1 << 3U)
+
+//#define VERBOSE (LOG_SETUP|LOG_CONF|LOG_REGS)
+//#define LOG_OUTPUT_STREAM std::cout
#include "logmacro.h"
+#define LOGSETUP(...) LOGMASKED(LOG_SETUP, __VA_ARGS__)
+#define LOGREGS(...) LOGMASKED(LOG_REGS, __VA_ARGS__)
+#define LOGCONF(...) LOGMASKED(LOG_CONF, __VA_ARGS__)
DEFINE_DEVICE_TYPE(MC6845, mc6845_device, "mc6845", "Motorola MC6845 CRTC")
DEFINE_DEVICE_TYPE(MC6845_1, mc6845_1_device, "mc6845_1", "Motorola MC6845-1 CRTC")
@@ -213,7 +219,19 @@ uint8_t mc6845_device::register_r()
void mc6845_device::register_w(uint8_t data)
{
- LOGMASKED(LOG_REGS, "%s:M6845 reg 0x%02x = 0x%02x\n", machine().describe_context(), m_register_address_latch, data);
+ LOGREGS("%s:M6845 reg 0x%02x = 0x%02x\n", machine().describe_context(), m_register_address_latch, data);
+
+ /* Omits LOGSETUP logs of cursor registers as they tend to be spammy */
+ if (m_register_address_latch < 0x0e &&
+ m_register_address_latch != 0x0a &&
+ m_register_address_latch != 0x0b) LOGSETUP(" * %02x <= %3u [%02x] %s\n", m_register_address_latch,
+ data, data, std::array<char const *, 16>
+ {{ "R0 - Horizontal Total", "R1 - Horizontal Displayed", "R2 - Horizontal Sync Position",
+ "R3 - Sync Width", "R4 - Vertical Total", "R5 - Vertical Total Adjust",
+ "R6 - Vertical Displayed", "R7 - Vertical Sync Position", "R8 - Interlace & Skew",
+ "R9 - Maximum Raster Address", "R10 - Cursor Start Address", "R11 - Cursor End Address",
+ "R12 - Start Address (H)", "R13 - Start Address (L)", "R14 - Cursor (H)",
+ "R15 - Cursor (L)" }}[(m_register_address_latch & 0x0f)]);
switch (m_register_address_latch)
{
@@ -342,7 +360,7 @@ uint8_t mos8563_device::register_r()
void mos8563_device::register_w(uint8_t data)
{
- LOGMASKED(LOG_REGS, "%s:MOS8563 reg 0x%02x = 0x%02x\n", machine().describe_context(), m_register_address_latch, data);
+ LOGREGS("%s:MOS8563 reg 0x%02x = 0x%02x\n", machine().describe_context(), m_register_address_latch, data);
switch (m_register_address_latch)
{
@@ -429,7 +447,7 @@ uint8_t hd6345_device::register_r()
void hd6345_device::register_w(uint8_t data)
{
- LOGMASKED(LOG_REGS, "%s:HD6345 reg 0x%02x = 0x%02x\n", machine().describe_context(), m_register_address_latch, data);
+ LOGREGS("%s:HD6345 reg 0x%02x = 0x%02x\n", machine().describe_context(), m_register_address_latch, data);
switch (m_register_address_latch)
{
@@ -571,8 +589,8 @@ void mc6845_device::recompute_parameters(bool postload)
else
visarea.set(0 + m_visarea_adjust_min_x, max_visible_x + m_visarea_adjust_max_x, 0 + m_visarea_adjust_min_y, max_visible_y + m_visarea_adjust_max_y);
- LOGMASKED(LOG_CONFIG, "M6845 config screen: HTOTAL: %d VTOTAL: %d MAX_X: %d MAX_Y: %d HSYNC: %d-%d VSYNC: %d-%d Freq: %ffps\n",
- horiz_pix_total, vert_pix_total, max_visible_x, max_visible_y, hsync_on_pos, hsync_off_pos - 1, vsync_on_pos, vsync_off_pos - 1, refresh.as_hz());
+ LOGCONF("M6845 config screen: HTOTAL: %d VTOTAL: %d MAX_X: %d MAX_Y: %d HSYNC: %d-%d VSYNC: %d-%d Freq: %ffps\n",
+ horiz_pix_total, vert_pix_total, max_visible_x, max_visible_y, hsync_on_pos, hsync_off_pos - 1, vsync_on_pos, vsync_off_pos - 1, refresh.as_hz());
if (has_screen())
screen().configure(horiz_pix_total, vert_pix_total, visarea, refresh.as_attoseconds());
@@ -1073,6 +1091,12 @@ uint32_t mc6845_device::screen_update(screen_device &screen, bitmap_rgb32 &bitma
{
assert(!m_update_row_cb.isnull());
+ if (m_display_disabled_msg_shown == true)
+ {
+ logerror("M6845: Valid screen parameters - display reenabled!!!\n");
+ m_display_disabled_msg_shown = false;
+ }
+
/* call the set up function if any */
if (!m_begin_update_cb.isnull())
m_begin_update_cb(bitmap, cliprect);
@@ -1095,7 +1119,11 @@ uint32_t mc6845_device::screen_update(screen_device &screen, bitmap_rgb32 &bitma
}
else
{
- LOGMASKED(LOG_CONFIG, "M6845: Invalid screen parameters - display disabled!!!\n");
+ if (m_display_disabled_msg_shown == false)
+ {
+ logerror("M6845: Invalid screen parameters - display disabled!!!\n");
+ m_display_disabled_msg_shown = true;
+ }
}
return 0;
@@ -1143,6 +1171,7 @@ void mc6845_device::device_start()
m_supports_status_reg_d7 = false;
m_supports_transparent = false;
m_has_valid_parameters = false;
+ m_display_disabled_msg_shown = false;
m_line_enable_ff = false;
m_vsync_ff = 0;
m_raster_counter = 0;
diff --git a/src/devices/video/mc6845.h b/src/devices/video/mc6845.h
index d124dc6fde6..f20b83e5eff 100644
--- a/src/devices/video/mc6845.h
+++ b/src/devices/video/mc6845.h
@@ -219,6 +219,7 @@ protected:
uint16_t m_vsync_on_pos;
uint16_t m_vsync_off_pos;
bool m_has_valid_parameters;
+ bool m_display_disabled_msg_shown;
uint16_t m_current_disp_addr; /* the display address currently drawn (used only in mc6845_update) */
diff --git a/src/emu/xtal.cpp b/src/emu/xtal.cpp
index 36acebccb34..e46994b2061 100644
--- a/src/emu/xtal.cpp
+++ b/src/emu/xtal.cpp
@@ -260,6 +260,7 @@ const double XTAL::known_xtals[] = {
18'720'000, /* 18.72_MHz_XTAL Nokia MikroMikko 1 */
18'867'000, /* 18.867_MHz_XTAL Decision Data IS-482 */
18'869'600, /* 18.8696_MHz_XTAL Memorex 2178 */
+ 19'170'000, /* Ericsson ISA8 Monochrome HR Graphics Board */
19'339'600, /* 19.3396_MHz_XTAL TeleVideo TVI-955 80-column display clock */
19'584'000, /* 19.584_MHz_XTAL ADM-42 */
19'600'000, /* 19.6_MHz_XTAL Universal Mr. Do - Model 8021 PCB */
diff --git a/src/mame/drivers/eispc.cpp b/src/mame/drivers/eispc.cpp
new file mode 100644
index 00000000000..f0d593f5cd6
--- /dev/null
+++ b/src/mame/drivers/eispc.cpp
@@ -0,0 +1,959 @@
+// license:BSD-3-Clause
+// copyright-holders:Joakim Larsson Edström
+/***************************************************************************************************
+ *
+ * Ericsson Information Systems PC "compatibles"
+ *
+ * The Ericsson PC was the the first original Ericsson design for the office PC market replacing the
+ * Step/One which was an OEM:ed clone of the Matsushita Mybrain 3000 (see myb3k.cpp driver).
+ *
+ **************************************************************
+ * Ericsson PC
+ *------------
+ * Links: https://youtu.be/6uilOdMJc24
+ * Form Factor: Desktop
+ * CPU: 8088 @ 4.77MHz
+ * RAM: 256K
+ * Bus: 6x ISA
+ * Video: Monchrome or Color 80x25 character mode. 320x200 and 640x400 grahics modes
+ * Display: Orange Gas Plasma (GP) display
+ * Mass storage: 2 x 5.25" 360K or 1 20Mb HDD
+ * On board ports: Beeper,
+ * Ports: serial, parallel
+ * Internal Options: Up to 640K RAM through add-on RAM card
+ * Misc: The hardware was not 100% PC compatible so non BIOS based software would not run. 50.000+ units sold
+ *
+ * TODO:
+ * - Add keyboard, first HLE as in pc.cpp and then LLE when the keyboard controller is dumped
+ * - Add the on-board FDC and boot DOS 1.xx
+ * - Complete the Ericsson 1070 MDA ISA board and test all the graphics modes inclusing 640x400 (aka HR)
+ * - Add the Ericsson 1065 HDC and boot from a hard drive
+ *
+ * Credits: The driver code is inspired from m24.cpp, myb3k.cpp and genpc.cpp. Information about the EPC has
+ * been contributed by many, mainly the people at Dalby Computer museum http://www.datormuseum.se/
+ * A dead pcb was donated by rfka01 and rom dumps by ZnaxQue@sweclockers.com
+ *
+ ************************************************************************************************************/
+/*
+ Links:
+ ------
+
+ */
+
+#include "emu.h"
+
+#include "machine/eispc_kb.h"
+
+// Devices
+#include "cpu/i86/i86.h"
+#include "machine/am9517a.h"
+#include "machine/i8251.h"
+#include "machine/i8255.h"
+#include "machine/pit8253.h"
+#include "machine/pic8259.h"
+#include "machine/upd765.h"
+#include "machine/ins8250.h"
+
+// Expansion cards
+//#include "bus/isa/isa.h"
+//#include "bus/isa/isa_cards.h"
+#include "bus/isa/ega.h"
+#include "bus/isa/mda.h"
+#include "machine/pc_lpt.h"
+
+#include "machine/ram.h"
+#include "machine/timer.h"
+#include "sound/spkrdev.h"
+#include "speaker.h"
+#include "imagedev/floppy.h"
+#include "formats/imd_dsk.h"
+#include "formats/pc_dsk.h"
+#include "bus/rs232/rs232.h"
+
+#define LOG_PPI (1U << 1)
+#define LOG_PIT (1U << 2)
+#define LOG_PIC (1U << 3)
+#define LOG_KBD (1U << 4)
+#define LOG_DMA (1U << 5)
+#define LOG_IRQ (1U << 6)
+#define LOG_FDC (1U << 7)
+#define LOG_LPT (1U << 8)
+#define LOG_NMI (1U << 9)
+#define LOG_BITS (1U << 10)
+
+//#define VERBOSE (LOG_BITS|LOG_KBD|LOG_IRQ)
+//#define LOG_OUTPUT_STREAM std::cout
+
+#include "logmacro.h"
+
+#define LOGPPI(...) LOGMASKED(LOG_PPI, __VA_ARGS__)
+#define LOGPIT(...) LOGMASKED(LOG_PIT, __VA_ARGS__)
+#define LOGPIC(...) LOGMASKED(LOG_PIC, __VA_ARGS__)
+#define LOGKBD(...) LOGMASKED(LOG_KBD, __VA_ARGS__)
+#define LOGDMA(...) LOGMASKED(LOG_DMA, __VA_ARGS__)
+#define LOGIRQ(...) LOGMASKED(LOG_IRQ, __VA_ARGS__)
+#define LOGFDC(...) LOGMASKED(LOG_FDC, __VA_ARGS__)
+#define LOGLPT(...) LOGMASKED(LOG_LPT, __VA_ARGS__)
+#define LOGNMI(...) LOGMASKED(LOG_NMI, __VA_ARGS__)
+#define LOGBITS(...) LOGMASKED(LOG_BITS, __VA_ARGS__)
+
+class epc_state : public driver_device
+{
+public:
+ epc_state(const machine_config &mconfig, device_type type, const char *tag) :
+ driver_device(mconfig, type, tag)
+ , m_maincpu(*this, "maincpu")
+ , m_ram(*this, RAM_TAG)
+ , m_isabus(*this, "isabus")
+ , m_dma8237a(*this, "dma8237")
+ , m_ppi8255(*this, "ppi8255")
+ , m_io_dsw(*this, "DSW")
+ , m_io_j10(*this, "J10")
+ , m_lpt(*this, "lpt")
+ , m_kbd8251(*this, "kbd8251")
+ , m_keyboard(*this, "keyboard")
+ , m_pic8259(*this, "pic8259")
+ , m_pit8253(*this, "pit8253")
+ , m_speaker(*this, "speaker")
+ , m_fdc(*this, "fdc")
+ , m_floppy_connectors(*this, "fdc:%u", 0)
+ , m_uart(*this, "uart8250")
+ { }
+
+ void epc(machine_config &config);
+ void init_epc();
+
+
+protected:
+ virtual void machine_start() override;
+ virtual void machine_reset() override;
+
+private:
+ required_device<i8086_cpu_device> m_maincpu;
+ required_device<ram_device> m_ram;
+ required_device<isa8_device> m_isabus;
+
+ // DMA
+ DECLARE_WRITE_LINE_MEMBER(dma_tc_w);
+ DECLARE_WRITE_LINE_MEMBER(dreq0_ck_w);
+ DECLARE_WRITE_LINE_MEMBER( epc_dma_hrq_changed );
+ DECLARE_WRITE_LINE_MEMBER( epc_dma8237_out_eop );
+ DECLARE_READ8_MEMBER( epc_dma_read_byte );
+ DECLARE_WRITE8_MEMBER( epc_dma_write_byte );
+ template <int Channel> uint8_t epc_dma8237_io_r(offs_t offset);
+ template <int Channel> void epc_dma8237_io_w(offs_t offset, uint8_t data);
+ template <int Channel> DECLARE_WRITE_LINE_MEMBER(epc_dack_w);
+ required_device<am9517a_device> m_dma8237a;
+ uint8_t m_dma_segment[4];
+ uint8_t m_dma_active;
+ bool m_tc;
+ bool m_txd;
+ bool m_rxrdy;
+ bool m_int;
+ bool m_dreq0_ck;
+
+ // PPI
+ required_device<i8255_device> m_ppi8255;
+ DECLARE_WRITE8_MEMBER(ppi_portb_w);
+ DECLARE_READ8_MEMBER(ppi_portc_r);
+ uint8_t m_ppi_portb;
+ required_ioport m_io_dsw;
+ required_ioport m_io_j10;
+
+ // Printer port
+ optional_device<pc_lpt_device> m_lpt;
+
+ // Keyboard Controller/USART
+ required_device<i8251_device> m_kbd8251;
+ required_device<eispc_keyboard_device> m_keyboard;
+ emu_timer *m_kbdclk_timer;
+ TIMER_CALLBACK_MEMBER(rxtxclk_w);
+ int m_rxtx_clk_state;
+
+ // Interrupt Controller
+ required_device<pic8259_device> m_pic8259;
+ DECLARE_WRITE_LINE_MEMBER(int_w);
+ uint8_t m_nmi_enabled;
+ uint8_t m_8087_int = 0;
+ const uint8_t m_parer_int = 0;
+ const uint8_t m_iochck_int = 0;
+ void update_nmi();
+
+ // Timer
+ required_device<pit8253_device> m_pit8253;
+
+ // Speaker
+ DECLARE_WRITE_LINE_MEMBER(speaker_ck_w);
+ required_device<speaker_sound_device> m_speaker;
+
+ void epc_map(address_map &map);
+ void epc_io(address_map &map);
+
+ // FDC
+ void check_fdc_irq();
+ void check_fdc_drq();
+ required_device<i8272a_device> m_fdc;
+ uint8_t m_ocr;
+ bool m_irq; // System signal after glue logic
+ bool m_drq; // System signal after glue logic
+ bool m_fdc_irq; // FDC output pin
+ bool m_fdc_drq; // FDC output pin
+
+ optional_device_array<floppy_connector, 4> m_floppy_connectors;
+ DECLARE_FLOPPY_FORMATS( epc_floppy_formats );
+
+ // UART
+ required_device<ins8250_device> m_uart;
+};
+
+void epc_state::check_fdc_irq()
+{
+ bool pirq = m_irq;
+ m_irq = m_fdc_irq && (m_ocr & 4) && (m_ocr & 8); // IRQ enabled and not in reset?
+ if(m_irq != pirq) // has the state changed?
+ {
+ LOGIRQ("FDC: IRQ6 request: %d\n", m_irq);
+ m_pic8259->ir6_w(m_irq);
+ }
+}
+
+void epc_state::check_fdc_drq()
+{
+ bool pdrq = m_drq;
+ m_drq = m_fdc_drq && (m_ocr & 4) && (m_ocr & 8); // DREQ enabled and not in reset?
+ if(m_drq != pdrq) // has the state changed?
+ {
+ LOGDMA("FDC: DMA channel 2 request: %d\n", m_drq);
+ m_dma8237a->dreq2_w(m_drq);
+ }
+}
+
+void epc_state::epc_map(address_map &map)
+{
+ map.unmap_value_high();
+ map(0x20000, 0x9ffff).noprw(); // Base RAM - mapped to avoid unmaped errors when BIOS is probing RAM size
+ // 0xa0000-0xaffff is reserved
+ map(0xb0000, 0xb7fff).noprw(); // Monochrome RAM - mapped to avoid unaped errors when BIOS is probing RAM size
+ map(0xb0000, 0xb7fff).noprw(); // Monochrome RAM - mapped to avoid unaped errors when BIOS is probing RAM size
+ map(0xb8000, 0xbffff).noprw(); // Color/Graphics RAM - mapped to avoid unaped errors when BIOS is probing RAM size
+ map(0xc0000, 0xeffff).noprw(); // Expansion ROM area - Hard Disk BIOS etc
+ map(0xf0000, 0xfffff).rom().region("bios", 0);
+}
+
+void epc_state::epc_io(address_map &map)
+{
+ map(0x0000, 0x000f).mirror(0x10).lrw8("dma8237_rw",
+ [this](offs_t offset) -> uint8_t
+ {
+ uint8_t data = m_dma8237a->read(offset);
+ LOGDMA("dma8237_r %04x\n", offset);
+ return data;
+ },
+ [this](offs_t offset, uint8_t data)
+ {
+ LOGDMA("dma8237_w %04x: %02x\n", offset, data);
+ m_dma8237a->write(offset, data);
+ }
+ );
+
+ map(0x0020, 0x0021).mirror(0x1e).lrw8("pic8259_rw",
+ [this](offs_t offset) -> uint8_t
+ {
+ uint8_t data = m_pic8259->read(offset);
+ LOGPIC("pic8259_r %04x: %02x\n", offset, data);
+ return data;
+ },
+ [this](offs_t offset, uint8_t data)
+ {
+ LOGPIC("pic8259_w %04x: %02x\n", offset, data);
+ m_pic8259->write(offset, data);
+ }
+ );
+
+ map(0x0040, 0x0043).mirror(0x1c).lrw8("pit8253_rw",
+ [this](offs_t offset) -> uint8_t
+ {
+ uint8_t data = m_pit8253->read(offset);
+ LOGPIT("pit8253_r %04x\n", offset);
+ return data;
+ },
+ [this](offs_t offset, uint8_t data)
+ {
+ LOGPIT("pit8253_w %04x: %02x\n", offset, data);
+ m_pit8253->write(offset, data);
+ }
+ );
+
+ map(0x0060, 0x0060).mirror(0x1c).lrw8("kbd_8251_data_rw",
+ [this]() -> uint8_t
+ {
+ uint8_t data = m_kbd8251->data_r();
+ LOGKBD("kbd8251_r %02x\n", data);
+ return data;
+ },
+ [this](offs_t offset, uint8_t data)
+ {
+ LOGKBD("kbd8251_w 0x60 %02x\n", data);
+ m_kbd8251->data_w(data);
+ }
+ );
+ // NOTE: PPI Port A is not mapped
+ map(0x0061, 0x0061).mirror(0x1c).lrw8("ppi8255_rw", // PPI Port B
+ [this](offs_t offset) -> uint8_t
+ {
+ uint8_t data = m_ppi8255->read(1);
+ LOGPPI("ppi8255_r Port B: %02x\n", data);
+ return data;
+ },
+ [this](offs_t offset, uint8_t data)
+ {
+ LOGPPI("ppi8255_w Port B: %02x\n", data);
+ m_ppi8255->write(1, data);
+ }
+ );
+
+ map(0x0062, 0x0062).mirror(0x1c).lrw8("ppi8255_rw", // PPI Port C
+ [this](offs_t offset) -> uint8_t
+ {
+ uint8_t data = m_ppi8255->read(2);
+ LOGPPI("ppi8255_r Port C: %02x\n", data);
+ return data;
+ },
+ [this](offs_t offset, uint8_t data)
+ {
+ LOGPPI("ppi8255_w Port C: %02x\n", data);
+ m_ppi8255->write(2, data);
+ }
+ );
+
+ map(0x0063, 0x0063).lrw8("ppi8255_rw", // PPI Control register
+ [this](offs_t offset) -> uint8_t
+ {
+ uint8_t data = m_ppi8255->read(3);
+ LOGPPI("ppi8255_r Control: %02x\n", data);
+ return data;
+ },
+ [this](offs_t offset, uint8_t data)
+ {
+ LOGPPI("ppi8255_w Control: %02x\n", data);
+ m_ppi8255->write(3, data);
+ }
+ );
+
+ map(0x0070, 0x0070).mirror(0x0e).lw8("i8251_data_w",
+ [this](offs_t offset, uint8_t data)
+ {
+ LOGKBD("kbd8251_w 0x70: %02x\n", data);
+ m_kbd8251->data_w(data);
+ }
+ );
+
+ map(0x0071, 0x0071).mirror(0x0e).lrw8("kbd_8251_stat_ctrl_rw",
+ [this](offs_t offset) -> uint8_t
+ {
+ uint8_t stat = m_kbd8251->status_r();
+ //LOGKBD("kbd8251_status_r %02x\n", stat);
+ return stat;
+ },
+ [this](offs_t offset, uint8_t data)
+ {
+ LOGKBD("kbd8251_control_w 0x71: %02x\n", data);
+ m_kbd8251->control_w(data);
+ }
+ );
+
+ map(0x0080, 0x0083).mirror(0xc).lw8("dma_segement_w",
+ [this](offs_t offset, uint8_t data)
+ {
+ LOGDMA("dma_segment_w %04x: %02x\n", offset, data);
+ m_dma_segment[offset] = data & 0x0f;
+ }
+ );
+
+ map(0x00a0, 0x00a1).mirror(0xe).lw8("nmi_enable_w",
+ [this](offs_t offset, uint8_t data)
+ {
+ LOGNMI("nmi_enable_w %04x: %02x\n", offset, data);
+ m_nmi_enabled = BIT(data,7);
+ update_nmi();
+ }
+ );
+
+ // FDC Output Control Register (same as PC XT DOR)
+ map(0x03f2, 0x03f3).lw8("ocr_w", // B0-B1 Drive select 0-3
+ [this](offs_t offset, uint8_t data) // B2 FDC Reset line
+ { // B3 Enable FDC DMA/IRQ
+ LOGFDC("FDC OCR: %02x\n", data);// B4-B7 Motor on for selected drive
+ uint8_t pocr = m_ocr;
+ uint8_t fid = m_ocr & 3;
+ m_ocr = data;
+ if ((m_ocr & 4) && m_floppy_connectors[fid]) // Not in reset and there is a floppy drive attached
+ {
+ floppy_image_device *floppy = m_floppy_connectors[fid]->get_device(); // try to retrieve the floppy
+ if (floppy)
+ {
+ LOGFDC(" - Motor %s for drive %d\n", (m_ocr & (0x10 << fid)) ? "ON" : "OFF", fid);
+ floppy->mon_w(!(m_ocr & (0x10 << fid)));
+ LOGFDC(" - Setting a floppy for drive %d\n", fid);
+ m_fdc->set_floppy((m_ocr & (0x10 << fid)) ? floppy : nullptr);
+ }
+ }
+ if (((pocr ^ m_ocr) & 4) && (m_ocr & 4) == 0) // If FDC reset state bit has changed to low then reset the FDC
+ m_fdc->reset();
+ check_fdc_irq();
+ check_fdc_drq();
+ }
+ );
+
+ map(0x03f4, 0x03f5).m(m_fdc, FUNC(i8272a_device::map));
+
+ map(0x03bc, 0x03be).lrw8("lpt_rw",
+ [this](address_space &space, offs_t offset, uint8_t mem_mask) -> uint8_t
+ {
+ uint8_t data = m_lpt->read(space, offset);
+ LOGLPT("LPT read offset %02x: %02x\n", offset, data);
+ return data;
+ },
+ [this](address_space &space, offs_t offset, uint8_t data)
+ {
+ LOGLPT("LPT write offset %02x: %02x\n", offset, data);
+ m_lpt->write(space, offset, data);
+ }
+ );
+
+ map(0x03f8, 0x03ff).rw(m_uart, FUNC(ins8250_device::ins8250_r), FUNC(ins8250_device::ins8250_w));
+}
+
+void epc_state::machine_start()
+{
+ m_maincpu->space(AS_PROGRAM).install_ram(0, m_ram->size() - 1, m_ram->pointer());
+
+ std::fill_n(&m_dma_segment[0], 4, 0);
+ m_dma_active = 0;
+ m_tc = false;
+ m_int = 1;
+ m_txd = false;
+ m_rxrdy = false;
+ m_dreq0_ck = true;
+ m_rxtx_clk_state = 0;
+
+ save_item(NAME(m_dma_segment));
+ save_item(NAME(m_dma_active));
+ save_item(NAME(m_tc));
+ save_item(NAME(m_int));
+ save_item(NAME(m_txd));
+ save_item(NAME(m_rxrdy));
+ save_item(NAME(m_ocr));
+ m_ocr = 0x00;
+ save_item(NAME(m_ppi_portb));
+ save_item(NAME(m_dreq0_ck));
+ save_item(NAME(m_rxtx_clk_state));
+}
+
+void epc_state::machine_reset()
+{
+ m_ppi_portb = 0;
+ m_keyboard->rst_line_w(ASSERT_LINE);
+ m_nmi_enabled = 0;
+ m_kbd8251->write_cts(0); // Held low always
+}
+
+void epc_state::init_epc()
+{
+ /* Keyboard UART Rxc/Txc is 19.2 kHz from x96 divider */
+ m_kbdclk_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(epc_state::rxtxclk_w), this));
+ m_kbdclk_timer->adjust(attotime::from_hz((XTAL(18'432'000) / 96) / 5));
+}
+
+TIMER_CALLBACK_MEMBER(epc_state::rxtxclk_w)
+{
+ m_kbd8251->write_rxc(m_rxtx_clk_state);
+ m_kbd8251->write_txc(m_rxtx_clk_state);
+ m_rxtx_clk_state ^= 0x01;
+ m_kbdclk_timer->adjust(attotime::from_hz((XTAL(18'432'000) / 96) / 5));
+}
+
+
+template <int Channel>
+uint8_t epc_state::epc_dma8237_io_r(offs_t offset)
+{
+ LOGDMA("epc_dma8237_io_r: %d\n", Channel);
+ if (Channel == 2)
+ return m_fdc->dma_r();
+ else
+ return m_isabus->dack_r(Channel);
+}
+
+template <int Channel>
+void epc_state::epc_dma8237_io_w(offs_t offset, uint8_t data)
+{
+ LOGDMA("epc_dma8237_io_w: %d - %02x\n", Channel, data);
+ if (Channel == 2)
+ m_fdc->dma_w(data);
+ else
+ m_isabus->dack_w(Channel, data);
+}
+
+template <int Channel>
+WRITE_LINE_MEMBER(epc_state::epc_dack_w)
+{
+ LOGDMA("epc_dack_w: %d - %d\n", Channel, state);
+
+ m_isabus->dack_line_w(Channel, state);
+
+ if (!state)
+ {
+ m_dma_active |= 1 << Channel;
+ if (Channel == 0)
+ m_dma8237a->dreq0_w(0);
+ if (m_tc)
+ m_isabus->eop_w(Channel, ASSERT_LINE);
+ }
+ else
+ {
+ m_dma_active &= ~(1 << Channel);
+ if (m_tc)
+ m_isabus->eop_w(Channel, CLEAR_LINE);
+ }
+}
+
+WRITE_LINE_MEMBER(epc_state::dma_tc_w)
+{
+ m_tc = (state == ASSERT_LINE);
+ for (int channel = 0; channel < 4; channel++)
+ {
+ if (BIT(m_dma_active, channel))
+ {
+ LOGDMA("dma_tc_w ch %d: %d\n", channel, state);
+ m_isabus->eop_w(channel, state);
+ }
+ }
+
+ // Special treatment for on board FDC
+ if (BIT(m_dma_active, 2))
+ {
+ m_fdc->tc_w(0);
+ }
+ else
+ {
+ m_fdc->tc_w(1);
+ }
+}
+
+WRITE_LINE_MEMBER(epc_state::dreq0_ck_w)
+{
+ if (state && !m_dreq0_ck && !BIT(m_dma_active, 0))
+ m_dma8237a->dreq0_w(1);
+
+ m_dreq0_ck = state;
+}
+
+WRITE_LINE_MEMBER(epc_state::speaker_ck_w)
+{
+ m_speaker->level_w((m_ppi_portb & 0x02) && state ? 1 : 0);
+}
+
+/**********************************************************
+ *
+ * PPI8255 interface
+ *
+ *
+ * PORT A (not used)
+ *
+ * Reads of port A is shadowed by UART8251A's read register
+ * gaining some compatibility with PC software. The UART8251
+ * communicates with the serial keyboard and extends it with
+ * write capability enabling keyboard led control as with a
+ * PC AT keyboard.
+ *
+ * PORT B (output)
+ * 0 - PB0 - - Control signal for the sound generator (short beeps)
+ * 1 - PB1 - - Control signal for the sound generator
+ * 2 - PB2 - - Unused
+ * 3 - PB3 - - Data select for the configuration switches 0=SW1-4 1=SW5-8
+ * 4 - PB4 - * - Enable ram parity check
+ * 5 - PB5 - * - Enable expansion I/O check
+ * 6 - PB6 - * - Keyboard reset
+ * 7 - PB7 - - Reset keyboard interrupt
+ *
+ * PORT C
+ * 0 - PC0 - - Dipswitch SW 1/5 PB3=0/PB3=1
+ * 1 - PC1 - - Dipswitch SW 2/6 PB3=0/PB3=1
+ * 2 - PC2 - - Dipswitch SW 3/7 PB3=0/PB3=1
+ * 3 - PC3 - - Dipswitch SW 4/8 PB3=0/PB3=1
+ * 4 - PC4 - SPK - Speaker/cassette data (spare in PC XT spec)
+ * 5 - PC5 - OUT2 - OUT2 from 8253 (ibmpcjr compatible)
+ * 6 - PC6 -
+ * 7 - PC7 -
+ *
+ * Ericsson PC SW:
+ * 1 - Not used. Must be set to OFF
+ * 2 - OFF - 8087 present
+ * ON - No 8087 present *)
+ * 3 - Not Used. Don't care but OFF *)
+ * 4 - Not Used. Must be set to ON
+ * 5+6 - Used to select display
+ * OFF OFF - Monochrome HR graphics monitor 3111 installed + 1020 color secondary monitor
+ * ON OFF - Monochrome HR graphics monitor 3111 installed + optional 1020 color main monitor *)
+ * OFF ON - Not used
+ * ON ON - Not used
+ * 7+8 - Used to select number of disk drives
+ * OFF OFF - Not used
+ * ON OFF - Not used
+ * OFF ON - two disk drives, system units 1030-1 and 1030-2
+ * ON ON - one disk drive, system units 1030-3, 1030-4, 1031-1 and 1031-2
+ *
+ * *) - Factory settings
+ *
+ **********************************************************/
+
+READ8_MEMBER( epc_state::ppi_portc_r )
+{
+ uint8_t data;
+
+ // Read 4 configurations dip switches depending on PB3
+ data = (m_io_dsw->read() >> ((m_ppi_portb & 0x08) ? 4 : 0) & 0x0f);
+
+ // TODO: verify what PC4-PC7 is used for, if anything
+
+ LOGPPI("PPI Port C read: %02x\n", data);
+
+ return data;
+}
+
+WRITE8_MEMBER( epc_state::ppi_portb_w )
+{
+ LOGPPI("PPI Port B write: %02x\n", data);
+ LOGPPI(" PB0 - Enable beeper : %d\n", (data & 0x01) ? 1 : 0);
+ LOGPPI(" PB1 - Beeper data : %d\n", (data & 0x02) ? 1 : 0);
+ LOGPPI(" PB2 - Unused : %d\n", (data & 0x04) ? 1 : 0);
+ LOGPPI(" PB3 - Port C dip switch select : %d\n", (data & 0x08) ? 1 : 0);
+ LOGPPI(" PB4 - RAM parity enable : %d\n", (data & 0x10) ? 1 : 0);
+ LOGPPI(" PB5 - ISA error checking enable : %d\n", (data & 0x20) ? 1 : 0);
+ LOGPPI(" PB6 - Reset keyboard : %d\n", (data & 0x40) ? 1 : 0);
+ LOGPPI(" PB7 - Reset keyboard interrupt : %d\n", (data & 0x80) ? 1 : 0);
+
+ uint8_t changed = m_ppi_portb ^ data;
+
+ m_ppi_portb = data;
+
+ if (changed & 0x40)
+ {
+ if (m_ppi_portb & 0x40)
+ {
+ LOGKBD("PB6 set, clearing Keyboard RESET\n");
+ m_keyboard->rst_line_w(CLEAR_LINE);
+ }
+ else
+ {
+ LOGKBD("PB6 cleared, asserting Keyboard RESET\n");
+ m_keyboard->rst_line_w(ASSERT_LINE);
+ }
+ }
+
+ if (changed & m_ppi_portb & 0x80)
+ {
+ LOGIRQ("PB7 set, clearing IRQ1 and releasing HOLD\n");
+ m_pic8259->ir1_w(CLEAR_LINE);
+ m_keyboard->hold_w(ASSERT_LINE);
+ }
+}
+
+WRITE_LINE_MEMBER(epc_state::int_w)
+{
+ if (m_int != state)
+ {
+ LOGIRQ("int_w: %d\n", state);
+ m_int = state;
+ m_maincpu->set_input_line(0, m_int);
+ }
+}
+
+static void epc_isa8_cards(device_slot_interface &device)
+{
+ device.option_add("epc_mda", ISA8_EPC_MDA);
+ device.option_add("ega", ISA8_EGA);
+ // device.option_add("epc_hdc1065", ISA8_EPC_HDC1065);
+ // device.option_add("epc_mb1080", ISA8_EPC_MB1080);
+}
+
+FLOPPY_FORMATS_MEMBER( epc_state::epc_floppy_formats )
+ FLOPPY_PC_FORMAT,
+ FLOPPY_IMD_FORMAT
+FLOPPY_FORMATS_END
+
+static void epc_sd_floppies(device_slot_interface &device)
+{
+ device.option_add("525sd", FLOPPY_525_SD);
+}
+
+void epc_state::epc(machine_config &config)
+{
+ I8088(config, m_maincpu, XTAL(14'318'181) / 3.0); // TWE crystal marked X1 verified divided through a 82874
+ m_maincpu->set_addrmap(AS_PROGRAM, &epc_state::epc_map);
+ m_maincpu->set_addrmap(AS_IO, &epc_state::epc_io);
+ m_maincpu->set_irq_acknowledge_callback("pic8259", FUNC(pic8259_device::inta_cb));
+
+ // DMA
+ AM9517A(config, m_dma8237a, XTAL(14'318'181) / 3.0); // TWE crystal marked X1 verified
+ m_dma8237a->out_hreq_callback().set(FUNC(epc_state::epc_dma_hrq_changed));
+ m_dma8237a->out_eop_callback().set(FUNC(epc_state::dma_tc_w));
+ m_dma8237a->in_memr_callback().set(FUNC(epc_state::epc_dma_read_byte));
+ m_dma8237a->out_memw_callback().set(FUNC(epc_state::epc_dma_write_byte));
+ m_dma8237a->in_ior_callback<1>().set(FUNC(epc_state::epc_dma8237_io_r<1>));
+ m_dma8237a->in_ior_callback<2>().set(FUNC(epc_state::epc_dma8237_io_r<2>));
+ m_dma8237a->in_ior_callback<3>().set(FUNC(epc_state::epc_dma8237_io_r<3>));
+ m_dma8237a->out_iow_callback<0>().set(FUNC(epc_state::epc_dma8237_io_w<0>));
+ m_dma8237a->out_iow_callback<1>().set(FUNC(epc_state::epc_dma8237_io_w<1>));
+ m_dma8237a->out_iow_callback<2>().set(FUNC(epc_state::epc_dma8237_io_w<2>));
+ m_dma8237a->out_iow_callback<3>().set(FUNC(epc_state::epc_dma8237_io_w<3>));
+ m_dma8237a->out_dack_callback<0>().set(FUNC(epc_state::epc_dack_w<0>));
+ m_dma8237a->out_dack_callback<1>().set(FUNC(epc_state::epc_dack_w<1>));
+ m_dma8237a->out_dack_callback<2>().set(FUNC(epc_state::epc_dack_w<2>));
+ m_dma8237a->out_dack_callback<3>().set(FUNC(epc_state::epc_dack_w<3>));
+
+ // TTL-level serial keyboard callback
+ EISPC_KB(config, "keyboard").txd_cb().set([this](bool state)
+ {
+ LOGBITS("KBD->EPC: %d\n", state);
+ m_kbd8251->write_rxd(state);
+ });
+
+ // Keyboard USART
+ I8251( config, m_kbd8251, XTAL(14'318'181) / 6.0 ); // TWE crystal marked X1 verified divided through a 82874
+
+ m_kbd8251->txd_handler().set([this](bool state)
+ {
+ if (m_txd != state)
+ {
+ LOGBITS("EPC->KBD: %d\n", state);
+ m_txd = state;
+ m_keyboard->rxd_w(m_txd);
+ }
+ });
+
+ m_kbd8251->rxrdy_handler().set([this](bool state)
+ {
+ m_rxrdy = state;
+ LOGKBD("KBD RxRdy: %d HOLD: %d\n", m_rxrdy ? 1 : 0, m_rxrdy ? 0 : 1);
+ m_keyboard->hold_w(!m_rxrdy);
+ if (m_rxrdy)
+ {
+ LOGIRQ("RxRdy set, asserting IRQ1\n");
+ m_pic8259->ir1_w(ASSERT_LINE); // Cleared by setting PB7
+ }
+ });
+ m_kbd8251->dtr_handler().set([this](bool state) // Controls RCLK for INS8250, either 19.2KHz or INS8250 BAUDOUT
+ {
+ LOGKBD("KBD DTR: %d\n", state ? 1 : 0); // TODO: Implement clock selection mux, need to check what state does what
+ });
+
+ // Interrupt Controller
+ PIC8259(config, m_pic8259);
+ m_pic8259->out_int_callback().set(FUNC(epc_state::int_w));
+
+ // Parallel port
+ I8255A(config, m_ppi8255);
+ m_ppi8255->out_pa_callback().set([this] (uint8_t data) { LOGPPI("PPI: write %02x to unused Port A\n", data); } ); // Port A is not used
+ m_ppi8255->out_pb_callback().set(FUNC(epc_state::ppi_portb_w));
+ m_ppi8255->in_pc_callback().set(FUNC(epc_state::ppi_portc_r));
+
+ // system board Parallel port
+ PC_LPT(config, m_lpt);
+ m_lpt->irq_handler().set([this](int state)
+ { // Jumper field J10 decides what IRQ to pull
+ if ((m_io_j10->read() & 0x03) == 0x01) { LOGIRQ("LPT IRQ2: %d\n", state); m_pic8259->ir2_w(state); }
+ if ((m_io_j10->read() & 0x0c) == 0x04) { LOGIRQ("LPT IRQ3: %d\n", state); m_pic8259->ir3_w(state); }
+ if ((m_io_j10->read() & 0x30) == 0x10) { LOGIRQ("LPT IRQ4: %d\n", state); m_pic8259->ir4_w(state); }
+ if ((m_io_j10->read() & 0xc0) == 0x40) { LOGIRQ("LPT IRQ7: %d\n", state); m_pic8259->ir7_w(state); } // Factory setting
+ });
+
+ // Timer
+ PIT8253(config, m_pit8253);
+ m_pit8253->set_clk<0>((XTAL(14'318'181) / 3.0) / 2.0 );
+ m_pit8253->set_clk<1>((XTAL(14'318'181) / 3.0) / 2.0 );
+ m_pit8253->set_clk<2>((XTAL(14'318'181) / 3.0) / 2.0 );
+ m_pit8253->out_handler<0>().set(m_pic8259, FUNC(pic8259_device::ir0_w));
+ m_pit8253->out_handler<1>().set(FUNC(epc_state::dreq0_ck_w));
+ m_pit8253->out_handler<2>().set(FUNC(epc_state::speaker_ck_w));
+
+ // Speaker
+ SPEAKER(config, "mono").front_center();
+ SPEAKER_SOUND(config, m_speaker).add_route(ALL_OUTPUTS, "mono", 1.00);
+
+ // ISA bus
+ ISA8(config, m_isabus, XTAL(14'318'181) / 3.0); // TEW crystal marked X1 verified
+ m_isabus->set_memspace(m_maincpu, AS_PROGRAM);
+ m_isabus->set_iospace(m_maincpu, AS_IO);
+ //m_isabus->irq2_callback().set(m_pic8259, FUNC(pic8259_device::ir2_w)); // Reserved in service manual
+ m_isabus->irq3_callback().set(m_pic8259, FUNC(pic8259_device::ir3_w));
+ m_isabus->irq4_callback().set(m_pic8259, FUNC(pic8259_device::ir4_w));
+ m_isabus->irq5_callback().set(m_pic8259, FUNC(pic8259_device::ir5_w));
+ m_isabus->irq6_callback().set(m_pic8259, FUNC(pic8259_device::ir6_w));
+ m_isabus->irq7_callback().set(m_pic8259, FUNC(pic8259_device::ir7_w));
+ m_isabus->drq1_callback().set(m_dma8237a, FUNC(am9517a_device::dreq1_w));
+ m_isabus->drq2_callback().set(m_dma8237a, FUNC(am9517a_device::dreq2_w));
+ m_isabus->drq3_callback().set(m_dma8237a, FUNC(am9517a_device::dreq3_w));
+ //m_isabus->iochck_callback().set(FUNC(epc_state::chck_w)); // TODO: Check schematics
+ m_isabus->iochck_callback().set([this] (int state)
+ {
+ if (m_nmi_enabled && !state && 0)
+ {
+ LOGNMI("IOCHCK: NMI Requested\n");
+ update_nmi();
+ }
+ });
+
+ ISA8_SLOT(config, "isa1", 0, m_isabus, epc_isa8_cards, "epc_mda", false);
+ ISA8_SLOT(config, "isa2", 0, m_isabus, epc_isa8_cards, nullptr, false);
+ ISA8_SLOT(config, "isa3", 0, m_isabus, epc_isa8_cards, nullptr, false);
+ ISA8_SLOT(config, "isa4", 0, m_isabus, epc_isa8_cards, nullptr, false);
+ ISA8_SLOT(config, "isa5", 0, m_isabus, epc_isa8_cards, nullptr, false);
+ ISA8_SLOT(config, "isa6", 0, m_isabus, epc_isa8_cards, nullptr, false);
+
+ // System board has 128kB memory with parity, expansion can be achieved through the
+ // 128kB Memory Expansion Board 1090 and/or the 128kB Multifunction Board MB1080-001
+ // and/or the 384kB MB1080-002. The MB1080 DRAM might need to be dynamically added as
+ // base address and also a video memory hole is configuarable.
+ RAM(config, m_ram).set_default_size("128K").set_extra_options("256K, 384K, 512K, 640K");
+
+ // FDC
+ I8272A(config, m_fdc, XTAL(16'000'000) / 2, false); // TEW crystal marked X3 verified
+ m_fdc->intrq_wr_callback().set([this] (int state){ m_fdc_irq = state; check_fdc_irq(); });
+ m_fdc->drq_wr_callback().set([this] (int state){ m_fdc_drq = state; check_fdc_drq(); });
+ FLOPPY_CONNECTOR(config, m_floppy_connectors[0], epc_sd_floppies, "525sd", epc_floppy_formats);
+ FLOPPY_CONNECTOR(config, m_floppy_connectors[1], epc_sd_floppies, "525sd", epc_floppy_formats);
+ //SOFTWARE_LIST(config, "epc_flop_list").set_original("epc_flop");
+
+ // system board UART TODO: Implement the descrete "Baud Rate Clock" from schematics that generates clocks for the 8250
+ INS8250(config, m_uart, XTAL(18'432'000) / 10); // TEW crystal marked X2 verified. TODO: Let 8051 DTR control RCLK (see above)
+ m_uart->out_tx_callback().set("uart", FUNC(rs232_port_device::write_txd));
+ m_uart->out_dtr_callback().set("uart", FUNC(rs232_port_device::write_dtr));
+ m_uart->out_rts_callback().set("uart", FUNC(rs232_port_device::write_rts));
+ m_uart->out_int_callback().set([this](int state)
+ { // Jumper field J10 decides what IRQ to pull
+ if ((m_io_j10->read() & 0x03) == 0x02) { LOGIRQ("UART IRQ2: %d\n", state); m_pic8259->ir2_w(state); }
+ if ((m_io_j10->read() & 0x0c) == 0x08) { LOGIRQ("UART IRQ3: %d\n", state); m_pic8259->ir3_w(state); }
+ if ((m_io_j10->read() & 0x30) == 0x20) { LOGIRQ("UART IRQ4: %d\n", state); m_pic8259->ir4_w(state); } // Factory setting
+ if ((m_io_j10->read() & 0xc0) == 0x80) { LOGIRQ("UART IRQ7: %d\n", state); m_pic8259->ir7_w(state); }
+ });
+
+ rs232_port_device &rs232(RS232_PORT(config, "uart", default_rs232_devices, nullptr));
+ rs232.rxd_handler().set(m_uart, FUNC(ins8250_uart_device::rx_w));
+ rs232.dcd_handler().set(m_uart, FUNC(ins8250_uart_device::dcd_w));
+ rs232.dsr_handler().set(m_uart, FUNC(ins8250_uart_device::dsr_w));
+ rs232.ri_handler().set(m_uart, FUNC(ins8250_uart_device::ri_w));
+ rs232.cts_handler().set(m_uart, FUNC(ins8250_uart_device::cts_w));
+}
+
+void epc_state::update_nmi()
+{
+ if (m_nmi_enabled &&
+ ((m_8087_int && (m_io_dsw->read() & 0x02)) || // FPU int only if FPU is enabled by DSW2
+ (m_parer_int != 0) || // Parity error is always false as it is an emulator, at least for now
+ (m_iochck_int != 0))) // Same goes for ISA board errors
+ {
+ LOGNMI(" NMI asserted\n");
+ m_maincpu->set_input_line(INPUT_LINE_NMI, ASSERT_LINE);
+ }
+ else
+ {
+ LOGNMI(" NMI Cleared\n");
+ m_maincpu->set_input_line(INPUT_LINE_NMI, CLEAR_LINE);
+ }
+}
+
+WRITE_LINE_MEMBER( epc_state::epc_dma_hrq_changed )
+{
+ LOGDMA("epc_dma_hrq_changed %d\n", state);
+
+ m_maincpu->set_input_line(INPUT_LINE_HALT, state ? ASSERT_LINE : CLEAR_LINE);
+
+ /* Assert HLDA */
+ m_dma8237a->hack_w(state);
+}
+
+
+READ8_MEMBER( epc_state::epc_dma_read_byte )
+{
+ if ((m_dma_active & 0x0f) == 0)
+ {
+ LOGDMA("epc_dma_read_byte failed\n");
+ return 0xff;
+ }
+
+ const int seg = (BIT(m_dma_active, 2) ? 0 : 2) | (BIT(m_dma_active, 3) ? 0 : 1);
+ return m_maincpu->space(AS_PROGRAM).read_byte(offset | u32(m_dma_segment[seg]) << 16);
+}
+
+WRITE8_MEMBER( epc_state::epc_dma_write_byte )
+{
+ if ((m_dma_active & 0x0f) == 0)
+ {
+ LOGDMA("epc_dma_write_byte failed\n");
+ return;
+ }
+
+ const int seg = (BIT(m_dma_active, 2) ? 0 : 2) | (BIT(m_dma_active, 3) ? 0 : 1);
+ m_maincpu->space(AS_PROGRAM).write_byte(offset | u32(m_dma_segment[seg]) << 16, data);
+}
+
+
+static INPUT_PORTS_START( epc_ports )
+ PORT_START("DSW")
+ PORT_DIPNAME( 0x01, 0x01, "Not used")
+ PORT_DIPSETTING( 0x00, "ON - Don't use")
+ PORT_DIPSETTING( 0x01, "OFF - Factory Setting")
+ PORT_DIPNAME( 0x02, 0x00, "8087 installed")
+ PORT_DIPSETTING( 0x00, DEF_STR(No) )
+ PORT_DIPSETTING( 0x02, DEF_STR(Yes) )
+ PORT_DIPNAME( 0x04, 0x04, "Not used")
+ PORT_DIPSETTING( 0x00, "ON - Don't care")
+ PORT_DIPSETTING( 0x04, "OFF - Factory Setting")
+ PORT_DIPNAME( 0x08, 0x00, "Not used")
+ PORT_DIPSETTING( 0x00, "ON - Factory Setting")
+ PORT_DIPSETTING( 0x08, "OFF - Don't use")
+ PORT_DIPNAME( 0x30, 0x30, "Main monitor")
+ PORT_DIPSETTING( 0x00, "Not used" )
+ PORT_DIPSETTING( 0x10, "Optional 1020 color" )
+ PORT_DIPSETTING( 0x20, "Not used" )
+ PORT_DIPSETTING( 0x30, "3111 HR Monochrome" )
+ PORT_DIPNAME( 0xc0, 0x40, "Number of floppy drives")
+ PORT_DIPSETTING( 0x00, "1" )
+ PORT_DIPSETTING( 0x40, "2" )
+ PORT_DIPSETTING( 0x80, "Not used" )
+ PORT_DIPSETTING( 0xc0, "Not used" )
+
+ PORT_START("J10") // Jumper area, field 0=no jumper 1=LPT 2=COM 3=n/a
+ PORT_DIPNAME(0x03, 0x00, "IRQ2")
+ PORT_DIPSETTING(0x00, "no jumper")
+ PORT_DIPSETTING(0x01, "LPT")
+ PORT_DIPSETTING(0x02, "COM")
+ PORT_DIPNAME(0x0c, 0x00, "IRQ3")
+ PORT_DIPSETTING(0x00, "no jumper")
+ PORT_DIPSETTING(0x04, "LPT")
+ PORT_DIPSETTING(0x08, "COM")
+ PORT_DIPNAME(0x30, 0x20, "IRQ4")
+ PORT_DIPSETTING(0x00, "no jumper")
+ PORT_DIPSETTING(0x10, "LPT")
+ PORT_DIPSETTING(0x20, "COM")
+ PORT_DIPNAME(0xc0, 0x40, "IRQ7")
+ PORT_DIPSETTING(0x00, "no jumper")
+ PORT_DIPSETTING(0x40, "LPT")
+ PORT_DIPSETTING(0x80, "COM")
+INPUT_PORTS_END
+
+ROM_START( epc )
+ ROM_REGION(0x10000,"bios", 0)
+ ROM_DEFAULT_BIOS("p860110")
+ ROM_SYSTEM_BIOS(0, "p840705", "P840705") // TODO: Fix "Keyboard error" for this bios
+ ROMX_LOAD("ericsson_8088.bin", 0xe000, 0x2000, CRC(3953c38d) SHA1(2bfc1f1d11d0da5664c3114994fc7aa3d6dd010d), ROM_BIOS(0))
+ ROM_SYSTEM_BIOS(1, "p860110", "P860110")
+ ROMX_LOAD("epcbios1.bin", 0xe000, 0x02000, CRC(79a83706) SHA1(33528c46a24d7f65ef5a860fbed05afcf797fc55), ROM_BIOS(1))
+ ROMX_LOAD("epcbios2.bin", 0xa000, 0x02000, CRC(3ca764ca) SHA1(02232fedef22d31a641f4b65933b9e269afce19e), ROM_BIOS(1))
+ ROMX_LOAD("epcbios3.bin", 0xc000, 0x02000, CRC(70483280) SHA1(b44b09da94d77b0269fc48f07d130b2d74c4bb8f), ROM_BIOS(1))
+ROM_END
+
+
+COMP( 1985, epc, 0, 0, epc, epc_ports, epc_state, init_epc, "Ericsson Information System", "Ericsson PC" , MACHINE_NOT_WORKING )
+//COMP( 1985, eppc, ibm5150, 0, pccga, pccga, pc_state, empty_init, "Ericsson Information System", "Ericsson Portable PC", MACHINE_NOT_WORKING )
diff --git a/src/mame/drivers/pc.cpp b/src/mame/drivers/pc.cpp
index 5402f35320a..0461f45a095 100644
--- a/src/mame/drivers/pc.cpp
+++ b/src/mame/drivers/pc.cpp
@@ -46,7 +46,6 @@ public:
void ncrpc4i(machine_config &config);
void kaypro16(machine_config &config);
void kaypropc(machine_config &config);
- void epc(machine_config &config);
void m15(machine_config &config);
void bondwell(machine_config &config);
void siemens(machine_config &config);
@@ -86,7 +85,6 @@ private:
static void cfg_single_360K(device_t *device);
static void cfg_single_720K(device_t *device);
- void epc_io(address_map &map);
void ibm5550_io(address_map &map);
void pc16_io(address_map &map);
void pc16_map(address_map &map);
@@ -533,55 +531,6 @@ ROM_START( mc1702 )
ROM_END
-/************************************************************** Ericsson PC ***
-
-Links: https://youtu.be/6uilOdMJc24
-Form Factor: Desktop
-CPU: 8088 @ 4.77MHz
-RAM: 256K
-Bus: 6x ISA
-Video: Monchrome or Color 80x25 character mode. 320x200 and 640x400 (CGA?) grahics modes
-Display: Orange Gas Plasma (GP) display
-Mass storage: 2 x 5.25" 360K or 1 20Mb HDD
-On board ports: Beeper,
-Ports: serial, parallel
-Internal Options: Up to 640K RAM through add-on RAM card
-Misc: The hardware was not 100% PC compatible so non BIOS based software would not run. 50.000+ units sold
-
-******************************************************************************/
-
-void pc_state::epc_io(address_map &map)
-{
- map.unmap_value_high();
- map(0x0000, 0x00ff).m("mb", FUNC(ibm5160_mb_device::map));
- map(0x0070, 0x0071).rw("i8251", FUNC(i8251_device::read), FUNC(i8251_device::write));
-}
-
-void pc_state::epc(machine_config &config)
-{
- pccga(config);
-
- i8088_cpu_device &maincpu(I8088(config.replace(), "maincpu", 4772720));
- maincpu.set_addrmap(AS_PROGRAM, &pc_state::pc8_map);
- maincpu.set_addrmap(AS_IO, &pc_state::epc_io);
- maincpu.set_irq_acknowledge_callback("mb:pic8259", FUNC(pic8259_device::inta_cb));
-
- subdevice<isa8_slot_device>("isa1")->set_default_option("ega");
- I8251(config, "i8251", 0); // clock?
-}
-
-ROM_START( epc )
- ROM_REGION(0x10000,"bios", 0)
- ROM_DEFAULT_BIOS("p860110")
- ROM_SYSTEM_BIOS(0, "p840705", "P840705")
- ROMX_LOAD("ericsson_8088.bin", 0xe000, 0x2000, CRC(3953c38d) SHA1(2bfc1f1d11d0da5664c3114994fc7aa3d6dd010d), ROM_BIOS(0))
- ROM_SYSTEM_BIOS(1, "p860110", "P860110")
- ROMX_LOAD("epcbios1.bin", 0xe000, 0x02000, CRC(79a83706) SHA1(33528c46a24d7f65ef5a860fbed05afcf797fc55), ROM_BIOS(1))
- ROMX_LOAD("epcbios2.bin", 0xa000, 0x02000, CRC(3ca764ca) SHA1(02232fedef22d31a641f4b65933b9e269afce19e), ROM_BIOS(1))
- ROMX_LOAD("epcbios3.bin", 0xc000, 0x02000, CRC(70483280) SHA1(b44b09da94d77b0269fc48f07d130b2d74c4bb8f), ROM_BIOS(1))
-ROM_END
-
-
/************************************************ Ericsson Portable PC - EPPC ***
Links: https://youtu.be/Qmke4L4Jls8 , https://youtu.be/yXK01gBQE6Q
@@ -1358,7 +1307,6 @@ ROM_END
// YEAR NAME PARENT COMPAT MACHINE INPUT CLASS INIT COMPANY FULLNAME FLAGS
COMP( 1984, dgone, ibm5150, 0, dgone, pccga, pc_state, empty_init, "Data General", "Data General/One" , MACHINE_NOT_WORKING )
-COMP( 1985, epc, ibm5150, 0, epc, pccga, pc_state, empty_init, "Ericsson Information System", "Ericsson PC" , MACHINE_NOT_WORKING )
COMP( 1985, eppc, ibm5150, 0, pccga, pccga, pc_state, empty_init, "Ericsson Information System", "Ericsson Portable PC", MACHINE_NOT_WORKING )
COMP( 1985, bw230, ibm5150, 0, bondwell, bondwell, pc_state, init_bondwell, "Bondwell Holding", "BW230 (PRO28 Series)", 0 )
COMP( 1992, iskr3104, ibm5150, 0, iskr3104, pccga, pc_state, empty_init, "Schetmash", "Iskra 3104", MACHINE_NOT_WORKING )
diff --git a/src/mame/machine/eispc_kb.cpp b/src/mame/machine/eispc_kb.cpp
new file mode 100644
index 00000000000..63d21058550
--- /dev/null
+++ b/src/mame/machine/eispc_kb.cpp
@@ -0,0 +1,412 @@
+// license:BSD-3-Clause
+// copyright-holders: Joakim Larsson Edström
+/**********************************************************************
+
+ Ericsson PC keyboard emulation
+
+ TTL-level bi-directional serial matrix keyboard
+
+ The mc6801 contains an internal ROM that handles scanning of the keyboard,
+ controlling the 2 or 3 LEDs and also the programming of the scan code for
+ a single programmable key.
+
+ There are two known variants of the keyboard. The first had the Ericsson
+ internal name "Sgt Pepper" where the hardware was OEMed/manufactured by
+ FACIT and had two LEDs while the second variant called "Roger Moore" had
+ three LEDs and was manufactured by Ericsson.
+
+ Both keyboard hooks up directly to the port of a 6801 MCU. There are
+ 16 column lines driven by Port 3 and Port 4 that goes low one at a time
+ during the scan process and when a key is pressed one of the six corresponding
+ row lines goes low and fed to through a 74HC04 inverter into port 1, where a
+ high bit means a key was pressed.
+
+ The connector has TX/Hold, Rx and Reset. Reset is connected directly to the
+ MCU so the host CPU can keep it in RESET until it needs the keyboard.
+ Rx is connected to the RX line of the SCI in the MCU, P23 - bit 3 of port 2.
+ Tx/Hold is bidirectional, connected to the TX line of the SCI in the MCU, P24
+ bit 4 of port 2, but can also be kept low by the host CPU to temporarily inhibit
+ the keyboard from sending more scan codes. This is sensed by P16 through a
+ 74HC04 inverter. The keyboard is specified to be able to buffer up to 20 scan codes.
+
+ The data is exchanged in both direction asynchronously at 1200 baud, 8 databits,
+ 1 start and 1 stop bit. At startup the host CPU sends a $00 (zero) byte to the
+ keyboard simultaneously with the MCU sending a $A5 to the CPU to ensure full
+ duplex operation. If the $A5 byte is not received EPC will display a "Keyboard
+ Error" message on the screen.
+
+ P17 and P20 are connected to LEDs on Caps Lock and Num Lock keys. The latter
+ keyboard variant Roger Moore also had a LED on Scroll Lock connected to P22.
+ P20, P21 and P22 are pulled high to bring the MCU into MODE 7 at RESET. NMI
+ and IRQ are pulled high and not connected to anything externally.
+
+ +--+--+--+--+--+-6x10K--o +5v
+ +-------+ | | | | | |
+ | P30|<------x--x--x--x--x--x--- COLUMNS x = 1N4448 diod towards P3/P4
+ | P31|<------x--x--x--x--x--x--- x 16 in serie with key button
+ | P32|<------x--x--x--x--x--x---
+ | P33|<------x--x--x--x--x--x--- A pressed button pulls a P1 row
+ | P34|<------x--x--x--x--x--x--- low when its P3/P4 column is
+ | P35|<------x--x--x--x--x--x--- being scanned
+ | P36|<------x--x--x--x--x--x---
+ | P37|<------x--x--x--x--x--x---
+ | P40|<------x--x--x--x--x--x---
+ | P41|<------x--x--x--x--x--x---
+ | P42|<------x--x--x--x--x--x---
+ | P43|<------x--x--x--x--x--x---
+ | P44|<------x--x--x--x--x--x---
+ | P45|<------x--x--x--x--x--x---
+ | P46|<------x--x--x--x--x--x---
+ | P47|<------x--x--x--x--x--x---
+ | | | | | | | |
+ | M6801 | | | | | | |
+ | | 6 x 74HC04 hex inverter
+ |P10-P15|<------+--+--+--+--+--+ ROWS x 6
+ +-------+
+
+ Credits
+ -------
+ The internal ROM was dumped in collaboration with Dalby Datormuseum, whom
+ also provided documentation and schematics of the keyboard
+
+ https://sites.google.com/site/dalbydatormuseum/home
+ https://github.com/MattisLind/6801reader
+
+ **********************************************************************/
+
+#include "emu.h"
+#include "eispc_kb.h"
+#include "cpu/m6800/m6801.h"
+
+//**************************************************************************
+// CONFIGURABLE LOGGING
+//**************************************************************************
+#define LOG_PORTS (1U << 1)
+#define LOG_RESET (1U << 2)
+#define LOG_BITS (1U << 3)
+#define LOG_UI (1U << 4)
+
+//#define VERBOSE (LOG_UI)
+//#define LOG_OUTPUT_STREAM std::cout
+
+#include "logmacro.h"
+
+#define LOGPORTS(...) LOGMASKED(LOG_PORTS, __VA_ARGS__)
+#define LOGRST(...) LOGMASKED(LOG_RESET, __VA_ARGS__)
+#define LOGBITS(...) LOGMASKED(LOG_BITS, __VA_ARGS__)
+#define LOGUI(...) LOGMASKED(LOG_UI, __VA_ARGS__)
+
+//**************************************************************************
+// MACROS / CONSTANTS
+//**************************************************************************
+
+#define M6801_TAG "mcu"
+
+namespace {
+
+INPUT_PORTS_START(eispc_kb)
+ PORT_START("P15")
+ PORT_BIT( 0x0001, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("KP 6") PORT_CODE(KEYCODE_6_PAD) PORT_CODE(KEYCODE_RIGHT) PORT_CHAR('6') PORT_CHAR(UCHAR_MAMEKEY(RIGHT)) // 77
+ PORT_BIT( 0x0002, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("KP +") PORT_CODE(KEYCODE_PLUS_PAD) PORT_CHAR('+') // 78
+ PORT_BIT( 0x0004, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("KP 5") PORT_CODE(KEYCODE_5_PAD) PORT_CHAR('5') // 76
+ PORT_BIT( 0x0008, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("* PRINT") PORT_CODE(KEYCODE_TILDE) PORT_CHAR('*') PORT_CHAR(UCHAR_MAMEKEY(PRTSCR)) // 55
+ PORT_BIT( 0x0010, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("R Shift") PORT_CODE(KEYCODE_RSHIFT) PORT_CHAR(UCHAR_SHIFT_1) // 54
+ PORT_BIT( 0x0020, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_MINUS) PORT_CHAR('-') PORT_CHAR('_') // 53
+ PORT_BIT( 0x0040, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME(". :") PORT_CODE(KEYCODE_STOP) PORT_CHAR('.') PORT_CHAR(':') // 52
+ PORT_BIT( 0x0080, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("F5") PORT_CODE(KEYCODE_F5) PORT_CHAR(UCHAR_MAMEKEY(F5)) // 63
+ PORT_BIT( 0x0100, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("F6") PORT_CODE(KEYCODE_F6) PORT_CHAR(UCHAR_MAMEKEY(F6)) // 64
+ PORT_BIT( 0x0200, IP_ACTIVE_LOW, IPT_UNUSED ) // no scancode is sent
+ PORT_BIT( 0x0400, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("CTRL") PORT_CODE(KEYCODE_LCONTROL) PORT_CHAR(UCHAR_MAMEKEY(LCONTROL)) // 29
+ PORT_BIT( 0x0800, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME(", ;") PORT_CODE(KEYCODE_COMMA) PORT_CHAR(',') PORT_CHAR(';') // 51
+ PORT_BIT( 0x1000, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_D) PORT_CHAR('D') PORT_CHAR('d') // 32
+ PORT_BIT( 0x2000, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_X) PORT_CHAR('X') PORT_CHAR('x') // 45
+ PORT_BIT( 0x4000, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_C) PORT_CHAR('C') PORT_CHAR('c') // 46
+ PORT_BIT( 0x8000, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_J) PORT_CHAR('J') PORT_CHAR('j') // 36
+
+ PORT_START("P14")
+ PORT_BIT( 0x0001, IP_ACTIVE_LOW, IPT_UNUSED ) // 00 - keyboard error
+ PORT_BIT( 0x0002, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("BREAK") PORT_CODE(KEYCODE_PAUSE) PORT_CHAR(UCHAR_MAMEKEY(PAUSE)) // 70
+ PORT_BIT( 0x0004, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("KP 7") PORT_CODE(KEYCODE_7_PAD) PORT_CHAR('7') PORT_CHAR(UCHAR_MAMEKEY(HOME)) // 71
+ PORT_BIT( 0x0008, IP_ACTIVE_LOW, IPT_UNUSED ) // ff - keyboard error
+ PORT_BIT( 0x0010, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_TILDE) PORT_CHAR('^') PORT_CHAR('~') PORT_CHAR(']') // 27
+ PORT_BIT( 0x0020, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_OPENBRACE) PORT_CHAR(0x00e5) PORT_CHAR(0x00c5) PORT_CHAR('[') // 26 å Å
+ PORT_BIT( 0x0040, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_P) PORT_CHAR('P') PORT_CHAR('p') // 25
+ PORT_BIT( 0x0080, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("F1") PORT_CODE(KEYCODE_F1) PORT_CHAR(UCHAR_MAMEKEY(F1)) // 59
+ PORT_BIT( 0x0100, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("F2") PORT_CODE(KEYCODE_F2) PORT_CHAR(UCHAR_MAMEKEY(F2)) // 60
+ PORT_BIT( 0x0200, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_W) PORT_CHAR('w') PORT_CHAR('W') // 17
+ PORT_BIT( 0x0400, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_E) PORT_CHAR('e') PORT_CHAR('E') // 18
+ PORT_BIT( 0x0800, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_O) PORT_CHAR('o') PORT_CHAR('O') // 24
+ PORT_BIT( 0x1000, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_R) PORT_CHAR('r') PORT_CHAR('R') // 19
+ PORT_BIT( 0x2000, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_T) PORT_CHAR('t') PORT_CHAR('T') // 20
+ PORT_BIT( 0x4000, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_Y) PORT_CHAR('y') PORT_CHAR('Y') // 21
+ PORT_BIT( 0x8000, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_I) PORT_CHAR('i') PORT_CHAR('I') // 23
+
+ PORT_START("P13")
+ PORT_BIT( 0x0001, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_NUMLOCK) PORT_CHAR(UCHAR_MAMEKEY(NUMLOCK)) // 69
+ PORT_BIT( 0x0002, IP_ACTIVE_LOW, IPT_UNUSED ) // ff - keyboard error
+ PORT_BIT( 0x0004, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("BS DEL") PORT_CODE(KEYCODE_BACKSPACE) PORT_CHAR(8) PORT_CHAR(UCHAR_MAMEKEY(DEL)) // 14
+ PORT_BIT( 0x0008, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_EQUALS) PORT_CHAR('=') PORT_CHAR('+') // 13
+ PORT_BIT( 0x0010, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_MINUS) PORT_CHAR('-') PORT_CHAR('_') // 12
+ PORT_BIT( 0x0020, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_0) PORT_CHAR('0') PORT_CHAR(')') // 11
+ PORT_BIT( 0x0040, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_9) PORT_CHAR('9') PORT_CHAR('(') // 10
+ PORT_BIT( 0x0080, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_1) PORT_CHAR('1') PORT_CHAR('!') // 02
+ PORT_BIT( 0x0100, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("ESC") PORT_CODE(KEYCODE_ESC) PORT_CHAR(UCHAR_MAMEKEY(ESC)) // 01
+ PORT_BIT( 0x0200, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_2) PORT_CHAR('2') PORT_CHAR('@') // 03
+ PORT_BIT( 0x0400, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_3) PORT_CHAR('3') PORT_CHAR('#') // 04
+ PORT_BIT( 0x0800, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_8) PORT_CHAR('8') PORT_CHAR('*') // 09
+ PORT_BIT( 0x1000, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_4) PORT_CHAR('4') PORT_CHAR('$') // 05
+ PORT_BIT( 0x2000, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_5) PORT_CHAR('5') PORT_CHAR('%') // 06
+ PORT_BIT( 0x4000, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_6) PORT_CHAR('6') PORT_CHAR('^') // 07
+ PORT_BIT( 0x8000, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_7) PORT_CHAR('7') PORT_CHAR('&') // 08
+
+ PORT_START("P12")
+ PORT_BIT( 0x0001, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("KP 9") PORT_CODE(KEYCODE_9_PAD) PORT_CHAR('9') PORT_CHAR(UCHAR_MAMEKEY(PGUP)) // 73
+ PORT_BIT( 0x0002, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("KP -") PORT_CODE(KEYCODE_MINUS_PAD) PORT_CHAR(UCHAR_MAMEKEY(MINUS_PAD)) // 74
+ PORT_BIT( 0x0004, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("KP 8") PORT_CODE(KEYCODE_8_PAD) PORT_CODE(KEYCODE_UP) PORT_CHAR('8') PORT_CHAR(UCHAR_MAMEKEY(UP)) // 72
+ PORT_BIT( 0x0008, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_TILDE) PORT_CHAR('`') PORT_CHAR('~') // 41
+ PORT_BIT( 0x0010, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_QUOTE) PORT_CHAR('\'') PORT_CHAR('"') // 40
+ PORT_BIT( 0x0020, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_COLON) PORT_CHAR(';') PORT_CHAR(':') // 39
+ PORT_BIT( 0x0040, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_L) PORT_CHAR('l') PORT_CHAR('L') // 38
+ PORT_BIT( 0x0080, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("F3") PORT_CODE(KEYCODE_F3) PORT_CHAR(UCHAR_MAMEKEY(F3)) // 61
+ PORT_BIT( 0x0100, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("F4") PORT_CODE(KEYCODE_F4) PORT_CHAR(UCHAR_MAMEKEY(F4)) // 62
+ PORT_BIT( 0x0200, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_Q) PORT_CHAR('q') PORT_CHAR('Q') // 16
+ PORT_BIT( 0x0400, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("TAB") PORT_CODE(KEYCODE_TAB) PORT_CHAR(9) // 15
+ PORT_BIT( 0x0800, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_K) PORT_CHAR('k') PORT_CHAR('K') // 37
+ PORT_BIT( 0x1000, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_F) PORT_CHAR('f') PORT_CHAR('F') // 33
+ PORT_BIT( 0x2000, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_G) PORT_CHAR('g') PORT_CHAR('G') // 34
+ PORT_BIT( 0x4000, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_H) PORT_CHAR('h') PORT_CHAR('H') // 35
+ PORT_BIT( 0x8000, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_U) PORT_CHAR('u') PORT_CHAR('U') // 22
+
+ PORT_START("P11")
+ PORT_BIT( 0x0001, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_DEL_PAD) PORT_CHAR(UCHAR_MAMEKEY(COMMA_PAD)) // 83
+ PORT_BIT( 0x0002, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("RETURN") PORT_CODE(KEYCODE_ENTER) PORT_CHAR(13) // 28
+ PORT_BIT( 0x0004, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("KP 0") PORT_CODE(KEYCODE_0_PAD) PORT_CHAR('0') PORT_CHAR(UCHAR_MAMEKEY(INSERT)) // 82
+ PORT_BIT( 0x0008, IP_ACTIVE_LOW, IPT_UNUSED ) // 89 - no key
+ PORT_BIT( 0x0010, IP_ACTIVE_LOW, IPT_UNUSED ) // 86 - no key
+ PORT_BIT( 0x0020, IP_ACTIVE_LOW, IPT_UNUSED ) // 87 - no key
+ PORT_BIT( 0x0040, IP_ACTIVE_LOW, IPT_UNUSED ) // 88 - no key
+ PORT_BIT( 0x0080, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("F9") PORT_CODE(KEYCODE_F9) PORT_CHAR(UCHAR_MAMEKEY(F9)) // 67
+ PORT_BIT( 0x0100, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("F10") PORT_CODE(KEYCODE_F10) PORT_CHAR(UCHAR_MAMEKEY(F10)) // 68
+ PORT_BIT( 0x0200, IP_ACTIVE_LOW, IPT_UNUSED ) // scan code ff - keyboard error
+ PORT_BIT( 0x0400, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_BACKSLASH) PORT_CHAR('\\') // 43
+ PORT_BIT( 0x0800, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("CAPS LOCK") PORT_CODE(KEYCODE_CAPSLOCK) PORT_CHAR(UCHAR_MAMEKEY(CAPSLOCK)) // 58
+ PORT_BIT( 0x1000, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("SHIFT LOCK") PORT_CODE(KEYCODE_LALT) // 56
+ PORT_BIT( 0x2000, IP_ACTIVE_LOW, IPT_UNUSED ) // 85 - no key
+ PORT_BIT( 0x4000, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_V) PORT_CHAR('v') PORT_CHAR('V') // 47
+ PORT_BIT( 0x8000, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_SPACE) PORT_CHAR(' ') // 57
+
+ PORT_START("P10")
+ PORT_BIT( 0x0001, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("KP 3") PORT_CODE(KEYCODE_3_PAD) PORT_CODE(KEYCODE_PGDN) // 81
+ PORT_BIT( 0x0002, IP_ACTIVE_LOW, IPT_UNUSED ) // ff - keyboard error
+ PORT_BIT( 0x0004, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("KP 2") PORT_CODE(KEYCODE_2_PAD) PORT_CODE(KEYCODE_DOWN) PORT_CHAR(UCHAR_MAMEKEY(2_PAD)) // 80
+ PORT_BIT( 0x0008, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("NEW LINE") PORT_CODE(KEYCODE_ENTER_PAD) PORT_CHAR(UCHAR_MAMEKEY(ENTER_PAD)) // 84 (programmable, default is 28)
+ PORT_BIT( 0x0010, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("KP 1") PORT_CODE(KEYCODE_1_PAD) PORT_CHAR(UCHAR_MAMEKEY(1_PAD)) // 79
+ PORT_BIT( 0x0020, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("KP 4") PORT_CODE(KEYCODE_4_PAD) PORT_CODE(KEYCODE_LEFT) PORT_CHAR('4') PORT_CHAR(UCHAR_MAMEKEY(LEFT)) // 75
+ PORT_BIT( 0x0040, IP_ACTIVE_LOW, IPT_UNUSED ) // ff - keyboard error
+ PORT_BIT( 0x0080, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("F7") PORT_CODE(KEYCODE_F7) PORT_CHAR(UCHAR_MAMEKEY(F7)) // 65
+ PORT_BIT( 0x0100, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("F8") PORT_CODE(KEYCODE_F8) PORT_CHAR(UCHAR_MAMEKEY(F8)) // 66
+ PORT_BIT( 0x0200, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_LSHIFT) PORT_CHAR(UCHAR_SHIFT_1) // 42
+ PORT_BIT( 0x0400, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_Z) PORT_CHAR('z') PORT_CHAR('Z') // 44
+ PORT_BIT( 0x0800, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_M) PORT_CHAR('m') PORT_CHAR('M') // 50
+ PORT_BIT( 0x1000, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_A) PORT_CHAR('a') PORT_CHAR('A') // 30
+ PORT_BIT( 0x2000, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_S) PORT_CHAR('s') PORT_CHAR('S') // 31
+ PORT_BIT( 0x4000, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_B) PORT_CHAR('b') PORT_CHAR('B') // 48
+ PORT_BIT( 0x8000, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_N) PORT_CHAR('n') PORT_CHAR('N') // 49
+INPUT_PORTS_END
+
+
+//-------------------------------------------------
+// ROM( eispc_kb )
+//-------------------------------------------------
+
+ROM_START( eispc_kb )
+ ROM_REGION( 0x800, M6801_TAG, 0 )
+ ROM_LOAD( "sgtpepper-1.2.bin", 0x000, 0x800, CRC(7107b841) SHA1(a939dd50622575c31fea9c7adb7a7db5403a7aca) )
+ROM_END
+
+} // anonymous namespace
+
+//**************************************************************************
+// DEVICE DEFINITIONS
+//**************************************************************************
+
+DEFINE_DEVICE_TYPE(EISPC_KB, eispc_keyboard_device, "eispc_kb", "Ericsson PC keyboard")
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+//-------------------------------------------------
+// eispc_keyboard_device - constructor
+//-------------------------------------------------
+
+eispc_keyboard_device::eispc_keyboard_device(
+ machine_config const &mconfig,
+ char const *tag,
+ device_t *owner,
+ uint32_t clock)
+ : device_t(mconfig, EISPC_KB, tag, owner, clock)
+ , m_mcu(*this, M6801_TAG)
+ , m_rows(*this, "P1%u", 0)
+ , m_txd_cb(*this)
+ , m_rxd_high(true)
+ , m_txd_high(true)
+ , m_hold(true)
+ , m_col_select(0)
+{
+}
+
+WRITE_LINE_MEMBER(eispc_keyboard_device::rxd_w)
+{
+ LOGBITS("KBD bit presented: %d\n", state);
+ m_rxd_high = CLEAR_LINE != state;
+}
+
+WRITE_LINE_MEMBER(eispc_keyboard_device::hold_w)
+{
+ m_hold = CLEAR_LINE == state;
+}
+
+WRITE_LINE_MEMBER(eispc_keyboard_device::rst_line_w)
+{
+ if (state == CLEAR_LINE)
+ {
+ m_mcu->resume(SUSPEND_REASON_RESET);
+ //m_mcu->set_input_line(INPUT_LINE_RESET, CLEAR_LINE);
+ LOGRST("KBD: Keyboard mcu reset line is cleared\n");
+ }
+ else
+ {
+ // set_input_line suspends with a true argument which causes "Keyboard error"
+ m_mcu->suspend(SUSPEND_REASON_RESET, false);
+ //m_mcu->set_input_line(INPUT_LINE_RESET, ASSERT_LINE);
+ LOGRST("KBD: Keyboard mcu reset line is asserted\n");
+ }
+
+}
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void eispc_keyboard_device::device_start()
+{
+ m_txd_cb.resolve_safe();
+
+ save_item(NAME(m_rxd_high));
+ save_item(NAME(m_txd_high));
+ save_item(NAME(m_col_select));
+
+ m_rxd_high = true;
+ m_txd_high = true;
+ m_col_select = 0;
+}
+
+
+
+//-------------------------------------------------
+// device_add_mconfig - add device configuration
+//-------------------------------------------------
+
+void eispc_keyboard_device::device_add_mconfig(machine_config &config)
+{
+ M6801(config, m_mcu, XTAL(4'915'200)); // Crystal verified from schematics and visual inspection
+ m_mcu->set_addrmap(AS_PROGRAM, &eispc_keyboard_device::eispc_kb_mem);
+
+ m_mcu->in_p1_cb().set([this]
+ {
+ uint8_t data = 0; // Indicate what keys are pressed in selected column
+
+ for (int i = 0; i < 6; i++) data |= ( (~m_rows[i]->read() & m_col_select) ? 0x20 >> i : 0 );
+
+ // Update txd bit
+ data &= 0x3f;
+ data |= ((!m_hold || !m_txd_high) ? 0 : 0x40);
+
+ if ((data & 0x3f) != 0 && data != m_p1)
+ {
+ LOGUI("Reading port 1: %02x m_col_select:%04x\n", data, m_col_select);
+ m_p1 = data;
+ }
+ return data;
+ });
+
+ m_mcu->out_p1_cb().set([this](uint8_t data)
+ {
+ LOGPORTS("Writing %02x PORT 1\n", data);
+ });
+
+ m_mcu->in_p2_cb().set([this]
+ {
+ uint8_t data = M6801_MODE_7 | (m_rxd_high ? (1 << 3) : 0);
+ LOGPORTS("Reading port 2: %02x\n", data);
+ //LOGBITS("KBD: Reading rxd_high: %02x\n", m_rxd_high);
+ return data;
+ });
+
+ m_mcu->out_p2_cb().set([this](uint8_t data)
+ {
+ LOGPORTS("Writing port 2: %02x\n", data);
+ LOGBITS("KBD: writing bit: %02x\n", BIT(data, 4));
+ });
+
+ m_mcu->out_ser_tx_cb().set([this](bool state)
+ {
+ m_txd_high = CLEAR_LINE != state;
+ LOGBITS("KBD: writing bit: %02x\n", m_txd_high);
+ m_txd_cb(state);
+ });
+
+ m_mcu->in_p3_cb().set([this]
+ {
+ LOGPORTS("Reading Port 3\n");
+ return 0x00;
+ });
+
+ m_mcu->out_p3_cb().set([this](uint8_t data)
+ {
+ m_col_select &= 0xff00;
+ m_col_select |= ~data;
+ });
+
+ m_mcu->in_p4_cb().set([this]
+ {
+ LOGPORTS("Reading Port 4\n");
+ return 0x00;
+ });
+
+ m_mcu->out_p4_cb().set([this](uint8_t data)
+ {
+ m_col_select &= 0x00ff;
+ m_col_select |= (~data << 8);
+ });
+}
+
+//-------------------------------------------------
+// input_ports - device-specific input ports
+//-------------------------------------------------
+
+ioport_constructor eispc_keyboard_device::device_input_ports() const
+{
+ return INPUT_PORTS_NAME( eispc_kb );
+}
+
+//-------------------------------------------------
+// ADDRESS_MAP( eispc_kb_mem )
+//-------------------------------------------------
+
+void eispc_keyboard_device::eispc_kb_mem(address_map &map)
+{
+ map(0x0000, 0x001f).rw(M6801_TAG, FUNC(m6801_cpu_device::m6801_io_r), FUNC(m6801_cpu_device::m6801_io_w));
+ map(0x0080, 0x00ff).ram();
+ map(0xf800, 0xffff).rom().region(M6801_TAG, 0);
+}
+
+//-------------------------------------------------
+// rom_region - device-specific ROM region
+//-------------------------------------------------
+
+const tiny_rom_entry *eispc_keyboard_device::device_rom_region() const
+{
+ return ROM_NAME( eispc_kb );
+}
diff --git a/src/mame/machine/eispc_kb.h b/src/mame/machine/eispc_kb.h
new file mode 100644
index 00000000000..eb582262f23
--- /dev/null
+++ b/src/mame/machine/eispc_kb.h
@@ -0,0 +1,43 @@
+// license:BSD-3-Clause
+// copyright-holders:Joakim Larsson Edström
+#ifndef MAME_MACHINE_EISPC_KB_H
+#define MAME_MACHINE_EISPC_KB_H
+
+#pragma once
+
+#include "cpu/m6800/m6801.h"
+
+DECLARE_DEVICE_TYPE(EISPC_KB, eispc_keyboard_device)
+
+class eispc_keyboard_device : public device_t
+{
+public:
+ auto txd_cb() { return m_txd_cb.bind(); }
+
+ eispc_keyboard_device(machine_config const &mconfig, char const *tag, device_t *owner, uint32_t clock = 0);
+
+ DECLARE_INPUT_CHANGED_MEMBER(key);
+ DECLARE_WRITE_LINE_MEMBER(rxd_w);
+ DECLARE_WRITE_LINE_MEMBER(hold_w);
+ DECLARE_WRITE_LINE_MEMBER(rst_line_w);
+
+protected:
+ virtual void device_start() override;
+ virtual void device_add_mconfig(machine_config &config) override;
+ virtual ioport_constructor device_input_ports() const override;
+ virtual tiny_rom_entry const *device_rom_region() const override;
+
+ required_device<m6801_cpu_device> m_mcu;
+ required_ioport_array<6> m_rows;
+ devcb_write_line m_txd_cb; // Callback for KBD-> EPC
+
+ bool m_rxd_high; // state of Rx input line
+ bool m_txd_high; // state of Tx output line
+ bool m_hold;
+ uint16_t m_col_select;
+ uint8_t m_p1;
+
+ void eispc_kb_mem(address_map &map);
+};
+
+#endif // MAME_MACHINE_EISPC_KB_H
diff --git a/src/mame/mame.lst b/src/mame/mame.lst
index 53d5886efa0..9cc91bdb7d6 100644
--- a/src/mame/mame.lst
+++ b/src/mame/mame.lst
@@ -12723,6 +12723,9 @@ splndrbt2 // (c) 1985 Alpha Denshi Co.
splndrbta // (c) 1985 Alpha Denshi Co.
splndrbtb // (c) 1985 Alpha Denshi Co.
+@source:eispc.cpp
+epc // 1984 Ericsson PC
+
@source:ertictac.cpp
ertictac // (c) 1992 Sisteme
ertictaca // (c) 1992 Sisteme
@@ -31678,7 +31681,6 @@ comport // Compaq Portable
dgone // 1984 Data General/One
eagle1600 //
eaglespirit // Eagle PC Spirit
-epc // 1984 Ericsson PC
eppc // 1985 Ericsson Portable PC
hyo88t // Hyosung Topstar 88T
ibm5550 //
diff --git a/src/mame/mess.flt b/src/mame/mess.flt
index ab84be3277b..4957998ab38 100644
--- a/src/mame/mess.flt
+++ b/src/mame/mess.flt
@@ -220,6 +220,7 @@ ec184x.cpp
ec65.cpp
ec7915.cpp
einstein.cpp
+eispc.cpp
elan_eu3a05.cpp
elan_eu3a14.cpp
electron.cpp