summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
author mamehaze <140764005+mamehaze@users.noreply.github.com>2026-05-15 16:46:53 +0100
committer GitHub <noreply@github.com>2026-05-15 17:46:53 +0200
commit6db34f14119b1b46c87e17af74b07544b6948e7a (patch)
tree0f5433ee0e1c2a9eb5b2d3685b909b9d1ba2402c
parente16cbf731e69d5df95a0cfcb954d25af9a228b64 (diff)
add sound to bftetris (#15342)
- added CHA/CHB (tied to timers g/h) for DAC sound output on GPL951xx, which is used by bftetris
-rw-r--r--scripts/src/machine.lua2
-rw-r--r--src/devices/machine/generalplus_gpl162xx_soc_video.cpp192
-rw-r--r--src/devices/machine/generalplus_gpl951xx_soc.cpp275
-rw-r--r--src/devices/machine/generalplus_gpl951xx_soc.h45
-rw-r--r--src/devices/machine/generalplus_gpl_chx.cpp341
-rw-r--r--src/devices/machine/generalplus_gpl_chx.h66
-rw-r--r--src/devices/machine/generalplus_gpl_dma.cpp7
-rw-r--r--src/devices/machine/generalplus_gpl_dma.h1
8 files changed, 800 insertions, 129 deletions
diff --git a/scripts/src/machine.lua b/scripts/src/machine.lua
index 14828a0e7d6..e47b20d0b9a 100644
--- a/scripts/src/machine.lua
+++ b/scripts/src/machine.lua
@@ -3601,6 +3601,8 @@ if MACHINES["SPG2XX"] then
MAME_DIR .. "src/devices/machine/generalplus_gpl_dma.h",
MAME_DIR .. "src/devices/machine/generalplus_gpl_timebase.cpp",
MAME_DIR .. "src/devices/machine/generalplus_gpl_timebase.h",
+ MAME_DIR .. "src/devices/machine/generalplus_gpl_chx.cpp",
+ MAME_DIR .. "src/devices/machine/generalplus_gpl_chx.h",
MAME_DIR .. "src/devices/machine/spg_renderer.cpp",
MAME_DIR .. "src/devices/machine/spg_renderer.h",
MAME_DIR .. "src/devices/machine/gpl_renderer.cpp",
diff --git a/src/devices/machine/generalplus_gpl162xx_soc_video.cpp b/src/devices/machine/generalplus_gpl162xx_soc_video.cpp
index cf5b56ce346..c8e8f17c0ac 100644
--- a/src/devices/machine/generalplus_gpl162xx_soc_video.cpp
+++ b/src/devices/machine/generalplus_gpl162xx_soc_video.cpp
@@ -816,18 +816,65 @@ void gcm394_base_video_device::video_dma_size_trigger_w(address_space &space, u1
}
}
+// P_PPU_RAM_Bank
+//
+// only lowest bit is used
+
void gcm394_base_video_device::ppu_ram_bank_w(u16 data)
{
LOGMASKED(LOG_GCM394_VIDEO, "%s:gcm394_base_video_device::ppu_ram_bank_w %04x\n", machine().describe_context(), data);
m_707e_spritebank = data;
}
+// P_FB_PPU_GO
+//
+// 15 FBI_UPD (Read Only, indicates FBI_ADDR is updated to current pointer)
+// 14 FBO_F (Read Only, used in interlace mode)
+// 13
+// 12
+//
+// 11
+// 10
+// 9
+// 8
+//
+// 7
+// 6
+// 5
+// 4
+//
+// 3
+// 2
+// 1
+// 0 PPU_GO (Render to framebuffer in frame base mode)
+
u16 gcm394_base_video_device::video_707c_r()
{
LOGMASKED(LOG_GCM394_VIDEO, "%s:gcm394_base_video_device::video_707c_r\n", machine().describe_context());
return 0x8000;
}
+// Format for GPL1625x / GPAC800
+//
+// S000 MMDF EfIV BDCP
+//
+// S# = SAVE_ROM (0 = normal mode, 1 = ROM saving mode, uses even line data for odd lines)
+// MM = FB_MONO (0 = RGB, 1 = Mono, 2 = 2bpp, 3 = 4bpp)
+// D* = SPR25D (0 = disable virtual 3D sprites, 1 = enable)
+// F = FB_FORMAT (0 = RGB565, 1 = RGBG)
+// E = FB_EN (0 = Half-line base mode, 1 = Frame base mode)
+// f = FREE (0 = 22 bit addressing, 1 = 27 bit addressing)
+// I* = VGA_NOINTL (0 = VGA interlace mode 640x480, 1 = VGA-non interlace mode, 640x240)
+// V* = VGA_EN (0 = QVGA / 320x240, 1 = VGA / 640x480)
+// B = TX_BOTUP (0 = top to bottom layers, 1 = bottom to top layers)
+// D = TX_DIRECT (0 = relative addressing, 1 = direct addressing)
+// C = TCHAR (0 = disable transparent tile, 1 = enable transparent tile - only works in relative address mode)
+// P = PPU_EN
+//
+// # not on GPL16250 (GPAC500 only?)
+// * not on GPL1622x / GPL1623x / GPAC500
+//
+
u16 gcm394_base_video_device::ppu_enable_r()
{
u16 retdata = m_renderer->get_video_reg_7f();
@@ -838,32 +885,33 @@ void gcm394_base_video_device::ppu_enable_w(u16 data)
{
LOGMASKED(LOG_GCM394_VIDEO, "%s:gcm394_base_video_device::ppu_enable_w %04x\n", machine().describe_context(), data);
- // Format for GPL1625x / GPAC800
- //
- // S000 MMDF EfIV BDCP
- //
- // S# = SAVE_ROM (0 = normal mode, 1 = ROM saving mode, uses even line data for odd lines)
- // MM = FB_MONO (0 = RGB, 1 = Mono, 2 = 2bpp, 3 = 4bpp)
- // D* = SPR25D (0 = disable virtual 3D sprites, 1 = enable)
- // F = FB_FORMAT (0 = RGB565, 1 = RGBG)
- // E = FB_EN (0 = Half-line base mode, 1 = Frame base mode)
- // f = FREE (0 = 22 bit addressing, 1 = 27 bit addressing)
- // I* = VGA_NOINTL (0 = VGA interlace mode 640x480, 1 = VGA-non interlace mode, 640x240)
- // V* = VGA_EN (0 = QVGA / 320x240, 1 = VGA / 640x480)
- // B = TX_BOTUP (0 = top to bottom layers, 1 = bottom to top layers)
- // D = TX_DIRECT (0 = relative addressing, 1 = direct addressing)
- // C = TCHAR (0 = disable transparent tile, 1 = enable transparent tile - only works in relative address mode)
- // P = PPU_EN
- //
- // # not on GPL16250 (GPAC500 only?)
- // * not on GPL1622x / GPL1623x / GPAC500
- //
-
m_707f = data;
m_renderer->set_video_reg_7f(data);
//popmessage("707f is %04x\n", data);
}
+// P_Palette_Control
+//
+// 15
+// 14
+// 13
+// 12
+//
+// 11
+// 10
+// 9
+// 8
+//
+// 7
+// 6
+// 5
+// 4
+//
+// 3 PAL_RAM_SEL[1] - ram banking for palette reads/writes
+// 2 PAL_RAM_SEL[0]
+// 1 PAL_TYPE[1] - enables 25-bit palette mode (otherwise 16-bit mode)
+// 0 PAL_TYPE[0] - selects which palettes to use
+
u16 gcm394_base_video_device::video_703a_palettebank_r()
{
LOGMASKED(LOG_GCM394_VIDEO, "%s:gcm394_base_video_device::video_703a_palettebank_r\n", machine().describe_context());
@@ -872,19 +920,33 @@ u16 gcm394_base_video_device::video_703a_palettebank_r()
void gcm394_base_video_device::video_703a_palettebank_w(u16 data)
{
- // I don't think bit 0 (0x01) is a bank select, it might be a 'mode select' for how the palette operates.
- // neither lazertag or tkmag220 set it
- // lazertag uses 2 banks (0 and 8)
- // tkmag220 only uses 1 bank (0)
-
- // ---- bb-s
- // bb = write bank?
- // s = sprite palette bank select?
LOGMASKED(LOG_GCM394_VIDEO, "%s:gcm394_base_video_device::video_703a_palettebank_w %04x\n", machine().describe_context(), data);
m_703a_palettebank = data;
}
+// P_PPU_IRQ_EN - IRQ enable/disable registers
+//
+// 15
+// 14
+// 13
+// 12
+//
+// 11 IRQ_EN11 R/W TV/TFT Frame End IRQ
+// 10 IRQ_EN10 R/W Frame buffer FIFO under-run IRQ
+// 9 IRQ_EN9 R/W Motion detection FIFO under-run IRQ
+// 8 IRQ_EN8 R/W Sensor position hit IRQ
+//
+// 7 IRQ_EN7 R/w Motion detection frame end IRQ
+// 6 IRQ_EN6 R/W Sensor frame end IRQ
+// 5 IRQ_EN5 R/W Sprite engine under-run IRQ
+// 4 IRQ_EN4 R/W Text engine under-run RIQ
+//
+// 3 IRQ_EN3 R/W Palette write error IRQ
+// 2 IRQ_EN2 R/W Sprite DMA transfer complete IRQ
+// 1 IRQ_EN1 R/W Video position IRQ
+// 0 IRQ_EN0 R/W Vertical blaking IRQ
+
u16 gcm394_base_video_device::videoirq_source_enable_r()
{
LOGMASKED(LOG_GCM394_VIDEO, "%s:gcm394_base_video_device::videoirq_source_enable_r\n", machine().describe_context());
@@ -901,13 +963,34 @@ void gcm394_base_video_device::videoirq_source_enable_w(u16 data)
check_video_irq();
}
+// P_PPU_IRQ_STS
+//
+// 15
+// 14
+// 13
+// 12
+//
+// 11 IRQ_STS11 TV/TFT Frame End IRQ
+// 10 IRQ_STS10 Frame buffer FIFO under-run IRQ
+// 9 IRQ_STS9 Motion detection FIFO under-run IRQ
+// 8 IRQ_STS8 Sensor position hit IRQ
+//
+// 7 IRQ_STS7 Motion detection frame end IRQ
+// 6 IRQ_STS6 Sensor frame end IRQ
+// 5 IRQ_STS5 Sprite engine under-run IRQ
+// 4 IRQ_STS4 Text engine under-run IRQ
+//
+// 3 IRQ_STS3 Palette write error IRQ
+// 2 IRQ_STS2 Sprite DMA transfer complete IRQ
+// 1 IRQ_STS1 Video position IRQ
+// 0 IRQ_STS0 Vertical blaking IRQ
+
u16 gcm394_base_video_device::video_7063_videoirq_source_r()
{
LOGMASKED(LOG_GCM394_VIDEO, "%s:gcm394_base_video_device::video_7063_videoirq_source_r\n", machine().describe_context());
return m_video_irq_status;
}
-
void gcm394_base_video_device::video_7063_videoirq_source_ack_w(u16 data)
{
LOGMASKED(LOG_GCM394_VIDEO, "video_7063_videoirq_source_ack_w: Video IRQ Acknowledge = %04x\n", data);
@@ -918,6 +1001,28 @@ void gcm394_base_video_device::video_7063_videoirq_source_ack_w(u16 data)
check_video_irq();
}
+// P_Blending
+//
+// 15
+// 14
+// 13
+// 12
+//
+// 11
+// 10
+// 9
+// 8
+//
+// 7
+// 6
+// 5
+// 4
+//
+// 3
+// 2
+// 1 BLDLVL[1]
+// 0 BLDLVL[0]
+
void gcm394_base_video_device::blending_w(u16 data)
{
LOGMASKED(LOG_GCM394_VIDEO, "%s:gcm394_base_video_device::blending_w %04x\n", machine().describe_context(), data);
@@ -980,6 +1085,28 @@ void gcm394_base_video_device::split_irq_xpos_w(u16 data)
update_raster_split_position();
}
+// P_TV_Control
+//
+// 15 TV_TEST
+// 14
+// 13
+// 12 HD_SEL (0 = CSYNC, 1 = HD)
+//
+// 11 VDSEL
+// 10 EVEN (0 = odd field, 1 = even field)
+// 9 SYNC
+// 8 VINFMT[1] - video input data format, 0 = RGB888, others = reserved
+//
+// 7 VINFMT[0]
+// 6 RESOLUTION[1] - 0 = 320x240, 1 = 640x240, 2 = reserved, 3 = internal colour bar
+// 5 RESOLUTION[0]
+// 4 NONINTL - 0 = interlaced, 1 = non-interlaced
+//
+// 3 TVSTD[2] - TV Standard Select
+// 2 TVSTD[1]
+// 1 TVSTD[0]
+// 0 TVEN - TV Module Enabled
+
u16 gcm394_base_video_device::video_703c_tvcontrol1_r()
{
LOGMASKED(LOG_GCM394_VIDEO, "%s:gcm394_base_video_device::video_703c_tvcontrol1_r\n", machine().describe_context());
@@ -993,6 +1120,8 @@ void gcm394_base_video_device::video_703c_tvcontrol1_w(u16 data)
m_renderer->set_video_reg_3c(data);
}
+// uncertain, apparently P_STN_COM_Clip or P_TFT_V_Width
+
u16 gcm394_base_video_device::video_7051_r()
{
/* related to what ends up crashing wrlshunt? */
@@ -1132,8 +1261,9 @@ void gcm394_base_video_device::vblank(int state)
if (m_video_irq_enable & 1)
{
// jak_prft expects 0x800 to be set in the status register or most of the main vblank code is skipped, why?
+ // 0x800 is TV/TFT Frame End IRQ
- m_video_irq_status |= 1 | 0x800;
+ m_video_irq_status |= (0x001 | 0x800);
LOGMASKED(LOG_GCM394_VIDEO, "Setting video IRQ status to %04x\n", m_video_irq_status);
check_video_irq();
}
diff --git a/src/devices/machine/generalplus_gpl951xx_soc.cpp b/src/devices/machine/generalplus_gpl951xx_soc.cpp
index cbc99c45725..ef4dd8277b6 100644
--- a/src/devices/machine/generalplus_gpl951xx_soc.cpp
+++ b/src/devices/machine/generalplus_gpl951xx_soc.cpp
@@ -385,7 +385,6 @@ void generalplus_gpl951xx_device::device_start()
save_item(NAME(m_int_priority_2));
save_item(NAME(m_int_priority_3));
save_item(NAME(m_misc_int_ctrl));
- save_item(NAME(m_cha_ctrl));
save_item(NAME(m_pllchange));
}
@@ -418,7 +417,6 @@ void generalplus_gpl951xx_device::device_reset()
m_int_priority_2 = 0;
m_int_priority_3 = 0;
m_misc_int_ctrl = 0;
- m_cha_ctrl = 0;
m_pllchange = 0;
for (int i = 0; i < 6; i++)
@@ -433,6 +431,30 @@ void generalplus_gpl951xx_device::device_reset()
// Timers
+void generalplus_gpl951xx_device::dac_0_w(uint16_t data)
+{
+ m_dac0->write(data);
+}
+
+TIMER_DEVICE_CALLBACK_MEMBER( generalplus_gpl951xx_device::timer_g_cb )
+{
+ m_timerg_ctrl |= 0x8000;
+ update_interrupts(1);
+ m_gpl_chx->process_cha_fifo(); // is cha hardwired to timerg overflow?
+}
+
+void generalplus_gpl951xx_device::dac_1_w(uint16_t data)
+{
+ m_dac1->write(data);
+}
+
+TIMER_DEVICE_CALLBACK_MEMBER( generalplus_gpl951xx_device::timer_h_cb )
+{
+ m_timerh_ctrl |= 0x8000;
+ update_interrupts(1);
+ m_gpl_chx->process_chb_fifo(); // is chb hardwired to timerh overflow?
+}
+
u16 generalplus_gpl951xx_device::timerg_preload_r()
{
logerror("%s: timerg_preload_r\n", machine().describe_context());
@@ -481,7 +503,7 @@ void generalplus_gpl951xx_device::timerg_ctrl_w(u16 data)
u8 srcbsel = (data & 0x0070) >> 4;
u8 srcasel = (data & 0x000f) >> 0;
- logerror("%s: timerg_ctrl_w %04x (tmgif_clear %01x) (interrupt enabled %01x) (timer enabled %01x) (ext0sel %01x) (ext1sel %01x) (srcbsel %01x) (srcasel %01x)\n", machine().describe_context(), data, tmgif_clear, tmgie, tmgen, ext0sel, ext1sel, srcbsel, srcasel);
+ logerror("%s: timerg_ctrl_w %04x (tmgif_clear %01x) (interrupt enabled %01x) (timer enabled %01x) (ext0sel %01x) (ext1sel %01x) (srcbsel %s) (srcasel %s)\n", machine().describe_context(), data, tmgif_clear, tmgie, tmgen, ext0sel, ext1sel, m_srcb[srcbsel], m_srca[srcasel]);
if (data & 0x8000)
{
@@ -492,7 +514,7 @@ void generalplus_gpl951xx_device::timerg_ctrl_w(u16 data)
{
if (data & 0x2000)
{
- m_timer_g->adjust(attotime::zero, 0, attotime::from_hz(2000));
+ m_timer_g->adjust(attotime::zero, 0, attotime::from_hz(8000));
}
else
{
@@ -555,7 +577,7 @@ void generalplus_gpl951xx_device::timerh_ctrl_w(u16 data)
u8 srcbsel = (data & 0x0070) >> 4;
u8 srcasel = (data & 0x000f) >> 0;
- logerror("%s: timerh_ctrl_w %04x (tmhif_clear %01x) (interrupt enabled %01x) (timer enabled %01x) (ext0sel %01x) (ext1sel %01x) (srcbsel %01x) (srcasel %01x)\n", machine().describe_context(), data, tmhif_clear, tmhie, tmhen, ext0sel, ext1sel, srcbsel, srcasel);
+ logerror("%s: timerh_ctrl_w %04x (tmhif_clear %01x) (interrupt enabled %01x) (timer enabled %01x) (ext0sel %01x) (ext1sel %01x) (srcbsel %01x) (srcasel %01x)\n", machine().describe_context(), data, tmhif_clear, tmhie, tmhen, ext0sel, ext1sel, m_srcb[srcbsel], m_srca[srcasel]);
if (data & 0x8000)
{
@@ -569,7 +591,7 @@ void generalplus_gpl951xx_device::timerh_ctrl_w(u16 data)
if (data & 0x2000)
{
logerror("started timerh\n");
- m_timer_h->adjust(attotime::zero, 0, attotime::from_hz(2000));
+ m_timer_h->adjust(attotime::zero, 0, attotime::from_hz(1000));
}
else
{
@@ -698,26 +720,6 @@ void generalplus_gpl951xx_device::spi_bank_w(u16 data)
m_spi_bank = data;
}
-u16 generalplus_gpl951xx_device::int_status3_r()
-{
- u16 ret = 0;
- LOGMASKED(LOG_OTHER, "%s: generalplus_gpl951xx_device::int_status3_r\n", machine().describe_context());
-
- if (m_timerh_ctrl & 0x8000)
- ret |= 0x8000;
-
- if (m_timerg_ctrl & 0x8000)
- ret |= 0x4000;
-
- return ret;
-}
-
-void generalplus_gpl951xx_device::int_status3_w(u16 data)
-{
- LOGMASKED(LOG_OTHER, "%s: generalplus_gpl951xx_device::int_status3_w %04x\n", machine().describe_context(), data);
- // bit 2 (SPU Beat Interrupt) is listed as R/W for GPL95, but not GPL162? (verify)
-}
-
TIMER_DEVICE_CALLBACK_MEMBER(generalplus_gpl951xx_device::timer_a_cb)
{
}
@@ -746,192 +748,244 @@ TIMER_DEVICE_CALLBACK_MEMBER(generalplus_gpl951xx_device::timer_f_cb)
template<int Port>
u16 generalplus_gpl951xx_device::io_data_r()
{
- LOGMASKED(LOG_OTHER, "%s:generalplus_gpl951xx_device::io_%c_data_r\n", machine().describe_context(), 'a' + Port);
+ LOGMASKED(LOG_OTHER, "%s: generalplus_gpl951xx_device::io_%c_data_r\n", machine().describe_context(), 'a' + Port);
return m_port_in[Port]();
}
template<int Port>
void generalplus_gpl951xx_device::io_data_w(u16 data)
{
- LOGMASKED(LOG_OTHER, "%s:generalplus_gpl951xx_device::io_%c_data_w %04x\n", machine().describe_context(), 'a' + Port, data);
+ LOGMASKED(LOG_OTHER, "%s: generalplus_gpl951xx_device::io_%c_data_w %04x\n", machine().describe_context(), 'a' + Port, data);
m_port_out[Port](data);
}
template<int Port>
u16 generalplus_gpl951xx_device::io_buffer_r()
{
- LOGMASKED(LOG_OTHER, "%s:generalplus_gpl951xx_device::io_%c_buffer_r\n", machine().describe_context(), 'a' + Port);
+ LOGMASKED(LOG_OTHER, "%s: generalplus_gpl951xx_device::io_%c_buffer_r\n", machine().describe_context(), 'a' + Port);
return m_port_in[Port]();
}
template<int Port>
void generalplus_gpl951xx_device::io_buffer_w(u16 data)
{
- LOGMASKED(LOG_OTHER, "%s:generalplus_gpl951xx_device::io_%c_buffer_w %04x\n", machine().describe_context(), 'a' + Port, data);
+ LOGMASKED(LOG_OTHER, "%s: generalplus_gpl951xx_device::io_%c_buffer_w %04x\n", machine().describe_context(), 'a' + Port, data);
m_port_out[Port](data);
}
template<int Port>
u16 generalplus_gpl951xx_device::io_dir_r()
{
- LOGMASKED(LOG_OTHER, "%s:generalplus_gpl951xx_device::io_%c_dir_r\n", machine().describe_context(), 'a' + Port);
+ LOGMASKED(LOG_OTHER, "%s: generalplus_gpl951xx_device::io_%c_dir_r\n", machine().describe_context(), 'a' + Port);
return m_io_dir[Port];
}
template<int Port>
void generalplus_gpl951xx_device::io_dir_w(u16 data)
{
- LOGMASKED(LOG_OTHER, "%s:generalplus_gpl951xx_device::io_%c_dir_w %04x\n", machine().describe_context(), 'a' + Port, data);
+ LOGMASKED(LOG_OTHER, "%s: generalplus_gpl951xx_device::io_%c_dir_w %04x\n", machine().describe_context(), 'a' + Port, data);
m_io_dir[Port] = data;
}
template<int Port>
u16 generalplus_gpl951xx_device::io_attrib_r()
{
- LOGMASKED(LOG_OTHER, "%s:generalplus_gpl951xx_device::io_%c_attrib_r\n", machine().describe_context(), 'a' + Port);
+ LOGMASKED(LOG_OTHER, "%s: generalplus_gpl951xx_device::io_%c_attrib_r\n", machine().describe_context(), 'a' + Port);
return m_io_attrib[Port];
}
template<int Port>
void generalplus_gpl951xx_device::io_attrib_w(u16 data)
{
- LOGMASKED(LOG_OTHER, "%s:generalplus_gpl951xx_device::io_%c_attrib_w %04x\n", machine().describe_context(), 'a' + Port, data);
+ LOGMASKED(LOG_OTHER, "%s: generalplus_gpl951xx_device::io_%c_attrib_w %04x\n", machine().describe_context(), 'a' + Port, data);
m_io_attrib[Port] = data;
}
template<int Port>
u16 generalplus_gpl951xx_device::io_drv_r()
{
- LOGMASKED(LOG_OTHER, "%s:generalplus_gpl951xx_device::io_%c_drv_r\n", machine().describe_context(), 'a' + Port);
+ LOGMASKED(LOG_OTHER, "%s: generalplus_gpl951xx_device::io_%c_drv_r\n", machine().describe_context(), 'a' + Port);
return 0xffff;
}
template<int Port>
void generalplus_gpl951xx_device::io_drv_w(u16 data)
{
- LOGMASKED(LOG_OTHER, "%s:generalplus_gpl951xx_device::io_%c_drv_w %04x\n", machine().describe_context(), 'a' + Port, data);
+ LOGMASKED(LOG_OTHER, "%s: generalplus_gpl951xx_device::io_%c_drv_w %04x\n", machine().describe_context(), 'a' + Port, data);
}
template<int Port>
u16 generalplus_gpl951xx_device::io_mux_r()
{
- LOGMASKED(LOG_OTHER, "%s:generalplus_gpl951xx_device::io_%c_mux_r\n", machine().describe_context(), 'a' + Port);
+ LOGMASKED(LOG_OTHER, "%s: generalplus_gpl951xx_device::io_%c_mux_r\n", machine().describe_context(), 'a' + Port);
return 0xffff;
}
template<int Port>
void generalplus_gpl951xx_device::io_mux_w(u16 data)
{
- LOGMASKED(LOG_OTHER, "%s:generalplus_gpl951xx_device::io_%c_mux_w %04x\n", machine().describe_context(), 'a' + Port, data);
+ LOGMASKED(LOG_OTHER, "%s: generalplus_gpl951xx_device::io_%c_mux_w %04x\n", machine().describe_context(), 'a' + Port, data);
}
template<int Port>
u16 generalplus_gpl951xx_device::io_latch_r()
{
- LOGMASKED(LOG_OTHER, "%s:generalplus_gpl951xx_device::io_%c_latch_r\n", machine().describe_context(), 'a' + Port);
+ LOGMASKED(LOG_OTHER, "%s: generalplus_gpl951xx_device::io_%c_latch_r\n", machine().describe_context(), 'a' + Port);
return 0xffff;
}
template<int Port>
void generalplus_gpl951xx_device::io_latch_w(u16 data)
{
- LOGMASKED(LOG_OTHER, "%s:generalplus_gpl951xx_device::io_%c_latch_w %04x\n", machine().describe_context(), 'a' + Port, data);
+ LOGMASKED(LOG_OTHER, "%s: generalplus_gpl951xx_device::io_%c_latch_w %04x\n", machine().describe_context(), 'a' + Port, data);
}
template<int Port>
u16 generalplus_gpl951xx_device::io_keyen_r()
{
- LOGMASKED(LOG_OTHER, "%s:generalplus_gpl951xx_device::io_%c_keyen_r\n", machine().describe_context(), 'a' + Port);
+ LOGMASKED(LOG_OTHER, "%s: generalplus_gpl951xx_device::io_%c_keyen_r\n", machine().describe_context(), 'a' + Port);
return 0xffff;
}
template<int Port>
void generalplus_gpl951xx_device::io_keyen_w(u16 data)
{
- LOGMASKED(LOG_OTHER, "%s:generalplus_gpl951xx_device::io_%c_keyen_w %04x\n", machine().describe_context(), 'a' + Port, data);
+ LOGMASKED(LOG_OTHER, "%s: generalplus_gpl951xx_device::io_%c_keyen_w %04x\n", machine().describe_context(), 'a' + Port, data);
}
// Misc
u16 generalplus_gpl951xx_device::sys_ctrl_r()
{
- LOGMASKED(LOG_OTHER, "%s:generalplus_gpl951xx_device::sys_ctrl_r\n", machine().describe_context());
+ LOGMASKED(LOG_OTHER, "%s: generalplus_gpl951xx_device::sys_ctrl_r\n", machine().describe_context());
return m_sys_ctrl;
}
void generalplus_gpl951xx_device::sys_ctrl_w(u16 data)
{
- LOGMASKED(LOG_OTHER, "%s:generalplus_gpl951xx_device::sys_ctrl_w %04x\n", machine().describe_context(), data);
+ LOGMASKED(LOG_OTHER, "%s: generalplus_gpl951xx_device::sys_ctrl_w %04x\n", machine().describe_context(), data);
m_sys_ctrl = data;
}
void generalplus_gpl951xx_device::clock_ctrl_w(u16 data)
{
- LOGMASKED(LOG_OTHER, "%s:generalplus_gpl951xx_device::clock_ctrl_w %04x\n", machine().describe_context(), data);
+ LOGMASKED(LOG_OTHER, "%s: generalplus_gpl951xx_device::clock_ctrl_w %04x\n", machine().describe_context(), data);
m_clock_ctrl = data;
}
u16 generalplus_gpl951xx_device::clk_ctrl0_r()
{
- LOGMASKED(LOG_OTHER, "%s:generalplus_gpl951xx_device::clk_ctrl0_r\n", machine().describe_context());
+ LOGMASKED(LOG_OTHER, "%s: generalplus_gpl951xx_device::clk_ctrl0_r\n", machine().describe_context());
return 0x0000;
}
void generalplus_gpl951xx_device::clk_ctrl0_w(u16 data)
{
- LOGMASKED(LOG_OTHER, "%s:generalplus_gpl951xx_device::clk_ctrl0 %04x\n", machine().describe_context(), data);
+ LOGMASKED(LOG_OTHER, "%s: generalplus_gpl951xx_device::clk_ctrl0 %04x\n", machine().describe_context(), data);
}
void generalplus_gpl951xx_device::watchdog_ctrl_w(u16 data)
{
- LOGMASKED(LOG_OTHER, "%s:generalplus_gpl951xx_device::watchdog_ctrl_w %04x\n", machine().describe_context(), data);
+ LOGMASKED(LOG_OTHER, "%s: generalplus_gpl951xx_device::watchdog_ctrl_w %04x\n", machine().describe_context(), data);
}
u16 generalplus_gpl951xx_device::power_state_r()
{
- LOGMASKED(LOG_OTHER, "%s:generalplus_gpl951xx_device::power_state_r\n", machine().describe_context());
+ LOGMASKED(LOG_OTHER, "%s: generalplus_gpl951xx_device::power_state_r\n", machine().describe_context());
return 0x0002;
}
u16 generalplus_gpl951xx_device::pllclkwait_r()
{
- LOGMASKED(LOG_OTHER, "%s:generalplus_gpl951xx_device::pllclkwait_r\n", machine().describe_context());
+ LOGMASKED(LOG_OTHER, "%s: generalplus_gpl951xx_device::pllclkwait_r\n", machine().describe_context());
return 0x0000;
}
void generalplus_gpl951xx_device::pllclkwait_w(u16 data)
{
- LOGMASKED(LOG_OTHER, "%s:generalplus_gpl951xx_device::pllclkwait_w %04x\n", machine().describe_context(), data);
+ LOGMASKED(LOG_OTHER, "%s: generalplus_gpl951xx_device::pllclkwait_w %04x\n", machine().describe_context(), data);
}
// sets bit 0x0002 then expects it to have cleared
u16 generalplus_gpl951xx_device::cache_ctrl_r()
{
- LOGMASKED(LOG_OTHER, "%s:generalplus_gpl951xx_device::cache_ctrl_r\n", machine().describe_context());
+ LOGMASKED(LOG_OTHER, "%s: generalplus_gpl951xx_device::cache_ctrl_r\n", machine().describe_context());
return m_cache_ctrl & ~ 0x0002;
}
void generalplus_gpl951xx_device::cache_ctrl_w(u16 data)
{
- LOGMASKED(LOG_OTHER, "%s:generalplus_gpl951xx_device::cache_ctrl_w %04x\n", machine().describe_context(), data);
+ LOGMASKED(LOG_OTHER, "%s: generalplus_gpl951xx_device::cache_ctrl_w %04x\n", machine().describe_context(), data);
m_cache_ctrl = data;
}
+// P_INT_Status1
+//
+// 15 KEYIF - Key-change interrupt status (R/W)
+// 14 ADCRIF - Line ADC Converstion Ready interrupt status
+// 13 PwrONIF - Power on key change event status
+// 12 OTIF - Over temperature event status
+//
+// 11 UARTIF - UART Interrupt status
+// 10 SPI0 - Serial Peripheral Interface 0 interrupt status
+// 9 FPIF - FP Interrupt Status (LCD)
+// 8
+//
+// 7 ASIF - Line ADC Auto Sample Mode FIFO full interrupt status
+// 6
+// 5 AUDBIF - Audio Channel B (CHB) FIFO Empty Interrupt status
+// 4 AUDAIF - Audio Channel A (CHA) FIFO Empty Interrupt status
+//
+// 3 USB - USB interrupt status
+// 2 DMA - System DMA interrupt status
+// 1 EXT1IF - External interrupt 1 status (R/W)
+// 0 EXT0IF - External interrupt 0 status (R/W)
+
u16 generalplus_gpl951xx_device::int_status1_r()
{
- LOGMASKED(LOG_OTHER, "%s:generalplus_gpl951xx_device::int_status1_r\n", machine().describe_context());
- return 0x0000;
+ u16 ret = 0x0000;
+ LOGMASKED(LOG_OTHER, "%s: generalplus_gpl951xx_device::int_status1_r\n", machine().describe_context());
+
+ if (m_gpl_chx->is_cha_fifo_empty_irq())
+ ret |= 0x0010;
+
+ if (m_gpl_chx->is_chb_fifo_empty_irq())
+ ret |= 0x0020;
+
+ return ret;
}
void generalplus_gpl951xx_device::int_status1_w(u16 data)
{
- LOGMASKED(LOG_OTHER, "%s:generalplus_gpl951xx_device::int_status1_w %04x\n", machine().describe_context(), data);
+ LOGMASKED(LOG_OTHER, "%s: generalplus_gpl951xx_device::int_status1_w %04x\n", machine().describe_context(), data);
//m_int_status1 = data;
}
+// P_INT_Status2
+//
+// 15
+// 14
+// 13
+// 12
+//
+// 11 KSIF - Key-Scan Interrupt status
+// 10 TMBCIF - TimebaseC interrupt status
+// 9 TMBBIF - TimebaseB interrupt status
+// 8 TMBAIF - TimebaseA interrupt status
+//
+// 7 CTSIF - CTS Controller interrupt status
+// 6
+// 5 I2C - I2C Controller interrupt status
+// 4 NAND - NAND Flash Controller interrupt status
+//
+// 3
+// 2 SPI1 - Serial Peripheral Interface 1 interrupt status
+// 1 RTC - RTC Controller interrupt status
+// 0 ADCFF - MIC ADC Auto Sample Mode FIFO Full interrupt status
+
u16 generalplus_gpl951xx_device::int_status2_r()
{
- LOGMASKED(LOG_OTHER, "%s:generalplus_gpl951xx_device::int_status2_r\n", machine().describe_context());
+ LOGMASKED(LOG_OTHER, "%s: generalplus_gpl951xx_device::int_status2_r\n", machine().describe_context());
u16 ret = 0;
if (m_gpl_timebase->timebasea_irq_flag())
@@ -948,48 +1002,76 @@ u16 generalplus_gpl951xx_device::int_status2_r()
void generalplus_gpl951xx_device::int_status2_w(u16 data)
{
- LOGMASKED(LOG_OTHER, "%s:generalplus_gpl951xx_device::int_status2_w %04x\n", machine().describe_context(), data);
+ LOGMASKED(LOG_OTHER, "%s: generalplus_gpl951xx_device::int_status2_w %04x\n", machine().describe_context(), data);
// none of this bits are listed as writeable for GPL95xx or GPL162xx
}
+// P_INT_Status3
+//
+// 15 TMHIF - TimerH Interrupt status
+// 14 TMGIF - TimerG Interrupt status
+// 13 TMFIF - TimerF Interrupt status
+// 12 TMEIF - TimerE Interrupt status
+//
+// 11 TMDIF - TimerD Interrupt status
+// 10 TMCIF - TimerC Interrupt status
+// 9 TMBIF - TimerB Interrupt status
+// 8 TMAIF - TimerA Interrupt status
+//
+// 7 UNEXP - unexpected access Interrupt status
+// 6
+// 5
+// 4
+//
+// 3
+// 2 BEAT - SPU beat interrupt status (R/W)
+// 1
+// 0
+
+u16 generalplus_gpl951xx_device::int_status3_r()
+{
+ u16 ret = 0;
+ LOGMASKED(LOG_OTHER, "%s: generalplus_gpl951xx_device::int_status3_r\n", machine().describe_context());
+
+ if (m_timerh_ctrl & 0x8000)
+ ret |= 0x8000;
+
+ if (m_timerg_ctrl & 0x8000)
+ ret |= 0x4000;
+
+ return ret;
+}
+
+void generalplus_gpl951xx_device::int_status3_w(u16 data)
+{
+ LOGMASKED(LOG_OTHER, "%s: generalplus_gpl951xx_device::int_status3_w %04x\n", machine().describe_context(), data);
+ // bit 2 (SPU Beat Interrupt) is listed as R/W for GPL95, but not GPL162? (verify)
+}
+
void generalplus_gpl951xx_device::int_priority_1_w(u16 data)
{
- LOGMASKED(LOG_OTHER, "%s:generalplus_gpl951xx_device::int_priority_1_w %04x\n", machine().describe_context(), data);
+ LOGMASKED(LOG_OTHER, "%s: generalplus_gpl951xx_device::int_priority_1_w %04x\n", machine().describe_context(), data);
m_int_priority_1 = data;
}
void generalplus_gpl951xx_device::int_priority_2_w(u16 data)
{
- LOGMASKED(LOG_OTHER, "%s:generalplus_gpl951xx_device::int_priority_2_w %04x\n", machine().describe_context(), data);
+ LOGMASKED(LOG_OTHER, "%s: generalplus_gpl951xx_device::int_priority_2_w %04x\n", machine().describe_context(), data);
m_int_priority_2 = data;
}
void generalplus_gpl951xx_device::int_priority_3_w(u16 data)
{
- LOGMASKED(LOG_OTHER, "%s:generalplus_gpl951xx_device::int_priority_3_w %04x\n", machine().describe_context(), data);
+ LOGMASKED(LOG_OTHER, "%s: generalplus_gpl951xx_device::int_priority_3_w %04x\n", machine().describe_context(), data);
m_int_priority_3 = data;
}
void generalplus_gpl951xx_device::mint_ctrl_w(u16 data)
{
- LOGMASKED(LOG_OTHER, "%s:generalplus_gpl951xx_device::mint_ctrl_w %04x\n", machine().describe_context(), data);
+ LOGMASKED(LOG_OTHER, "%s: generalplus_gpl951xx_device::mint_ctrl_w %04x\n", machine().describe_context(), data);
m_misc_int_ctrl = data;
}
-// CHA (for sound output)
-
-u16 generalplus_gpl951xx_device::cha_ctrl_r()
-{
- LOGMASKED(LOG_OTHER, "%s:generalplus_gpl951xx_device::cha_ctrl_r\n", machine().describe_context());
- return 0xffff;
-}
-
-void generalplus_gpl951xx_device::cha_ctrl_w(u16 data)
-{
- LOGMASKED(LOG_OTHER, "%s:generalplus_gpl951xx_device::cha_ctrl_w %04x\n", machine().describe_context(), data);
- m_cha_ctrl = data;
-}
-
u16 generalplus_gpl951xx_device::spi_direct_r(offs_t offset)
{
@@ -1261,17 +1343,17 @@ void generalplus_gpl951xx_device::gpspi_direct_internal_map(address_map &map)
// 78ee
// 78ef
- map(0x0078f0, 0x0078f0).rw(FUNC(generalplus_gpl951xx_device::cha_ctrl_r), FUNC(generalplus_gpl951xx_device::cha_ctrl_w)); // 78f0 - CHA_Ctrl
- // 78f1 - CHA_Data
- // 78f2 - CHA_FIFO
+ map(0x0078f0, 0x0078f0).rw(m_gpl_chx, FUNC(gpl_chx_device::cha_ctrl_r), FUNC(gpl_chx_device::cha_ctrl_w)); // 78f0 - CHA_Ctrl
+ map(0x0078f1, 0x0078f1).rw(m_gpl_chx, FUNC(gpl_chx_device::cha_data_r), FUNC(gpl_chx_device::cha_data_w)); // 78f1 - CHA_Data
+ map(0x0078f2, 0x0078f2).rw(m_gpl_chx, FUNC(gpl_chx_device::cha_fifo_r), FUNC(gpl_chx_device::cha_fifo_w)); // 78f2 - CHA_FIFO
// 78f3
// 78f4
// 78f5
// 78f6
// 78f7
- // 78f8 - CHB_Ctrl
- // 78f9 - CHB_Data
- // 78fa - CHB_FIFO
+ map(0x0078f8, 0x0078f8).rw(m_gpl_chx, FUNC(gpl_chx_device::chb_ctrl_r), FUNC(gpl_chx_device::chb_ctrl_w)); // 78f8 - CHB_Ctrl
+ map(0x0078f9, 0x0078f9).rw(m_gpl_chx, FUNC(gpl_chx_device::chb_data_r), FUNC(gpl_chx_device::chb_data_w)); // 78f9 - CHB_Data
+ map(0x0078fa, 0x0078fa).rw(m_gpl_chx, FUNC(gpl_chx_device::chb_fifo_r), FUNC(gpl_chx_device::chb_fifo_w)); // 78fa - CHB_FIFO
// 78fb
// 78fc
// 78fd
@@ -1510,18 +1592,16 @@ void generalplus_gpl951xx_device::update_interrupts(int state)
{
set_state_unsynced(UNSP_IRQ4_LINE, CLEAR_LINE);
}
-}
-TIMER_DEVICE_CALLBACK_MEMBER( generalplus_gpl951xx_device::timer_g_cb )
-{
- m_timerg_ctrl |= 0x8000;
- update_interrupts(1);
-}
+ if ((m_gpl_chx->is_cha_fifo_empty_irq()) || (m_gpl_chx->is_chb_fifo_empty_irq()))
+ {
+ set_state_unsynced(UNSP_IRQ1_LINE, ASSERT_LINE);
+ }
+ else
+ {
+ set_state_unsynced(UNSP_IRQ1_LINE, CLEAR_LINE);
+ }
-TIMER_DEVICE_CALLBACK_MEMBER( generalplus_gpl951xx_device::timer_h_cb )
-{
- m_timerh_ctrl |= 0x8000;
- update_interrupts(1);
}
u16 generalplus_gpl951xx_device::read_space(offs_t offset)
@@ -1563,10 +1643,18 @@ void generalplus_gpl951xx_device::device_add_mconfig(machine_config &config)
m_spg_audio->add_route(0, *this, 1.0, 0);
m_spg_audio->add_route(1, *this, 1.0, 1);
+ // technically I think this gets mixed down to the same 'DAC' as the regular audio output
+ DAC_16BIT_R2R_TWOS_COMPLEMENT(config, m_dac0, 0).add_route(0, *this, 1.0, 0);
+ DAC_16BIT_R2R_TWOS_COMPLEMENT(config, m_dac1, 0).add_route(0, *this, 1.0, 1);
+
GPL_DMA(config, m_gpl_dma, 0);
m_gpl_dma->space_read_callback().set(FUNC(generalplus_gpl951xx_device::read_space));
m_gpl_dma->space_write_callback().set(FUNC(generalplus_gpl951xx_device::write_space));
+ GPL_CHX(config, m_gpl_chx, 0);
+ m_gpl_chx->cha_write_callback().set(FUNC(generalplus_gpl951xx_device::dac_0_w));
+ m_gpl_chx->chb_write_callback().set(FUNC(generalplus_gpl951xx_device::dac_1_w));
+
GPL_TIMEBASE(config, m_gpl_timebase, 0);
m_gpl_timebase->updateirqs_callback().set(FUNC(generalplus_gpl951xx_device::update_interrupts));
@@ -1603,6 +1691,9 @@ generalplus_gpl951xx_device::generalplus_gpl951xx_device(const machine_config &m
m_timer_g(*this, "timer_g"),
m_timer_h(*this, "timer_h"),
m_rtc(*this, "rtc"),
+ m_gpl_chx(*this, "gpl_chx"),
+ m_dac0(*this, "dac0"),
+ m_dac1(*this, "dac1"),
m_gpl_dma(*this, "gpl_dma"),
m_gpl_timebase(*this, "gpl_timebase"),
m_screen(*this, finder_base::DUMMY_TAG),
diff --git a/src/devices/machine/generalplus_gpl951xx_soc.h b/src/devices/machine/generalplus_gpl951xx_soc.h
index 684bf23f199..dd71bf4d1c4 100644
--- a/src/devices/machine/generalplus_gpl951xx_soc.h
+++ b/src/devices/machine/generalplus_gpl951xx_soc.h
@@ -9,10 +9,12 @@
#include "cpu/unsp/unsp.h"
#include "machine/timer.h"
+#include "sound/dac.h"
#include "screen.h"
#include "emupal.h"
+#include "generalplus_gpl_chx.h"
#include "generalplus_gpl_dma.h"
#include "generalplus_gpl_timebase.h"
#include "generalplus_gpl162xx_soc_video.h"
@@ -123,6 +125,9 @@ private:
u16 timerh_preload_r();
void timerh_preload_w(u16 data);
+ void dac_0_w(uint16_t data);
+ void dac_1_w(uint16_t data);
+
template<int Port> u16 io_data_r();
template<int Port> void io_data_w(u16 data);
template<int Port> u16 io_buffer_r();
@@ -175,9 +180,6 @@ private:
void int_priority_3_w(u16 data);
void mint_ctrl_w(u16 data);
- u16 cha_ctrl_r();
- void cha_ctrl_w(u16 data);
-
void update_interrupts(int state);
void audioirq_w(int state);
@@ -198,6 +200,38 @@ private:
u16 m_byteswap;
+ const char* m_srcb[8] =
+ {
+ "2048Hz",
+ "1024Hz",
+ "256Hz",
+ "TimeBaseB",
+ "TimeBaseA",
+ "(logic low)",
+ "(logic high)",
+ "EXT1 with pre-scaler"
+ };
+
+ const char* m_srca[16] =
+ {
+ "SYSCLK/2",
+ "SYSCLK/256",
+ "32768Hz",
+ "8192Hz",
+ "4096Hz",
+ "(logic high)",
+ "Timer Overflow",
+ "EXT0 with pre-scaler",
+ "(logic low)",
+ "9: reserved",
+ "a: reserved",
+ "b: reserved",
+ "c: reserved",
+ "d: reserved",
+ "e: reserved",
+ "f: reserved"
+ };
+
u16 m_timerg_preload;
u16 m_timerg_ctrl;
u16 m_timerh_preload;
@@ -228,8 +262,6 @@ private:
u16 m_misc_int_ctrl;
- u16 m_cha_ctrl;
-
u16 m_pllchange;
u16 m_spi_bank;
@@ -254,6 +286,9 @@ private:
required_device<timer_device> m_timer_g;
required_device<timer_device> m_timer_h;
required_device<gpl951xx_rtc_device> m_rtc;
+ required_device<gpl_chx_device> m_gpl_chx;
+ required_device<dac_16bit_r2r_twos_complement_device> m_dac0;
+ required_device<dac_16bit_r2r_twos_complement_device> m_dac1;
required_device<gpl_dma_device> m_gpl_dma;
required_device<gpl_timebase_device> m_gpl_timebase;
required_device<screen_device> m_screen;
diff --git a/src/devices/machine/generalplus_gpl_chx.cpp b/src/devices/machine/generalplus_gpl_chx.cpp
new file mode 100644
index 00000000000..bed0f9c34c0
--- /dev/null
+++ b/src/devices/machine/generalplus_gpl_chx.cpp
@@ -0,0 +1,341 @@
+// license:BSD-3-Clause
+// copyright-holders:David Haywood
+
+#include "emu.h"
+#include "generalplus_gpl_chx.h"
+
+// System DMA memory mode can be configured to
+// 1 (CHA) or 7 (CHB) but the software we've seen doesn't appear to do that
+// so it's unclear how that relates to any of this
+
+#define LOG_CHX (1U << 1)
+
+#define VERBOSE (LOG_CHX)
+
+#include "logmacro.h"
+
+DEFINE_DEVICE_TYPE(GPL_CHX, gpl_chx_device, "gpl_chx", "Generalplus GPL162xx / GPL951xx CHA/CHB Sound")
+
+gpl_chx_device::gpl_chx_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
+ device_t(mconfig, GPL_CHX, tag, owner, clock),
+ m_cha_output_cb(*this),
+ m_chb_output_cb(*this),
+ m_updateirqs_cb(*this)
+{
+}
+
+void gpl_chx_device::device_start()
+{
+ save_item(NAME(m_cha_ctrl));
+ save_item(NAME(m_chb_ctrl));
+ save_item(NAME(m_cha_fifo_reg));
+ save_item(NAME(m_chb_fifo_reg));
+ save_item(NAME(m_cha_fifo));
+ save_item(NAME(m_chb_fifo));
+ save_item(NAME(m_cha_fifo_readpos));
+ save_item(NAME(m_cha_fifo_writepos));
+ save_item(NAME(m_cha_fifo_entries));
+ save_item(NAME(m_chb_fifo_readpos));
+ save_item(NAME(m_chb_fifo_writepos));
+ save_item(NAME(m_chb_fifo_entries));
+}
+
+void gpl_chx_device::device_reset()
+{
+ m_cha_ctrl = 0;
+ m_chb_ctrl = 0;
+
+ for (int i = 0; i < 16; i++)
+ {
+ m_cha_fifo[i] = 0;
+ m_chb_fifo[i] = 0;
+ }
+
+ m_cha_fifo_reg = 0;
+ m_chb_fifo_reg = 0;
+
+ m_cha_fifo_readpos = 0;
+ m_cha_fifo_writepos = 0;
+ m_cha_fifo_entries = 0;
+
+ m_chb_fifo_readpos = 0;
+ m_chb_fifo_writepos = 0;
+ m_chb_fifo_entries = 0;
+}
+
+
+// CHA (for sound output)
+
+// P_CHA_Ctrl
+//
+// 15 FEMI/C - FIFO Empty IRQ Flag - Write to clear
+// 14 FEMIEN - FIFO Empty Interrupt Enable
+// 13 CHAEN - CHA Enable
+// 12 DACBEN
+//
+// 11 SIGNEN - used signed data
+// 10 AMP_PE - Positive-side push-pull amp enable
+// 9 AMP_NE - Negative-side push-pull amp enable
+// 8
+//
+// 7 ONE_DAC - Mix CHA and CHB data to CHA
+// 6 GAIN[3]
+// 5 GAIN[2]
+// 4 GAIN[1]
+//
+// 3 GAIN[0]
+// 2 CASCADE1 - External signal1 (ACIN) mixing enable
+// 1 CASCADE0 - External signal0 (ACIN) mixing enable
+// 0
+
+u16 gpl_chx_device::cha_ctrl_r()
+{
+ LOGMASKED(LOG_CHX, "%s: gpl_chx_device::cha_ctrl_r\n", machine().describe_context());
+ return m_cha_ctrl;
+}
+
+void gpl_chx_device::cha_ctrl_w(u16 data)
+{
+ LOGMASKED(LOG_CHX, "%s: gpl_chx_device::cha_ctrl_w %04x\n", machine().describe_context(), data);
+
+ if (data & 0x8000)
+ {
+ // clear flag
+ data &= 0x7fff;
+ m_updateirqs_cb(1);
+ }
+
+ m_cha_ctrl = data;
+}
+
+// P_CHA_Data
+//
+// 15-0 CHADATA
+
+u16 gpl_chx_device::cha_data_r()
+{
+ LOGMASKED(LOG_CHX, "%s: gpl_chx_device::cha_data_r\n", machine().describe_context());
+ return 0xffff;
+}
+
+void gpl_chx_device::cha_data_w(u16 data)
+{
+ LOGMASKED(LOG_CHX, "%s: gpl_chx_device::cha_data_w %04x\n", machine().describe_context(), data);
+
+ if (m_cha_fifo_entries < 16)
+ {
+ m_cha_fifo[m_cha_fifo_writepos] = data;
+ m_cha_fifo_writepos++;
+ m_cha_fifo_writepos &= 0xf;
+
+ m_cha_fifo_entries++;
+ }
+ else
+ {
+ // trying to overflow the FIFO
+ }
+
+}
+
+// P_CHA_FIFO
+//
+// 15 FFUL - CHA FIFO full flag
+// 14 FFUNRN - CHA FIFO under run flag
+// 13
+// 12
+//
+// 11
+// 10
+// 9
+// 8 FRST - FIFO Reset
+//
+// 7 CHAFEILV[3] - CHA FIFO Empty Interrupt Level
+// 6 CHAFEILV[2]
+// 5 CHAFEILV[1]
+// 4 CHAFEILV[0]
+//
+// 3 CHAFINX[3] - CHA FIFO Used
+// 2 CHAFINX[2]
+// 1 CHAFINX[1]
+// 0 CHAFINX[0]
+
+u16 gpl_chx_device::cha_fifo_r()
+{
+ LOGMASKED(LOG_CHX, "%s: gpl_chx_device::cha_fifo_r\n", machine().describe_context());
+ return (m_cha_fifo_reg & 0xfff0) | (m_cha_fifo_entries & 0x000f);
+}
+
+void gpl_chx_device::cha_fifo_w(u16 data)
+{
+ LOGMASKED(LOG_CHX, "%s: gpl_chx_device::cha_fifo_w %04x\n", machine().describe_context(), data);
+ m_cha_fifo_reg = (m_cha_fifo_reg & 0xff0f) | (data & 0x00f0);
+
+ if (data & 0x0100)
+ {
+ m_cha_fifo_readpos = 0;
+ m_cha_fifo_writepos = 0;
+ m_cha_fifo_entries = 0;
+ }
+}
+
+// P_CHB_Ctrl
+// this is different to CHA_Ctrl
+//
+// 15 FEMIF/C - FIFO Empty Interrupt Flag - write to clear
+// 14 FEMIEN - FIFO Empty Interrupt Enable
+// 13 CHBEN - CHB Enable
+// 12 SSF - CHB service Frequency (0 = different to CHAA, 1 = the same)
+//
+// 11 CHACFG - CHB uses CHA config (0 = CHB config, 1 = CHA config)
+// 10 MONO - Mono mode (0 = Stereo, 1 = Mono)
+// 9
+// 8
+//
+// 7
+// 6
+// 5
+// 4
+//
+// 3
+// 2
+// 1
+// 0
+
+u16 gpl_chx_device::chb_ctrl_r()
+{
+ LOGMASKED(LOG_CHX, "%s: gpl_chx_device::chb_ctrl_r\n", machine().describe_context());
+ return m_chb_ctrl;
+}
+
+void gpl_chx_device::chb_ctrl_w(u16 data)
+{
+ LOGMASKED(LOG_CHX, "%s: gpl_chx_device::chb_ctrl_w %04x\n", machine().describe_context(), data);
+
+ if (data & 0x8000)
+ {
+ // clear flag
+ data &= 0x7fff;
+ m_updateirqs_cb(1);
+ }
+
+ m_chb_ctrl = data;
+}
+
+// P_CHB_Data
+//
+// 15-0 CHBDATA
+
+u16 gpl_chx_device::chb_data_r()
+{
+ LOGMASKED(LOG_CHX, "%s: gpl_chx_device::chb_data_r\n", machine().describe_context());
+ return 0xffff;
+}
+
+void gpl_chx_device::chb_data_w(u16 data)
+{
+ LOGMASKED(LOG_CHX, "%s: gpl_chx_device::chb_data_w %04x\n", machine().describe_context(), data);
+
+ if (m_chb_fifo_entries < 16)
+ {
+ m_chb_fifo[m_cha_fifo_writepos] = data;
+ m_chb_fifo_writepos++;
+ m_chb_fifo_writepos &= 0xf;
+
+ m_chb_fifo_entries++;
+ }
+ else
+ {
+ // trying to overflow the FIFO
+ }
+}
+
+// P_CHB_FIFO
+//
+// same as CHA_FIFO but for CHAB
+
+u16 gpl_chx_device::chb_fifo_r()
+{
+ LOGMASKED(LOG_CHX, "%s: gpl_chx_device::chb_fifo_r\n", machine().describe_context());
+ return (m_chb_fifo_reg & 0xfff0) | (m_chb_fifo_entries & 0x000f);
+}
+
+void gpl_chx_device::chb_fifo_w(u16 data)
+{
+ LOGMASKED(LOG_CHX, "%s: gpl_chx_device::chb_fifo_w %04x\n", machine().describe_context(), data);
+ m_chb_fifo_reg = (m_chb_fifo_reg & 0xff0f) | (data & 0x00f0);
+
+ if (data & 0x0100)
+ {
+ m_chb_fifo_readpos = 0;
+ m_chb_fifo_writepos = 0;
+ m_chb_fifo_entries = 0;
+ }
+}
+
+void gpl_chx_device::process_cha_fifo()
+{
+ if (!(m_cha_ctrl & 0x2000))
+ return;
+
+ // should we be calling cha_data_r to do this?
+
+ if (m_cha_fifo_entries > 0)
+ {
+ u16 retdata = m_cha_fifo[m_cha_fifo_readpos];
+ m_cha_fifo_entries--;
+ m_cha_fifo_readpos++;
+ m_cha_fifo_readpos &= 0xf;
+ m_cha_output_cb(retdata);
+ }
+ else
+ {
+ // trying to underflow the FIFO?
+ }
+
+ u8 emptyamount = (m_cha_fifo_reg & 0x00f0) >> 4;
+
+ if (m_cha_fifo_entries <= emptyamount)
+ {
+ if (m_cha_ctrl & 0x4000)
+ {
+ m_cha_ctrl |= 0x8000;
+ m_updateirqs_cb(1);
+ }
+ }
+}
+
+void gpl_chx_device::process_chb_fifo()
+{
+ if (!(m_chb_ctrl & 0x2000))
+ return;
+
+ // should we be calling chb_data_r to do this?
+
+ if (m_chb_fifo_entries > 0)
+ {
+ u16 retdata = m_chb_fifo[m_chb_fifo_readpos];
+ m_chb_fifo_entries--;
+ m_chb_fifo_readpos++;
+ m_chb_fifo_readpos &= 0xf;
+ m_chb_output_cb(retdata);
+ }
+ else
+ {
+ // trying to underflow the FIFO?
+ }
+
+ u8 emptyamount = (m_chb_fifo_reg & 0x00f0) >> 4;
+
+ if (m_chb_fifo_entries <= emptyamount)
+ {
+ if (m_chb_ctrl & 0x4000)
+ {
+ m_chb_ctrl |= 0x8000;
+ m_updateirqs_cb(1);
+ }
+ }
+}
+
+void gpl_chx_device::device_add_mconfig(machine_config &config)
+{
+}
diff --git a/src/devices/machine/generalplus_gpl_chx.h b/src/devices/machine/generalplus_gpl_chx.h
new file mode 100644
index 00000000000..041d16c765a
--- /dev/null
+++ b/src/devices/machine/generalplus_gpl_chx.h
@@ -0,0 +1,66 @@
+// license:BSD-3-Clause
+// copyright-holders:David Haywood
+#ifndef MAME_MACHINE_GENERALPLUS_GPL_CHX_H
+#define MAME_MACHINE_GENERALPLUS_GPL_CHX_H
+
+#pragma once
+
+class gpl_chx_device : public device_t
+{
+public:
+ gpl_chx_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+
+ auto cha_write_callback() { return m_cha_output_cb.bind(); }
+ auto chb_write_callback() { return m_chb_output_cb.bind(); }
+ auto updateirqs_callback() { return m_updateirqs_cb.bind(); }
+
+ bool is_cha_fifo_empty_irq() { return (m_cha_ctrl & 0x8000) ? true : false; }
+ bool is_chb_fifo_empty_irq() { return (m_chb_ctrl & 0x8000) ? true : false; }
+
+ u16 cha_ctrl_r();
+ void cha_ctrl_w(u16 data);
+ u16 cha_data_r();
+ void cha_data_w(u16 data);
+ u16 cha_fifo_r();
+ void cha_fifo_w(u16 data);
+ u16 chb_ctrl_r();
+ void chb_ctrl_w(u16 data);
+ u16 chb_data_r();
+ void chb_data_w(u16 data);
+ u16 chb_fifo_r();
+ void chb_fifo_w(u16 data);
+
+ void process_cha_fifo();
+ void process_chb_fifo();
+
+protected:
+ virtual void device_start() override ATTR_COLD;
+ virtual void device_reset() override ATTR_COLD;
+ virtual void device_add_mconfig(machine_config &config) override ATTR_COLD;
+
+private:
+ u16 m_cha_ctrl;
+ u16 m_chb_ctrl;
+
+ u16 m_cha_fifo[16];
+ u16 m_chb_fifo[16];
+
+ u16 m_cha_fifo_reg;
+ u16 m_chb_fifo_reg;
+
+ u8 m_cha_fifo_readpos;
+ u8 m_cha_fifo_writepos;
+ u8 m_cha_fifo_entries;
+
+ u8 m_chb_fifo_readpos;
+ u8 m_chb_fifo_writepos;
+ u8 m_chb_fifo_entries;
+
+ devcb_write16 m_cha_output_cb;
+ devcb_write16 m_chb_output_cb;
+ devcb_write_line m_updateirqs_cb;
+};
+
+DECLARE_DEVICE_TYPE(GPL_CHX, gpl_chx_device)
+
+#endif // MAME_MACHINE_GENERALPLUS_GPL_CHX_H
diff --git a/src/devices/machine/generalplus_gpl_dma.cpp b/src/devices/machine/generalplus_gpl_dma.cpp
index 5d6510246fb..98a77fb7133 100644
--- a/src/devices/machine/generalplus_gpl_dma.cpp
+++ b/src/devices/machine/generalplus_gpl_dma.cpp
@@ -25,6 +25,7 @@ void gpl_dma_device::device_start()
save_item(NAME(m_dma_params));
save_item(NAME(m_dma_latched));
save_item(NAME(m_system_dma_memtype));
+ save_item(NAME(m_dma_status));
}
void gpl_dma_device::device_reset()
@@ -39,6 +40,7 @@ void gpl_dma_device::device_reset()
}
m_system_dma_memtype = 0x0000;
+ m_dma_status = 0x0000;
}
@@ -149,13 +151,14 @@ void gpl_dma_device::system_dma_params_channel3_w(offs_t offset, u16 data)
u16 gpl_dma_device::system_dma_status_r()
{
LOGMASKED(LOG_GCM394_SYSDMA, "%s:sunplus_gcm394_base_device::system_dma_status_r (7abf)\n", machine().describe_context());
- return 0x00ff;
+ return m_dma_status;
}
void gpl_dma_device::system_dma_status_w(u16 data)
{
// writes to the low 4 bits clear the channel complete interrupt flags
LOGMASKED(LOG_GCM394_SYSDMA, "%s:sunplus_gcm394_base_device::system_dma_status_w %04x\n", machine().describe_context(), data);
+ m_dma_status &= ~data;
}
// m_dma_params[0] is P_DMA_Ctrl
@@ -243,6 +246,8 @@ void gpl_dma_device::trigger_systemm_dma(int channel)
m_dma_params[1][channel] = m_dma_params[2][channel] = m_dma_params[3][channel] = m_dma_params[4][channel] = m_dma_params[5][channel] = m_dma_params[6][channel] = 0x0000;
m_dma_latched[channel] = false;
+ m_dma_status |= 1 << channel; // the flag seems to be set even if IRQs are disabled
+
//machine().debug_break();
}
diff --git a/src/devices/machine/generalplus_gpl_dma.h b/src/devices/machine/generalplus_gpl_dma.h
index de914250bf0..548cc6cbde8 100644
--- a/src/devices/machine/generalplus_gpl_dma.h
+++ b/src/devices/machine/generalplus_gpl_dma.h
@@ -42,6 +42,7 @@ private:
u16 m_system_dma_memtype;
u16 m_dma_params[8][4];
u8 m_dma_latched[4];
+ u16 m_dma_status;
devcb_read16 m_space_read_cb;
devcb_write16 m_space_write_cb;