#ifndef YMFM_SSG_H
#define YMFM_SSG_H
#pragma once
#include "ymfm.h"
namespace ymfm
{
class ssg_override
{
public:
virtual ~ssg_override() = default;
virtual void ssg_reset() = 0;
virtual uint8_t ssg_read(uint32_t regnum) = 0;
virtual void ssg_write(uint32_t regnum, uint8_t data) = 0;
virtual void ssg_prescale_changed() = 0;
};
class ssg_registers
{
public:
static constexpr uint32_t OUTPUTS = 3;
static constexpr uint32_t CHANNELS = 3;
static constexpr uint32_t REGISTERS = 0x10;
static constexpr uint32_t ALL_CHANNELS = (1 << CHANNELS) - 1;
ssg_registers() { }
void reset();
void save_restore(ymfm_saved_state &state);
uint8_t read(uint32_t index) { return m_regdata[index]; }
void write(uint32_t index, uint8_t data) { m_regdata[index] = data; }
uint32_t noise_period() const { return bitfield(m_regdata[0x06], 0, 5); }
uint32_t io_b_out() const { return bitfield(m_regdata[0x07], 7); }
uint32_t io_a_out() const { return bitfield(m_regdata[0x07], 6); }
uint32_t envelope_period() const { return m_regdata[0x0b] | (m_regdata[0x0c] << 8); }
uint32_t envelope_continue() const { return bitfield(m_regdata[0x0d], 3); }
uint32_t envelope_attack() const { return bitfield(m_regdata[0x0d], 2); }
uint32_t envelope_alternate() const { return bitfield(m_regdata[0x0d], 1); }
uint32_t envelope_hold() const { return bitfield(m_regdata[0x0d], 0); }
uint32_t io_a_data() const { return m_regdata[0x0e]; }
uint32_t io_b_data() const { return m_regdata[0x0f]; }
uint32_t ch_noise_enable_n(uint32_t choffs) const { return bitfield(m_regdata[0x07], 3 + choffs); }
uint32_t ch_tone_enable_n(uint32_t choffs) const { return bitfield(m_regdata[0x07], 0 + choffs); }
uint32_t ch_tone_period(uint32_t choffs) const { return m_regdata[0x00 + 2 * choffs] | (bitfield(m_regdata[0x01 + 2 * choffs], 0, 4) << 8); }
uint32_t ch_envelope_enable(uint32_t choffs) const { return bitfield(m_regdata[0x08 + choffs], 4); }
uint32_t ch_amplitude(uint32_t choffs) const { return bitfield(m_regdata[0x08 + choffs], 0, 4); }
private:
uint8_t m_regdata[REGISTERS]; };
class ssg_engine
{
public:
static constexpr int OUTPUTS = ssg_registers::OUTPUTS;
static constexpr int CHANNELS = ssg_registers::CHANNELS;
static constexpr int CLOCK_DIVIDER = 8;
using output_data = ymfm_output<OUTPUTS>;
ssg_engine(ymfm_interface &intf);
void override(ssg_override &override) { m_override = &override; }
void reset();
void save_restore(ymfm_saved_state &state);
void clock();
void output(output_data &output);
uint8_t read(uint32_t regnum);
void write(uint32_t regnum, uint8_t data);
ymfm_interface &intf() { return m_intf; }
ssg_registers ®s() { return m_regs; }
bool overridden() const { return (m_override != nullptr); }
void prescale_changed() { if (m_override != nullptr) m_override->ssg_prescale_changed(); }
private:
ymfm_interface &m_intf; uint32_t m_tone_count[3]; uint32_t m_tone_state[3]; uint32_t m_envelope_count; uint32_t m_envelope_state; uint32_t m_noise_count; uint32_t m_noise_state; ssg_registers m_regs; ssg_override *m_override; };
}
#endif