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