akkera 102
/
apuplay
SPC music playback tools for real snes apu
apu.cpp
- Committer:
- akkera102
- Date:
- 2017-01-19
- Revision:
- 8:072621697467
- Parent:
- 2:62e6e22f8be2
File content as of revision 8:072621697467:
#include "apu.h" #include "mbed.h" #include "gpio.h" // cmd.cpp extern int g_verbose; static int port0 = 0; void apu_init(void) { port0 = 0; gpio_init(); } // Reset the APU by whatever means it needs reset. void apu_reset(void) { gpio_reset(); } unsigned char apu_read(int address) { unsigned char tmp = gpio_read(address); // printf("apu_read: a=%d -> %02x\n", address, tmp); return tmp; } void apu_write(int address, unsigned char data) { // printf("apu_write: a=%d, %02x\n", address, data); gpio_write(address, data); } // Write many bytes using handshake (see apu_writeHandshake) int apu_writeBytes(unsigned char *data, int len) { // printf("apu_writeBytes: %d...\n", len); for(int i=0; i<len; i++) { if(apu_writeHandshake(1, data[i])) { return 1; } } return 0; } // Write to address 'address', write the previously // read value from port0 back to port 0 and wait // for port0 value to be different from the written one. int apu_writeHandshake(int address, int data) { apu_write(address, data); apu_write(0, port0); if(!apu_waitInport(0, port0, 500)) { return 1; } if(++port0 == 256) { port0 = 0; } return 0; } // return false on timeout, otherwise true int apu_waitInport(int port, unsigned char data, int timeout_ms) { // printf("apu_waitInport: addr: %d, data: %02x\n", port, data); int ms; Timer t; t.start(); while(apu_read(port) != data) { ms = t.read_ms(); if(ms > timeout_ms) { if(g_verbose) { printf("timeout after %d milli\n", ms); } return 0; } } return 1; } // Initialise an spc transfer at 'address'. // To be used after reset of after jumping to rom // // Use apu_newTransfer for additional transfers // // return -1 on error, 0 if success int apu_initTransfer(unsigned short address) { // Initializing the transfer // Wait for port 2140 to be $aa if(!apu_waitInport(0, 0xaa, 500)) { if(g_verbose) { printf("Should read 0xaa, but reads %02x\n", apu_read(0)); } return -1; } // and Wait for port 2141 to be $bb if(!apu_waitInport(1, 0xbb, 500)) { if(g_verbose) { printf("Should read 0xaa, but reads %02x\n", apu_read(0)); } return -1; } // The spc is now ready // Write any value other than 0 to 2141 apu_write(1, 1); // Write the destination address to poirt $2142 and $2143, with the // low byte written at $2142 apu_write(2, (address & 0x00ff)); // low apu_write(3, (address & 0xff00) >> 8); // high So our code will go at $0002 // Write $CC to port $2140 apu_write(0, 0xCC); // Wait for $2140 to be $CC if(!apu_waitInport(0, 0xcc, 500)) { if(g_verbose) { printf("Should read 0xcc, but reads %02x\n", apu_read(0)); } return -1; } port0 = 0; return 0; } // initialise a new transfer after the first transfer. // // returns 0 on success, -1 on error int apu_newTransfer(unsigned short address) { int i; apu_write(1, 1); apu_write(3, (address & 0xff00) >> 8); apu_write(2, (address & 0x00ff)); i = apu_read(0); i += 2; i &= 0xff; // if it's 0, increase it again if(!i) { i += 2; } apu_write(0, i); if(!apu_waitInport(0, i, 500)) { fprintf(stderr, "apu_newTransfer: timeout\n"); return -1; } port0 = 0; return 0; } // End transfer and jump to address void apu_endTransfer(unsigned short start_address) { int i; apu_write(1, 0); apu_write(3, (start_address & 0xff00) >> 8); apu_write(2, (start_address & 0x00ff)); i = apu_read(0); i += 2; i &= 0xff; // if it's 0, increase it again if(!i) { i+=2; } apu_write(0, i); }