summaryrefslogtreecommitdiffstatshomepage
path: root/src/mame/audio/jaguar.c
blob: 0c405cd908a11caa93ce237e87af89daf79d6c02 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
/***************************************************************************

    Atari Jaguar hardware

****************************************************************************

    ------------------------------------------------------------
    JERRY REGISTERS
    ------------------------------------------------------------
    F10000-F13FFF   R/W   xxxxxxxx xxxxxxxx   Jerry
    F10000            W   xxxxxxxx xxxxxxxx   JPIT1 - timer 1 pre-scaler
    F10004            W   xxxxxxxx xxxxxxxx   JPIT2 - timer 1 divider
    F10008            W   xxxxxxxx xxxxxxxx   JPIT3 - timer 2 pre-scaler
    F1000C            W   xxxxxxxx xxxxxxxx   JPIT4 - timer 2 divider
    F10010            W   ------xx xxxxxxxx   CLK1 - processor clock divider
    F10012            W   ------xx xxxxxxxx   CLK2 - video clock divider
    F10014            W   -------- --xxxxxx   CLK3 - chroma clock divider
    F10020          R/W   ---xxxxx ---xxxxx   JINTCTRL - interrupt control register
                      W   ---x---- --------      (J_SYNCLR - clear synchronous serial intf ints)
                      W   ----x--- --------      (J_ASYNCLR - clear asynchronous serial intf ints)
                      W   -----x-- --------      (J_TIM2CLR - clear timer 2 [tempo] interrupts)
                      W   ------x- --------      (J_TIM1CLR - clear timer 1 [sample] interrupts)
                      W   -------x --------      (J_EXTCLR - clear external interrupts)
                    R/W   -------- ---x----      (J_SYNENA - enable synchronous serial intf ints)
                    R/W   -------- ----x---      (J_ASYNENA - enable asynchronous serial intf ints)
                    R/W   -------- -----x--      (J_TIM2ENA - enable timer 2 [tempo] interrupts)
                    R/W   -------- ------x-      (J_TIM1ENA - enable timer 1 [sample] interrupts)
                    R/W   -------- -------x      (J_EXTENA - enable external interrupts)
    F10030          R/W   -------- xxxxxxxx   ASIDATA - asynchronous serial data
    F10032            W   -x------ -xxxxxxx   ASICTRL - asynchronous serial control
                      W   -x------ --------      (TXBRK - transmit break)
                      W   -------- -x------      (CLRERR - clear error)
                      W   -------- --x-----      (RINTEN - enable receiver interrupts)
                      W   -------- ---x----      (TINTEN - enable transmitter interrupts)
                      W   -------- ----x---      (RXIPOL - receiver input polarity)
                      W   -------- -----x--      (TXOPOL - transmitter output polarity)
                      W   -------- ------x-      (PAREN - parity enable)
                      W   -------- -------x      (ODD - odd parity select)
    F10032          R     xxx-xxxx x-xxxxxx   ASISTAT - asynchronous serial status
                    R     x------- --------      (ERROR - OR of PE,FE,OE)
                    R     -x------ --------      (TXBRK - transmit break)
                    R     --x----- --------      (SERIN - serial input)
                    R     ----x--- --------      (OE - overrun error)
                    R     -----x-- --------      (FE - framing error)
                    R     ------x- --------      (PE - parity error)
                    R     -------x --------      (TBE - transmit buffer empty)
                    R     -------- x-------      (RBF - receive buffer full)
                    R     -------- ---x----      (TINTEN - enable transmitter interrupts)
                    R     -------- ----x---      (RXIPOL - receiver input polarity)
                    R     -------- -----x--      (TXOPOL - transmitter output polarity)
                    R     -------- ------x-      (PAREN - parity enable)
                    R     -------- -------x      (ODD - odd parity)
    F10034          R/W   xxxxxxxx xxxxxxxx   ASICLK - asynchronous serial interface clock
    ------------------------------------------------------------
    F14000-F17FFF   R/W   xxxxxxxx xxxxxxxx   Joysticks and GPIO0-5
    F14000          R     xxxxxxxx xxxxxxxx   JOYSTICK - read joystick state
    F14000            W   x------- xxxxxxxx   JOYSTICK - latch joystick output
                      W   x------- --------      (enable joystick outputs)
                      W   -------- xxxxxxxx      (joystick output data)
    F14002          R     xxxxxxxx xxxxxxxx   JOYBUTS - button register
    F14800-F14FFF   R/W   xxxxxxxx xxxxxxxx   GPI00 - reserved
    F15000-F15FFF   R/W   xxxxxxxx xxxxxxxx   GPI01 - reserved
    F16000-F16FFF   R/W   xxxxxxxx xxxxxxxx   GPI02 - reserved
    F17000-F177FF   R/W   xxxxxxxx xxxxxxxx   GPI03 - reserved
    F17800-F17BFF   R/W   xxxxxxxx xxxxxxxx   GPI04 - reserved
    F17C00-F17FFF   R/W   xxxxxxxx xxxxxxxx   GPI05 - reserved
    ------------------------------------------------------------
    F18000-F1FFFF   R/W   xxxxxxxx xxxxxxxx   Jerry DSP
    F1A100          R/W   xxxxxxxx xxxxxxxx   D_FLAGS - DSP flags register
                    R/W   x------- --------      (DMAEN - DMA enable)
                    R/W   -x------ --------      (REGPAGE - register page)
                      W   --x----- --------      (D_EXT0CLR - clear external interrupt 0)
                      W   ---x---- --------      (D_TIM2CLR - clear timer 2 interrupt)
                      W   ----x--- --------      (D_TIM1CLR - clear timer 1 interrupt)
                      W   -----x-- --------      (D_I2SCLR - clear I2S interrupt)
                      W   ------x- --------      (D_CPUCLR - clear CPU interrupt)
                    R/W   -------x --------      (D_EXT0ENA - enable external interrupt 0)
                    R/W   -------- x-------      (D_TIM2ENA - enable timer 2 interrupt)
                    R/W   -------- -x------      (D_TIM1ENA - enable timer 1 interrupt)
                    R/W   -------- --x-----      (D_I2SENA - enable I2S interrupt)
                    R/W   -------- ---x----      (D_CPUENA - enable CPU interrupt)
                    R/W   -------- ----x---      (IMASK - interrupt mask)
                    R/W   -------- -----x--      (NEGA_FLAG - ALU negative)
                    R/W   -------- ------x-      (CARRY_FLAG - ALU carry)
                    R/W   -------- -------x      (ZERO_FLAG - ALU zero)
    F1A102          R/W   -------- ------xx   D_FLAGS - upper DSP flags
                    R/W   -------- ------x-      (D_EXT1ENA - enable external interrupt 1)
                    R/W   -------- -------x      (D_EXT1CLR - clear external interrupt 1)
    F1A104            W   -------- ----xxxx   D_MTXC - matrix control register
                      W   -------- ----x---      (MATCOL - column/row major)
                      W   -------- -----xxx      (MATRIX3-15 - matrix width)
    F1A108            W   ----xxxx xxxxxx--   D_MTXA - matrix address register
    F1A10C            W   -------- -----x-x   D_END - data organization register
                      W   -------- -----x--      (BIG_INST - big endian instruction fetch)
                      W   -------- -------x      (BIG_IO - big endian I/O)
    F1A110          R/W   xxxxxxxx xxxxxxxx   D_PC - DSP program counter
    F1A114          R/W   xxxxxxxx xx-xxxxx   D_CTRL - DSP control/status register
                    R     xxxx---- --------      (VERSION - DSP version code)
                    R/W   ----x--- --------      (BUS_HOG - hog the bus!)
                    R/W   -----x-- --------      (D_EXT0LAT - external interrupt 0 latch)
                    R/W   ------x- --------      (D_TIM2LAT - timer 2 interrupt latch)
                    R/W   -------x --------      (D_TIM1LAT - timer 1 interrupt latch)
                    R/W   -------- x-------      (D_I2SLAT - I2S interrupt latch)
                    R/W   -------- -x------      (D_CPULAT - CPU interrupt latch)
                    R/W   -------- ---x----      (SINGLE_GO - single step one instruction)
                    R/W   -------- ----x---      (SINGLE_STEP - single step mode)
                    R/W   -------- -----x--      (FORCEINT0 - cause interrupt 0 on GPU)
                    R/W   -------- ------x-      (CPUINT - send GPU interrupt to CPU)
                    R/W   -------- -------x      (DSPGO - enable DSP execution)
    F1A116          R/W   -------- -------x   D_CTRL - upper DSP control/status register
                    R/W   -------- -------x      (D_EXT1LAT - external interrupt 1 latch)
    F1A118-F1A11B     W   xxxxxxxx xxxxxxxx   D_MOD - modulo instruction mask
    F1A11C-F1A11F   R     xxxxxxxx xxxxxxxx   D_REMAIN - divide unit remainder
    F1A11C            W   -------- -------x   D_DIVCTRL - divide unit control
                      W   -------- -------x      (DIV_OFFSET - 1=16.16 divide, 0=32-bit divide)
    F1A120-F1A123   R     xxxxxxxx xxxxxxxx   D_MACHI - multiply & accumulate high bits
    F1A148            W   xxxxxxxx xxxxxxxx   R_DAC - right transmit data
    F1A14C            W   xxxxxxxx xxxxxxxx   L_DAC - left transmit data
    F1A150            W   -------- xxxxxxxx   SCLK - serial clock frequency
    F1A150          R     -------- ------xx   SSTAT
                    R     -------- ------x-      (left - no description)
                    R     -------- -------x      (WS - word strobe status)
    F1A154            W   -------- --xxxx-x   SMODE - serial mode
                      W   -------- --x-----      (EVERYWORD - interrupt on MSB of every word)
                      W   -------- ---x----      (FALLING - interrupt on falling edge)
                      W   -------- ----x---      (RISING - interrupt of rising edge)
                      W   -------- -----x--      (WSEN - enable word strobes)
                      W   -------- -------x      (INTERNAL - enables serial clock)
    ------------------------------------------------------------
    F1B000-F1CFFF   R/W   xxxxxxxx xxxxxxxx   Local DSP RAM
    ------------------------------------------------------------
    F1D000          R     xxxxxxxx xxxxxxxx   ROM_TRI - triangle wave
    F1D200          R     xxxxxxxx xxxxxxxx   ROM_SINE - full sine wave
    F1D400          R     xxxxxxxx xxxxxxxx   ROM_AMSINE - amplitude modulated sine wave
    F1D600          R     xxxxxxxx xxxxxxxx   ROM_12W - sine wave and second order harmonic
    F1D800          R     xxxxxxxx xxxxxxxx   ROM_CHIRP16 - chirp
    F1DA00          R     xxxxxxxx xxxxxxxx   ROM_NTRI - triangle wave with noise
    F1DC00          R     xxxxxxxx xxxxxxxx   ROM_DELTA - spike
    F1DE00          R     xxxxxxxx xxxxxxxx   ROM_NOISE - white noise
    ------------------------------------------------------------
    F20000-FFFFFF   R     xxxxxxxx xxxxxxxx   Bootstrap ROM

****************************************************************************/

