akkera 102
/
apuplay
SPC music playback tools for real snes apu
Diff: apu.cpp
- Revision:
- 0:5bd52e196edb
- Child:
- 1:02a06cd10a33
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/apu.cpp Mon Jan 09 13:54:39 2017 +0000 @@ -0,0 +1,206 @@ +/* hwapu - SPC music playback tools for real snes apu + * Copyright (C) 2004-2005 Raphael Assenat <raph@raphnet.net> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ +#include <stdio.h> +#include <string.h> +#include "apu.h" +#include <time.h> +// #include <sys/time.h> +#include "mbed.h" + + +//#define TRACE_RW + +extern int g_verbose; // from main.c + +/******************** G L O B A L S ************************************/ +static int port0=0; +static APU_ops *apu_ops = NULL; + +void apu_setOps(APU_ops *ops) +{ + apu_ops = ops; +} + +static int SetPort0 (short data) +{ + port0=data; + return 0; +} + +void apu_write (int address, unsigned char data) +{ +//#ifdef TRACE_RW +// printf("apu_write: a=%d, %02x\n", address, data); +//#endif + apu_ops->write(address, data); +} + +unsigned char apu_read (int address) +{ + unsigned char tmp = apu_ops->read(address); +//#ifdef TRACE_RW +// printf("apu_read: a=%d -> %02x\n", address, tmp); +//#endif + + return tmp; +} + +/* 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) +{ +// int i; +// i = 0; + apu_write(address, data); + apu_write(0,port0); + + if (!apu_waitInport(0, port0, 500)) { + return 1; + } + port0++; + if (port0 == 256) + port0 = 0; + + return 0; + + +} + + +int apu_writeBytes(unsigned char *data, int len) +{ + int i; +#ifdef TRACE_RW + printf("apu_writeBytes: %d...\n", len); +#endif + for (i=0; i<len; i++) { + if (apu_writeHandshake(1, data[i])) { return 1; } + } + return 0; +} + +void apu_reset(void) //Reset the APU by whatever means it needs reset. +{ + apu_ops->reset(); + +} + +/* return false on timeout, otherwise true */ +int apu_waitInport(int port, unsigned char data, int timeout_ms) +{ + // struct timeval tv_before, tv_now; + // gettimeofday(&tv_before, NULL); + int elaps_milli; + Timer t; + t.start(); + +#ifdef TRACE_RW + printf("apu_waitInport: addr: %d, data: %02x\n",port,data); +#endif + + while(apu_read(port)!=data) { + //usleep(1); +// gettimeofday(&tv_now, NULL); +// elaps_milli = (tv_now.tv_sec - tv_before.tv_sec) * 1000; +// elaps_milli += (tv_now.tv_usec-tv_before.tv_usec)/1000; + elaps_milli = t.read_ms(); + if (elaps_milli > timeout_ms ) + { + if (g_verbose) + printf("timeout after %d milli\n", elaps_milli); + return 0; + } + } + return 1; +} + +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&0xff); // 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; + } + + SetPort0(0); + + return 0; +} + +int apu_newTransfer(unsigned short address) +{ + int i; + apu_write(1,1); + apu_write(3, (address&0xff00)>>8); + apu_write(2, (address & 0xff)); + + i = apu_read(0); + i += 2; i &= 0xff; + if (!i) { i += 2; } // if it's 0, increase it again + apu_write(0, i); + if (!apu_waitInport(0, i, 500)) { + fprintf(stderr, "apu_newTransfer: timeout\n"); return -1; + } + + SetPort0(0); + + return 0; +} + +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 & 0xff)); + + i = apu_read(0); + i +=2; i &= 0xff; + if (!i) { i+=2 ; } // if it's 0, increase it again + apu_write(0, i); +} + +