SPC music playback tools for real snes apu

Dependencies:   mbed

Committer:
akkera102
Date:
Thu Jan 19 04:51:28 2017 +0000
Revision:
8:072621697467
Parent:
2:62e6e22f8be2
fifth

Who changed what in which revision?

UserRevisionLine numberNew 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 }