#include "emu.h"
#include "includes/jaguar.h"
#include "cpu/jaguar/jaguar.h"


/* Jerry registers */
enum
{
	JPIT1,		DSP0,		JPIT2,		DSP1,
	JPIT3,		DSP2,		JPIT4,		DSP3,
	CLK1,		CLK2,		CLK3,
	JINTCTRL = 0x20/2,
	ASIDATA = 0x30/2,	ASICTRL,	ASICLK,
	DSP_REGS
};



/*************************************
 *
 *  Jerry -> GPU interrupts
 *
 *************************************/

void jaguar_state::update_gpu_irq()
{
	if (m_gpu_irq_state & m_dsp_regs[JINTCTRL] & 0x1f)
	{
		m_gpu->set_input_line(1, ASSERT_LINE);
		gpu_resume();
	}
	else
		m_gpu->set_input_line(1, CLEAR_LINE);
}


void jaguar_state::external_int(device_t *device, int newstate)
{
	jaguar_state &state = *device->machine().driver_data<jaguar_state>();
	if (newstate != CLEAR_LINE)
		state.m_gpu_irq_state |= 1;
	else
		state.m_gpu_irq_state &= ~1;
	state.update_gpu_irq();
}



/*************************************
 *
 *  Sound initialization
 *
 *************************************/

