diff options
Diffstat (limited to 'trunk/src/mame/audio/tiamc1.c')
-rw-r--r-- | trunk/src/mame/audio/tiamc1.c | 351 |
1 files changed, 351 insertions, 0 deletions
diff --git a/trunk/src/mame/audio/tiamc1.c b/trunk/src/mame/audio/tiamc1.c new file mode 100644 index 00000000000..7dac127017b --- /dev/null +++ b/trunk/src/mame/audio/tiamc1.c @@ -0,0 +1,351 @@ +/*************************************************************************** + + TIA-MC1 sound hardware + + driver by Eugene Sandulenko + special thanks to Shiru for his standalone emulator and documentation + + timer1 timer0 + |--------| |--------| + | 8253 | | 8253 | |---| + in0 | | | | | 1 | |---| + ----+ g0 o0 +---+ g0 o0 +---+ | | & | + in1 | | | | | o---+ | out + ----+ g1 o1 +---+ g1 o1 +---+ | | +----- + in2 | | | | |---| | | + ----+ g2 o2 +---+ g2 o2 +-----------+ | + clk1| | | | |---| + ----+ clk | +-+ clk | + | | | | | + |--------| | |--------| + clk0 | + ---------------+ + + in0-in2 comes from port #da + clk0 comes from 8224 and equals to 1777777Hz, i.e. processor clock + clk1 comes from divider 16000000/4/16/16/2 = 7812Hz + + ******************** + + TODO: use machine/pit8253.c + +***************************************************************************/ + +#include "emu.h" +#include "includes/tiamc1.h" + +#define CLOCK_DIVIDER 16 +#define BUF_LEN 100000 + +struct timer8253chan { + UINT16 count; + UINT16 cnval; + UINT8 bcdMode; + UINT8 cntMode; + UINT8 valMode; + UINT8 gate; + UINT8 output; + UINT8 loadCnt; + UINT8 enable; +}; + +struct timer8253struct { + struct timer8253chan channel[3]; +}; + +typedef struct _tiamc1_sound_state tiamc1_sound_state; +struct _tiamc1_sound_state +{ + sound_stream *m_channel; + int m_timer1_divider; + + struct timer8253struct m_timer0; + struct timer8253struct m_timer1; +}; + + +#define T8253_CHAN0 0 +#define T8253_CHAN1 1 +#define T8253_CHAN2 2 +#define T8253_CWORD 3 + + +INLINE tiamc1_sound_state *get_safe_token(device_t *device) +{ + assert(device != NULL); + assert(device->type() == TIAMC1); + + return (tiamc1_sound_state *)downcast<legacy_device_base *>(device)->token(); +} + + +static void timer8253_reset(struct timer8253struct *t) { + memset(t,0,sizeof(struct timer8253struct)); +} + + +static void timer8253_tick(struct timer8253struct *t,int chn) { + if (t->channel[chn].enable && t->channel[chn].gate) { + switch (t->channel[chn].cntMode) { + case 0: + t->channel[chn].count--; + if (t->channel[chn].count == 0xffff) + t->channel[chn].output = 1; + break; + + case 3: + t->channel[chn].count--; + + if (t->channel[chn].count < (t->channel[chn].cnval >> 1)) + t->channel[chn].output = 0; + else + t->channel[chn].output = 1; + + if (t->channel[chn].count == 0xffff) + t->channel[chn].count = t->channel[chn].cnval; + break; + + case 4: + t->channel[chn].count--; + if(t->channel[chn].count==0) + t->channel[chn].output = 1; + + if(t->channel[chn].count == 0xffff) { + t->channel[chn].enable = 0; + t->channel[chn].output = 1; + } + break; + } + } +} + + + +static void timer8253_wr(struct timer8253struct *t, int reg, UINT8 val) +{ + int chn; + + switch (reg) { + case T8253_CWORD: + chn = val >> 6; + if (chn < 3) { + t->channel[chn].bcdMode = (val & 1) ? 1 : 0; + t->channel[chn].cntMode = (val >> 1) & 0x07; + t->channel[chn].valMode = (val >> 4) & 0x03; + + switch (t->channel[chn].valMode) { + case 1: + case 2: + t->channel[chn].loadCnt = 1; + break; + + case 3: + t->channel[chn].loadCnt = 2; + break; + + default: + mame_printf_debug("unhandled val mode %i\n", t->channel[chn].valMode); + } + + switch (t->channel[chn].cntMode) { + case 0: + t->channel[chn].output = 0; + t->channel[chn].enable = 0; + break; + + case 3: + t->channel[chn].output = 1; + break; + + case 4: + t->channel[chn].output = 1; + t->channel[chn].enable = 0; + break; + + default: + mame_printf_debug("unhandled cnt mode %i\n", t->channel[chn].cntMode); + } + } + break; + + default: + chn = reg; + + switch (t->channel[chn].valMode) { + case 1: + t->channel[chn].cnval = (t->channel[chn].cnval & 0xff00) | val; + break; + case 2: + t->channel[chn].cnval = (t->channel[chn].cnval & 0x00ff) | (val << 8); + break; + case 3: + t->channel[chn].cnval = (t->channel[chn].cnval >> 8) | (val << 8); + break; + default: + mame_printf_debug("unhandled val mode %i\n", t->channel[chn].valMode); + } + + if (t->channel[chn].cntMode==0) { + t->channel[chn].enable = 0; + } + + t->channel[chn].loadCnt--; + + if (t->channel[chn].loadCnt == 0) { + switch (t->channel[chn].valMode) { + case 1: + case 2: + t->channel[chn].loadCnt = 1; + break; + + case 3: + t->channel[chn].loadCnt = 2; + break; + + default: + mame_printf_debug("unhandled val mode %i\n", t->channel[chn].valMode); + } + + switch (t->channel[chn].cntMode) { + case 3: + t->channel[chn].count = t->channel[chn].cnval; + t->channel[chn].enable = 1; + break; + + case 0: + case 4: + t->channel[chn].count = t->channel[chn].cnval; + t->channel[chn].enable = 1; + break; + + default: + mame_printf_debug("unhandled cnt mode %i\n", t->channel[chn].cntMode); + } + } + } +} + +static void timer8253_set_gate(struct timer8253struct *t, int chn, UINT8 gate) +{ + t->channel[chn].gate = gate; +} + + + +static char timer8253_get_output(struct timer8253struct *t, int chn) +{ + return t->channel[chn].output; +} + + + +WRITE8_DEVICE_HANDLER( tiamc1_timer0_w ) +{ + tiamc1_sound_state *state = get_safe_token(device); + timer8253_wr(&state->m_timer0, offset, data); +} + +WRITE8_DEVICE_HANDLER( tiamc1_timer1_w ) +{ + tiamc1_sound_state *state = get_safe_token(device); + timer8253_wr(&state->m_timer1, offset, data); +} + +WRITE8_DEVICE_HANDLER( tiamc1_timer1_gate_w ) +{ + tiamc1_sound_state *state = get_safe_token(device); + timer8253_set_gate(&state->m_timer1, 0, (data & 1) ? 1 : 0); + timer8253_set_gate(&state->m_timer1, 1, (data & 2) ? 1 : 0); + timer8253_set_gate(&state->m_timer1, 2, (data & 4) ? 1 : 0); +} + + +static STREAM_UPDATE( tiamc1_sound_update ) +{ + tiamc1_sound_state *state = get_safe_token(device); + int count, o0, o1, o2, len, orval = 0; + + len = samples * CLOCK_DIVIDER; + + for (count = 0; count < len; count++) { + state->m_timer1_divider++; + if (state->m_timer1_divider == 228) { + state->m_timer1_divider = 0; + timer8253_tick(&state->m_timer1, 0); + timer8253_tick(&state->m_timer1, 1); + timer8253_tick(&state->m_timer1, 2); + + timer8253_set_gate(&state->m_timer0, 0, timer8253_get_output(&state->m_timer1, 0)); + timer8253_set_gate(&state->m_timer0, 1, timer8253_get_output(&state->m_timer1, 1)); + timer8253_set_gate(&state->m_timer0, 2, timer8253_get_output(&state->m_timer1, 2)); + } + + timer8253_tick(&state->m_timer0, 0); + timer8253_tick(&state->m_timer0, 1); + timer8253_tick(&state->m_timer0, 2); + + o0 = timer8253_get_output(&state->m_timer0, 0) ? 1 : 0; + o1 = timer8253_get_output(&state->m_timer0, 1) ? 1 : 0; + o2 = timer8253_get_output(&state->m_timer0, 2) ? 1 : 0; + + orval = (orval << 1) | (((o0 | o1) ^ 0xff) & o2); + + if ((count + 1) % CLOCK_DIVIDER == 0) { + outputs[0][count / CLOCK_DIVIDER] = orval ? 0x2828 : 0; + orval = 0; + } + } +} + +static DEVICE_START( tiamc1_sound ) +{ + tiamc1_sound_state *state = get_safe_token(device); + running_machine &machine = device->machine(); + int i, j; + + timer8253_reset(&state->m_timer0); + timer8253_reset(&state->m_timer1); + + state->m_channel = device->machine().sound().stream_alloc(*device, 0, 1, device->clock() / CLOCK_DIVIDER, 0, tiamc1_sound_update); + + state->m_timer1_divider = 0; + + for (i = 0; i < 2; i++) { + struct timer8253struct *t = (i ? &state->m_timer1 : &state->m_timer0); + + for (j = 0; j < 3; j++) { + state_save_register_item(machine, "channel", NULL, i * 3 + j, t->channel[j].count); + state_save_register_item(machine, "channel", NULL, i * 3 + j, t->channel[j].cnval); + state_save_register_item(machine, "channel", NULL, i * 3 + j, t->channel[j].bcdMode); + state_save_register_item(machine, "channel", NULL, i * 3 + j, t->channel[j].cntMode); + state_save_register_item(machine, "channel", NULL, i * 3 + j, t->channel[j].valMode); + state_save_register_item(machine, "channel", NULL, i * 3 + j, t->channel[j].gate); + state_save_register_item(machine, "channel", NULL, i * 3 + j, t->channel[j].output); + state_save_register_item(machine, "channel", NULL, i * 3 + j, t->channel[j].loadCnt); + state_save_register_item(machine, "channel", NULL, i * 3 + j, t->channel[j].enable); + } + } + + device->save_item(NAME(state->m_timer1_divider)); +} + + +DEVICE_GET_INFO( tiamc1_sound ) +{ + switch (state) + { + /* --- the following bits of info are returned as 64-bit signed integers --- */ + case DEVINFO_INT_TOKEN_BYTES: info->i = sizeof(tiamc1_sound_state); break; + + /* --- the following bits of info are returned as pointers to data or functions --- */ + case DEVINFO_FCT_START: info->start = DEVICE_START_NAME(tiamc1_sound); break; + + /* --- the following bits of info are returned as NULL-terminated strings --- */ + case DEVINFO_STR_NAME: strcpy(info->s, "TIA-MC1 Custom"); break; + case DEVINFO_STR_SOURCE_FILE: strcpy(info->s, __FILE__); break; + } +} + + + +DEFINE_LEGACY_SOUND_DEVICE(TIAMC1, tiamc1_sound); |