akkera 102
/
apuplay
SPC music playback tools for real snes apu
apu.cpp@0:5bd52e196edb, 2017-01-09 (annotated)
- Committer:
- akkera102
- Date:
- Mon Jan 09 13:54:39 2017 +0000
- Revision:
- 0:5bd52e196edb
- Child:
- 1:02a06cd10a33
first
Who changed what in which revision?
User | Revision | Line number | New 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 | 0:5bd52e196edb | 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 |