From 6b43a40500193a8342aa64e6849fcba5e7402565 Mon Sep 17 00:00:00 2001 From: angelosa Date: Wed, 13 Apr 2022 16:53:26 +0200 Subject: arm_iomd.cpp: improve serial DAC overrun/int handling, makes SFXs to work better in ppcar; acorn_vidc.cpp: workaround missing default QS1000 sounds in ssfindo/tetfight by disabling DAC outputs for the time being; --- src/devices/machine/acorn_vidc.cpp | 95 ++++++++++++++++++++++++++++++-------- src/devices/machine/acorn_vidc.h | 18 +++++--- src/devices/machine/arm_iomd.cpp | 34 +++++++------- src/devices/machine/arm_iomd.h | 13 +++--- src/mame/drivers/ssfindo.cpp | 20 ++++---- 5 files changed, 119 insertions(+), 61 deletions(-) diff --git a/src/devices/machine/acorn_vidc.cpp b/src/devices/machine/acorn_vidc.cpp index df95dba9079..f055d11b886 100644 --- a/src/devices/machine/acorn_vidc.cpp +++ b/src/devices/machine/acorn_vidc.cpp @@ -12,8 +12,10 @@ * nebulus: 20 lines off with aa310; * lotustc2: abuses color flipping; * quazer: needs in-flight DMA; - - improve sound DAC writes; - - subclass this for VIDC20 emulation (RiscPC); + - move DAC handling into a separate sub-device(s), + particularly needed for proper VIDC20 mixing and likely for fixing aliasing + issues in VIDC10; + - complete VIDC20 emulation (RiscPC/ssfindo.cpp); - Are CRTC values correct? VGA modes have a +1 in display line; **********************************************************************************************/ @@ -208,7 +210,7 @@ void acorn_vidc10_device::device_reset() { m_cursor_enable = false; memset(m_stereo_image, 4, m_sound_max_channels); - for (int ch=0;chadjust(attotime::never); m_sound_timer->adjust(attotime::never); @@ -317,11 +319,11 @@ inline void acorn_vidc10_device::update_4bpp_palette(u16 index, u32 paldata) void acorn_vidc10_device::pal_data_display_w(offs_t offset, u32 data) { - update_4bpp_palette(offset+0x100, data); + update_4bpp_palette(offset + 0x100, data); //printf("%02x: %01x %01x %01x [%d]\n",offset,r,g,b,screen().vpos()); // 8bpp - for(int idx=0;idx<0x100;idx+=0x10) + for (int idx = 0; idx < 0x100; idx += 0x10) { int b = ((data & 0x700) >> 8) | ((idx & 0x80) >> 4); int g = ((data & 0x030) >> 4) | ((idx & 0x60) >> 3); @@ -415,8 +417,8 @@ inline void acorn_vidc10_device::refresh_stereo_image(u8 channel) const float left_gain[8] = { 1.0f, 2.0f, 1.66f, 1.34f, 1.0f, 0.66f, 0.34f, 0.0f }; const float right_gain[8] = { 1.0f, 0.0f, 0.34f, 0.66f, 1.0f, 1.34f, 1.66f, 2.0f }; - m_lspeaker->set_input_gain(channel,left_gain[m_stereo_image[channel]]*m_sound_input_gain); - m_rspeaker->set_input_gain(channel,right_gain[m_stereo_image[channel]]*m_sound_input_gain); + m_lspeaker->set_input_gain(channel, left_gain[m_stereo_image[channel]] * m_sound_input_gain); + m_rspeaker->set_input_gain(channel, right_gain[m_stereo_image[channel]] * m_sound_input_gain); //printf("%d %f %f\n",channel,m_lspeaker->input(channel).gain(),m_rspeaker->input(channel).gain()); } @@ -454,7 +456,7 @@ void acorn_vidc10_device::refresh_sound_frequency() { // TODO: Range is between 3 and 256 usecs double sndhz = 1e6 / ((m_sound_frequency_latch & 0xff) + 2); - sndhz /= m_sound_internal_divider; + sndhz /= get_dac_mode() == true ? 2.0 : 8.0; m_sound_timer->adjust(attotime::zero, 0, attotime::from_hz(sndhz)); //printf("VIDC: audio DMA start, sound freq %d, sndhz = %f\n", (m_crtc_regs[0xc0] & 0xff)-2, sndhz); } @@ -479,17 +481,17 @@ void acorn_vidc10_device::draw(bitmap_rgb32 &bitmap, const rectangle &cliprect, //printf("%d %d %d %d\n",ystart, ysize, cliprect.min_y, cliprect.max_y); - for (int srcy = raster_ystart; srcy>(xi*pen_byte_size)) & pen_mask); + u16 dot = (pen >> (xi * pen_byte_size)) & pen_mask; if (is_cursor == true && dot == 0) continue; dot += pen_base; @@ -556,7 +558,11 @@ READ_LINE_MEMBER(acorn_vidc10_device::flyback_r) return false; } -// VIDC20 +/* + * + * VIDC20 overrides + * + */ void arm_vidc20_device::regs_map(address_map &map) { @@ -564,6 +570,7 @@ void arm_vidc20_device::regs_map(address_map &map) map(0x10, 0x1f).w(FUNC(arm_vidc20_device::vidc20_pal_data_index_w)); map(0x40, 0x7f).w(FUNC(arm_vidc20_device::vidc20_pal_data_cursor_w)); map(0x80, 0x9f).w(FUNC(arm_vidc20_device::vidc20_crtc_w)); +// map(0xa0, 0xa7) stereo image map(0xb0, 0xb0).w(FUNC(arm_vidc20_device::vidc20_sound_frequency_w)); map(0xb1, 0xb1).w(FUNC(arm_vidc20_device::vidc20_sound_control_w)); map(0xd0, 0xdf).w(FUNC(arm_vidc20_device::fsynreg_w)); @@ -572,6 +579,7 @@ void arm_vidc20_device::regs_map(address_map &map) arm_vidc20_device::arm_vidc20_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) : acorn_vidc10_device(mconfig, ARM_VIDC20, tag, owner, clock, 2) + , m_dac32(*this, "serial_dac_%u", 0) { m_space_config = address_space_config("regs_space", ENDIANNESS_LITTLE, 32, 8, -2, address_map_constructor(FUNC(arm_vidc20_device::regs_map), this)); m_pal_4bpp_base = 0x000; @@ -583,8 +591,20 @@ arm_vidc20_device::arm_vidc20_device(const machine_config &mconfig, const char * void arm_vidc20_device::device_add_mconfig(machine_config &config) { acorn_vidc10_device::device_add_mconfig(config); - // ... - // TODO: for simplicity we may as well add separate DACs for 32-bit mode + + // FIXME: disable DACs for the time being + // so that it won't mixin with QS1000 source for ssfindo.cpp games + for (int i = 0; i < m_sound_max_channels; i++) + { + m_dac[i]->reset_routes(); + m_dac[i]->add_route(0, m_lspeaker, 0.0); + m_dac[i]->add_route(0, m_rspeaker, 0.0); + } + + // For simplicity we separate DACs for 32-bit mode + // TODO: how stereo image copes with this if at all? + DAC_16BIT_R2R_TWOS_COMPLEMENT(config, m_dac32[0], 0).add_route(ALL_OUTPUTS, m_lspeaker, 0.25); + DAC_16BIT_R2R_TWOS_COMPLEMENT(config, m_dac32[1], 0).add_route(ALL_OUTPUTS, m_rspeaker, 0.25); } void arm_vidc20_device::device_config_complete() @@ -623,13 +643,30 @@ void arm_vidc20_device::device_reset() // TODO: sensible defaults m_vco_r_modulo = 1; m_vco_v_modulo = 1; + + // make sure DACs don't output any undefined behaviour for now + // (will cause wild DC offset in ssfindo.cpp games) + for (int ch = 0; ch < 8; ch ++) + write_dac(ch, 0); + + write_dac32(0, 0); + write_dac32(1, 0); } void arm_vidc20_device::device_timer(emu_timer &timer, device_timer_id id, int param) { acorn_vidc10_device::device_timer(timer, id, param); + // TODO: other timers +} + +inline void arm_vidc20_device::refresh_stereo_image(u8 channel) +{ + // TODO: set_input_gain hampers with both QS1000 and serial DAC mode + // Best option is to move the legacy DAC handling into a separate device, + // make it proper 8 channel output while clients are responsible of mix-ins } + inline void arm_vidc20_device::update_8bpp_palette(u16 index, u32 paldata) { int r,g,b; @@ -732,7 +769,7 @@ void arm_vidc20_device::vidc20_control_w(u32 data) // ---- --00: VCLK // ---- --01: HCLK // ---- --10: RCLK ("recommended" 24 MHz) - // ---- --11: undefined, prolly same as RCLK + // ---- --11: undefined, probably same as RCLK m_pixel_source = data & 3; m_pixel_rate = (data & 0x1c) >> 2; // (data & 0x700) >> 8 FIFO load @@ -750,6 +787,26 @@ void arm_vidc20_device::vidc20_sound_control_w(u32 data) { // TODO: VIDC10 mode, ext clock bit 0 m_dac_serial_mode = BIT(data, 1); + + if (m_dac_serial_mode) + { + m_dac32[0]->set_output_gain(0, 1.0); + m_dac32[1]->set_output_gain(0, 1.0); + + for (int ch = 0; ch < m_sound_max_channels; ch++) + m_dac[ch]->set_output_gain(0, 0.0); + } + else + { + m_dac32[0]->set_output_gain(0, 0.0); + m_dac32[1]->set_output_gain(0, 0.0); + + for (int ch = 0; ch < m_sound_max_channels; ch++) + { + //m_dac[ch]->set_output_gain(0, 0.0); + refresh_stereo_image(ch); + } + } } void arm_vidc20_device::vidc20_sound_frequency_w(u32 data) @@ -761,7 +818,7 @@ void arm_vidc20_device::vidc20_sound_frequency_w(u32 data) void arm_vidc20_device::write_dac32(u8 channel, u16 data) { - m_dac[channel & 1]->write(data); + m_dac32[channel & 1]->write(data); } bool arm_vidc20_device::get_dac_mode() @@ -774,5 +831,3 @@ u32 arm_vidc20_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap // TODO: support for true color modes return acorn_vidc10_device::screen_update(screen, bitmap, cliprect); } - - diff --git a/src/devices/machine/acorn_vidc.h b/src/devices/machine/acorn_vidc.h index 5b68aefc559..d5e86cb1e30 100644 --- a/src/devices/machine/acorn_vidc.h +++ b/src/devices/machine/acorn_vidc.h @@ -46,6 +46,8 @@ public: void set_cursor_enable(bool state) { m_cursor_enable = state; } u32 get_cursor_size() { return (m_crtc_regs[CRTC_VCER] - m_crtc_regs[CRTC_VCSR]) * (32/4); } + virtual bool get_dac_mode() { return false; } + protected: acorn_vidc10_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock, int dac_type); @@ -81,7 +83,6 @@ protected: u16 m_pal_4bpp_base; u16 m_pal_cursor_base; u16 m_pal_border_base; - const double m_sound_internal_divider = 8.0; u8 m_bpp_mode, m_crtc_interlace; u8 m_sound_frequency_latch; @@ -90,9 +91,12 @@ protected: required_device_array m_dac; int m_dac_type; -private: required_device m_lspeaker; required_device m_rspeaker; + + virtual void refresh_stereo_image(u8 channel); + const int m_sound_max_channels = 8; +private: devcb_write_line m_vblank_cb; devcb_write_line m_sound_drq_cb; @@ -124,9 +128,7 @@ private: bool m_sound_frequency_test_bit; u8 m_stereo_image[8]; const float m_sound_input_gain = 0.05f; - const int m_sound_max_channels = 8; int16_t m_ulaw_lookup[256]; - inline void refresh_stereo_image(u8 channel); }; class acorn_vidc1_device : public acorn_vidc10_device @@ -154,7 +156,7 @@ public: arm_vidc20_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock); void write_dac32(u8 channel, u16 data); - bool get_dac_mode(); + virtual bool get_dac_mode() override; protected: virtual void device_add_mconfig(machine_config &config) override; @@ -167,8 +169,6 @@ protected: u32 screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect); virtual u32 get_pixel_clock() override; - const double m_sound_internal_divider = 1.0; - private: void vidc20_pal_data_display_w(offs_t offset, u32 data); void vidc20_pal_data_index_w(u32 data); @@ -186,6 +186,10 @@ private: u8 m_pixel_rate; u8 m_vco_r_modulo; u8 m_vco_v_modulo; + + required_device_array m_dac32; + + virtual void refresh_stereo_image(u8 channel) override; }; DECLARE_DEVICE_TYPE(ARM_VIDC20, arm_vidc20_device) diff --git a/src/devices/machine/arm_iomd.cpp b/src/devices/machine/arm_iomd.cpp index af71ab3f53a..2880c46e714 100644 --- a/src/devices/machine/arm_iomd.cpp +++ b/src/devices/machine/arm_iomd.cpp @@ -259,8 +259,6 @@ void arm_iomd_device::device_start() save_item(NAME(m_sndend)); save_item(NAME(m_sound_dma_on)); save_item(NAME(m_sndcur_buffer)); - save_item(NAME(m_snd_overrun)); - save_item(NAME(m_snd_int)); save_pointer(NAME(m_sndcur_reg), sounddma_ch_size); save_pointer(NAME(m_sndend_reg), sounddma_ch_size); @@ -303,11 +301,11 @@ void arm_iomd_device::device_reset() m_irq_mask[i] = 0; } - for (i=0; iadjust(attotime::never); m_sound_dma_on = false; - for (i=0; i u32 arm_iomd_device::sdcur_r() { return m_sndcur_reg[Which]; } @@ -572,6 +568,7 @@ template void arm_iomd_device::sdend_w(offs_t offset, u32 data, m_sndend_reg[Which] &= 0x00fffff0; m_sndstop_reg[Which] = BIT(data, 31); m_sndlast_reg[Which] = BIT(data, 30); + m_sndbuffer_ok[Which] = true; } u32 arm_iomd_device::sdcr_r() @@ -594,12 +591,19 @@ void arm_iomd_device::sdcr_w(u32 data) // ... } - // TODO: bit 7 resets sound DMA + // TODO: sound DMA reset + // eats samples in ppcar +// if (BIT(data, 7)) +// m_sndbuffer_ok[0] = m_sndbuffer_ok[1] = false; } u32 arm_iomd_device::sdst_r() { - return (m_snd_overrun << 2) | (m_snd_int << 1) | m_sndcur_buffer; + // TODO: confirm implementation + bool sound_overrun = m_sndbuffer_ok[0] == false && m_sndbuffer_ok[1] == false; + bool sound_int = m_sndbuffer_ok[0] == false || m_sndbuffer_ok[1] == false; + + return (sound_overrun << 2) | (sound_int << 1) | m_sndcur_buffer; } // video DMA @@ -706,11 +710,7 @@ inline void arm_iomd_device::sounddma_swap_buffer() { m_sndcur = m_sndcur_reg[m_sndcur_buffer]; m_sndend = m_sndcur + (m_sndend_reg[m_sndcur_buffer] + 0x10); - m_sndbuffer_ok[m_sndcur_buffer] = true; - - // TODO: actual condition for int - m_snd_overrun = false; - m_snd_int = false; +// m_sndbuffer_ok[m_sndcur_buffer] = true; } WRITE_LINE_MEMBER( arm_iomd_device::sound_drq ) @@ -720,21 +720,21 @@ WRITE_LINE_MEMBER( arm_iomd_device::sound_drq ) if (m_vidc->get_dac_mode() == true) { - for (int ch=0;ch<2;ch++) + if (!m_sndbuffer_ok[m_sndcur_buffer]) + return; + + for (int ch = 0; ch < 2; ch++) m_vidc->write_dac32(ch, (m_host_space->read_word(m_sndcur + ch*2))); m_sndcur += 4; if (m_sndcur >= m_sndend) { - // TODO: interrupt bit - m_vidc->update_sound_mode(m_sound_dma_on); if (m_sound_dma_on) { m_sndbuffer_ok[m_sndcur_buffer] = false; m_sndcur_buffer ^= 1; - m_snd_overrun = (m_sndbuffer_ok[m_sndcur_buffer] == false); sounddma_swap_buffer(); } else diff --git a/src/devices/machine/arm_iomd.h b/src/devices/machine/arm_iomd.h index c7c98035e85..8600c55cf22 100644 --- a/src/devices/machine/arm_iomd.h +++ b/src/devices/machine/arm_iomd.h @@ -118,13 +118,12 @@ private: void cursinit_w(offs_t offset, u32 data, u32 mem_mask = ~0); static constexpr int sounddma_ch_size = 2; - u32 m_sndcur, m_sndend; - u32 m_sndcur_reg[sounddma_ch_size], m_sndend_reg[sounddma_ch_size]; - bool m_sndstop_reg[sounddma_ch_size], m_sndlast_reg[sounddma_ch_size]; - bool m_sndbuffer_ok[sounddma_ch_size]; - bool m_sound_dma_on; - u8 m_sndcur_buffer; - bool m_snd_overrun, m_snd_int; + u32 m_sndcur = 0, m_sndend = 0; + u32 m_sndcur_reg[sounddma_ch_size]{}, m_sndend_reg[sounddma_ch_size]{}; + bool m_sndstop_reg[sounddma_ch_size]{}, m_sndlast_reg[sounddma_ch_size]{}; + bool m_sndbuffer_ok[sounddma_ch_size]{}; + bool m_sound_dma_on = false; + u8 m_sndcur_buffer = 0; inline void sounddma_swap_buffer(); template u32 sdcur_r(); template void sdcur_w(offs_t offset, u32 data, u32 mem_mask = ~0); diff --git a/src/mame/drivers/ssfindo.cpp b/src/mame/drivers/ssfindo.cpp index c653b76e3a8..ce06865870f 100644 --- a/src/mame/drivers/ssfindo.cpp +++ b/src/mame/drivers/ssfindo.cpp @@ -1,6 +1,6 @@ // license:BSD-3-Clause // copyright-holders:Tomasz Slanina -/************************************************************************ +/************************************************************************************************** 'RISC PC' hardware @@ -17,10 +17,10 @@ TODO: - timing - unknown reads/writes - improve sound hook up - - ppcar uses the VIDC internal DAC for SFX and the QS1000 for music. It's configured to use the undumped internal ROM. + - ppcar: uses the VIDC internal DAC for SFX and the QS1000 for music. + It's configured to use the undumped internal ROM. - -************************************************************************************************************* +=================================================================================================== See See Find Out Icarus, 1999 @@ -69,7 +69,7 @@ Notes: mounting pads for 4 more of these ROMs but they're not populated. -************************************************************************************************************** +=================================================================================================== Pong Pong Car Icarus, 1999 @@ -124,7 +124,7 @@ Notes: DU5, DU6 These ROMs are mounted on a small plug-in daughterboard. There are additional mounting pads for 4 more of these ROMs but they're not populated. -*/ +**************************************************************************************************/ #include "emu.h" #include "cpu/arm7/arm7.h" @@ -235,7 +235,7 @@ private: uint32_t tetfight_unk_r(); }; -//TODO: eeprom 24c01 & 24c02 +// TODO: eeprom 24c01 & 24c02 // TODO: untangle, kill hacks uint8_t ssfindo_state::iolines_r() { @@ -616,8 +616,8 @@ void ssfindo_state::ssfindo(machine_config &config) qs1000_device &qs1000(QS1000(config, "qs1000", 24_MHz_XTAL)); qs1000.set_external_rom(true); // qs1000.p1_out().set(FUNC()); // TODO: writes something here - qs1000.add_route(0, "lspeaker", 1.0); - qs1000.add_route(1, "rspeaker", 1.0); + qs1000.add_route(0, "lspeaker", 0.25); + qs1000.add_route(1, "rspeaker", 0.25); } void ssfindo_state::ppcar(machine_config &config) @@ -740,4 +740,4 @@ void tetfight_state::init_tetfight() GAME( 1999, ssfindo, 0, ssfindo, ssfindo, ssfindo_state, init_ssfindo, ROT0, "Icarus", "See See Find Out", MACHINE_IMPERFECT_SOUND | MACHINE_SUPPORTS_SAVE ) GAME( 1999, ppcar, 0, ppcar, ppcar, ssfindo_state, init_ppcar, ROT0, "Icarus", "Pang Pang Car", MACHINE_IMPERFECT_SOUND | MACHINE_SUPPORTS_SAVE ) -GAME( 2001, tetfight,0, tetfight, tetfight, tetfight_state, init_tetfight, ROT0, "Sego", "Tetris Fighters", MACHINE_IMPERFECT_SOUND | MACHINE_NOT_WORKING | MACHINE_SUPPORTS_SAVE ) +GAME( 2001, tetfight,0, tetfight, tetfight, tetfight_state, init_tetfight, ROT0, "Sego", "Tetris Fighters", MACHINE_IMPERFECT_SOUND | MACHINE_NOT_WORKING | MACHINE_SUPPORTS_SAVE ) // severe frame hiccups -- cgit v1.2.3