diff --git a/hash/hp_ipc_rom.xml b/hash/hp_ipc_rom.xml
new file mode 100644
index 00000000000..b2fe442e907
--- /dev/null
+++ b/hash/hp_ipc_rom.xml
@@ -0,0 +1,22 @@
+
+
+
+
+
+
+ Software Engineering ROM
+ 1986
+ Hewlett-Packard
+
+
+
+
+
+
+
+
+
+
+
diff --git a/scripts/target/mame/mess.lua b/scripts/target/mame/mess.lua
index a3ce421a8c3..8dd3c92a5ff 100644
--- a/scripts/target/mame/mess.lua
+++ b/scripts/target/mame/mess.lua
@@ -2603,6 +2603,8 @@ files {
MAME_DIR .. "src/mame/machine/hp9845_printer.h",
MAME_DIR .. "src/mame/machine/hp98x5_io_sys.cpp",
MAME_DIR .. "src/mame/machine/hp98x5_io_sys.h",
+ MAME_DIR .. "src/mame/machine/hp_ipc_optrom.cpp",
+ MAME_DIR .. "src/mame/machine/hp_ipc_optrom.h",
MAME_DIR .. "src/mame/video/hp48.cpp",
MAME_DIR .. "src/mame/drivers/hp49gp.cpp",
MAME_DIR .. "src/mame/drivers/hp9845.cpp",
diff --git a/src/mame/drivers/hp_ipc.cpp b/src/mame/drivers/hp_ipc.cpp
index c963b061497..74e05e364de 100644
--- a/src/mame/drivers/hp_ipc.cpp
+++ b/src/mame/drivers/hp_ipc.cpp
@@ -374,6 +374,7 @@ Software to look for
#include "sound/dac.h"
#include "machine/input_merger.h"
#include "bus/hp_ipc_io/hp_ipc_io.h"
+#include "machine/hp_ipc_optrom.h"
#include "emupal.h"
#include "screen.h"
@@ -398,6 +399,7 @@ public:
, m_irq6_merger(*this , "merge_irq6")
, m_io_slot_a(*this , "slot_a")
, m_io_slot_b(*this , "slot_b")
+ , m_rom_slots(*this , "rom%u" , 0)
{ }
void hp_ipc_base(machine_config &config);
@@ -452,6 +454,7 @@ private:
required_device m_irq6_merger;
required_device m_io_slot_a;
required_device m_io_slot_b;
+ required_device_array m_rom_slots;
uint32_t m_mmu[4], m_lowest_ram_addr;
uint16_t *m_internal_ram;
@@ -744,6 +747,15 @@ void hp_ipc_state::machine_reset()
m_spkr->cs_w(1);
m_spkr->sk_w(0);
m_spkr->di_w(0);
+
+ // Load optional ROMs (if any)
+ // But first unload anything in opt ROM range
+ m_bankdev->space().unmap_read(0x100000 , 0x4fffff);
+ m_bankdev->space().unmap_read(0x100000 + 0x1800000, 0x4fffff + 0x1800000);
+
+ for (auto& slot : m_rom_slots) {
+ slot->install_read_handler(m_bankdev->space());
+ }
}
@@ -781,6 +793,7 @@ void hp_ipc_state::hp_ipc_base(machine_config &config)
FLOPPY_CONNECTOR(config, "fdc:0", hp_ipc_floppies, "35dd", hp_ipc_state::floppy_formats);
SOFTWARE_LIST(config, "flop_list").set_original("hp_ipc");
+ SOFTWARE_LIST(config, "rom_list").set_original("hp_ipc_rom");
mm58167_device &rtc(MM58167(config, "rtc", 32.768_kHz_XTAL));
rtc.irq().set(FUNC(hp_ipc_state::irq_1));
@@ -841,6 +854,11 @@ void hp_ipc_state::hp_ipc_base(machine_config &config)
m_io_slot_b->irq5_cb().set(m_irq5_merger , FUNC(input_merger_any_high_device::in_w<2>));
m_io_slot_b->irq6_cb().set(m_irq6_merger , FUNC(input_merger_any_high_device::in_w<2>));
+ // Optional ROMs
+ for (auto& finder : m_rom_slots) {
+ HP_IPC_OPTROM(config, finder);
+ }
+
RAM(config, RAM_TAG).set_default_size("512K").set_extra_options("768K,1M,1576K,2M,3M,4M,5M,6M,7M,7680K");
}
diff --git a/src/mame/machine/hp_ipc_optrom.cpp b/src/mame/machine/hp_ipc_optrom.cpp
new file mode 100644
index 00000000000..75b66ec7a67
--- /dev/null
+++ b/src/mame/machine/hp_ipc_optrom.cpp
@@ -0,0 +1,84 @@
+// license:BSD-3-Clause
+// copyright-holders: F. Ulivi
+/*********************************************************************
+
+ hp_ipc_optrom.cpp
+
+ Optional ROMs for HP Integral PC
+
+*********************************************************************/
+
+#include "emu.h"
+#include "hp_ipc_optrom.h"
+#include "softlist.h"
+
+// Debugging
+#define VERBOSE 1
+#include "logmacro.h"
+
+DEFINE_DEVICE_TYPE(HP_IPC_OPTROM, hp_ipc_optrom_device, "hp_ipc_optrom", "HP IPC optional ROM")
+
+// +--------------------+
+// |hp_ipc_optrom_device|
+// +--------------------+
+hp_ipc_optrom_device::hp_ipc_optrom_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : device_t(mconfig, HP_IPC_OPTROM, tag, owner, clock)
+ , device_image_interface(mconfig, *this)
+ , m_base(0)
+{
+}
+
+hp_ipc_optrom_device::~hp_ipc_optrom_device()
+{
+}
+
+void hp_ipc_optrom_device::install_read_handler(address_space& space)
+{
+ if (loaded_through_softlist()) {
+ auto region = get_software_region("rom");
+ auto len = get_software_region_length("rom");
+
+ // Supervisor mode
+ space.install_rom(m_base , m_base + len - 1 , region);
+ // User mode
+ space.install_rom(m_base + 0x1800000 , m_base + 0x1800000 + len - 1 , region);
+ }
+}
+
+void hp_ipc_optrom_device::device_start()
+{
+}
+
+image_init_result hp_ipc_optrom_device::call_load()
+{
+ LOG("hp_ipc_optrom: call_load\n");
+ if (!loaded_through_softlist()) {
+ LOG("hp_ipc_optrom: must be loaded from sw list\n");
+ return image_init_result::FAIL;
+ }
+
+ const char *base_feature = get_feature("base");
+ if (base_feature == nullptr) {
+ LOG("hp_ipc_optrom: no 'base' feature\n");
+ return image_init_result::FAIL;
+ }
+
+ if (base_feature[ 0 ] != '0' || base_feature[ 1 ] != 'x' || sscanf(&base_feature[ 2 ] , "%x" , &m_base) != 1) {
+ LOG("hp_ipc_optrom: can't parse 'base' feature\n");
+ return image_init_result::FAIL;
+ }
+
+ // Valid base values: multiple of 1M, [0x100000..0x4fffff]
+ if ((m_base & 0xfffffU) != 0 || m_base < 0x100000U || m_base > 0x400000U) {
+ LOG("hp_ipc_optrom: illegal base (%x)\n" , m_base);
+ return image_init_result::FAIL;
+ }
+
+ LOG("hp_ipc_optrom: loaded base=0x%06x\n" , m_base);
+ return image_init_result::PASS;
+}
+
+void hp_ipc_optrom_device::call_unload()
+{
+ LOG("hp_ipc_optrom: call_unload\n");
+}
diff --git a/src/mame/machine/hp_ipc_optrom.h b/src/mame/machine/hp_ipc_optrom.h
new file mode 100644
index 00000000000..93872a0a5b8
--- /dev/null
+++ b/src/mame/machine/hp_ipc_optrom.h
@@ -0,0 +1,58 @@
+// license:BSD-3-Clause
+// copyright-holders: F. Ulivi
+/*********************************************************************
+
+ hp_ipc_optrom.h
+
+ Optional ROMs for HP Integral PC
+
+*********************************************************************/
+
+#ifndef MAME_MACHINE_HP_IPC_OPTROM_H
+#define MAME_MACHINE_HP_IPC_OPTROM_H
+
+#pragma once
+
+#include "softlist_dev.h"
+
+class hp_ipc_optrom_device : public device_t,
+ public device_image_interface
+{
+public:
+ // construction/destruction
+ hp_ipc_optrom_device(machine_config const &mconfig, char const *tag, device_t *owner)
+ : hp_ipc_optrom_device(mconfig, tag, owner, (uint32_t)0)
+ {
+ }
+
+ hp_ipc_optrom_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+ virtual ~hp_ipc_optrom_device();
+
+ void install_read_handler(address_space& space);
+
+protected:
+ // device-level overrides
+ virtual void device_start() override;
+
+ // image-level overrides
+ virtual image_init_result call_load() override;
+ virtual void call_unload() override;
+ virtual const software_list_loader &get_software_list_loader() const override { return rom_software_list_loader::instance(); }
+
+ virtual iodevice_t image_type() const noexcept override { return IO_ROM; }
+ virtual bool is_readable() const noexcept override { return true; }
+ virtual bool is_writeable() const noexcept override { return false; }
+ virtual bool is_creatable() const noexcept override { return false; }
+ virtual bool must_be_loaded() const noexcept override { return false; }
+ virtual bool is_reset_on_load() const noexcept override { return true; }
+ virtual const char *image_interface() const noexcept override { return "hp_ipc_rom"; }
+ virtual const char *file_extensions() const noexcept override { return "bin"; }
+
+private:
+ offs_t m_base;
+};
+
+// device type definition
+DECLARE_DEVICE_TYPE(HP_IPC_OPTROM, hp_ipc_optrom_device)
+
+#endif // MAME_MACHINE_HP_IPC_OPTROM_H