akkera 102
/
apuplay
SPC music playback tools for real snes apu
Diff: apu.cpp
- Revision:
- 2:62e6e22f8be2
- Parent:
- 1:02a06cd10a33
--- a/apu.cpp Mon Jan 09 13:58:58 2017 +0000 +++ b/apu.cpp Wed Jan 11 16:00:29 2017 +0000 @@ -1,206 +1,210 @@ -/* 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" - +#include "gpio.h" -//#define TRACE_RW +// cmd.cpp +extern int g_verbose; -extern int g_verbose; // from main.c +static int port0 = 0; -/******************** G L O B A L S ************************************/ -static int port0=0; -static APU_ops *apu_ops = NULL; - -void apu_setOps(APU_ops *ops) +void apu_init(void) { - apu_ops = ops; + port0 = 0; + gpio_init(); } -static int SetPort0 (short data) +// Reset the APU by whatever means it needs reset. +void apu_reset(void) { - port0=data; - return 0; + gpio_reset(); } -void apu_write (int address, unsigned char data) +unsigned char apu_read(int address) { -//#ifdef TRACE_RW -// printf("apu_write: a=%d, %02x\n", address, data); -//#endif - apu_ops->write(address, data); -} + unsigned char tmp = gpio_read(address); -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) +void apu_write(int address, unsigned char 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; +// printf("apu_write: a=%d, %02x\n", address, data); - return 0; - - + gpio_write(address, data); } - +// Write many bytes using handshake (see apu_writeHandshake) 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; } +// printf("apu_writeBytes: %d...\n", len); + + for(int 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. +// 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_ops->reset(); + 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 */ +// 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; +// printf("apu_waitInport: addr: %d, data: %02x\n", port, data); + + int ms; 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 ) + while(apu_read(port) != data) + { + ms = t.read_ms(); + if(ms > timeout_ms) { - if (g_verbose) - printf("timeout after %d milli\n", elaps_milli); + 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) + // 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); + // 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)); + } - /* 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); - + // 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 & 0xff)); + apu_write(1, 1); + apu_write(3, (address & 0xff00) >> 8); + apu_write(2, (address & 0x00ff)); + + i = apu_read(0); + i += 2; + i &= 0xff; - i = apu_read(0); - i += 2; i &= 0xff; - if (!i) { i += 2; } // if it's 0, increase it again + // 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; + + if(!apu_waitInport(0, i, 500)) + { + fprintf(stderr, "apu_newTransfer: timeout\n"); + return -1; } - SetPort0(0); - + 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 & 0xff)); + apu_write(3, (start_address & 0xff00) >> 8); + apu_write(2, (start_address & 0x00ff)); - i = apu_read(0); - i +=2; i &= 0xff; - if (!i) { i+=2 ; } // if it's 0, increase it again + i = apu_read(0); + i += 2; + i &= 0xff; + + // if it's 0, increase it again + if(!i) + { + i+=2; + } apu_write(0, i); } - -