mirror of
https://github.com/holub/mame
synced 2025-10-04 08:28:39 +03:00
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:
commit
6e98146ef4
@ -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",
|
||||
|
@ -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 ];
|
||||
|
@ -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);
|
||||
|
@ -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 );
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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,7 +589,7 @@ 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",
|
||||
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())
|
||||
@ -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;
|
||||
|
@ -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) */
|
||||
|
||||
|
@ -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
959
src/mame/drivers/eispc.cpp
Normal 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 )
|
@ -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 )
|
||||
|
412
src/mame/machine/eispc_kb.cpp
Normal file
412
src/mame/machine/eispc_kb.cpp
Normal 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 );
|
||||
}
|
43
src/mame/machine/eispc_kb.h
Normal file
43
src/mame/machine/eispc_kb.h
Normal 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
|
@ -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 //
|
||||
|
@ -220,6 +220,7 @@ ec184x.cpp
|
||||
ec65.cpp
|
||||
ec7915.cpp
|
||||
einstein.cpp
|
||||
eispc.cpp
|
||||
elan_eu3a05.cpp
|
||||
elan_eu3a14.cpp
|
||||
electron.cpp
|
||||
|
Loading…
Reference in New Issue
Block a user