akkera 102
/
apuplay
SPC music playback tools for real snes apu
apu.cpp@8:072621697467, 2017-01-19 (annotated)
- Committer:
- akkera102
- Date:
- Thu Jan 19 04:51:28 2017 +0000
- Revision:
- 8:072621697467
- Parent:
- 2:62e6e22f8be2
fifth
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
akkera102 | 0:5bd52e196edb | 1 | #include "apu.h" |
akkera102 | 0:5bd52e196edb | 2 | #include "mbed.h" |
akkera102 | 2:62e6e22f8be2 | 3 | #include "gpio.h" |
akkera102 | 0:5bd52e196edb | 4 | |
akkera102 | 2:62e6e22f8be2 | 5 | // cmd.cpp |
akkera102 | 2:62e6e22f8be2 | 6 | extern int g_verbose; |
akkera102 | 0:5bd52e196edb | 7 | |
akkera102 | 2:62e6e22f8be2 | 8 | static int port0 = 0; |
akkera102 | 0:5bd52e196edb | 9 | |
akkera102 | 2:62e6e22f8be2 | 10 | void apu_init(void) |
akkera102 | 0:5bd52e196edb | 11 | { |
akkera102 | 2:62e6e22f8be2 | 12 | port0 = 0; |
akkera102 | 2:62e6e22f8be2 | 13 | gpio_init(); |
akkera102 | 0:5bd52e196edb | 14 | } |
akkera102 | 0:5bd52e196edb | 15 | |
akkera102 | 2:62e6e22f8be2 | 16 | // Reset the APU by whatever means it needs reset. |
akkera102 | 2:62e6e22f8be2 | 17 | void apu_reset(void) |
akkera102 | 0:5bd52e196edb | 18 | { |
akkera102 | 2:62e6e22f8be2 | 19 | gpio_reset(); |
akkera102 | 0:5bd52e196edb | 20 | } |
akkera102 | 0:5bd52e196edb | 21 | |
akkera102 | 2:62e6e22f8be2 | 22 | unsigned char apu_read(int address) |
akkera102 | 0:5bd52e196edb | 23 | { |
akkera102 | 2:62e6e22f8be2 | 24 | unsigned char tmp = gpio_read(address); |
akkera102 | 0:5bd52e196edb | 25 | |
akkera102 | 0:5bd52e196edb | 26 | // printf("apu_read: a=%d -> %02x\n", address, tmp); |
akkera102 | 0:5bd52e196edb | 27 | |
akkera102 | 0:5bd52e196edb | 28 | return tmp; |
akkera102 | 0:5bd52e196edb | 29 | } |
akkera102 | 0:5bd52e196edb | 30 | |
akkera102 | 2:62e6e22f8be2 | 31 | void apu_write(int address, unsigned char data) |
akkera102 | 0:5bd52e196edb | 32 | { |
akkera102 | 2:62e6e22f8be2 | 33 | // printf("apu_write: a=%d, %02x\n", address, data); |
akkera102 | 0:5bd52e196edb | 34 | |
akkera102 | 2:62e6e22f8be2 | 35 | gpio_write(address, data); |
akkera102 | 0:5bd52e196edb | 36 | } |
akkera102 | 0:5bd52e196edb | 37 | |
akkera102 | 2:62e6e22f8be2 | 38 | // Write many bytes using handshake (see apu_writeHandshake) |
akkera102 | 0:5bd52e196edb | 39 | int apu_writeBytes(unsigned char *data, int len) |
akkera102 | 0:5bd52e196edb | 40 | { |
akkera102 | 2:62e6e22f8be2 | 41 | // printf("apu_writeBytes: %d...\n", len); |
akkera102 | 2:62e6e22f8be2 | 42 | |
akkera102 | 2:62e6e22f8be2 | 43 | for(int i=0; i<len; i++) |
akkera102 | 2:62e6e22f8be2 | 44 | { |
akkera102 | 2:62e6e22f8be2 | 45 | if(apu_writeHandshake(1, data[i])) |
akkera102 | 2:62e6e22f8be2 | 46 | { |
akkera102 | 2:62e6e22f8be2 | 47 | return 1; |
akkera102 | 2:62e6e22f8be2 | 48 | } |
akkera102 | 0:5bd52e196edb | 49 | } |
akkera102 | 2:62e6e22f8be2 | 50 | |
akkera102 | 0:5bd52e196edb | 51 | return 0; |
akkera102 | 0:5bd52e196edb | 52 | } |
akkera102 | 0:5bd52e196edb | 53 | |
akkera102 | 2:62e6e22f8be2 | 54 | // Write to address 'address', write the previously |
akkera102 | 2:62e6e22f8be2 | 55 | // read value from port0 back to port 0 and wait |
akkera102 | 2:62e6e22f8be2 | 56 | // for port0 value to be different from the written one. |
akkera102 | 2:62e6e22f8be2 | 57 | int apu_writeHandshake(int address, int data) |
akkera102 | 0:5bd52e196edb | 58 | { |
akkera102 | 2:62e6e22f8be2 | 59 | apu_write(address, data); |
akkera102 | 2:62e6e22f8be2 | 60 | apu_write(0, port0); |
akkera102 | 2:62e6e22f8be2 | 61 | |
akkera102 | 2:62e6e22f8be2 | 62 | if(!apu_waitInport(0, port0, 500)) |
akkera102 | 2:62e6e22f8be2 | 63 | { |
akkera102 | 2:62e6e22f8be2 | 64 | return 1; |
akkera102 | 2:62e6e22f8be2 | 65 | } |
akkera102 | 0:5bd52e196edb | 66 | |
akkera102 | 2:62e6e22f8be2 | 67 | if(++port0 == 256) |
akkera102 | 2:62e6e22f8be2 | 68 | { |
akkera102 | 2:62e6e22f8be2 | 69 | port0 = 0; |
akkera102 | 2:62e6e22f8be2 | 70 | } |
akkera102 | 2:62e6e22f8be2 | 71 | |
akkera102 | 2:62e6e22f8be2 | 72 | return 0; |
akkera102 | 0:5bd52e196edb | 73 | } |
akkera102 | 0:5bd52e196edb | 74 | |
akkera102 | 2:62e6e22f8be2 | 75 | // return false on timeout, otherwise true |
akkera102 | 0:5bd52e196edb | 76 | int apu_waitInport(int port, unsigned char data, int timeout_ms) |
akkera102 | 0:5bd52e196edb | 77 | { |
akkera102 | 2:62e6e22f8be2 | 78 | // printf("apu_waitInport: addr: %d, data: %02x\n", port, data); |
akkera102 | 2:62e6e22f8be2 | 79 | |
akkera102 | 2:62e6e22f8be2 | 80 | int ms; |
akkera102 | 0:5bd52e196edb | 81 | Timer t; |
akkera102 | 0:5bd52e196edb | 82 | t.start(); |
akkera102 | 0:5bd52e196edb | 83 | |
akkera102 | 2:62e6e22f8be2 | 84 | while(apu_read(port) != data) |
akkera102 | 2:62e6e22f8be2 | 85 | { |
akkera102 | 2:62e6e22f8be2 | 86 | ms = t.read_ms(); |
akkera102 | 2:62e6e22f8be2 | 87 | if(ms > timeout_ms) |
akkera102 | 0:5bd52e196edb | 88 | { |
akkera102 | 2:62e6e22f8be2 | 89 | if(g_verbose) |
akkera102 | 2:62e6e22f8be2 | 90 | { |
akkera102 | 2:62e6e22f8be2 | 91 | printf("timeout after %d milli\n", ms); |
akkera102 | 2:62e6e22f8be2 | 92 | } |
akkera102 | 2:62e6e22f8be2 | 93 | |
akkera102 | 0:5bd52e196edb | 94 | return 0; |
akkera102 | 0:5bd52e196edb | 95 | } |
akkera102 | 0:5bd52e196edb | 96 | } |
akkera102 | 2:62e6e22f8be2 | 97 | |
akkera102 | 0:5bd52e196edb | 98 | return 1; |
akkera102 | 0:5bd52e196edb | 99 | } |
akkera102 | 0:5bd52e196edb | 100 | |
akkera102 | 2:62e6e22f8be2 | 101 | // Initialise an spc transfer at 'address'. |
akkera102 | 2:62e6e22f8be2 | 102 | // To be used after reset of after jumping to rom |
akkera102 | 2:62e6e22f8be2 | 103 | // |
akkera102 | 2:62e6e22f8be2 | 104 | // Use apu_newTransfer for additional transfers |
akkera102 | 2:62e6e22f8be2 | 105 | // |
akkera102 | 2:62e6e22f8be2 | 106 | // return -1 on error, 0 if success |
akkera102 | 0:5bd52e196edb | 107 | int apu_initTransfer(unsigned short address) |
akkera102 | 0:5bd52e196edb | 108 | { |
akkera102 | 2:62e6e22f8be2 | 109 | // Initializing the transfer |
akkera102 | 2:62e6e22f8be2 | 110 | // Wait for port 2140 to be $aa |
akkera102 | 2:62e6e22f8be2 | 111 | if(!apu_waitInport(0, 0xaa, 500)) |
akkera102 | 2:62e6e22f8be2 | 112 | { |
akkera102 | 2:62e6e22f8be2 | 113 | if(g_verbose) |
akkera102 | 2:62e6e22f8be2 | 114 | { |
akkera102 | 0:5bd52e196edb | 115 | printf("Should read 0xaa, but reads %02x\n", apu_read(0)); |
akkera102 | 2:62e6e22f8be2 | 116 | } |
akkera102 | 2:62e6e22f8be2 | 117 | |
akkera102 | 0:5bd52e196edb | 118 | return -1; |
akkera102 | 0:5bd52e196edb | 119 | } |
akkera102 | 0:5bd52e196edb | 120 | |
akkera102 | 2:62e6e22f8be2 | 121 | // and Wait for port 2141 to be $bb |
akkera102 | 2:62e6e22f8be2 | 122 | if(!apu_waitInport(1, 0xbb, 500)) |
akkera102 | 2:62e6e22f8be2 | 123 | { |
akkera102 | 2:62e6e22f8be2 | 124 | if(g_verbose) |
akkera102 | 2:62e6e22f8be2 | 125 | { |
akkera102 | 2:62e6e22f8be2 | 126 | printf("Should read 0xaa, but reads %02x\n", apu_read(0)); |
akkera102 | 2:62e6e22f8be2 | 127 | } |
akkera102 | 0:5bd52e196edb | 128 | |
akkera102 | 0:5bd52e196edb | 129 | return -1; |
akkera102 | 0:5bd52e196edb | 130 | } |
akkera102 | 0:5bd52e196edb | 131 | |
akkera102 | 2:62e6e22f8be2 | 132 | // The spc is now ready |
akkera102 | 2:62e6e22f8be2 | 133 | |
akkera102 | 2:62e6e22f8be2 | 134 | // Write any value other than 0 to 2141 |
akkera102 | 2:62e6e22f8be2 | 135 | apu_write(1, 1); |
akkera102 | 2:62e6e22f8be2 | 136 | |
akkera102 | 2:62e6e22f8be2 | 137 | // Write the destination address to poirt $2142 and $2143, with the |
akkera102 | 2:62e6e22f8be2 | 138 | // low byte written at $2142 |
akkera102 | 2:62e6e22f8be2 | 139 | apu_write(2, (address & 0x00ff)); // low |
akkera102 | 2:62e6e22f8be2 | 140 | apu_write(3, (address & 0xff00) >> 8); // high So our code will go at $0002 |
akkera102 | 2:62e6e22f8be2 | 141 | |
akkera102 | 2:62e6e22f8be2 | 142 | // Write $CC to port $2140 |
akkera102 | 2:62e6e22f8be2 | 143 | apu_write(0, 0xCC); |
akkera102 | 2:62e6e22f8be2 | 144 | |
akkera102 | 2:62e6e22f8be2 | 145 | // Wait for $2140 to be $CC |
akkera102 | 2:62e6e22f8be2 | 146 | if(!apu_waitInport(0, 0xcc, 500)) |
akkera102 | 2:62e6e22f8be2 | 147 | { |
akkera102 | 2:62e6e22f8be2 | 148 | if(g_verbose) |
akkera102 | 2:62e6e22f8be2 | 149 | { |
akkera102 | 2:62e6e22f8be2 | 150 | printf("Should read 0xcc, but reads %02x\n", apu_read(0)); |
akkera102 | 2:62e6e22f8be2 | 151 | } |
akkera102 | 2:62e6e22f8be2 | 152 | |
akkera102 | 2:62e6e22f8be2 | 153 | return -1; |
akkera102 | 2:62e6e22f8be2 | 154 | } |
akkera102 | 2:62e6e22f8be2 | 155 | |
akkera102 | 2:62e6e22f8be2 | 156 | port0 = 0; |
akkera102 | 0:5bd52e196edb | 157 | return 0; |
akkera102 | 0:5bd52e196edb | 158 | } |
akkera102 | 0:5bd52e196edb | 159 | |
akkera102 | 2:62e6e22f8be2 | 160 | // initialise a new transfer after the first transfer. |
akkera102 | 2:62e6e22f8be2 | 161 | // |
akkera102 | 2:62e6e22f8be2 | 162 | // returns 0 on success, -1 on error |
akkera102 | 0:5bd52e196edb | 163 | int apu_newTransfer(unsigned short address) |
akkera102 | 0:5bd52e196edb | 164 | { |
akkera102 | 0:5bd52e196edb | 165 | int i; |
akkera102 | 2:62e6e22f8be2 | 166 | apu_write(1, 1); |
akkera102 | 2:62e6e22f8be2 | 167 | apu_write(3, (address & 0xff00) >> 8); |
akkera102 | 2:62e6e22f8be2 | 168 | apu_write(2, (address & 0x00ff)); |
akkera102 | 2:62e6e22f8be2 | 169 | |
akkera102 | 2:62e6e22f8be2 | 170 | i = apu_read(0); |
akkera102 | 2:62e6e22f8be2 | 171 | i += 2; |
akkera102 | 2:62e6e22f8be2 | 172 | i &= 0xff; |
akkera102 | 0:5bd52e196edb | 173 | |
akkera102 | 2:62e6e22f8be2 | 174 | // if it's 0, increase it again |
akkera102 | 2:62e6e22f8be2 | 175 | if(!i) |
akkera102 | 2:62e6e22f8be2 | 176 | { |
akkera102 | 2:62e6e22f8be2 | 177 | i += 2; |
akkera102 | 2:62e6e22f8be2 | 178 | } |
akkera102 | 0:5bd52e196edb | 179 | apu_write(0, i); |
akkera102 | 2:62e6e22f8be2 | 180 | |
akkera102 | 2:62e6e22f8be2 | 181 | if(!apu_waitInport(0, i, 500)) |
akkera102 | 2:62e6e22f8be2 | 182 | { |
akkera102 | 2:62e6e22f8be2 | 183 | fprintf(stderr, "apu_newTransfer: timeout\n"); |
akkera102 | 2:62e6e22f8be2 | 184 | return -1; |
akkera102 | 0:5bd52e196edb | 185 | } |
akkera102 | 0:5bd52e196edb | 186 | |
akkera102 | 2:62e6e22f8be2 | 187 | port0 = 0; |
akkera102 | 0:5bd52e196edb | 188 | return 0; |
akkera102 | 0:5bd52e196edb | 189 | } |
akkera102 | 0:5bd52e196edb | 190 | |
akkera102 | 2:62e6e22f8be2 | 191 | // End transfer and jump to address |
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 | 2:62e6e22f8be2 | 197 | apu_write(3, (start_address & 0xff00) >> 8); |
akkera102 | 2:62e6e22f8be2 | 198 | apu_write(2, (start_address & 0x00ff)); |
akkera102 | 0:5bd52e196edb | 199 | |
akkera102 | 2:62e6e22f8be2 | 200 | i = apu_read(0); |
akkera102 | 2:62e6e22f8be2 | 201 | i += 2; |
akkera102 | 2:62e6e22f8be2 | 202 | i &= 0xff; |
akkera102 | 2:62e6e22f8be2 | 203 | |
akkera102 | 2:62e6e22f8be2 | 204 | // if it's 0, increase it again |
akkera102 | 2:62e6e22f8be2 | 205 | if(!i) |
akkera102 | 2:62e6e22f8be2 | 206 | { |
akkera102 | 2:62e6e22f8be2 | 207 | i+=2; |
akkera102 | 2:62e6e22f8be2 | 208 | } |
akkera102 | 0:5bd52e196edb | 209 | apu_write(0, i); |
akkera102 | 0:5bd52e196edb | 210 | } |