diff --git a/scripts/src/bus.lua b/scripts/src/bus.lua index df699c95229..213b7d93e76 100644 --- a/scripts/src/bus.lua +++ b/scripts/src/bus.lua @@ -715,6 +715,23 @@ if (BUSES["EP64"]~=null) then end +--------------------------------------------------- +-- +--@src/devices/bus/hp_hil/hp_hil.h,BUSES["HPHIL"] = true +--------------------------------------------------- + +if (BUSES["HPHIL"]~=null) then + files { + MAME_DIR .. "src/devices/bus/hp_hil/hp_hil.cpp", + MAME_DIR .. "src/devices/bus/hp_hil/hp_hil.h", + MAME_DIR .. "src/devices/bus/hp_hil/hil_devices.cpp", + MAME_DIR .. "src/devices/bus/hp_hil/hil_devices.h", + MAME_DIR .. "src/devices/bus/hp_hil/hlekbd.cpp", + MAME_DIR .. "src/devices/bus/hp_hil/hlekbd.h", + } +end + + --------------------------------------------------- -- --@src/devices/bus/generic/slot.h,BUSES["GENERIC"] = true diff --git a/scripts/src/formats.lua b/scripts/src/formats.lua index 5216a40332a..81ab80f32be 100644 --- a/scripts/src/formats.lua +++ b/scripts/src/formats.lua @@ -893,6 +893,18 @@ if (FORMATS["HECT_TAP"]~=null or _OPTIONS["with-tools"]) then } end +-------------------------------------------------- +-- +--@src/lib/formats/hp_ipc_dsk.h,FORMATS["HP_IPC_DSK"] = true +-------------------------------------------------- + +if (FORMATS["HP_IPC_DSK"]~=null or _OPTIONS["with-tools"]) then + files { + MAME_DIR.. "src/lib/formats/hp_ipc_dsk.cpp", + MAME_DIR.. "src/lib/formats/hp_ipc_dsk.h", + } +end + -------------------------------------------------- -- --@src/lib/formats/iq151_dsk.h,FORMATS["IQ151_DSK"] = true diff --git a/scripts/src/video.lua b/scripts/src/video.lua index 93e8fad6f6d..742a7c7c34f 100644 --- a/scripts/src/video.lua +++ b/scripts/src/video.lua @@ -364,6 +364,18 @@ if (VIDEOS["HLCD0538"]~=null) then } end +-------------------------------------------------- +-- +--@src/devices/video/hp1ll3.h,VIDEOS["HP1LL3"] = true +-------------------------------------------------- + +if (VIDEOS["HP1LL3"]~=null) then + files { + MAME_DIR .. "src/devices/video/hp1ll3.cpp", + MAME_DIR .. "src/devices/video/hp1ll3.h", + } +end + -------------------------------------------------- -- --@src/devices/video/huc6202.h,VIDEOS["HUC6202"] = true diff --git a/scripts/target/mame/mess.lua b/scripts/target/mame/mess.lua index f91d4edd87c..edcfd610c47 100644 --- a/scripts/target/mame/mess.lua +++ b/scripts/target/mame/mess.lua @@ -301,6 +301,7 @@ VIDEOS["HD61830"] = true VIDEOS["HD66421"] = true VIDEOS["HLCD0515"] = true VIDEOS["HLCD0538"] = true +VIDEOS["HP1LL3"] = true VIDEOS["HUC6202"] = true VIDEOS["HUC6260"] = true VIDEOS["HUC6261"] = true @@ -652,6 +653,7 @@ BUSES["GAMEBOY"] = true BUSES["GAMEGEAR"] = true BUSES["GBA"] = true BUSES["GENERIC"] = true +BUSES["HPHIL"] = true BUSES["IEEE488"] = true BUSES["IMI7000"] = true BUSES["INTV"] = true @@ -797,6 +799,7 @@ FORMATS["GTP_CAS"] = true FORMATS["HECTOR_MINIDISC"] = true FORMATS["HECT_DSK"] = true FORMATS["HECT_TAP"] = true +FORMATS["HP_IPC_DSK"] = true FORMATS["IQ151_DSK"] = true FORMATS["ITT3030_DSK"] = true FORMATS["JVC_DSK"] = true diff --git a/src/devices/bus/hp_hil/hil_devices.cpp b/src/devices/bus/hp_hil/hil_devices.cpp new file mode 100644 index 00000000000..c4a6988a6ae --- /dev/null +++ b/src/devices/bus/hp_hil/hil_devices.cpp @@ -0,0 +1,11 @@ +// license:BSD-3-Clause +// copyright-holders:Sergey Svishchev + +#include "emu.h" +#include "hil_devices.h" + +#include "hlekbd.h" + +SLOT_INTERFACE_START(hp_hil_devices) + SLOT_INTERFACE(STR_KBD_HP_INTEGRAL, HP_IPC_HLE_KEYBOARD) +SLOT_INTERFACE_END diff --git a/src/devices/bus/hp_hil/hil_devices.h b/src/devices/bus/hp_hil/hil_devices.h new file mode 100644 index 00000000000..90a45fd5922 --- /dev/null +++ b/src/devices/bus/hp_hil/hil_devices.h @@ -0,0 +1,25 @@ +// license:BSD-3-Clause +// copyright-holders:Sergey Svishchev +/*************************************************************************** + + HP-HIL devices + +***************************************************************************/ + +#ifndef __HP_HIL_DEVICES_H__ +#define __HP_HIL_DEVICES_H__ + + +#define STR_KBD_HP_46020A "hp_46020a" // ITF Keyboard +#define STR_KBD_HP_46021A "hp_46021a" // ITF Keyboard +#define STR_KBD_HP_46030A "hp_46030a" // Vectra Keyboard +#define STR_KBD_HP_INTEGRAL "hp_ipc_kbd" // Integral Keyboard + +#define STR_MOUSE_HP_46060A "hp_46060a" // 2-button mouse +#define STR_MOUSE_HP_46060B "hp_46060b" // 3-button mouse + + +SLOT_INTERFACE_EXTERN(hp_hil_devices); + + +#endif /* __HP_HIL_DEVICES_H__ */ diff --git a/src/devices/bus/hp_hil/hlekbd.cpp b/src/devices/bus/hp_hil/hlekbd.cpp new file mode 100644 index 00000000000..f575e9108a7 --- /dev/null +++ b/src/devices/bus/hp_hil/hlekbd.cpp @@ -0,0 +1,412 @@ +// license:BSD-3-Clause +// copyright-holders:Sergey Svishchev +#include "hlekbd.h" + +#include "machine/keyboard.ipp" + + +/*************************************************************************** + DEVICE TYPE GLOBALS +***************************************************************************/ + +device_type const HP_IPC_HLE_KEYBOARD = device_creator; + + +namespace bus { namespace hp_hil { +namespace { +/*************************************************************************** + INPUT PORT DEFINITIONS +***************************************************************************/ + + +// ID codes: A0h..BFh (HP-HIL reference, p. B-4) + (IPC Service Manual, p. 10-2) +INPUT_PORTS_START( id ) + PORT_START("COL0") + PORT_DIPNAME( 0xff, 0xb7, "Layout" ) + PORT_DIPSETTING( 0xBF, "US" ) + PORT_DIPSETTING( 0xAF, "German" ) + PORT_DIPSETTING( 0xB7, "UK" ) + PORT_DIPSETTING( 0xBB, "French" ) + PORT_DIPSETTING( 0xBD, "Katakana" ) + PORT_DIPSETTING( 0xBE, "Latin Spanish" ) + PORT_DIPSETTING( 0xA7, "Canadian English" ) + PORT_DIPSETTING( 0xAB, "Italian" ) + PORT_DIPSETTING( 0xAD, "Dutch" ) + PORT_DIPSETTING( 0xAE, "Swedish" ) + PORT_DIPSETTING( 0xB3, "European Spanish" ) + PORT_DIPSETTING( 0xB5, "Belgian (Flemish)" ) + PORT_DIPSETTING( 0xB6, "Finnish" ) + PORT_DIPSETTING( 0xB4, "Swiss German" ) + PORT_DIPSETTING( 0xBA, "Norwegian" ) + PORT_DIPSETTING( 0xBC, "Danish" ) + PORT_DIPSETTING( 0xB2, "Swiss French" ) +INPUT_PORTS_END + +INPUT_PORTS_START( basic ) + // keycodes 90..9f + PORT_START("COL1") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Menu") PORT_CODE(KEYCODE_F9) PORT_CHAR(UCHAR_MAMEKEY(F9)) + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("F4") PORT_CODE(KEYCODE_F4) PORT_CHAR(UCHAR_MAMEKEY(F4)) + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("F3") PORT_CODE(KEYCODE_F3) PORT_CHAR(UCHAR_MAMEKEY(F3)) + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("F2") PORT_CODE(KEYCODE_F2) PORT_CHAR(UCHAR_MAMEKEY(F2)) + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("F1") PORT_CODE(KEYCODE_F1) PORT_CHAR(UCHAR_MAMEKEY(F1)) + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("KP 8") PORT_CODE(KEYCODE_8_PAD) PORT_CHAR(UCHAR_MAMEKEY(8_PAD)) + PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Stop") + PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Print/Enter") + + // keycodes a0..af + PORT_START("COL2") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("User/System") PORT_CODE(KEYCODE_F10) PORT_CHAR(UCHAR_MAMEKEY(F10)) + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("F5") PORT_CODE(KEYCODE_F5) PORT_CHAR(UCHAR_MAMEKEY(F5)) + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("F6") PORT_CODE(KEYCODE_F6) PORT_CHAR(UCHAR_MAMEKEY(F6)) + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("F7") PORT_CODE(KEYCODE_F7) PORT_CHAR(UCHAR_MAMEKEY(F7)) + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("F8") PORT_CODE(KEYCODE_F8) PORT_CHAR(UCHAR_MAMEKEY(F8)) + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("KP 9") PORT_CODE(KEYCODE_9_PAD) PORT_CHAR(UCHAR_MAMEKEY(9_PAD)) + PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Clear Line") + PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Clear Display") + + // keycodes b0..bf + PORT_START("COL3") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_8) PORT_CHAR('8') PORT_CHAR('*') + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_9) PORT_CHAR('9') PORT_CHAR('(') + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_0) PORT_CHAR('0') PORT_CHAR(')') + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_EQUALS) PORT_CHAR('=') PORT_CHAR('+') + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_SLASH) PORT_CHAR('/') PORT_CHAR('?') + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Backspace") PORT_CODE(KEYCODE_BACKSPACE) PORT_CHAR(8) + PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_UNUSED ) + + // keycodes c0..cf + PORT_START("COL4") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_I) PORT_CHAR('i') PORT_CHAR('I') PORT_CHAR(0x09) PORT_CHAR(0x09) + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_O) PORT_CHAR('o') PORT_CHAR('O') PORT_CHAR(0x0f) PORT_CHAR(0x0f) + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_P) PORT_CHAR('p') PORT_CHAR('P') PORT_CHAR(0x10) PORT_CHAR(0x10) + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_OPENBRACE) PORT_CHAR('[') PORT_CHAR('{') + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_CLOSEBRACE) PORT_CHAR(']') PORT_CHAR('}') + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("< >") + PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_UNUSED ) + + // keycodes d0..df + PORT_START("COL5") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_J) PORT_CHAR('j') PORT_CHAR('J') PORT_CHAR(0x0a) PORT_CHAR(0x0a) + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_K) PORT_CHAR('k') PORT_CHAR('K') PORT_CHAR(0x0b) PORT_CHAR(0x0b) + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_L) PORT_CHAR('l') PORT_CHAR('L') PORT_CHAR(0x0c) PORT_CHAR(0x0c) + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_QUOTE) PORT_CHAR('\'') PORT_CHAR('"') + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_BACKSLASH) PORT_CHAR('\\') PORT_CHAR('|') + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Return") PORT_CODE(KEYCODE_ENTER) PORT_CHAR(13) + PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Home") PORT_CODE(KEYCODE_HOME) PORT_CHAR(UCHAR_MAMEKEY(HOME)) + PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_UNUSED ) + + // keycodes e0..ef + PORT_START("COL6") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_M) PORT_CHAR('m') PORT_CHAR('M') PORT_CHAR(0x0d) PORT_CHAR(0x0d) + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_COMMA) PORT_CHAR(',') PORT_CHAR('<') + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_STOP) PORT_CHAR('.') PORT_CHAR('>') + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_MINUS) PORT_CHAR('-') PORT_CHAR('_') + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Select") PORT_CODE(KEYCODE_PLUS_PAD) PORT_CHAR(UCHAR_MAMEKEY(PLUS_PAD)) + PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_UNUSED ) + + // keycodes f0..ff + PORT_START("COL7") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_N) PORT_CHAR('n') PORT_CHAR('N') PORT_CHAR(0x0e) PORT_CHAR(0x0e) + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Space") PORT_CODE(KEYCODE_SPACE) PORT_CHAR(' ') + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("KP .") PORT_CODE(KEYCODE_DEL_PAD) PORT_CHAR(UCHAR_MAMEKEY(DEL_PAD)) + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Left") PORT_CODE(KEYCODE_LEFT) PORT_CHAR(UCHAR_MAMEKEY(LEFT)) + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Down") PORT_CODE(KEYCODE_DOWN) PORT_CHAR(UCHAR_MAMEKEY(DOWN)) + PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Up") PORT_CODE(KEYCODE_UP) PORT_CHAR(UCHAR_MAMEKEY(UP)) + PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Right") PORT_CODE(KEYCODE_RIGHT) PORT_CHAR(UCHAR_MAMEKEY(RIGHT)) + + // keycodes 00..0f + PORT_START("COL8") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("KP 5") PORT_CODE(KEYCODE_5_PAD) PORT_CHAR(UCHAR_MAMEKEY(5_PAD)) + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Extend Char R")PORT_CODE(KEYCODE_RALT) PORT_CHAR(UCHAR_SHIFT_2) + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Extend Char L")PORT_CODE(KEYCODE_LALT) PORT_CHAR(UCHAR_SHIFT_2) + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("R Shift") PORT_CODE(KEYCODE_RSHIFT) PORT_CHAR(UCHAR_MAMEKEY(RSHIFT)) + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("L Shift") PORT_CODE(KEYCODE_LSHIFT) PORT_CHAR(UCHAR_SHIFT_1) + PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Control") PORT_CODE(KEYCODE_LCONTROL) PORT_CHAR(UCHAR_MAMEKEY(LCONTROL)) + PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Break/Reset") + + // keycodes 10..1f + PORT_START("COL9") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("KP 4") PORT_CODE(KEYCODE_4_PAD) PORT_CHAR(UCHAR_MAMEKEY(4_PAD)) + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("KP 7") PORT_CODE(KEYCODE_7_PAD) PORT_CHAR(UCHAR_MAMEKEY(7_PAD)) + PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_UNUSED ) + + // keycodes 20..2f + PORT_START("COL10") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("KP 1") PORT_CODE(KEYCODE_1_PAD) PORT_CHAR(UCHAR_MAMEKEY(1_PAD)) + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("KP 2") PORT_CODE(KEYCODE_2_PAD) PORT_CHAR(UCHAR_MAMEKEY(2_PAD)) + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("KP 0") PORT_CODE(KEYCODE_0_PAD) PORT_CHAR(UCHAR_MAMEKEY(0_PAD)) + PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_UNUSED ) + + // keycodes 30..3f + PORT_START("COL11") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_B) PORT_CHAR('b') PORT_CHAR('B') PORT_CHAR(0x02) PORT_CHAR(0x02) + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_V) PORT_CHAR('v') PORT_CHAR('V') PORT_CHAR(0x16) PORT_CHAR(0x16) + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_C) PORT_CHAR('c') PORT_CHAR('C') PORT_CHAR(0x03) PORT_CHAR(0x03) + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_X) PORT_CHAR('x') PORT_CHAR('X') PORT_CHAR(0x18) PORT_CHAR(0x18) + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_Z) PORT_CHAR('z') PORT_CHAR('Z') PORT_CHAR(0x1a) PORT_CHAR(0x1a) + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("DEL/Esc") PORT_CODE(KEYCODE_ESC) PORT_CHAR(UCHAR_MAMEKEY(ESC)) + + // keycodes 40..4f + PORT_START("COL12") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("KP 6") PORT_CODE(KEYCODE_6_PAD) PORT_CHAR(UCHAR_MAMEKEY(6_PAD)) + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("KP 3") PORT_CODE(KEYCODE_3_PAD) PORT_CHAR(UCHAR_MAMEKEY(3_PAD)) + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_UNUSED ) + + // keycodes 50..5f + PORT_START("COL13") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_H) PORT_CHAR('h') PORT_CHAR('H') PORT_CHAR(0x08) PORT_CHAR(0x08) + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_G) PORT_CHAR('g') PORT_CHAR('G') PORT_CHAR(0x07) PORT_CHAR(0x07) + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_F) PORT_CHAR('f') PORT_CHAR('F') PORT_CHAR(0x06) PORT_CHAR(0x06) + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_D) PORT_CHAR('d') PORT_CHAR('D') PORT_CHAR(0x04) PORT_CHAR(0x04) + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_S) PORT_CHAR('s') PORT_CHAR('S') PORT_CHAR(0x13) PORT_CHAR(0x13) + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_A) PORT_CHAR('a') PORT_CHAR('A') PORT_CHAR(0x01) PORT_CHAR(0x01) + PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Caps Lock") PORT_CODE(KEYCODE_CAPSLOCK) PORT_CHAR(UCHAR_MAMEKEY(CAPSLOCK)) + + // keycodes 60..6f + PORT_START("COL14") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_U) PORT_CHAR('u') PORT_CHAR('U') PORT_CHAR(0x15) PORT_CHAR(0x15) + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_Y) PORT_CHAR('y') PORT_CHAR('Y') PORT_CHAR(0x19) PORT_CHAR(0x19) + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_T) PORT_CHAR('t') PORT_CHAR('T') PORT_CHAR(0x14) PORT_CHAR(0x14) + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_R) PORT_CHAR('r') PORT_CHAR('R') PORT_CHAR(0x12) PORT_CHAR(0x12) + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_E) PORT_CHAR('e') PORT_CHAR('E') PORT_CHAR(0x05) PORT_CHAR(0x05) + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_W) PORT_CHAR('w') PORT_CHAR('W') PORT_CHAR(0x17) PORT_CHAR(0x17) + PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_Q) PORT_CHAR('q') PORT_CHAR('Q') PORT_CHAR(0x11) PORT_CHAR(0x11) + PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Tab") PORT_CODE(KEYCODE_TAB) PORT_CHAR(9) + + // keycodes 70..7f + PORT_START("COL15") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_7) PORT_CHAR('7') PORT_CHAR('&') + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_6) PORT_CHAR('6') PORT_CHAR('^') + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_5) PORT_CHAR('5') PORT_CHAR('%') + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_4) PORT_CHAR('4') PORT_CHAR('$') + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_3) PORT_CHAR('3') PORT_CHAR('#') + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_2) PORT_CHAR('2') PORT_CHAR('@') + PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_1) PORT_CHAR('1') PORT_CHAR('!') + PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_TILDE) PORT_CHAR('`') PORT_CHAR('~') +INPUT_PORTS_END + + +INPUT_PORTS_START( hle_hp_ipc_device ) + PORT_INCLUDE( basic ) + PORT_INCLUDE( id ) +INPUT_PORTS_END + + +} // anonymous namespace + + +/*************************************************************************** + BASE HLE KEYBOARD DEVICE +***************************************************************************/ + +/*-------------------------------------------------- + hle_device_base::hle_device_base + designated device constructor +--------------------------------------------------*/ + +hle_device_base::hle_device_base(machine_config const &mconfig, device_type type, char const *name, char const *tag, device_t *owner, uint32_t clock, char const *shortname, char const *source) + : device_t(mconfig, type, name, tag, owner, clock, shortname, source) + , device_hp_hil_interface(mconfig, *this) + , device_matrix_keyboard_interface(mconfig, *this, "COL1", "COL2", "COL3", "COL4", "COL5", "COL6", "COL7", "COL8", "COL9", "COL10", "COL11", "COL12", "COL13", "COL14", "COL15") +{ } + + +/*-------------------------------------------------- + hle_device_base::~hle_device_base + destructor +--------------------------------------------------*/ + +hle_device_base::~hle_device_base() +{ } + + +/*-------------------------------------------------- + hle_device_base::device_start + perform expensive initialisations, allocate + resources, register for save state +--------------------------------------------------*/ + +void hle_device_base::device_start() +{ + set_hp_hil_mlc_device(); + + m_powerup = true; + m_passthru = false; +} + + +/*-------------------------------------------------- + hle_device_base::device_reset + perform startup tasks, also used for host + requested reset +--------------------------------------------------*/ + +void hle_device_base::device_reset() +{ + m_fifo.clear(); + + // kick the base + reset_key_state(); + start_processing(attotime::from_hz(1'200)); +} + + +/*-------------------------------------------------- + hle_device_base::device_timer + handle timed events +--------------------------------------------------*/ + +void hle_device_base::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + device_matrix_keyboard_interface::device_timer(timer, id, param, ptr); +} + +void hle_device_base::hil_write(uint16_t data) +{ + int frames = 0; +// printf("rx from mlc %04X (%s %02X)\n", data, BIT(data, 11) ? "command" : "data", data & 255); + + if (BIT(data, 11)) switch (data & 255) + { + case HPHIL_IFC: + m_powerup = false; + break; + + case HPHIL_EPT: + m_passthru = true; + break; + + case HPHIL_ELB: + m_passthru = false; + break; + + case HPHIL_ACF+1: + m_device_id = data & 7; + m_device_id16 = m_device_id << 8; + m_hp_hil_mlc->hil_write((data & ~7) | ((data + 1) & 7)); + return; + break; + + case HPHIL_POL: + if (!m_fifo.empty()) + { + m_hp_hil_mlc->hil_write(m_device_id16 | 0x40); // Keycode Set 1, no coordinate data + frames = 1; + while (!m_fifo.empty()) + { + m_hp_hil_mlc->hil_write(m_device_id16 | m_fifo.dequeue()); + frames++; + } + } + m_hp_hil_mlc->hil_write(HPMLC_W1_C | m_device_id16 | HPHIL_POL | ((data + frames) & 7)); + return; + break; + + case HPHIL_DSR: + m_device_id = m_device_id16 = 0; + m_powerup = true; + break; + + case HPHIL_IDD: + m_hp_hil_mlc->hil_write(m_device_id16 | ioport("COL0")->read()); + m_hp_hil_mlc->hil_write(m_device_id16 | 0); + break; + + case HPHIL_DHR: + device_reset(); + return; + break; + + default: + logerror("command %02X unknown\n", data & 255); + break; + } + + if (!m_passthru) + m_hp_hil_mlc->hil_write(data); +// else +// m_next->hil_write(data); +} + +void hle_device_base::transmit_byte(uint8_t byte) +{ + if (!m_fifo.full()) { +// printf("queuing %02X\n", byte); + m_fifo.enqueue(byte); + } +// else +// printf("queuing fail (fifo full)\n"); +} + +/*-------------------------------------------------- + hle_device_base::key_make + handle a key being pressed +--------------------------------------------------*/ + +void hle_device_base::key_make(uint8_t row, uint8_t column) +{ + transmit_byte((((row + 1) ^ 8) << 4) + (column << 1)); +} + + +/*-------------------------------------------------- + hle_device_base::key_break + handle a key being released +--------------------------------------------------*/ + +void hle_device_base::key_break(uint8_t row, uint8_t column) +{ + transmit_byte((((row + 1) ^ 8) << 4) + (column << 1) + 1); +} + + +/*************************************************************************** + HP INTEGRAL HLE KEYBOARD DEVICE +***************************************************************************/ + +/*-------------------------------------------------- + hle_hp_ipc_device::hle_hp_ipc_device + abbreviated constructor +--------------------------------------------------*/ + +hle_hp_ipc_device::hle_hp_ipc_device(machine_config const &mconfig, char const *tag, device_t *owner, uint32_t clock) + : hle_device_base(mconfig, HP_IPC_HLE_KEYBOARD, "HP Integral Keyboard (HLE)", tag, owner, clock, "hp_ipc_hle_kbd", __FILE__) +{ } + + +/*-------------------------------------------------- + hle_hp_ipc_device::device_input_ports + get input ports for this device +--------------------------------------------------*/ + +ioport_constructor hle_hp_ipc_device::device_input_ports() const +{ + return INPUT_PORTS_NAME(hle_hp_ipc_device); +} + + +} } // namespace bus::hp_hil diff --git a/src/devices/bus/hp_hil/hlekbd.h b/src/devices/bus/hp_hil/hlekbd.h new file mode 100644 index 00000000000..5b72367f010 --- /dev/null +++ b/src/devices/bus/hp_hil/hlekbd.h @@ -0,0 +1,60 @@ +// license:BSD-3-Clause +// copyright-holders:Sergey Svishchev +#ifndef MAME_DEVICES_HP_HIL_HLEKBD_H +#define MAME_DEVICES_HP_HIL_HLEKBD_H + +#pragma once + +#include "hp_hil.h" +#include "machine/keyboard.h" + + +extern device_type const HP_IPC_HLE_KEYBOARD; + + +namespace bus { namespace hp_hil { +class hle_device_base + : public device_t + , public device_hp_hil_interface + , protected device_matrix_keyboard_interface<15U> +{ +public: + +protected: + // constructor/destructor + hle_device_base(machine_config const &mconfig, device_type type, char const *name, char const *tag, device_t *owner, uint32_t clock, char const *shortname, char const *source); + virtual ~hle_device_base() override; + + // device overrides + virtual void device_start() override; + virtual void device_reset() override; + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override; + + // device_matrix_keyboard_interface overrides + virtual void key_make(uint8_t row, uint8_t column) override; + virtual void key_break(uint8_t row, uint8_t column) override; + + // device_hp_hil_interface overrides + virtual void hil_write(uint16_t data) override; + +private: + // device_serial_interface uses 10'000 range + // device_matrix_keyboard_interface uses 20'000 range + + void transmit_byte(uint8_t byte); + + util::fifo m_fifo; +}; + + +class hle_hp_ipc_device : public hle_device_base +{ +public: + hle_hp_ipc_device(machine_config const &mconfig, char const *tag, device_t *owner, uint32_t clock); + + virtual ioport_constructor device_input_ports() const override; +}; + +} } // namespace bus::hp_hil + +#endif // MAME_DEVICES_HP_HIL_HLEKBD_H diff --git a/src/devices/bus/hp_hil/hp_hil.cpp b/src/devices/bus/hp_hil/hp_hil.cpp new file mode 100644 index 00000000000..79b57f9b8de --- /dev/null +++ b/src/devices/bus/hp_hil/hp_hil.cpp @@ -0,0 +1,282 @@ +// license:BSD-3-Clause +// copyright-holders:Sergey Svishchev +/*************************************************************************** + + HP-HIL Keyboard connector interface + +***************************************************************************/ + + +#include "emu.h" +#include "hp_hil.h" + + +#define VERBOSE_DBG 0 + +#define DBG_LOG(N,M,A) \ + do { \ + if(VERBOSE_DBG>=N) \ + { \ + if( M ) \ + logerror("%11.6f at %s: %-10s",machine().time().as_double(),machine().describe_context(),(char*)M ); \ + logerror A; \ + } \ + } while (0) + + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +const device_type HP_HIL_SLOT = device_creator; + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// hp_hil_slot_device - constructor +//------------------------------------------------- +hp_hil_slot_device::hp_hil_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : device_t(mconfig, HP_HIL_SLOT, "HP_HIL_SLOT", tag, owner, clock, "hp_hil_slot", __FILE__) + , device_slot_interface(mconfig, *this) +{ +} + + +void hp_hil_slot_device::static_set_hp_hil_slot(device_t &device, device_t *owner, const char *mlc_tag) +{ + hp_hil_slot_device &hp_hil = dynamic_cast(device); + hp_hil.m_owner = owner; + hp_hil.m_mlc_tag = mlc_tag; +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void hp_hil_slot_device::device_start() +{ + device_hp_hil_interface *dev = dynamic_cast(get_card_device()); + + if (dev) device_hp_hil_interface::static_set_hp_hil_mlc(*dev,m_owner->subdevice(m_mlc_tag)); +} + + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +const device_type HP_HIL_MLC = device_creator; + + +//------------------------------------------------- +// hp_hil_mlc_device - constructor +//------------------------------------------------- +hp_hil_mlc_device::hp_hil_mlc_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : device_t(mconfig, HP_HIL_MLC, "HP-HIL Master Link Controller", tag, owner, clock, "hp_hil", __FILE__) + , int_cb(*this) + , nmi_cb(*this) +{ +} + +void hp_hil_mlc_device::add_hp_hil_device( device_hp_hil_interface *device ) +{ + m_device_list.append(*device); +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- +void hp_hil_mlc_device::device_start() +{ + // resolve callbacks + int_cb.resolve_safe(); + nmi_cb.resolve_safe(); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- +void hp_hil_mlc_device::device_reset() +{ + // FIFO contents are not initialized at powerup or reset + + m_r2 = 0; + m_r3 = 0; // HPMLC_R3_NMI; +} + + +WRITE8_MEMBER(hp_hil_mlc_device::write) +{ + device_hp_hil_interface *entry = m_device_list.first(); + + DBG_LOG(2,"Write", ("%d <- %02x\n", offset, data)); + + switch (offset) + { + case 0: + DBG_LOG(1,"Transmit", ("%scommand 0x%02x to device %d\n", !m_loop?"loopback ":"", data, m_w1 & 7)); + if (m_loop & 2) // no devices on 2nd link loop + return; + if (m_loop == 0) + { + if (!m_fifo.full()) { + m_fifo.enqueue(data | (m_w1 << 8)); + m_r3 |= HPMLC_R3_INT; + int_cb(ASSERT_LINE); + } + return; + } + if ((m_w1 & 7) == 0) // broadcast + { + while (entry) + { + entry->hil_write(data | (m_w1 << 8)); + entry = entry->next(); + } + } else + { + while (entry) + { + if (entry->device_id() == (m_w1 & 7)) + entry->hil_write(data | (m_w1 << 8)); + entry = entry->next(); + } + } + break; + + case 1: + m_w1 = data & 0xf; + break; + + case 2: + m_w2 = data; + break; + + case 3: + m_w3 = data; + break; + + case 32: // loopback switch: bit 0 = loop0, bit 1 = loop1 + m_loop = data; + break; + } +} + +READ8_MEMBER(hp_hil_mlc_device::read) +{ + uint8_t data = 0; + + switch (offset) + { + case 0: + if (!m_fifo.empty()) + data = m_fifo.dequeue() & 255; + break; + + case 1: + if (!m_fifo.empty()) + data = m_fifo.peek() >> 8; + break; + + case 2: + data = m_r2; + m_r2 &= ~(HPMLC_R2_PERR|HPMLC_R2_FERR|HPMLC_R2_FOF); + break; + + case 3: + data = m_r3; + m_r3 &= ~(HPMLC_R3_INT|HPMLC_R3_NMI|HPMLC_R3_LERR); + int_cb(CLEAR_LINE); + break; + } + + DBG_LOG(2,"Read", ("%d == %02x\n", offset, data)); + + return data; +} + +void hp_hil_mlc_device::hil_write(uint16_t data) +{ + DBG_LOG(1,"Receive", ("%s %04X fifo %s\n", + BIT(data, 11)?"command":"data", data, m_fifo.full()?"full":(m_fifo.empty()?"empty":"ok"))); + + if (!m_fifo.full()) + { + if (!BIT(data, 11)) + { + m_fifo.enqueue(data); + } + else if (!m_fifo.empty() || !(m_w2 & HPMLC_W2_IPF)) + { + m_fifo.enqueue(data); + m_r3 |= HPMLC_R3_INT; + m_w3 &= ~HPMLC_W3_APE; + int_cb(ASSERT_LINE); + } + } + else + { + m_r2 |= HPMLC_R2_FOF; + m_r3 |= HPMLC_R3_INT; + int_cb(ASSERT_LINE); + } +} + +WRITE_LINE_MEMBER(hp_hil_mlc_device::ap_w) +{ + if (state && (m_w3 & HPMLC_W3_APE)) + { + device_hp_hil_interface *entry = m_device_list.first(); + + while (entry) + { + entry->hil_write(HPMLC_W1_C | HPHIL_POL); + entry = entry->next(); + } + } +} + + +//************************************************************************** +// DEVICE PC KBD INTERFACE +//************************************************************************** + +//------------------------------------------------- +// device_hp_hil_interface - constructor +//------------------------------------------------- + +device_hp_hil_interface::device_hp_hil_interface(const machine_config &mconfig, device_t &device) + : device_slot_card_interface(mconfig, device) + , m_hp_hil_mlc(nullptr) + , m_hp_hil_mlc_dev(nullptr) + , m_next(nullptr) +{ +} + + +//------------------------------------------------- +// ~device_hp_hil_interface - destructor +//------------------------------------------------- + +device_hp_hil_interface::~device_hp_hil_interface() +{ +} + + +void device_hp_hil_interface::static_set_hp_hil_mlc(device_t &device, device_t *mlc_device) +{ + device_hp_hil_interface &hp_hil = dynamic_cast(device); + hp_hil.m_hp_hil_mlc_dev = mlc_device; +} + + +void device_hp_hil_interface::set_hp_hil_mlc_device() +{ + m_hp_hil_mlc = dynamic_cast(m_hp_hil_mlc_dev); + m_hp_hil_mlc->add_hp_hil_device(this); +} + diff --git a/src/devices/bus/hp_hil/hp_hil.h b/src/devices/bus/hp_hil/hp_hil.h new file mode 100644 index 00000000000..ec531c6c3ff --- /dev/null +++ b/src/devices/bus/hp_hil/hp_hil.h @@ -0,0 +1,200 @@ +// license:BSD-3-Clause +// copyright-holders:Sergey Svishchev +/*************************************************************************** + + HP-HIL Keyboard connector interface + +***************************************************************************/ + +#pragma once + +#ifndef __HP_HIL_H__ +#define __HP_HIL_H__ + +#include "emu.h" + + +#define HPMLC_R1_OB 0x10 + +#define HPMLC_W1_C 0x0800 + +#define HPMLC_R2_PERR 0x01 +#define HPMLC_R2_FERR 0x02 +#define HPMLC_R2_FOF 0x04 + +#define HPMLC_W2_TEST 0x01 +#define HPMLC_W2_IPF 0x04 + +#define HPMLC_R3_INT 0x01 +#define HPMLC_R3_NMI 0x02 +#define HPMLC_R3_LERR 0x04 + +#define HPMLC_W3_APE 0x02 + +// commands +#define HPHIL_IFC 0x00 // Interface Clear +#define HPHIL_EPT 0x01 // Enter Pass-Thru Mode +#define HPHIL_ELB 0x02 // Enter Loop-Back Mode +#define HPHIL_IDD 0x03 // Identify and Describe +#define HPHIL_DSR 0x04 // Device Soft Reset +#define HPHIL_PST 0x05 // Perform Self Test +#define HPHIL_RRG 0x06 // Read Register +#define HPHIL_WRG 0x07 // Write Register +#define HPHIL_ACF 0x08 // Auto Configure [08..0f] +#define HPHIL_POL 0x10 // Poll [10..1f] +#define HPHIL_RPL 0x20 // RePoll [20..2f] +#define HPHIL_RNM 0x30 // Report Name +#define HPHIL_RST 0x31 // Report Status +#define HPHIL_EXD 0x32 // Extended Describe +#define HPHIL_RSC 0x33 // Report Security Code +#define HPHIL_DKA 0x3D // Disable Keyswitch AutoRepeat +#define HPHIL_EK1 0x3E // Enable Keyswitch AutoRepeat 30cps +#define HPHIL_EK2 0x3F // Enable Keyswitch AutoRepeat 60cps +#define HPHIL_PR1 0x40 // Prompt 1..7 [40..46] +#define HPHIL_PRM 0x47 // Prompt (General Purpose) +#define HPHIL_AK1 0x48 // Acknowledge 1..7 [40..46] +#define HPHIL_ACK 0x4F // Acknowledge (General Purpose) +#define HPHIL_RIO 0xFA // Register I/O Error +#define HPHIL_SHR 0xFB // System Hard Reset +#define HPHIL_TER 0xFC // Transmission Error +#define HPHIL_CAE 0xFD // Configuration Address Error +#define HPHIL_DHR 0xFE // Device Hard Reset + +/* + * init sequnce (p. 4-13) + * + * DHR + * IFC + * ACF + * IDD + * EXD + * EPT + * ELB + * RPL + * POL + * EPT + * ELB + * + */ + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_HP_HIL_INT_CALLBACK(_devcb) \ + devcb = &hp_hil_mlc_device::set_int_callback(*device, DEVCB_##_devcb); + +#define MCFG_HP_HIL_NMI_CALLBACK(_devcb) \ + devcb = &hp_hil_mlc_device::set_nmi_callback(*device, DEVCB_##_devcb); + +#define MCFG_HP_HIL_SLOT_ADD(_mlc_tag, _tag, _slot_intf, _def_slot) \ + MCFG_DEVICE_ADD(_tag, HP_HIL_SLOT, 0) \ + MCFG_DEVICE_SLOT_INTERFACE(_slot_intf, _def_slot, false) \ + hp_hil_slot_device::static_set_hp_hil_slot(*device, owner, _mlc_tag); + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + + +class hp_hil_slot_device : public device_t, + public device_slot_interface +{ +public: + // construction/destruction + hp_hil_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + + // device-level overrides + virtual void device_start() override; + + // inline configuration + static void static_set_hp_hil_slot(device_t &device, device_t *owner, const char *mlc_tag); + +protected: + // configuration + device_t *m_owner; + const char *m_mlc_tag; +}; + + +// device type definition +extern const device_type HP_HIL_SLOT; + + +class device_hp_hil_interface; + +class hp_hil_mlc_device : public device_t +{ +public: + // construction/destruction + hp_hil_mlc_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + ~hp_hil_mlc_device() { m_device_list.detach_all(); } + + template static devcb_base &set_int_callback(device_t &device, _Object object) { return downcast(device).int_cb.set_callback(object); } + template static devcb_base &set_nmi_callback(device_t &device, _Object object) { return downcast(device).nmi_cb.set_callback(object); } + + void add_hp_hil_device(device_hp_hil_interface *device); + + DECLARE_READ8_MEMBER(read); + DECLARE_WRITE8_MEMBER(write); + DECLARE_WRITE_LINE_MEMBER(ap_w); + + void hil_write(uint16_t data); + +protected: + // device-level overrides + virtual void device_start() override; + virtual void device_reset() override; + + simple_list m_device_list; + + util::fifo m_fifo; + uint8_t m_r2, m_r3, m_w1, m_w2, m_w3, m_loop; + +private: + devcb_write_line int_cb, nmi_cb; +}; + + +// device type definition +extern const device_type HP_HIL_MLC; + + +// ======================> device_hp_hil_interface + +class device_hp_hil_interface : public device_slot_card_interface +{ + friend class hp_hil_mlc_device; + +public: + // construction/destruction + device_hp_hil_interface(const machine_config &mconfig, device_t &device); + virtual ~device_hp_hil_interface(); + + device_hp_hil_interface *next() const { return m_next; } + + void set_hp_hil_mlc_device(); + + // inline configuration + static void static_set_hp_hil_mlc(device_t &device, device_t *mlc_device); + + virtual void hil_write(uint16_t data) { }; + int device_id() { return m_device_id; }; + + hp_hil_mlc_device *m_hp_hil_mlc; + device_t *m_hp_hil_mlc_dev; + device_hp_hil_interface *m_next; + +protected: + virtual void device_reset() { } + + hp_hil_slot_device *m_slot; + + int m_device_id; + uint16_t m_device_id16; + bool m_powerup; + bool m_passthru; +}; + + +#endif /* __HP_HIL_H__ */ diff --git a/src/devices/video/hp1ll3.cpp b/src/devices/video/hp1ll3.cpp new file mode 100644 index 00000000000..7a097e0ea5f --- /dev/null +++ b/src/devices/video/hp1ll3.cpp @@ -0,0 +1,713 @@ +// license:BSD-3-Clause +// copyright-holders:Sergey Svishchev +/* + HP 1LL3-0005 GPU emulation. + + Used by HP Integral PC, possibly other HP products. + + On IPC, memory is 4 16Kx4bit DRAM chips = 32KB total (16K words), + but firmware probes memory size and can work with 128KB memory. + Undocumented "_desktop" mode requires this. + + Capabilities: + - up to 1024x1024 px on screen + - lines + - rectangles + - area fill with user-defined pattern + - 16x16 user-defined proportional font, with automatic cursor + - 16x16 user-defined sprite for mouse cursor (not a sprite layer) + - windows with blitter (copy, fill and scroll) and clipping + + To do: + . proper cursor and mouse pointers [cursor can be offset from the pen location] + + variable width fonts [?? placed relative to current window] + + basic lines + - patterned lines + . bit blits & scroll + . meaning of WRRR bits + . meaning of CONF data [+ autoconfiguration] + - interrupt generation + - realistic timing? + - &c. +*/ + +#include "emu.h" +#include "hp1ll3.h" + +#include "screen.h" + + +//************************************************************************** +// MACROS / CONSTANTS +//************************************************************************** + +#define VERBOSE_DBG 2 /* general debug messages */ + +#define DBG_LOG(N,M,A) \ + do { \ + if(VERBOSE_DBG>=N) \ + { \ + if( M ) \ + logerror("%11.6f at %s: %-16s",machine().time().as_double(),machine().describe_context(),(char*)M ); \ + logerror A; \ + } \ + } while (0) + + +#define HPGPU_VRAM_SIZE 16384 // *4 // experiment +#define HPGPU_HORZ_TOTAL 512 +#define HPGPU_VERT_TOTAL 256 + + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +// devices +const device_type HP1LL3 = device_creator; + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// hp1ll3_device - constructor +//------------------------------------------------- + +hp1ll3_device::hp1ll3_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : device_t(mconfig, HP1LL3, "Hewlett-Package 1LL3-0005 GPU", tag, owner, clock, "hp1ll3", __FILE__) + , device_video_interface(mconfig, *this) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void hp1ll3_device::device_start() +{ + // register for state saving + save_item(NAME(m_conf)); + + machine().first_screen()->register_screen_bitmap(m_bitmap); + + m_cursor.allocate(16, 16); + m_sprite.allocate(16, 16); + + m_videoram = std::make_unique(HPGPU_VRAM_SIZE*2); // x2 size to make WRWIN/RDWIN easier +} + +void hp1ll3_device::device_reset() +{ + m_input_ptr = m_command = 0; + m_sad = m_fad = m_dad = m_org = m_rr = m_udl = 0; + m_enable_video = m_enable_cursor = m_enable_sprite = m_busy = false; +} + + +inline void hp1ll3_device::point(int x, int y, int px) +{ + uint16_t offset = m_sad; + + offset += y*(HPGPU_HORZ_TOTAL/16) + (x >> 4); + + if (px) + m_videoram[offset] |= (1 << (15-(x%16))); + else + m_videoram[offset] &= ~(1 << (15-(x%16))); +} + +// Bresenham algorithm -- from ef9365.cpp +void hp1ll3_device::line(int x1, int y1, int x2, int y2) +{ + int dx; + int dy,t; + int e; + int x,y; + int incy; + int diago,horiz; + unsigned char c1; + + c1=0; + incy=1; + + if(x2>x1) + dx = x2 - x1; + else + dx = x1 - x2; + + if(y2>y1) + dy = y2 - y1; + else + dy = y1 - y2; + + if( dy > dx ) + { + t = y2; + y2 = x2; + x2 = t; + + t = y1; + y1 = x1; + x1 = t; + + t = dx; + dx = dy; + dy = t; + + c1 = 1; + } + + if( x1 > x2 ) + { + t = y2; + y2 = y1; + y1 = t; + + t = x1; + x1 = x2; + x2 = t; + } + + horiz = dy<<1; + diago = ( dy - dx )<<1; + e = ( dy<<1 ) - dx; + + if( y1 <= y2 ) + incy = 1; + else + incy = -1; + + x = x1; + y = y1; + + if(c1) + { + do + { + point(y,x,m_udl); + + if( e > 0 ) + { + y = y + incy; + e = e + diago; + } + else + { + e = e + horiz; + } + + x++; + + } while( x <= x2 ); + } + else + { + do + { + point(x,y,m_udl); + + if( e > 0 ) + { + y = y + incy; + e = e + diago; + } + else + { + e = e + horiz; + } + + x++; + + } while( x <= x2 ); + } + + return; +} + +void hp1ll3_device::fill(int org_x, int org_y, int w, int h, int arg) +{ + uint16_t gfx, offset, mask, max_x = org_x + w; + + if (m_enable_cursor) bitblt(m_cursor_x, m_cursor_y, m_dad, 16, 16, RR_XOR); + if (m_enable_sprite) bitblt(m_sprite_x, m_sprite_y, m_dad + 16, 16, 16, RR_XOR); + + for (int y = org_y; y < org_y + h; y++) { + gfx = m_videoram[m_dad + (0x10 * arg) + y%16]; + if (m_rr == RR_COPYINVERTED) gfx ^= 0xffff; + for (int x = org_x; x < max_x;) { + mask = 0xffff; + offset = m_sad + m_org + y * (HPGPU_HORZ_TOTAL/16) + (x >> 4); + + if (offset >= m_sad + (HPGPU_VERT_TOTAL * HPGPU_HORZ_TOTAL/WS)) + DBG_LOG(0,"HPGPU",("buffer overflow in FILL: %04x (%d, %d)\n", offset, 16*x, y)); + + // clipping + if (x == org_x) { + mask >>= (org_x % WS); + x += (WS - (org_x % WS)); + } else { + if ((max_x - x) < WS) { + mask &= ~((1 << (WS - (max_x % WS))) - 1); + } + x += WS; + } + m_videoram[offset] &= ~mask; + m_videoram[offset] |= gfx & mask; + } + } + + if (m_enable_cursor) bitblt(m_cursor_x, m_cursor_y, m_dad, 16, 16, RR_XOR); + if (m_enable_sprite) bitblt(m_sprite_x, m_sprite_y, m_dad + 16, 16, 16, RR_XOR); +} + +// sprite drawing -- source is 16x16 px max, no window clipping +void hp1ll3_device::bitblt(int dstx, int dsty, uint16_t srcaddr, int width, int height, int op) +{ + uint16_t gfx, offset, mask; + int max_x, max_y; + + max_x = dstx + width; + if (max_x >= HPGPU_HORZ_TOTAL) + max_x = HPGPU_HORZ_TOTAL; + + max_y = dsty + height; + if (max_y >= HPGPU_VERT_TOTAL) + max_y = HPGPU_VERT_TOTAL; + + for (int y = dsty; y < max_y; y++) { + mask = 0xffff; + gfx = m_videoram[srcaddr + y - dsty] & mask; + offset = m_sad + y * (HPGPU_HORZ_TOTAL/16) + (dstx >> 4); + + if (offset >= m_sad + (HPGPU_VERT_TOTAL * HPGPU_HORZ_TOTAL/16)) + DBG_LOG(0,"HPGPU",("buffer overflow in bitblt: %04x (%d, %d)\n", offset, 16*dstx, y)); + + // are we crossing word boundary? + if (dstx % 16) { + if (op == RR_XOR) + { + m_videoram[offset ] ^= gfx >> (dstx % 16); + m_videoram[offset + 1] ^= gfx << (16 - (dstx % 16)); + } + } else { + if (op == RR_XOR) + { + m_videoram[offset] ^= (gfx & mask); + } + } + } +} + +void hp1ll3_device::label(uint8_t chr, int width) +{ + uint16_t x, gfx, bg = 0x3f, offset, font = m_fontdata + chr * 16; + int max_y = m_cursor_y + m_fontheight; + + if (max_y >= m_window.org_y + m_window.height) + max_y = m_window.org_y + m_window.height - 1 - m_cursor_y; + else + max_y -= m_cursor_y; + + if (m_enable_cursor) bitblt(m_cursor_x, m_cursor_y, m_dad, 16, 16, RR_XOR); + if (m_enable_sprite) bitblt(m_sprite_x, m_sprite_y, m_dad + 16, 16, 16, RR_XOR); + + for (int y = 0; y < max_y; y++) { + x = m_cursor_x; + offset = m_sad + (m_cursor_y + y) * (HPGPU_HORZ_TOTAL/16) + (x >> 4); + gfx = m_videoram[font + y] >> (16 - width); + + if (offset >= m_sad + (HPGPU_VERT_TOTAL * HPGPU_HORZ_TOTAL/16)) + DBG_LOG(0,"HPGPU",("buffer overflow in LABEL: %04x (%d, %d)\n", offset, 16*x, y)); + + // are we crossing word boundary? + if ((x % 16) > (16 - width)) { + if (m_rr == RR_COPYINVERTED) { + m_videoram[offset ] |= bg >> ((x % 16) - (16 - width)); + m_videoram[offset + 1] |= bg << (16 - ((x + width) % 16)); + } else { + m_videoram[offset ] &= ~(bg>> ((x % 16) - (16 - width))); + m_videoram[offset + 1] &= ~(bg<< (16 - ((x + width) % 16))); + } + m_videoram[offset ] ^= gfx >> ((x % 16) - (16 - width)); + m_videoram[offset + 1] ^= gfx << (16 - ((x + width) % 16)); + } else { + if (m_rr == RR_COPYINVERTED) { + m_videoram[offset ] |= bg << ((16 - width) - (x % 16)); + } else { + m_videoram[offset ] &= ~(bg<< ((16 - width) - (x % 16))); + } + m_videoram[offset ] ^= gfx << ((16 - width) - (x % 16)); + } + } + + m_cursor_x += width; + if (m_enable_cursor) bitblt(m_cursor_x, m_cursor_y, m_dad, 16, 16, RR_XOR); + if (m_enable_sprite) bitblt(m_sprite_x, m_sprite_y, m_dad + 16, 16, 16, RR_XOR); +} + + +uint32_t hp1ll3_device::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect) +{ + int x, y, offset; + uint16_t gfx, *p; + + if (!m_enable_video) { + bitmap.fill(rgb_t::black()); + return 0; + } + + // XXX last line is not actually drawn on real hw + for (y = 0; y < HPGPU_VERT_TOTAL-1; y++) { + offset = m_sad + y*(HPGPU_HORZ_TOTAL/16); + p = &m_bitmap.pix16(y); + + for (x = offset; x < offset + HPGPU_HORZ_TOTAL/16; x++) + { + gfx = m_videoram[x]; + + *p++ = BIT(gfx, 15); + *p++ = BIT(gfx, 14); + *p++ = BIT(gfx, 13); + *p++ = BIT(gfx, 12); + *p++ = BIT(gfx, 11); + *p++ = BIT(gfx, 10); + *p++ = BIT(gfx, 9); + *p++ = BIT(gfx, 8); + *p++ = BIT(gfx, 7); + *p++ = BIT(gfx, 6); + *p++ = BIT(gfx, 5); + *p++ = BIT(gfx, 4); + *p++ = BIT(gfx, 3); + *p++ = BIT(gfx, 2); + *p++ = BIT(gfx, 1); + *p++ = BIT(gfx, 0); + } + } + + copybitmap(bitmap, m_bitmap, 0, 0, 0, 0, cliprect); + + return 0; +} + +//------------------------------------------------- +// read - register read +//------------------------------------------------- + +/* + * offset 0: CSR + * + * bit 0 gpu is busy + * bit 1 data is ready + * bit 3 vert blank time + * bit 7 out of window + * + * offset 2: data + */ + +READ8_MEMBER( hp1ll3_device::read ) +{ + uint8_t data = 0; + + switch (offset) + { + case 0: + data = m_busy ? 1 : 0; + data |= 2; + data |= (m_screen->vblank() ? 8 : 0); + break; + + case 2: + switch (m_command) + { + case RDMEM: + if (m_memory_ptr < HPGPU_VRAM_SIZE*2) { + if (m_memory_ptr & 1) { + data = m_videoram[m_memory_ptr >> 1] & 0xff; + } else { + data = m_videoram[m_memory_ptr >> 1] >> 8; + } + m_memory_ptr++; + } + break; + } + } + + DBG_LOG(1,"HPGPU", ("R @ %d == %02x\n", offset, data)); + + return data; +} + + +//------------------------------------------------- +// write - register write +//------------------------------------------------- + +WRITE8_MEMBER( hp1ll3_device::write ) +{ + DBG_LOG(1,"HPGPU", ("W @ %d <- %02x\n", offset, data)); + + switch (offset) + { + case 0: + command(data); + break; + + case 2: + switch (m_command) + { + case CONF: + if (m_conf_ptr & 1) { + m_conf[m_conf_ptr >> 1] |= data; + } else { + m_conf[m_conf_ptr >> 1] = data << 8; + } + if (m_conf_ptr++ == 22) { + DBG_LOG(2,"HPGPU",("CONF data received: %04X %04X %04X %04X %04X %04X %04X %04X %04X %04X %04X\n", + m_conf[0], m_conf[1], m_conf[2], m_conf[3], + m_conf[4], m_conf[5], m_conf[6], m_conf[7], + m_conf[8], m_conf[9], m_conf[10])); + } + break; + + case WRMEM: + if (m_memory_ptr < HPGPU_VRAM_SIZE*2) { + if (m_memory_ptr & 1) { + m_videoram[m_memory_ptr >> 1] |= data; + } else { + m_videoram[m_memory_ptr >> 1] = data << 8; + } + m_memory_ptr++; + } + break; + + default: + switch (m_input_ptr) + { + case 0: + m_input[0] = data << 8; + break; + + case 1: + m_input[0] |= data; + break; + + case 2: + m_input[1] = data << 8; + break; + + case 3: + m_input[1] |= data; + break; + } + DBG_LOG(2,"HPGPU",("wrote %02x at %d, input buffer is %04X %04X\n", data, m_input_ptr, m_input[0], m_input[1])); + m_input_ptr++; + } + } +} + + +void hp1ll3_device::command(int command) +{ + int c, w; + + switch (command) + { + + // type 0 commands -- no data + + case NOP: + DBG_LOG(2,"HPGPU",("command: NOP [%d, 0x%x]\n", command, command)); + switch (m_command) + { + case RDMEM: + DBG_LOG(1,"HPGPU",("RDMEM of %d words at %04X complete\n", (m_memory_ptr >> 1) - m_input[0], m_input[0])); + break; + + case WRMEM: + DBG_LOG(1,"HPGPU",("WRMEM of %d words to %04X complete\n", (m_memory_ptr >> 1) - m_input[0], m_input[0])); + break; + } + break; + + case DISVID: + DBG_LOG(2,"HPGPU",("command: DISVID [%d, 0x%x]\n", command, command)); + m_enable_video = false; + break; + + case ENVID: + DBG_LOG(2,"HPGPU",("command: ENVID [%d, 0x%x]\n", command, command)); + DBG_LOG(1,"HPGPU",("enable video; SAD %04x FAD %04x DAD %04x ORG %04x UDL %04x RR %04x\n", + m_sad, m_fad, m_dad, m_org, m_udl, m_rr)); + m_enable_video = true; + break; + + case DISSP: + DBG_LOG(2,"HPGPU",("command: DISSP [%d, 0x%x]\n", command, command)); + if (m_enable_sprite) { + bitblt(m_sprite_x, m_sprite_y, m_dad + 16, 16, 16, RR_XOR); + m_enable_sprite = false; + } + break; + + case ENSP: + DBG_LOG(2,"HPGPU",("command: ENSP [%d, 0x%x]\n", command, command)); + if (m_enable_sprite) { + bitblt(m_sprite_x, m_sprite_y, m_dad + 16, 16, 16, RR_XOR); + } + bitblt(m_sprite_x, m_sprite_y, m_dad + 16, 16, 16, RR_XOR); + m_enable_sprite = true; + DBG_LOG(1,"HPGPU",("enable sprite; cursor %d,%d sprite %d,%d\n", m_cursor_x, m_cursor_y, m_sprite_x, m_sprite_y)); + break; + + case DISCURS: + DBG_LOG(2,"HPGPU",("command: DISCURS [%d, 0x%x]\n", command, command)); + if (m_enable_cursor) { + bitblt(m_cursor_x, m_cursor_y, m_dad, 16, 16, RR_XOR); + m_enable_cursor = false; + } + break; + + case ENCURS: + DBG_LOG(2,"HPGPU",("command: ENCURS [%d, 0x%x]\n", command, command)); + if (m_enable_cursor) { + bitblt(m_cursor_x, m_cursor_y, m_dad, 16, 16, RR_XOR); + } + bitblt(m_cursor_x, m_cursor_y, m_dad, 16, 16, RR_XOR); + m_enable_cursor = true; + DBG_LOG(1,"HPGPU",("enable cursor; cursor %d,%d sprite %d,%d\n", m_cursor_x, m_cursor_y, m_sprite_x, m_sprite_y)); + break; + + // type 1 commands -- 1 word of data expected in the buffer + + // start of screen memory + case WRSAD: + DBG_LOG(2,"HPGPU",("command: WRSAD [%d, 0x%x] (0x%04x)\n", command, command, m_input[0])); + m_sad = m_input[0]; + break; + + // start of font memory + case WRFAD: + DBG_LOG(2,"HPGPU",("command: WRFAD [%d, 0x%x] (0x%04x)\n", command, command, m_input[0])); + m_fad = m_input[0]; + m_fontheight = m_videoram[m_fad]; + m_fontdata = m_fad + m_videoram[m_fad + 1] + 2; + DBG_LOG(1,"HPGPU",("font data set: FAD %04X header %d bitmaps %04X height %d\n", + m_fad, m_videoram[m_fad + 1], m_fontdata, m_fontheight)); + break; + + // start of data area + case WRDAD: + DBG_LOG(2,"HPGPU",("command: WRDAD [%d, 0x%x] (0x%04x)\n", command, command, m_input[0])); + m_dad = m_input[0]; + break; + + // ?? + case WRORG: + DBG_LOG(2,"HPGPU",("command: WRORG [%d, 0x%x] (0x%04x)\n", command, command, m_input[0])); + m_org = m_input[0]; + break; + + // set replacement rule (raster op) + case WRRR: + DBG_LOG(2,"HPGPU",("command: WRRR [%d, 0x%x] (0x%04x)\n", command, command, m_input[0])); + m_rr = m_input[0]; + break; + + // set user-defined line pattern + case WRUDL: + DBG_LOG(2,"HPGPU",("command: WRUDL [%d, 0x%x] (0x%04x)\n", command, command, m_input[0])); + m_udl = m_input[0]; + break; + + // area fill + case FILL: + DBG_LOG(2,"HPGPU",("command: FILL [%d, 0x%x] (0x%04x) from (%d,%d) size (%d,%d) rop 0x%x\n", + command, command, m_input[0], + m_window.org_x, m_window.org_y, m_window.width, m_window.height, m_rr)); + fill(m_window.org_x, m_window.org_y, m_window.width, m_window.height, m_input[0]); + break; + + case LABEL: + DBG_LOG(2,"HPGPU",("command: LABEL [%d, 0x%x] (0x%04x, '%c') at %d,%d\n", command, command, m_input[0], + (m_input[0]<32||m_input[0]>127) ? ' ' : m_input[0], m_cursor_x, m_cursor_y)); + c = m_input[0] & 255; + w = (c & 1) ? + (m_videoram[m_fad + 2 + (c>>1)] & 255) : + (m_videoram[m_fad + 2 + (c>>1)] >> 8); + label(c, w); + break; + + // type 2 commands -- 2 words of data expected in the buffer + + case DRAWPX: + DBG_LOG(2,"HPGPU",("command: DRAWPX [%d, 0x%x] (%d, %d)\n", command, command, m_input[0], m_input[1])); + point(m_input[0], m_input[1],(m_rr != RR_COPYINVERTED)); + break; + + // set window size + case WRWINSIZ: + DBG_LOG(2,"HPGPU",("command: WRWINSIZ [%d, 0x%x] (%d, %d)\n", command, command, m_input[0], m_input[1])); + m_window.width = m_input[0]; + m_window.height = m_input[1]; + break; + + // set window origin + case WRWINORG: + DBG_LOG(2,"HPGPU",("command: WRWINORG [%d, 0x%x] (%d, %d)\n", command, command, m_input[0], m_input[1])); + m_window.org_x = m_input[0]; + m_window.org_y = m_input[1]; + break; + + // move pointer absolute + case MOVEP: + DBG_LOG(2,"HPGPU",("command: MOVEP [%d, 0x%x] (%d, %d)\n", command, command, m_input[0], m_input[1])); + if (m_enable_cursor) bitblt(m_cursor_x, m_cursor_y, m_dad, 16, 16, RR_XOR); + if (m_enable_sprite) bitblt(m_sprite_x, m_sprite_y, m_dad + 16, 16, 16, RR_XOR); + m_cursor_x = m_input[0]; + m_cursor_y = m_input[1]; + if (m_enable_cursor) bitblt(m_cursor_x, m_cursor_y, m_dad, 16, 16, RR_XOR); + if (m_enable_sprite) bitblt(m_sprite_x, m_sprite_y, m_dad + 16, 16, 16, RR_XOR); + break; + + // move sprite absolute + case MOVESP: + DBG_LOG(2,"HPGPU",("command: MOVESP [%d, 0x%x] (%d, %d)\n", command, command, m_input[0], m_input[1])); + m_sprite_x = m_input[0]; + m_sprite_y = m_input[1]; + break; + + // draw to ... + case DRAWP: + DBG_LOG(2,"HPGPU",("command: DRAWP [%d, 0x%x] (%d, %d) to (%d, %d)\n", + command, command, m_cursor_x, m_cursor_y, m_input[0], m_input[1])); + line(m_cursor_x, m_cursor_y, m_input[0], m_input[1]); + m_cursor_x = m_input[0]; + m_cursor_y = m_input[1]; + break; + + // type 3 command -- CONF -- accept configuration parameters (11 words) + + case CONF: + m_conf_ptr = 0; + break; + + // type 4 commands -- like type 1 plus data is read or written after command, terminated by NOP + + case RDMEM: + case WRMEM: + DBG_LOG(2,"HPGPU",("command: %s [%d, 0x%x] (0x%04x)\n", + command == RDMEM?"RDMEM":"WRMEM", command, command, m_input[0])); + m_memory_ptr = m_input[0] << 1; // memory is word-addressable + break; + + default: + DBG_LOG(1,"HPGPU",("command: UNKNOWN [%d, 0x%x]\n", command, command)); + break; + } + + m_input_ptr = 0; + m_command = command; +} diff --git a/src/devices/video/hp1ll3.h b/src/devices/video/hp1ll3.h new file mode 100644 index 00000000000..490bd5c5369 --- /dev/null +++ b/src/devices/video/hp1ll3.h @@ -0,0 +1,176 @@ +// license:BSD-3-Clause +// copyright-holders:Sergey Svishchev +/*************************************************************************** + + HP 1LL3-0005 GPU emulation. + + ***************************************************************************/ + + +#pragma once + +#ifndef __HP1LL3_H__ +#define __HP1LL3_H__ + +///************************************************************************* +// MACROS / CONSTANTS +///************************************************************************* + +/* + * command types (send) + * + * 0 -- no data + * 1 -- write 1 word of data, then command + * 2 -- write 2 words of data, then command + * 3 -- write command, then 11 words of data (= CONF only?) + * 4 -- write 1 word of data, then command, then write X words of data, then write NOP + * + * (read) + * + * 3 -- ??? + * 4 -- write 1 word of data, then command, then read X words of data, then write NOP + */ +#define NOP 0 // type 0 +#define CONF 2 // type 3, configure GPU (screen size, timings...). 11 words of data. +#define DISVID 3 // type 0, disable video +#define ENVID 4 // type 0, enable video +#define WRMEM 7 // type 4, write GPU memory at offset, terminate by NOP +#define RDMEM 8 // type 4, read GPU memory from offset, terminate by NOP +#define WRSAD 9 // type 1, set screen area start address +#define WRORG 10 // type 1, set ??? +#define WRDAD 11 // type 1, set data area start address (16x16 area fill, sprite and cursor) +#define WRRR 12 // type 1, set replacement rule (rasterop) +#define MOVEP 13 // type 2, move pointer +#define IMOVEP 14 +#define DRAWP 15 // type 2, draw line +#define IDRAWP 16 +#define RDP 17 +#define WRUDL 18 // type 1, set user-defined line pattern (16-bit) +#define WRWINSIZ 19 // type 2, set ??? +#define WRWINORG 20 // type 2, set ??? +#define COPY 21 // type 2 +#define FILL 22 // type 1, fill area +#define FRAME 23 // type _, draw rectangle +#define SCROLUP 24 // type 2 +#define SCROLDN 25 // type 2 +#define SCROLLF 26 // type 2 +#define SCROLRT 27 // type 2 +#define RDWIN 28 // type 1 +#define WRWIN 29 // type 1 +#define RDWINPARM 30 +#define CR 31 +#define CRLFx 32 +#define LABEL 36 // type 1, draw text +#define ENSP 38 // type 0, enable sprite +#define DISSP 39 // type 0, disable sprite +#define MOVESP 40 // type 2, move sprite +#define IMOVESP 41 +#define RDSP 42 +#define DRAWPX 43 // type _, draw single pixel +#define WRFAD 44 // type 1, set font area start address +#define ENCURS 45 // type 0 +#define DISCURS 46 // type 0 +#define ID 63 + + +/* + * Replacement Rules (rops). sources: + * + * - NetBSD's diofbvar.h (definitions for Topcat chip) + * - pdf/hp/9000_300/specs/A-5958-4362-9_Series_300_Display_Color_Card_Theory_of_Operation_Oct85.pdf + * refers to TOPCAT documentation p/n A-1FH2-2001-7 (not online) + */ +#define RR_FORCE_ZERO 0x0 +#define RR_CLEAR RR_FORCE_ZERO +#define RR_AND 0x1 +#define RR_AND_NOT_OLD 0x2 +#define RR_NEW 0x3 +#define RR_COPY RR_NEW +#define RR_AND_NOT_NEW 0x4 +#define RR_OLD 0x5 +#define RR_XOR 0x6 +#define RR_OR 0x7 +#define RR_NOR 0x8 +#define RR_XNOR 0x9 +#define RR_NOT_OLD 0xa +#define RR_INVERT RR_NOT_OLD +#define RR_OR_NOT_OLD 0xb +#define RR_NOT_NEW 0xc +#define RR_COPYINVERTED RR_NOT_NEW +#define RR_OR_NOT_NEW 0xd +#define RR_NAND 0xe +#define RR_FORCE_ONE 0xf + +#define WS 16 // bits in a word + + +///************************************************************************* +// INTERFACE CONFIGURATION MACROS +///************************************************************************* + +#define MCFG_HP1LL3_ADD(_tag) \ + MCFG_DEVICE_ADD(_tag, HP1LL3, 0) + +///************************************************************************* +// TYPE DEFINITIONS +///************************************************************************* + + +// ======================> hp1ll3_device + +class hp1ll3_device : public device_t, + public device_video_interface +{ +public: + // construction/destruction + hp1ll3_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + + DECLARE_READ8_MEMBER(read); + DECLARE_WRITE8_MEMBER(write); + + uint32_t screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect); + +protected: + // device-level overrides + virtual void device_start() override; + virtual void device_reset() override; + +private: + void command(int command); + + inline void point(int x, int y, int px); + void label(uint8_t chr, int width); + void fill(int x, int y, int w, int h, int arg); + void line(int x_from, int y_from, int x_to, int y_to); + void bitblt(int dstx, int dsty, uint16_t srcaddr, int width, int height, int op); + + uint16_t m_conf[11], m_input[2]; + int m_input_ptr, m_memory_ptr, m_conf_ptr; + int m_command; + + uint16_t m_sad; + uint16_t m_org; + uint16_t m_dad; + uint16_t m_rr; + uint16_t m_fad, m_fontdata, m_fontheight; + uint16_t m_udl; + + bool m_enable_video, m_enable_cursor, m_enable_sprite; + uint16_t m_cursor_x, m_cursor_y; + uint16_t m_sprite_x, m_sprite_y; + struct { + uint16_t width, height, org_x, org_y, width_w; + } m_window; + std::unique_ptr m_videoram; + + bool m_busy; + + bitmap_ind16 m_bitmap, m_cursor, m_sprite; +}; + + +// device type definition +extern const device_type HP1LL3; + + +#endif diff --git a/src/emu/drivers/xtal.h b/src/emu/drivers/xtal.h index 7e9e809aed2..555a77e3f26 100644 --- a/src/emu/drivers/xtal.h +++ b/src/emu/drivers/xtal.h @@ -150,6 +150,7 @@ enum XTAL_15_4MHz = 15400000, /* DVK KSM */ XTAL_15_468MHz = 15468480, /* Bank Panic h/w, Sega G80 */ XTAL_15_8976MHz = 15897600, /* IAI Swyft */ + XTAL_15_92MHz = 15920000, /* HP Integral PC */ XTAL_16MHz = 16000000, /* Extremely common, used on 100's of PCBs */ XTAL_16_384MHz = 16384000, XTAL_16_5888MHz = 16588800, /* SM 7238 */ diff --git a/src/lib/formats/hp_ipc_dsk.cpp b/src/lib/formats/hp_ipc_dsk.cpp new file mode 100644 index 00000000000..ed65ada7a61 --- /dev/null +++ b/src/lib/formats/hp_ipc_dsk.cpp @@ -0,0 +1,42 @@ +// license:BSD-3-Clause +// copyright-holders:Sergey Svishchev +/********************************************************************* + + formats/hp_ipc_dsk.c + + HP Integral PC format + +*********************************************************************/ + +#include + +#include "formats/hp_ipc_dsk.h" + +hp_ipc_format::hp_ipc_format() : wd177x_format(formats) +{ +} + +const char *hp_ipc_format::name() const +{ + return "hp_ipc"; +} + +const char *hp_ipc_format::description() const +{ + return "HP Integral PC disk image"; +} + +const char *hp_ipc_format::extensions() const +{ + return "img"; +} + +const hp_ipc_format::format hp_ipc_format::formats[] = { + // images from coho.org. gaps unverified. + { floppy_image::FF_35, floppy_image::DSDD, floppy_image::MFM, + 2000, 9, 77, 2, 512, {}, 1, {}, 60, 22, 43 }, + {} +}; + +const floppy_format_type FLOPPY_HP_IPC_FORMAT = &floppy_image_format_creator; + diff --git a/src/lib/formats/hp_ipc_dsk.h b/src/lib/formats/hp_ipc_dsk.h new file mode 100644 index 00000000000..11969da02e2 --- /dev/null +++ b/src/lib/formats/hp_ipc_dsk.h @@ -0,0 +1,30 @@ +// license:BSD-3-Clause +// copyright-holders:Sergey Svishchev +/********************************************************************* + + formats/hp_ipc_dsk.h + + hp_ipc format + +*********************************************************************/ + +#ifndef HP_IPC_DSK_H_ +#define HP_IPC_DSK_H_ + +#include "wd177x_dsk.h" + +class hp_ipc_format : public wd177x_format { +public: + hp_ipc_format(); + + virtual const char *name() const override; + virtual const char *description() const override; + virtual const char *extensions() const override; + +private: + static const format formats[]; +}; + +extern const floppy_format_type FLOPPY_HP_IPC_FORMAT; + +#endif diff --git a/src/mame/drivers/hp_ipc.cpp b/src/mame/drivers/hp_ipc.cpp index e59559cb791..bd708c0ce90 100644 --- a/src/mame/drivers/hp_ipc.cpp +++ b/src/mame/drivers/hp_ipc.cpp @@ -2,10 +2,51 @@ // copyright-holders: /****************************************************************************** - Integral Personal Computer (HP9807A) Hewlett-Packard, 1985 +Driver to-do list +================= + +- softlist: merge dumps from coho.org and classiccmp.org +- keyboard: NMI generation, autorepeat +- HP-HIL mouse +- RTC chip: proper month, day +- switchable graphics resolution ("_desktop" mode uses 640x400) +- HP-IB chip +- CS/80, SS/80 storage protocol(s) and drives +- HP-IL printer +- sound (needs dump of COP452) + +QA +- diagnstc.td0: display test [cannot execute] +- diagnstc.td0: complete keyboard test [keyboard stops responding] +- diagnstc.td0: speaker test +- diagnstc.td0: printer test ++ diagnstc.td0: auto: floppy disc test ++ diagnstc.td0: auto: ram test +- diagnstc.td0: auto: rtc test [cannot execute] +- diagnstc.td0: auto: short keyboard test [cannot execute + keyboard stops responding] + +maybe +- drive AP line of MLC from a timer +- RTC standby interrupt? +- what does _desktop do except setting 640x400 mode? +- non-HLE keyboard and mouse? (need dumps of COP4xx) + +slot devices +- 82915A -- 300/1200 bps modem; http://www.hpmuseum.net/display_item.php?hw=920 +- 82919A -- serial; http://www.hpmuseum.net/display_item.php?hw=445 +- 82920A -- current loop; http://www.hpmuseum.net/display_item.php?hw=975 +- 82922A -- BCD interface; http://www.hpmuseum.net/display_item.php?hw=921 +- 82923A -- GPIO; http://www.hpmuseum.net/display_item.php?hw=976 +- 82924A -- HP-IL; http://www.hpmuseum.net/display_item.php?hw=922 +- 82968A -- up to 256 KB of ROM on top of operating system PCA +- 82971A -- up to 1 MB of EPROM or 2 MB or masked ROM +- 82998A -- HP-IB; http://www.hpmuseum.net/display_item.php?hw=933 +- 98071A -- 640x400 composite Video + Serial; http://www.hpmuseum.net/display_item.php?hw=935 + + This is a portable mains-powered UNIX workstation computer system produced by Hewlett-Packard and launched in 1985 Basic hardware specs are.... - 68000 CPU at 7.96MHz @@ -74,7 +115,7 @@ Notes: LS74 - 74LS74 at U2 provides system clock dividers /4 /2 MB81256 - Fujitsu MB81256 256Kx1 DRAM. Total RAM 512Kx8/256Kx16. HP part# 1818-3308. U20-U35 (DIP16) TMS4500 - Texas Instruments TMS4500A DRAM Controller at U4. Clock input 3.98MHz [15.92/4] (DIP40) - U58 - HP-HIL Keyboard Interface 'Cerberus'. Clock input on pin 24 is unknown (DIP24) + U58 - 1RD2-6001, HP-HIL Master Link Controller 'Cerberus'. Clock input on pin 24 is unknown (DIP24) U60 - Unknown IC used as an interrupt encoder. Possibly a logic chip? (DIP20) 555 - 555 Timer J1/J2 - Connectors joining to LOGIC B PCA (logic A to logic B bus) @@ -121,13 +162,13 @@ HP Part# 00095-60952 | J14 J6 J5 J4 J3 J7 J1 J8 J9 J12 | |------------------------------------------------------------------------------------------------------| Notes: - GPU - GPU (Graphics Processor) at U1. Clock input 3MHz [24/8]. VSync on pin 45, HSync on pin 46 (DIP48) + GPU - 1LL3-0005 GPU (Graphics Processor) at U1. Clock input 3MHz [24/8]. VSync on pin 45, HSync on pin 46 (DIP48) 16Kx4 - 16Kx4 DRAM, organised as 32Kx8bit/16Kx16bit at U3, U4, U5 & U6. Chip type unknown, likely Fujitsu MB81416 (DIP18) WD2797 - Western Digital WD2797 Floppy Disk Controller at U18. Clock input 2MHz [24/2/3/2] (DIP40) HP-IL(1) - HP-IL 1LJ7-0015 'Saturn' Thinkjet Printer Controller IC at U28. Clock input 3MHz on pin 9 [24/8] (DIP48) - HP-IL(2) - HP-IL Interface IC at U31. Clock input 2MHz on pin 22 [24/2/3/2] (DIP28) + HP-IL(2) - HP-IL 1LB3 Interface IC at U31. Clock input 2MHz on pin 22 [24/2/3/2] (DIP28) 1Kb - 1Kb RAM at U27 for printer buffer (DIP28, type unknown, very old, with only DATA0,1,2,3, C/D and DIN,DOUT) - ROM - 16Kb (2Kx8?) Some kind of very early DIP28 PROM/ROM? Same pinout as 1Kb RAM above. Holds the character font table for the printer + ROM - 16Kb (32Kx4) Some kind of very early DIP28 PROM/ROM? Same pinout as 1Kb RAM above. Holds the character font table for the printer Four versions of this ROM exist, one each for Japan/Arabic/Hebrew and one for all other regions NS58167A - National Semiconductor NS58167A Clock Controller RTC at U44. Clock input 32.768kHz (DIP24) LM358 - National Semiconductor LM358 Operational Amplifier at U40 (DIP8) @@ -246,7 +287,7 @@ F80000-FFFFFF - Reserved 512Kb Access to 800000-FFFFFF can be remapped by the MMU registers. -Interrupts +Interrupts (all autovectored) ---------- High Priority 7 - Soft reset from keyboard (NMI) /\ 6 - RTC or NBIR3 (external I/O) @@ -259,10 +300,81 @@ Low Priority 1 - RTC Note external interrupt lines NBIR0 to NBIR3 can be asserted by an interface connected to the external I/O port +Useful links etc. +----------------- + +bitsavers://pdf/hp/integral/00095-90126_Integral_Personal_Computer_Service_Jan86.pdf + +bitsavers://pdf/hp/hp-hil/45918A-90001_HP-HIL_Technical_Reference_Manual_Jan86.pdf + HP-HIL MLC, SLC datasheets + +bitsavers://pdf/sony/floppy/Sony_OA-D32_Microfloppy_Service_Nov83.pdf + OA-D32W + +http://www.hpl.hp.com/hpjournal/pdfs/IssuePDFs/1983-01.pdf + HP-IL issue + +http://www.hpl.hp.com/hpjournal/pdfs/IssuePDFs/1985-10.pdf + IPC issue + +http://www.hpl.hp.com/hpjournal/pdfs/IssuePDFs/1987-06.pdf + HP-HIL article + +http://www.hpmuseum.net/pdf/ComputerNews_1985_Jan15_37pages_OCR.pdf + introducing the IPC + +http://www.hpmuseum.net/pdf/ComputerFocus_1985_Nov_25pages_OCR.pdf + SysV upgrade + +http://www.hpmuseum.net/pdf/InformationSystemsAndManufacturingNews_81pages_Jun1-86_OCR.pdf + EPROM/ROM modules + +http://www.hpmuseum.net/pdf/HPChannels_1986_11_37pages_Nov86_OCR.pdf + SW Eng ROM and serial option for it + +http://www.coho.org/~pete/downloads/IPC/burst/Freeware/IPC_Driver_Writers_Disc/hp-ux.5.0.0 + kernel namelist + +http://www.hpmuseum.net/display_item.php?hw=122 + overview, manuals, software + +http://www.ambry.com/hp-computer-model/9807A.html + replacement parts + +http://www.brouhaha.com/~eric/hpcalc/chips/ + chip part numbers + + +Software to look for +-------------------- + +00095-60978 "Service ROM - Used in trobleshooting the integral PC" via ambry +00095-60925 "Service ROM" via service manual +00095-60969 "Service Diagnostic Disc" via service manual +00095-60950 "I/O Component-Level Diagnostic Disc" via serial interface service manual + +00095-60006 (original System III-based HP-UX 1.0 ROM) +82995A (same bits as 82991A; the latter is an upgrade kit, former was pre-installed) +82989J Technical Basic ROM (Jan'1986) +82987A Software Engineering ROM (Nov'1986) (possibly can be rebuilt from floppy images on coho?) + ******************************************************************************/ #include "emu.h" + +#include "bus/hp_hil/hp_hil.h" +#include "bus/hp_hil/hil_devices.h" #include "cpu/m68000/m68000.h" +#include "formats/hp_ipc_dsk.h" +#include "machine/bankdev.h" +#include "machine/mm58167.h" +#include "machine/ram.h" +#include "machine/wd_fdc.h" +#include "video/hp1ll3.h" + +#include "rendlay.h" + +#include "screen.h" class hp_ipc_state : public driver_device @@ -271,81 +383,381 @@ public: hp_ipc_state(const machine_config &mconfig, device_type type, const char *tag) : driver_device(mconfig, type, tag) , m_maincpu(*this, "maincpu") + , m_bankdev(*this, "bankdev") + , m_fdc(*this, "fdc") + , m_ram(*this, RAM_TAG) + , m_screen(*this, "screen") { } + virtual void machine_start() override; + virtual void machine_reset() override; + + DECLARE_READ16_MEMBER(mem_r); + DECLARE_WRITE16_MEMBER(mem_w); + DECLARE_READ16_MEMBER(mmu_r); DECLARE_WRITE16_MEMBER(mmu_w); DECLARE_READ16_MEMBER(ram_r); DECLARE_WRITE16_MEMBER(ram_w); + DECLARE_READ16_MEMBER(trap_r); + DECLARE_WRITE16_MEMBER(trap_w); + + DECLARE_READ8_MEMBER(floppy_id_r); + DECLARE_WRITE8_MEMBER(floppy_id_w); + DECLARE_FLOPPY_FORMATS(floppy_formats); + + DECLARE_WRITE_LINE_MEMBER(irq_1); + DECLARE_WRITE_LINE_MEMBER(irq_2); + DECLARE_WRITE_LINE_MEMBER(irq_3); + DECLARE_WRITE_LINE_MEMBER(irq_4); + DECLARE_WRITE_LINE_MEMBER(irq_5); + DECLARE_WRITE_LINE_MEMBER(irq_6); + DECLARE_WRITE_LINE_MEMBER(irq_7); + + emu_timer *m_bus_error_timer; private: required_device m_maincpu; + required_device m_bankdev; + required_device m_fdc; + required_device m_ram; + required_device m_screen; - uint32_t m_mmu[4]; - uint16_t m_internal_ram[0x40000]; + uint32_t m_mmu[4], m_lowest_ram_addr; + uint16_t *m_internal_ram; + int m_fc; - inline uint32_t get_ram_address(offs_t offset) { return (m_mmu[(m_maincpu->get_fc() >> 1) & 3] + offset) & 0x3FFFFF; } + floppy_image_device *m_floppy; + + inline uint32_t get_ram_address(offs_t offset) + { + return (m_mmu[(m_maincpu->get_fc() >> 1) & 3] + offset) & 0x3FFFFF; + } + +protected: + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override; + void set_bus_error(uint32_t address, bool write, uint16_t mem_mask); + bool m_bus_error; }; -static ADDRESS_MAP_START(hp_ipc_mem, AS_PROGRAM, 16, hp_ipc_state) - AM_RANGE(0x000000, 0x07FFFF) AM_ROM - AM_RANGE(0x600000, 0x60FFFF) AM_WRITE(mmu_w) - AM_RANGE(0x800000, 0xFFFFFF) AM_READWRITE(ram_r, ram_w) +void hp_ipc_state::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + m_bus_error = false; +} + +void hp_ipc_state::set_bus_error(uint32_t address, bool write, uint16_t mem_mask) +{ + if (m_bus_error) + { + return; + } + if (!ACCESSING_BITS_8_15) + { + address++; + } + m_bus_error = true; + m_maincpu->set_buserror_details(address, write, m_maincpu->get_fc()); + m_maincpu->set_input_line(M68K_LINE_BUSERROR, ASSERT_LINE); + m_bus_error_timer->adjust(m_maincpu->cycles_to_attotime(16)); // let rmw cycles complete +} + +static ADDRESS_MAP_START(hp_ipc_mem_outer, AS_PROGRAM, 16, hp_ipc_state) + AM_RANGE(0x000000, 0xFFFFFF) AM_READWRITE(mem_r, mem_w) ADDRESS_MAP_END +static ADDRESS_MAP_START(hp_ipc_mem_inner, AS_PROGRAM, 16, hp_ipc_state) +// user mode + AM_RANGE(0x1000000, 0x17FFFFF) AM_READWRITE(ram_r, ram_w) + AM_RANGE(0x1800000, 0x187FFFF) AM_ROM AM_REGION("maincpu", 0) + AM_RANGE(0x1E20000, 0x1E2000F) AM_DEVREADWRITE8("gpu", hp1ll3_device, read, write, 0x00ff) + AM_RANGE(0x1E40000, 0x1E4002F) AM_DEVREADWRITE8("rtc", mm58167_device, read, write, 0x00ff) + +// supervisor mode + AM_RANGE(0x0000000, 0x007FFFF) AM_ROM AM_REGION("maincpu", 0) // Internal ROM (operating system PCA) + AM_RANGE(0x0080000, 0x00FFFFF) AM_UNMAP // Internal ROM (option ROM PCA) + AM_RANGE(0x0100000, 0x04FFFFF) AM_UNMAP // External ROM modules + AM_RANGE(0x0600000, 0x060FFFF) AM_READWRITE(mmu_r, mmu_w) + AM_RANGE(0x0610000, 0x0610007) AM_READWRITE8(floppy_id_r, floppy_id_w, 0x00ff) + AM_RANGE(0x0610008, 0x061000F) AM_DEVREADWRITE8("fdc", wd2797_t, read, write, 0x00ff) + AM_RANGE(0x0620000, 0x062000F) AM_DEVREADWRITE8("gpu", hp1ll3_device, read, write, 0x00ff) + AM_RANGE(0x0630000, 0x063FFFF) AM_NOP // AM_DEVREADWRITE8(TMS9914_TAG, tms9914_device, read, write, 0x00ff) + AM_RANGE(0x0640000, 0x064002F) AM_DEVREADWRITE8("rtc", mm58167_device, read, write, 0x00ff) + AM_RANGE(0x0650000, 0x065FFFF) AM_NOP // HP-IL Printer (optional; ROM sets _desktop to 0 if not mapped) -- sys/lpint.h + AM_RANGE(0x0660000, 0x06600FF) AM_DEVREADWRITE8("mlc", hp_hil_mlc_device, read, write, 0x00ff) // 'caravan', scrn/caravan.h + AM_RANGE(0x0670000, 0x067FFFF) AM_NOP // Speaker (NatSemi COP 452) + AM_RANGE(0x0680000, 0x068FFFF) AM_NOP // 'SIMON (98628) fast HP-IB card' -- sys/simon.h + AM_RANGE(0x0700000, 0x07FFFFF) AM_UNMAP // External I/O + AM_RANGE(0x0800000, 0x0FFFFFF) AM_READWRITE(ram_r, ram_w) + +// bus error handler + AM_RANGE(0x0000000, 0x1FFFFFF) AM_READWRITE(trap_r, trap_w) +ADDRESS_MAP_END static INPUT_PORTS_START(hp_ipc) INPUT_PORTS_END +READ16_MEMBER(hp_ipc_state::mmu_r) +{ + uint16_t data = (m_mmu[offset & 3] >> 10); + + return data; +} + WRITE16_MEMBER(hp_ipc_state::mmu_w) { - logerror("mmu_w: offset = %08x, data = %04x, register = %d, data_to_add = %08x\n", offset, data, offset & 3, (data & 0xFFF) << 10); m_mmu[offset & 3] = (data & 0xFFF) << 10; } +READ16_MEMBER(hp_ipc_state::mem_r) +{ + int fc = m_maincpu->get_fc() & 4; + + if (fc != m_fc) + { + m_fc = fc; + m_bankdev->set_bank(m_fc ? 0 : 1); + } + + return m_bankdev->read16(space, offset, mem_mask); +} + +WRITE16_MEMBER(hp_ipc_state::mem_w) +{ + int fc = m_maincpu->get_fc() & 4; + + if (fc != m_fc) + { + m_fc = fc; + m_bankdev->set_bank(m_fc ? 0 : 1); + } + + m_bankdev->write16(space, offset, data, mem_mask); +} + +READ16_MEMBER(hp_ipc_state::trap_r) +{ + if (!machine().side_effect_disabled()) set_bus_error((offset << 1) & 0xFFFFFF, 0, mem_mask); + + return 0xffff; +} + +WRITE16_MEMBER(hp_ipc_state::trap_w) +{ + if (!machine().side_effect_disabled()) set_bus_error((offset << 1) & 0xFFFFFF, 1, mem_mask); +} + READ16_MEMBER(hp_ipc_state::ram_r) { uint32_t ram_address = get_ram_address(offset); + uint16_t data = 0xffff; - //logerror("RAM read, offset = %08x, ram address = %08X\n", offset, ram_address); - - if (ram_address < 0x380000) + if (ram_address < m_lowest_ram_addr) { - // External RAM modules + if (!machine().side_effect_disabled()) set_bus_error((offset << 1) + 0x800000, 0, mem_mask); } else if (ram_address < 0x3c0000) { // Internal RAM - return m_internal_ram[offset & 0x3ffff]; + data = m_internal_ram[ram_address - m_lowest_ram_addr]; } - return 0xffff; -} + return data; +} WRITE16_MEMBER(hp_ipc_state::ram_w) { uint32_t ram_address = get_ram_address(offset); - //logerror("RAM write, offset = %08x, ram address = %08X, data = %04x\n", offset, ram_address, data); - - if (ram_address < 0x380000) + if (ram_address < m_lowest_ram_addr) { - // External RAM modules + if (!machine().side_effect_disabled()) set_bus_error((offset << 1) + 0x800000, 1, mem_mask); } else if (ram_address < 0x3c0000) { // Internal RAM - m_internal_ram[offset & 0x3ffff] = data; + COMBINE_DATA(&m_internal_ram[ram_address - m_lowest_ram_addr]); } } +/* + * bit 6 -- INTRQ + * bit 1 -- disk changed (from drive) + * bit 0 -- write protect (from drive) + */ +READ8_MEMBER(hp_ipc_state::floppy_id_r) +{ + uint8_t data = 0; + + data = (m_fdc->intrq_r() << 6); + + if (m_floppy) + { + data |= (m_fdc->intrq_r() << 6) | (m_floppy->dskchg_r() << 1) | m_floppy->wpt_r(); + } + + return data; +} + +/* + * bit 7 -- 1: motor on (via inverter to drive's /MTorOn) + * bit 3 -- 1: head 0, 0: head 1 (via inverter to drive's /SSO) + * bit 1 -- 1: drive select (via inverter to drive's /DRIVE SEL 1) + * bit 0 -- 1: reset disc_changed (via inverter to drive's /DSKRST) + */ +WRITE8_MEMBER(hp_ipc_state::floppy_id_w) +{ + floppy_image_device *floppy0 = m_fdc->subdevice("0")->get_device(); + + if (!BIT(data, 1)) + { + if (m_floppy == nullptr) + { + m_floppy = floppy0; + m_fdc->set_floppy(m_floppy); + } + } + else + { + m_floppy = nullptr; + } + + if (m_floppy) + { + m_floppy->ss_w(BIT(data, 3)); + m_floppy->mon_w(!BIT(data, 7)); + if (BIT(data, 0)) + m_floppy->dskchg_w(0); + } + else + { + floppy0->mon_w(1); + } +} + + +WRITE_LINE_MEMBER(hp_ipc_state::irq_1) +{ + m_maincpu->set_input_line_and_vector(M68K_IRQ_1, state, M68K_INT_ACK_AUTOVECTOR); +} + +WRITE_LINE_MEMBER(hp_ipc_state::irq_2) +{ + m_maincpu->set_input_line_and_vector(M68K_IRQ_2, state, M68K_INT_ACK_AUTOVECTOR); +} + +WRITE_LINE_MEMBER(hp_ipc_state::irq_3) +{ + m_maincpu->set_input_line_and_vector(M68K_IRQ_3, state, M68K_INT_ACK_AUTOVECTOR); +} + +WRITE_LINE_MEMBER(hp_ipc_state::irq_4) +{ + m_maincpu->set_input_line_and_vector(M68K_IRQ_4, state, M68K_INT_ACK_AUTOVECTOR); +} + +WRITE_LINE_MEMBER(hp_ipc_state::irq_5) +{ + m_maincpu->set_input_line_and_vector(M68K_IRQ_5, state, M68K_INT_ACK_AUTOVECTOR); +} + +WRITE_LINE_MEMBER(hp_ipc_state::irq_6) +{ + m_maincpu->set_input_line_and_vector(M68K_IRQ_6, state, M68K_INT_ACK_AUTOVECTOR); +} + +WRITE_LINE_MEMBER(hp_ipc_state::irq_7) +{ + m_maincpu->set_input_line_and_vector(M68K_IRQ_7, state, M68K_INT_ACK_AUTOVECTOR); +} + + +void hp_ipc_state::machine_start() +{ + m_bus_error_timer = timer_alloc(0); + + m_bankdev->set_bank(1); + + m_lowest_ram_addr = 0x3c0000 - (m_ram->size() >> 1); + m_internal_ram = (uint16_t *) m_ram->pointer(); +} + +void hp_ipc_state::machine_reset() +{ + m_floppy = nullptr; +} + + +FLOPPY_FORMATS_MEMBER( hp_ipc_state::floppy_formats ) + FLOPPY_HP_IPC_FORMAT +FLOPPY_FORMATS_END + +static SLOT_INTERFACE_START( hp_ipc_floppies ) + SLOT_INTERFACE( "35dd", SONY_OA_D32W ) +SLOT_INTERFACE_END + +/* + * IRQ levels (page 5-4) + * + * 7 Soft reset from keyboard, non-maskable + * 6 Real-time clock or NBIR3 (ext. I/O) + * 5 Disc Drive or NBIR2 + * 4 GPU or NBIR1 + * 3 HP-IB, printer, or NBIR0 + * 2 HP-HIL devices (keyboard, mouse) + * 1 Real-time clock + */ static MACHINE_CONFIG_START(hp_ipc, hp_ipc_state) - /* basic machine hardware */ - MCFG_CPU_ADD("maincpu", M68000, 15920000 / 2) - MCFG_CPU_PROGRAM_MAP(hp_ipc_mem) + MCFG_CPU_ADD("maincpu", M68000, XTAL_15_92MHz / 2) + MCFG_CPU_PROGRAM_MAP(hp_ipc_mem_outer) + + MCFG_DEVICE_ADD("bankdev", ADDRESS_MAP_BANK, 0) + MCFG_DEVICE_PROGRAM_MAP(hp_ipc_mem_inner) + MCFG_ADDRESS_MAP_BANK_ENDIANNESS(ENDIANNESS_BIG) + MCFG_ADDRESS_MAP_BANK_ADDRBUS_WIDTH(25) + MCFG_ADDRESS_MAP_BANK_DATABUS_WIDTH(16) + MCFG_ADDRESS_MAP_BANK_STRIDE(0x1000000) + + // horizontal time = 60 us (min) + // ver.refresh period = ~300 us + // ver.period = 16.7ms (~60 hz) + MCFG_SCREEN_ADD_MONOCHROME("screen", RASTER, rgb_t::amber()) + MCFG_SCREEN_UPDATE_DEVICE("gpu", hp1ll3_device, screen_update) + MCFG_SCREEN_RAW_PARAMS(XTAL_6MHz * 2, 720, 0, 512, 278, 0, 256) +// when _desktop == 0: +// MCFG_SCREEN_RAW_PARAMS(XTAL_6MHz * 2, 720, 0, 640, 480, 0, 400) + MCFG_SCREEN_VBLANK_CALLBACK(DEVWRITELINE("mlc", hp_hil_mlc_device, ap_w)) // XXX actually it's driven by 555 (U59) + MCFG_DEFAULT_LAYOUT(layout_lcd) + + MCFG_SCREEN_PALETTE("palette") + MCFG_PALETTE_ADD_MONOCHROME("palette") + + MCFG_HP1LL3_ADD("gpu") +// MCFG_HP1LL3_IRQ_CALLBACK(WRITELINE(hp_ipc_state, irq_4)) + MCFG_VIDEO_SET_SCREEN("screen") + + // XXX actual clock is 1MHz; remove this workaround (and change 2000 to 100 in hp_ipc_dsk.cpp) + // XXX when floppy code correctly handles 600 rpm drives. + MCFG_WD2797_ADD("fdc", XTAL_2MHz) + MCFG_WD_FDC_INTRQ_CALLBACK(WRITELINE(hp_ipc_state, irq_5)) + MCFG_FLOPPY_DRIVE_ADD("fdc:0", hp_ipc_floppies, "35dd", hp_ipc_state::floppy_formats) + + MCFG_SOFTWARE_LIST_ADD("flop_list","hp_ipc") + + MCFG_DEVICE_ADD("rtc", MM58167, XTAL_32_768kHz) + MCFG_MM58167_IRQ_CALLBACK(WRITELINE(hp_ipc_state, irq_1)) +// MCFG_MM58167_STANDBY_IRQ_CALLBACK(WRITELINE(hp_ipc_state, irq_6)) + + MCFG_DEVICE_ADD("mlc", HP_HIL_MLC, XTAL_15_92MHz/2) + MCFG_HP_HIL_INT_CALLBACK(WRITELINE(hp_ipc_state, irq_2)) + MCFG_HP_HIL_NMI_CALLBACK(WRITELINE(hp_ipc_state, irq_7)) + MCFG_HP_HIL_SLOT_ADD("mlc", "hil1", hp_hil_devices, "hp_ipc_kbd") + + MCFG_RAM_ADD(RAM_TAG) + MCFG_RAM_DEFAULT_SIZE("512K") + MCFG_RAM_EXTRA_OPTIONS("768K,1M,1576K,2M,3M,4M,5M,6M,7M,7680K") MACHINE_CONFIG_END @@ -355,4 +767,4 @@ ROM_START(hp_ipc) ROM_END -COMP(1985, hp_ipc, 0, 0, hp_ipc, hp_ipc, driver_device, 0, "HP", "Integral Personal Computer", MACHINE_IS_SKELETON) +COMP(1985, hp_ipc, 0, 0, hp_ipc, hp_ipc, driver_device, 0, "HP", "Integral Personal Computer", MACHINE_NO_SOUND|MACHINE_IMPERFECT_GRAPHICS|MACHINE_IMPERFECT_KEYBOARD)