diff --git a/hash/segaai.xml b/hash/segaai.xml
new file mode 100644
index 00000000000..90e60e2e7bd
--- /dev/null
+++ b/hash/segaai.xml
@@ -0,0 +1,740 @@
+
+
+
+
+
+
+
+ Alice World
+ 1988
+ Sega
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Alice World (tape, older)
+ 1986
+ Sega
+ Cassette is not supported yet.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Robinson Land
+ 1988
+ Sega
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Robinson Land (tape, older)
+ 1987
+ Sega
+ Cassette is not supported yet.
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Cosmic Train
+ 1988
+ Sega
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Cosmic Train (tape, older)
+ 1987
+ Sega
+ Cassette is not supported yet.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Cinderella Labyrinth
+ 1988
+ Sega
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Cinderella Labyrinth (tape, older)
+ 1986
+ Sega
+ Cassette is not supported yet.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Gulliver Pocket
+ 1988
+ Sega
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Gulliver Pocket (tape, older)
+ 1986
+ Sega
+ Cassette is not supported yet.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Mozart Academy
+ 1988
+ Sega
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Mozart Academy (tape, older)
+ 1986
+ Sega
+ Cassette is not supported yet.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Arabian Night
+ 1988
+ Sega
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Arabian Night (tape, older)
+ 1987
+ Sega
+ Cassette is not supported yet.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Andersen Dream
+ 1988
+ Sega
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Andersen Dream (tape, older)
+ 1987
+ Sega
+ Cassette is not supported yet.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Ocean Fantasy
+ 1988
+ Sega
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Ocean Fantasy (tape, older)
+ 1987
+ Sega
+ Cassette is not supported yet.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Columbus Map
+ 1988
+ Sega
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Columbus Map (tape, older)
+ 1987
+ Sega
+ Cassette is not supported yet.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Runrun Music
+ 1988
+ Sega
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Tantan Rhythm
+ 1988
+ Sega
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Ranran Melody
+ 1988
+ Sega
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Okeiko Hanamaru Aiueo
+ 1988
+ Sega
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Waku Waku ABC to 123
+ 1988
+ Sega
+
+
+
+
+
+
+
+
+
+
+
+ Henshin Kanji
+ 1988
+ Sega
+
+
+
+
+
+
+
+
+
+
+
+ Pinpon Numbers
+ 1987
+ Sega
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Pinpon Music Rhythm
+ 1987
+ Sega
+ No sound and cannot start a game.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Pinpon Music Melody
+ 1987
+ Sega
+ No sound and cannot start a game.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Eigo de Ohanashi - English Wonder School: Folk & Fairy Tales
+ 1989
+ Sega
+ Cassette is not supported yet.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Eigo de Game - English Wonder School: Popo's Adventure
+ 1989
+ Sega
+ Cassette is not supported yet. Eigo de Game 2: Only the first entry from the menu works, the color names and 'big' are spoken. The other menu entries hang waiting for the cassette.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ AI Enikki
+ 1989
+ Sega?
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ AI Enikki (1986)
+ 1986
+ Sega?
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/scripts/src/bus.lua b/scripts/src/bus.lua
index 0c84aa0dbe9..6d720410673 100644
--- a/scripts/src/bus.lua
+++ b/scripts/src/bus.lua
@@ -2395,6 +2395,25 @@ if (BUSES["S100"]~=null) then
end
+---------------------------------------------------
+--
+--@src/devices/bus/segaai/segaai_exp.h,BUSES["SEGAAI"] = true
+---------------------------------------------------
+
+if (BUSES["SEGAAI"]~=null) then
+ files {
+ MAME_DIR .. "src/devices/bus/segaai/rom.cpp",
+ MAME_DIR .. "src/devices/bus/segaai/rom.h",
+ MAME_DIR .. "src/devices/bus/segaai/segaai_exp.cpp",
+ MAME_DIR .. "src/devices/bus/segaai/segaai_exp.h",
+ MAME_DIR .. "src/devices/bus/segaai/segaai_slot.cpp",
+ MAME_DIR .. "src/devices/bus/segaai/segaai_slot.h",
+ MAME_DIR .. "src/devices/bus/segaai/soundbox.cpp",
+ MAME_DIR .. "src/devices/bus/segaai/soundbox.h",
+ }
+end
+
+
---------------------------------------------------
--
--@src/devices/bus/spc1000/exp.h,BUSES["SPC1000"] = true
diff --git a/src/devices/bus/segaai/rom.cpp b/src/devices/bus/segaai/rom.cpp
new file mode 100644
index 00000000000..1d7d613416e
--- /dev/null
+++ b/src/devices/bus/segaai/rom.cpp
@@ -0,0 +1,93 @@
+// license:BSD-3-Clause
+// copyright-holders:Wilbert Pol
+/***********************************************************************************************************
+
+ Sega AI card emulation
+
+ ***********************************************************************************************************/
+
+
+#include "emu.h"
+#include "rom.h"
+
+
+namespace {
+
+class segaai_rom_128_device : public device_t,
+ public segaai_card_interface
+{
+public:
+ segaai_rom_128_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
+ : segaai_rom_128_device(mconfig, SEGAAI_ROM_128, tag, owner, clock)
+ { }
+
+ virtual void install_memory_handlers(address_space *space) override;
+
+protected:
+ segaai_rom_128_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock)
+ : device_t(mconfig, type, tag, owner, clock)
+ , segaai_card_interface(mconfig, *this)
+ { }
+
+ virtual void device_start() override { }
+};
+
+void segaai_rom_128_device::install_memory_handlers(address_space *space)
+{
+ space->install_rom(0xa0000, 0xbffff, cart_rom_region()->base());
+}
+
+
+
+class segaai_rom_256_device : public segaai_rom_128_device
+{
+public:
+ segaai_rom_256_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
+ : segaai_rom_128_device(mconfig, SEGAAI_ROM_256, tag, owner, clock)
+ , m_rom_bank(*this, "rombank%u", 0U)
+ { }
+
+ virtual void install_memory_handlers(address_space *space) override;
+
+private:
+ template void bank_w(u8 data);
+ void unknown0_w(u8 data);
+ void unknown1_w(u8 data);
+
+ memory_bank_array_creator<2> m_rom_bank;
+};
+
+void segaai_rom_256_device::install_memory_handlers(address_space *space)
+{
+ for (int i = 0; i < 2; i++)
+ m_rom_bank[i]->configure_entries(0, cart_rom_region()->bytes() / 0x4000, cart_rom_region()->base(), 0x4000);
+
+ space->install_rom(0xa0000, 0xa3fff, 0x10000, cart_rom_region()->base());
+ space->install_read_bank(0xa4000, 0xa7fff, 0x10000, m_rom_bank[0]);
+ space->install_read_bank(0xa8000, 0xabfff, 0x10000, m_rom_bank[1]);
+ space->install_write_handler(0xafffc, 0xafffc, 0, 0x10000, 0, emu::rw_delegate(*this, FUNC(segaai_rom_256_device::unknown0_w)));
+ space->install_write_handler(0xafffd, 0xafffd, 0, 0x10000, 0, emu::rw_delegate(*this, FUNC(segaai_rom_256_device::unknown1_w)));
+ space->install_write_handler(0xafffe, 0xafffe, 0, 0x10000, 0, emu::rw_delegate(*this, FUNC(segaai_rom_256_device::bank_w<0>)));
+ space->install_write_handler(0xaffff, 0xaffff, 0, 0x10000, 0, emu::rw_delegate(*this, FUNC(segaai_rom_256_device::bank_w<1>)));
+}
+
+template
+void segaai_rom_256_device::bank_w(u8 data)
+{
+ m_rom_bank[Bank]->set_entry(data & 0x0f);
+}
+
+void segaai_rom_256_device::unknown0_w(u8 data)
+{
+ // Unknown, upon start $00 is written and sometimes $80 after that
+}
+
+void segaai_rom_256_device::unknown1_w(u8 data)
+{
+ // Unknown, upon start $00 is written
+}
+
+} // anonymous namespace
+
+DEFINE_DEVICE_TYPE_PRIVATE(SEGAAI_ROM_128, segaai_card_interface, segaai_rom_128_device, "segaai_rom_128", "Sega AI Card - 128KB")
+DEFINE_DEVICE_TYPE_PRIVATE(SEGAAI_ROM_256, segaai_card_interface, segaai_rom_256_device, "segaai_rom_256", "Sega AI Card - 256KB")
diff --git a/src/devices/bus/segaai/rom.h b/src/devices/bus/segaai/rom.h
new file mode 100644
index 00000000000..a9a830c7b78
--- /dev/null
+++ b/src/devices/bus/segaai/rom.h
@@ -0,0 +1,14 @@
+// license:BSD-3-Clause
+// copyright-holders:Wilbert Pol
+#ifndef MAME_BUS_SEGAAI_ROM_H
+#define MAME_BUS_SEGAAI_ROM_H
+
+#pragma once
+
+#include "segaai_slot.h"
+
+
+DECLARE_DEVICE_TYPE(SEGAAI_ROM_128, segaai_card_interface);
+DECLARE_DEVICE_TYPE(SEGAAI_ROM_256, segaai_card_interface);
+
+#endif
diff --git a/src/devices/bus/segaai/segaai_exp.cpp b/src/devices/bus/segaai/segaai_exp.cpp
new file mode 100644
index 00000000000..926cfd84d9b
--- /dev/null
+++ b/src/devices/bus/segaai/segaai_exp.cpp
@@ -0,0 +1,48 @@
+// license:BSD-3-Clause
+// copyright-holders:Wilbert Pol
+/***********************************************************************************************************
+
+ Sega AI Expansion slot emulation
+
+ ***********************************************************************************************************/
+
+
+#include "emu.h"
+#include "segaai_exp.h"
+
+DEFINE_DEVICE_TYPE(SEGAAI_EXP_SLOT, segaai_exp_slot_device, "segaai_exp_slot", "Sega AI Expansion Slot")
+
+
+segaai_exp_interface::segaai_exp_interface(const machine_config &mconfig, device_t &device)
+ : device_interface(device, "segaai_exp")
+ , m_slot(dynamic_cast(device.owner()))
+{
+}
+
+segaai_exp_interface::~segaai_exp_interface()
+{
+}
+
+
+
+segaai_exp_slot_device::segaai_exp_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
+ : device_t(mconfig, SEGAAI_EXP_SLOT, tag, owner, clock)
+ , device_single_card_slot_interface(mconfig, *this)
+ , m_mem_space(*this, finder_base::DUMMY_TAG, -1)
+ , m_io_space(*this, finder_base::DUMMY_TAG, -1)
+{
+}
+
+segaai_exp_slot_device::~segaai_exp_slot_device()
+{
+}
+
+
+// slot interfaces
+#include "soundbox.h"
+
+void segaai_exp(device_slot_interface &device)
+{
+ device.option_add("soundbox", SEGAAI_SOUNDBOX);
+}
+
diff --git a/src/devices/bus/segaai/segaai_exp.h b/src/devices/bus/segaai/segaai_exp.h
new file mode 100644
index 00000000000..c1d96166a11
--- /dev/null
+++ b/src/devices/bus/segaai/segaai_exp.h
@@ -0,0 +1,63 @@
+// license:BSD-3-Clause
+// copyright-holders:Wilbert Pol
+#ifndef MAME_BUS_SEGAAI_EXP_H
+#define MAME_BUS_SEGAAI_EXP_H
+
+#pragma once
+
+
+DECLARE_DEVICE_TYPE(SEGAAI_EXP_SLOT, segaai_exp_slot_device);
+
+
+class segaai_exp_interface;
+
+class segaai_exp_slot_device : public device_t,
+ public device_single_card_slot_interface
+{
+public:
+ template
+ segaai_exp_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock, T &&opts, const char *dflt)
+ : segaai_exp_slot_device(mconfig, tag, owner, clock)
+ {
+ option_reset();
+ opts(*this);
+ set_default_option(dflt);
+ set_fixed(false);
+ }
+ segaai_exp_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock);
+ virtual ~segaai_exp_slot_device();
+
+ template void set_mem_space(T &&tag, int no) { m_mem_space.set_tag(std::forward(tag), no); }
+ template void set_io_space(T &&tag, int no) { m_io_space.set_tag(std::forward(tag), no); }
+
+ address_space& mem_space() { return *m_mem_space; }
+ address_space& io_space() { return *m_io_space; }
+
+protected:
+ virtual void device_start() override { }
+
+private:
+ optional_address_space m_mem_space;
+ optional_address_space m_io_space;
+};
+
+
+class segaai_exp_interface : public device_interface
+{
+public:
+ segaai_exp_interface(const machine_config &mconfig, device_t &device);
+ virtual ~segaai_exp_interface();
+
+protected:
+ address_space& mem_space() { return m_slot->mem_space(); }
+ address_space& io_space() { return m_slot->io_space(); }
+
+private:
+ segaai_exp_slot_device *const m_slot;
+};
+
+
+// slot interfaces
+void segaai_exp(device_slot_interface &device);
+
+#endif
diff --git a/src/devices/bus/segaai/segaai_slot.cpp b/src/devices/bus/segaai/segaai_slot.cpp
new file mode 100644
index 00000000000..c7e10d59c54
--- /dev/null
+++ b/src/devices/bus/segaai/segaai_slot.cpp
@@ -0,0 +1,99 @@
+// license:BSD-3-Clause
+// copyright-holders:Wilbert Pol
+/***********************************************************************************************************
+
+ Sega AI card emulation
+
+ ***********************************************************************************************************/
+
+
+#include "emu.h"
+#include "segaai_slot.h"
+
+
+DEFINE_DEVICE_TYPE(SEGAAI_CARD_SLOT, segaai_card_slot_device, "segaai_card_slot", "Sega AI Card Slot")
+
+
+static char const *const ROM_128 = "rom_128";
+static char const *const ROM_256 = "rom_256";
+
+
+segaai_card_interface::segaai_card_interface(const machine_config &mconfig, device_t &device)
+ : device_interface(device, "segaai_card")
+ , m_slot(dynamic_cast(device.owner()))
+{
+}
+
+segaai_card_interface::~segaai_card_interface()
+{
+}
+
+
+
+segaai_card_slot_device::segaai_card_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
+ : device_t(mconfig, SEGAAI_CARD_SLOT, tag, owner, clock)
+ , device_cartrom_image_interface(mconfig, *this)
+ , device_single_card_slot_interface(mconfig, *this)
+ , m_address_space(*this, finder_base::DUMMY_TAG, -1, 8)
+{
+}
+
+segaai_card_slot_device::~segaai_card_slot_device()
+{
+}
+
+void segaai_card_slot_device::device_start()
+{
+ m_cart = get_card_device();
+}
+
+std::pair segaai_card_slot_device::call_load()
+{
+ if (m_cart)
+ {
+ const u32 length = !loaded_through_softlist() ? this->length() : get_software_region_length("rom");
+
+ if (length != 0x20000 && length != 0x40000)
+ {
+ return std::make_pair(image_error::INVALIDIMAGE, "Invalid card size. Supported sizes are: 128KB, 256KB");
+ }
+
+ if (!loaded_through_softlist())
+ {
+ memory_region *const romregion = machine().memory().region_alloc(subtag("rom"), length, 1, ENDIANNESS_LITTLE);
+ if (fread(romregion->base(), length) != length)
+ return std::make_pair(image_error::UNSPECIFIED, "Unable to fully read file");
+ }
+
+ m_cart->install_memory_handlers(m_address_space.target());
+
+ return std::make_pair(std::error_condition(), std::string());
+ }
+
+ return std::make_pair(std::error_condition(), std::string());
+}
+
+std::string segaai_card_slot_device::get_default_card_software(get_default_card_software_hook &hook) const
+{
+ if (hook.image_file())
+ {
+ uint64_t length;
+ hook.image_file()->length(length);
+
+ return std::string(length == 0x40000 ? ROM_256 : ROM_128);
+ }
+
+ return software_get_default_slot(ROM_128);
+}
+
+
+
+// slot interfaces
+#include "rom.h"
+
+
+void segaai_cards(device_slot_interface &device)
+{
+ device.option_add_internal(ROM_128, SEGAAI_ROM_128);
+ device.option_add_internal(ROM_256, SEGAAI_ROM_256);
+}
diff --git a/src/devices/bus/segaai/segaai_slot.h b/src/devices/bus/segaai/segaai_slot.h
new file mode 100644
index 00000000000..5e8723fe471
--- /dev/null
+++ b/src/devices/bus/segaai/segaai_slot.h
@@ -0,0 +1,73 @@
+// license:BSD-3-Clause
+// copyright-holders:Wilbert Pol
+#ifndef MAME_BUS_SEGAAI_SLOT_H
+#define MAME_BUS_SEGAAI_SLOT_H
+
+#pragma once
+
+#include "imagedev/cartrom.h"
+
+
+DECLARE_DEVICE_TYPE(SEGAAI_CARD_SLOT, segaai_card_slot_device);
+
+
+class segaai_card_interface;
+
+
+class segaai_card_slot_device : public device_t,
+ public device_cartrom_image_interface,
+ public device_single_card_slot_interface
+{
+public:
+ template
+ segaai_card_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, T &&opts, const char *dflt)
+ : segaai_card_slot_device(mconfig, tag, owner, u32(0))
+ {
+ option_reset();
+ opts(*this);
+ set_default_option(dflt);
+ set_fixed(false);
+ }
+ segaai_card_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock);
+ virtual ~segaai_card_slot_device();
+
+ template void set_address_space(T &&tag, int no) { m_address_space.set_tag(std::forward(tag), no); }
+ virtual std::pair call_load() override;
+ virtual void call_unload() override {}
+ virtual const char *image_type_name() const noexcept override { return "card"; }
+ virtual const char *image_brief_type_name() const noexcept override { return "card"; }
+
+ virtual bool is_reset_on_load() const noexcept override { return true; }
+ virtual const char *image_interface() const noexcept override { return "segaai_card"; }
+ virtual const char *file_extensions() const noexcept override { return "aic,bin"; }
+
+ virtual std::string get_default_card_software(get_default_card_software_hook &hook) const override;
+
+protected:
+ virtual void device_start() override;
+
+private:
+ optional_address_space m_address_space;
+ segaai_card_interface* m_cart;
+};
+
+
+class segaai_card_interface : public device_interface
+{
+public:
+ segaai_card_interface(const machine_config &mconfig, device_t &device);
+ virtual ~segaai_card_interface();
+
+ virtual void install_memory_handlers(address_space *space) { }
+
+protected:
+ memory_region *cart_rom_region() { return m_slot ? m_slot->memregion("rom") : nullptr; }
+
+private:
+ segaai_card_slot_device *const m_slot;
+};
+
+
+void segaai_cards(device_slot_interface &device);
+
+#endif
diff --git a/src/devices/bus/segaai/soundbox.cpp b/src/devices/bus/segaai/soundbox.cpp
new file mode 100644
index 00000000000..5730ab0042d
--- /dev/null
+++ b/src/devices/bus/segaai/soundbox.cpp
@@ -0,0 +1,320 @@
+// license:BSD-3-Clause
+// copyright-holders:Wilbert Pol, Fabio Priuli
+// thanks-to:Chris Covell
+/***********************************************************************************************************
+
+ Sega AI Soundbox expansion emulation
+
+
+ Sega AI Computer Sound Box, Model "AI-2002" quick PCB overview by Chris Covell
+
+ICs on board:
+
+IC 2 TMP82C53F-2 (91/09) Toshiba (Peripheral Timer)
+IC 3 HN27512G-25 (87/12) Hitachi 64K EPROM
+IC 6 YM2151 (91/10) Yamaha FM chip
+IC 7 TMP82C55AF-10 (88/15) Toshiba (Peripheral Interface)
+IC 8 YM3012 (91/10) Yamaha Stereo DAC
+IC 9 HA17358 Hitachi Dual Op-Amp
+IC 10 LC7537N Sanyo (Volume Control IC)
+IC 11 C324C (90/42) NEC Quad Op-Amp
+IC 12 LA4520 (Sanyo Power Audio Amp?)
+IC 16-19 MB81464-12 (91/12) Fujitsu 32K DRAMs
+
+
+Misc Flat DIPs
+
+IC ?? LS125A Hitachi (near C41)
+IC ?? 74HC04 TI (near C38)
+IC ?? 74HC157A x2 Toshiba (near C37)
+IC ?? 74HC138 TI (near C44, furthest)
+IC ?? 74HC139 TI (near C44, closest)
+
+TODO:
+- Connections of the 8253
+- Keyboard matrix is scanned on a timer irq (#FC) from 8253??
+- LC7537N
+
+
+HC04
+pin 1 A1 - PB7
+pin 2 Y1 -> HC04 pin 3 A2
+pin 3 A2 <- HC04 pin 2 Y1
+pin 4 Y2 -> 4th point, 1st row below HC04?
+pin 5 A3 -
+pin 6 Y3 -
+pin 7 GND -
+pin 8 Y4 - 1st point, 2nd row below HC04
+pin 9 A4 - 1st point, 1st row below HC04
+pin 10 Y5 -
+pin 11 A5 <- HC04 pin 12 Y6
+pin 12 Y6 -> HC04 pin 11 A5
+pin 13 A6 - point just below C38 then continues to DRAMs
+pin 14 VCC -
+
+8255 PB7 - connected to HC04 pin 1?, pulled low
+
+TMP8253
+pin 9 CLK0 - seems to be tied to pin 24 in ym2151
+pin 14 OUT0 - --> 2nd point, 2nd row below HC04
+pin 15 GATE0 - NC
+pin 18 OUT1 - 7th point, 1st row below HC04 -> 8th point, 1st row below HC04 -> LS125 pin 2?
+pin 19 GATE1 - 6th point, 1st row below HC04 -> 4th point, 1st row below HC04
+pin 20 CLK1 - 5th point, 1st row below HC04 -> 2nd point, 1st row below HC04 -> left point above C37 -> pin 1 2 lc157s to the right of IC16 (can't be right)
+
+timer 0 - mode 3 - square wave (000A), gate not involved
+timer 1 - mode 2 - rate generator (0E90), gate involved
+0e90 = 3818
+
+ ***********************************************************************************************************/
+
+
+#include "emu.h"
+#include "soundbox.h"
+
+#include "machine/i8255.h"
+#include "machine/pit8253.h"
+#include "sound/ymopm.h"
+
+#include "speaker.h"
+
+//#define VERBOSE (LOG_GENERAL)
+#include "logmacro.h"
+
+
+namespace {
+
+class segaai_soundbox_device : public device_t,
+ public segaai_exp_interface
+{
+public:
+ segaai_soundbox_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
+ : device_t(mconfig, SEGAAI_SOUNDBOX, tag, owner, clock)
+ , segaai_exp_interface(mconfig, *this)
+ , m_tmp8253(*this, "tmp8253")
+ , m_tmp8255(*this, "tmp8255")
+ , m_ym2151(*this, "ym2151")
+ , m_rom(*this, "soundbox")
+ , m_rows(*this, "ROW%u", 0U)
+ , m_row(0)
+ { }
+
+ static constexpr feature_type unemulated_features() { return feature::KEYBOARD; }
+
+protected:
+ virtual void device_add_mconfig(machine_config &config) override;
+ virtual const tiny_rom_entry *device_rom_region() const override;
+ virtual ioport_constructor device_input_ports() const override;
+ virtual void device_start() override;
+
+private:
+ static constexpr u32 EXPANSION_RAM_SIZE = 0x20000;
+
+ u8 tmp8255_porta_r();
+ void tmp8255_portb_w(u8 data);
+ void tmp8255_portc_w(u8 data);
+ void ym2151_irq_w(int state);
+ void tmp8253_out0_w(int state);
+ void tmp8253_out1_w(int state);
+
+ required_device m_tmp8253;
+ required_device m_tmp8255;
+ required_device m_ym2151;
+ required_region_ptr m_rom;
+ required_ioport_array<8> m_rows;
+ std::unique_ptr m_ram;
+ u8 m_row;
+};
+
+void segaai_soundbox_device::device_add_mconfig(machine_config &config)
+{
+ PIT8253(config, m_tmp8253);
+ m_tmp8253->set_clk<0>(clock()); // ~3.58 MHz, seems to be tied to pin 24 in ym2151
+ m_tmp8253->out_handler<0>().set(FUNC(segaai_soundbox_device::tmp8253_out0_w));
+ // gate0 not connected
+ m_tmp8253->set_clk<1>(clock()); // 3.58 MHz?
+ m_tmp8253->out_handler<1>().set(FUNC(segaai_soundbox_device::tmp8253_out1_w));
+ // timer 2 is not connected, also not set up by the code
+
+ I8255(config, m_tmp8255);
+ m_tmp8255->in_pa_callback().set(FUNC(segaai_soundbox_device::tmp8255_porta_r));
+ m_tmp8255->in_pb_callback().set_constant(0xff);
+ m_tmp8255->out_pb_callback().set(FUNC(segaai_soundbox_device::tmp8255_portb_w));
+ m_tmp8255->out_pc_callback().set(FUNC(segaai_soundbox_device::tmp8255_portc_w));
+
+ SPEAKER(config, "lspeaker").front_left();
+ SPEAKER(config, "rspeaker").front_right();
+ YM2151(config, m_ym2151, DERIVED_CLOCK(1,1)); // ~3.58MHz
+ m_ym2151->irq_handler().set(FUNC(segaai_soundbox_device::ym2151_irq_w));
+ m_ym2151->add_route(0, "lspeaker", 1.00);
+ m_ym2151->add_route(1, "rspeaker", 1.00);
+}
+
+ROM_START(soundbox)
+ ROM_REGION(0x10000, "soundbox", 0)
+ ROM_LOAD("ai-snd-2002-cecb.bin", 0x0000, 0x10000, CRC(ef2dabc0) SHA1(b60cd9f6f46b6c77dba8610df6fd83368569e713))
+ROM_END
+
+const tiny_rom_entry *segaai_soundbox_device::device_rom_region() const
+{
+ return ROM_NAME(soundbox);
+}
+
+static INPUT_PORTS_START(soundbox)
+ PORT_START("ROW0")
+ PORT_BIT(0x0001, IP_ACTIVE_LOW, IPT_UNUSED)
+ PORT_BIT(0x0002, IP_ACTIVE_LOW, IPT_UNUSED)
+ PORT_BIT(0x0004, IP_ACTIVE_LOW, IPT_UNUSED)
+ PORT_BIT(0x0008, IP_ACTIVE_LOW, IPT_UNUSED)
+ PORT_BIT(0x0010, IP_ACTIVE_LOW, IPT_UNUSED)
+ PORT_BIT(0x0020, IP_ACTIVE_LOW, IPT_UNUSED)
+ PORT_BIT(0x0040, IP_ACTIVE_LOW, IPT_UNUSED)
+ PORT_BIT(0x0080, IP_ACTIVE_LOW, IPT_UNUSED)
+
+ PORT_START("ROW1")
+ PORT_BIT(0x0001, IP_ACTIVE_LOW, IPT_UNUSED)
+ PORT_BIT(0x0002, IP_ACTIVE_LOW, IPT_UNUSED)
+ PORT_BIT(0x0004, IP_ACTIVE_LOW, IPT_UNUSED)
+ PORT_BIT(0x0008, IP_ACTIVE_LOW, IPT_UNUSED)
+ PORT_BIT(0x0010, IP_ACTIVE_LOW, IPT_UNUSED)
+ PORT_BIT(0x0020, IP_ACTIVE_LOW, IPT_UNUSED)
+ PORT_BIT(0x0040, IP_ACTIVE_LOW, IPT_UNUSED)
+ PORT_BIT(0x0080, IP_ACTIVE_LOW, IPT_UNUSED)
+
+ PORT_START("ROW2")
+ PORT_BIT(0x0001, IP_ACTIVE_LOW, IPT_UNUSED)
+ PORT_BIT(0x0002, IP_ACTIVE_LOW, IPT_UNUSED)
+ PORT_BIT(0x0004, IP_ACTIVE_LOW, IPT_UNUSED)
+ PORT_BIT(0x0008, IP_ACTIVE_LOW, IPT_UNUSED)
+ PORT_BIT(0x0010, IP_ACTIVE_LOW, IPT_UNUSED)
+ PORT_BIT(0x0020, IP_ACTIVE_LOW, IPT_UNUSED)
+ PORT_BIT(0x0040, IP_ACTIVE_LOW, IPT_UNUSED)
+ PORT_BIT(0x0080, IP_ACTIVE_LOW, IPT_UNUSED)
+
+ PORT_START("ROW3")
+ PORT_BIT(0x0001, IP_ACTIVE_LOW, IPT_UNUSED)
+ PORT_BIT(0x0002, IP_ACTIVE_LOW, IPT_UNUSED)
+ PORT_BIT(0x0004, IP_ACTIVE_LOW, IPT_UNUSED)
+ PORT_BIT(0x0008, IP_ACTIVE_LOW, IPT_UNUSED)
+ PORT_BIT(0x0010, IP_ACTIVE_LOW, IPT_UNUSED)
+ PORT_BIT(0x0020, IP_ACTIVE_LOW, IPT_UNUSED)
+ PORT_BIT(0x0040, IP_ACTIVE_LOW, IPT_UNUSED)
+ PORT_BIT(0x0080, IP_ACTIVE_LOW, IPT_UNUSED)
+
+ PORT_START("ROW4")
+ PORT_BIT(0x0001, IP_ACTIVE_LOW, IPT_UNUSED)
+ PORT_BIT(0x0002, IP_ACTIVE_LOW, IPT_UNUSED)
+ PORT_BIT(0x0004, IP_ACTIVE_LOW, IPT_UNUSED)
+ PORT_BIT(0x0008, IP_ACTIVE_LOW, IPT_UNUSED)
+ PORT_BIT(0x0010, IP_ACTIVE_LOW, IPT_UNUSED)
+ PORT_BIT(0x0020, IP_ACTIVE_LOW, IPT_UNUSED)
+ PORT_BIT(0x0040, IP_ACTIVE_LOW, IPT_UNUSED)
+ PORT_BIT(0x0080, IP_ACTIVE_LOW, IPT_UNUSED)
+
+ PORT_START("ROW5")
+ PORT_BIT(0x0001, IP_ACTIVE_LOW, IPT_UNUSED)
+ PORT_BIT(0x0002, IP_ACTIVE_LOW, IPT_UNUSED)
+ PORT_BIT(0x0004, IP_ACTIVE_LOW, IPT_UNUSED)
+ PORT_BIT(0x0008, IP_ACTIVE_LOW, IPT_UNUSED)
+ PORT_BIT(0x0010, IP_ACTIVE_LOW, IPT_UNUSED)
+ PORT_BIT(0x0020, IP_ACTIVE_LOW, IPT_UNUSED)
+ PORT_BIT(0x0040, IP_ACTIVE_LOW, IPT_UNUSED)
+ PORT_BIT(0x0080, IP_ACTIVE_LOW, IPT_UNUSED)
+
+ PORT_START("ROW6")
+ PORT_BIT(0x0001, IP_ACTIVE_LOW, IPT_UNUSED)
+ PORT_BIT(0x0002, IP_ACTIVE_LOW, IPT_UNUSED)
+ PORT_BIT(0x0004, IP_ACTIVE_LOW, IPT_UNUSED)
+ PORT_BIT(0x0008, IP_ACTIVE_LOW, IPT_UNUSED)
+ PORT_BIT(0x0010, IP_ACTIVE_LOW, IPT_UNUSED)
+ PORT_BIT(0x0020, IP_ACTIVE_LOW, IPT_UNUSED)
+ PORT_BIT(0x0040, IP_ACTIVE_LOW, IPT_UNUSED)
+ PORT_BIT(0x0080, IP_ACTIVE_LOW, IPT_UNUSED)
+
+ PORT_START("ROW7")
+ PORT_BIT(0x0001, IP_ACTIVE_LOW, IPT_UNUSED)
+ PORT_BIT(0x0002, IP_ACTIVE_LOW, IPT_UNUSED)
+ PORT_BIT(0x0004, IP_ACTIVE_LOW, IPT_UNUSED)
+ PORT_BIT(0x0008, IP_ACTIVE_LOW, IPT_UNUSED)
+ PORT_BIT(0x0010, IP_ACTIVE_LOW, IPT_UNUSED)
+ PORT_BIT(0x0020, IP_ACTIVE_LOW, IPT_UNUSED)
+ PORT_BIT(0x0040, IP_ACTIVE_LOW, IPT_UNUSED)
+ PORT_BIT(0x0080, IP_ACTIVE_LOW, IPT_UNUSED)
+INPUT_PORTS_END
+
+ioport_constructor segaai_soundbox_device::device_input_ports() const
+{
+ return INPUT_PORTS_NAME(soundbox);
+}
+
+void segaai_soundbox_device::device_start()
+{
+ m_row = 0;
+ m_ram = std::make_unique(EXPANSION_RAM_SIZE);
+
+ save_pointer(NAME(m_ram), EXPANSION_RAM_SIZE);
+ save_item(NAME(m_row));
+
+ mem_space().install_ram(0x20000, 0x3ffff, &m_ram[0]);
+ mem_space().install_rom(0x80000, 0x8ffff, m_rom);
+ io_space().install_read_handler(0x20, 0x23, emu::rw_delegate(*m_ym2151, FUNC(ym2151_device::read)));
+ io_space().install_write_handler(0x20, 0x23, emu::rw_delegate(*m_ym2151, FUNC(ym2151_device::write)));
+ io_space().install_read_handler(0x24, 0x27, emu::rw_delegate(*m_tmp8253, FUNC(pit8253_device::read)));
+ io_space().install_write_handler(0x24, 0x27, emu::rw_delegate(*m_tmp8253, FUNC(pit8253_device::write)));
+ io_space().install_read_handler(0x28, 0x2b, emu::rw_delegate(*m_tmp8255, FUNC(i8255_device::read)));
+ io_space().install_write_handler(0x28, 0x2b, emu::rw_delegate(*m_tmp8255, FUNC(i8255_device::write)));
+}
+
+u8 segaai_soundbox_device::tmp8255_porta_r()
+{
+ // Read pressed keys on music keyboard row (see routine @0x82399)
+ u8 result = 0xff;
+ for (int i = 0; i < 8; i++)
+ if (BIT(m_row, i)) result &= m_rows[i]->read();
+ return result;
+}
+
+/*
+ 8255 port B
+
+ 76543210
+ +-------- 8253 GATE1
+ +-------
+ +------
+ +-----
+ +----
+ +--- LC7537N pin22 DI
+ +-- LC7537N pin21 CLK
+ +- LC7537N pin20 DI
+*/
+void segaai_soundbox_device::tmp8255_portb_w(u8 data)
+{
+ LOG("soundbox 8255 port B write $%02X\n", data);
+ m_tmp8253->write_gate1(BIT(data, 7));
+}
+
+void segaai_soundbox_device::tmp8255_portc_w(u8 data)
+{
+ // Selects music keyboard row to scan (see routine @0x82399)
+ LOG("soundbox m_row = $%02X\n", data);
+ m_row = data;
+}
+
+void segaai_soundbox_device::ym2151_irq_w(int state)
+{
+ LOG("Soundbox: IRQ from ym2151 is '%s'\n", state ? "ASSERT" : "CLEAR");
+}
+
+void segaai_soundbox_device::tmp8253_out0_w(int state)
+{
+// LOG("Soundbox: OUT0 from tmp8253 is '%s'\n", state ? "ASSERT" : "CLEAR");
+}
+
+void segaai_soundbox_device::tmp8253_out1_w(int state)
+{
+// LOG("Soundbox: OUT1 from tmp8253 is '%s'\n", state ? "ASSERT" : "CLEAR");
+}
+
+} // anonymous namespace
+
+DEFINE_DEVICE_TYPE_PRIVATE(SEGAAI_SOUNDBOX, segaai_exp_interface, segaai_soundbox_device, "segaai_soundbox", "Sega AI Expansion - Soundbox")
diff --git a/src/devices/bus/segaai/soundbox.h b/src/devices/bus/segaai/soundbox.h
new file mode 100644
index 00000000000..041c50195f0
--- /dev/null
+++ b/src/devices/bus/segaai/soundbox.h
@@ -0,0 +1,14 @@
+// license:BSD-3-Clause
+// copyright-holders:Wilbert Pol, Fabio Priuli
+// thanks-to:Chris Covell
+#ifndef MAME_BUS_SEGAAI_SOUNDBOX_H
+#define MAME_BUS_SEGAAI_SOUNDBOX_H
+
+#pragma once
+
+#include "segaai_exp.h"
+
+
+DECLARE_DEVICE_TYPE(SEGAAI_SOUNDBOX, segaai_exp_interface);
+
+#endif
diff --git a/src/mame/layout/segaai.lay b/src/mame/layout/segaai.lay
new file mode 100644
index 00000000000..ab4f768d3da
--- /dev/null
+++ b/src/mame/layout/segaai.lay
@@ -0,0 +1,94 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ]]>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/mame/mame.lst b/src/mame/mame.lst
index b7ac8f6357c..cc288fcfa17 100644
--- a/src/mame/mame.lst
+++ b/src/mame/mame.lst
@@ -39461,6 +39461,9 @@ tvochken //
@source:sega/sega_sawatte.cpp
sawatte //
+@source:sega/segaai.cpp
+segaai // (c) 1986 Sega
+
@source:sega/segaatom.cpp
spongbob // (c) 200? Sega
diff --git a/src/mame/sega/segaai.cpp b/src/mame/sega/segaai.cpp
new file mode 100644
index 00000000000..15dc91a972c
--- /dev/null
+++ b/src/mame/sega/segaai.cpp
@@ -0,0 +1,728 @@
+// license:BSD-3-Clause
+// copyright-holders:Wilbert Pol, Fabio Priuli
+// thanks-to:Chris Covell
+/*
+
+ Sega AI driver
+
+
+ Not much is known at this stage, except that the system was intended to be
+ used for educational purposes in schools. Yet the audio chips seem much more
+ powerful than what an educational computer requires...
+
+ CPU : 16bit V20 @ 5MHz
+ ROM : 128KB OS.with SEGA PROLOG
+ RAM : 128KB
+ VRAM : 64KB
+ Video : V9938 Resolution 256x212
+ Sound : SN76489
+ Cassette Drive : 9600bps
+ TV Output : RGB, Video, RF
+ Keyboard : new JIS arrangement (Japanese input mapping)
+
+
+TODO:
+- Cassette, playback is controlled by the computer. Games with cassette
+ spin up the cassette for about 2 seconds
+ - The tape sometimes seeks back and forth for 5-15 seconds for the right
+ voice clip, while the game and player (kids) wait
+ "In these tapes, by the way, the left audio channel is the narration,
+ and the right channel the data bursts right before each one."
+- Keyboard?
+- SEGA Prolog? How to enter?
+
+- Sound box:
+ Note from ccovell:
+ "With the Sound Box attached, I connected the output line of the Sound
+ Box's keyboard pins to one or more input pins, and it suddenly played an
+ FM instrument and printed "piano" on the screen! From this, pressing U/D
+ on the pad cycled through the various instruments, and the PL/PR buttons
+ lowered and raised the volume."
+
+===========================================================================
+
+ Sega AI Computer quick PCB overview by Chris Covell
+
+ Major ICs
+
+ IC 1 D701080-5 (86/09?) NEC V20 CPU DIP40
+ IC 2 315-5200 (86/25) SEGA QFP100
+ IC 3 27C512-25 (86/15) 64K EPROM "E000 8/24"
+ IC 4 27C512-25 (86/06) 64K EPROM "F000 7/21"
+ IC 5 MPR-7689 (86/22) SEGA "264 AA E79" (ROM) DIP28
+ IC 10 V9938 Yamaha MSX2 VDP
+ IC 13 D7759C (86/12) NEC Speech Synthesizer DIP40
+ IC 14 MPR-7619 (86/23) SEGA (ROM) DIP28
+ IC 15 MPR-7620 (86/23) SEGA (ROM) DIP28
+ IC 16 SN76489AN TI PSG DIP16
+ IC 17 D8251AFC (86/09) NEC Communications Interface DIP28
+ IC 18 315-5201 (86/25) SEGA (bodge wire on pins 9,10) DIP20
+ IC 19 M5204A (87?/01) OKI
+ IC 20 D8255AC-2 (86/08) NEC Peripheral Interface DIP40
+
+ IC 6,7,8,9,11,12 D41464C-12 NEC 32K DRAMs - 128K RAM, 64K VRAM
+
+ Crystals, etc
+
+ X1 20.000 "KDS 6D"
+ X2 21.47727 "KDS"
+ X3 640kHz "CSB 640 P"
+
+ Connectors
+
+ CN1 6-pin DIN Power connector
+ CN2 8-pin DIN "AUX" connector
+ CN3 Video phono jack
+ CN4 Audio phono jack
+ CN5 35-pin Sega MyCard connector
+ CN6 60-pin expansion connector A1..A30 Bottom, B1..B30 Top
+ CN7 9-pin header connector to "Joy, Button, LED" unit
+ CN8 13(?) pin flat flex connector to pressure pad
+ CN9 9-pin header connector to tape drive motor, etc.
+ CN10 13-pin header connector to tape heads
+ JP2 2-wire header to SW2 button board
+ PJ1 7-wire header to Keyboard / Mic connector board
+ MIC 2-wire header to mic on KB/Mic board
+ SW1 Reset Switch
+
+ Power switch is on the AC Adaptor
+
+ Joypad unit (by Mitsumi) has U/D/L/R, "PL" and "PR" buttons, and a power LED.
+
+Power Connector Pinout (Seen from AC Adaptor plug):
+ 1 5 1 12V COM 5 5V COM
+ 6 2 12V OUT 6 5V OUT
+ 2 4 3 5V COM
+ 3 4 5V OUT
+
+AUX Connector Pinout:
+ 7 6 1 +5V(?) 5 csync
+ 3 8 1 2 GND 6 green
+ 5 4 3 blue 7 Audio out
+ 2 4 +5V(?) 8 red
+
+New JIS Keyboard Connector Pinout:
+ 1 2 1,2,3 data lines
+ 3 4 5 4 ?? 5,8 data lines
+ 6 7 8 6 GND 7 +5V
+
+
+*/
+
+#include "emu.h"
+
+#include "bus/segaai/segaai_exp.h"
+#include "bus/segaai/segaai_slot.h"
+#include "cpu/nec/nec.h"
+#include "imagedev/cassette.h"
+#include "machine/i8251.h"
+#include "machine/i8255.h"
+#include "sound/sn76496.h"
+#include "sound/upd7759.h"
+#include "video/v9938.h"
+
+#include "crsshair.h"
+#include "softlist.h"
+#include "softlist_dev.h"
+#include "speaker.h"
+
+#include "segaai.lh"
+
+//#define VERBOSE (LOG_GENERAL)
+#include "logmacro.h"
+
+
+namespace {
+
+class segaai_state : public driver_device
+{
+public:
+ segaai_state(const machine_config &mconfig, device_type type, const char *tag)
+ : driver_device(mconfig, type, tag)
+ , m_maincpu(*this, "maincpu")
+ , m_screen(*this, "screen")
+ , m_sound(*this, "sn76489a")
+ , m_v9938(*this, "v9938")
+ , m_upd7759(*this, "upd7759")
+ , m_i8251(*this, "i8251")
+ , m_i8255(*this, "i8255")
+ , m_cassette(*this, "cassette")
+ , m_cardslot(*this, "cardslot")
+ , m_expslot(*this, "exp")
+ , m_port4(*this, "PORT4")
+ , m_port5(*this, "PORT5")
+ , m_touch(*this, "TOUCH")
+ , m_touchpadx(*this, "TOUCHPADX")
+ , m_touchpady(*this, "TOUCHPADY")
+ , m_vector(0)
+ { }
+
+ void segaai(machine_config &config);
+
+protected:
+ virtual void machine_start() override;
+
+private:
+ static constexpr u8 VECTOR_V9938 = 0xf8;
+ static constexpr u8 VECTOR_I8251_SEND = 0xf9;
+ static constexpr u8 VECTOR_I8251_RECEIVE = 0xfa;
+ static constexpr u8 VECTOR_UPD7759 = 0xfb;
+
+ static constexpr u8 IRQ_V9938 = 0x01;
+ static constexpr u8 IRQ_UPD7759 = 0x08;
+
+ // 8255 Port B bits
+ static constexpr u8 TOUCH_PAD_PRESSED = 0x02;
+ static constexpr u8 TOUCH_PAD_DATA_AVAILABLE = 0x04;
+
+ static constexpr u8 UPD7759_MODE = 0x01;
+ static constexpr u8 UPD7759_BANK = 0x02;
+
+ void mem_map(address_map &map);
+ void io_map(address_map &map);
+ void update_irq_state();
+ u32 get_vector() { return m_vector; }
+ void vdp_interrupt(int state);
+ void upd7759_drq_w(int state);
+ IRQ_CALLBACK_MEMBER(irq_callback);
+ u8 i8255_portb_r();
+ u8 i8255_portc_r();
+ void i8255_portc_w(u8 data);
+ void upd7759_ctrl_w(u8 data);
+ void upd7759_data_w(u8 data);
+ void port1c_w(u8 data);
+ void port1d_w(u8 data);
+ void port1e_w(u8 data);
+ u8 port1e_r();
+ u8 irq_enable_r();
+ void irq_enable_w(u8 data);
+ void irq_select_w(u8 data);
+
+ required_device m_maincpu;
+ required_device m_screen;
+ required_device m_sound;
+ required_device m_v9938;
+ required_device m_upd7759;
+ required_device m_i8251;
+ required_device m_i8255;
+ required_device m_cassette;
+ required_device m_cardslot;
+ required_device m_expslot;
+ required_ioport m_port4;
+ required_ioport m_port5;
+ required_ioport m_touch;
+ required_ioport m_touchpadx;
+ required_ioport m_touchpady;
+
+ u8 m_i8255_portb;
+ u8 m_upd7759_ctrl;
+ u8 m_port_1c;
+ u8 m_port_1d;
+ u8 m_port_1e;
+ u32 m_prev_v9938_irq;
+ u32 m_prev_upd7759_irq;
+ u8 m_touchpad_x;
+ u8 m_touchpad_y;
+ u8 m_irq_active;
+ u8 m_irq_enabled;
+ u32 m_vector;
+};
+
+
+void segaai_state::mem_map(address_map &map)
+{
+ map(0x00000, 0x1ffff).ram();
+ // 0x20000-0x3ffff - Dynamically mapped by expansion slot
+ // 0x80000-0x8ffff - Dynamically mapped by expansion slot
+ // 0xa0000-0xbffff - Dynamically mapped by cardslot
+ map(0xc0000, 0xdffff).rom();
+ map(0xe0000, 0xeffff).rom();
+ map(0xf0000, 0xfffff).rom();
+}
+
+
+/*
+Interesting combination of I/O actions from the BIOS:
+
+EC267: B0 03 mov al,3h
+EC269: E6 17 out 17h,al
+EC26B: B0 FC mov al,0FCh ; 11111100
+EC26D: E6 0F out 0Fh,al
+EC26F: B0 FF mov al,0FFh
+EC271: E6 08 out 8h,al
+
+same code at ECDBE, ED2FC
+EC2D6: B0 05 mov al,5h
+EC2D8: E6 17 out 17h,al
+EC2DA: B0 FA mov al,0FAh ; 11111010
+EC2DC: E6 0F out 0Fh,al
+EC2DE: B0 00 mov al,0h
+EC2E0: E4 08 in al,8h
+
+same code at ECE08, ECE1D, ED282, EDBA8, EDD78
+EC319: B0 04 mov al,4h
+EC31B: E6 17 out 17h,al
+EC31D: B0 FE mov al,0FEh ; 11111110
+EC31F: E6 0F out 0Fh,al
+
+ECB45: 80 FA 03 cmp dl,3h
+ECB48: 74 05 be 0ECB4Fh
+ECB4A: B0 09 mov al,9h
+ECB4C: E9 02 00 br 0ECB51h
+ECB4F: B0 08 mov al,8h
+ECB51: E6 17 out 17h,al
+
+same code at ED02A, ED17E, ED1DC
+ECEE5: B0 03 mov al,3h
+ECEE7: E6 17 out 17h,al
+ECEE9: B0 FC mov al,0FCh ; 11111100
+ECEEB: E6 0F out 0Fh,al
+ECEED: B0 00 mov al,0h
+ECEEF: E6 08 out 8h,al
+
+same code at ED0D9, ED120, EDB04, EDC8F
+ECF0D: B0 02 mov al,2h
+ECF0F: E6 17 out 17h,al
+ECF11: B0 FE mov al,0FEh ; 11111110
+ECF13: E6 0F out 0Fh,al
+
+*/
+
+void segaai_state::io_map(address_map &map)
+{
+ map(0x00, 0x03).rw(m_v9938, FUNC(v9938_device::read), FUNC(v9938_device::write));
+ map(0x04, 0x07).rw(m_i8255, FUNC(i8255_device::read), FUNC(i8255_device::write));
+ // port 7, bit 7, engages tape?
+
+ map(0x08, 0x08).rw(m_i8251, FUNC(i8251_device::data_r), FUNC(i8251_device::data_w));
+ map(0x09, 0x09).rw(m_i8251, FUNC(i8251_device::status_r), FUNC(i8251_device::control_w));
+
+ // 0x0a (w) - ??
+ // 0a: 00 written during boot
+ map(0x0b, 0x0b).w(FUNC(segaai_state::upd7759_ctrl_w));
+
+ map(0x0c, 0x0c).w(m_sound, FUNC(sn76489a_device::write));
+
+ // 0x0e (w) - ??
+ // 0x0f (w) - ??
+ // during boot:
+ // 0e <- 13
+ // 0f <- ff
+ // 0f <- 07
+ // 0e <- 07
+ // 0e <- 08
+ // 0f <- fe
+
+ map(0x14, 0x14).mirror(0x01).w(FUNC(segaai_state::upd7759_data_w));
+
+ // IRQ Enable
+ map(0x16, 0x16).rw(FUNC(segaai_state::irq_enable_r), FUNC(segaai_state::irq_enable_w));
+ // IRQ Enable (per IRQ source selection) Why 2 registers for IRQ enable?
+ map(0x17, 0x17).w(FUNC(segaai_state::irq_select_w));
+
+ // Touchpad
+ map(0x1c, 0x1c).w(FUNC(segaai_state::port1c_w));
+ map(0x1d, 0x1d).w(FUNC(segaai_state::port1d_w));
+ map(0x1e, 0x1e).rw(FUNC(segaai_state::port1e_r), FUNC(segaai_state::port1e_w));
+
+ // 0x1f (w) - ??
+
+ // Expansion I/O
+ // 0x20-0x3f - Dynamically mapped by expansion slot
+}
+
+
+static INPUT_PORTS_START(ai_kbd)
+ PORT_START("PORT4")
+ PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_JOYSTICK_UP) PORT_8WAY
+ PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN) PORT_8WAY
+ PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT) PORT_8WAY
+ PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT) PORT_8WAY
+ PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_BUTTON2) PORT_NAME("PL")
+ PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_BUTTON1) PORT_NAME("RL")
+ PORT_BIT(0x40, IP_ACTIVE_HIGH, IPT_CUSTOM) PORT_READ_LINE_DEVICE_MEMBER("upd7759", upd7759_device, busy_r)
+ PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_UNUSED) // Microphone sensor
+
+ PORT_START("PORT5")
+ PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_BUTTON3) PORT_NAME("Grey Button")
+ PORT_BIT(0xfe, IP_ACTIVE_LOW, IPT_UNUSED)
+
+ PORT_START("TOUCH")
+ PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_BUTTON4) PORT_NAME("Press touchpad")
+
+ PORT_START("TOUCHPADX")
+ PORT_BIT(0xff, 0x80, IPT_LIGHTGUN_X) PORT_CROSSHAIR(X, 1.0, 0.0, 0) PORT_SENSITIVITY(30) PORT_KEYDELTA(10) PORT_MINMAX(0, 255) PORT_PLAYER(1) PORT_NAME("Touchpad X")
+
+ PORT_START("TOUCHPADY")
+ PORT_BIT(0xff, 0x80, IPT_LIGHTGUN_Y) PORT_CROSSHAIR(Y, 1.0, 0.0, 0) PORT_SENSITIVITY(30) PORT_KEYDELTA(10) PORT_MINMAX(0, 255) PORT_PLAYER(1) PORT_NAME("Touchpad Y")
+INPUT_PORTS_END
+
+
+void segaai_state::update_irq_state()
+{
+ int state = CLEAR_LINE;
+
+ if (m_irq_active & m_irq_enabled)
+ {
+ state = ASSERT_LINE;
+ }
+
+ m_maincpu->set_input_line(0, state);
+}
+
+
+// Based on edge triggers level triggers are created
+void segaai_state::vdp_interrupt(int state)
+{
+ if (state != CLEAR_LINE)
+ {
+ if (m_prev_v9938_irq == CLEAR_LINE)
+ {
+ m_irq_active |= IRQ_V9938;
+ }
+ }
+ m_prev_v9938_irq = state;
+
+ update_irq_state();
+}
+
+
+// Based on edge triggers level triggers are created
+void segaai_state::upd7759_drq_w(int state)
+{
+ int upd7759_irq = state ? CLEAR_LINE : ASSERT_LINE;
+ if (upd7759_irq != CLEAR_LINE)
+ {
+ if (m_prev_upd7759_irq == CLEAR_LINE)
+ {
+ m_irq_active |= IRQ_UPD7759;
+ }
+ }
+ m_prev_upd7759_irq = upd7759_irq;
+
+ update_irq_state();
+}
+
+
+IRQ_CALLBACK_MEMBER(segaai_state::irq_callback)
+{
+ if (m_irq_active & m_irq_enabled & IRQ_V9938)
+ {
+ m_vector = VECTOR_V9938;
+ m_irq_active &= ~IRQ_V9938;
+ }
+ else if (m_irq_active & m_irq_enabled & IRQ_UPD7759)
+ {
+ m_vector = VECTOR_UPD7759;
+ m_irq_active &= ~IRQ_UPD7759;
+ }
+ else
+ {
+ if (m_irq_active & m_irq_enabled)
+ {
+ fatalerror("Unknown irq triggered: $%02X active, $%02X enabled\n", m_irq_active, m_irq_enabled);
+ }
+ fatalerror("irq_callback called but no irq active and enabled: $%02X active, $%02X enabled\n", m_irq_active, m_irq_enabled);
+ }
+
+ update_irq_state();
+ return m_vector;
+}
+
+
+/*
+Mainboard 8255 port B
+
+ 76543210
+ +-------- Tape input (right channel?), unknown if input is signal level or bit
+ +------- Tape head engaged
+ +------ Tape insertion sensor (0 - tape is inserted, 1 - no tape inserted)
+ +----- Tape write enable sensor
+ +---- keyboard connector pin 3
+ +--- 0 = Touch pad data available
+ +-- 0 = Touch pad pressed
+ +- Trigger button near touch panel (active low)
+*/
+u8 segaai_state::i8255_portb_r()
+{
+ m_i8255_portb = (m_i8255_portb & 0xf8) | (m_port5->read() & 0x01);
+
+ if (BIT(m_port_1d, 0))
+ {
+ if (!BIT(m_touch->read(), 0))
+ {
+ m_i8255_portb |= TOUCH_PAD_PRESSED;
+ }
+
+ m_i8255_portb |= TOUCH_PAD_DATA_AVAILABLE;
+ }
+ else
+ {
+ m_i8255_portb |= TOUCH_PAD_PRESSED;
+ }
+
+ if (m_cassette->get_image() != nullptr)
+ {
+ m_i8255_portb &= ~0x20;
+ }
+ else
+ {
+ m_i8255_portb |= 0x20;
+ }
+
+ // when checking whether the tape is running Popoland wants to see bit7 set and bit5 reset
+ // toggling this stops eigogam2 from booting normally into a game.
+ // For tape reading eigogam2 routines at A11EA and A120C
+ // There is a whistle tone on the cassette before normal speech starts, the code there likely
+ // checks for this whistle tone.
+ //m_i8255_portb ^= 0x80;
+
+ return m_i8255_portb;
+}
+
+
+/*
+Mainboard 8255 port C
+
+ 76543210
+ +-------- keyboard connector pin 5
+ +------- keyboard connector pin 8
+ +------ keyboard connector pin 2
+ +----- keyboard connector pin 1
+ +---- Output
+ +--- Output
+ +-- Output
+ +- Output
+*/
+u8 segaai_state::i8255_portc_r()
+{
+ u8 data = 0xf0;
+
+ return data;
+}
+
+
+/*
+ pin 10-13 - PC0-PC3 -> RA41
+ PC0-PC3 continue on underside of pcb
+ pin 14-17 - PC4-PC7 -> RA42
+ PC3 continues on underside of pcb
+ PC2 - pin 6 upa2003c, drives upa2003c pin 11
+ PC1 - pin 4 upa2003c, drives upa2003c pin 13
+ PC0 - pin 2 upd2003c, drives upa2003c pin 15
+ these go to 3 dots to the left of resistors below upa2003c?
+ which end up on the 9 pin flat connector on the lower left side of the pcb
+ PC4 - to pin 1 of 7 pin connector bottom right side of pcb -> jis keyboard connector ?
+ CN9 - 9 pin connector goes to cassette interface
+ pin 1 - red
+ pin 2 - black
+ pin 3 - blue
+ pin 4 - yellow
+ pin 5 - white
+ pin 6 - black/grey
+ pin 7 - blue
+ pin 8 - grey
+ pin 9 - brown
+*/
+void segaai_state::i8255_portc_w(u8 data)
+{
+ // Writes to bits 6,5,4, unknown what they mean
+ // Bit 0 written by cosmictr
+ LOG("i8255 port c write: %02x\n", data);
+}
+
+
+void segaai_state::upd7759_data_w(u8 data)
+{
+ m_upd7759->start_w(ASSERT_LINE);
+ m_upd7759->port_w(data);
+ m_upd7759->start_w(CLEAR_LINE);
+}
+
+
+void segaai_state::upd7759_ctrl_w(u8 data)
+{
+ LOG("I/O Port $0b write: $%02x\n", data);
+
+ m_upd7759_ctrl = data;
+
+ // bit0 is connected to /md line of the uPD7759
+ m_upd7759->md_w((m_upd7759_ctrl & UPD7759_MODE) ? 0 : 1);
+
+ // bit1 selects which ROM should be used?
+ m_upd7759->set_rom_bank((m_upd7759_ctrl & UPD7759_BANK) >> 1);
+}
+
+
+// I/O Port 16 - IRQ Enable
+u8 segaai_state::irq_enable_r()
+{
+ return m_irq_enabled;
+}
+
+
+// IRQ Enable
+// 76543210
+// +-------- ???
+// +------- ???
+// +------ ???
+// +----- ???
+// +---- D7759 IRQ enable
+// +--- ???
+// +-- ??? 8251 receive?
+// +- V9938 IRQ enable
+void segaai_state::irq_enable_w(u8 data)
+{
+ m_irq_enabled = data;
+ m_irq_active &= data;
+ update_irq_state();
+}
+
+// I/O Port 17 - IRQ Enable selection
+// This port seems to be used to set or reset specific bits in the IRQ enable register.
+// Why 2 ways of setting/clearing irq enable bits?
+void segaai_state::irq_select_w(u8 data)
+{
+ int pin = (data >> 1) & 0x07;
+ if (BIT(data, 0))
+ {
+ m_irq_enabled |= (1 << pin);
+ }
+ else
+ {
+ m_irq_enabled &= ~(1 << pin);
+ m_irq_active &= m_irq_enabled;
+ }
+ update_irq_state();
+}
+
+
+void segaai_state::port1c_w(u8 data)
+{
+ m_port_1c = data;
+}
+
+
+void segaai_state::port1d_w(u8 data)
+{
+ m_port_1d = data;
+}
+
+
+void segaai_state::port1e_w(u8 data)
+{
+ m_port_1e = data;
+}
+
+
+u8 segaai_state::port1e_r()
+{
+ if (BIT(m_port_1c, 0))
+ {
+ return m_touchpady->read();
+ }
+ else
+ {
+ return m_touchpadx->read();
+ }
+}
+
+
+void segaai_state::machine_start()
+{
+ m_i8255_portb = 0x7f;
+ m_upd7759_ctrl = 0;
+ m_port_1c = 0;
+ m_port_1d = 0;
+ m_port_1e = 0;
+ m_prev_v9938_irq = CLEAR_LINE;
+ m_prev_upd7759_irq = CLEAR_LINE;
+ m_touchpad_x = 0;
+ m_touchpad_y = 0;
+ m_vector = 0;
+ m_irq_enabled = 0;
+ m_irq_active = 0;
+
+ save_item(NAME(m_i8255_portb));
+ save_item(NAME(m_upd7759_ctrl));
+ save_item(NAME(m_port_1c));
+ save_item(NAME(m_port_1d));
+ save_item(NAME(m_port_1e));
+ save_item(NAME(m_prev_v9938_irq));
+ save_item(NAME(m_prev_upd7759_irq));
+ save_item(NAME(m_touchpad_x));
+ save_item(NAME(m_touchpad_y));
+ save_item(NAME(m_irq_active));
+ save_item(NAME(m_irq_enabled));
+ save_item(NAME(m_vector));
+
+ machine().crosshair().get_crosshair(0).set_screen(CROSSHAIR_SCREEN_NONE);
+}
+
+
+void segaai_state::segaai(machine_config &config)
+{
+ V20(config, m_maincpu, 20_MHz_XTAL/4);
+ m_maincpu->set_addrmap(AS_PROGRAM, &segaai_state::mem_map);
+ m_maincpu->set_addrmap(AS_IO, &segaai_state::io_map);
+ m_maincpu->set_irq_acknowledge_callback(FUNC(segaai_state::irq_callback));
+
+ V9938(config, m_v9938, 21.477272_MHz_XTAL);
+ m_v9938->set_screen_ntsc(m_screen);
+ m_v9938->set_vram_size(0x10000);
+ m_v9938->int_cb().set(FUNC(segaai_state::vdp_interrupt));
+
+ SCREEN(config, m_screen, SCREEN_TYPE_RASTER);
+
+ I8255(config, m_i8255);
+ m_i8255->in_pa_callback().set_ioport(m_port4);
+ m_i8255->in_pb_callback().set(FUNC(segaai_state::i8255_portb_r));
+ m_i8255->in_pc_callback().set(FUNC(segaai_state::i8255_portc_r));
+ m_i8255->out_pc_callback().set(FUNC(segaai_state::i8255_portc_w));
+
+ I8251(config, m_i8251, 0);
+
+ SPEAKER(config, "mono").front_center();
+
+ SN76489A(config, m_sound, 21.477272_MHz_XTAL/6); // not verified, but sounds close to real hw recordings
+ m_sound->add_route(ALL_OUTPUTS, "mono", 1.00);
+
+ UPD7759(config, m_upd7759);
+ m_upd7759->add_route(ALL_OUTPUTS, "mono", 0.70);
+ m_upd7759->drq().set(FUNC(segaai_state::upd7759_drq_w));
+
+ // Card slot
+ SEGAAI_CARD_SLOT(config, m_cardslot, segaai_cards, nullptr);
+ m_cardslot->set_address_space(m_maincpu, AS_PROGRAM);
+ SOFTWARE_LIST(config, "software").set_original("segaai");
+
+ // Expansion slot
+ SEGAAI_EXP_SLOT(config, m_expslot, 21'477'272/6, segaai_exp, nullptr); // not verified, assuming 3.58MHz
+ m_expslot->set_mem_space(m_maincpu, AS_PROGRAM);
+ m_expslot->set_io_space(m_maincpu, AS_IO);
+
+ // Built-in cassette
+ CASSETTE(config, m_cassette).set_stereo();
+ m_cassette->set_default_state(CASSETTE_STOPPED | CASSETTE_SPEAKER_ENABLED | CASSETTE_MOTOR_ENABLED);
+ m_cassette->set_interface("cass");
+ m_cassette->add_route(0, "mono", 0.70); // Channel 0 contains regular recorded sound
+ m_cassette->set_channel(1); // Channel 1 contains data
+
+ config.set_default_layout(layout_segaai);
+}
+
+
+ROM_START(segaai)
+ ROM_REGION(0x100000, "maincpu", 0)
+ ROM_LOAD("mpr-7689.ic5", 0xc0000, 0x20000, CRC(62402ac9) SHA1(bf52d22b119d54410dad4949b0687bb0edf3e143))
+ ROM_LOAD("e000 8_24.ic3", 0xe0000, 0x10000, CRC(c8b6a539) SHA1(cbf8473d1e3d8037ea98e9ca8b9aafdc8d16ff23)) // actual label is "e000 8/24"
+ ROM_LOAD("f000 7_21.ic4", 0xf0000, 0x10000, CRC(64d6cd8c) SHA1(68c130048f16d6a0abe1978e84440931470222d9)) // actual label is "f000 7/21"
+
+ ROM_REGION(0x40000, "upd7759", 0)
+ ROM_LOAD("mpr-7619.ic14", 0x00000, 0x20000, CRC(d1aea002) SHA1(c8d5408bba65b17301f19cf9ebd2b635d642525a))
+ ROM_LOAD("mpr-7620.ic15", 0x20000, 0x20000, CRC(e042754b) SHA1(02aede7a3e2fda9cbca621b530afa4520cf16610))
+ROM_END
+
+} // anonymous namespace
+
+COMP(1986, segaai, 0, 0, segaai, ai_kbd, segaai_state, empty_init, "Sega", "AI", MACHINE_NOT_WORKING)