Merge pull request #5686 from JoakimLarsson/epc_3

Rebase and completion of split out of epc driver and addition of graphics card
This commit is contained in:
Joakim Larsson Edström 2019-10-11 21:59:27 +02:00 committed by GitHub
commit 6e98146ef4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 2232 additions and 237 deletions

View File

@ -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",

View File

@ -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 ];

View File

@ -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);

View File

@ -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 );
}

View File

@ -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

View File

@ -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)
{

View File

@ -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)

View File

@ -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)

View File

@ -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;

View File

@ -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) */

View File

@ -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 */

959
src/mame/drivers/eispc.cpp Normal file
View File

@ -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 )

View File

@ -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 )

View File

@ -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 );
}

View File

@ -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

View File

@ -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 //

View File

@ -220,6 +220,7 @@ ec184x.cpp
ec65.cpp
ec7915.cpp
einstein.cpp
eispc.cpp
elan_eu3a05.cpp
elan_eu3a14.cpp
electron.cpp