diff options
| author | 2026-05-15 16:46:53 +0100 | |
|---|---|---|
| committer | 2026-05-15 17:46:53 +0200 | |
| commit | 6db34f14119b1b46c87e17af74b07544b6948e7a (patch) | |
| tree | 0f5433ee0e1c2a9eb5b2d3685b909b9d1ba2402c | |
| parent | e16cbf731e69d5df95a0cfcb954d25af9a228b64 (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.lua | 2 | ||||
| -rw-r--r-- | src/devices/machine/generalplus_gpl162xx_soc_video.cpp | 192 | ||||
| -rw-r--r-- | src/devices/machine/generalplus_gpl951xx_soc.cpp | 275 | ||||
| -rw-r--r-- | src/devices/machine/generalplus_gpl951xx_soc.h | 45 | ||||
| -rw-r--r-- | src/devices/machine/generalplus_gpl_chx.cpp | 341 | ||||
| -rw-r--r-- | src/devices/machine/generalplus_gpl_chx.h | 66 | ||||
| -rw-r--r-- | src/devices/machine/generalplus_gpl_dma.cpp | 7 | ||||
| -rw-r--r-- | src/devices/machine/generalplus_gpl_dma.h | 1 |
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; |
