// license:BSD-3-Clause
// copyright-holders:Barry Rodewald
/*
* Gravis Ultrasound ISA card
*
* Started: 28/01/2012
*
* I/O port map (info from the Gravis Ultrasound SDK documentation):
* Base port is 0x2X0 - where X is defined by a jumper
*
* MIDI:
* 0x3X0 - MIDI Control (read), MIDI Status (write)
* 0x3X1 - MIDI Transmit (write), MIDI Receive (read)
* MIDI operates identically to a 6850 UART
*
* Joystick:
* 0x201 - Joystick trigger timer (write), Joystick data (read)
*
* GF1 Synthesiser:
* 0x3X2 - Page register (voice select)
* 0x3X3 - Global Register select
* 0x3X4 - Global Data (low byte)
* 0x3X5 - Global Data (high byte)
* 0x2X6 - IRQ status register (read only, active high)
* 0x2X8 - Timer control register
* 0x2X9 - Timer data
* 0x3X7 - DRAM data (can be via DMA also)
*
* Board:
* 0x2X0: Mix control register (write only)
* 0x2XB: IRQ/DMA control register (write only) - dependant on mix control bit 6
* 0x2XF: Register controls (board rev 3.4+ only)
* 0x7X6: Board version (read only, board rev 3.7+ only)
*
* Mixer Control:
* 0x7X6: Control port (write only)
* 0x3X6: Data port (write only)
*/
#ifndef MAME_BUS_ISA_GUS_H
#define MAME_BUS_ISA_GUS_H
#pragma once
#include "isa.h"
#include "machine/6850acia.h"
//**************************************************************************
// TYPE DEFINITIONS
//**************************************************************************
// ======================> gf1_device
#define GF1_CLOCK 9878400
class gf1_device :
public acia6850_device,
public device_sound_interface
{
public:
struct gus_voice
{
uint8_t voice_ctrl;
uint16_t freq_ctrl;
uint32_t start_addr;
uint32_t end_addr;
uint8_t vol_ramp_rate;
uint8_t vol_ramp_start;
uint8_t vol_ramp_end;
uint16_t current_vol;
uint32_t current_addr;
uint8_t pan_position;
uint8_t vol_ramp_ctrl;
uint32_t vol_count;
bool rollover;
int16_t sample; // current sample data
};
// construction/destruction
gf1_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
auto txirq_handler() { return m_txirq_handler.bind(); }
auto rxirq_handler() { return m_rxirq_handler.bind(); }
auto wave_irq_handler() { return m_wave_irq_handler.bind(); }
auto ramp_irq_handler() { return m_ramp_irq_handler.bind(); }
auto timer1_irq_handler() { return m_timer1_irq_handler.bind(); }
auto timer2_irq_handler() { return m_timer2_irq_handler.bind(); }
auto sb_irq_handler() { return m_sb_irq_handler.bind(); }
auto dma_irq_handler() { return m_dma_irq_handler.bind(); }
auto drq1_handler() { return m_drq1_handler.bind(); }
auto drq2_handler() { return m_drq2_handler.bind(); }
auto nmi_handler() { return m_nmi_handler.bind(); }
// current IRQ/DMA channel getters
uint8_t gf1_irq() { if(m_gf1_irq != 0) return m_gf1_irq; else return m_midi_irq; } // workaround for win95 loading dumb values
uint8_t midi_irq() { if(m_irq_combine == 0) return m_midi_irq; else return m_gf1_irq; }
uint8_t dma_channel1() { return m_dma_channel1; }
uint8_t dma_channel2() { if(m_dma_combine == 0) return m_dma_channel2; else return m_dma_channel1; }
uint8_t global_reg_select_r(offs_t offset);
void global_reg_select_w(offs_t offset, uint8_t data);
uint8_t global_reg_data_r(offs_t offset);
void global_reg_data_w(offs_t offset, uint8_t data);
uint8_t dram_r(offs_t offset);
void dram_w(offs_t offset, uint8_t data);
uint8_t adlib_r(offs_t offset);
void adlib_w(offs_t offset, uint8_t data);
uint8_t adlib_cmd_r(offs_t offset);
void adlib_cmd_w(offs_t offset, uint8_t data);
uint8_t mix_ctrl_r(offs_t offset);
void mix_ctrl_w(offs_t offset, uint8_t data);
uint8_t stat_r();
void stat_w(uint8_t data);
uint8_t sb_r(offs_t offset);
void sb_w(offs_t offset, uint8_t data);
void sb2x6_w(uint8_t data);
// DMA signals
uint8_t dack_r(int line);
void dack_w(int line,uint8_t data);
void eop_w(int state);
// optional information overrides
virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
virtual void sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples) override;
protected:
// voice-specific registers
gus_voice m_voice[32];
// global registers (not voice-specific)
uint8_t m_dma_dram_ctrl;
uint16_t m_dma_start_addr;
uint32_t m_dram_addr;
uint8_t m_timer_ctrl;
uint8_t m_timer1_count;
uint8_t m_timer2_count;
uint8_t m_timer1_value;
uint8_t m_timer2_value;
uint16_t m_sampling_freq;
uint8_t m_sampling_ctrl;
uint8_t m_joy_trim_dac;
uint8_t m_reset;
uint8_t m_active_voices;
uint8_t m_irq_source;
void set_irq(uint8_t source, uint8_t voice);
void reset_irq(uint8_t source);
void update_volume_ramps();
std::vector<uint8_t> m_wave_ram;
// device-level overrides
virtual void device_start() override;
virtual void device_reset() override;
virtual void device_stop() override;
virtual void device_clock_changed() override;
virtual void update_irq() override;
private:
// internal state
sound_stream* m_stream;
emu_timer* m_timer1;
emu_timer* m_timer2;
emu_timer* m_dmatimer;
emu_timer* m_voltimer;
uint8_t m_current_voice;
uint8_t m_current_reg;
//uint8_t m_port;
//uint8_t m_irq;
//uint8_t m_dma;
uint8_t m_adlib_cmd;
uint8_t m_mix_ctrl;
uint8_t m_gf1_irq;
uint8_t m_midi_irq;
uint8_t m_dma_channel1;
uint8_t m_dma_channel2;
uint8_t m_irq_combine;
uint8_t m_dma_combine;
uint8_t m_adlib_timer_cmd;
uint8_t m_adlib_timer1_enable;
uint8_t m_adlib_timer2_enable;
uint8_t m_adlib_status;
uint8_t m_adlib_data;
uint8_t m_voice_irq_fifo[32];
uint8_t m_voice_irq_ptr;
uint8_t m_voice_irq_current;
uint8_t m_dma_16bit; // set by bit 6 of the DMA DRAM control reg
uint8_t m_statread;
uint8_t m_sb_data_2xc;
uint8_t m_sb_data_2xe;
uint8_t m_reg_ctrl;
uint8_t m_fake_adlib_status;
uint32_t m_dma_current;
uint16_t m_volume_table[4096];
static const device_timer_id ADLIB_TIMER1 = 0;
static const device_timer_id ADLIB_TIMER2 = 1;
static const device_timer_id DMA_TIMER = 2;
static const device_timer_id VOL_RAMP_TIMER = 3;
int m_txirq;
int m_rxirq;
devcb_write_line m_txirq_handler;
devcb_write_line m_rxirq_handler;
devcb_write_line m_wave_irq_handler;
devcb_write_line m_ramp_irq_handler;
devcb_write_line m_timer1_irq_handler;
devcb_write_line m_timer2_irq_handler;
devcb_write_line m_sb_irq_handler;
devcb_write_line m_dma_irq_handler;
devcb_write_line m_drq1_handler;
devcb_write_line m_drq2_handler;
devcb_write_line m_nmi_handler;
};
class isa16_gus_device :
public device_t,
public device_isa16_card_interface
{
public:
isa16_gus_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
void set_irq(uint8_t source);
void reset_irq(uint8_t source);
void set_midi_irq(uint8_t source);
void reset_midi_irq(uint8_t source);
uint8_t board_r(offs_t offset);
uint8_t synth_r(offs_t offset);
void board_w(offs_t offset, uint8_t data);
void synth_w(offs_t offset, uint8_t data);
uint8_t adlib_r(offs_t offset);
void adlib_w(offs_t offset, uint8_t data);
uint8_t joy_r(offs_t offset);
void joy_w(offs_t offset, uint8_t data);
// DMA overrides
virtual uint8_t dack_r(int line) override;
virtual void dack_w(int line,uint8_t data) override;
virtual void eop_w(int state) override;
protected:
// device-level overrides
virtual void device_start() override;
virtual void device_reset() override;
virtual void device_stop() override;
// optional information overrides
virtual void device_add_mconfig(machine_config &config) override;
virtual ioport_constructor device_input_ports() const override;
private:
DECLARE_WRITE_LINE_MEMBER(midi_txirq);
DECLARE_WRITE_LINE_MEMBER(midi_rxirq);
DECLARE_WRITE_LINE_MEMBER(wavetable_irq);
DECLARE_WRITE_LINE_MEMBER(volumeramp_irq);
DECLARE_WRITE_LINE_MEMBER(timer1_irq);
DECLARE_WRITE_LINE_MEMBER(timer2_irq);
DECLARE_WRITE_LINE_MEMBER(sb_irq);
DECLARE_WRITE_LINE_MEMBER(dma_irq);
DECLARE_WRITE_LINE_MEMBER(drq1_w);
DECLARE_WRITE_LINE_MEMBER(drq2_w);
DECLARE_WRITE_LINE_MEMBER(nmi_w);
DECLARE_WRITE_LINE_MEMBER(write_acia_clock);
required_device<gf1_device> m_gf1;
uint8_t m_irq_status;
attotime m_joy_time;
};
// device type definition
DECLARE_DEVICE_TYPE(GF1, gf1_device)
DECLARE_DEVICE_TYPE(ISA16_GUS, isa16_gus_device)
#endif // MAME_BUS_ISA_GUS_H