SPC music playback tools for real snes apu

Dependencies:   mbed

Committer:
akkera102
Date:
Mon Jan 09 13:58:58 2017 +0000
Revision:
1:02a06cd10a33
Parent:
0:5bd52e196edb
Child:
2:62e6e22f8be2
test

Who changed what in which revision?

UserRevisionLine numberNew contents of line
akkera102 0:5bd52e196edb 1 /* hwapu - SPC music playback tools for real snes apu
akkera102 0:5bd52e196edb 2 * Copyright (C) 2004-2005 Raphael Assenat <raph@raphnet.net>
akkera102 0:5bd52e196edb 3 *
akkera102 0:5bd52e196edb 4 * This program is free software; you can redistribute it and/or modify
akkera102 0:5bd52e196edb 5 * it under the terms of the GNU General Public License as published by
akkera102 0:5bd52e196edb 6 * the Free Software Foundation; either version 2 of the License, or
akkera102 0:5bd52e196edb 7 * (at your option) any later version.
akkera102 0:5bd52e196edb 8 *
akkera102 0:5bd52e196edb 9 * This program is distributed in the hope that it will be useful,
akkera102 0:5bd52e196edb 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
akkera102 0:5bd52e196edb 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
akkera102 0:5bd52e196edb 12 * GNU General Public License for more details.
akkera102 0:5bd52e196edb 13 *
akkera102 0:5bd52e196edb 14 * You should have received a copy of the GNU General Public License
akkera102 0:5bd52e196edb 15 * along with this program; if not, write to the Free Software
akkera102 0:5bd52e196edb 16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
akkera102 0:5bd52e196edb 17 */
akkera102 0:5bd52e196edb 18 #include <stdio.h>
akkera102 1:02a06cd10a33 19 #include <string.h>/**/
akkera102 0:5bd52e196edb 20 #include "apu.h"
akkera102 0:5bd52e196edb 21 #include <time.h>
akkera102 0:5bd52e196edb 22 // #include <sys/time.h>
akkera102 0:5bd52e196edb 23 #include "mbed.h"
akkera102 0:5bd52e196edb 24
akkera102 0:5bd52e196edb 25
akkera102 0:5bd52e196edb 26 //#define TRACE_RW
akkera102 0:5bd52e196edb 27
akkera102 0:5bd52e196edb 28 extern int g_verbose; // from main.c
akkera102 0:5bd52e196edb 29
akkera102 0:5bd52e196edb 30 /******************** G L O B A L S ************************************/
akkera102 0:5bd52e196edb 31 static int port0=0;
akkera102 0:5bd52e196edb 32 static APU_ops *apu_ops = NULL;
akkera102 0:5bd52e196edb 33
akkera102 0:5bd52e196edb 34 void apu_setOps(APU_ops *ops)
akkera102 0:5bd52e196edb 35 {
akkera102 0:5bd52e196edb 36 apu_ops = ops;
akkera102 0:5bd52e196edb 37 }
akkera102 0:5bd52e196edb 38
akkera102 0:5bd52e196edb 39 static int SetPort0 (short data)
akkera102 0:5bd52e196edb 40 {
akkera102 0:5bd52e196edb 41 port0=data;
akkera102 0:5bd52e196edb 42 return 0;
akkera102 0:5bd52e196edb 43 }
akkera102 0:5bd52e196edb 44
akkera102 0:5bd52e196edb 45 void apu_write (int address, unsigned char data)
akkera102 0:5bd52e196edb 46 {
akkera102 0:5bd52e196edb 47 //#ifdef TRACE_RW
akkera102 0:5bd52e196edb 48 // printf("apu_write: a=%d, %02x\n", address, data);
akkera102 0:5bd52e196edb 49 //#endif
akkera102 0:5bd52e196edb 50 apu_ops->write(address, data);
akkera102 0:5bd52e196edb 51 }
akkera102 0:5bd52e196edb 52
akkera102 0:5bd52e196edb 53 unsigned char apu_read (int address)
akkera102 0:5bd52e196edb 54 {
akkera102 0:5bd52e196edb 55 unsigned char tmp = apu_ops->read(address);
akkera102 0:5bd52e196edb 56 //#ifdef TRACE_RW
akkera102 0:5bd52e196edb 57 // printf("apu_read: a=%d -> %02x\n", address, tmp);
akkera102 0:5bd52e196edb 58 //#endif
akkera102 0:5bd52e196edb 59
akkera102 0:5bd52e196edb 60 return tmp;
akkera102 0:5bd52e196edb 61 }
akkera102 0:5bd52e196edb 62
akkera102 0:5bd52e196edb 63 /* Write to address 'address', write the previously
akkera102 0:5bd52e196edb 64 * read value from port0 back to port 0 and wait
akkera102 0:5bd52e196edb 65 * for port0 value to be different from the written one.
akkera102 0:5bd52e196edb 66 */
akkera102 0:5bd52e196edb 67 int apu_writeHandshake(int address, int data)
akkera102 0:5bd52e196edb 68 {
akkera102 0:5bd52e196edb 69 // int i;
akkera102 0:5bd52e196edb 70 // i = 0;
akkera102 0:5bd52e196edb 71 apu_write(address, data);
akkera102 0:5bd52e196edb 72 apu_write(0,port0);
akkera102 0:5bd52e196edb 73
akkera102 0:5bd52e196edb 74 if (!apu_waitInport(0, port0, 500)) {
akkera102 0:5bd52e196edb 75 return 1;
akkera102 0:5bd52e196edb 76 }
akkera102 0:5bd52e196edb 77 port0++;
akkera102 0:5bd52e196edb 78 if (port0 == 256)
akkera102 0:5bd52e196edb 79 port0 = 0;
akkera102 0:5bd52e196edb 80
akkera102 0:5bd52e196edb 81 return 0;
akkera102 0:5bd52e196edb 82
akkera102 0:5bd52e196edb 83
akkera102 0:5bd52e196edb 84 }
akkera102 0:5bd52e196edb 85
akkera102 0:5bd52e196edb 86
akkera102 0:5bd52e196edb 87 int apu_writeBytes(unsigned char *data, int len)
akkera102 0:5bd52e196edb 88 {
akkera102 0:5bd52e196edb 89 int i;
akkera102 0:5bd52e196edb 90 #ifdef TRACE_RW
akkera102 0:5bd52e196edb 91 printf("apu_writeBytes: %d...\n", len);
akkera102 0:5bd52e196edb 92 #endif
akkera102 0:5bd52e196edb 93 for (i=0; i<len; i++) {
akkera102 0:5bd52e196edb 94 if (apu_writeHandshake(1, data[i])) { return 1; }
akkera102 0:5bd52e196edb 95 }
akkera102 0:5bd52e196edb 96 return 0;
akkera102 0:5bd52e196edb 97 }
akkera102 0:5bd52e196edb 98
akkera102 0:5bd52e196edb 99 void apu_reset(void) //Reset the APU by whatever means it needs reset.
akkera102 0:5bd52e196edb 100 {
akkera102 0:5bd52e196edb 101 apu_ops->reset();
akkera102 0:5bd52e196edb 102
akkera102 0:5bd52e196edb 103 }
akkera102 0:5bd52e196edb 104
akkera102 0:5bd52e196edb 105 /* return false on timeout, otherwise true */
akkera102 0:5bd52e196edb 106 int apu_waitInport(int port, unsigned char data, int timeout_ms)
akkera102 0:5bd52e196edb 107 {
akkera102 0:5bd52e196edb 108 // struct timeval tv_before, tv_now;
akkera102 0:5bd52e196edb 109 // gettimeofday(&tv_before, NULL);
akkera102 0:5bd52e196edb 110 int elaps_milli;
akkera102 0:5bd52e196edb 111 Timer t;
akkera102 0:5bd52e196edb 112 t.start();
akkera102 0:5bd52e196edb 113
akkera102 0:5bd52e196edb 114 #ifdef TRACE_RW
akkera102 0:5bd52e196edb 115 printf("apu_waitInport: addr: %d, data: %02x\n",port,data);
akkera102 0:5bd52e196edb 116 #endif
akkera102 0:5bd52e196edb 117
akkera102 0:5bd52e196edb 118 while(apu_read(port)!=data) {
akkera102 0:5bd52e196edb 119 //usleep(1);
akkera102 0:5bd52e196edb 120 // gettimeofday(&tv_now, NULL);
akkera102 0:5bd52e196edb 121 // elaps_milli = (tv_now.tv_sec - tv_before.tv_sec) * 1000;
akkera102 0:5bd52e196edb 122 // elaps_milli += (tv_now.tv_usec-tv_before.tv_usec)/1000;
akkera102 0:5bd52e196edb 123 elaps_milli = t.read_ms();
akkera102 0:5bd52e196edb 124 if (elaps_milli > timeout_ms )
akkera102 0:5bd52e196edb 125 {
akkera102 0:5bd52e196edb 126 if (g_verbose)
akkera102 0:5bd52e196edb 127 printf("timeout after %d milli\n", elaps_milli);
akkera102 0:5bd52e196edb 128 return 0;
akkera102 0:5bd52e196edb 129 }
akkera102 0:5bd52e196edb 130 }
akkera102 0:5bd52e196edb 131 return 1;
akkera102 0:5bd52e196edb 132 }
akkera102 0:5bd52e196edb 133
akkera102 0:5bd52e196edb 134 int apu_initTransfer(unsigned short address)
akkera102 0:5bd52e196edb 135 {
akkera102 0:5bd52e196edb 136 /* Initializing the transfer */
akkera102 0:5bd52e196edb 137 /* Wait for port 2140 to be $aa */
akkera102 0:5bd52e196edb 138 if (!apu_waitInport(0, 0xaa, 500)) {
akkera102 0:5bd52e196edb 139 if (g_verbose)
akkera102 0:5bd52e196edb 140 printf("Should read 0xaa, but reads %02x\n", apu_read(0));
akkera102 0:5bd52e196edb 141 return -1;
akkera102 0:5bd52e196edb 142 }
akkera102 0:5bd52e196edb 143 /* and Wait for port 2141 to be $bb */
akkera102 0:5bd52e196edb 144 if (!apu_waitInport(1, 0xbb, 500)) {
akkera102 0:5bd52e196edb 145 if (g_verbose)
akkera102 0:5bd52e196edb 146 printf("Should read 0xaa, but reads %02x\n", apu_read(0));
akkera102 0:5bd52e196edb 147 return -1;
akkera102 0:5bd52e196edb 148 }
akkera102 0:5bd52e196edb 149 /* The spc is now ready */
akkera102 0:5bd52e196edb 150
akkera102 0:5bd52e196edb 151 /* Write any value other than 0 to 2141 */
akkera102 0:5bd52e196edb 152 apu_write(1, 1);
akkera102 0:5bd52e196edb 153 /* Write the destination address to poirt $2142 and $2143, with the
akkera102 0:5bd52e196edb 154 * low byte written at $2142 */
akkera102 0:5bd52e196edb 155 apu_write(2, address&0xff); // low
akkera102 0:5bd52e196edb 156 apu_write(3, (address&0xff00)>>8); // high So our code will go at $0002
akkera102 0:5bd52e196edb 157 /* Write $CC to port $2140 */
akkera102 0:5bd52e196edb 158 apu_write(0, 0xCC);
akkera102 0:5bd52e196edb 159
akkera102 0:5bd52e196edb 160 /* Wait for $2140 to be $CC */
akkera102 0:5bd52e196edb 161 if (!apu_waitInport(0, 0xcc, 500)) {
akkera102 0:5bd52e196edb 162 if (g_verbose)
akkera102 0:5bd52e196edb 163 printf("Should read 0xcc, but reads %02x\n", apu_read(0));
akkera102 0:5bd52e196edb 164 return -1;
akkera102 0:5bd52e196edb 165 }
akkera102 0:5bd52e196edb 166
akkera102 0:5bd52e196edb 167 SetPort0(0);
akkera102 0:5bd52e196edb 168
akkera102 0:5bd52e196edb 169 return 0;
akkera102 0:5bd52e196edb 170 }
akkera102 0:5bd52e196edb 171
akkera102 0:5bd52e196edb 172 int apu_newTransfer(unsigned short address)
akkera102 0:5bd52e196edb 173 {
akkera102 0:5bd52e196edb 174 int i;
akkera102 0:5bd52e196edb 175 apu_write(1,1);
akkera102 0:5bd52e196edb 176 apu_write(3, (address&0xff00)>>8);
akkera102 0:5bd52e196edb 177 apu_write(2, (address & 0xff));
akkera102 0:5bd52e196edb 178
akkera102 0:5bd52e196edb 179 i = apu_read(0);
akkera102 0:5bd52e196edb 180 i += 2; i &= 0xff;
akkera102 0:5bd52e196edb 181 if (!i) { i += 2; } // if it's 0, increase it again
akkera102 0:5bd52e196edb 182 apu_write(0, i);
akkera102 0:5bd52e196edb 183 if (!apu_waitInport(0, i, 500)) {
akkera102 0:5bd52e196edb 184 fprintf(stderr, "apu_newTransfer: timeout\n"); return -1;
akkera102 0:5bd52e196edb 185 }
akkera102 0:5bd52e196edb 186
akkera102 0:5bd52e196edb 187 SetPort0(0);
akkera102 0:5bd52e196edb 188
akkera102 0:5bd52e196edb 189 return 0;
akkera102 0:5bd52e196edb 190 }
akkera102 0:5bd52e196edb 191
akkera102 0:5bd52e196edb 192 void apu_endTransfer(unsigned short start_address)
akkera102 0:5bd52e196edb 193 {
akkera102 0:5bd52e196edb 194 int i;
akkera102 0:5bd52e196edb 195
akkera102 0:5bd52e196edb 196 apu_write(1, 0);
akkera102 0:5bd52e196edb 197 apu_write(3, (start_address & 0xff00)>>8);
akkera102 0:5bd52e196edb 198 apu_write(2, (start_address & 0xff));
akkera102 0:5bd52e196edb 199
akkera102 0:5bd52e196edb 200 i = apu_read(0);
akkera102 0:5bd52e196edb 201 i +=2; i &= 0xff;
akkera102 0:5bd52e196edb 202 if (!i) { i+=2 ; } // if it's 0, increase it again
akkera102 0:5bd52e196edb 203 apu_write(0, i);
akkera102 0:5bd52e196edb 204 }
akkera102 0:5bd52e196edb 205
akkera102 0:5bd52e196edb 206