void jaguar_state::sound_start()
{
	m_serial_timer = timer_alloc(TID_SERIAL);

#if ENABLE_SPEEDUP_HACKS
	if (m_hacks_enabled)
		m_dsp->space(AS_PROGRAM)->install_write_handler(0xf1a100, 0xf1a103, write32_delegate(FUNC(jaguar_state::dsp_flags_w), this));
#endif
}



/*************************************
 *
 *  Jerry 16-bit register access
 *
 *************************************/

READ16_MEMBER( jaguar_state::jerry_regs_r )
{
	if (offset != JINTCTRL && offset != JINTCTRL+2)
		logerror("%08X:jerry read register @ F10%03X\n", space.device().safe_pcbase(), offset * 2);

	switch (offset)
	{
		case JINTCTRL:
			return m_gpu_irq_state;
		case ASICTRL:
			return (m_dsp_regs[offset] & 0xfeff) | 0x100; // assume fifo empty
	}

	return m_dsp_regs[offset];
}


WRITE16_MEMBER( jaguar_state::jerry_regs_w )
{
	COMBINE_DATA(&m_dsp_regs[offset]);

	switch (offset)
	{
		case JINTCTRL:
			m_gpu_irq_state &= ~(m_dsp_regs[JINTCTRL] >> 8);
			update_gpu_irq();
			break;
	}

	if (offset != JINTCTRL && offset != JINTCTRL+2 && offset != ASICTRL)
		logerror("%08X:jerry write register @ F10%03X = %04X\n", space.device().safe_pcbase(), offset * 2, data);
}



