akkera 102
/
apuplay
SPC music playback tools for real snes apu
apuplay_embedded.cpp@0:5bd52e196edb, 2017-01-09 (annotated)
- Committer:
- akkera102
- Date:
- Mon Jan 09 13:54:39 2017 +0000
- Revision:
- 0:5bd52e196edb
first
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
akkera102 | 0:5bd52e196edb | 1 | /* hwapu - SPC music playback tools for real snes apu |
akkera102 | 0:5bd52e196edb | 2 | * Copyright (C) 2004-2005 Raphael Assenat <raph@raphnet.net> |
akkera102 | 0:5bd52e196edb | 3 | * |
akkera102 | 0:5bd52e196edb | 4 | * This program is free software; you can redistribute it and/or modify |
akkera102 | 0:5bd52e196edb | 5 | * it under the terms of the GNU General Public License as published by |
akkera102 | 0:5bd52e196edb | 6 | * the Free Software Foundation; either version 2 of the License, or |
akkera102 | 0:5bd52e196edb | 7 | * (at your option) any later version. |
akkera102 | 0:5bd52e196edb | 8 | * |
akkera102 | 0:5bd52e196edb | 9 | * This program is distributed in the hope that it will be useful, |
akkera102 | 0:5bd52e196edb | 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
akkera102 | 0:5bd52e196edb | 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
akkera102 | 0:5bd52e196edb | 12 | * GNU General Public License for more details. |
akkera102 | 0:5bd52e196edb | 13 | * |
akkera102 | 0:5bd52e196edb | 14 | * You should have received a copy of the GNU General Public License |
akkera102 | 0:5bd52e196edb | 15 | * along with this program; if not, write to the Free Software |
akkera102 | 0:5bd52e196edb | 16 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
akkera102 | 0:5bd52e196edb | 17 | */ |
akkera102 | 0:5bd52e196edb | 18 | #include <stdio.h> |
akkera102 | 0:5bd52e196edb | 19 | #include "apuplay.h" |
akkera102 | 0:5bd52e196edb | 20 | #include "apu.h" |
akkera102 | 0:5bd52e196edb | 21 | #include "dsploader.h" |
akkera102 | 0:5bd52e196edb | 22 | #include "bootcode.h" |
akkera102 | 0:5bd52e196edb | 23 | #ifdef PROGRESS_SPINNER |
akkera102 | 0:5bd52e196edb | 24 | #include "pspin.h" |
akkera102 | 0:5bd52e196edb | 25 | #endif |
akkera102 | 0:5bd52e196edb | 26 | |
akkera102 | 0:5bd52e196edb | 27 | extern int g_debug; |
akkera102 | 0:5bd52e196edb | 28 | extern int g_verbose; |
akkera102 | 0:5bd52e196edb | 29 | extern int g_exit_now; |
akkera102 | 0:5bd52e196edb | 30 | extern int g_playing; |
akkera102 | 0:5bd52e196edb | 31 | extern int g_progress; |
akkera102 | 0:5bd52e196edb | 32 | |
akkera102 | 0:5bd52e196edb | 33 | int LoadAPU_embedded(FILE *fptr) |
akkera102 | 0:5bd52e196edb | 34 | { |
akkera102 | 0:5bd52e196edb | 35 | int i=0, j=0, count=0, val=0; |
akkera102 | 0:5bd52e196edb | 36 | |
akkera102 | 0:5bd52e196edb | 37 | unsigned char spc_pcl; |
akkera102 | 0:5bd52e196edb | 38 | unsigned char spc_pch; |
akkera102 | 0:5bd52e196edb | 39 | unsigned char spc_a; |
akkera102 | 0:5bd52e196edb | 40 | unsigned char spc_x; |
akkera102 | 0:5bd52e196edb | 41 | unsigned char spc_y; |
akkera102 | 0:5bd52e196edb | 42 | unsigned char spc_sw; |
akkera102 | 0:5bd52e196edb | 43 | unsigned char spc_sp; |
akkera102 | 0:5bd52e196edb | 44 | |
akkera102 | 0:5bd52e196edb | 45 | // unsigned char spcdata[65536]; |
akkera102 | 0:5bd52e196edb | 46 | // unsigned char spcram[64]; |
akkera102 | 0:5bd52e196edb | 47 | |
akkera102 | 0:5bd52e196edb | 48 | unsigned char dsp_kon=0; |
akkera102 | 0:5bd52e196edb | 49 | unsigned char dsp_flg=0; |
akkera102 | 0:5bd52e196edb | 50 | unsigned char dsp_esa=0; |
akkera102 | 0:5bd52e196edb | 51 | unsigned char dsp_edl=0; |
akkera102 | 0:5bd52e196edb | 52 | |
akkera102 | 0:5bd52e196edb | 53 | unsigned char workbuf[64]; |
akkera102 | 0:5bd52e196edb | 54 | |
akkera102 | 0:5bd52e196edb | 55 | int echosize, echoregion, bootptr, readcount=0; |
akkera102 | 0:5bd52e196edb | 56 | |
akkera102 | 0:5bd52e196edb | 57 | fseek(fptr, 0x25, SEEK_SET); |
akkera102 | 0:5bd52e196edb | 58 | |
akkera102 | 0:5bd52e196edb | 59 | fread(&spc_pcl, 1, 1, fptr); |
akkera102 | 0:5bd52e196edb | 60 | fread(&spc_pch, 1, 1, fptr); |
akkera102 | 0:5bd52e196edb | 61 | fread(&spc_a, 1, 1, fptr); |
akkera102 | 0:5bd52e196edb | 62 | fread(&spc_x, 1, 1, fptr); |
akkera102 | 0:5bd52e196edb | 63 | fread(&spc_y, 1, 1, fptr); |
akkera102 | 0:5bd52e196edb | 64 | fread(&spc_sw, 1, 1, fptr); |
akkera102 | 0:5bd52e196edb | 65 | fread(&spc_sp, 1, 1, fptr); |
akkera102 | 0:5bd52e196edb | 66 | |
akkera102 | 0:5bd52e196edb | 67 | if (g_debug) { |
akkera102 | 0:5bd52e196edb | 68 | printf("PC: %02x%02x\n", spc_pch, spc_pcl); |
akkera102 | 0:5bd52e196edb | 69 | printf("A: %02X\n", spc_a); |
akkera102 | 0:5bd52e196edb | 70 | printf("X: %02X\n", spc_x); |
akkera102 | 0:5bd52e196edb | 71 | printf("Y: %02X\n", spc_y); |
akkera102 | 0:5bd52e196edb | 72 | printf("SW: %02X\n", spc_sw); |
akkera102 | 0:5bd52e196edb | 73 | printf("SP: %02X\n", spc_sp); |
akkera102 | 0:5bd52e196edb | 74 | } |
akkera102 | 0:5bd52e196edb | 75 | |
akkera102 | 0:5bd52e196edb | 76 | apu_reset(); |
akkera102 | 0:5bd52e196edb | 77 | apu_initTransfer(0x0002); |
akkera102 | 0:5bd52e196edb | 78 | |
akkera102 | 0:5bd52e196edb | 79 | if (g_verbose) |
akkera102 | 0:5bd52e196edb | 80 | printf("Restoring dsp registers...\n"); |
akkera102 | 0:5bd52e196edb | 81 | |
akkera102 | 0:5bd52e196edb | 82 | if (g_exit_now || !g_playing) { apu_reset(); return 0; } |
akkera102 | 0:5bd52e196edb | 83 | |
akkera102 | 0:5bd52e196edb | 84 | /* first, we send a small program called the dsploader which we will |
akkera102 | 0:5bd52e196edb | 85 | * use to restore the DSP registers (with our modified KON and FLG to |
akkera102 | 0:5bd52e196edb | 86 | * keep it silent) */ |
akkera102 | 0:5bd52e196edb | 87 | if (apu_writeBytes(dsploader, 16)) { |
akkera102 | 0:5bd52e196edb | 88 | fprintf(stderr, "Timeout sending dsploader\n"); |
akkera102 | 0:5bd52e196edb | 89 | return -1; |
akkera102 | 0:5bd52e196edb | 90 | } |
akkera102 | 0:5bd52e196edb | 91 | apu_endTransfer(0x0002); |
akkera102 | 0:5bd52e196edb | 92 | |
akkera102 | 0:5bd52e196edb | 93 | if (g_exit_now || !g_playing) { apu_reset(); return 0; } |
akkera102 | 0:5bd52e196edb | 94 | |
akkera102 | 0:5bd52e196edb | 95 | /* restore the 128 dsp registers one by one with the help of the dsp loader. */ |
akkera102 | 0:5bd52e196edb | 96 | fseek(fptr, OFFSET_DSPDATA, SEEK_SET); |
akkera102 | 0:5bd52e196edb | 97 | for (i=0; i<128; i+=64) |
akkera102 | 0:5bd52e196edb | 98 | { |
akkera102 | 0:5bd52e196edb | 99 | fread(workbuf, 64, 1, fptr); |
akkera102 | 0:5bd52e196edb | 100 | for (j=0; j<64; j++) |
akkera102 | 0:5bd52e196edb | 101 | { |
akkera102 | 0:5bd52e196edb | 102 | /* mute all voices and stop all notes */ |
akkera102 | 0:5bd52e196edb | 103 | if (i+j == DSP_FLG) { |
akkera102 | 0:5bd52e196edb | 104 | dsp_flg = workbuf[j]; // save it for later |
akkera102 | 0:5bd52e196edb | 105 | workbuf[j] = DSP_FLG_MUTE|DSP_FLG_ECEN; |
akkera102 | 0:5bd52e196edb | 106 | } |
akkera102 | 0:5bd52e196edb | 107 | if (i+j == DSP_KON) { |
akkera102 | 0:5bd52e196edb | 108 | dsp_kon = workbuf[j]; // save it for later |
akkera102 | 0:5bd52e196edb | 109 | workbuf[j] = 0x00; |
akkera102 | 0:5bd52e196edb | 110 | } |
akkera102 | 0:5bd52e196edb | 111 | |
akkera102 | 0:5bd52e196edb | 112 | // take note of some values while we upload... |
akkera102 | 0:5bd52e196edb | 113 | if (i+j == DSP_ESA) { dsp_esa = workbuf[j]; } |
akkera102 | 0:5bd52e196edb | 114 | if (i+j == DSP_EDL) { dsp_edl = workbuf[j]; } |
akkera102 | 0:5bd52e196edb | 115 | |
akkera102 | 0:5bd52e196edb | 116 | apu_write(1, workbuf[j]); |
akkera102 | 0:5bd52e196edb | 117 | apu_write(0, i+j); |
akkera102 | 0:5bd52e196edb | 118 | if (!apu_waitInport(0, i+j, 500)) { |
akkera102 | 0:5bd52e196edb | 119 | if (apu_read(0)==0xaa) { |
akkera102 | 0:5bd52e196edb | 120 | // fprintf(stderr, "ingored\n"); |
akkera102 | 0:5bd52e196edb | 121 | } else { |
akkera102 | 0:5bd52e196edb | 122 | fprintf(stderr, "timeout 3\n"); return -1; |
akkera102 | 0:5bd52e196edb | 123 | } |
akkera102 | 0:5bd52e196edb | 124 | } |
akkera102 | 0:5bd52e196edb | 125 | |
akkera102 | 0:5bd52e196edb | 126 | if (g_exit_now || !g_playing) { apu_reset(); return 0; } |
akkera102 | 0:5bd52e196edb | 127 | #ifdef PROGRESS_SPINNER |
akkera102 | 0:5bd52e196edb | 128 | if (g_progress) { |
akkera102 | 0:5bd52e196edb | 129 | pspin_update(); |
akkera102 | 0:5bd52e196edb | 130 | } |
akkera102 | 0:5bd52e196edb | 131 | #endif |
akkera102 | 0:5bd52e196edb | 132 | } |
akkera102 | 0:5bd52e196edb | 133 | |
akkera102 | 0:5bd52e196edb | 134 | } |
akkera102 | 0:5bd52e196edb | 135 | // if (g_verbose) |
akkera102 | 0:5bd52e196edb | 136 | // printf("\n"); |
akkera102 | 0:5bd52e196edb | 137 | |
akkera102 | 0:5bd52e196edb | 138 | /* after receiving 128 registers, the dsp loaded will jump |
akkera102 | 0:5bd52e196edb | 139 | * inside the rom at address $ffc9. Once 0xAA appears in |
akkera102 | 0:5bd52e196edb | 140 | * port0, the apu is ready for a new transfer. */ |
akkera102 | 0:5bd52e196edb | 141 | if (!apu_waitInport(0, 0xaa, 500)) { |
akkera102 | 0:5bd52e196edb | 142 | fprintf(stderr, "timeout 4\n"); return -1; |
akkera102 | 0:5bd52e196edb | 143 | } |
akkera102 | 0:5bd52e196edb | 144 | |
akkera102 | 0:5bd52e196edb | 145 | // fseek(fptr, OFFSET_SPCRAM, SEEK_SET); |
akkera102 | 0:5bd52e196edb | 146 | // fread(spcram, 64, 1, fptr); |
akkera102 | 0:5bd52e196edb | 147 | |
akkera102 | 0:5bd52e196edb | 148 | /* save a bunch of registers to be restored |
akkera102 | 0:5bd52e196edb | 149 | * later by the "bootcode" */ |
akkera102 | 0:5bd52e196edb | 150 | bootcode[BOOT_DSP_FLG] = dsp_flg; |
akkera102 | 0:5bd52e196edb | 151 | bootcode[BOOT_DSP_KON] = dsp_kon; |
akkera102 | 0:5bd52e196edb | 152 | bootcode[BOOT_A] = spc_a; |
akkera102 | 0:5bd52e196edb | 153 | bootcode[BOOT_Y] = spc_y; |
akkera102 | 0:5bd52e196edb | 154 | bootcode[BOOT_X] = spc_x; |
akkera102 | 0:5bd52e196edb | 155 | bootcode[BOOT_SP] = spc_sp - 3; // save new stack pointer |
akkera102 | 0:5bd52e196edb | 156 | |
akkera102 | 0:5bd52e196edb | 157 | /* save address $0000 and $0001 to be restored by "bootcode" */ |
akkera102 | 0:5bd52e196edb | 158 | fseek(fptr, OFFSET_SPCDATA, SEEK_SET); |
akkera102 | 0:5bd52e196edb | 159 | fread(workbuf, 2, 1, fptr); |
akkera102 | 0:5bd52e196edb | 160 | bootcode[0x01] = workbuf[0]; |
akkera102 | 0:5bd52e196edb | 161 | bootcode[0x04] = workbuf[1]; |
akkera102 | 0:5bd52e196edb | 162 | |
akkera102 | 0:5bd52e196edb | 163 | /* save most spc registers (0xf0 to 0xff) into bootcode to be restored |
akkera102 | 0:5bd52e196edb | 164 | * later */ |
akkera102 | 0:5bd52e196edb | 165 | fseek(fptr, OFFSET_SPCDATA+0xf0, SEEK_SET); |
akkera102 | 0:5bd52e196edb | 166 | fread(workbuf, 0x10, 1, fptr); |
akkera102 | 0:5bd52e196edb | 167 | for (i=0xf0; i<=0xff; i++) { |
akkera102 | 0:5bd52e196edb | 168 | switch (i) |
akkera102 | 0:5bd52e196edb | 169 | { |
akkera102 | 0:5bd52e196edb | 170 | case SPC_PORT0: bootcode[BOOT_SPC_PORT0] = workbuf[i-0xf0]; break; |
akkera102 | 0:5bd52e196edb | 171 | case SPC_PORT1: bootcode[BOOT_SPC_PORT1] = workbuf[i-0xf0]; break; |
akkera102 | 0:5bd52e196edb | 172 | case SPC_PORT2: bootcode[BOOT_SPC_PORT2] = workbuf[i-0xf0]; break; |
akkera102 | 0:5bd52e196edb | 173 | case SPC_PORT3: bootcode[BOOT_SPC_PORT3] = workbuf[i-0xf0]; break; |
akkera102 | 0:5bd52e196edb | 174 | case SPC_TIMER0: bootcode[BOOT_SPC_TIMER0] = workbuf[i-0xf0]; break; |
akkera102 | 0:5bd52e196edb | 175 | case SPC_TIMER1: bootcode[BOOT_SPC_TIMER1] = workbuf[i-0xf0]; break; |
akkera102 | 0:5bd52e196edb | 176 | case SPC_TIMER2: bootcode[BOOT_SPC_TIMER2] = workbuf[i-0xf0]; break; |
akkera102 | 0:5bd52e196edb | 177 | case SPC_CONTROL: bootcode[BOOT_SPC_CONTROL] = workbuf[i-0xf0]; break; |
akkera102 | 0:5bd52e196edb | 178 | case SPC_REGADD: bootcode[BOOT_SPC_REGADD] = workbuf[i-0xf0]; break; |
akkera102 | 0:5bd52e196edb | 179 | } |
akkera102 | 0:5bd52e196edb | 180 | } |
akkera102 | 0:5bd52e196edb | 181 | |
akkera102 | 0:5bd52e196edb | 182 | |
akkera102 | 0:5bd52e196edb | 183 | |
akkera102 | 0:5bd52e196edb | 184 | /* to produce an echo effect, the dsp uses a memory region. |
akkera102 | 0:5bd52e196edb | 185 | * ESA: Esa * 100h becomes the lead-off address of the echo |
akkera102 | 0:5bd52e196edb | 186 | * region. Calculate this address... */ |
akkera102 | 0:5bd52e196edb | 187 | echoregion = dsp_esa * 256; |
akkera102 | 0:5bd52e196edb | 188 | |
akkera102 | 0:5bd52e196edb | 189 | /* echo delay. The bigger the delay is, more memory is needed. |
akkera102 | 0:5bd52e196edb | 190 | * calculate how much memory used... */ |
akkera102 | 0:5bd52e196edb | 191 | echosize = dsp_edl * 2048; |
akkera102 | 0:5bd52e196edb | 192 | if (echosize==0) { echosize = 4; } |
akkera102 | 0:5bd52e196edb | 193 | |
akkera102 | 0:5bd52e196edb | 194 | if (g_debug) { |
akkera102 | 0:5bd52e196edb | 195 | printf("debug: echoregion: $%04x, size %d\n", echoregion, echosize); |
akkera102 | 0:5bd52e196edb | 196 | } |
akkera102 | 0:5bd52e196edb | 197 | |
akkera102 | 0:5bd52e196edb | 198 | apu_initTransfer(0x0002); |
akkera102 | 0:5bd52e196edb | 199 | if (g_verbose) |
akkera102 | 0:5bd52e196edb | 200 | printf("Restoring spc700 memory...\n"); |
akkera102 | 0:5bd52e196edb | 201 | |
akkera102 | 0:5bd52e196edb | 202 | if (g_debug) { |
akkera102 | 0:5bd52e196edb | 203 | printf("debug: Sending spc memory from 0x02 to 0xef\n"); |
akkera102 | 0:5bd52e196edb | 204 | } |
akkera102 | 0:5bd52e196edb | 205 | /* send the first part of the memory (0x02 to 0xef) |
akkera102 | 0:5bd52e196edb | 206 | * After 0xef comes spc700 registers (0xf0 to 0xff). Those |
akkera102 | 0:5bd52e196edb | 207 | * are taken care of by the bootcode. 0x00 and 0x01 are |
akkera102 | 0:5bd52e196edb | 208 | * retored by the bootcode too. */ |
akkera102 | 0:5bd52e196edb | 209 | fseek(fptr, OFFSET_SPCDATA, SEEK_SET); |
akkera102 | 0:5bd52e196edb | 210 | for (j=0; j<256; j+=64) |
akkera102 | 0:5bd52e196edb | 211 | { |
akkera102 | 0:5bd52e196edb | 212 | fread(workbuf, 64, 1, fptr); |
akkera102 | 0:5bd52e196edb | 213 | for (i=0; i<0x40; i++) { |
akkera102 | 0:5bd52e196edb | 214 | if (j+i>=0xf0) { break; } |
akkera102 | 0:5bd52e196edb | 215 | if (j==0 && i<2) { continue; } // skip $0000 and $0001 |
akkera102 | 0:5bd52e196edb | 216 | apu_write(1, workbuf[i]); |
akkera102 | 0:5bd52e196edb | 217 | apu_write(0, j+i-2); |
akkera102 | 0:5bd52e196edb | 218 | if (!apu_waitInport(0, j+i-2, 500)) { |
akkera102 | 0:5bd52e196edb | 219 | fprintf(stderr, "timeout 5\n"); return -1; |
akkera102 | 0:5bd52e196edb | 220 | } |
akkera102 | 0:5bd52e196edb | 221 | #ifdef PROGRESS_SPINNER |
akkera102 | 0:5bd52e196edb | 222 | if (g_progress) |
akkera102 | 0:5bd52e196edb | 223 | pspin_update(); |
akkera102 | 0:5bd52e196edb | 224 | #endif |
akkera102 | 0:5bd52e196edb | 225 | if (g_exit_now || !g_playing) { apu_reset(); return 0; } |
akkera102 | 0:5bd52e196edb | 226 | } |
akkera102 | 0:5bd52e196edb | 227 | if (j+i>=0xf0) { break; } |
akkera102 | 0:5bd52e196edb | 228 | } |
akkera102 | 0:5bd52e196edb | 229 | |
akkera102 | 0:5bd52e196edb | 230 | // if (g_verbose) |
akkera102 | 0:5bd52e196edb | 231 | // printf("\n"); |
akkera102 | 0:5bd52e196edb | 232 | |
akkera102 | 0:5bd52e196edb | 233 | if (apu_newTransfer(0x100)) { apu_reset(); return -1; } |
akkera102 | 0:5bd52e196edb | 234 | |
akkera102 | 0:5bd52e196edb | 235 | if (g_debug) { |
akkera102 | 0:5bd52e196edb | 236 | printf("debug: Sending spc memory from 0x100 to 0xffc0\n"); |
akkera102 | 0:5bd52e196edb | 237 | } |
akkera102 | 0:5bd52e196edb | 238 | /* upload the external memory region data (0x100 (page 1) to 0xffbf (rom), |
akkera102 | 0:5bd52e196edb | 239 | * and look for an area with the same consecutive value repeated 77 times */ |
akkera102 | 0:5bd52e196edb | 240 | fseek(fptr, OFFSET_SPCDATA+0x100, SEEK_SET); |
akkera102 | 0:5bd52e196edb | 241 | bootptr = -1; |
akkera102 | 0:5bd52e196edb | 242 | for (i=0x100; i <= 65471; i+= 16) |
akkera102 | 0:5bd52e196edb | 243 | { |
akkera102 | 0:5bd52e196edb | 244 | fread(workbuf, 16, 1, fptr); |
akkera102 | 0:5bd52e196edb | 245 | |
akkera102 | 0:5bd52e196edb | 246 | for (j=0; j<16; j++) { |
akkera102 | 0:5bd52e196edb | 247 | /* push program counter and status ward on stack */ |
akkera102 | 0:5bd52e196edb | 248 | if ((i+j) == (0x100 +spc_sp - 0)) { |
akkera102 | 0:5bd52e196edb | 249 | workbuf[j] = spc_pch; |
akkera102 | 0:5bd52e196edb | 250 | } |
akkera102 | 0:5bd52e196edb | 251 | if ((i+j) == (0x100 +spc_sp - 1)) { |
akkera102 | 0:5bd52e196edb | 252 | workbuf[j] = spc_pcl; |
akkera102 | 0:5bd52e196edb | 253 | } |
akkera102 | 0:5bd52e196edb | 254 | if ((i+j) == (0x100 +spc_sp - 2)) { |
akkera102 | 0:5bd52e196edb | 255 | workbuf[j] = spc_sw; |
akkera102 | 0:5bd52e196edb | 256 | } |
akkera102 | 0:5bd52e196edb | 257 | |
akkera102 | 0:5bd52e196edb | 258 | if ((i > echoregion + echosize) || (i < echoregion) ) |
akkera102 | 0:5bd52e196edb | 259 | { |
akkera102 | 0:5bd52e196edb | 260 | if (val==workbuf[j]) { |
akkera102 | 0:5bd52e196edb | 261 | count++; |
akkera102 | 0:5bd52e196edb | 262 | if (count>=77) { |
akkera102 | 0:5bd52e196edb | 263 | bootptr = i+j-77; |
akkera102 | 0:5bd52e196edb | 264 | // printf("nbptr: %d\n", i+j-77); |
akkera102 | 0:5bd52e196edb | 265 | } |
akkera102 | 0:5bd52e196edb | 266 | } |
akkera102 | 0:5bd52e196edb | 267 | else { |
akkera102 | 0:5bd52e196edb | 268 | val = workbuf[j]; |
akkera102 | 0:5bd52e196edb | 269 | count = 0; |
akkera102 | 0:5bd52e196edb | 270 | } |
akkera102 | 0:5bd52e196edb | 271 | } |
akkera102 | 0:5bd52e196edb | 272 | else |
akkera102 | 0:5bd52e196edb | 273 | { |
akkera102 | 0:5bd52e196edb | 274 | count = 0; |
akkera102 | 0:5bd52e196edb | 275 | } |
akkera102 | 0:5bd52e196edb | 276 | } |
akkera102 | 0:5bd52e196edb | 277 | |
akkera102 | 0:5bd52e196edb | 278 | if (apu_writeBytes(workbuf, 16)) |
akkera102 | 0:5bd52e196edb | 279 | { |
akkera102 | 0:5bd52e196edb | 280 | fprintf(stderr, "Transfer error\n"); |
akkera102 | 0:5bd52e196edb | 281 | return -1; |
akkera102 | 0:5bd52e196edb | 282 | } |
akkera102 | 0:5bd52e196edb | 283 | |
akkera102 | 0:5bd52e196edb | 284 | if (i % 256 == 0) { |
akkera102 | 0:5bd52e196edb | 285 | readcount += 256; |
akkera102 | 0:5bd52e196edb | 286 | #ifdef PROGRESS_SPINNER |
akkera102 | 0:5bd52e196edb | 287 | if (g_progress) { |
akkera102 | 0:5bd52e196edb | 288 | pspin_update(); |
akkera102 | 0:5bd52e196edb | 289 | } |
akkera102 | 0:5bd52e196edb | 290 | #endif |
akkera102 | 0:5bd52e196edb | 291 | } |
akkera102 | 0:5bd52e196edb | 292 | if (g_exit_now || !g_playing) { apu_reset(); return 0; } |
akkera102 | 0:5bd52e196edb | 293 | } |
akkera102 | 0:5bd52e196edb | 294 | |
akkera102 | 0:5bd52e196edb | 295 | // bootptr = 0x2e47; |
akkera102 | 0:5bd52e196edb | 296 | if (g_debug) { |
akkera102 | 0:5bd52e196edb | 297 | printf("debug: area for bootcode: $%04x (%02X)\n", bootptr, val); |
akkera102 | 0:5bd52e196edb | 298 | } |
akkera102 | 0:5bd52e196edb | 299 | |
akkera102 | 0:5bd52e196edb | 300 | /* we did not find an area of 77 consecutive identical byte values. */ |
akkera102 | 0:5bd52e196edb | 301 | if (bootptr == -1) |
akkera102 | 0:5bd52e196edb | 302 | { |
akkera102 | 0:5bd52e196edb | 303 | /* We will have to use the echo region. The region will need to be |
akkera102 | 0:5bd52e196edb | 304 | * at least 77 bytes... */ |
akkera102 | 0:5bd52e196edb | 305 | if (echosize < 77) { |
akkera102 | 0:5bd52e196edb | 306 | fprintf(stderr, "This spc file does not have sufficient ram to be loaded"); |
akkera102 | 0:5bd52e196edb | 307 | return -1; |
akkera102 | 0:5bd52e196edb | 308 | } |
akkera102 | 0:5bd52e196edb | 309 | else { |
akkera102 | 0:5bd52e196edb | 310 | /* we will use the echo region */ |
akkera102 | 0:5bd52e196edb | 311 | bootptr = echoregion; |
akkera102 | 0:5bd52e196edb | 312 | } |
akkera102 | 0:5bd52e196edb | 313 | } |
akkera102 | 0:5bd52e196edb | 314 | |
akkera102 | 0:5bd52e196edb | 315 | if (g_debug) { |
akkera102 | 0:5bd52e196edb | 316 | printf("debug: Sending spc memory from 0xffc0 to 0xffff\n"); |
akkera102 | 0:5bd52e196edb | 317 | } |
akkera102 | 0:5bd52e196edb | 318 | /* upload the external memory area overlapping with the rom... I guess |
akkera102 | 0:5bd52e196edb | 319 | * if we write to those address from the SPC it really writes to this |
akkera102 | 0:5bd52e196edb | 320 | * memory area, but if you read you'll probably get the ROM code. Maybe |
akkera102 | 0:5bd52e196edb | 321 | * it's really Read/Write from the DSP point of view... TODO: Check this |
akkera102 | 0:5bd52e196edb | 322 | * |
akkera102 | 0:5bd52e196edb | 323 | * Maybe also setting SPC_CONTROL msb bit enables this region? It's not |
akkera102 | 0:5bd52e196edb | 324 | * documented my manual... |
akkera102 | 0:5bd52e196edb | 325 | * */ |
akkera102 | 0:5bd52e196edb | 326 | if (bootcode[BOOT_SPC_CONTROL] & 0x80) { |
akkera102 | 0:5bd52e196edb | 327 | fseek(fptr, OFFSET_SPCRAM, SEEK_SET); |
akkera102 | 0:5bd52e196edb | 328 | fread(workbuf, 64, 1, fptr); |
akkera102 | 0:5bd52e196edb | 329 | } |
akkera102 | 0:5bd52e196edb | 330 | else { |
akkera102 | 0:5bd52e196edb | 331 | fseek(fptr, OFFSET_SPCDATA + 65472, SEEK_SET); |
akkera102 | 0:5bd52e196edb | 332 | fread(workbuf, 64, 1, fptr); |
akkera102 | 0:5bd52e196edb | 333 | } |
akkera102 | 0:5bd52e196edb | 334 | |
akkera102 | 0:5bd52e196edb | 335 | if (apu_writeBytes(workbuf, 64)) { |
akkera102 | 0:5bd52e196edb | 336 | return -1; |
akkera102 | 0:5bd52e196edb | 337 | } |
akkera102 | 0:5bd52e196edb | 338 | |
akkera102 | 0:5bd52e196edb | 339 | // if (g_verbose) |
akkera102 | 0:5bd52e196edb | 340 | // printf("\n"); |
akkera102 | 0:5bd52e196edb | 341 | |
akkera102 | 0:5bd52e196edb | 342 | if (apu_newTransfer(bootptr)) { apu_reset(); return -1; } |
akkera102 | 0:5bd52e196edb | 343 | |
akkera102 | 0:5bd52e196edb | 344 | /* Copy our bootcode into the area we found */ |
akkera102 | 0:5bd52e196edb | 345 | if (apu_writeBytes(bootcode, 77)) { |
akkera102 | 0:5bd52e196edb | 346 | fprintf(stderr, "Bootcode transfer error\n"); |
akkera102 | 0:5bd52e196edb | 347 | return -1; |
akkera102 | 0:5bd52e196edb | 348 | } |
akkera102 | 0:5bd52e196edb | 349 | |
akkera102 | 0:5bd52e196edb | 350 | apu_endTransfer(bootptr); |
akkera102 | 0:5bd52e196edb | 351 | |
akkera102 | 0:5bd52e196edb | 352 | //i = 0; |
akkera102 | 0:5bd52e196edb | 353 | if (!apu_waitInport(0, 0x53, 500)) { |
akkera102 | 0:5bd52e196edb | 354 | fprintf(stderr, "timeout 7\n"); |
akkera102 | 0:5bd52e196edb | 355 | return -1; |
akkera102 | 0:5bd52e196edb | 356 | } |
akkera102 | 0:5bd52e196edb | 357 | |
akkera102 | 0:5bd52e196edb | 358 | if (g_debug) { |
akkera102 | 0:5bd52e196edb | 359 | printf("Setting final port values $%02X $%02X $%02X $%02X\n", |
akkera102 | 0:5bd52e196edb | 360 | bootcode[BOOT_SPC_PORT0], bootcode[BOOT_SPC_PORT1], |
akkera102 | 0:5bd52e196edb | 361 | bootcode[BOOT_SPC_PORT2], bootcode[BOOT_SPC_PORT3]); |
akkera102 | 0:5bd52e196edb | 362 | } |
akkera102 | 0:5bd52e196edb | 363 | |
akkera102 | 0:5bd52e196edb | 364 | /* Restore the ports to the value they |
akkera102 | 0:5bd52e196edb | 365 | * had in the .spc (this is not done by the bootcode because |
akkera102 | 0:5bd52e196edb | 366 | * Port0-3 have 2 different values (The value set internally is |
akkera102 | 0:5bd52e196edb | 367 | * seen externaly and the value seen internally is set externally) */ |
akkera102 | 0:5bd52e196edb | 368 | apu_write(0, bootcode[BOOT_SPC_PORT0]); |
akkera102 | 0:5bd52e196edb | 369 | apu_write(1, bootcode[BOOT_SPC_PORT1]); |
akkera102 | 0:5bd52e196edb | 370 | apu_write(2, bootcode[BOOT_SPC_PORT2]); |
akkera102 | 0:5bd52e196edb | 371 | apu_write(3, bootcode[BOOT_SPC_PORT3]); |
akkera102 | 0:5bd52e196edb | 372 | |
akkera102 | 0:5bd52e196edb | 373 | |
akkera102 | 0:5bd52e196edb | 374 | if (g_exit_now || !g_playing) { apu_reset(); return 0; } |
akkera102 | 0:5bd52e196edb | 375 | return 0; |
akkera102 | 0:5bd52e196edb | 376 | } |
akkera102 | 0:5bd52e196edb | 377 | |
akkera102 | 0:5bd52e196edb | 378 |