|
|
1.1 root 1: /*
2: Hatari - Crossbar.c
3:
1.1.1.5 root 4: This file is distributed under the GNU General Public License, version 2
5: or at your option any later version. Read the file gpl.txt for details.
1.1 root 6:
7: Falcon Crossbar (Matrice) emulation.
1.1.1.7 ! root 8: input device:
1.1 root 9: - DSP transmit (SSI)
10: - external DSP connector
11: - ADC (micro + PSG chip)
12: - DMA playback
13:
14: output device:
15: - external DSP connector
16: - DSP receive (SSI)
17: - DAC (headphone, loudspeaker and monitor sound)
18: - DMA record
19:
20: There are 3 possible clocks :
21: - internal clock 25,175 MHz (Ste compatible)
22: - internal clock 32 MHz
23: - external clock (DSP external port, up to 32 Mhz)
24:
1.1.1.7 ! root 25: Transfers between 2 devices can use handshaking or continuous mode
1.1 root 26:
27: Hardware I/O registers:
28: $FF8900 (byte) : Sound DMA control
29: $FF8901 (byte) : Sound DMA control
30: $FF8903 (byte) : Frame Start Hi
31: $FF8905 (byte) : Frame Start Mi
32: $FF8907 (byte) : Frame Start Lo
33: $FF8909 (byte) : Frame Count Hi
34: $FF890B (byte) : Frame Count Mi
35: $FF890D (byte) : Frame Count Lo
36: $FF890F (byte) : Frame End Hi
37: $FF8911 (byte) : Frame End Mi
38: $FF8913 (byte) : Frame End Lo
39: $FF8920 (byte) : Sound Mode Control
40: $FF8921 (byte) : Sound Mode Control
41: $FF8930 (word) : DMA Crossbar Input Select Controller
42: $FF8932 (word) : DMA Crossbar Output Select Controller
43: $FF8934 (byte) : External Sync Frequency Divider
44: $FF8935 (byte) : Internal Sync Frequency Divider
45: $FF8936 (byte) : Record Track select
46: $FF8937 (byte) : Codec Input Source
47: $FF8938 (byte) : Codec ADC Input
48: $FF8939 (byte) : Gain Settings Per Channel
1.1.1.5 root 49: $FF893A (word) : Attenuation Settings Per Channel
1.1 root 50: $FF893C (word) : Codec Status
51: $FF8940 (word) : GPIO Data Direction
52: $FF8942 (word) : GPIO Data
53:
54:
55: Crossbar schematics:
1.1.1.7 ! root 56:
1.1 root 57: - one receiving device can be connected to only one source device
58: - one source device can be connected to multiple receiving device
59:
60: Source devices
61: CROSSBAR
62: EXT INPUT ---O------O------O-----O
63: CHANNEL | | | |
64: | | | |
65: DSP ---O------O------O-----O
66: TRANSMIT | | | |
67: | | | |
68: Mic L -----| DMA ---O------O------O-----O
1.1.1.7 ! root 69: /---|XOR ----|\ PLAYBACK | | | |
1.1 root 70: PSG --| | \ | | | |
71: \---| | /-------X--------O------O------O-----O
72: Mic R -----|XOR ----|/ | | | | |
73: ADC | | DMA DSP EXT OUTPUT Receiving Devices
74: | | RECEIVE CHANNEL
75: | |
76: -----------------
77: \ + /
78: \-----------/
79: |
80: |
81: -----
82: \ / DAC
83: \ /
84: |
85: |
86: Output to:
1.1.1.7 ! root 87: - header,
! 88: - internal speaker,
! 89: - monitor speaker
1.1 root 90: */
91:
92: const char crossbar_fileid[] = "Hatari Crossbar.c : " __DATE__ " " __TIME__;
93:
94: #include "main.h"
95: #include "audio.h"
96: #include "configuration.h"
97: #include "cycInt.h"
98: #include "ioMem.h"
99: #include "log.h"
100: #include "memorySnapShot.h"
101: #include "mfp.h"
102: #include "sound.h"
103: #include "crossbar.h"
104: #include "microphone.h"
105: #include "stMemory.h"
106: #include "dsp.h"
107:
108:
109: #define DACBUFFER_SIZE 2048
110: #define DECIMAL_PRECISION 65536
111:
112:
113: /* Crossbar internal functions */
1.1.1.4 root 114: static int Crossbar_DetectSampleRate(Uint16 clock);
1.1 root 115: static void Crossbar_Recalculate_Clocks_Cycles(void);
116: static void Crossbar_Start_InterruptHandler_25Mhz(void);
117: static void Crossbar_Start_InterruptHandler_32Mhz(void);
118:
119: /* Dma_Play sound functions */
120: static void Crossbar_setDmaPlay_Settings(void);
121: static void Crossbar_Process_DMAPlay_Transfer(void);
122:
123: /* Dma_Record sound functions */
124: static void Crossbar_setDmaRecord_Settings(void);
125: void Crossbar_SendDataToDmaRecord(Sint16 value);
126: static void Crossbar_Process_DMARecord_HandshakeMode(void);
127:
128: /* Dsp Xmit functions */
129: static void Crossbar_SendDataToDspReceive(Uint32 value, Uint16 frame);
130: static void Crossbar_Process_DSPXmit_Transfer(void);
131:
132: /* DAC functions */
133: static void Crossbar_SendDataToDAC(Sint16 value, Uint16 sample_pos);
134:
135: /* ADC functions */
136: static void Crossbar_Process_ADCXmit_Transfer(void);
137:
138: /* external data used by the MFP */
139: Uint16 nCbar_DmaSoundControl;
140:
141: /* internal datas */
142:
143: /* dB = 20log(gain) : gain = antilog(dB/20) */
144: /* Table gain values = (int)(powf(10.0, dB/20.0)*65536.0 + 0.5) 1.5dB steps */
145:
146: /* Values for Codec's ADC volume control (* DECIMAL_PRECISION) */
147: /* PSG must be amplified by 2.66.. before mixing with crossbar */
148: /* The ADC table values are multiplied by 2'2/3 and divided */
149: /* by 4 (later multplied by 4) eg 43691 = 65536 * 2.66.. / 4.0 */
150: static const Uint16 Crossbar_ADC_volume_table[16] =
151: {
152: 3276, 3894, 4628, 5500, 6537, 7769, 9234, 10975,
153: 13043, 15502, 18424, 21897, 26025, 30931, 36761, 43691
154: };
155:
156: /* Values for Codec's DAC volume control (* DECIMAL_PRECISION) */
157: static const Uint16 Crossbar_DAC_volume_table[16] =
158: {
159: 65535, 55142, 46396, 39037, 32846, 27636, 23253, 19565,
160: 16462, 13851, 11654, 9806, 8250, 6942, 5841, 4915
161: };
162:
1.1.1.4 root 163: static const int Ste_SampleRates[4] =
1.1 root 164: {
1.1.1.4 root 165: 6258,
166: 12517,
167: 25033,
168: 50066
1.1 root 169: };
170:
1.1.1.4 root 171: static const int Falcon_SampleRates_25Mhz[15] =
1.1 root 172: {
1.1.1.4 root 173: 49170,
174: 32780,
175: 24585,
176: 19668,
177: 16390,
178: 14049,
179: 12292,
180: 10927,
181: 9834,
182: 8940,
183: 8195,
184: 7565,
185: 7024,
186: 6556,
187: 6146
1.1 root 188: };
189:
1.1.1.4 root 190: static const int Falcon_SampleRates_32Mhz[15] =
1.1 root 191: {
1.1.1.4 root 192: 62500,
193: 41666,
194: 31250,
195: 25000,
196: 20833,
197: 17857,
198: 15624,
199: 13889,
200: 12500,
201: 11363,
202: 10416,
203: 9615,
204: 8928,
205: 8333,
206: 7812
1.1 root 207: };
208:
209: struct dma_s {
210: Uint32 frameStartAddr; /* Sound frame start */
211: Uint32 frameEndAddr; /* Sound frame end */
212: Uint32 frameCounter; /* Counter in current sound frame */
213: Uint32 frameLen; /* Length of the frame */
214: Uint32 isRunning; /* Is Playing / Recording ? */
215: Uint32 loopMode; /* Loop mode enabled ? */
216: Uint32 currentFrame; /* Current Frame Played / Recorded (in stereo, 2 frames = 1 track) */
217: Uint32 timerA_int; /* Timer A interrupt at end of Play / Record ? */
218: Uint32 mfp15_int; /* MFP-15 interrupt at end of Play / Record ? */
219: Uint32 isConnectedToCodec;
220: Uint32 isConnectedToDsp;
221: Uint32 isConnectedToDspInHandShakeMode;
222: Uint32 isConnectedToDma;
223: Uint32 handshakeMode_Frame; /* state of the frame in handshake mode */
224: };
225:
226: struct crossbar_s {
227: Uint32 dmaSelected; /* 1 = DMA Record; 0 = DMA Play */
228: Uint32 playTracks; /* number of tracks played */
229: Uint32 recordTracks; /* number of tracks recorded */
230: Uint16 track_monitored; /* track monitored by the DAC */
231: Uint32 is16Bits; /* 0 = 8 bits; 1 = 16 bits */
232: Uint32 isStereo; /* 0 = mono; 1 = stereo */
233: Uint32 steFreq; /* from 0 (6258 Hz) to 3 (50066 Hz) */
234: Uint32 isInSteFreqMode; /* 0 = Falcon frequency mode ; 1 = Ste frequency mode */
235: Uint32 int_freq_divider; /* internal frequency divider */
236: Uint32 isDacMuted; /* 0 = DAC is running; 1 = DAC is muted */
237: Uint32 dspXmit_freq; /* 0 = 25 Mhz ; 1 = external clock ; 2 = 32 Mhz */
238: Uint32 dmaPlay_freq; /* 0 = 25 Mhz ; 1 = external clock ; 2 = 32 Mhz */
239: Uint16 codecInputSource; /* codec input source */
240: Uint16 codecAdcInput; /* codec ADC input */
241: Uint16 gainSettingLeft; /* Left channel gain for ADC */
242: Uint16 gainSettingRight; /* Right channel gain for ADC */
243: Uint16 attenuationSettingLeft; /* Left channel attenuation for DAC */
244: Uint16 attenuationSettingRight; /* Right channel attenuation for DAC */
245: Uint16 microphone_ADC_is_started;
1.1.1.7 ! root 246:
1.1 root 247: Uint32 clock25_cycles; /* cycles for 25 Mzh interrupt */
248: Uint32 clock25_cycles_decimal; /* decimal part of cycles counter for 25 Mzh interrupt (*DECIMAL_PRECISION) */
249: Uint32 clock25_cycles_counter; /* Cycle counter for 25 Mhz interrupts */
250: Uint32 pendingCyclesOver25; /* Number of delayed cycles for the interrupt */
251: Uint32 clock32_cycles; /* cycles for 32 Mzh interrupt */
252: Uint32 clock32_cycles_decimal; /* decimal part of cycles counter for 32 Mzh interrupt (*DECIMAL_PRECISION) */
253: Uint32 clock32_cycles_counter; /* Cycle counter for 32 Mhz interrupts */
254: Uint32 pendingCyclesOver32; /* Number of delayed cycles for the interrupt */
1.1.1.4 root 255: Sint64 frequence_ratio; /* Ratio between host computer's sound frequency and hatari's sound frequency */
256: Sint64 frequence_ratio2; /* Ratio between hatari's sound frequency and host computer's sound frequency */
1.1.1.7 ! root 257:
1.1 root 258: Uint32 dmaPlay_CurrentFrameStart; /* current DmaPlay Frame start ($ff8903 $ff8905 $ff8907) */
259: Uint32 dmaPlay_CurrentFrameCount; /* current DmaRecord Frame start ($ff8903 $ff8905 $ff8907) */
260: Uint32 dmaPlay_CurrentFrameEnd; /* current DmaRecord Frame start ($ff8903 $ff8905 $ff8907) */
261: Uint32 dmaRecord_CurrentFrameStart; /* current DmaPlay Frame end ($ff890f $ff8911 $ff8913) */
262: Uint32 dmaRecord_CurrentFrameCount; /* current DmaRecord Frame start ($ff8903 $ff8905 $ff8907) */
263: Uint32 dmaRecord_CurrentFrameEnd; /* current DmaRecord Frame end ($ff890f $ff8911 $ff8913) */
1.1.1.4 root 264: Uint32 adc2dac_readBufferPosition; /* read position for direct adc->dac transfer */
265: Sint64 adc2dac_readBufferPosition_float; /* float value of read position for direct adc->dac transfer index */
1.1.1.7 ! root 266:
1.1.1.2 root 267: Uint32 save_special_transfer; /* Used in a special undocumented transfer mode (dsp sent is not in handshake mode and dsp receive is in handshake mode) */
1.1 root 268: };
269:
270: struct codec_s {
271: Sint16 buffer_left[DACBUFFER_SIZE];
272: Sint16 buffer_right[DACBUFFER_SIZE];
1.1.1.4 root 273: Sint64 readPosition_float;
1.1 root 274: Uint32 readPosition;
275: Uint32 writePosition;
276: Uint32 isConnectedToCodec;
277: Uint32 isConnectedToDsp;
278: Uint32 isConnectedToDma;
279: Uint32 wordCount;
280: };
281:
282: struct dsp_s {
283: Uint32 isTristated; /* 0 = DSP is not tristated; 1 = DSP is tristated */
284: Uint32 isInHandshakeMode; /* 0 = not in hanshake mode; 1 = in hanshake mode */
285: Uint32 isConnectedToCodec;
286: Uint32 isConnectedToDsp;
287: Uint32 isConnectedToDma;
288: Uint32 wordCount; /* count number of words received from DSP transmitter (for TX frame computing) */
289: };
290:
291: static struct crossbar_s crossbar;
292: static struct dma_s dmaPlay;
293: static struct dma_s dmaRecord;
294: static struct codec_s dac;
295: static struct codec_s adc;
296: static struct dsp_s dspXmit;
297: static struct dsp_s dspReceive;
298:
299: /**
300: * Reset Crossbar variables.
301: */
302: void Crossbar_Reset(bool bCold)
303: {
304: nCbar_DmaSoundControl = 0;
305:
306: /* Stop DMA sound playing / record */
307: IoMem_WriteByte(0xff8901,0);
308: dmaPlay.isRunning = 0;
309: dmaPlay.loopMode = 0;
310: dmaPlay.currentFrame = 0;
311: dmaPlay.isConnectedToDspInHandShakeMode = 0;
312: dmaPlay.handshakeMode_Frame = 0;
313: dmaRecord.isRunning = 0;
314: dmaRecord.loopMode = 0;
315: dmaRecord.currentFrame = 0;
316: dmaRecord.isConnectedToDspInHandShakeMode = 0;
317: dmaRecord.handshakeMode_Frame = 0;
318:
319: /* DAC inits */
320: memset(dac.buffer_left, 0, sizeof(dac.buffer_left));
321: memset(dac.buffer_right, 0, sizeof(dac.buffer_right));
1.1.1.4 root 322: dac.readPosition_float = 0;
1.1 root 323: dac.readPosition = 0;
324: dac.writePosition = 0;
325:
326: /* ADC inits */
1.1.1.2 root 327: memset(adc.buffer_left, 0, sizeof(adc.buffer_left));
328: memset(adc.buffer_right, 0, sizeof(adc.buffer_right));
1.1.1.4 root 329: adc.readPosition_float = 0;
1.1 root 330: adc.readPosition = 0;
331: adc.writePosition = 0;
332:
333: /* DSP inits */
334: dspXmit.wordCount = 0;
335:
336: /* Crossbar inits */
337: crossbar.clock25_cycles = 160;
338: crossbar.clock25_cycles_decimal = 0;
339: crossbar.clock25_cycles_counter = 0;
340: crossbar.pendingCyclesOver25 = 0;
341: crossbar.clock32_cycles = 160;
342: crossbar.clock32_cycles_decimal = 0;
343: crossbar.clock32_cycles_counter = 0;
344: crossbar.pendingCyclesOver32 = 0;
345: crossbar.frequence_ratio = 0;
346: crossbar.frequence_ratio2 = 0;
347:
348: crossbar.dmaSelected = 0;
349: crossbar.track_monitored = 0;
350: crossbar.isInSteFreqMode = 1;
351: crossbar.int_freq_divider = 0;
352: crossbar.steFreq = 3;
353: crossbar.playTracks = 1;
354: crossbar.is16Bits = 0;
355: crossbar.isStereo = 1;
356: crossbar.codecInputSource = 3;
357: crossbar.codecAdcInput = 3;
358: crossbar.gainSettingLeft = 3276;
359: crossbar.gainSettingRight = 3276;
360: crossbar.attenuationSettingLeft = 65535;
361: crossbar.attenuationSettingRight = 65535;
1.1.1.4 root 362: crossbar.adc2dac_readBufferPosition = 0;
363: crossbar.adc2dac_readBufferPosition_float = 0;
1.1 root 364:
365: /* Start 25 Mhz and 32 Mhz Clocks */
366: Crossbar_Recalculate_Clocks_Cycles();
367: Crossbar_Start_InterruptHandler_25Mhz();
368: Crossbar_Start_InterruptHandler_32Mhz();
369:
370: /* Start Microphone jack emulation */
1.1.1.7 ! root 371: if (crossbar.microphone_ADC_is_started == 0) {
1.1 root 372: crossbar.microphone_ADC_is_started = Microphone_Start((int)nAudioFrequency);
373: }
374:
1.1.1.2 root 375: /* Initialize special transfer mode */
376: crossbar.save_special_transfer = 0;
1.1.1.7 ! root 377:
1.1 root 378: /* Initialize Crossbar values after reboot */
379: IoMem_WriteByte(0xff8900,0x05);
380: IoMem_WriteByte(0xff8903,0xff);
381: IoMem_WriteByte(0xff8905,0xff);
382: IoMem_WriteByte(0xff8907,0xfe);
383: IoMem_WriteByte(0xff8909,0xff);
384: IoMem_WriteByte(0xff890b,0xff);
385: IoMem_WriteByte(0xff890d,0xfe);
386: IoMem_WriteByte(0xff890f,0xff);
387: IoMem_WriteByte(0xff8911,0xff);
388: IoMem_WriteByte(0xff8913,0xfe);
389: IoMem_WriteWord(0xff893c,0x2401);
390: }
391:
392: /**
393: * Save/Restore snapshot of local variables ('MemorySnapShot_Store' handles type)
394: */
395: void Crossbar_MemorySnapShot_Capture(bool bSave)
396: {
397: /* Save/Restore details */
398: MemorySnapShot_Store(&nCbar_DmaSoundControl, sizeof(nCbar_DmaSoundControl));
399: MemorySnapShot_Store(&dmaPlay, sizeof(dmaPlay));
400: MemorySnapShot_Store(&dmaRecord, sizeof(dmaRecord));
401: MemorySnapShot_Store(&crossbar, sizeof(crossbar));
402: MemorySnapShot_Store(&dac, sizeof(dac));
403: MemorySnapShot_Store(&adc, sizeof(adc));
404: MemorySnapShot_Store(&dspXmit, sizeof(dspXmit));
405: MemorySnapShot_Store(&dspReceive, sizeof(dspReceive));
406: }
407:
408:
409: /*----------------------------------------------------------------------*/
410: /* Hardware I/O functions */
411: /*----------------------------------------------------------------------*/
412:
413: /**
1.1.1.4 root 414: * Write byte to Microwire Mask register(0xff8924).
415: * Note: On Falcon, the Microwire is not present.
416: * But for compatibility with the STe, Atari implemented the Microwire
1.1.1.7 ! root 417: * as follow (when one writes at the following address):
1.1.1.4 root 418: * $ff8922: always reads 0 for any value written at this address
419: * $ff8924: NOT the value, then 8 cycles later, NOT the value again to its initial value.
420: */
421: void Crossbar_Microwire_WriteWord(void)
422: {
423: Uint16 microwire = IoMem_ReadWord(0xff8924);
424: LOG_TRACE(TRACE_CROSSBAR, "Crossbar : $ff8924 (MicroWire Mask) write: 0x%04x\n", microwire);
425:
426: /* NOT the value and store it */
427: microwire = ~microwire;
428: IoMem_WriteWord(0xff8924, microwire);
429: LOG_TRACE(TRACE_CROSSBAR, "Crossbar : $ff8924 (MicroWire Mask) NOT value: 0x%04x\n", microwire);
430:
431: /* Start a new Microwire interrupt */
432: CycInt_AddRelativeInterrupt(8, INT_CPU_CYCLE, INTERRUPT_DMASOUND_MICROWIRE);
433: }
434:
435: /**
436: * Crossbar Microwire mask interrupt, called from dmaSnd.c
437: */
438: void Crossbar_InterruptHandler_Microwire(void)
439: {
440: Uint16 microwire = IoMem_ReadWord(0xff8924);
441:
442: /* Remove this interrupt from list and re-order */
443: CycInt_AcknowledgeInterrupt();
444:
445: /* NOT the value again to it's original value and store it */
446: microwire = ~microwire;
447: IoMem_WriteWord(0xff8924, microwire);
448: LOG_TRACE(TRACE_CROSSBAR, "Crossbar : $ff8924 (MicroWire Mask) NOT value to original: 0x%04x\n", microwire);
449: }
450:
451: /**
1.1 root 452: * Write byte to buffer interrupts (0xff8900).
453: */
454: void Crossbar_BufferInter_WriteByte(void)
455: {
456: Uint8 dmaCtrl = IoMem_ReadByte(0xff8900);
457:
458: LOG_TRACE(TRACE_CROSSBAR, "Crossbar : $ff8900 (Sound DMA control) write: 0x%02x\n", dmaCtrl);
459:
460: dmaPlay.timerA_int = (dmaCtrl & 0x4) >> 2;
461: dmaPlay.mfp15_int = (dmaCtrl & 0x1);
462: dmaRecord.timerA_int = (dmaCtrl & 0x8) >> 3;
463: dmaRecord.mfp15_int = (dmaCtrl & 0x2) >> 1;
464: }
465:
466: /**
467: * Write byte from DMA control register (0xff8901).
468: */
469: void Crossbar_DmaCtrlReg_WriteByte(void)
470: {
471: Uint8 sndCtrl = IoMem_ReadByte(0xff8901);
472:
473: LOG_TRACE(TRACE_CROSSBAR, "Crossbar : $ff8901 (additional Sound DMA control) write: 0x%02x\n", sndCtrl);
474:
475: crossbar.dmaSelected = (sndCtrl & 0x80) >> 7;
476:
477: /* DMA Play mode */
478: if ((dmaPlay.isRunning == 0) && (sndCtrl & CROSSBAR_SNDCTRL_PLAY))
479: {
480: /* Turning on DMA Play sound emulation */
481: dmaPlay.isRunning = 1;
482: nCbar_DmaSoundControl = sndCtrl;
483: dmaPlay.loopMode = (sndCtrl & 0x2) >> 1;
484: Crossbar_setDmaPlay_Settings();
485: }
486: else if (dmaPlay.isRunning && ((sndCtrl & CROSSBAR_SNDCTRL_PLAY) == 0))
487: {
488: /* Create samples up until this point with current values */
1.1.1.2 root 489: Sound_Update(false);
1.1 root 490:
491: /* Turning off DMA play sound emulation */
492: dmaPlay.isRunning = 0;
493: dmaPlay.loopMode = 0;
494: nCbar_DmaSoundControl = sndCtrl;
495: }
496:
497: /* DMA Record mode */
498: if ((dmaRecord.isRunning == 0) && (sndCtrl & CROSSBAR_SNDCTRL_RECORD))
499: {
500: /* Turning on DMA record sound emulation */
501: dmaRecord.isRunning = 1;
502: nCbar_DmaSoundControl = sndCtrl;
1.1.1.2 root 503: dmaRecord.loopMode = (sndCtrl & 0x20) >> 5;
1.1 root 504: Crossbar_setDmaRecord_Settings();
505: }
506: else if (dmaRecord.isRunning && ((sndCtrl & CROSSBAR_SNDCTRL_RECORD) == 0))
507: {
508: /* Turning off DMA record sound emulation */
509: dmaRecord.isRunning = 0;
510: dmaRecord.loopMode = 0;
1.1.1.2 root 511: nCbar_DmaSoundControl = sndCtrl;
1.1 root 512: }
513: }
514:
515:
516: /**
517: * Read byte from sound frame start high register (0xff8903).
518: */
519: void Crossbar_FrameStartHigh_ReadByte(void)
520: {
521: if (crossbar.dmaSelected == 0) {
522: /* DMA Play selected */
523: IoMem_WriteByte(0xff8903, crossbar.dmaPlay_CurrentFrameStart >> 16);
524: }
525: else {
526: /* DMA Record selected */
527: IoMem_WriteByte(0xff8903, crossbar.dmaRecord_CurrentFrameStart >> 16);
528: }
529: }
530:
531: /**
532: * Write byte to sound frame start high register (0xff8903).
533: */
534: void Crossbar_FrameStartHigh_WriteByte(void)
535: {
536: Uint32 addr;
537:
538: LOG_TRACE(TRACE_CROSSBAR, "Crossbar : $ff8903 (Sound frame start high) write: 0x%02x\n", IoMem_ReadByte(0xff8903));
539:
540: addr = (IoMem_ReadByte(0xff8903) << 16) + (IoMem_ReadByte(0xff8905) << 8) + IoMem_ReadByte(0xff8907);
541:
542: if (crossbar.dmaSelected == 0) {
543: /* DMA Play selected */
544: crossbar.dmaPlay_CurrentFrameStart = addr & ~1;
545: }
546: else {
547: /* DMA Record selected */
548: crossbar.dmaRecord_CurrentFrameStart = addr & ~1;
549: }
550: }
551:
552: /**
553: * Read byte from sound frame start medium register (0xff8905).
554: */
555: void Crossbar_FrameStartMed_ReadByte(void)
556: {
557: if (crossbar.dmaSelected == 0) {
558: /* DMA Play selected */
559: IoMem_WriteByte(0xff8905, crossbar.dmaPlay_CurrentFrameStart >> 8);
560: }
561: else {
562: /* DMA Record selected */
563: IoMem_WriteByte(0xff8905, crossbar.dmaRecord_CurrentFrameStart >> 8);
564: }
565: }
566:
567: /**
568: * Write byte to sound frame start medium register (0xff8905).
569: */
570: void Crossbar_FrameStartMed_WriteByte(void)
571: {
572: Uint32 addr;
573:
574: LOG_TRACE(TRACE_CROSSBAR, "Crossbar : $ff8905 (Sound frame start med) write: 0x%02x\n", IoMem_ReadByte(0xff8905));
575:
576: addr = (IoMem_ReadByte(0xff8903) << 16) + (IoMem_ReadByte(0xff8905) << 8) + IoMem_ReadByte(0xff8907);
577:
578: if (crossbar.dmaSelected == 0) {
579: /* DMA Play selected */
580: crossbar.dmaPlay_CurrentFrameStart = addr & ~1;
581: }
582: else {
583: /* DMA Record selected */
584: crossbar.dmaRecord_CurrentFrameStart = addr & ~1;
585: }
586: }
587:
588: /**
589: * Read byte from sound frame start low register (0xff8907).
590: */
591: void Crossbar_FrameStartLow_ReadByte(void)
592: {
593: if (crossbar.dmaSelected == 0) {
594: /* DMA Play selected */
595: IoMem_WriteByte(0xff8907, crossbar.dmaPlay_CurrentFrameStart);
596: }
597: else {
598: /* DMA Record selected */
599: IoMem_WriteByte(0xff8907, crossbar.dmaRecord_CurrentFrameStart);
600: }
601: }
602:
603: /**
604: * Write byte to sound frame start low register (0xff8907).
605: */
606: void Crossbar_FrameStartLow_WriteByte(void)
607: {
608: Uint32 addr;
609:
610: LOG_TRACE(TRACE_CROSSBAR, "Crossbar : $ff8907 (Sound frame start low) write: 0x%02x\n", IoMem_ReadByte(0xff8907));
611:
612: addr = (IoMem_ReadByte(0xff8903) << 16) + (IoMem_ReadByte(0xff8905) << 8) + IoMem_ReadByte(0xff8907);
613:
614: if (crossbar.dmaSelected == 0) {
615: /* DMA Play selected */
616: crossbar.dmaPlay_CurrentFrameStart = addr & ~1;
617: }
618: else {
619: /* DMA Record selected */
620: crossbar.dmaRecord_CurrentFrameStart = addr & ~1;
621: }
622: }
623:
624: /*-----------------------------------------------------------------------*/
625:
626: /**
627: * Read byte from sound frame count high register (0xff8909).
628: */
629: void Crossbar_FrameCountHigh_ReadByte(void)
630: {
631: if (crossbar.dmaSelected == 0) {
632: /* DMA Play selected */
633: IoMem_WriteByte(0xff8909, (dmaPlay.frameStartAddr + dmaPlay.frameCounter) >> 16);
634: }
635: else {
636: /* DMA Record selected */
637: IoMem_WriteByte(0xff8909, (dmaRecord.frameStartAddr + dmaRecord.frameCounter) >> 16);
638: }
639: }
640:
641: /**
642: * Write byte to sound frame count high register (0xff8909).
643: */
644: void Crossbar_FrameCountHigh_WriteByte(void)
645: {
646: Uint32 addr;
647:
648: LOG_TRACE(TRACE_CROSSBAR, "Crossbar : $ff8909 (Sound frame count high) write: 0x%02x\n", IoMem_ReadByte(0xff8909));
649:
650: /* Compute frameCounter current address */
651: addr = (IoMem_ReadByte(0xff8909) << 16) + (IoMem_ReadByte(0xff890b) << 8) + IoMem_ReadByte(0xff890d);
652:
653: if (crossbar.dmaSelected == 0) {
654: /* DMA Play selected */
655: crossbar.dmaPlay_CurrentFrameCount = addr;
656: }
657: else {
658: /* DMA Record selected */
659: crossbar.dmaRecord_CurrentFrameCount = addr;
660: }
661: }
662:
663: /**
664: * Read byte from sound frame count medium register (0xff890b).
665: */
666: void Crossbar_FrameCountMed_ReadByte(void)
667: {
668: if (crossbar.dmaSelected == 0) {
669: /* DMA Play selected */
670: IoMem_WriteByte(0xff890b, (dmaPlay.frameStartAddr + dmaPlay.frameCounter) >> 8);
671: }
672: else {
673: /* DMA Record selected */
674: IoMem_WriteByte(0xff890b, (dmaRecord.frameStartAddr + dmaRecord.frameCounter) >> 8);
675: }
676: }
677:
678: /**
679: * Write byte to sound frame count medium register (0xff890b).
680: */
681: void Crossbar_FrameCountMed_WriteByte(void)
682: {
683: Uint32 addr;
684:
685: LOG_TRACE(TRACE_CROSSBAR, "Crossbar : $ff890b (Sound frame count med) write: 0x%02x\n", IoMem_ReadByte(0xff890b));
686:
687: /* Compute frameCounter current address */
688: addr = (IoMem_ReadByte(0xff8909) << 16) + (IoMem_ReadByte(0xff890b) << 8) + IoMem_ReadByte(0xff890d);
689:
690: if (crossbar.dmaSelected == 0) {
691: /* DMA Play selected */
692: crossbar.dmaPlay_CurrentFrameCount = addr;
693: }
694: else {
695: /* DMA Record selected */
696: crossbar.dmaRecord_CurrentFrameCount = addr;
697: }
698: }
699:
700: /**
701: * Read byte from sound frame count low register (0xff890d).
702: */
703: void Crossbar_FrameCountLow_ReadByte(void)
704: {
705: if (crossbar.dmaSelected == 0) {
706: /* DMA Play selected */
707: IoMem_WriteByte(0xff890d, (dmaPlay.frameStartAddr + dmaPlay.frameCounter));
708: }
709: else {
710: /* DMA Record selected */
711: IoMem_WriteByte(0xff890d, (dmaRecord.frameStartAddr + dmaRecord.frameCounter));
712: }
713: }
714:
715: /**
716: * Write byte to sound frame count low register (0xff890d).
717: */
718: void Crossbar_FrameCountLow_WriteByte(void)
719: {
720: Uint32 addr;
721:
722: LOG_TRACE(TRACE_CROSSBAR, "Crossbar : $ff890d (Sound frame count low) write: 0x%02x\n", IoMem_ReadByte(0xff890d));
723:
724: /* Compute frameCounter current address */
725: addr = (IoMem_ReadByte(0xff8909) << 16) + (IoMem_ReadByte(0xff890b) << 8) + IoMem_ReadByte(0xff890d);
726:
727: if (crossbar.dmaSelected == 0) {
728: /* DMA Play selected */
729: crossbar.dmaPlay_CurrentFrameCount = addr;
730: }
731: else {
732: /* DMA Record selected */
733: crossbar.dmaRecord_CurrentFrameCount = addr;
734: }
735: }
736:
737: /*-----------------------------------------------------------------------*/
738:
739: /**
740: * Read byte from sound frame end high register (0xff890f).
741: */
742: void Crossbar_FrameEndHigh_ReadByte(void)
743: {
744: if (crossbar.dmaSelected == 0) {
745: /* DMA Play selected */
746: IoMem_WriteByte(0xff890f, crossbar.dmaPlay_CurrentFrameEnd >> 16);
747: }
748: else {
749: /* DMA Record selected */
750: IoMem_WriteByte(0xff890f, crossbar.dmaRecord_CurrentFrameEnd >> 16);
751: }
752: }
753:
754: /**
755: * Write byte to sound frame end high register (0xff890f).
756: */
757: void Crossbar_FrameEndHigh_WriteByte(void)
758: {
759: Uint32 addr;
760:
761: LOG_TRACE(TRACE_CROSSBAR, "Crossbar : $ff890f (Sound frame end high) write: 0x%02x\n", IoMem_ReadByte(0xff890f));
762:
763: addr = (IoMem_ReadByte(0xff890f) << 16) + (IoMem_ReadByte(0xff8911) << 8) + IoMem_ReadByte(0xff8913);
764:
765: if (crossbar.dmaSelected == 0) {
766: /* DMA Play selected */
767: crossbar.dmaPlay_CurrentFrameEnd = addr & ~1;
768: }
769: else {
770: /* DMA Record selected */
771: crossbar.dmaRecord_CurrentFrameEnd = addr & ~1;
772: }
773: }
774:
775: /**
776: * Read byte from sound frame end medium register (0xff8911).
777: */
778: void Crossbar_FrameEndMed_ReadByte(void)
779: {
780: if (crossbar.dmaSelected == 0) {
781: /* DMA Play selected */
782: IoMem_WriteByte(0xff8911, crossbar.dmaPlay_CurrentFrameEnd >> 8);
783: }
784: else {
785: /* DMA Record selected */
786: IoMem_WriteByte(0xff8911, crossbar.dmaRecord_CurrentFrameEnd >> 8);
787: }
788: }
789:
790: /**
791: * Write byte to sound frame end medium register (0xff8911).
792: */
793: void Crossbar_FrameEndMed_WriteByte(void)
794: {
795: Uint32 addr;
796:
797: LOG_TRACE(TRACE_CROSSBAR, "Crossbar : $ff8911 (Sound frame end med) write: 0x%02x\n", IoMem_ReadByte(0xff8911));
798:
799: addr = (IoMem_ReadByte(0xff890f) << 16) + (IoMem_ReadByte(0xff8911) << 8) + IoMem_ReadByte(0xff8913);
800:
801: if (crossbar.dmaSelected == 0) {
802: /* DMA Play selected */
803: crossbar.dmaPlay_CurrentFrameEnd = addr & ~1;
804: }
805: else {
806: /* DMA Record selected */
807: crossbar.dmaRecord_CurrentFrameEnd = addr & ~1;
808: }
809: }
810:
811: /**
812: * Read byte from sound frame end low register (0xff8913).
813: */
814: void Crossbar_FrameEndLow_ReadByte(void)
815: {
816: if (crossbar.dmaSelected == 0) {
817: /* DMA Play selected */
818: IoMem_WriteByte(0xff8913, crossbar.dmaPlay_CurrentFrameEnd);
819: }
820: else {
821: /* DMA Record selected */
822: IoMem_WriteByte(0xff8913, crossbar.dmaRecord_CurrentFrameEnd);
823: }
824: }
825:
826: /**
827: * Write byte to sound frame end low register (0xff8913).
828: */
829: void Crossbar_FrameEndLow_WriteByte(void)
830: {
831: Uint32 addr;
832:
833: LOG_TRACE(TRACE_CROSSBAR, "Crossbar : $ff8913 (Sound frame end low) write: 0x%02x\n", IoMem_ReadByte(0xff8913));
834:
835: addr = (IoMem_ReadByte(0xff890f) << 16) + (IoMem_ReadByte(0xff8911) << 8) + IoMem_ReadByte(0xff8913);
836:
837: if (crossbar.dmaSelected == 0) {
838: /* DMA Play selected */
839: crossbar.dmaPlay_CurrentFrameEnd = addr & ~1;
840: }
841: else {
842: /* DMA Record selected */
843: crossbar.dmaRecord_CurrentFrameEnd = addr & ~1;
844: }
845: }
846:
847: /*-----------------------------------------------------------------------*/
848: /**
849: * Write byte to DMA track control (0xff8920).
850: */
851: void Crossbar_DmaTrckCtrl_WriteByte(void)
852: {
853: Uint8 sndCtrl = IoMem_ReadByte(0xff8920);
854:
855: LOG_TRACE(TRACE_CROSSBAR, "Crossbar : $ff8920 (sound mode control) write: 0x%02x\n", sndCtrl);
856:
857: crossbar.playTracks = (sndCtrl & 3) + 1;
858: crossbar.track_monitored = (sndCtrl & 30) >> 4;
859: }
860:
861: /**
862: * Write word to sound mode register (0xff8921).
863: */
864: void Crossbar_SoundModeCtrl_WriteByte(void)
865: {
866: Uint8 sndCtrl = IoMem_ReadByte(0xff8921);
867:
868: LOG_TRACE(TRACE_CROSSBAR, "crossbar : $ff8921 (additional sound mode control) write: 0x%02x\n", sndCtrl);
869:
870: crossbar.is16Bits = (sndCtrl & 0x40) >> 6;
871: crossbar.isStereo = 1 - ((sndCtrl & 0x80) >> 7);
872: crossbar.steFreq = sndCtrl & 0x3;
873:
874: Crossbar_Recalculate_Clocks_Cycles();
875: }
876:
877: /**
878: * Write word to Falcon Crossbar source controller (0xff8930).
879: Source: A/D Convertor BIT 15 14 13 12
880: 00 - 25.175Mhz clock -------------------------+--+
881: 01 - External clock --------------------------+--+
882: 10 - 32Mhz clock (Don't use) -----------------+--'
883:
884: Source: External Input BIT 11 10 9 8
885: 0 - DSP IN, 1 - All others ----------------' | | |
886: 00 - 25.175Mhz clock -------------------------+--+ |
887: 01 - External clock --------------------------+--+ |
888: 10 - 32Mhz clock -----------------------------+--' |
889: 0 - Handshake on, 1 - Handshake off ----------------'
890:
891: Source: DSP-XMIT BIT 7 6 5 4
892: 0 - Tristate and disconnect DSP -----------+ | | |
893: (Only for external SSI use) | | | |
894: 1 - Connect DSP to multiplexer ------------' | | |
895: 00 - 25.175Mhz clock -------------------------+--+ |
896: 01 - External clock --------------------------+--+ |
897: 10 - 32Mhz clock -----------------------------+--' |
898: 0 - Handshake on, 1 - Handshake off ----------------'
899:
900: Source: DMA-PLAYBACK BIT 3 2 1 0
901: 0 - Handshaking on, dest DSP-REC ----------+ | | |
902: 1 - Destination is not DSP-REC ------------' | | |
903: 00 - 25.175Mhz clock -------------------------+--+ |
904: 01 - External clock --------------------------+--+ |
905: 10 - 32Mhz clock -----------------------------+--' |
906: 0 - Handshake on, 1 - Handshake off ----------------'
907: */
908: void Crossbar_SrcControler_WriteWord(void)
909: {
910: Uint16 nCbSrc = IoMem_ReadWord(0xff8930);
911:
912: LOG_TRACE(TRACE_CROSSBAR, "Crossbar : $ff8930 (source device) write: 0x%04x\n", nCbSrc);
913:
914: dspXmit.isTristated = 1 - ((nCbSrc >> 7) & 0x1);
915: dspXmit.isInHandshakeMode = 1 - ((nCbSrc >> 4) & 0x1);
1.1.1.7 ! root 916:
1.1 root 917: crossbar.dspXmit_freq = (nCbSrc >> 5) & 0x3;
918: crossbar.dmaPlay_freq = (nCbSrc >> 1) & 0x3;
919: }
920:
921: /**
922: * Write word to Falcon Crossbar destination controller (0xff8932).
923: Source: D/A Convertor BIT 15 14 13 12
1.1.1.2 root 924: 00 - DMA output ------------------------------+--+
925: 01 - DSP output ------------------------------+--+
926: 10 - External input --------------------------+--+
927: 11 - ADC input -------------------------------+--'
1.1 root 928:
929: Source: External OutPut BIT 11 10 9 8
930: 0 - DSP OUT, 1 - All others ---------------' | | |
931: 00 - DMA output ------------------------------+--+ |
932: 01 - DSP output ------------------------------+--+ |
933: 10 - External input --------------------------+--+ |
934: 11 - ADC input -------------------------------+--' |
935: 0 - Handshake on, 1 - Handshake off ----------------'
936:
937: Source: DSP-RECEIVE BIT 7 6 5 4
938: 0 - Tristate and disconnect DSP -----------+ | | |
939: (Only for external SSI use) | | | |
940: 1 - Connect DSP to multiplexer ------------' | | |
941: 00 - DMA output ------------------------------+--+ |
942: 01 - DSP output ------------------------------+--+ |
943: 10 - External input --------------------------+--+ |
944: 11 - ADC input -------------------------------+--' |
945: 0 - Handshake on, 1 - Handshake off ----------------'
946:
947: Source: DMA-RECORD BIT 3 2 1 0
948: 0 - Handshaking on, dest DSP-XMIT ---------+ | | |
949: 1 - All -----------------------------------' | | |
950: 00 - DMA output ------------------------------+--+ |
951: 01 - DSP output ------------------------------+--+ |
952: 10 - External input --------------------------+--+ |
953: 11 - ADC input -------------------------------+--' |
954: 0 - Handshake on, 1 - Handshake off ----------------'
955: */
956: void Crossbar_DstControler_WriteWord(void)
957: {
958: Uint16 destCtrl = IoMem_ReadWord(0xff8932);
959:
960: LOG_TRACE(TRACE_CROSSBAR, "Crossbar : $ff8932 (destination device) write: 0x%04x\n", destCtrl);
961:
962: dspReceive.isTristated = 1 - ((destCtrl & 0x80) >> 7);
963: dspReceive.isInHandshakeMode = 1 - ((destCtrl & 0x10) >> 4);
964:
965: /* destinations devices connexions */
966: dspReceive.isConnectedToCodec = (destCtrl & 0x60) == 0x60 ? 1 : 0;
967: dspReceive.isConnectedToDsp = (destCtrl & 0x60) == 0x20 ? 1 : 0;
968: dspReceive.isConnectedToDma = (destCtrl & 0x60) == 0x00 ? 1 : 0;
969:
970: dmaRecord.isConnectedToCodec = (destCtrl & 0x6) == 0x6 ? 1 : 0;
971: dmaRecord.isConnectedToDsp = (destCtrl & 0x6) == 0x2 ? 1 : 0;
972: dmaRecord.isConnectedToDma = (destCtrl & 0x6) == 0x0 ? 1 : 0;
973:
974: dac.isConnectedToCodec = (destCtrl & 0x6000) == 0x6000 ? 1 : 0;
975: dac.isConnectedToDsp = (destCtrl & 0x6000) == 0x2000 ? 1 : 0;
976: dac.isConnectedToDma = (destCtrl & 0x6000) == 0x0000 ? 1 : 0;
977:
978: /* sources devices connexions */
979: dspXmit.isConnectedToCodec = (destCtrl & 0x6000) == 0x2000 ? 1 : 0;
980: dspXmit.isConnectedToDsp = (destCtrl & 0x60) == 0x20 ? 1 : 0;
981: dspXmit.isConnectedToDma = (destCtrl & 0x6) == 0x2 ? 1 : 0;
982:
983: dmaPlay.isConnectedToCodec = (destCtrl & 0x6000) == 0x0000 ? 1 : 0;
984: dmaPlay.isConnectedToDsp = (destCtrl & 0x60) == 0x00 ? 1 : 0;
985: dmaPlay.isConnectedToDma = (destCtrl & 0x6) == 0x0 ? 1 : 0;
986:
987: adc.isConnectedToCodec = (destCtrl & 0x6000) == 0x6000 ? 1 : 0;
988: adc.isConnectedToDsp = (destCtrl & 0x60) == 0x60 ? 1 : 0;
989: adc.isConnectedToDma = (destCtrl & 0x6) == 0x6 ? 1 : 0;
990:
1.1.1.2 root 991: dmaPlay.isConnectedToDspInHandShakeMode = (((destCtrl >> 4) & 7) == 0 ? 1 : 0);
1.1.1.3 root 992: dmaPlay.handshakeMode_Frame = dmaPlay.isConnectedToDspInHandShakeMode;
993:
1.1 root 994: dmaRecord.isConnectedToDspInHandShakeMode = ((destCtrl & 0xf) == 2 ? 1 : 0);
995: }
996:
997: /**
998: * Write byte to external clock divider register (0xff8934).
999: */
1000: void Crossbar_FreqDivExt_WriteByte(void)
1001: {
1002: LOG_TRACE(TRACE_CROSSBAR, "Crossbar : $ff8934 (ext. clock divider) write: 0x%02x\n", IoMem_ReadByte(0xff8934));
1003: }
1004:
1005: /**
1006: * Write byte to internal clock divider register (0xff8935).
1007: */
1008: void Crossbar_FreqDivInt_WriteByte(void)
1009: {
1010: Uint8 clkDiv = IoMem_ReadByte(0xff8935);
1011:
1012: LOG_TRACE(TRACE_CROSSBAR, "Crossbar : $ff8935 (int. clock divider) write: 0x%02x\n", clkDiv);
1013:
1014: crossbar.int_freq_divider = clkDiv & 0xf;
1015: Crossbar_Recalculate_Clocks_Cycles();
1016: }
1017:
1018: /**
1019: * Write byte to record track select register (0xff8936).
1020: * 0 = Record 1 track
1021: * 1 = Record 2 tracks
1022: * 2 = Record 3 tracks
1023: * 3 = Record 4 tracks
1024: */
1025: void Crossbar_TrackRecSelect_WriteByte(void)
1026: {
1027: Uint8 recTrack = IoMem_ReadByte(0xff8936);
1028:
1029: LOG_TRACE(TRACE_CROSSBAR, "Crossbar : $ff8936 (record track select) write: 0x%02x\n", recTrack);
1030:
1031: crossbar.recordTracks = recTrack & 3;
1032: }
1033:
1034: /**
1035: * Write byte to CODEC input source from 16 bit adder (0xff8937).
1036: * Bit 1 : source = multiplexer
1.1.1.7 ! root 1037: * Bit 0 : source = A/D convertor
1.1 root 1038: */
1039: void Crossbar_CodecInput_WriteByte(void)
1040: {
1041: Uint8 inputSource = IoMem_ReadByte(0xff8937);
1042:
1043: LOG_TRACE(TRACE_CROSSBAR, "Crossbar : $ff8937 (CODEC input) write: 0x%02x\n", IoMem_ReadByte(0xff8937));
1044:
1045: crossbar.codecInputSource = inputSource & 3;
1046: }
1047:
1048: /**
1049: * Write byte to A/D converter input for L+R channel (0xff8938).
1050: * Bit 1 : Left (0 = Microphone ; 1 = PSG soundchip)
1051: * Bit 0 : Right (0 = Microphone ; 1 = PSG soundchip)
1052: */
1053: void Crossbar_AdcInput_WriteByte(void)
1054: {
1055: Uint8 input = IoMem_ReadByte(0xff8938);
1056:
1057: LOG_TRACE(TRACE_CROSSBAR, "Crossbar : $ff8938 (ADC input) write: 0x%02x\n", IoMem_ReadByte(0xff8938));
1058:
1059: crossbar.codecAdcInput = input & 3;
1060: }
1061:
1062: /**
1063: * Write byte to input amplifier register (amplification for ADC device) (0xff8939).
1064: * Bits LLLLRRRR
1065: * Amplification is in +1.5 dB steps
1066: */
1067: void Crossbar_InputAmp_WriteByte(void)
1068: {
1069: Uint8 amplification = IoMem_ReadByte(0xff8939);
1070:
1071: LOG_TRACE(TRACE_CROSSBAR, "Crossbar : $ff8939 (CODEC channel amplification) write: 0x%02x\n", IoMem_ReadByte(0xff8939));
1072:
1073: crossbar.gainSettingLeft = Crossbar_ADC_volume_table[amplification >> 4];
1074: crossbar.gainSettingRight = Crossbar_ADC_volume_table[amplification & 0xf];
1075: }
1076:
1077: /**
1078: * Write byte to channel reduction register (attenuation for DAC device) (0xff893a).
1.1.1.5 root 1079: * Bits XXXXLLLL RRRRXXXX
1.1 root 1080: * Reduction is in -1.5 dB steps
1081: */
1.1.1.5 root 1082: void Crossbar_OutputReduct_WriteWord(void)
1.1 root 1083: {
1.1.1.5 root 1084: Uint16 reduction = IoMem_ReadWord(0xff893a);
1.1 root 1085:
1.1.1.5 root 1086: LOG_TRACE(TRACE_CROSSBAR, "Crossbar : $ff893a (CODEC channel attenuation) write: 0x%04x\n", reduction);
1.1 root 1087:
1.1.1.5 root 1088: crossbar.attenuationSettingLeft = Crossbar_DAC_volume_table[(reduction >> 8) & 0x0f];
1089: crossbar.attenuationSettingRight = Crossbar_DAC_volume_table[(reduction >> 4) & 0x0f];
1.1 root 1090: }
1091:
1092: /**
1093: * Write word to CODEC status register (0xff893c).
1094: * Bit 1 : Left Channel Overflow (0/1)
1095: * Bit 0 : Right Channel Overflow (0/1)
1096: */
1097: void Crossbar_CodecStatus_WriteWord(void)
1098: {
1099: LOG_TRACE(TRACE_CROSSBAR, "Crossbar : $ff893c (CODEC status) write: 0x%04x\n", IoMem_ReadWord(0xff893c));
1100: }
1101:
1102:
1103:
1104: /*----------------------------------------------------------------------*/
1105: /*------------------------- Crossbar functions -------------------------*/
1106: /*----------------------------------------------------------------------*/
1107:
1108: /**
1109: * Recalculates internal clocks 25 Mhz and 32 Mhz cycles
1110: */
1111: static void Crossbar_Recalculate_Clocks_Cycles(void)
1112: {
1113: double cyclesClk;
1114:
1115: crossbar.clock25_cycles_counter = 0;
1116: crossbar.clock32_cycles_counter = 0;
1117:
1118: /* Calculate 25 Mhz clock cycles */
1119: cyclesClk = ((double)CPU_FREQ / Crossbar_DetectSampleRate(25)) / (double)(crossbar.playTracks) / 2.0;
1120: crossbar.clock25_cycles = (int)(cyclesClk);
1121: crossbar.clock25_cycles_decimal = (int)((cyclesClk - (double)(crossbar.clock25_cycles)) * (double)DECIMAL_PRECISION);
1122:
1123: /* Calculate 32 Mhz clock cycles */
1124: cyclesClk = ((double)CPU_FREQ / Crossbar_DetectSampleRate(32)) / (double)(crossbar.playTracks) / 2.0;
1125: crossbar.clock32_cycles = (int)(cyclesClk);
1126: crossbar.clock32_cycles_decimal = (int)((cyclesClk - (double)(crossbar.clock32_cycles)) * (double)DECIMAL_PRECISION);
1.1.1.7 ! root 1127:
1.1 root 1128: LOG_TRACE(TRACE_CROSSBAR, "Crossbar : Recalculate_clock_Cycles\n");
1129: LOG_TRACE(TRACE_CROSSBAR, " clock25 : %d\n", crossbar.clock25_cycles);
1130: LOG_TRACE(TRACE_CROSSBAR, " clock32 : %d\n", crossbar.clock32_cycles);
1131:
1132: /* Verify if the new frequency doesn't mute the DAC */
1133: crossbar.isDacMuted = 0;
1134: if ((crossbar.int_freq_divider == 0) && (crossbar.steFreq == 0))
1135: crossbar.isDacMuted = 1;
1136:
1.1.1.7 ! root 1137: if ((crossbar.int_freq_divider == 6) || (crossbar.int_freq_divider == 8) ||
1.1 root 1138: (crossbar.int_freq_divider == 10) || (crossbar.int_freq_divider >= 12)) {
1139: crossbar.isDacMuted = 1;
1.1.1.4 root 1140: LOG_TRACE(TRACE_CROSSBAR, " DAC is muted\n");
1.1 root 1141: }
1.1.1.2 root 1142:
1143: // Compute Ratio between host computer sound frequency and Hatari's sound frequency.
1144: Crossbar_Compute_Ratio();
1145: }
1146:
1147: /**
1.1.1.7 ! root 1148: * Compute Ratio between host computer sound frequency and Hatari's DAC sound frequency and
1.1.1.4 root 1149: * ratio between hatari's DAC sound frequency and host's sound frequency.
1150: * Both values use << 32 to simulate floating point precision
1.1.1.2 root 1151: * Can be called by audio.c if a sound frequency value is changed in the parameter GUI.
1152: */
1153: void Crossbar_Compute_Ratio(void)
1154: {
1.1.1.4 root 1155: crossbar.frequence_ratio = ( ((Sint64)Crossbar_DetectSampleRate(25)) << 32) / nAudioFrequency;
1156: crossbar.frequence_ratio2 = ( ((Sint64)nAudioFrequency) << 32) / Crossbar_DetectSampleRate(25);
1.1 root 1157: }
1158:
1159: /**
1160: * Detect sample rate frequency
1161: * clock : value of the internal clock (25 or 32).
1162: */
1.1.1.4 root 1163: static int Crossbar_DetectSampleRate(Uint16 clock)
1.1 root 1164: {
1165: /* Ste compatible sound */
1166: if (crossbar.int_freq_divider == 0) {
1167: crossbar.isInSteFreqMode = 1;
1168: return Ste_SampleRates[crossbar.steFreq];
1169: }
1170:
1171: crossbar.isInSteFreqMode = 0;
1172:
1173: /* 25 Mhz internal clock */
1174: if (clock == 25)
1175: return Falcon_SampleRates_25Mhz[crossbar.int_freq_divider - 1];
1176:
1177: /* 32 Mhz internal clock */
1178: return Falcon_SampleRates_32Mhz[crossbar.int_freq_divider - 1];
1179: }
1180:
1181: /**
1182: * Start internal 25 Mhz clock interrupt.
1183: */
1184: static void Crossbar_Start_InterruptHandler_25Mhz(void)
1185: {
1186: Uint32 cycles_25;
1.1.1.7 ! root 1187:
1.1 root 1188: cycles_25 = crossbar.clock25_cycles;
1189: crossbar.clock25_cycles_counter += crossbar.clock25_cycles_decimal;
1.1.1.7 ! root 1190:
1.1 root 1191: if (crossbar.clock25_cycles_counter >= DECIMAL_PRECISION) {
1192: crossbar.clock25_cycles_counter -= DECIMAL_PRECISION;
1193: cycles_25 ++;
1194: }
1195:
1196: if (crossbar.pendingCyclesOver25 >= cycles_25) {
1197: crossbar.pendingCyclesOver25 -= cycles_25;
1198: cycles_25 = 0;
1199: }
1200: else {
1201: cycles_25 -= crossbar.pendingCyclesOver25;
1202: crossbar.pendingCyclesOver25 = 0;
1203: }
1204:
1205: CycInt_AddRelativeInterrupt(cycles_25, INT_CPU_CYCLE, INTERRUPT_CROSSBAR_25MHZ);
1206: }
1207:
1208: /**
1209: * Start internal 32 Mhz clock interrupt.
1210: */
1211: static void Crossbar_Start_InterruptHandler_32Mhz(void)
1212: {
1213: Uint32 cycles_32;
1.1.1.7 ! root 1214:
1.1 root 1215: cycles_32 = crossbar.clock32_cycles;
1216: crossbar.clock32_cycles_counter += crossbar.clock32_cycles_decimal;
1217:
1218: if (crossbar.clock32_cycles_counter >= DECIMAL_PRECISION) {
1219: crossbar.clock32_cycles_counter -= DECIMAL_PRECISION;
1220: cycles_32 ++;
1221: }
1222:
1223: if (crossbar.pendingCyclesOver32 >= cycles_32){
1224: crossbar.pendingCyclesOver32 -= cycles_32;
1225: cycles_32 = 0;
1226: }
1227: else {
1228: cycles_32 -= crossbar.pendingCyclesOver32;
1229: crossbar.pendingCyclesOver32 = 0;
1230: }
1231:
1232: CycInt_AddRelativeInterrupt(cycles_32, INT_CPU_CYCLE, INTERRUPT_CROSSBAR_32MHZ);
1233: }
1234:
1235:
1236: /**
1237: * Execute transfers for internal 25 Mhz clock.
1238: */
1239: void Crossbar_InterruptHandler_25Mhz(void)
1240: {
1241: /* How many cycle was this sound interrupt delayed (>= 0) */
1242: crossbar.pendingCyclesOver25 += -INT_CONVERT_FROM_INTERNAL ( PendingInterruptCount , INT_CPU_CYCLE );
1243:
1244: /* Remove this interrupt from list and re-order */
1245: CycInt_AcknowledgeInterrupt();
1246:
1247: /* If transfer mode is in Ste mode, use only this clock for all the transfers */
1248: if (crossbar.isInSteFreqMode) {
1249: Crossbar_Process_DSPXmit_Transfer();
1250: Crossbar_Process_DMAPlay_Transfer();
1251: Crossbar_Process_ADCXmit_Transfer();
1.1.1.7 ! root 1252:
1.1 root 1253: /* Restart the 25 Mhz clock interrupt */
1254: Crossbar_Start_InterruptHandler_25Mhz();
1255: return;
1256: }
1257:
1258: Crossbar_Process_ADCXmit_Transfer();
1.1.1.7 ! root 1259:
1.1 root 1260: /* DSP Play transfer ? */
1261: if (crossbar.dspXmit_freq == CROSSBAR_FREQ_25MHZ) {
1262: Crossbar_Process_DSPXmit_Transfer();
1263: }
1.1.1.7 ! root 1264:
1.1 root 1265: /* DMA Play transfer ? */
1266: if (crossbar.dmaPlay_freq == CROSSBAR_FREQ_25MHZ) {
1267: Crossbar_Process_DMAPlay_Transfer();
1268: }
1269:
1270: /* Restart the 25 Mhz clock interrupt */
1271: Crossbar_Start_InterruptHandler_25Mhz();
1272: }
1273:
1274: /**
1275: * Execute transfers for internal 32 Mhz clock.
1276: */
1277: void Crossbar_InterruptHandler_32Mhz(void)
1278: {
1279: /* How many cycle was this sound interrupt delayed (>= 0) */
1280: crossbar.pendingCyclesOver32 += -INT_CONVERT_FROM_INTERNAL ( PendingInterruptCount , INT_CPU_CYCLE );
1281:
1282: /* Remove this interrupt from list and re-order */
1283: CycInt_AcknowledgeInterrupt();
1284:
1285: /* If transfer mode is in Ste mode, don't use this clock for all the transfers */
1286: if (crossbar.isInSteFreqMode) {
1287: /* Restart the 32 Mhz clock interrupt */
1288: Crossbar_Start_InterruptHandler_32Mhz();
1289: return;
1290: }
1.1.1.7 ! root 1291:
1.1 root 1292: /* DSP Play transfer ? */
1293: if (crossbar.dspXmit_freq == CROSSBAR_FREQ_32MHZ) {
1294: Crossbar_Process_DSPXmit_Transfer();
1295: }
1.1.1.7 ! root 1296:
1.1 root 1297: /* DMA Play transfer ? */
1298: if (crossbar.dmaPlay_freq == CROSSBAR_FREQ_32MHZ) {
1299: Crossbar_Process_DMAPlay_Transfer();
1300: }
1301:
1302: /* Restart the 32 Mhz clock interrupt */
1303: Crossbar_Start_InterruptHandler_32Mhz();
1304: }
1305:
1306:
1307: /*----------------------------------------------------------------------*/
1308: /*--------------------- DSP Xmit processing ----------------------------*/
1309: /*----------------------------------------------------------------------*/
1310:
1311: /**
1312: * Process DSP xmit to crossbar transfer
1313: */
1314: static void Crossbar_Process_DSPXmit_Transfer(void)
1315: {
1316: Uint16 frame=0;
1317: Sint32 data;
1.1.1.7 ! root 1318:
1.1.1.2 root 1319: /* If DSP Xmit is tristated, do nothing */
1320: if (dspXmit.isTristated)
1321: return;
1.1 root 1322:
1323: /* Is DSP Xmit connected to DMA Record in handshake mode ? */
1324: if (dmaRecord.isConnectedToDspInHandShakeMode) {
1325: Crossbar_Process_DMARecord_HandshakeMode();
1326: return;
1327: }
1328:
1329: /* Is DSP Xmit connected to something ? */
1330: if (!dspXmit.isConnectedToCodec && !dspXmit.isConnectedToDma && !dspXmit.isConnectedToDsp)
1331: return;
1332:
1333: if (dspXmit.wordCount == 0) {
1334: frame = 1;
1335: }
1336:
1337: /* Send the frame status to the DSP SSI Xmit */
1338: DSP_SsiReceive_SC2(frame);
1339:
1340: /* Send the clock to the DSP SSI Xmit */
1341: DSP_SsiReceive_SCK();
1342:
1343: /* read data from DSP Xmit */
1344: data = DSP_SsiReadTxValue();
1345:
1.1.1.4 root 1346: LOG_TRACE(TRACE_CROSSBAR, "Crossbar : DSP --> Crossbar transfer\t0x%06x\n", data);
1347:
1.1 root 1348: /* Send DSP data to the DAC ? */
1349: if (dspXmit.isConnectedToCodec) {
1350: Crossbar_SendDataToDAC(data, dspXmit.wordCount);
1351: }
1352:
1353: /* Send DSP data to the DMA record ? */
1354: if (dspXmit.isConnectedToDma) {
1355: Crossbar_SendDataToDmaRecord(data);
1356: }
1357:
1358: /* Send DSP data to the DSP in ? */
1359: if (dspXmit.isConnectedToDsp) {
1360: Crossbar_SendDataToDspReceive(data, frame);
1361: }
1362:
1363: /* increase dspXmit.wordCount for next sample */
1364: dspXmit.wordCount++;
1365: if (dspXmit.wordCount >= (crossbar.playTracks * 2)) {
1366: dspXmit.wordCount = 0;
1367: }
1368: }
1369:
1370: /*----------------------------------------------------------------------*/
1371: /*--------------------- DSP Receive processing -------------------------*/
1372: /*----------------------------------------------------------------------*/
1373:
1374: /**
1375: * Transmit data from crossbar to DSP receive.
1376: */
1377: static void Crossbar_SendDataToDspReceive(Uint32 value, Uint16 frame)
1378: {
1379: /* Verify that DSP IN is not tristated */
1380: if (dspReceive.isTristated) {
1381: return;
1382: }
1383:
1384: /* Send sample to DSP receive */
1385: DSP_SsiWriteRxValue(value);
1386:
1387: /* Send the frame status to the DSP SSI receive */
1388: /* only in non hanshake mode */
1389: if (dmaPlay.handshakeMode_Frame == 0) {
1390: DSP_SsiReceive_SC1(frame);
1391: }
1392:
1393: dmaPlay.handshakeMode_Frame = 0;
1.1.1.7 ! root 1394:
1.1 root 1395: /* Send the clock to the DSP SSI receive */
1396: DSP_SsiReceive_SC0();
1397: }
1398:
1399: /*----------------------------------------------------------------------*/
1400: /*--------------------- DMA PLAY sound processing ----------------------*/
1401: /*----------------------------------------------------------------------*/
1402:
1403: /**
1404: * Set DMA Play sound start frame buffer, stop frame buffer, frame length
1405: */
1406: static void Crossbar_setDmaPlay_Settings(void)
1407: {
1408: /* DMA setings */
1409: dmaPlay.frameStartAddr = crossbar.dmaPlay_CurrentFrameStart;
1410: dmaPlay.frameEndAddr = crossbar.dmaPlay_CurrentFrameEnd;
1411: dmaPlay.frameLen = dmaPlay.frameEndAddr - dmaPlay.frameStartAddr;
1412: // dmaPlay.frameCounter = crossbar.dmaPlay_CurrentFrameCount - crossbar.dmaPlay_CurrentFrameStart;
1413: dmaPlay.frameCounter = 0;
1414:
1415: if (dmaPlay.frameEndAddr <= dmaPlay.frameStartAddr)
1416: {
1417: Log_Printf(LOG_WARN, "crossbar DMA Play: Illegal buffer size (from 0x%06x to 0x%06x)\n",
1418: dmaPlay.frameStartAddr, dmaPlay.frameEndAddr);
1419: }
1420: }
1421:
1422: /**
1423: * Process DMA Play transfer to crossbar
1424: */
1425: static void Crossbar_Process_DMAPlay_Transfer(void)
1426: {
1.1.1.2 root 1427: Uint16 temp, increment_frame;
1.1 root 1428: Sint16 value, eightBits;
1429: Sint8 *pFrameStart;
1430: Uint8 dmaCtrlReg;
1.1.1.7 ! root 1431:
1.1 root 1432: /* if DMA play is not running, return */
1433: if (dmaPlay.isRunning == 0)
1434: return;
1435:
1436: pFrameStart = (Sint8 *)&STRam[dmaPlay.frameStartAddr];
1.1.1.2 root 1437: increment_frame = 0;
1.1.1.7 ! root 1438:
1.1 root 1439: /* 16 bits stereo mode ? */
1440: if (crossbar.is16Bits) {
1441: eightBits = 1;
1442: value = (Sint16)do_get_mem_word(&pFrameStart[dmaPlay.frameCounter]);
1.1.1.2 root 1443: increment_frame = 2;
1.1 root 1444: }
1445: /* 8 bits stereo ? */
1446: else if (crossbar.isStereo) {
1447: eightBits = 64;
1448: value = (Sint16) pFrameStart[dmaPlay.frameCounter];
1.1.1.2 root 1449: increment_frame = 1;
1.1 root 1450: }
1451: /* 8 bits mono */
1452: else {
1453: eightBits = 64;
1454: value = (Sint16) pFrameStart[dmaPlay.frameCounter];
1455: if ((dmaPlay.currentFrame & 1) == 0) {
1.1.1.2 root 1456: increment_frame = 1;
1.1 root 1457: }
1458: }
1.1.1.2 root 1459:
1.1.1.3 root 1460: if (dmaPlay.isConnectedToDspInHandShakeMode) {
1461: /* Handshake mode */
1.1.1.2 root 1462: if (dmaPlay.handshakeMode_Frame == 0)
1463: return;
1464:
1465: dmaPlay.frameCounter += increment_frame;
1466:
1.1.1.7 ! root 1467: /* Special undocumented transfer mode :
1.1.1.3 root 1468: When DMA Play --> DSP Receive is in HandShake mode at 32 Mhz,
1.1.1.2 root 1469: datas are shifted 2 bits on the left after the transfer.
1.1.1.7 ! root 1470: This occurs with all demos using the Mpeg2 player from nocrew (amanita, LostBlubb, Wait, ...)
1.1.1.2 root 1471: */
1.1.1.3 root 1472: if (crossbar.dmaPlay_freq == CROSSBAR_FREQ_32MHZ) {
1473: temp = (crossbar.save_special_transfer<<2) + ((value & 0xc000)>>14);
1474: crossbar.save_special_transfer = value;
1475: value = temp;
1476: }
1.1.1.2 root 1477: }
1478: else {
1.1.1.3 root 1479: /* Non Handshake mode */
1.1.1.2 root 1480: dmaPlay.frameCounter += increment_frame;
1481: }
1482:
1.1 root 1483: /* Send sample to the DMA record ? */
1484: if (dmaPlay.isConnectedToDma) {
1485: LOG_TRACE(TRACE_CROSSBAR, "Crossbar : DMA Play --> DMA record\n");
1486: Crossbar_SendDataToDmaRecord(value);
1487: }
1488:
1489: /* Send sample to the DAC ? */
1490: if (dmaPlay.isConnectedToCodec) {
1491: LOG_TRACE(TRACE_CROSSBAR, "Crossbar : DMA Play --> DAC\n");
1492: Crossbar_SendDataToDAC(value * eightBits, dmaPlay.currentFrame);
1493: }
1494:
1495: /* Send sample to the DSP in ? */
1496: if (dmaPlay.isConnectedToDsp) {
1497: LOG_TRACE(TRACE_CROSSBAR, "Crossbar : DMA Play --> DSP record\n");
1498: /* New frame ? */
1499: if (dmaPlay.currentFrame == 0) {
1500: Crossbar_SendDataToDspReceive(value, 1);
1501: }
1502: else {
1503: Crossbar_SendDataToDspReceive(value, 0);
1504: }
1505: }
1506:
1507: /* increase dmaPlay.currentFrame for next sample */
1508: dmaPlay.currentFrame ++;
1509: if (dmaPlay.currentFrame >= (crossbar.playTracks * 2)) {
1510: dmaPlay.currentFrame = 0;
1511: }
1512:
1513: /* Check if end-of-frame has been reached and raise interrupts if needed. */
1514: if (dmaPlay.frameCounter >= dmaPlay.frameLen)
1.1.1.7 ! root 1515: {
1.1 root 1516: /* Send a MFP15_Int (I7) at end of replay buffer if enabled */
1517: if (dmaPlay.mfp15_int) {
1.1.1.5 root 1518: MFP_InputOnChannel ( MFP_INT_GPIP7 , 0 );
1.1 root 1519: LOG_TRACE(TRACE_CROSSBAR, "Crossbar : MFP15 (IT7) interrupt from DMA play\n");
1520: }
1521:
1522: /* Send a TimerA_Int at end of replay buffer if enabled */
1523: if (dmaPlay.timerA_int) {
1524: if (MFP_TACR == 0x08) { /* Is timer A in Event Count mode? */
1525: MFP_TimerA_EventCount_Interrupt();
1526: LOG_TRACE(TRACE_CROSSBAR, "Crossbar : MFP Timer A interrupt from DMA play\n");
1527: }
1528: }
1529:
1530: if (dmaPlay.loopMode) {
1531: Crossbar_setDmaPlay_Settings();
1.1.1.7 ! root 1532: }
1.1 root 1533: else {
1.1.1.2 root 1534: /* Create samples up until this point with current values */
1535: Sound_Update(false);
1536:
1.1 root 1537: dmaCtrlReg = IoMem_ReadByte(0xff8901) & 0xfe;
1.1.1.2 root 1538: IoMem_WriteByte(0xff8901, dmaCtrlReg);
1539:
1540: /* Turning off DMA play sound emulation */
1541: dmaPlay.isRunning = 0;
1542: dmaPlay.loopMode = 0;
1543: nCbar_DmaSoundControl = dmaCtrlReg;
1.1 root 1544: }
1545: }
1546: }
1547:
1548: /**
1549: * Function called when DmaPlay is in handshake mode */
1550: void Crossbar_DmaPlayInHandShakeMode(void)
1551: {
1552: dmaPlay.handshakeMode_Frame = 1;
1553: }
1554:
1555: /*----------------------------------------------------------------------*/
1556: /*--------------------- DMA Record processing --------------------------*/
1557: /*----------------------------------------------------------------------*/
1558:
1559: /**
1560: * Set DMA Record sound start frame buffer, stop frame buffer, frame length
1561: */
1562: static void Crossbar_setDmaRecord_Settings(void)
1563: {
1564: /* DMA setings */
1565: dmaRecord.frameStartAddr = crossbar.dmaRecord_CurrentFrameStart;
1566: dmaRecord.frameEndAddr = crossbar.dmaRecord_CurrentFrameEnd;
1567: dmaRecord.frameLen = dmaRecord.frameEndAddr - dmaRecord.frameStartAddr;
1568: // dmaRecord.frameCounter = crossbar.dmaRecord_CurrentFrameCount - crossbar.dmaRecord_CurrentFrameStart;
1569: dmaRecord.frameCounter = 0;
1570:
1571: if (dmaRecord.frameEndAddr <= dmaRecord.frameStartAddr) {
1572: Log_Printf(LOG_WARN, "crossbar DMA Record: Illegal buffer size (from 0x%06x to 0x%06x)\n",
1573: dmaRecord.frameStartAddr, dmaRecord.frameEndAddr);
1574: }
1575: }
1576:
1577: /**
1578: * DMA Record processing
1579: */
1580: void Crossbar_SendDataToDmaRecord(Sint16 value)
1581: {
1582: Sint8 *pFrameStart;
1583: Uint8 dmaCtrlReg;
1584:
1585: if (dmaRecord.isRunning == 0) {
1586: return;
1587: }
1.1.1.7 ! root 1588:
1.1 root 1589: pFrameStart = (Sint8 *)&STRam[dmaRecord.frameStartAddr];
1590:
1591: /* 16 bits stereo mode ? */
1592: if (crossbar.is16Bits) {
1593: do_put_mem_word(&pFrameStart[dmaRecord.frameCounter], value);
1594: dmaRecord.frameCounter += 2;
1595: }
1596: /* 8 bits stereo ? */
1597: else if (crossbar.isStereo) {
1598: do_put_mem_word(&pFrameStart[dmaRecord.frameCounter], value);
1599: dmaRecord.frameCounter += 2;
1600: // pFrameStart[dmaRecord.frameCounter] = (Uint8)value;
1601: // dmaRecord.frameCounter ++;
1602: }
1603: /* 8 bits mono */
1604: else {
1605: pFrameStart[dmaRecord.frameCounter] = (Uint8)value;
1606: dmaRecord.frameCounter ++;
1607: }
1608:
1609: /* Check if end-of-frame has been reached and raise interrupts if needed. */
1610: if (dmaRecord.frameCounter >= dmaRecord.frameLen)
1611: {
1612: /* Send a MFP15_Int (I7) at end of record buffer if enabled */
1613: if (dmaRecord.mfp15_int) {
1.1.1.5 root 1614: MFP_InputOnChannel ( MFP_INT_GPIP7 , 0 );
1.1 root 1615: LOG_TRACE(TRACE_CROSSBAR, "Crossbar : MFP15 (IT7) interrupt from DMA record\n");
1616: }
1.1.1.7 ! root 1617:
1.1 root 1618: /* Send a TimerA_Int at end of record buffer if enabled */
1619: if (dmaRecord.timerA_int) {
1620: if (MFP_TACR == 0x08) /* Is timer A in Event Count mode? */
1621: MFP_TimerA_EventCount_Interrupt();
1.1.1.7 ! root 1622: LOG_TRACE(TRACE_CROSSBAR, "Crossbar : MFP Timer A interrupt from DMA record\n");
1.1 root 1623: }
1624:
1625: if (dmaRecord.loopMode) {
1626: Crossbar_setDmaRecord_Settings();
1627: }
1628: else {
1629: dmaCtrlReg = IoMem_ReadByte(0xff8901) & 0xef;
1.1.1.2 root 1630: IoMem_WriteByte(0xff8901, dmaCtrlReg);
1631:
1632: /* Turning off DMA record sound emulation */
1633: dmaRecord.isRunning = 0;
1634: dmaRecord.loopMode = 0;
1635: nCbar_DmaSoundControl = dmaCtrlReg;
1.1 root 1636: }
1637: }
1638: }
1639:
1640:
1641: /**
1642: * Process DMA Record connected to DSP Xmit in HandShake mode.
1643: * In this special case, DMA Record is the "master" and Dsp Xmit is the "slave".
1644: */
1645: static void Crossbar_Process_DMARecord_HandshakeMode(void)
1646: {
1647: Sint16 data;
1648:
1649: /* If DMA record is activated and is running */
1650: if (dmaRecord.isRunning == 0) {
1651: return;
1652: }
1653:
1654: /* If DSP frame is activated (SC2 pin of the SSI port) */
1655: if (dmaRecord.handshakeMode_Frame == 0) {
1656: return;
1657: }
1658:
1659: /* Send the clock to the DSP SSI Xmit */
1660: DSP_SsiReceive_SCK();
1661:
1662: /* read data from DSP Xmit */
1663: data = DSP_SsiReadTxValue();
1664: dmaRecord.handshakeMode_Frame = 0;
1.1.1.7 ! root 1665:
1.1 root 1666: Crossbar_SendDataToDmaRecord(data);
1667: }
1668:
1669: /**
1670: * Get the frame value from DSP SSI (handshake mode only)
1671: */
1672: void Crossbar_DmaRecordInHandShakeMode_Frame(Uint32 frame)
1673: {
1674: dmaRecord.handshakeMode_Frame = frame;
1675: }
1676:
1677:
1678: /*----------------------------------------------------------------------*/
1679: /*-------------------------- ADC processing ----------------------------*/
1680: /*----------------------------------------------------------------------*/
1681:
1682: /**
1683: * Get datas recorded by the microphone and convert them into falcon internal frequency
1684: * - micro_bufferL : left track recorded by the microphone
1685: * - micro_bufferR : right track recorded by the microphone
1686: * - microBuffer_size : buffers size
1687: */
1688: void Crossbar_GetMicrophoneDatas(Sint16 *micro_bufferL, Sint16 *micro_bufferR, Uint32 microBuffer_size)
1689: {
1.1.1.4 root 1690: Uint32 i, size, bufferIndex;
1691: Sint64 idxPos;
1.1 root 1692:
1.1.1.4 root 1693: size = (microBuffer_size * crossbar.frequence_ratio>>32);
1.1 root 1694: bufferIndex = 0;
1.1.1.4 root 1695: idxPos = 0;
1696:
1.1 root 1697: for (i = 0; i < size; i++) {
1698: adc.writePosition = (adc.writePosition + 1) % DACBUFFER_SIZE;
1699:
1700: adc.buffer_left[adc.writePosition] = micro_bufferL[bufferIndex];
1.1.1.7 ! root 1701: adc.buffer_right[adc.writePosition] = micro_bufferR[bufferIndex];
1.1 root 1702:
1.1.1.4 root 1703: idxPos += crossbar.frequence_ratio2;
1.1.1.7 ! root 1704: bufferIndex += idxPos>>32;
1.1.1.4 root 1705: idxPos &= 0xffffffff; /* only keep the fractional part */
1.1 root 1706: }
1707: }
1708:
1709: /**
1710: * Process ADC transfer to crossbar
1711: */
1712: static void Crossbar_Process_ADCXmit_Transfer(void)
1713: {
1714: Sint16 sample;
1715: Uint16 frame;
1.1.1.7 ! root 1716:
1.1 root 1717: /* swap from left to right channel or right to left channel */
1718: adc.wordCount = 1 - adc.wordCount;
1.1.1.7 ! root 1719:
1.1 root 1720: /* Left Channel */
1721: if (adc.wordCount == 0) {
1722: sample = adc.buffer_left[adc.readPosition];
1723: frame = 1;
1724: }
1725: else {
1726: sample = adc.buffer_right[adc.readPosition];
1727: adc.readPosition = (adc.readPosition + 1) % DACBUFFER_SIZE;
1728: frame = 0;
1729: }
1.1.1.7 ! root 1730:
1.1 root 1731: /* Send sample to DSP receive ? */
1732: if (adc.isConnectedToDsp) {
1733: Crossbar_SendDataToDspReceive(sample, frame);
1734: }
1.1.1.7 ! root 1735:
1.1 root 1736: /* Send sample to DMA record ? */
1737: if (adc.isConnectedToDma) {
1738: Crossbar_SendDataToDmaRecord(sample);
1739: }
1740:
1741: /* Send sample to DAC ? */
1742: if (adc.isConnectedToCodec) {
1743: Crossbar_SendDataToDAC(sample, adc.wordCount);
1744: }
1745: }
1746:
1747:
1748: /*----------------------------------------------------------------------*/
1749: /*-------------------------- DAC processing ----------------------------*/
1750: /*----------------------------------------------------------------------*/
1751:
1752: /**
1753: * Put sample from crossbar into the DAC buffer.
1754: * - value : sample value to play
1755: * - sample_pos : position of the sample in the track (used to play the monitored track)
1756: */
1757: static void Crossbar_SendDataToDAC(Sint16 value, Uint16 sample_pos)
1758: {
1759: Uint16 track = crossbar.track_monitored * 2;
1760:
1761: if (sample_pos == track) {
1762: /* Left channel */
1763: dac.buffer_left[dac.writePosition] = value;
1764: }
1765: else if (sample_pos == track + 1) {
1766: /* Right channel */
1767: dac.buffer_right[dac.writePosition] = value;
1768: dac.writePosition = (dac.writePosition + 1) % (DACBUFFER_SIZE);
1769: }
1770: }
1771:
1772: /**
1.1.1.7 ! root 1773: * Mix PSG sound with microphone sound in ADC.
1.1 root 1774: * Also mix ADC sound sample with the crossbar DAC samples.
1775: * (Called by sound.c)
1776: */
1777: void Crossbar_GenerateSamples(int nMixBufIdx, int nSamplesToGenerate)
1778: {
1.1.1.6 root 1779: int i, j, nBufIdx;
1780: int n;
1.1 root 1781: Sint16 adc_leftData, adc_rightData, dac_LeftData, dac_RightData;
1.1.1.7 ! root 1782:
1.1 root 1783: if (crossbar.isDacMuted) {
1784: /* Output sound = 0 */
1785: for (i = 0; i < nSamplesToGenerate; i++) {
1786: nBufIdx = (nMixBufIdx + i) % MIXBUFFER_SIZE;
1787: MixBuffer[nBufIdx][0] = 0;
1788: MixBuffer[nBufIdx][1] = 0;
1789: }
1790:
1791: /* Counters are refreshed for when DAC becomes unmuted */
1792: dac.readPosition = dac.writePosition;
1.1.1.4 root 1793: crossbar.adc2dac_readBufferPosition = adc.writePosition;
1.1 root 1794: return;
1795: }
1796:
1797: for (i = 0; i < nSamplesToGenerate; i++)
1798: {
1799: nBufIdx = (nMixBufIdx + i) % MIXBUFFER_SIZE;
1800:
1801: /* ADC mixing (PSG sound or microphone sound for left and right channels) */
1802: switch (crossbar.codecAdcInput) {
1803: case 0:
1804: default: /* Just here to remove compiler's warnings */
1805: /* Microphone sound for left and right channels */
1.1.1.4 root 1806: adc_leftData = adc.buffer_left[crossbar.adc2dac_readBufferPosition];
1807: adc_rightData = adc.buffer_right[crossbar.adc2dac_readBufferPosition];
1.1 root 1808: break;
1809: case 1:
1810: /* Microphone sound for left channel, PSG sound for right channel */
1.1.1.4 root 1811: adc_leftData = adc.buffer_left[crossbar.adc2dac_readBufferPosition];
1.1 root 1812: adc_rightData = MixBuffer[nBufIdx][1];
1813: break;
1814: case 2:
1815: /* PSG sound for left channel, microphone sound for right channel */
1816: adc_leftData = MixBuffer[nBufIdx][0];
1.1.1.4 root 1817: adc_rightData = adc.buffer_right[crossbar.adc2dac_readBufferPosition];
1.1 root 1818: break;
1819: case 3:
1820: /* PSG sound for left and right channels */
1821: adc_leftData = MixBuffer[nBufIdx][0];
1822: adc_rightData = MixBuffer[nBufIdx][1];
1823: break;
1824: }
1825:
1826: /* DAC mixing (direct ADC + crossbar) */
1827: switch (crossbar.codecInputSource) {
1828: case 0:
1829: default: /* Just here to remove compiler's warnings */
1830: /* No sound */
1831: dac_LeftData = 0;
1832: dac_RightData = 0;
1833: break;
1834: case 1:
1835: /* direct ADC->DAC sound only ADC*4/65536 */
1836: dac_LeftData = (adc_leftData * crossbar.gainSettingLeft) >> 14;
1837: dac_RightData = (adc_rightData * crossbar.gainSettingRight) >> 14;
1838: break;
1839: case 2:
1840: /* Crossbar->DAC sound only */
1841: dac_LeftData = dac.buffer_left[dac.readPosition];
1842: dac_RightData = dac.buffer_right[dac.readPosition];
1843: break;
1844: case 3:
1845: /* Mixing Direct ADC sound with Crossbar->DMA sound */
1846: dac_LeftData = ((adc_leftData * crossbar.gainSettingLeft) >> 14) +
1847: dac.buffer_left[dac.readPosition];
1848: dac_RightData = ((adc_rightData * crossbar.gainSettingRight) >> 14) +
1849: dac.buffer_right[dac.readPosition];
1850: break;
1851: }
1.1.1.7 ! root 1852:
1.1 root 1853: MixBuffer[nBufIdx][0] = (dac_LeftData * crossbar.attenuationSettingLeft) >> 16;
1854: MixBuffer[nBufIdx][1] = (dac_RightData * crossbar.attenuationSettingRight) >> 16;
1855:
1.1.1.7 ! root 1856: /* Upgrade dac's buffer read pointer */
1.1.1.4 root 1857: dac.readPosition_float += crossbar.frequence_ratio;
1858: n = dac.readPosition_float >> 32; /* number of samples to skip */
1.1.1.6 root 1859:
1860: if (n) {
1861: // It becomes safe to zero old data if tail has moved
1862: for (j=0; j<n; j++) {
1863: dac.buffer_left[(dac.readPosition+j) % DACBUFFER_SIZE] = 0;
1864: dac.buffer_right[(dac.readPosition+j) % DACBUFFER_SIZE] = 0;
1865: }
1866: }
1867:
1.1.1.4 root 1868: dac.readPosition = (dac.readPosition + n) % DACBUFFER_SIZE;
1869: dac.readPosition_float &= 0xffffffff; /* only keep the fractional part */
1.1.1.7 ! root 1870:
! 1871: /* Upgrade adc->dac's buffer read pointer */
1.1.1.4 root 1872: crossbar.adc2dac_readBufferPosition_float += crossbar.frequence_ratio;
1873: n = crossbar.adc2dac_readBufferPosition_float >> 32; /* number of samples to skip */
1874: crossbar.adc2dac_readBufferPosition = (crossbar.adc2dac_readBufferPosition + n) % DACBUFFER_SIZE;
1875: crossbar.adc2dac_readBufferPosition_float &= 0xffffffff; /* only keep the fractional part */
1.1 root 1876: }
1877: }
1.1.1.6 root 1878:
1879:
1880: /**
1881: * display the Crossbar registers values (for debugger info command)
1882: */
1.1.1.7 ! root 1883: void Crossbar_Info(FILE *fp, Uint32 dummy)
1.1.1.6 root 1884: {
1885: char matrixDMA[5], matrixDAC[5], matrixDSP[5], matrixEXT[5];
1886: char frqDMA[11], frqDAC[11], frqDSP[11], frqEXT[11];
1887: char frqSTE[30], frq25Mhz[30], frq32Mhz[30];
1888: char dataSize[15];
1.1.1.7 ! root 1889:
1.1.1.6 root 1890: static const Uint32 Ste_SampleRates[4] = {
1891: 6258, 12517, 25033, 50066
1892: };
1893:
1894: static const Uint32 Falcon_SampleRates_25Mhz[15] = {
1895: 49170, 32780, 24585, 19668, 16390, 14049, 12292, 10927, 9834, 8940, 8195, 7565, 7024, 6556, 6146
1896: };
1897:
1898: static const Uint32 Falcon_SampleRates_32Mhz[15] = {
1899: 62500, 41666, 31250, 25000, 20833, 17857, 15624, 13889, 12500, 11363, 10416, 9615, 8928, 8333, 7812
1900: };
1901:
1902: if (ConfigureParams.System.nMachineType != MACHINE_FALCON) {
1.1.1.7 ! root 1903: fprintf(fp, "Not Falcon - no Crossbar!\n");
1.1.1.6 root 1904: return;
1905: }
1906:
1.1.1.7 ! root 1907: fprintf(fp, "$FF8900.b : Sound DMA control : %02x\n", IoMem_ReadByte(0xff8900));
! 1908: fprintf(fp, "$FF8901.b : Sound DMA control : %02x\n", IoMem_ReadByte(0xff8901));
! 1909: fprintf(fp, "$FF8903.b : Frame Start High : %02x\n", IoMem_ReadByte(0xff8903));
! 1910: fprintf(fp, "$FF8905.b : Frame Start middle : %02x\n", IoMem_ReadByte(0xff8905));
! 1911: fprintf(fp, "$FF8907.b : Frame Start low : %02x\n", IoMem_ReadByte(0xff8907));
! 1912: fprintf(fp, "$FF8909.b : Frame Count High : %02x\n", IoMem_ReadByte(0xff8909));
! 1913: fprintf(fp, "$FF890B.b : Frame Count middle : %02x\n", IoMem_ReadByte(0xff890b));
! 1914: fprintf(fp, "$FF890D.b : Frame Count low : %02x\n", IoMem_ReadByte(0xff890d));
! 1915: fprintf(fp, "$FF890F.b : Frame End High : %02x\n", IoMem_ReadByte(0xff890f));
! 1916: fprintf(fp, "$FF8911.b : Frame End middle : %02x\n", IoMem_ReadByte(0xff8911));
! 1917: fprintf(fp, "$FF8913.b : Frame End low : %02x\n", IoMem_ReadByte(0xff8913));
! 1918: fprintf(fp, "\n");
! 1919: fprintf(fp, "$FF8920.b : Sound Mode Control : %02x\n", IoMem_ReadByte(0xff8920));
! 1920: fprintf(fp, "$FF8921.b : Sound Mode Control : %02x\n", IoMem_ReadByte(0xff8921));
! 1921: fprintf(fp, "$FF8930.w : DMA Crossbar Input Select Controller : %04x\n", IoMem_ReadWord(0xff8930));
! 1922: fprintf(fp, "$FF8932.w : DMA Crossbar Output Select Controller : %04x\n", IoMem_ReadWord(0xff8932));
! 1923: fprintf(fp, "\n");
! 1924: fprintf(fp, "$FF8934.b : External Sync Frequency Divider : %02x\n", IoMem_ReadByte(0xff8934));
! 1925: fprintf(fp, "$FF8935.b : Internal Sync Frequency Divider : %02x\n", IoMem_ReadByte(0xff8935));
! 1926: fprintf(fp, "$FF8936.b : Record Track select : %02x\n", IoMem_ReadByte(0xff8936));
! 1927: fprintf(fp, "$FF8937.b : Codec Input Source : %02x\n", IoMem_ReadByte(0xff8937));
! 1928: fprintf(fp, "$FF8938.b : Codec ADC Input : %02x\n", IoMem_ReadByte(0xff8938));
! 1929: fprintf(fp, "$FF8939.b : Gain Settings Per Channel : %02x\n", IoMem_ReadByte(0xff8939));
! 1930: fprintf(fp, "$FF893A.b : Attenuation Settings Per Channel : %02x\n", IoMem_ReadByte(0xff893a));
! 1931: fprintf(fp, "$FF893C.w : Codec Status : %04x\n", IoMem_ReadWord(0xff893c));
! 1932: fprintf(fp, "$FF8940.w : GPIO Data Direction : %04x\n", IoMem_ReadWord(0xff8940));
! 1933: fprintf(fp, "$FF8942.w : GPIO Data : %04x\n", IoMem_ReadWord(0xff8942));
! 1934: fprintf(fp, "\n");
! 1935:
1.1.1.6 root 1936: /* DAC connexion */
1937: switch ((IoMem_ReadWord(0xff8932) >> 13) & 0x3) {
1.1.1.7 ! root 1938: case 0 :
1.1.1.6 root 1939: /* DAC connexion with DMA Playback */
1940: if ((IoMem_ReadWord(0xff8930) & 0x1) == 1)
1941: strcpy(matrixDAC, "OOXO");
1942: else
1943: strcpy(matrixDAC, "OOHO");
1944: break;
1945: case 1 :
1946: /* DAC connexion with DSP Transmit */
1947: if ((IoMem_ReadWord(0xff8930) & 0x10) == 0x10)
1948: strcpy(matrixDAC, "OXOO");
1949: else
1950: strcpy(matrixDAC, "OHOO");
1951: break;
1952: case 2 :
1953: /* DAC connexion with External Input */
1954: if ((IoMem_ReadWord(0xff8930) & 0x100) == 0x100)
1955: strcpy(matrixDAC, "XOOO");
1956: else
1957: strcpy(matrixDAC, "HOOO");
1958: break;
1.1.1.7 ! root 1959: case 3 :
1.1.1.6 root 1960: /* DAC connexion with ADC */
1961: strcpy(matrixDAC, "OOOX");
1962: break;
1963: }
1964:
1965: /* DMA connexion */
1966: switch (IoMem_ReadWord(0xff8932) & 0x7) {
1967: case 0 : strcpy(matrixDMA, "OOHO"); break;
1968: case 1 : strcpy(matrixDMA, "OOXO"); break;
1969: case 2 : strcpy(matrixDMA, "OHOO"); break;
1970: case 3 : strcpy(matrixDMA, "OXOO"); break;
1971: case 4 : strcpy(matrixDMA, "HOOO"); break;
1972: case 5 : strcpy(matrixDMA, "XOOO"); break;
1973: case 6 : strcpy(matrixDMA, "OOOH"); break;
1974: case 7 : strcpy(matrixDMA, "OOOX"); break;
1975: }
1976:
1977: /* DSP connexion */
1978: switch ((IoMem_ReadWord(0xff8932) >> 4) & 0x7) {
1979: case 0 : strcpy(matrixDSP, "OOHO"); break;
1980: case 1 : strcpy(matrixDSP, "OOXO"); break;
1981: case 2 : strcpy(matrixDSP, "OHOO"); break;
1982: case 3 : strcpy(matrixDSP, "OXOO"); break;
1983: case 4 : strcpy(matrixDSP, "HOOO"); break;
1984: case 5 : strcpy(matrixDSP, "XOOO"); break;
1985: case 6 : strcpy(matrixDSP, "OOOH"); break;
1986: case 7 : strcpy(matrixDSP, "OOOX"); break;
1987: }
1988:
1989: /* External input connexion */
1990: switch ((IoMem_ReadWord(0xff8932) >> 8) & 0x7) {
1991: case 0 : strcpy(matrixEXT, "OOHO"); break;
1992: case 1 : strcpy(matrixEXT, "OOXO"); break;
1993: case 2 : strcpy(matrixEXT, "OHOO"); break;
1994: case 3 : strcpy(matrixEXT, "OXOO"); break;
1995: case 4 : strcpy(matrixEXT, "HOOO"); break;
1996: case 5 : strcpy(matrixEXT, "XOOO"); break;
1997: case 6 : strcpy(matrixEXT, "OOOH"); break;
1998: case 7 : strcpy(matrixEXT, "OOOX"); break;
1999: }
2000:
2001: if ((IoMem_ReadByte(0xff8935) & 0xf) == 0) {
2002: strcpy(frqDSP, "(STe Freq)");
2003: strcpy(frqDMA, "(STe Freq)");
2004: strcpy(frqEXT, "(STe Freq)");
2005: strcpy(frqDAC, "(STe Freq)");
2006: }
2007: else {
2008: /* DSP Clock */
2009: switch ((IoMem_ReadWord(0xff8930) >> 5) & 0x3) {
2010: case 0: strcpy(frqDSP, " (25 Mhz) "); break;
2011: case 1: strcpy(frqDSP, "(External)"); break;
2012: case 2: strcpy(frqDSP, " (32 Mhz) "); break;
2013: default: strcpy(frqDSP, "undefined "); break;
2014: }
2015:
2016: /* DMA Clock */
2017: switch ((IoMem_ReadWord(0xff8930) >> 1) & 0x3) {
2018: case 0: strcpy(frqDMA, " (25 Mhz) "); break;
2019: case 1: strcpy(frqDMA, "(External)"); break;
2020: case 2: strcpy(frqDMA, " (32 Mhz) "); break;
2021: default: strcpy(frqDMA, "undefined "); break;
2022: }
2023:
2024: /* External Clock */
2025: switch ((IoMem_ReadWord(0xff8930) >> 9) & 0x3) {
2026: case 0: strcpy(frqEXT, " (25 Mhz) "); break;
2027: case 1: strcpy(frqEXT, "(External)"); break;
2028: case 2: strcpy(frqEXT, " (32 Mhz) "); break;
2029: default: strcpy(frqEXT, "undefined "); break;
2030: }
2031:
2032: /* DAC Clock */
2033: strcpy(frqDAC, " (25 Mhz) ");
2034: }
2035:
2036: /* data size */
2037: switch ((IoMem_ReadByte(0xff8921) >> 6) & 0x3) {
2038: case 0: strcpy (dataSize, "8 bits stereo"); break;
2039: case 1: strcpy (dataSize, "16 bits stereo"); break;
2040: case 2: strcpy (dataSize, "8 bits mono"); break;
2041: default: strcpy (dataSize, "undefined"); break;
2042: }
2043:
2044: /* STE, 25Mhz and 32 Mhz sound frequencies */
2045: if ((IoMem_ReadByte(0xff8935) & 0xf) == 0) {
2046: sprintf(frqSTE, "Ste Freq : %d Khz", Ste_SampleRates[IoMem_ReadByte(0xff8921) & 0x3]);
2047: strcpy (frq25Mhz, "25 Mhz Freq : - Khz");
2048: strcpy (frq32Mhz, "32 Mzh Freq : - Khz");
2049: }
2050: else {
2051: strcpy (frqSTE, "Ste Freq : - Khz");
2052: sprintf(frq25Mhz, "25 Mhz Freq : %d Khz", Falcon_SampleRates_25Mhz[(IoMem_ReadByte(0xff8935) & 0xf) - 1]);
2053: sprintf(frq32Mhz, "32 Mzh Freq : %d Khz", Falcon_SampleRates_32Mhz[(IoMem_ReadByte(0xff8935) & 0xf) - 1]);
2054: }
2055:
2056: /* Display the crossbar Matrix */
1.1.1.7 ! root 2057: fprintf(fp, " INPUT\n");
! 2058: fprintf(fp, "External Imp ---%c------%c------%c------%c\n", matrixDAC[0], matrixDMA[0], matrixDSP[0], matrixEXT[0]);
! 2059: fprintf(fp, "%s | | | | O = no connexion\n", frqEXT);
! 2060: fprintf(fp, " | | | | X = connexion\n");
! 2061: fprintf(fp, "Dsp Transmit ---%c------%c------%c------%c H = Handshake connexion\n", matrixDAC[1], matrixDMA[1], matrixDSP[1], matrixEXT[1]);
! 2062: fprintf(fp, "%s | | | |\n", frqDSP);
! 2063: fprintf(fp, " | | | | %s\n", dataSize);
! 2064: fprintf(fp, "DMA PlayBack ---%c------%c------%c------%c\n", matrixDAC[2], matrixDMA[2], matrixDSP[2], matrixEXT[2]);
! 2065: fprintf(fp, "%s | | | | Sound Freq :\n", frqDMA);
! 2066: fprintf(fp, " | | | | %s\n", frqSTE);
! 2067: fprintf(fp, "ADC ---%c------%c------%c------%c %s\n", matrixDAC[3], matrixDMA[3], matrixDSP[3], matrixEXT[3], frq25Mhz);
! 2068: fprintf(fp, "%s | | | | %s\n", frqDAC, frq32Mhz);
! 2069: fprintf(fp, " | | | |\n");
! 2070: fprintf(fp, " DAC DMA DSP External OUTPUT\n");
! 2071: fprintf(fp, " Record Record Out\n");
! 2072: fprintf(fp, "\n");
1.1.1.6 root 2073: }
2074:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.