redalert, demoneye: Audio updates

- More accurate emulation of 555-based IRQ timing
- Use 6821 PIA device to generate sound IRQ in Demoneye
- Simplify handler signatures (nw)
This commit is contained in:
AJR 2020-05-01 21:33:36 -04:00
parent 8a4aca5899
commit d563a7a2d6
4 changed files with 79 additions and 46 deletions

View File

@ -15,7 +15,6 @@
#include "cpu/m6800/m6800.h" #include "cpu/m6800/m6800.h"
#include "cpu/m6502/m6502.h" #include "cpu/m6502/m6502.h"
#include "machine/rescap.h" #include "machine/rescap.h"
#include "machine/6821pia.h"
#include "speaker.h" #include "speaker.h"
@ -23,25 +22,45 @@
#define REDALERT_AUDIO_PCB_CLOCK (XTAL(12'500'000)) #define REDALERT_AUDIO_PCB_CLOCK (XTAL(12'500'000))
#define REDALERT_AUDIO_CPU_CLOCK (REDALERT_AUDIO_PCB_CLOCK / 12) #define REDALERT_AUDIO_CPU_CLOCK (REDALERT_AUDIO_PCB_CLOCK / 12)
#define REDALERT_AY8910_CLOCK (REDALERT_AUDIO_PCB_CLOCK / 6) #define REDALERT_AY8910_CLOCK (REDALERT_AUDIO_PCB_CLOCK / 6)
#define REDALERT_AUDIO_CPU_IRQ_FREQ (1000000000.0 / PERIOD_OF_555_ASTABLE_NSEC(RES_K(120), RES_K(2.7), CAP_U(0.01))) #define REDALERT_AUDIO_CPU_IRQ_FREQ (PERIOD_OF_555_ASTABLE(RES_K(120), RES_K(2.7), CAP_U(0.01)))
#define REDALERT_AUDIO_CPU_IRQ_TIME (PERIOD_OF_555_ASTABLE(RES_K(2.7), 0, CAP_U(0.01))) /* 555 discharge time */
#define REDALERT_VOICE_PCB_CLOCK (XTAL(6'000'000)) #define REDALERT_VOICE_PCB_CLOCK (XTAL(6'000'000))
#define REDALERT_VOICE_CPU_CLOCK (REDALERT_VOICE_PCB_CLOCK) #define REDALERT_VOICE_CPU_CLOCK (REDALERT_VOICE_PCB_CLOCK)
#define REDALERT_HC55516_CLOCK (REDALERT_VOICE_PCB_CLOCK / 256) #define REDALERT_HC55516_CLOCK (REDALERT_VOICE_PCB_CLOCK / 256)
#define DEMONEYE_AUDIO_PCB_CLOCK (XTAL(3'579'545)) #define DEMONEYE_AUDIO_PCB_CLOCK (XTAL(3'579'545))
#define DEMONEYE_AUDIO_CPU_CLOCK (DEMONEYE_AUDIO_PCB_CLOCK / 4) /* what's the real divisor? */ #define DEMONEYE_AUDIO_CPU_CLOCK (DEMONEYE_AUDIO_PCB_CLOCK) /* what's the real divisor? */
#define DEMONEYE_AY8910_CLOCK (DEMONEYE_AUDIO_PCB_CLOCK / 2) /* what's the real divisor? */ #define DEMONEYE_AY8910_CLOCK (DEMONEYE_AUDIO_PCB_CLOCK / 2) /* what's the real divisor? */
TIMER_CALLBACK_MEMBER(redalert_state::audio_irq_on)
{
if (m_sndpia.found())
m_sndpia->cb1_w(0); // guess
else
m_audiocpu->set_input_line(m6502_device::IRQ_LINE, ASSERT_LINE);
m_audio_irq_off_timer->adjust(REDALERT_AUDIO_CPU_IRQ_TIME);
}
TIMER_CALLBACK_MEMBER(redalert_state::audio_irq_off)
{
if (m_sndpia.found())
m_sndpia->cb1_w(1); // guess
else
m_audiocpu->set_input_line(m6502_device::IRQ_LINE, CLEAR_LINE);
}
/************************************* /*************************************
* *
* Read Alert analog sounds * Red Alert analog sounds
* *
*************************************/ *************************************/
WRITE8_MEMBER(redalert_state::redalert_analog_w) void redalert_state::redalert_analog_w(uint8_t data)
{ {
/* this port triggers analog sounds /* this port triggers analog sounds
D0 = Formation Aircraft? D0 = Formation Aircraft?
@ -63,7 +82,7 @@ WRITE8_MEMBER(redalert_state::redalert_analog_w)
* *
*************************************/ *************************************/
WRITE8_MEMBER(redalert_state::redalert_audio_command_w) void redalert_state::redalert_audio_command_w(uint8_t data)
{ {
/* the byte is connected to port A of the AY8910 */ /* the byte is connected to port A of the AY8910 */
m_soundlatch->write(data); m_soundlatch->write(data);
@ -75,7 +94,7 @@ WRITE8_MEMBER(redalert_state::redalert_audio_command_w)
} }
WRITE8_MEMBER(redalert_state::redalert_AY8910_w) void redalert_state::redalert_AY8910_w(uint8_t data)
{ {
/* BC2 is connected to a pull-up resistor, so BC2=1 always */ /* BC2 is connected to a pull-up resistor, so BC2=1 always */
switch (data & 0x03) switch (data & 0x03)
@ -100,13 +119,13 @@ WRITE8_MEMBER(redalert_state::redalert_AY8910_w)
} }
READ8_MEMBER(redalert_state::redalert_ay8910_latch_1_r) uint8_t redalert_state::redalert_ay8910_latch_1_r()
{ {
return m_ay8910_latch_1; return m_ay8910_latch_1;
} }
WRITE8_MEMBER(redalert_state::redalert_ay8910_latch_2_w) void redalert_state::redalert_ay8910_latch_2_w(uint8_t data)
{ {
m_ay8910_latch_2 = data; m_ay8910_latch_2 = data;
} }
@ -129,6 +148,11 @@ void redalert_state::redalert_audio_map(address_map &map)
void redalert_state::sound_start() void redalert_state::sound_start()
{ {
m_audio_irq_on_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(redalert_state::audio_irq_on), this));
m_audio_irq_off_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(redalert_state::audio_irq_off), this));
m_audio_irq_on_timer->adjust(REDALERT_AUDIO_CPU_IRQ_FREQ, 0, REDALERT_AUDIO_CPU_IRQ_FREQ);
save_item(NAME(m_ay8910_latch_1)); save_item(NAME(m_ay8910_latch_1));
save_item(NAME(m_ay8910_latch_2)); save_item(NAME(m_ay8910_latch_2));
} }
@ -140,7 +164,7 @@ void redalert_state::sound_start()
* *
*************************************/ *************************************/
WRITE8_MEMBER(redalert_state::redalert_voice_command_w) void redalert_state::redalert_voice_command_w(uint8_t data)
{ {
m_soundlatch2->write((data & 0x78) >> 3); m_soundlatch2->write((data & 0x78) >> 3);
m_voicecpu->set_input_line(I8085_RST75_LINE, (~data & 0x80) ? ASSERT_LINE : CLEAR_LINE); m_voicecpu->set_input_line(I8085_RST75_LINE, (~data & 0x80) ? ASSERT_LINE : CLEAR_LINE);
@ -179,7 +203,6 @@ void redalert_state::redalert_audio_m37b(machine_config &config)
{ {
M6502(config, m_audiocpu, REDALERT_AUDIO_CPU_CLOCK); M6502(config, m_audiocpu, REDALERT_AUDIO_CPU_CLOCK);
m_audiocpu->set_addrmap(AS_PROGRAM, &redalert_state::redalert_audio_map); m_audiocpu->set_addrmap(AS_PROGRAM, &redalert_state::redalert_audio_map);
m_audiocpu->set_periodic_int(FUNC(redalert_state::irq0_line_hold), attotime::from_hz(REDALERT_AUDIO_CPU_IRQ_FREQ));
GENERIC_LATCH_8(config, m_soundlatch); GENERIC_LATCH_8(config, m_soundlatch);
@ -243,7 +266,7 @@ void redalert_state::ww3_audio(machine_config &config)
*************************************/ *************************************/
WRITE8_MEMBER(redalert_state::demoneye_audio_command_w) void redalert_state::demoneye_audio_command_w(uint8_t data)
{ {
/* the byte is connected to port A of the AY8910 */ /* the byte is connected to port A of the AY8910 */
m_soundlatch->write(data); m_soundlatch->write(data);
@ -251,19 +274,19 @@ WRITE8_MEMBER(redalert_state::demoneye_audio_command_w)
} }
WRITE8_MEMBER(redalert_state::demoneye_ay8910_latch_1_w) void redalert_state::demoneye_ay8910_latch_1_w(uint8_t data)
{ {
m_ay8910_latch_1 = data; m_ay8910_latch_1 = data;
} }
READ8_MEMBER(redalert_state::demoneye_ay8910_latch_2_r) uint8_t redalert_state::demoneye_ay8910_latch_2_r()
{ {
return m_ay8910_latch_2; return m_ay8910_latch_2;
} }
WRITE8_MEMBER(redalert_state::demoneye_ay8910_data_w) void redalert_state::demoneye_ay8910_data_w(uint8_t data)
{ {
switch (m_ay8910_latch_1 & 0x03) switch (m_ay8910_latch_1 & 0x03)
{ {
@ -303,7 +326,7 @@ WRITE8_MEMBER(redalert_state::demoneye_ay8910_data_w)
void redalert_state::demoneye_audio_map(address_map &map) void redalert_state::demoneye_audio_map(address_map &map)
{ {
map(0x0500, 0x0503).mirror(0xc000).rw("sndpia", FUNC(pia6821_device::read), FUNC(pia6821_device::write)); map(0x0500, 0x0503).mirror(0xc000).rw(m_sndpia, FUNC(pia6821_device::read), FUNC(pia6821_device::write));
map(0x2000, 0x3fff).mirror(0xc000).rom(); map(0x2000, 0x3fff).mirror(0xc000).rom();
} }
@ -319,12 +342,12 @@ void redalert_state::demoneye_audio(machine_config &config)
{ {
M6802(config, m_audiocpu, DEMONEYE_AUDIO_CPU_CLOCK); M6802(config, m_audiocpu, DEMONEYE_AUDIO_CPU_CLOCK);
m_audiocpu->set_addrmap(AS_PROGRAM, &redalert_state::demoneye_audio_map); m_audiocpu->set_addrmap(AS_PROGRAM, &redalert_state::demoneye_audio_map);
m_audiocpu->set_periodic_int(FUNC(redalert_state::irq0_line_hold), attotime::from_hz(REDALERT_AUDIO_CPU_IRQ_FREQ)); /* guess */
pia6821_device &sndpia(PIA6821(config, "sndpia", 0)); PIA6821(config, m_sndpia);
sndpia.readpa_handler().set(FUNC(redalert_state::demoneye_ay8910_latch_2_r)); m_sndpia->readpa_handler().set(FUNC(redalert_state::demoneye_ay8910_latch_2_r));
sndpia.writepa_handler().set(FUNC(redalert_state::demoneye_ay8910_data_w)); m_sndpia->writepa_handler().set(FUNC(redalert_state::demoneye_ay8910_data_w));
sndpia.writepb_handler().set(FUNC(redalert_state::demoneye_ay8910_latch_1_w)); m_sndpia->writepb_handler().set(FUNC(redalert_state::demoneye_ay8910_latch_1_w));
m_sndpia->irqb_handler().set_inputline(m_audiocpu, M6802_IRQ_LINE);
SPEAKER(config, "mono").front_center(); SPEAKER(config, "mono").front_center();

View File

@ -119,8 +119,9 @@ INTERRUPT_GEN_MEMBER(redalert_state::redalert_vblank_interrupt)
} }
READ8_MEMBER(redalert_state::redalert_interrupt_clear_r) uint8_t redalert_state::redalert_interrupt_clear_r()
{ {
if (!machine().side_effects_disabled())
m_maincpu->set_input_line(M6502_IRQ_LINE, CLEAR_LINE); m_maincpu->set_input_line(M6502_IRQ_LINE, CLEAR_LINE);
/* the result never seems to be actually used */ /* the result never seems to be actually used */
@ -129,19 +130,20 @@ READ8_MEMBER(redalert_state::redalert_interrupt_clear_r)
WRITE8_MEMBER(redalert_state::redalert_interrupt_clear_w) void redalert_state::redalert_interrupt_clear_w(uint8_t data)
{ {
redalert_interrupt_clear_r(space, 0); m_maincpu->set_input_line(M6502_IRQ_LINE, CLEAR_LINE);
} }
READ8_MEMBER(redalert_state::panther_interrupt_clear_r) uint8_t redalert_state::panther_interrupt_clear_r()
{ {
if (!machine().side_effects_disabled())
m_maincpu->set_input_line(M6502_IRQ_LINE, CLEAR_LINE); m_maincpu->set_input_line(M6502_IRQ_LINE, CLEAR_LINE);
return ioport("STICK0")->read(); return ioport("STICK0")->read();
} }
READ8_MEMBER(redalert_state::panther_unk_r) uint8_t redalert_state::panther_unk_r()
{ {
return ((machine().rand() & 0x01) | (ioport("C020")->read() & 0xfe)); return ((machine().rand() & 0x01) | (ioport("C020")->read() & 0xfe));
} }

View File

@ -19,6 +19,7 @@
#pragma once #pragma once
#include "cpu/i8085/i8085.h" #include "cpu/i8085/i8085.h"
#include "machine/6821pia.h"
#include "machine/gen_latch.h" #include "machine/gen_latch.h"
#include "sound/ay8910.h" #include "sound/ay8910.h"
#include "sound/hc55516.h" #include "sound/hc55516.h"
@ -39,6 +40,7 @@ public:
m_ay8910(*this, "aysnd"), m_ay8910(*this, "aysnd"),
m_ay(*this, "ay%u", 1U), m_ay(*this, "ay%u", 1U),
m_cvsd(*this, "cvsd"), m_cvsd(*this, "cvsd"),
m_sndpia(*this, "sndpia"),
m_screen(*this, "screen"), m_screen(*this, "screen"),
m_soundlatch(*this, "soundlatch"), m_soundlatch(*this, "soundlatch"),
m_soundlatch2(*this, "soundlatch2") m_soundlatch2(*this, "soundlatch2")
@ -72,35 +74,38 @@ private:
optional_device<ay8910_device> m_ay8910; optional_device<ay8910_device> m_ay8910;
optional_device_array<ay8910_device, 2> m_ay; optional_device_array<ay8910_device, 2> m_ay;
optional_device<hc55516_device> m_cvsd; optional_device<hc55516_device> m_cvsd;
optional_device<pia6821_device> m_sndpia;
required_device<screen_device> m_screen; required_device<screen_device> m_screen;
required_device<generic_latch_8_device> m_soundlatch; required_device<generic_latch_8_device> m_soundlatch;
optional_device<generic_latch_8_device> m_soundlatch2; optional_device<generic_latch_8_device> m_soundlatch2;
std::unique_ptr<uint8_t[]> m_bitmap_colorram; std::unique_ptr<uint8_t[]> m_bitmap_colorram;
uint8_t m_control_xor; uint8_t m_control_xor;
DECLARE_READ8_MEMBER(redalert_interrupt_clear_r); uint8_t redalert_interrupt_clear_r();
DECLARE_WRITE8_MEMBER(redalert_interrupt_clear_w); void redalert_interrupt_clear_w(uint8_t data);
DECLARE_READ8_MEMBER(panther_interrupt_clear_r); uint8_t panther_interrupt_clear_r();
DECLARE_READ8_MEMBER(panther_unk_r); uint8_t panther_unk_r();
DECLARE_WRITE8_MEMBER(redalert_bitmap_videoram_w); void redalert_bitmap_videoram_w(offs_t offset, uint8_t data);
DECLARE_WRITE8_MEMBER(redalert_audio_command_w); void redalert_audio_command_w(uint8_t data);
DECLARE_READ8_MEMBER(redalert_ay8910_latch_1_r); uint8_t redalert_ay8910_latch_1_r();
DECLARE_WRITE8_MEMBER(redalert_ay8910_latch_2_w); void redalert_ay8910_latch_2_w(uint8_t data);
DECLARE_WRITE8_MEMBER(redalert_voice_command_w); void redalert_voice_command_w(uint8_t data);
DECLARE_WRITE8_MEMBER(demoneye_audio_command_w); void demoneye_audio_command_w(uint8_t data);
DECLARE_VIDEO_START(redalert); DECLARE_VIDEO_START(redalert);
DECLARE_VIDEO_START(ww3); DECLARE_VIDEO_START(ww3);
uint32_t screen_update_redalert(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect); uint32_t screen_update_redalert(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect);
uint32_t screen_update_demoneye(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect); uint32_t screen_update_demoneye(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect);
uint32_t screen_update_panther(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect); uint32_t screen_update_panther(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect);
INTERRUPT_GEN_MEMBER(redalert_vblank_interrupt); INTERRUPT_GEN_MEMBER(redalert_vblank_interrupt);
DECLARE_WRITE8_MEMBER(redalert_analog_w); TIMER_CALLBACK_MEMBER(audio_irq_on);
DECLARE_WRITE8_MEMBER(redalert_AY8910_w); TIMER_CALLBACK_MEMBER(audio_irq_off);
void redalert_analog_w(uint8_t data);
void redalert_AY8910_w(uint8_t data);
DECLARE_WRITE_LINE_MEMBER(sod_callback); DECLARE_WRITE_LINE_MEMBER(sod_callback);
DECLARE_READ_LINE_MEMBER(sid_callback); DECLARE_READ_LINE_MEMBER(sid_callback);
DECLARE_WRITE8_MEMBER(demoneye_ay8910_latch_1_w); void demoneye_ay8910_latch_1_w(uint8_t data);
DECLARE_READ8_MEMBER(demoneye_ay8910_latch_2_r); uint8_t demoneye_ay8910_latch_2_r();
DECLARE_WRITE8_MEMBER(demoneye_ay8910_data_w); void demoneye_ay8910_data_w(uint8_t data);
void get_pens(pen_t *pens); void get_pens(pen_t *pens);
void get_panther_pens(pen_t *pens); void get_panther_pens(pen_t *pens);
@ -116,6 +121,9 @@ private:
void redalert_voice_map(address_map &map); void redalert_voice_map(address_map &map);
emu_timer *m_audio_irq_on_timer;
emu_timer *m_audio_irq_off_timer;
uint8_t m_ay8910_latch_1; uint8_t m_ay8910_latch_1;
uint8_t m_ay8910_latch_2; uint8_t m_ay8910_latch_2;
}; };

View File

@ -24,7 +24,7 @@
* *
*************************************/ *************************************/
WRITE8_MEMBER(redalert_state::redalert_bitmap_videoram_w) void redalert_state::redalert_bitmap_videoram_w(offs_t offset, uint8_t data)
{ {
m_bitmap_videoram[offset ] = data; m_bitmap_videoram[offset ] = data;
m_bitmap_colorram[offset >> 3] = *m_bitmap_color & 0x07; m_bitmap_colorram[offset >> 3] = *m_bitmap_color & 0x07;