diff --git a/hash/hp98x6_rom.xml b/hash/hp98x6_rom.xml
new file mode 100644
index 00000000000..1f76cda4bf4
--- /dev/null
+++ b/hash/hp98x6_rom.xml
@@ -0,0 +1,46 @@
+
+
+
+
+
+
+ BASIC 4.0
+ 1985
+ Hewlett-Packard
+
+
+
+
+
+
+
+
+
+ BASIC 5.1
+ 1988
+ Hewlett-Packard
+
+
+
+
+
+
+
+
+
+ SSS HPL+II
+ 1992
+ Structured Software Systems
+
+
+
+
+
+
+
+
diff --git a/src/mame/hp/hp98x6.cpp b/src/mame/hp/hp98x6.cpp
index 62131e52d42..c1f04569d50 100644
--- a/src/mame/hp/hp98x6.cpp
+++ b/src/mame/hp/hp98x6.cpp
@@ -22,6 +22,7 @@
// | Knob | * | * | * | * |
// | Beeper | * | * | * | * |
// | ID PROM | * | * | * | * |
+// | Option ROMs | * | * | * | * |
// | B/W 80x25 text video w/ attributes | * | | * | |
// | B/W 50x25 text video w/ attributes | | * | | |
// | B/W 400x300 graphic video | * | * | | |
@@ -37,7 +38,6 @@
//
// What's not in for all the models:
// - Expansion cards
-// - Option ROMs
//
// Main references:
// - Olivier De Smet's standalone emulator:
@@ -47,6 +47,7 @@
#include "emu.h"
+#include "hp98x6_optrom.h"
#include "hp98x6_upi.h"
#include "bus/ieee488/ieee488.h"
@@ -63,6 +64,7 @@
#include "emupal.h"
#include "screen.h"
+#include "softlist_dev.h"
// Debugging
#define LOG_FDC_MASK (LOG_GENERAL << 1)
@@ -137,6 +139,7 @@ protected:
, m_upi(*this, "upi")
, m_hpib(*this, "hpib")
, m_chargen(*this, "chargen")
+ , m_rom_drawers(*this, "drawer%u", 0U)
{
}
@@ -161,6 +164,8 @@ protected:
// Character generator
required_region_ptr m_chargen;
+ required_device_array m_rom_drawers;
+
bool m_hsync_en;
bool m_graphic_en;
bool m_hpib_irq;
@@ -176,7 +181,13 @@ void hp98x6_base_state::machine_start()
save_item(NAME(m_hpib_dma_en));
save_item(NAME(m_upi_irq7));
- m_cpu->space(AS_PROGRAM).install_ram(0x1000000 - m_ram->size(), 0xffffff, m_ram->pointer());
+ auto space = &m_cpu->space(AS_PROGRAM);
+
+ space->install_ram(0x1000000 - m_ram->size(), 0xffffff, m_ram->pointer());
+
+ for (auto& finder : m_rom_drawers) {
+ finder->install_handlers(space);
+ }
}
void hp98x6_base_state::machine_reset()
@@ -228,6 +239,13 @@ void hp98x6_base_state::hp98x6_base(machine_config &config, unsigned dot_clock,
ieee.ren_callback().set(m_hpib , FUNC(tms9914_device::ren_w));
IEEE488_SLOT(config, "ieee_dev", 0, hp_ieee488_devices, nullptr);
IEEE488_SLOT(config, "ieee_rem", 0, remote488_devices, nullptr);
+
+ // Optional ROM slots
+ for (auto& finder : m_rom_drawers) {
+ HP98X6_OPTROM(config, finder);
+ }
+
+ SOFTWARE_LIST(config, "optrom_list").set_original("hp98x6_rom");
}
void hp98x6_base_state::cpu_mem_map(address_map &map)
diff --git a/src/mame/hp/hp98x6_optrom.cpp b/src/mame/hp/hp98x6_optrom.cpp
new file mode 100644
index 00000000000..6bc6ac06385
--- /dev/null
+++ b/src/mame/hp/hp98x6_optrom.cpp
@@ -0,0 +1,92 @@
+// license:BSD-3-Clause
+// copyright-holders: F. Ulivi
+/*********************************************************************
+
+ hp98x6_optrom.cpp
+
+ Optional ROMs for HP98x6 systems
+
+*********************************************************************/
+
+#include "emu.h"
+#include "hp98x6_optrom.h"
+#include "softlist.h"
+
+// Debugging
+#define VERBOSE 0
+#include "logmacro.h"
+
+DEFINE_DEVICE_TYPE(HP98X6_OPTROM, hp98x6_optrom_device, "hp98x6_optrom", "HP98x6 optional ROM")
+
+struct optrom_region {
+ offs_t m_start;
+ const char *m_tag;
+};
+
+constexpr std::array region_tab =
+ {{
+ { 0x100000, "rom100000" },
+ { 0x80000, "rom80000" }
+ }};
+
+// +--------------------+
+// |hp98x6_optrom_device|
+// +--------------------+
+hp98x6_optrom_device::hp98x6_optrom_device(machine_config const &mconfig, char const *tag, device_t *owner)
+ : hp98x6_optrom_device(mconfig, tag, owner, (uint32_t)0)
+{
+}
+
+hp98x6_optrom_device::hp98x6_optrom_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : device_t(mconfig, HP98X6_OPTROM, tag, owner, clock)
+ , device_rom_image_interface(mconfig, *this)
+ , m_space_r(nullptr)
+{
+}
+
+hp98x6_optrom_device::~hp98x6_optrom_device()
+{
+}
+
+void hp98x6_optrom_device::install_handlers(address_space *space_r)
+{
+ m_space_r = space_r;
+
+ for (const struct optrom_region& reg : region_tab) {
+ uint8_t *ptr = get_software_region(reg.m_tag);
+ if (ptr != nullptr) {
+ auto len = get_software_region_length(reg.m_tag);
+ LOG("%s loaded, %u long\n", reg.m_tag, len);
+ space_r->install_rom(reg.m_start , reg.m_start + len - 1 , ptr);
+ }
+ }
+}
+
+void hp98x6_optrom_device::device_start()
+{
+}
+
+std::pair hp98x6_optrom_device::call_load()
+{
+ LOG("hp98x6_optrom: call_load\n");
+ if (!loaded_through_softlist()) {
+ return std::make_pair(image_error::UNSUPPORTED, "Option ROMs must be loaded from software list");
+ }
+
+ return std::make_pair(std::error_condition(), std::string());
+}
+
+void hp98x6_optrom_device::call_unload()
+{
+ LOG("hp98x6_optrom: call_unload\n");
+ if (m_space_r != nullptr) {
+ for (const struct optrom_region& reg : region_tab) {
+ auto len = get_software_region_length(reg.m_tag);
+ if (len != 0) {
+ m_space_r->unmap_read(reg.m_start , reg.m_start + len - 1);
+ LOG("%s unloaded\n" , reg.m_tag);
+ }
+ }
+ }
+ machine().schedule_soft_reset();
+}
diff --git a/src/mame/hp/hp98x6_optrom.h b/src/mame/hp/hp98x6_optrom.h
new file mode 100644
index 00000000000..44541403bd0
--- /dev/null
+++ b/src/mame/hp/hp98x6_optrom.h
@@ -0,0 +1,46 @@
+// license:BSD-3-Clause
+// copyright-holders: F. Ulivi
+/*********************************************************************
+
+ hp98x6_optrom.h
+
+ Optional ROMs for HP98x6 systems
+
+*********************************************************************/
+#ifndef MAME_HP_HP98X6_OPTROM_H
+#define MAME_HP_HP98X6_OPTROM_H
+
+#pragma once
+
+#include "imagedev/cartrom.h"
+
+class hp98x6_optrom_device : public device_t,
+ public device_rom_image_interface
+{
+public:
+ // construction/destruction
+ hp98x6_optrom_device(machine_config const &mconfig, char const *tag, device_t *owner);
+ hp98x6_optrom_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+ virtual ~hp98x6_optrom_device();
+
+ void install_handlers(address_space *space_r);
+
+protected:
+ // device_t implementation
+ virtual void device_start() override;
+
+ // device_image_interface implementation
+ virtual std::pair call_load() override;
+ virtual void call_unload() override;
+
+ virtual bool is_reset_on_load() const noexcept override { return true; }
+ virtual const char *image_interface() const noexcept override { return "hp98x6_rom"; }
+ virtual const char *file_extensions() const noexcept override { return "bin"; }
+
+ address_space *m_space_r;
+};
+
+// device type definition
+DECLARE_DEVICE_TYPE(HP98X6_OPTROM, hp98x6_optrom_device)
+
+#endif /* MAME_HP_HP98X6_OPTROM_H */