summaryrefslogtreecommitdiffstatshomepage
path: root/src/mame/audio/jaguar.c
blob: 1f10cb987185bd83c071e3cb7dd2c58b6d96a626 (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
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
/***************************************************************************

    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 - traingle 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 "driver.h"
#include "includes/jaguar.h"
#include "cpu/jaguar/jaguar.h"
#include "sound/dac.h"
#include <math.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
};



/* DSP variables */
static UINT16 dsp_regs[DSP_REGS];

static UINT16 serial_frequency;
static emu_timer *serial_timer;

static UINT8 gpu_irq_state;

#if ENABLE_SPEEDUP_HACKS

static TIMER_CALLBACK( serial_chunky_callback );
static WRITE32_HANDLER( dsp_flags_w );

#else

static TIMER_CALLBACK( serial_callback );

#endif



/*************************************
 *
 *  DSP optimization control
 *
 *************************************/

void jaguar_dsp_suspend(void)
{
	cpunum_suspend(2, SUSPEND_REASON_SPIN, 1);
}


void jaguar_dsp_resume(void)
{
	cpunum_resume(2, SUSPEND_REASON_SPIN);
}



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

static void update_gpu_irq(void)
{
	if (gpu_irq_state & dsp_regs[JINTCTRL] & 0x1f)
	{
		cpunum_set_input_line(1, 1, ASSERT_LINE);
		jaguar_gpu_resume();
	}
	else
		cpunum_set_input_line(1, 1, CLEAR_LINE);
}


void jaguar_external_int(int state)
{
	if (state != CLEAR_LINE)
		gpu_irq_state |= 1;
	else
		gpu_irq_state &= ~1;
	update_gpu_irq();
}



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

void cojag_sound_init(void)
{
	int i;

	/* fill the wave ROM -- these are pretty cheesy guesses */
	for (i = 0; i < 0x80; i++)
	{
		/* F1D000 = triangle wave */
		jaguar_wave_rom[0x000 + i] = ((i <= 0x40) ? i : 0x80 - i) * 32767 / 0x40;

		/* F1D200 = full sine wave */
		jaguar_wave_rom[0x080 + i] = (int)(32767. * sin(2.0 * M_PI * (double)i / (double)0x80));

		/* F1D400 = amplitude modulated sine wave? */
		jaguar_wave_rom[0x100 + i] = (int)(32767. * sin(2.0 * M_PI * (double)i / (double)0x80));

		/* F1D600 = sine wave and second order harmonic */
		jaguar_wave_rom[0x180 + i] = (int)(32767. * sin(2.0 * M_PI * (double)i / (double)0x80));

		/* F1D800 = chirp (sine wave of increasing frequency) */
		jaguar_wave_rom[0x200 + i] = (int)(32767. * sin(2.0 * M_PI * (double)i / (double)0x80));

		/* F1DA00 = traingle wave with noise */
		jaguar_wave_rom[0x280 + i] = jaguar_wave_rom[0x000 + i] * (mame_rand(Machine) % 32768) / 32768;

		/* F1DC00 = spike */
		jaguar_wave_rom[0x300 + i] = (i == 0x40) ? 32767 : 0;

		/* F1DE00 = white noise */
		jaguar_wave_rom[0x380 + i] = mame_rand(Machine) % 32768;
	}

#if ENABLE_SPEEDUP_HACKS
	memory_install_write32_handler(2, ADDRESS_SPACE_PROGRAM, 0xf1a100, 0xf1a103, 0, 0, dsp_flags_w);
#endif
}



/*************************************
 *
 *  Sound reset
 *
 *************************************/

void cojag_sound_reset(void)
{
#if ENABLE_SPEEDUP_HACKS
	serial_timer = timer_alloc(serial_chunky_callback, NULL);
#else
	serial_timer = timer_alloc(serial_callback, NULL);
#endif
}



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

READ16_HANDLER( jaguar_jerry_regs_r )
{
	if (offset != JINTCTRL && offset != JINTCTRL+2)
		logerror("%08X:jerry read register @ F10%03X\n", activecpu_get_previouspc(), offset * 2);

	switch (offset)
	{
		case JINTCTRL:
			return gpu_irq_state;
	}

	return dsp_regs[offset];
}


WRITE16_HANDLER( jaguar_jerry_regs_w )
{
	COMBINE_DATA(&dsp_regs[offset]);

	switch (offset)
	{
		case JINTCTRL:
			gpu_irq_state &= ~(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", activecpu_get_previouspc(), offset * 2, data);
}



/*************************************
 *
 *  Jerry 32-bit register access
 *
 *************************************/

READ32_HANDLER( jaguar_jerry_regs32_r )
{
	return (jaguar_jerry_regs_r(offset * 2, 0) << 16) | jaguar_jerry_regs_r(offset * 2 + 1, 0);
}


WRITE32_HANDLER( jaguar_jerry_regs32_w )
{
	if (ACCESSING_MSW32)
		jaguar_jerry_regs_w(offset * 2, data >> 16, mem_mask >> 16);
	if (ACCESSING_LSW32)
		jaguar_jerry_regs_w(offset * 2 + 1, data, mem_mask);
}



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

#if ENABLE_SPEEDUP_HACKS

static WRITE32_HANDLER( dsp_flags_w )
{
	/* write the data through */
	jaguardsp_ctrl_w(2, 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 (cpu_getactivecpu() == 2 && !(mem_mask & 0x0000ff00) && (data & 0x400))
	{
		/* see if we're going back to the spin loop */
		if (!(data & 0x04000) && activecpu_get_reg(JAGUAR_R22) != 0)
		{
			UINT32 r30 = activecpu_get_reg(JAGUAR_R30) & 0xffffff;
			if (r30 >= 0xf1b124 && r30 <= 0xf1b126)
				jaguar_dsp_suspend();
		}
	}
}

#endif



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

#if ENABLE_SPEEDUP_HACKS

static TIMER_CALLBACK( serial_chunky_callback )
{
	/* assert the A2S IRQ on CPU #2 (DSP) */
	cpunum_set_input_line(2, 1, ASSERT_LINE);
	jaguar_dsp_resume();

	/* fix flaky code in interrupt handler which thwarts our speedup */
	if ((jaguar_dsp_ram[0x3e/4] & 0xffff) == 0xbfbc &&
		(jaguar_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 */
		jaguar_dsp_ram[0x3e/4] = (jaguar_dsp_ram[0x3e/4] & 0xffff0000) | 0xe400;
		jaguar_dsp_ram[0x42/4] = (jaguar_dsp_ram[0x42/4] & 0xffff0000) | 0xbfbc;
	}
}

#else

static TIMER_CALLBACK( serial_callback )
{
	/* assert the A2S IRQ on CPU #2 (DSP) */
	cpunum_set_input_line(2, 1, ASSERT_LINE);
	jaguar_dsp_resume();
}

#endif



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

READ32_HANDLER( jaguar_serial_r )
{
	logerror("%08X:jaguar_serial_r(%X)\n", activecpu_get_previouspc(), offset);
	return 0;
}


WRITE32_HANDLER( jaguar_serial_w )
{
	switch (offset)
	{
		/* right DAC */
		case 2:
			DAC_signed_data_16_w(1, (data & 0xffff) ^ 0x8000);
			break;

		/* left DAC */
		case 3:
			DAC_signed_data_16_w(0, (data & 0xffff) ^ 0x8000);
			break;

		/* frequency register */
		case 4:
			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_mul(ATTOTIME_IN_HZ(26000000), 32 * 2 * (serial_frequency + 1));
				timer_adjust(serial_timer, rate, 0, rate);
			}
			break;

		default:
			logerror("%08X:jaguar_serial_w(%X,%X)\n", activecpu_get_previouspc(), offset, data);
			break;
	}
}