diff options
| author | 2025-08-19 16:04:52 +0200 | |
|---|---|---|
| committer | 2025-08-19 16:07:38 +0200 | |
| commit | d02041915289239b8d84544b5f216f7243bd3490 (patch) | |
| tree | e18261976ad89c94b602c30cf0a78e2f430d4038 | |
| parent | 0fbeb6294a26e227191b962b49da95a2d01472db (diff) | |
pc/teradrive: preliminary hookup of 286 view of MD space, Z80 basics, YM7101 VDP basics
* fix bug in PC side where menu cursors are uncontrollable (read pad inputs in MD space)
| -rw-r--r-- | scripts/src/video.lua | 13 | ||||
| -rw-r--r-- | src/devices/video/ym7101.cpp | 252 | ||||
| -rw-r--r-- | src/devices/video/ym7101.h | 72 | ||||
| -rw-r--r-- | src/mame/pc/teradrive.cpp | 274 |
4 files changed, 594 insertions, 17 deletions
diff --git a/scripts/src/video.lua b/scripts/src/video.lua index b73d2330269..4d1ff53036d 100644 --- a/scripts/src/video.lua +++ b/scripts/src/video.lua @@ -45,6 +45,19 @@ end -------------------------------------------------- -- +--@src/devices/video/ym7101.h,VIDEOS["YM7101"] = true +-------------------------------------------------- + +if (VIDEOS["YM7101"]~=null) then + files { + MAME_DIR .. "src/devices/video/ym7101.cpp", + MAME_DIR .. "src/devices/video/ym7101.h", + } +end + + +-------------------------------------------------- +-- --@src/devices/video/am8052.h,VIDEOS["AM8052"] = true -------------------------------------------------- diff --git a/src/devices/video/ym7101.cpp b/src/devices/video/ym7101.cpp new file mode 100644 index 00000000000..7ee842f68bc --- /dev/null +++ b/src/devices/video/ym7101.cpp @@ -0,0 +1,252 @@ +// license:BSD-3-Clause +// copyright-holders:Angelo Salese +/************************************************************************************************** + +Rewrite of Sega 315-5315 MD VDP (tied to Teradrive) + +Notes: +- Teradrive actually has 128 KiB compared to stock 64, this means that d_titov2 won't possibly work +here; +- Should eventually derive from 315-5124 (the SMS VDP); + +**************************************************************************************************/ + +#include "emu.h" +#include "ym7101.h" + +#define LOG_REGS (1U << 1) + +#define VERBOSE (LOG_GENERAL | LOG_REGS) +//#define LOG_OUTPUT_FUNC osd_printf_info +#include "logmacro.h" + +#define LOGREGS(...) LOGMASKED(LOG_REGS, __VA_ARGS__) + + +DEFINE_DEVICE_TYPE(YM7101, ym7101_device, "ym7101", "Yamaha YM7101") + +ym7101_device::ym7101_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) + : device_t(mconfig, YM7101, tag, owner, clock) + , device_memory_interface(mconfig, *this) + , device_video_interface(mconfig, *this) + , m_space_vram_config("videoram", ENDIANNESS_BIG, 8, 17, 0, address_map_constructor(FUNC(ym7101_device::vram_map), this)) + , m_space_regs_config("regs", ENDIANNESS_BIG, 8, 6, 0, address_map_constructor(FUNC(ym7101_device::regs_map), this)) + , m_vint_callback(*this) +// , m_hint_callback(*this) + , m_sint_callback(*this) +{ +} + +void ym7101_device::device_start() +{ + m_scan_timer = timer_alloc(FUNC(ym7101_device::scan_timer_callback), this); +} + +void ym7101_device::device_reset() +{ + m_ie0 = false; + m_scan_timer->adjust(screen().time_until_pos(224), 224); +} + +device_memory_interface::space_config_vector ym7101_device::memory_space_config() const +{ + return space_config_vector { + std::make_pair(AS_DATA, &m_space_vram_config), + std::make_pair(AS_IO, &m_space_regs_config) + }; +} + + +void ym7101_device::if_map(address_map &map) +{ + // Control Port + map(0x04, 0x05).mirror(2).lrw16( + NAME([this] (offs_t offset, u16 mem_mask) { + return screen().vblank() << 3; + }), + NAME([this] (offs_t offset, u16 data, u16 mem_mask) { + //printf("%04x %04x\n", data, mem_mask); + if (ACCESSING_BITS_0_15) + { + // TODO: as FIFO + if ((data & 0xc000) == 0x8000) + { + space(AS_IO).write_byte((data >> 8) & 0x3f, data & 0xff); + } + } + }) + ); +} + +void ym7101_device::vram_map(address_map &map) +{ + if (!has_configured_map(0)) + map(0x00000, 0x1ffff).ram(); +} + +// https://plutiedev.com/vdp-registers +// https://segaretro.org/Sega_Mega_Drive/VDP_registers +// NOTE: in decimal units, classic Yamaha +static const char *const size_names[] = { "256/32", "512/64", "<invalid>", "1024/128" }; + +void ym7101_device::regs_map(address_map &map) +{ + map(0, 0).lw8(NAME([this] (u8 data) { + LOGREGS("#00: Mode Register 1 %02x\n", data); + LOGREGS("\tL %d IE1 %d M4: %d M3: %d DE: %d\n" + , BIT(data, 5) + , BIT(data, 4) + , BIT(data, 2) + , BIT(data, 1) + , BIT(data, 0) + ); + })); + map(1, 1).lw8(NAME([this] (u8 data) { + LOGREGS("#01: Mode Register 2 %02x\n", data); + m_ie0 = !!BIT(data, 5); + LOGREGS("\tVR %d DE %d IE0: %d M1: %d M2: %d M5: %d\n" + , BIT(data, 7) + , BIT(data, 6) + , m_ie0 + , BIT(data, 4) + , BIT(data, 3) + , BIT(data, 2) + ); + })); + map(2, 2).lw8(NAME([this] (u8 data) { + LOGREGS("#02: Plane A Name Table %02x (%05x)\n" + , data + , (data & 0x78) << 10 + ); + })); + map(3, 3).lw8(NAME([this] (u8 data) { + LOGREGS("#03: Window Name Table %02x (%05x)\n" + , data + , (data & 0x7e) << 10 + ); + })); + map(4, 4).lw8(NAME([this] (u8 data) { + LOGREGS("#04: Plane B Name Table %02x (%05x)\n" + , data + , (data & 0xf) << 13 + ); + })); + map(5, 5).lw8(NAME([this] (u8 data) { + LOGREGS("#05: Sprite Table %02x (%05x)\n" + , data + , data << 9 + ); + })); + map(6, 6).lw8(NAME([this] (u8 data) { + LOGREGS("#06: 128kB Sprite Table %02x (%d)\n", data , BIT(data, 5)); + })); + map(7, 7).lw8(NAME([this] (u8 data) { + LOGREGS("#07: Background Color %02x & 0x3f\n", data); + })); +// map(8, 8) Master System h scroll +// map(9, 9) Master System v scroll + map(10, 10).lw8(NAME([this] (u8 data) { + LOGREGS("#10: Horizontal Interrupt Counter %02x (%d)\n", data, data); + })); + // <-- mode 4 ignores everything beyond this point + map(11, 11).lw8(NAME([this] (u8 data) { + LOGREGS("#11: Mode Register 3 %02x\n", data); + LOGREGS("\tIE2 %d VS %d HS %d\n" + , BIT(data, 3) + , BIT(data, 2) + , data & 3 + ); + })); + map(12, 12).lw8(NAME([this] (u8 data) { + LOGREGS("#12: Mode Register 4 %02x\n", data); + LOGREGS("\tRSx %d (%s) VS %d HS %d EP %d SH %d LSx %d\n" + , BIT(data, 7) + , BIT(data, 7) ? "H320" : "H256" + , BIT(data, 6) + , BIT(data, 5) + , BIT(data, 4) + , BIT(data, 3) + , (data & 6) >> 1 + ); + if (BIT(data, 7) != BIT(data, 0)) + popmessage("ym7101.cpp: invalid RS setting %02x", data & 0x81); + })); + map(13, 13).lw8(NAME([this] (u8 data) { + LOGREGS("#13: Horizontal Scroll address %02x (%05x)\n", data, (data & 0x7f) << 10); + })); + map(14, 14).lw8(NAME([this] (u8 data) { + // TODO: extra address bits for 128 KiB mode? + LOGREGS("#14: 128 KiB plane address %02x (%02x)\n", data, data & 0x11); + })); + map(15, 15).lw8(NAME([this] (u8 data) { + LOGREGS("#15: autoincrement %02x\n", data); + })); + map(16, 16).lw8(NAME([this] (u8 data) { + LOGREGS("#16: Plane Size %02x\n", data); + LOGREGS("\tH %d (%s) V %d (%s)\n" + , (data & 0x30) >> 4 + , size_names[(data & 0x30) >> 4] + , (data & 3) + , size_names[(data & 0x3)] + ); + })); + map(17, 17).lw8(NAME([this] (u8 data) { + LOGREGS("#17: Window Plane Horizontal position %02x\n", data); + LOGREGS("\tR %d HP %d\n" + , BIT(data, 7) + , (data & 0x1f) * 8 + ); + })); + map(18, 18).lw8(NAME([this] (u8 data) { + LOGREGS("#18: Window Plane Vertical position %02x\n", data); + LOGREGS("\tD %d VP %d\n" + , BIT(data, 7) + , (data & 0x1f) * 8 + ); + })); + map(19, 19).lw8(NAME([this] (u8 data) { + LOGREGS("#19: DMA length low %02x\n", data); + })); + map(20, 20).lw8(NAME([this] (u8 data) { + LOGREGS("#20: DMA length high %02x\n", data); + })); + map(21, 21).lw8(NAME([this] (u8 data) { + LOGREGS("#21: DMA source low %02x\n", data); + })); + map(22, 22).lw8(NAME([this] (u8 data) { + LOGREGS("#22: DMA source mid %02x\n", data); + })); + map(23, 23).lw8(NAME([this] (u8 data) { + LOGREGS("#23: DMA source high %02x data %02x mode %02x\n", data, data & 0x3f, data >> 6); + })); + +} + +TIMER_CALLBACK_MEMBER(ym7101_device::scan_timer_callback) +{ + int scanline = param; + + // TODO: to execution pipeline + if (scanline == 224 && m_ie0) + { + m_vint_callback(true); + } + + // TODO: correct? + if (scanline == 240) + m_sint_callback(true); + if (scanline == 241) + m_sint_callback(false); + + scanline ++; + scanline %= screen().height(); + + m_scan_timer->adjust(screen().time_until_pos(scanline), scanline); +} + +u32 ym7101_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect) +{ + return 0; +} + + diff --git a/src/devices/video/ym7101.h b/src/devices/video/ym7101.h new file mode 100644 index 00000000000..f3b4faf2c66 --- /dev/null +++ b/src/devices/video/ym7101.h @@ -0,0 +1,72 @@ +// license:BSD-3-Clause +// copyright-holders:Angelo Salese + +#ifndef MAME_VIDEO_YM7101_H +#define MAME_VIDEO_YM7101_H + +#pragma once + +#include "machine/timer.h" +//#include "sound/sn76496.h" + +#include "emupal.h" +#include "screen.h" + +class ym7101_device : public device_t, + public device_memory_interface, + public device_video_interface +{ +public: + ym7101_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock); + + void if_map(address_map &map) ATTR_COLD; + + auto vint_cb() { return m_vint_callback.bind(); } + //auto hint_cb() { return m_lv4irqline_callback.bind(); } + auto sint_cb() { return m_sint_callback.bind(); } + + u32 screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect); + + void irq_ack() + { + if (machine().side_effects_disabled()) + return; + + //if (m_vint_pending) + //{ + // m_vint_pending = 0; + m_vint_callback(false); + //} + //else if (m_hint_pending) + //{ + // m_hint_pending = 0; + // m_hint_callback(false); + //} + } + +protected: + virtual void device_start() override ATTR_COLD; + virtual void device_reset() override ATTR_COLD; + virtual space_config_vector memory_space_config() const override; + +private: + void vram_map(address_map &map) ATTR_COLD; + void regs_map(address_map &map) ATTR_COLD; + + const address_space_config m_space_vram_config; + const address_space_config m_space_regs_config; + + devcb_write_line m_vint_callback; +// devcb_write_line m_hint_callback; + devcb_write_line m_sint_callback; + + TIMER_CALLBACK_MEMBER(scan_timer_callback); + emu_timer *m_scan_timer; + + bool m_ie0; +}; + +DECLARE_DEVICE_TYPE(YM7101, ym7101_device) + + +#endif // MAME_VIDEO_YM7101_H diff --git a/src/mame/pc/teradrive.cpp b/src/mame/pc/teradrive.cpp index 51b24b8f40b..304004076d8 100644 --- a/src/mame/pc/teradrive.cpp +++ b/src/mame/pc/teradrive.cpp @@ -1,23 +1,30 @@ // license:BSD-3-Clause // copyright-holders: Angelo Salese +// thanks-to: Mask of Destiny /************************************************************************************************** Sega Teradrive IBM PS/2 Model 30 (PS/55 5510Z) + Japanese Sega Mega Drive (TMSS MD1 VA3 or VA4) -References: +References (Teradrive specifics): - https://www.retrodev.com/blastem/trac/wiki/TeradriveHardwareNotes +- https://plutiedev.com/mirror/teradrive-hardware-info +- https://github.com/RetroSwimAU/TeradriveCode +- https://www.youtube.com/watch?v=yjg3gmTo4WA +- https://www.asahi-net.or.jp/~ds6k-mtng/tera.htm + +References (generic MD): - https://plutiedev.com/cartridge-slot - https://plutiedev.com/vdp-registers - https://segaretro.org/Sega_Mega_Drive/VDP_general_usage -- https://plutiedev.com/mirror/teradrive-hardware-info - https://segaretro.org/Sega_Mega_Drive/Technical_specifications -- https://github.com/RetroSwimAU/TeradriveCode -- https://www.youtube.com/watch?v=yjg3gmTo4WA +- https://gendev.spritesmind.net/forum/viewtopic.php?p=37011#p37011 NOTES (PC side): - F1 at POST will bring a setup menu; +- F2 (allegedly at DOS/V boot) will dual boot the machine; +- a program named VVCHG switches back and forth between MD and PC, and setup 68k to 10 MHz mode; NOTES (MD side): - 16 KiB of Z80 RAM (vs. 8 of stock) @@ -27,30 +34,38 @@ NOTES (MD side): - focus 3 is the current default for MD side TODO: -- keyboard issues on Sega menu (hold arrow and press enter to go to floppy loading); - "TIMER FAIL" when exiting from setup menu (keyboard?); - RAM size always gets detected as 2560K even when it's not (from chipset?); - Quadtel EMM driver fails recognizing WD76C10 chipset with j4.0 driver disk; - Cannot HDD format with floppy insthdd.bat, cannot boot from HDD (needs floppy first). Attached disk is a WDL-330PS with no geometry info available; +- ISA16 needs a way to install 16-bit handlers for 68k accesses to work + (matters for pzlcnst game.exe, that will access VDP ports from 286); - MD side, as a testbed for rewriting base HW; +- hookup MD control ports (needs sega/mdioport.h to be moved out); +- SEGA TERADRIVE テラドライブ ユーザーズマニュアル known to exist (not scanned yet) **************************************************************************************************/ #include "emu.h" -#include "bus/generic/slot.h" #include "bus/generic/carts.h" +#include "bus/generic/slot.h" +#include "bus/isa/isa.h" #include "bus/isa/isa_cards.h" #include "bus/pc_kbd/keyboards.h" #include "bus/pc_kbd/pc_kbdc.h" +//#include "bus/sms_ctrl/smsctrl.h" #include "cpu/i86/i286.h" //#include "cpu/i386/i386.h" #include "cpu/m68000/m68000.h" -#include "machine/at.h" +#include "cpu/z80/z80.h" #include "machine/ram.h" #include "machine/wd7600.h" +#include "sound/spkrdev.h" +#include "sound/ymopn.h" +#include "video/ym7101.h" #include "screen.h" #include "softlist_dev.h" @@ -70,6 +85,7 @@ public: isa16_ibm_79f2661(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); template <typename T> void set_romdisk_tag(T &&tag) { m_romdisk.set_tag(std::forward<T>(tag)); } + template <typename T> void set_md_space(T &&tag, int index) { m_md_space.set_tag(std::forward<T>(tag), index); } auto tmss_bank_callback() { return m_tmss_bank_cb.bind(); } auto reg_1163_read_callback() { return m_reg_1163_read_cb.bind(); } auto reg_1163_write_callback() { return m_reg_1163_write_cb.bind(); } @@ -83,8 +99,11 @@ protected: private: required_memory_region m_romdisk; memory_bank_creator m_rom_window_bank; + // TODO: may be optional for 5510Z + required_address_space m_md_space; void io_map(address_map &map) ATTR_COLD; + void md_mem_map(address_map &map) ATTR_COLD; void remap(int space_id, offs_t start, offs_t end) override; @@ -93,6 +112,7 @@ private: u8 m_reg_1163 = 0; u8 m_reg_1164 = 0; u16 m_68k_address = 0; + bool m_68k_view = false; devcb_write8 m_tmss_bank_cb; devcb_read8 m_reg_1163_read_cb; @@ -108,6 +128,7 @@ isa16_ibm_79f2661::isa16_ibm_79f2661(const machine_config &mconfig, const char * , device_isa16_card_interface(mconfig, *this) , m_romdisk(*this, finder_base::DUMMY_TAG) , m_rom_window_bank(*this, "rom_window_bank") + , m_md_space(*this, finder_base::DUMMY_TAG, -1) , m_tmss_bank_cb(*this) , m_reg_1163_read_cb(*this, 0) , m_reg_1163_write_cb(*this) @@ -127,6 +148,7 @@ void isa16_ibm_79f2661::device_reset() m_rom_bank = 0; m_rom_address = 0x0e; m_reg_1163 = 0; + m_68k_view = false; m_reg_1164 = 0; m_68k_address = 0; m_reg_1163_write_cb(0); @@ -135,13 +157,43 @@ void isa16_ibm_79f2661::device_reset() remap(AS_IO, 0, 0xffff); } +// TODO: ISA has no method for 16-bit installs! +void isa16_ibm_79f2661::md_mem_map(address_map &map) +{ + map(0x0000, 0x1fff).lrw8( + NAME([this] (offs_t offset) { + return m_md_space->read_byte((offset) + (m_68k_address << 12)); + }), + NAME([this] (offs_t offset, u8 data) { + m_md_space->write_byte((offset) + (m_68k_address << 12), data); + }) + ); +// map(0x0000, 0x1fff).lrw16( +// NAME([this] (offs_t offset, u16 mem_mask) { +// printf("%05x & %08x\n", (offset << 1) + (m_68k_address << 12), mem_mask); +// return swapendian_int16(m_md_space->read_word((offset << 1) + (m_68k_address << 12), swapendian_int16(mem_mask))); +// }), +// NAME([this] (offs_t offset, u16 data, u16 mem_mask) { +// m_md_space->write_word((offset << 1) + (m_68k_address << 12), swapendian_int16(data), swapendian_int16(mem_mask)); +// }) +// ); +} + void isa16_ibm_79f2661::remap(int space_id, offs_t start, offs_t end) { if (space_id == AS_PROGRAM) { - u32 base_addr = (m_rom_address << 12) | 0xc0000; - //printf("%08x %02x\n", base_addr, m_rom_bank); - m_isa->install_bank(base_addr, base_addr | 0x1fff, m_rom_window_bank); + const u32 base_addr = (m_rom_address << 12) | 0xc0000; + + if (m_68k_view) + { + m_isa->install_memory(base_addr, base_addr | 0x1fff, *this, &isa16_ibm_79f2661::md_mem_map); + } + else + { + //printf("%08x %02x\n", base_addr, m_rom_bank); + m_isa->install_bank(base_addr, base_addr | 0x1fff, m_rom_window_bank); + } } if (space_id == AS_IO) { @@ -198,6 +250,13 @@ void isa16_ibm_79f2661::io_map(address_map &map) return (m_reg_1163 & 0xcf) | (m_reg_1163_read_cb() & 0x30); }), NAME([this] (offs_t offset, u8 data) { + logerror("$1163: %02x\n", data); + if (BIT(data, 1) != BIT(m_reg_1163, 1)) + { + m_68k_view = !!BIT(data, 1); + remap(AS_PROGRAM, 0, 0xfffff); + } + m_reg_1163 = data; m_reg_1163_write_cb(data); }) @@ -240,6 +299,8 @@ void isa16_ibm_79f2661::io_map(address_map &map) NAME([this] (offs_t offset, u16 data, u16 mem_mask) { COMBINE_DATA(&m_68k_address); m_68k_address &= 0xffffe; + //if (m_68k_view) + // remap(AS_PROGRAM, 0, 0xfffff); }) ); } @@ -259,10 +320,15 @@ public: , m_speaker(*this, "speaker") , m_system_in(*this, "SYSTEM_IN") , m_md68kcpu(*this, "md68kcpu") + , m_mdz80cpu(*this, "mdz80cpu") , m_mdscreen(*this, "mdscreen") , m_tmss_bank(*this, "tmss_bank") , m_tmss_view(*this, "tmss_view") , m_md_cart(*this, "md_cart") + , m_md_vdp(*this, "md_vdp") + , m_opn(*this, "opn") + , m_md_68k_sound_view(*this, "md_68k_sound_view") + //, m_md_ctrl_ports(*this, { "md_ctrl1", "md_ctrl2", "md_exp" }) { } void teradrive(machine_config &config); @@ -276,6 +342,9 @@ protected: void x86_map(address_map &map) ATTR_COLD; void md_68k_map(address_map &map) ATTR_COLD; + void md_cpu_space_map(address_map &map); + void md_68k_z80_map(address_map &map) ATTR_COLD; + void md_z80_map(address_map &map) ATTR_COLD; private: required_device<i80286_cpu_device> m_x86cpu; required_device<wd7600_device> m_chipset; @@ -323,11 +392,15 @@ private: // MD side required_device<m68000_device> m_md68kcpu; -// required_device<z80_device> m_mdz80cpu; + required_device<z80_device> m_mdz80cpu; required_device<screen_device> m_mdscreen; required_memory_bank m_tmss_bank; memory_view m_tmss_view; required_device<generic_slot_device> m_md_cart; + required_device<ym7101_device> m_md_vdp; + required_device<ym_generic_device> m_opn; + memory_view m_md_68k_sound_view; + //optional_device_array<sms_control_port_device, 3> m_md_ctrl_ports; // TODO: main PC screen can also swap the VGA with this // (roughly #5801 and #11343 league) @@ -335,6 +408,11 @@ private: u8 m_isa_address_bank = 0; u8 m_68k_hs = 0; + std::unique_ptr<u8[]> m_sound_program; + bool m_z80_reset = false; + bool m_z80_busrq = false; + void flush_z80_state(); + u32 m_z80_main_address = 0; }; void teradrive_state::x86_map(address_map &map) @@ -365,7 +443,7 @@ void teradrive_state::x86_io(address_map &map) u32 teradrive_state::md_screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect) { - // m_mdvdp->screen_update(...); + m_md_vdp->screen_update(screen, bitmap, cliprect); return 0; } @@ -391,12 +469,52 @@ void teradrive_state::md_68k_map(address_map &map) m_tmss_view[0](0x000000, 0x000fff).bankr(m_tmss_bank); // map(0x800000, 0x9fffff) unmapped or 32X -// map(0xa00000, 0xa07eff).mirror(0x8000) Z80 address space -// map(0xa07f00, 0xa07fff).mirror(0x8000) Z80 VDP space (freezes machine if accessed from 68k) + map(0xa00000, 0xa07fff).view(m_md_68k_sound_view); + m_md_68k_sound_view[0](0xa00000, 0xa07fff).m(*this, FUNC(teradrive_state::md_68k_z80_map)); +// map(0xa07f00, 0xa07fff) Z80 VDP space (freezes machine if accessed from 68k) +// map(0xa08000, 0xa0ffff) Z80 68k window (assume no DTACK) // map(0xa10000, 0xa100ff) I/O // map(0xa11000, 0xa110ff) memory mode register // map(0xa11100, 0xa111ff) Z80 BUSREQ/BUSACK + map(0xa11100, 0xa11101).lrw16( + NAME([this] (offs_t offset, u16 mem_mask) { + u16 res = (m_z80_busrq || m_z80_reset) << 8; + return res; + }), + NAME([this] (offs_t offset, u16 data, u16 mem_mask) { + if (!ACCESSING_BITS_0_7) + { + m_z80_busrq = !!BIT(~data, 8); + } + else if (!ACCESSING_BITS_8_15) + { + m_z80_busrq = !!BIT(~data, 0); + } + else // word access + { + m_z80_busrq = !!BIT(~data, 8); + } + flush_z80_state(); + }) + ); // map(0xa11200, 0xa112ff) Z80 RESET + map(0xa11200, 0xa11201).lw16( + NAME([this] (offs_t offset, u16 data, u16 mem_mask) { + if (!ACCESSING_BITS_0_7) + { + m_z80_reset = !!BIT(~data, 8); + } + else if (!ACCESSING_BITS_8_15) + { + m_z80_reset = !!BIT(~data, 0); + } + else // word access + { + m_z80_reset = !!BIT(~data, 8); + } + flush_z80_state(); + }) + ); // map(0xa11300, 0xa113ff) <open bus> // map(0xa11400, 0xa1dfff) <unmapped> (no DTACK generation, freezes machine without additional HW) @@ -434,12 +552,92 @@ void teradrive_state::md_68k_map(address_map &map) }) ); // map(0xc00000, 0xdfffff) VDP and PSG (with mirrors and holes) - map(0xc00005, 0xc00005).lr8(NAME([this] (offs_t offset) { - return m_mdscreen->vblank() << 3; - })); + map(0xc00000, 0xc0001f).m(m_md_vdp, FUNC(ym7101_device::if_map)); map(0xe00000, 0xe0ffff).mirror(0x1f0000).ram(); // Work RAM, usually accessed at $ff0000 } +void teradrive_state::md_cpu_space_map(address_map &map) +{ + map(0xfffff3, 0xfffff3).before_time(m_md68kcpu, FUNC(m68000_device::vpa_sync)).after_delay(m_md68kcpu, FUNC(m68000_device::vpa_after)).lr8(NAME([] () -> u8 { return 25; })); + // TODO: IPL0 (external irq tied to VDP IE2) + map(0xfffff5, 0xfffff5).before_time(m_md68kcpu, FUNC(m68000_device::vpa_sync)).after_delay(m_md68kcpu, FUNC(m68000_device::vpa_after)).lr8(NAME([] () -> u8 { return 26; })); + map(0xfffff7, 0xfffff7).before_time(m_md68kcpu, FUNC(m68000_device::vpa_sync)).after_delay(m_md68kcpu, FUNC(m68000_device::vpa_after)).lr8(NAME([] () -> u8 { return 27; })); + // TODO: IPL1 + map(0xfffff9, 0xfffff9).before_time(m_md68kcpu, FUNC(m68000_device::vpa_sync)).after_delay(m_md68kcpu, FUNC(m68000_device::vpa_after)).lr8(NAME([this] () -> u8 { + //m_md_vdp->irq_ack(); + return 28; + })); + map(0xfffffb, 0xfffffb).before_time(m_md68kcpu, FUNC(m68000_device::vpa_sync)).after_delay(m_md68kcpu, FUNC(m68000_device::vpa_after)).lr8(NAME([] () -> u8 { return 29; })); + map(0xfffffd, 0xfffffd).before_time(m_md68kcpu, FUNC(m68000_device::vpa_sync)).after_delay(m_md68kcpu, FUNC(m68000_device::vpa_after)).lr8(NAME([this] () -> u8 { + m_md_vdp->irq_ack(); + return 30; + })); + map(0xffffff, 0xffffff).before_time(m_md68kcpu, FUNC(m68000_device::vpa_sync)).after_delay(m_md68kcpu, FUNC(m68000_device::vpa_after)).lr8(NAME([] () -> u8 { return 31; })); +} + + +void teradrive_state::flush_z80_state() +{ + m_mdz80cpu->set_input_line(INPUT_LINE_RESET, m_z80_reset ? ASSERT_LINE : CLEAR_LINE); + m_mdz80cpu->set_input_line(Z80_INPUT_LINE_BUSRQ, m_z80_busrq ? CLEAR_LINE : ASSERT_LINE); + if (!m_z80_reset && !m_z80_busrq) + m_md_68k_sound_view.select(0); + else + m_md_68k_sound_view.disable(); +} + +void teradrive_state::md_68k_z80_map(address_map &map) +{ + map(0x0000, 0x3fff).lrw16( + NAME([this] (offs_t offset, u16 mem_mask) { + u16 res = m_sound_program[(offset << 1) ^ 1] | (m_sound_program[offset << 1] << 8); + return res; + }), + NAME([this] (offs_t offset, u16 data, u16 mem_mask) { + if (!ACCESSING_BITS_0_7) + { + m_sound_program[(offset<<1)] = (data & 0xff00) >> 8; + } + else if (!ACCESSING_BITS_8_15) + { + m_sound_program[(offset<<1) ^ 1] = (data & 0x00ff); + } + else + { + m_sound_program[(offset<<1)] = (data & 0xff00) >> 8; + } + }) + ); + map(0x4000, 0x4003).mirror(0x1ffc).rw(m_opn, FUNC(ym_generic_device::read), FUNC(ym_generic_device::write)); +} + +void teradrive_state::md_z80_map(address_map &map) +{ + map(0x0000, 0x3fff).lrw8( + NAME([this] (offs_t offset) { + return m_sound_program[offset]; + }), + NAME([this] (offs_t offset, u8 data) { + m_sound_program[offset] = data; + }) + ); + map(0x4000, 0x4003).mirror(0x1ffc).rw(m_opn, FUNC(ym_generic_device::read), FUNC(ym_generic_device::write)); + map(0x6000, 0x60ff).lw8(NAME([this] (offs_t offset, u8 data) { + m_z80_main_address = ((m_z80_main_address >> 1) | ((data & 1) << 23)) & 0xff8000; + })); + map(0x8000, 0xffff).lrw8( + NAME([this] (offs_t offset) { + address_space &space68k = m_md68kcpu->space(); + u8 ret = space68k.read_byte(m_z80_main_address + offset); + return ret; + + }), + NAME([this] (offs_t offset, u8 data) { + address_space &space68k = m_md68kcpu->space(); + space68k.write_byte(m_z80_main_address + offset, data); + }) + ); +} /* @@ -498,6 +696,7 @@ void teradrive_state::romdisk_config(device_t *device) auto *state = device->subdevice<teradrive_state>(":"); isa16_ibm_79f2661 &bus_switch = *downcast<isa16_ibm_79f2661 *>(device); bus_switch.set_romdisk_tag("romdisk"); + bus_switch.set_md_space(":md68kcpu", AS_PROGRAM); bus_switch.tmss_bank_callback().set(*state, FUNC(teradrive_state::tmss_bank_w)); bus_switch.reg_1163_read_callback().set(*state, FUNC(teradrive_state::reg_1163_r)); bus_switch.reg_1163_write_callback().set(*state, FUNC(teradrive_state::reg_1163_w)); @@ -526,11 +725,15 @@ INPUT_PORTS_END void teradrive_state::machine_start() { m_tmss_bank->configure_entries(0, 0x200, memregion("tmss")->base(), 0x1000); + // doubled in space + m_sound_program = std::make_unique<u8[]>(0x4000); } void teradrive_state::machine_reset() { m_68k_hs = 0; + m_z80_reset = true; + flush_z80_state(); } void teradrive_isa_cards(device_slot_interface &device) @@ -644,17 +847,54 @@ void teradrive_state::teradrive(machine_config &config) M68000(config, m_md68kcpu, md_master_xtal / 7); m_md68kcpu->set_addrmap(AS_PROGRAM, &teradrive_state::md_68k_map); + m_md68kcpu->set_addrmap(m68000_base_device::AS_CPU_SPACE, &teradrive_state::md_cpu_space_map); + + Z80(config, m_mdz80cpu, md_master_xtal / 7 / 2); + m_mdz80cpu->set_addrmap(AS_PROGRAM, &teradrive_state::md_z80_map); SCREEN(config, m_mdscreen, SCREEN_TYPE_RASTER); // NOTE: PAL is 423x312 m_mdscreen->set_raw(md_master_xtal / 8, 427, 0, 320, 262, 0, 224); m_mdscreen->set_screen_update(FUNC(teradrive_state::md_screen_update)); + YM7101(config, m_md_vdp, md_master_xtal / 4); + m_md_vdp->set_screen(m_mdscreen); + m_md_vdp->vint_cb().set_inputline(m_md68kcpu, 6); +// m_md_vdp->hint_cb().set_inputline(m_md68kcpu, 4); + m_md_vdp->sint_cb().set_inputline(m_mdz80cpu, INPUT_LINE_IRQ0); + +// SMS_CONTROL_PORT(config, m_ctrl_ports[0], sms_control_port_devices, SMS_CTRL_OPTION_MD_PAD); +// m_ctrl_ports[0]->th_handler().set(m_ioports[0], FUNC(megadrive_io_port_device::th_w)); +// m_ctrl_ports[0]->set_screen(m_screen); +// +// m_ioports[0]->set_in_handler(m_ctrl_ports[0], FUNC(sms_control_port_device::in_r)); +// m_ioports[0]->set_out_handler(m_ctrl_ports[0], FUNC(sms_control_port_device::out_w)); +// +// SMS_CONTROL_PORT(config, m_ctrl_ports[1], sms_control_port_devices, SMS_CTRL_OPTION_MD_PAD); +// m_ctrl_ports[1]->th_handler().set(m_ioports[1], FUNC(megadrive_io_port_device::th_w)); +// m_ctrl_ports[1]->set_screen(m_screen); +// +// m_ioports[1]->set_in_handler(m_ctrl_ports[1], FUNC(sms_control_port_device::in_r)); +// m_ioports[1]->set_out_handler(m_ctrl_ports[1], FUNC(sms_control_port_device::out_w)); +// +// SMS_CONTROL_PORT(config, m_ctrl_ports[2], sms_control_port_devices, nullptr); +// m_ctrl_ports[2]->th_handler().set(m_ioports[2], FUNC(megadrive_io_port_device::th_w)); +// m_ctrl_ports[2]->set_screen(m_screen); +// +// m_ioports[2]->set_in_handler(m_ctrl_ports[2], FUNC(sms_control_port_device::in_r)); +// m_ioports[2]->set_out_handler(m_ctrl_ports[2], FUNC(sms_control_port_device::out_w)); + // TODO: vestigial GENERIC_CARTSLOT(config, m_md_cart, generic_plain_slot, "megadriv_cart"); m_md_cart->set_width(GENERIC_ROM16_WIDTH); // TODO: generic_cartslot has issues with softlisted endianness (use loose for now) m_md_cart->set_endian(ENDIANNESS_BIG); + + SPEAKER(config, "md_speaker", 2).front(); + + YM2612(config, m_opn, md_master_xtal / 7); + m_opn->add_route(0, "md_speaker", 0.50, 0); + m_opn->add_route(1, "md_speaker", 0.50, 1); } ROM_START( teradrive ) |
