diff options
Diffstat (limited to 'src/devices/sound/ay8910.h')
| -rw-r--r-- | src/devices/sound/ay8910.h | 160 |
1 files changed, 149 insertions, 11 deletions
diff --git a/src/devices/sound/ay8910.h b/src/devices/sound/ay8910.h index c1bbf718245..685e8d837e5 100644 --- a/src/devices/sound/ay8910.h +++ b/src/devices/sound/ay8910.h @@ -43,8 +43,9 @@ #define AY8910_RESISTOR_OUTPUT (0x08) /* - * This define specifies the initial state of YM2149 - * pin 26 (SEL pin). By default it is set to high, + * This define specifies the initial state of + * YM2149, YM3439, AY8930 pin 26 (SEL pin). + * By default it is set to high, * compatible with AY8910. */ /* TODO: make it controllable while it's running (used by any hw???) */ @@ -61,6 +62,14 @@ public: PSG_TYPE_YM }; + enum config_t + { + PSG_DEFAULT = 0x0, + PSG_PIN26_IS_CLKSEL = 0x1, + PSG_EXTENDED_ENVELOPE = 0x2, + PSG_HAS_EXPANDED_MODE = 0x4 + }; + // construction/destruction ay8910_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock); @@ -77,9 +86,13 @@ public: void address_w(u8 data); void data_w(u8 data); - /* /RES */ + // /RES void reset_w(u8 data = 0) { ay8910_reset_ym(); } + // /SEL + void set_pin26_low_w(u8 data = 0); + void set_pin26_high_w(u8 data = 0); + // use this when BC1 == A0; here, BC1=0 selects 'data' and BC1=1 selects 'latch address' void data_address_w(offs_t offset, u8 data) { ay8910_write_ym(~offset & 1, data); } // note that directly connecting BC1 to A0 puts data on 0 and address on 1 @@ -113,7 +126,7 @@ public: protected: ay8910_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, - u32 clock, psg_type_t psg_type, int streams, int ioports); + u32 clock, psg_type_t psg_type, int streams, int ioports, int config = PSG_DEFAULT); // device-level overrides virtual void device_start() override; @@ -132,6 +145,134 @@ protected: private: static constexpr unsigned NUM_CHANNELS = 3; + /* register id's */ + enum + { + AY_AFINE = 0x00, + AY_ACOARSE = 0x01, + AY_BFINE = 0x02, + AY_BCOARSE = 0x03, + AY_CFINE = 0x04, + AY_CCOARSE = 0x05, + AY_NOISEPER = 0x06, + AY_ENABLE = 0x07, + AY_AVOL = 0x08, + AY_BVOL = 0x09, + AY_CVOL = 0x0a, + AY_EAFINE = 0x0b, + AY_EACOARSE = 0x0c, + AY_EASHAPE = 0x0d, + AY_PORTA = 0x0e, + AY_PORTB = 0x0f, + AY_EBFINE = 0x10, + AY_EBCOARSE = 0x11, + AY_ECFINE = 0x12, + AY_ECCOARSE = 0x13, + AY_EBSHAPE = 0x14, + AY_ECSHAPE = 0x15, + AY_ADUTY = 0x16, + AY_BDUTY = 0x17, + AY_CDUTY = 0x18, + AY_NOISEAND = 0x19, + AY_NOISEOR = 0x1a, + AY_TEST = 0x1f + }; + + // structs + struct tone_t + { + u32 period; + u8 volume; + u8 duty; + s32 count; + u8 duty_cycle; + u8 output; + + void reset() + { + period = 0; + volume = 0; + duty = 0; + count = 0; + duty_cycle = 0; + output = 0; + } + + void set_period(u8 fine, u8 coarse) + { + period = fine | (coarse << 8); + } + + void set_volume(u8 val) + { + volume = val; + } + + void set_duty(u8 val) + { + duty = val; + } + }; + + struct envelope_t + { + u32 period; + s32 count; + s8 step; + u32 volume; + u8 hold, alternate, attack, holding; + + void reset() + { + period = 0; + count = 0; + step = 0; + volume = 0; + hold = 0; + alternate = 0; + attack = 0; + holding = 0; + } + + void set_period(u8 fine, u8 coarse) + { + period = fine | (coarse << 8); + } + + void set_shape(u8 shape, u8 mask) + { + attack = (shape & 0x04) ? mask : 0x00; + if ((shape & 0x08) == 0) + { + /* if Continue = 0, map the shape to the equivalent one which has Continue = 1 */ + hold = 1; + alternate = attack; + } + else + { + hold = shape & 0x01; + alternate = shape & 0x02; + } + step = mask; + holding = 0; + volume = (step ^ attack); + } + }; + + // inlines + inline bool tone_enable(int chan) { return BIT(m_regs[AY_ENABLE], chan); } + inline u8 tone_volume(tone_t *tone) { return tone->volume & (is_expnaded_mode() ? 0x1f : 0x0f); } + inline u8 tone_envelope(tone_t *tone) { return (tone->volume >> (is_expnaded_mode() ? 5 : 4)) & ((m_feature & PSG_EXTENDED_ENVELOPE) ? 3 : 1); } + inline u8 tone_duty(tone_t *tone) { return is_expnaded_mode() ? (tone->duty & 0x8 ? 0x8 : tone->duty) : 0x4; } + inline u8 get_envelope_chan(int chan) { return is_expnaded_mode() ? chan : 0; } + + inline bool noise_enable(int chan) { return BIT(m_regs[AY_ENABLE], 3 + chan); } + inline u8 noise_period() { return is_expnaded_mode() ? m_regs[AY_NOISEPER] & 0xff : (m_regs[AY_NOISEPER] & 0x1f) << 1; } + inline u8 noise_output() { return m_rng & 1; } + + inline bool is_expnaded_mode() { return ((m_feature & PSG_HAS_EXPANDED_MODE) && ((m_mode & 0xe) == 0xa)); } + inline u8 get_register_bank() { return is_expnaded_mode() ? (m_mode & 0x1) << 4 : 0; } + // internal helpers void set_type(psg_type_t psg_type); inline u16 mix_3D(); @@ -151,16 +292,12 @@ private: sound_stream *m_channel; bool m_active; s32 m_register_latch; - u8 m_regs[16]; + u8 m_regs[16 * 2]; s32 m_last_enable; - s32 m_count[NUM_CHANNELS]; - u8 m_output[NUM_CHANNELS]; + tone_t m_tone[NUM_CHANNELS]; + envelope_t m_envelope[NUM_CHANNELS]; u8 m_prescale_noise; s32 m_count_noise; - s32 m_count_env; - s8 m_env_step; - u32 m_env_volume; - u8 m_hold,m_alternate,m_attack,m_holding; s32 m_rng; u8 m_mode; u8 m_env_step_mask; @@ -174,6 +311,7 @@ private: s32 m_env_table[NUM_CHANNELS][32]; std::unique_ptr<s32[]> m_vol3d_table; int m_flags; /* Flags */ + int m_feature; /* Chip specific features */ int m_res_load[3]; /* Load on channel in ohms */ devcb_read8 m_port_a_read_cb; devcb_read8 m_port_b_read_cb; |
