summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
-rw-r--r--src/devices/sound/ymz770.cpp129
-rw-r--r--src/devices/sound/ymz770.h8
2 files changed, 126 insertions, 11 deletions
diff --git a/src/devices/sound/ymz770.cpp b/src/devices/sound/ymz770.cpp
index c7a7a91a114..86f2710f2fa 100644
--- a/src/devices/sound/ymz770.cpp
+++ b/src/devices/sound/ymz770.cpp
@@ -102,9 +102,11 @@ void ymz770_device::device_start()
}
for (int ch = 0; ch < 8; ch++)
{
- save_item(NAME(m_sequences[ch].sequence), ch);
- save_item(NAME(m_sequences[ch].control), ch);
save_item(NAME(m_sequences[ch].delay), ch);
+ save_item(NAME(m_sequences[ch].sequence), ch);
+ save_item(NAME(m_sequences[ch].timer), ch);
+ save_item(NAME(m_sequences[ch].stopchan), ch);
+ save_item(NAME(m_sequences[ch].loop), ch);
save_item(NAME(m_sequences[ch].is_playing), ch);
}
}
@@ -133,9 +135,11 @@ void ymz770_device::device_reset()
}
for (auto & sequence : m_sequences)
{
- sequence.sequence = 0;
- sequence.control = 0;
sequence.delay = 0;
+ sequence.sequence = 0;
+ sequence.timer = 0;
+ sequence.stopchan = 0;
+ sequence.loop = 0;
sequence.is_playing = false;
}
}
@@ -268,7 +272,7 @@ void ymz770_device::sequencer()
switch (reg)
{
case 0x0f:
- if (sequence.control & 1)
+ if (sequence.loop)
{
// loop sequence
uint8_t sqn = sequence.sequence;
@@ -401,7 +405,7 @@ void ymz770_device::internal_reg_write(uint8_t reg, uint8_t data)
m_sequences[ch].is_playing = false;
}
- m_sequences[ch].control = data;
+ m_sequences[ch].loop = data & 1;
break;
default:
@@ -503,9 +507,65 @@ void ymz774_device::internal_reg_write(uint8_t reg, uint8_t data)
}
else if (reg < 0xd0)
{
- if (m_bank == 0) // Sequencer, in PGM2 games not used at all
+ if (m_bank == 0)
{
- if (data) logerror("sequencer unimplemented %02X %02X\n", reg, data);
+ if (reg < 0xb0)
+ {
+ int sq = reg & 7;
+ switch (reg & 0xf8)
+ {
+ case 0x60: // sequence num H and L
+ case 0x68:
+ sq = (reg >> 1) & 7;
+ if (sq & 1)
+ m_sequences[sq].sequence = (m_sequences[sq].sequence & 0xff00) | data;
+ else
+ m_sequences[sq].sequence = (m_sequences[sq].sequence & 0x00ff) | ((data & 0x0f) << 8); // TODO check if total number really upto 0x1000
+ break;
+ case 0x70: // Start / Stop
+ if (data)
+ {
+ uint32_t pptr = get_seq_offs(m_sequences[sq].sequence);
+ m_sequences[sq].data = &m_rom[pptr];
+ m_sequences[sq].delay = 0;
+ m_sequences[sq].is_playing = true;
+ }
+ else
+ {
+ m_sequences[sq].is_playing = false;
+ }
+ break;
+ case 0x78: // Pause / Resume
+ if (data) logerror("SEQ pause/resume unimplemented %02X %02X\n", reg, data);
+ break;
+ case 0x80: // Loop count, 0 = off, 255 - infinite
+ m_sequences[sq].loop = data;
+ break;
+ case 0x88: // timer H and L
+ case 0x90:
+ sq = (reg >> 1) & 7;
+ if (sq & 1)
+ m_sequences[sq].timer = (m_sequences[sq].timer & 0xff00) | data;
+ else
+ m_sequences[sq].timer = (m_sequences[sq].timer & 0x00ff) | (data << 8);
+ break;
+ case 0x98: // Off trigger, bit4 = on/off, bits0-3 channel (end sequence when channel playback ends)
+ if (data) logerror("SEQ Off trigger unimplemented %02X %02X\n", reg, data);
+ break;
+ case 0xa0: // stop channel mask H and L, what it for ? stop chanels immediatelly or when sequence ends (so far assuming later) ?
+ case 0xa8:
+ sq = (reg >> 1) & 7;
+ if (sq & 1)
+ m_sequences[sq].stopchan = (m_sequences[sq].stopchan & 0xff00) | data;
+ else
+ m_sequences[sq].stopchan = (m_sequences[sq].stopchan & 0x00ff) | (data << 8);
+ break;
+ }
+ }
+ else
+ {
+ if (data) logerror("SQC unimplemented %02X %02X\n", reg, data);
+ }
}
// else bank1 - Equalizer control
}
@@ -529,3 +589,56 @@ void ymz774_device::internal_reg_write(uint8_t reg, uint8_t data)
}
}
}
+
+void ymz774_device::sequencer()
+{
+ for (int i = 0; i < 8; i++)
+ {
+ auto & sequence = m_sequences[i];
+ if (sequence.is_playing)
+ {
+ if (sequence.delay > 0)
+ {
+ --sequence.delay;
+ }
+ else
+ {
+ int reg = *sequence.data++;
+ uint8_t data = *sequence.data++;
+ switch (reg)
+ {
+ case 0xff: // end
+ for (int ch = 0; ch < 16; ch++) // check this
+ if (sequence.stopchan & (1 << ch))
+ m_channels[ch].is_playing = false;
+ if (sequence.loop)
+ {
+ if (sequence.loop != 255)
+ --sequence.loop;
+ uint32_t pptr = get_seq_offs(sequence.sequence);
+ sequence.data = &m_rom[pptr];
+ }
+ else
+ {
+ sequence.is_playing = false;
+ }
+ break;
+ case 0xfe: // timer delay
+ sequence.delay = sequence.timer * 32; // possible needed -1 or +(32-1)
+ break;
+ default:
+ if (m_bank == 0 && reg >= 0x60 && reg < 0xb0) // if we hit SEQ registers need to add this sequence offset
+ {
+ int sqn = i;
+ if (reg < 0x70 || (reg >= 0x88 && reg < 0x98) || reg >= 0xa0)
+ sqn = i * 2;
+ internal_reg_write(reg + sqn, data);
+ }
+ else
+ internal_reg_write(reg, data);
+ break;
+ }
+ }
+ }
+ }
+}
diff --git a/src/devices/sound/ymz770.h b/src/devices/sound/ymz770.h
index 03921759cf2..0393b5f706e 100644
--- a/src/devices/sound/ymz770.h
+++ b/src/devices/sound/ymz770.h
@@ -95,9 +95,11 @@ protected:
};
struct ymz_sequence
{
+ uint32_t delay;
uint16_t sequence;
- uint8_t control;
- uint8_t delay;
+ uint16_t timer;
+ uint16_t stopchan;
+ uint8_t loop;
uint8_t *data;
bool is_playing;
};
@@ -119,7 +121,7 @@ protected:
virtual void internal_reg_write(uint8_t reg, uint8_t data) override;
virtual uint32_t get_phrase_offs(int phrase) override { int ph = phrase * 4; return ((m_rom[ph] & 0x0f) << 24 | m_rom[ph + 1] << 16 | m_rom[ph + 2] << 8 | m_rom[ph + 3]) * 2; };
virtual uint32_t get_seq_offs(int sqn) override { int sq = sqn * 4 + 0x2000; return ((m_rom[sq] & 0x0f) << 24 | m_rom[sq + 1] << 16 | m_rom[sq + 2] << 8 | m_rom[sq + 3]) * 2; };
- virtual void sequencer() override {};
+ virtual void sequencer() override;
private:
int m_bank;
};