/*************************************
 *
 *  Speedier sound hack
 *
 *************************************/

#if ENABLE_SPEEDUP_HACKS

WRITE32_MEMBER( jaguar_state::dsp_flags_w )
{
	/* write the data through */
	jaguardsp_ctrl_w(m_dsp, offset, data, mem_mask);

	/* if they were clearing the A2S interrupt, see if we are headed for the spin */
	/* loop with R22 != 0; if we are, just start spinning again */
	if (&space.device() == m_dsp && ACCESSING_BITS_8_15 && (data & 0x400))
	{
		/* see if we're going back to the spin loop */
		if (!(data & 0x04000) && m_dsp->state(JAGUAR_R22) != 0)
		{
			UINT32 r30 = m_dsp->state(JAGUAR_R30) & 0xffffff;
			if (r30 >= 0xf1b124 && r30 <= 0xf1b126)
				dsp_suspend();
		}
	}
}

#endif



/*************************************
 *
 *  Serial port interrupt generation
 *
 *************************************/

void jaguar_state::serial_update()
{
	if (m_hacks_enabled)
	{
		/* assert the A2S IRQ on CPU #2 (DSP) */
		m_dsp->set_input_line(1, ASSERT_LINE);
		dsp_resume();

		/* fix flaky code in interrupt handler which thwarts our speedup */
		if ((m_dsp_ram[0x3e/4] & 0xffff) == 0xbfbc &&
			(m_dsp_ram[0x42/4] & 0xffff) == 0xe400)
		{
			/* move the store r28,(r29) into the branch delay slot, swapping it with */
			/* the nop that's currently there */
			m_dsp_ram[0x3e/4] = (m_dsp_ram[0x3e/4] & 0xffff0000) | 0xe400;
			m_dsp_ram[0x42/4] = (m_dsp_ram[0x42/4] & 0xffff0000) | 0xbfbc;
		}
	}
	else
	{
		/* assert the A2S IRQ on CPU #2 (DSP) */
		m_dsp->set_input_line(1, ASSERT_LINE);
		dsp_resume();
	}
}



/*************************************
 *
 *  Serial port handlers
 *
 *************************************/

READ32_MEMBER( jaguar_state::serial_r )
{
	logerror("%08X:jaguar_serial_r(%X)\n", space.device().safe_pcbase(), offset);
	return 0;
}


WRITE32_MEMBER( jaguar_state::serial_w )
{
	switch (offset)
	{
		/* right DAC */
		case 2:
			m_dac2->write_signed16((data & 0xffff) ^ 0x8000);
			break;

		/* left DAC */
		case 3:
			m_dac1->write_signed16((data & 0xffff) ^ 0x8000);
			break;

		/* frequency register */
		case 4:
			m_serial_frequency = data & 0xffff;
			break;

		/* control register -- only very specific modes supported */
		case 5:
			if ((data & 0x3f) != 0x15)
				logerror("Unexpected write to SMODE = %X\n", data);
			if ((data & 0x3f) == 0x15)
			{
				attotime rate = attotime::from_hz(26000000) * (32 * 2 * (m_serial_frequency + 1));
				m_serial_timer->adjust(rate, 0, rate);
			}
			break;

		default:
			logerror("%08X:jaguar_serial_w(%X,%X)\n", space.device().safe_pcbase(), offset, data);
			break;
	}
}