From 245b399d0b020d36bdddd7cd7fc1401a7c8b06dd Mon Sep 17 00:00:00 2001 From: wilbertpol Date: Tue, 23 Jan 2024 21:23:49 +0000 Subject: [PATCH] New not working system & software list: Sega AI (#11747) * bus/segaai: Rename device_segaai_card_interface to segaai_card_interface * bus/segaai: Rename device_segaai_exp_interface to segaai_exp_interface * hash/segaai.xml: Add barcode for several titles. * hash/segaai.xml: Merge eigooha1 and eigooha2 into eigoohan, and eigogam1 and eigogam2 into eigogame. * hash/segaai.xml: Update description for Eigo de Ohanashi and Eigo de Game. * hash/segaai.xml: Add notes to Pinpon Music Rhythm and Melody. * hash/segaai.xml: Merge Okeiko Aiueo and Hanamaru Aiueo into a single software item. * hash/segaai.xml: Swapped checksums for Okeiko Aiueo and Hanamaru Aiueo and updated some notes. * hash/segaai.xml: Added and replaced some overlays. Added placeholders for some older revisions released on cassette. * hash/segaai.xml: Add cassette dumps of Alice World, Robinson Land, and Cosmis Train. * hash/segaai.xml: Add dumps of several older cassette versions. * hash/segaai.xml: Add/update serial, alt_title, and barcodes for cassette releases. * hash/segaai.xml: Use improved overlay scans. * layout/segaai.lay: Display clickable area when no overlay is present. * layout/segaai.lay: Make cursor square. * sega/segaai.cpp: Update old driver. * sega/segaai.cpp: Let cards and expansions install themselves. * sega/segaai.cpp: Adjust upd7759 sound level. * sega/segaai.cpp: Mark cassette as stereo. * sega/segaai.cpp: Only output the left channel from the cassette player. * sega/segaai.cpp: Set the cassette channel to use for data input. * sega/segaai.cpp: Add upd7759 busy signal to input port 4. --- hash/segaai.xml | 740 +++++++++++++++++++++++++ scripts/src/bus.lua | 19 + src/devices/bus/segaai/rom.cpp | 93 ++++ src/devices/bus/segaai/rom.h | 14 + src/devices/bus/segaai/segaai_exp.cpp | 48 ++ src/devices/bus/segaai/segaai_exp.h | 63 +++ src/devices/bus/segaai/segaai_slot.cpp | 99 ++++ src/devices/bus/segaai/segaai_slot.h | 73 +++ src/devices/bus/segaai/soundbox.cpp | 320 +++++++++++ src/devices/bus/segaai/soundbox.h | 14 + src/mame/layout/segaai.lay | 94 ++++ src/mame/mame.lst | 3 + src/mame/sega/segaai.cpp | 728 ++++++++++++++++++++++++ 13 files changed, 2308 insertions(+) create mode 100644 hash/segaai.xml create mode 100644 src/devices/bus/segaai/rom.cpp create mode 100644 src/devices/bus/segaai/rom.h create mode 100644 src/devices/bus/segaai/segaai_exp.cpp create mode 100644 src/devices/bus/segaai/segaai_exp.h create mode 100644 src/devices/bus/segaai/segaai_slot.cpp create mode 100644 src/devices/bus/segaai/segaai_slot.h create mode 100644 src/devices/bus/segaai/soundbox.cpp create mode 100644 src/devices/bus/segaai/soundbox.h create mode 100644 src/mame/layout/segaai.lay create mode 100644 src/mame/sega/segaai.cpp 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)