summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
author angelosa <lordkale4@gmail.com>2025-08-19 16:04:52 +0200
committer angelosa <lordkale4@gmail.com>2025-08-19 16:07:38 +0200
commitd02041915289239b8d84544b5f216f7243bd3490 (patch)
treee18261976ad89c94b602c30cf0a78e2f430d4038
parent0fbeb6294a26e227191b962b49da95a2d01472db (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.lua13
-rw-r--r--src/devices/video/ym7101.cpp252
-rw-r--r--src/devices/video/ym7101.h72
-rw-r--r--src/mame/pc/teradrive.cpp274
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 )