1 /* KallistiOS ##version##
4 (c)2000-2002 Dan Potter
6 Generic sound driver with streaming capabilities
8 This slightly more complicated version allows for sound effect channels,
9 and full sampling rate, panning, and volume control for each.
13 #include "aica_cmd_iface.h"
16 /****************** Timer *******************************************/
18 #define timer (*((volatile uint32 *)AICA_MEM_CLOCK))
20 void timer_wait(uint32 jiffies) {
21 uint32 fin = timer + jiffies;
27 /****************** Tiny Libc ***************************************/
31 void * memcpy(void *dest, const void *src, size_t count) {
32 unsigned char *tmp = (unsigned char *) dest;
33 unsigned char *s = (unsigned char *) src;
41 /****************** Main Program ************************************/
43 /* Our SH-4 interface (statically placed memory structures) */
44 volatile aica_queue_t *q_cmd = (volatile aica_queue_t *)AICA_MEM_CMD_QUEUE;
45 volatile aica_queue_t *q_resp = (volatile aica_queue_t *)AICA_MEM_RESP_QUEUE;
46 volatile aica_channel_t *chans = (volatile aica_channel_t *)AICA_MEM_CHANNELS;
48 /* Process a CHAN command */
49 void process_chn(uint32 chn, aica_channel_t *chndat) {
50 switch(chndat->cmd & AICA_CH_CMD_MASK) {
51 case AICA_CH_CMD_NONE:
53 case AICA_CH_CMD_START:
55 if(chndat->cmd & AICA_CH_START_SYNC) {
59 memcpy((void*)(chans + chn), chndat, sizeof(aica_channel_t));
61 aica_play(chn, chndat->cmd & AICA_CH_START_DELAY);
65 case AICA_CH_CMD_STOP:
68 case AICA_CH_CMD_UPDATE:
70 if(chndat->cmd & AICA_CH_UPDATE_SET_FREQ) {
71 chans[chn].freq = chndat->freq;
75 if(chndat->cmd & AICA_CH_UPDATE_SET_VOL) {
76 chans[chn].vol = chndat->vol;
80 if(chndat->cmd & AICA_CH_UPDATE_SET_PAN) {
81 chans[chn].pan = chndat->pan;
92 /* Process one packet of queue data */
93 uint32 process_one(uint32 tail) {
94 uint32 pktdata[AICA_CMD_MAX_SIZE], *pdptr, size, i;
95 volatile uint32 * src;
98 src = (volatile uint32 *)(q_cmd->data + tail);
99 pkt = (aica_cmd_t *)pktdata;
102 /* Get the size field */
105 if(size > AICA_CMD_MAX_SIZE)
106 size = AICA_CMD_MAX_SIZE;
108 /* Copy out the packet data */
109 for(i = 0; i < size; i++) {
112 if((uint32)src >= (q_cmd->data + q_cmd->size))
113 src = (volatile uint32 *)q_cmd->data;
116 /* Figure out what type of packet it is */
121 /* Not implemented yet */
124 process_chn(pkt->cmd_id, (aica_channel_t *)pkt->cmd_data);
126 case AICA_CMD_SYNC_CLOCK:
127 /* Reset our timer clock to zero */
138 /* Look for an available request in the command queue; if one is there
139 then process it and move the tail pointer. */
140 void process_cmd_queue() {
141 uint32 head, tail, tsloc, ts;
143 /* Grab these values up front in case SH-4 changes head */
147 /* Do we have anything to process? */
148 while(head != tail) {
149 /* Look at the next packet. If our clock isn't there yet, then
150 we won't process anything yet either. */
151 tsloc = tail + offsetof(aica_cmd_t, timestamp);
153 if(tsloc >= q_cmd->size)
154 tsloc -= q_cmd->size;
156 ts = *((volatile uint32*)(q_cmd->data + tsloc));
158 if(ts > 0 && ts >= timer)
162 ts = process_one(tail);
164 /* Ok, skip over the packet */
167 if(tail >= q_cmd->size)
177 /* Setup our queues */
178 q_cmd->head = q_cmd->tail = 0;
179 q_cmd->data = AICA_MEM_CMD_QUEUE + sizeof(aica_queue_t);
180 q_cmd->size = AICA_MEM_RESP_QUEUE - q_cmd->data;
181 q_cmd->process_ok = 1;
184 q_resp->head = q_resp->tail = 0;
185 q_resp->data = AICA_MEM_RESP_QUEUE + sizeof(aica_queue_t);
186 q_resp->size = AICA_MEM_CHANNELS - q_resp->data;
187 q_resp->process_ok = 1;
190 /* Initialize the AICA part of the SPU */
193 /* Wait for a command */
195 /* Update channel position counters */
196 for(i = 0; i < 64; i++)
199 /* Check for a command */
200 if(q_cmd->process_ok)
203 /* Little delay to prevent memory lock */