summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
-rw-r--r--scripts/src/bus.lua17
-rw-r--r--scripts/src/formats.lua12
-rw-r--r--scripts/src/video.lua12
-rw-r--r--scripts/target/mame/mess.lua3
-rw-r--r--src/devices/bus/hp_hil/hil_devices.cpp11
-rw-r--r--src/devices/bus/hp_hil/hil_devices.h25
-rw-r--r--src/devices/bus/hp_hil/hlekbd.cpp412
-rw-r--r--src/devices/bus/hp_hil/hlekbd.h60
-rw-r--r--src/devices/bus/hp_hil/hp_hil.cpp282
-rw-r--r--src/devices/bus/hp_hil/hp_hil.h200
-rw-r--r--src/devices/video/hp1ll3.cpp713
-rw-r--r--src/devices/video/hp1ll3.h176
-rw-r--r--src/emu/drivers/xtal.h1
-rw-r--r--src/lib/formats/hp_ipc_dsk.cpp42
-rw-r--r--src/lib/formats/hp_ipc_dsk.h30
-rw-r--r--src/mame/drivers/hp_ipc.cpp472
16 files changed, 2438 insertions, 30 deletions
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
@@ -717,6 +717,23 @@ 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
@@ -895,6 +895,18 @@ 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
@@ -366,6 +366,18 @@ 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<bus::hp_hil::hle_hp_ipc_device>;
+
+
+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<uint8_t, 8> 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<hp_hil_slot_device>;
+
+//**************************************************************************
+// 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<hp_hil_slot_device &>(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<device_hp_hil_interface *>(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>;
+
+
+//-------------------------------------------------
+// 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_interface &>(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<hp_hil_mlc_device *>(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<class _Object> static devcb_base &set_int_callback(device_t &device, _Object object) { return downcast<hp_hil_mlc_device &>(device).int_cb.set_callback(object); }
+ template<class _Object> static devcb_base &set_nmi_callback(device_t &device, _Object object) { return downcast<hp_hil_mlc_device &>(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<device_hp_hil_interface> m_device_list;
+
+ util::fifo<uint16_t, 16> 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<hp1ll3_device>;
+
+
+//**************************************************************************
+// 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<uint16_t[]>(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<uint16_t[]> 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 <assert.h>
+
+#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<hp_ipc_format>;
+
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<m68000_device> m_maincpu;
+ required_device<address_map_bank_device> m_bankdev;
+ required_device<wd2797_t> m_fdc;
+ required_device<ram_device> m_ram;
+ required_device<screen_device> m_screen;
+
+ uint32_t m_mmu[4], m_lowest_ram_addr;
+ uint16_t *m_internal_ram;
+ int m_fc;
- uint32_t m_mmu[4];
- uint16_t m_internal_ram[0x40000];
+ 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;
+ }
- 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<floppy_connector>("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)