SPC music playback tools for real snes apu

Dependencies:   mbed

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers apu.cpp Source File

apu.cpp

00001 #include "apu.h"
00002 #include "mbed.h"
00003 #include "gpio.h"
00004 
00005 // cmd.cpp
00006 extern int g_verbose;
00007 
00008 static int port0 = 0;
00009 
00010 void apu_init(void)
00011 {
00012     port0 = 0;
00013     gpio_init();
00014 }
00015 
00016 // Reset the APU by whatever means it needs reset.
00017 void apu_reset(void)
00018 {
00019     gpio_reset();
00020 }
00021 
00022 unsigned char apu_read(int address)
00023 {
00024     unsigned char tmp = gpio_read(address);
00025 
00026 //  printf("apu_read: a=%d -> %02x\n", address, tmp);
00027 
00028     return tmp;
00029 }
00030 
00031 void apu_write(int address, unsigned char data)
00032 {
00033 //  printf("apu_write: a=%d, %02x\n", address, data);
00034 
00035     gpio_write(address, data);  
00036 }
00037 
00038 // Write many bytes using handshake (see apu_writeHandshake)
00039 int apu_writeBytes(unsigned char *data, int len)
00040 {
00041 //  printf("apu_writeBytes: %d...\n", len);
00042 
00043     for(int i=0; i<len; i++)
00044     {
00045         if(apu_writeHandshake(1, data[i]))
00046         {
00047             return 1;
00048         }
00049     }
00050 
00051     return 0;
00052 }
00053 
00054 // Write to address 'address', write the previously
00055 // read value from port0 back to port 0 and wait
00056 // for port0 value to be different from the written one.
00057 int apu_writeHandshake(int address, int data)
00058 {
00059     apu_write(address, data);
00060     apu_write(0, port0);
00061     
00062     if(!apu_waitInport(0, port0, 500))
00063     {
00064         return 1;
00065     }
00066 
00067     if(++port0 == 256)
00068     {
00069         port0 = 0;
00070     }
00071 
00072     return 0;
00073 }
00074 
00075 // return false on timeout, otherwise true
00076 int apu_waitInport(int port, unsigned char data, int timeout_ms)
00077 {
00078 //  printf("apu_waitInport: addr: %d, data: %02x\n", port, data);
00079 
00080     int ms;
00081     Timer t;
00082     t.start();
00083 
00084     while(apu_read(port) != data)
00085     {
00086         ms = t.read_ms();
00087         if(ms > timeout_ms)
00088         {
00089             if(g_verbose)
00090             { 
00091                 printf("timeout after %d milli\n", ms);
00092             }
00093 
00094             return 0;
00095         }
00096     }
00097 
00098     return 1;
00099 }
00100 
00101 // Initialise an spc transfer at 'address'. 
00102 // To be used after reset of after jumping to rom
00103 //
00104 // Use apu_newTransfer for additional transfers
00105 // 
00106 // return -1 on error, 0 if success
00107 int apu_initTransfer(unsigned short address)
00108 {
00109     // Initializing the transfer
00110     // Wait for port 2140 to be $aa
00111     if(!apu_waitInport(0, 0xaa, 500))
00112     {
00113         if(g_verbose)
00114         { 
00115             printf("Should read 0xaa, but reads %02x\n", apu_read(0));
00116         }
00117 
00118         return -1;
00119     }
00120 
00121     // and Wait for port 2141 to be $bb
00122     if(!apu_waitInport(1, 0xbb, 500))
00123     {
00124         if(g_verbose)
00125         { 
00126             printf("Should read 0xaa, but reads %02x\n", apu_read(0));
00127         }
00128 
00129         return -1;
00130     }
00131 
00132     // The spc is now ready
00133 
00134     // Write any value other than 0 to 2141
00135     apu_write(1, 1);
00136 
00137     // Write the destination address to poirt $2142 and $2143, with the
00138     // low byte written at $2142
00139     apu_write(2, (address & 0x00ff));      // low
00140     apu_write(3, (address & 0xff00) >> 8); // high So our code will go at $0002
00141 
00142     // Write $CC to port $2140
00143     apu_write(0, 0xCC);
00144 
00145     // Wait for $2140 to be $CC
00146     if(!apu_waitInport(0, 0xcc, 500))
00147     {
00148         if(g_verbose)
00149         { 
00150             printf("Should read 0xcc, but reads %02x\n", apu_read(0));
00151         }
00152 
00153         return -1;
00154     }
00155 
00156     port0 = 0;
00157     return 0;
00158 }
00159 
00160 // initialise a new transfer after the first transfer.
00161 //
00162 // returns 0 on success, -1 on error
00163 int apu_newTransfer(unsigned short address)
00164 {
00165     int i;
00166     apu_write(1, 1);
00167     apu_write(3, (address & 0xff00) >> 8);
00168     apu_write(2, (address & 0x00ff));
00169 
00170     i  = apu_read(0);
00171     i += 2;
00172     i &= 0xff;
00173 
00174     // if it's 0, increase it again
00175     if(!i)
00176     {
00177         i += 2;
00178     }
00179     apu_write(0, i);
00180 
00181     if(!apu_waitInport(0, i, 500))
00182     {
00183         fprintf(stderr, "apu_newTransfer: timeout\n");
00184         return -1;
00185     }
00186     
00187     port0 = 0;
00188     return 0;
00189 }
00190 
00191 // End transfer and jump to address
00192 void apu_endTransfer(unsigned short start_address)
00193 {
00194     int i;
00195     
00196     apu_write(1, 0);
00197     apu_write(3, (start_address & 0xff00) >> 8);
00198     apu_write(2, (start_address & 0x00ff));
00199 
00200     i  = apu_read(0);
00201     i += 2;
00202     i &= 0xff;
00203 
00204     // if it's 0, increase it again
00205     if(!i)
00206     {
00207         i+=2;
00208     }
00209     apu_write(0, i);
00210 }