diff --git a/hash/hp9845b_rom.xml b/hash/hp9845b_rom.xml
index f5586960f2e..9f419f6dfd0 100644
--- a/hash/hp9845b_rom.xml
+++ b/hash/hp9845b_rom.xml
@@ -10,7 +10,8 @@
-
+
+
@@ -24,7 +25,8 @@
-
+
+
@@ -38,7 +40,8 @@
-
+
+
@@ -53,7 +56,8 @@
-
+
+
@@ -67,7 +71,9 @@
-
+
+
+
@@ -81,7 +87,8 @@
-
+
+
@@ -95,7 +102,8 @@
-
+
+
@@ -109,7 +117,8 @@
-
+
+
@@ -123,7 +132,8 @@
-
+
+
@@ -136,7 +146,8 @@
-
+
+
@@ -150,7 +161,8 @@
-
+
+
@@ -159,6 +171,7 @@
+
IMAGE/45 Database Manager (Rev B)
198?
@@ -179,6 +192,7 @@
+
IMAGE/45 Database Manager (Rev C)
198?
@@ -206,12 +220,14 @@
-
+
+
+
Resource Management
198?
@@ -237,7 +253,8 @@
-
+
+
@@ -251,7 +268,8 @@
-
+
+
@@ -267,7 +285,8 @@
-
+
+
@@ -281,7 +300,8 @@
-
+
+
@@ -297,7 +317,8 @@
-
+
+
@@ -314,7 +335,8 @@
-
+
+
diff --git a/scripts/src/bus.lua b/scripts/src/bus.lua
index cd9923ea1fc..e5545c46287 100644
--- a/scripts/src/bus.lua
+++ b/scripts/src/bus.lua
@@ -2673,3 +2673,14 @@ if (BUSES["SVI_SLOT"]~=null) then
MAME_DIR .. "src/devices/bus/svi3x8/slot/sv807.h",
}
end
+
+---------------------------------------------------
+--
+--@src/devices/bus/hp_optroms/hp_optrom.h,BUSES["HP_OPTROM"] = true
+---------------------------------------------------
+
+if (BUSES["HP_OPTROM"]~=null) then
+ files {
+ MAME_DIR .. "src/devices/bus/hp_optroms/hp_optrom.cpp",
+ }
+end
diff --git a/scripts/target/mame/mess.lua b/scripts/target/mame/mess.lua
index 93039ee80bd..38f515ecffa 100644
--- a/scripts/target/mame/mess.lua
+++ b/scripts/target/mame/mess.lua
@@ -623,6 +623,7 @@ BUSES["INTV_CTRL"] = true
BUSES["IQ151"] = true
BUSES["ISA"] = true
BUSES["ISBX"] = true
+BUSES["HP_OPTROM"] = true
BUSES["KC"] = true
BUSES["LPCI"] = true
BUSES["M5"] = true
diff --git a/src/devices/bus/hp_optroms/hp_optrom.cpp b/src/devices/bus/hp_optroms/hp_optrom.cpp
new file mode 100644
index 00000000000..74391e96838
--- /dev/null
+++ b/src/devices/bus/hp_optroms/hp_optrom.cpp
@@ -0,0 +1,151 @@
+// license:BSD-3-Clause
+// copyright-holders: F. Ulivi
+/*********************************************************************
+
+ hp_optrom.cpp
+
+ Optional ROMs for HP9845 systems
+
+*********************************************************************/
+
+#include "hp_optrom.h"
+#include "softlist.h"
+#include "cpu/hphybrid/hphybrid.h"
+
+const device_type HP_OPTROM_CART = &device_creator;
+const device_type HP_OPTROM_SLOT = &device_creator;
+
+// +---------------------+
+// |hp_optrom_cart_device|
+// +---------------------+
+hp_optrom_cart_device::hp_optrom_cart_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) :
+ device_t(mconfig, type, name, tag, owner, clock, shortname, source),
+ device_slot_card_interface(mconfig, *this)
+{
+}
+
+hp_optrom_cart_device::hp_optrom_cart_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) :
+ device_t(mconfig, HP_OPTROM_CART, "HP9845 optional ROM cartridge", tag, owner, clock, "hp_optrom_cart", __FILE__),
+ device_slot_card_interface(mconfig, *this)
+{
+}
+
+// +---------------------+
+// |hp_optrom_slot_device|
+// +---------------------+
+hp_optrom_slot_device::hp_optrom_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) :
+ device_t(mconfig, HP_OPTROM_SLOT, "HP9845 optional ROM Slot", tag, owner, clock, "hp_optrom_slot", __FILE__),
+ device_image_interface(mconfig, *this),
+ device_slot_interface(mconfig, *this),
+ m_cart(nullptr),
+ m_base_addr(0),
+ m_end_addr(0)
+{
+}
+
+hp_optrom_slot_device::~hp_optrom_slot_device()
+{
+}
+
+void hp_optrom_slot_device::device_start()
+{
+ m_cart = dynamic_cast(get_card_device());
+}
+
+void hp_optrom_slot_device::device_config_complete()
+{
+ update_names(HP_OPTROM_SLOT , "optional_rom" , "optrom");
+}
+
+bool hp_optrom_slot_device::call_load()
+{
+ logerror("hp_optrom: call_load\n");
+ if (m_cart == nullptr || !m_from_swlist) {
+ logerror("hp_optrom: fail 1\n");
+ return IMAGE_INIT_FAIL;
+ }
+
+ const software_part *part_ptr = part_entry();
+ if (part_ptr == nullptr) {
+ logerror("hp_optrom: fail 2\n");
+ return IMAGE_INIT_FAIL;
+ }
+
+ const char *base_feature = part_ptr->feature("base");
+ if (base_feature == nullptr) {
+ logerror("hp_optrom: no 'base' feature\n");
+ return IMAGE_INIT_FAIL;
+ }
+
+ offs_t base_addr;
+ if (base_feature[ 0 ] != '0' || base_feature[ 1 ] != 'x' || sscanf(&base_feature[ 2 ] , "%x" , &base_addr) != 1) {
+ logerror("hp_optrom: can't parse 'base' feature\n");
+ return IMAGE_INIT_FAIL;
+ }
+
+ // Valid BSC values for ROMs on LPU drawer: 0x07 0x0b .... 0x3b
+ // Valid BSC values for ROMs on PPU drawer: 0x09 0x0d .... 0x3d
+ // (BSC is field in bits 16..21 of base address)
+ // Bit 15 of base address must be 0
+ // Base address must be multiple of 0x1000
+ if ((base_addr & ~0x3f7000UL) != 0 || ((base_addr & 0x30000) != 0x10000 && (base_addr & 0x30000) != 0x30000) || base_addr < 0x70000) {
+ logerror("hp_optrom: illegal base address (%x)\n" , base_addr);
+ return IMAGE_INIT_FAIL;
+ }
+
+ auto length = get_software_region_length("rom") / 2;
+
+ if (length < 0x1000 || length > 0x8000 || (length & 0xfff) != 0 || ((base_addr & 0x7000) + length) > 0x8000) {
+ logerror("hp_optrom: illegal region length (%x)\n" , length);
+ return IMAGE_INIT_FAIL;
+ }
+
+ offs_t end_addr = base_addr + length - 1;
+ logerror("hp_optrom: base_addr = %06x end_addr = %06x\n" , base_addr , end_addr);
+
+ m_content.resize(length * 2);
+ UINT8 *buffer = m_content.data();
+ memcpy(buffer , get_software_region("rom") , length * 2);
+
+ // Install ROM in address space of every CPU
+ device_interface_iterator iter(machine().root_device());
+ for (hp_hybrid_cpu_device *cpu = iter.first(); cpu != nullptr; cpu = iter.next()) {
+ logerror("hp_optrom: install in %s AS\n" , cpu->tag());
+ cpu->space(AS_PROGRAM).install_rom(base_addr , end_addr , buffer);
+ }
+
+ m_base_addr = base_addr;
+ m_end_addr = end_addr;
+
+ return IMAGE_INIT_PASS;
+}
+
+void hp_optrom_slot_device::call_unload()
+{
+ logerror("hp_optrom: call_unload\n");
+ if (m_cart != nullptr && m_base_addr != 0 && m_end_addr != 0) {
+ device_interface_iterator iter(machine().root_device());
+ for (hp_hybrid_cpu_device *cpu = iter.first(); cpu != nullptr; cpu = iter.next()) {
+ cpu->space(AS_PROGRAM).unmap_read(m_base_addr , m_end_addr);
+ }
+ m_content.resize(0);
+ m_base_addr = 0;
+ m_end_addr = 0;
+ }
+}
+
+bool hp_optrom_slot_device::call_softlist_load(software_list_device &swlist, const char *swname, const rom_entry *start_entry)
+{
+ logerror("hp_optrom: call_softlist_load\n");
+ machine().rom_load().load_software_part_region(*this, swlist, swname, start_entry);
+ return TRUE;
+}
+
+std::string hp_optrom_slot_device::get_default_card_software()
+{
+ return software_get_default_slot("rom");
+}
+
+SLOT_INTERFACE_START(hp_optrom_slot_device)
+ SLOT_INTERFACE_INTERNAL("rom", HP_OPTROM_CART)
+SLOT_INTERFACE_END
diff --git a/src/devices/bus/hp_optroms/hp_optrom.h b/src/devices/bus/hp_optroms/hp_optrom.h
new file mode 100644
index 00000000000..a18fd5e4087
--- /dev/null
+++ b/src/devices/bus/hp_optroms/hp_optrom.h
@@ -0,0 +1,74 @@
+// license:BSD-3-Clause
+// copyright-holders: F. Ulivi
+/*********************************************************************
+
+ hp_optrom.h
+
+ Optional ROMs for HP9845 systems
+
+*********************************************************************/
+
+#pragma once
+
+#ifndef _HP_OPTROM_H_
+#define _HP_OPTROM_H_
+
+#include "emu.h"
+
+class hp_optrom_cart_device : public device_t,
+ public device_slot_card_interface
+{
+public:
+ // construction/destruction
+ hp_optrom_cart_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source);
+ hp_optrom_cart_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start() override {}
+};
+
+class hp_optrom_slot_device : public device_t,
+ public device_image_interface,
+ public device_slot_interface
+{
+public:
+ // construction/destruction
+ hp_optrom_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+ virtual ~hp_optrom_slot_device();
+
+ // device-level overrides
+ virtual void device_start() override;
+ virtual void device_config_complete() override;
+
+ // image-level overrides
+ virtual bool call_load() override;
+ virtual void call_unload() override;
+ virtual bool call_softlist_load(software_list_device &swlist, const char *swname, const rom_entry *start_entry) override;
+
+ virtual iodevice_t image_type() const override { return IO_CARTSLOT; }
+ virtual bool is_readable() const override { return true; }
+ virtual bool is_writeable() const override { return false; }
+ virtual bool is_creatable() const override { return false; }
+ virtual bool must_be_loaded() const override { return false; }
+ virtual bool is_reset_on_load() const override { return true; }
+ virtual const option_guide *create_option_guide() const override { return nullptr; }
+ virtual const char *image_interface() const override { return "hp9845b_rom"; }
+ virtual const char *file_extensions() const override { return "bin"; }
+
+ // slot interface overrides
+ virtual std::string get_default_card_software() override;
+
+protected:
+ hp_optrom_cart_device *m_cart;
+ dynamic_buffer m_content;
+ offs_t m_base_addr;
+ offs_t m_end_addr;
+};
+
+// device type definition
+extern const device_type HP_OPTROM_SLOT;
+extern const device_type HP_OPTROM_CART;
+
+SLOT_INTERFACE_EXTERN(hp_optrom_slot_device);
+
+#endif /* _HP_OPTROM_H_ */
diff --git a/src/mame/drivers/hp9845.cpp b/src/mame/drivers/hp9845.cpp
index 4890b0ad92e..9353ab4ed48 100644
--- a/src/mame/drivers/hp9845.cpp
+++ b/src/mame/drivers/hp9845.cpp
@@ -18,22 +18,22 @@
// - Text mode screen
// - Keyboard
// - T15 tape drive
+// - Software list to load optional ROMs
// What's not yet in:
// - Beeper
// - Graphic screen
// - Better naming of tape drive image (it's now "magt", should be "t15")
// - Better documentation of this file
-// - Software list to load optional ROMs
// What's wrong:
// - I'm using character generator from HP64K (another driver of mine): no known dump of the original one
// - Speed, as usual
-// - There are a couple of undocumented opcodes that PPU executes at each keyboard interrupt: don't know if ignoring them is a Bad Thing (tm) or not
#include "emu.h"
#include "cpu/z80/z80.h"
#include "softlist.h"
#include "cpu/hphybrid/hphybrid.h"
#include "machine/hp_taco.h"
+#include "bus/hp_optroms/hp_optrom.h"
#define BIT_MASK(n) (1U << (n))
@@ -674,7 +674,6 @@ static ADDRESS_MAP_START(global_mem_map , AS_PROGRAM , 16 , hp9845b_state)
AM_RANGE(0x014000 , 0x017fff) AM_RAM AM_SHARE("ppu_ram")
AM_RANGE(0x030000 , 0x037fff) AM_ROM AM_REGION("lpu" , 0)
AM_RANGE(0x050000 , 0x057fff) AM_ROM AM_REGION("ppu" , 0)
-//AM_RANGE(0x250000 , 0x251fff) AM_ROM AM_REGION("test_rom" , 0)
ADDRESS_MAP_END
static ADDRESS_MAP_START(ppu_io_map , AS_IO , 16 , hp9845b_state)
@@ -719,6 +718,16 @@ static MACHINE_CONFIG_START( hp9845b, hp9845b_state )
MCFG_TACO_FLG_HANDLER(WRITELINE(hp9845b_state , t15_flg_w))
MCFG_TACO_STS_HANDLER(WRITELINE(hp9845b_state , t15_sts_w))
+ // In real machine there were 8 slots for LPU ROMs and 8 slots for PPU ROMs in
+ // right-hand side and left-hand side drawers, respectively.
+ // Here we do away with the distinction between LPU & PPU ROMs: in the end they
+ // are visible to both CPUs at the same addresses.
+ // For now we define just a couple of slots..
+ MCFG_DEVICE_ADD("drawer1", HP_OPTROM_SLOT, 0)
+ MCFG_DEVICE_SLOT_INTERFACE(hp_optrom_slot_device, NULL, false)
+ MCFG_DEVICE_ADD("drawer2", HP_OPTROM_SLOT, 0)
+ MCFG_DEVICE_SLOT_INTERFACE(hp_optrom_slot_device, NULL, false)
+
MCFG_SOFTWARE_LIST_ADD("optrom_list", "hp9845b_rom")
MACHINE_CONFIG_END
@@ -755,10 +764,6 @@ ROM_END
#define rom_hp9835b rom_hp9835a
ROM_START( hp9845b )
- ROM_REGION(0x4000 , "test_rom" , ROMREGION_16BIT | ROMREGION_BE)
- ROM_LOAD("09845-66520-45_00-Test_ROM.bin" , 0x0000 , 0x2000 , CRC(95a5b299))
- ROM_LOAD("09845-66520-45_10-Test_ROM.bin" , 0x2000 , 0x2000 , CRC(257e4c66))
-
ROM_REGION(0x800 , "chargen" , 0)
// Don't have the real character generator from HP9845, use the one from HP64000 for now
ROM_LOAD("1818_2668.bin" , 0 , 0x800 , BAD_DUMP CRC(32a52664) SHA1(8b2a49a32510103ff424e8481d5ed9887f609f2f))