|
|
1.1 ! root 1: /* ! 2: DSP M56001 emulation ! 3: Host/Emulator <-> DSP glue ! 4: ! 5: (C) 2003-2008 ARAnyM developer team ! 6: ! 7: This program is free software; you can redistribute it and/or modify ! 8: it under the terms of the GNU General Public License as published by ! 9: the Free Software Foundation; either version 2 of the License, or ! 10: (at your option) any later version. ! 11: ! 12: This program is distributed in the hope that it will be useful, ! 13: but WITHOUT ANY WARRANTY; without even the implied warranty of ! 14: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ! 15: GNU General Public License for more details. ! 16: ! 17: You should have received a copy of the GNU General Public License ! 18: along with this program; if not, write to the Free Software ! 19: Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ! 20: */ ! 21: ! 22: #ifdef HAVE_CONFIG_H ! 23: #include "config.h" ! 24: #endif ! 25: ! 26: #include <string.h> ! 27: ! 28: #include "math.h" ! 29: #include "dsp_core.h" ! 30: #include "dsp_cpu.h" ! 31: ! 32: #ifndef M_PI ! 33: #define M_PI 3.141592653589793238462643383279502 ! 34: #endif ! 35: ! 36: #define DEBUG 0 ! 37: ! 38: /* More disasm infos, if wanted */ ! 39: #define DSP_DISASM_HOSTREAD 0 /* Dsp->Host transfer */ ! 40: #define DSP_DISASM_HOSTWRITE 0 /* Host->Dsp transfer */ ! 41: #define DSP_DISASM_STATE 0 /* State changes */ ! 42: ! 43: /* Execute DSP instructions till the DSP waits for a read/write */ ! 44: #define DSP_HOST_FORCEEXEC 1 ! 45: ! 46: /* Init DSP emulation */ ! 47: void dsp_core_init(dsp_core_t *dsp_core) ! 48: { ! 49: int i; ! 50: ! 51: #if DEBUG ! 52: fprintf(stderr, "Dsp: core init\n"); ! 53: #endif ! 54: ! 55: memset(dsp_core->ram, 0,sizeof(dsp_core->ram)); ! 56: memset(dsp_core->ramint, 0,sizeof(dsp_core->ramint)); ! 57: memset(dsp_core->hostport, 0,sizeof(dsp_core->hostport)); ! 58: ! 59: /* Initialize Y:rom[0x0100-0x01ff] with a sin table */ ! 60: for (i=0;i<256;i++) { ! 61: float src = (((float) i)*M_PI)/128.0; ! 62: Sint32 dest = (Sint32) (sin(src) * 8388608.0); /* 1<<23 */ ! 63: if (dest>8388607) { ! 64: dest = 8388607; ! 65: } else if (dest<-8388608) { ! 66: dest = -8388608; ! 67: } ! 68: dsp_core->rom[DSP_SPACE_Y][0x100+i]=dest & 0x00ffffff; ! 69: } ! 70: ! 71: /* Initialize X:rom[0x0100-0x017f] with a mu-law table */ ! 72: { ! 73: const Uint16 mulaw_base[8]={ ! 74: 0x7d7c, 0x3e7c, 0x1efc, 0x0f3c, 0x075c, 0x036c, 0x0174, 0x0078 ! 75: }; ! 76: ! 77: Uint32 position = 0x0100; ! 78: Uint32 offset = 0x040000; ! 79: ! 80: for(i=0;i<8;i++) { ! 81: int j; ! 82: Uint32 value = mulaw_base[i]<<8; ! 83: ! 84: for (j=0;j<16;j++) { ! 85: dsp_core->rom[DSP_SPACE_X][position++]=value; ! 86: value -= offset; ! 87: } ! 88: ! 89: offset >>= 1; ! 90: } ! 91: } ! 92: ! 93: /* Initialize X:rom[0x0180-0x01ff] with a a-law table */ ! 94: { ! 95: const Sint32 multiply_base[8]={ ! 96: 0x1580, 0x0ac0, 0x5600, 0x2b00, ! 97: 0x1580, 0x0058, 0x0560, 0x02b0 ! 98: }; ! 99: const Sint32 multiply_col[4]={0x10, 0x01, 0x04, 0x02}; ! 100: const Sint32 multiply_line[4]={0x40, 0x04, 0x10, 0x08}; ! 101: const Sint32 base_values[4]={0, -1, 2, 1}; ! 102: Uint32 pos=0x0180; ! 103: ! 104: for (i=0;i<8;i++) { ! 105: Sint32 alawbase, j; ! 106: ! 107: alawbase = multiply_base[i]<<8; ! 108: for (j=0;j<4;j++) { ! 109: Sint32 alawbase1, k; ! 110: ! 111: alawbase1 = alawbase + ((base_values[j]*multiply_line[i & 3])<<12); ! 112: ! 113: for (k=0;k<4;k++) { ! 114: Sint32 alawbase2; ! 115: ! 116: alawbase2 = alawbase1 + ((base_values[k]*multiply_col[i & 3])<<12); ! 117: ! 118: dsp_core->rom[DSP_SPACE_X][pos++]=alawbase2; ! 119: } ! 120: } ! 121: } ! 122: } ! 123: ! 124: dsp_core->thread = NULL; ! 125: dsp_core->semaphore = NULL; ! 126: dsp_core->mutex = NULL; ! 127: ! 128: dsp_core->running = 0; ! 129: } ! 130: ! 131: /* Shutdown DSP emulation */ ! 132: void dsp_core_shutdown(dsp_core_t *dsp_core) ! 133: { ! 134: #if DEBUG ! 135: fprintf(stderr, "Dsp: core shutdown\n"); ! 136: #endif ! 137: ! 138: dsp_core->running = 0; ! 139: ! 140: if (dsp_core->thread) { ! 141: if (SDL_SemValue(dsp_core->semaphore)==0) { ! 142: SDL_SemPost(dsp_core->semaphore); ! 143: } ! 144: SDL_WaitThread(dsp_core->thread, NULL); ! 145: dsp_core->thread = NULL; ! 146: } ! 147: ! 148: /* Destroy the semaphore */ ! 149: if (dsp_core->semaphore) { ! 150: SDL_DestroySemaphore(dsp_core->semaphore); ! 151: dsp_core->semaphore = NULL; ! 152: } ! 153: ! 154: /* Destroy mutex */ ! 155: if (dsp_core->mutex) { ! 156: SDL_DestroyMutex(dsp_core->mutex); ! 157: dsp_core->mutex = NULL; ! 158: } ! 159: } ! 160: ! 161: /* Reset */ ! 162: void dsp_core_reset(dsp_core_t *dsp_core) ! 163: { ! 164: int i; ! 165: ! 166: #if DEBUG ! 167: fprintf(stderr, "Dsp: core reset\n"); ! 168: #endif ! 169: ! 170: /* Kill existing thread and semaphore */ ! 171: dsp_core_shutdown(dsp_core); ! 172: ! 173: /* Memory */ ! 174: memset(dsp_core->periph, 0,sizeof(dsp_core->periph)); ! 175: memset(dsp_core->stack, 0,sizeof(dsp_core->stack)); ! 176: memset(dsp_core->registers, 0,sizeof(dsp_core->registers)); ! 177: ! 178: dsp_core->bootstrap_pos = 0; ! 179: ! 180: /* Registers */ ! 181: dsp_core->pc = 0x0000; ! 182: dsp_core->registers[DSP_REG_OMR]=0x02; ! 183: for (i=0;i<8;i++) { ! 184: dsp_core->registers[DSP_REG_M0+i]=0x00ffff; ! 185: } ! 186: ! 187: /* host port init, dsp side */ ! 188: dsp_core->periph[DSP_SPACE_X][DSP_HOST_HSR]=(1<<DSP_HOST_HSR_HTDE); ! 189: ! 190: /* host port init, cpu side */ ! 191: dsp_core->hostport[CPU_HOST_CVR]=0x12; ! 192: dsp_core->hostport[CPU_HOST_ISR]=(1<<CPU_HOST_ISR_TRDY)|(1<<CPU_HOST_ISR_TXDE); ! 193: dsp_core->hostport[CPU_HOST_IVR]=0x0f; ! 194: ! 195: /* Other hardware registers */ ! 196: dsp_core->periph[DSP_SPACE_X][DSP_IPR]=0; ! 197: dsp_core->periph[DSP_SPACE_X][DSP_BCR]=0xffff; ! 198: ! 199: /* Misc */ ! 200: dsp_core->loop_rep = 0; ! 201: ! 202: #if DEBUG ! 203: fprintf(stderr, "Dsp: reset done\n"); ! 204: #endif ! 205: ! 206: /* Create thread, semaphore, mutex if needed */ ! 207: if (dsp_core->semaphore == NULL) { ! 208: dsp_core->semaphore = SDL_CreateSemaphore(0); ! 209: } ! 210: if (dsp_core->mutex == NULL) { ! 211: dsp_core->mutex = SDL_CreateMutex(); ! 212: } ! 213: if (dsp_core->thread == NULL) { ! 214: dsp_core->thread = SDL_CreateThread(dsp56k_do_execute, dsp_core); ! 215: } ! 216: } ! 217: ! 218: /* Force execution of DSP instructions, till cpu has read/written host port ! 219: Should not be needed at all, as it slows down host cpu emulation ! 220: */ ! 221: ! 222: #if DSP_HOST_FORCEEXEC ! 223: static void dsp_core_force_exec(dsp_core_t *dsp_core) ! 224: { ! 225: Uint32 start = SDL_GetTicks(); ! 226: ! 227: while (dsp_core->running /* DSP thread running */ ! 228: && (SDL_SemValue(dsp_core->semaphore)!=0) /* and executing instructions */ ! 229: && (SDL_GetTicks()-start<200)) ! 230: { ! 231: SDL_Delay(1); ! 232: } ! 233: } ! 234: #endif ! 235: ! 236: static void dsp_core_hostport_update_trdy(dsp_core_t *dsp_core) ! 237: { ! 238: int trdy; ! 239: ! 240: /* Clear/set TRDY bit */ ! 241: dsp_core->hostport[CPU_HOST_ISR] &= 0xff-(1<<CPU_HOST_ISR_TRDY); ! 242: trdy = (dsp_core->hostport[CPU_HOST_ISR]>>CPU_HOST_ISR_TXDE) ! 243: & ~(dsp_core->periph[DSP_SPACE_X][DSP_HOST_HSR]>>DSP_HOST_HSR_HRDF); ! 244: dsp_core->hostport[CPU_HOST_ISR] |= (trdy & 1)<< CPU_HOST_ISR_TRDY; ! 245: } ! 246: ! 247: /* Host port transfer ? (dsp->host) */ ! 248: static void dsp_core_dsp2host(dsp_core_t *dsp_core) ! 249: { ! 250: if (dsp_core->hostport[CPU_HOST_ISR] & (1<<CPU_HOST_ISR_RXDF)) { ! 251: return; ! 252: } ! 253: if (dsp_core->periph[DSP_SPACE_X][DSP_HOST_HSR] & (1<<DSP_HOST_HSR_HTDE)) { ! 254: return; ! 255: } ! 256: ! 257: dsp_core->hostport[CPU_HOST_RXL] = dsp_core->periph[DSP_SPACE_X][DSP_HOST_HTX]; ! 258: dsp_core->hostport[CPU_HOST_RXM] = dsp_core->periph[DSP_SPACE_X][DSP_HOST_HTX]>>8; ! 259: dsp_core->hostport[CPU_HOST_RXH] = dsp_core->periph[DSP_SPACE_X][DSP_HOST_HTX]>>16; ! 260: #if DSP_DISASM_HOSTWRITE ! 261: fprintf(stderr, "Dsp: (D->H): Transfer 0x%06x\n", dsp_core->periph[DSP_SPACE_X][DSP_HOST_HTX]); ! 262: #endif ! 263: ! 264: /* Set HTDE bit to say that DSP can write */ ! 265: dsp_core->periph[DSP_SPACE_X][DSP_HOST_HSR] |= 1<<DSP_HOST_HSR_HTDE; ! 266: #if DSP_DISASM_HOSTWRITE ! 267: fprintf(stderr, "Dsp: (D->H): Dsp HTDE set\n"); ! 268: #endif ! 269: ! 270: /* Set RXDF bit to say that host can read */ ! 271: dsp_core->hostport[CPU_HOST_ISR] |= 1<<CPU_HOST_ISR_RXDF; ! 272: #if DSP_DISASM_HOSTWRITE ! 273: fprintf(stderr, "Dsp: (D->H): Host RXDF set\n"); ! 274: #endif ! 275: } ! 276: ! 277: /* Host port transfer ? (host->dsp) */ ! 278: static void dsp_core_host2dsp(dsp_core_t *dsp_core) ! 279: { ! 280: if (dsp_core->hostport[CPU_HOST_ISR] & (1<<CPU_HOST_ISR_TXDE)) { ! 281: return; ! 282: } ! 283: if (dsp_core->periph[DSP_SPACE_X][DSP_HOST_HSR] & (1<<DSP_HOST_HSR_HRDF)) { ! 284: return; ! 285: } ! 286: ! 287: dsp_core->periph[DSP_SPACE_X][DSP_HOST_HRX] = dsp_core->hostport[CPU_HOST_TXL]; ! 288: dsp_core->periph[DSP_SPACE_X][DSP_HOST_HRX] |= dsp_core->hostport[CPU_HOST_TXM]<<8; ! 289: dsp_core->periph[DSP_SPACE_X][DSP_HOST_HRX] |= dsp_core->hostport[CPU_HOST_TXH]<<16; ! 290: #if DSP_DISASM_HOSTREAD ! 291: fprintf(stderr, "Dsp: (H->D): Transfer 0x%06x\n", dsp_core->periph[DSP_SPACE_X][DSP_HOST_HRX]); ! 292: #endif ! 293: ! 294: /* Set HRDF bit to say that DSP can read */ ! 295: dsp_core->periph[DSP_SPACE_X][DSP_HOST_HSR] |= 1<<DSP_HOST_HSR_HRDF; ! 296: #if DSP_DISASM_HOSTREAD ! 297: fprintf(stderr, "Dsp: (H->D): Dsp HRDF set\n"); ! 298: #endif ! 299: ! 300: /* Set TXDE bit to say that host can write */ ! 301: dsp_core->hostport[CPU_HOST_ISR] |= 1<<CPU_HOST_ISR_TXDE; ! 302: # if DSP_DISASM_HOSTREAD ! 303: fprintf(stderr, "Dsp: (H->D): Host TXDE set\n"); ! 304: # endif ! 305: ! 306: dsp_core_hostport_update_trdy(dsp_core); ! 307: } ! 308: ! 309: void dsp_core_hostport_dspread(dsp_core_t *dsp_core) ! 310: { ! 311: /* Clear HRDF bit to say that DSP has read */ ! 312: dsp_core->periph[DSP_SPACE_X][DSP_HOST_HSR] &= 0xff-(1<<DSP_HOST_HSR_HRDF); ! 313: #if DSP_DISASM_HOSTREAD ! 314: fprintf(stderr, "Dsp: (H->D): Dsp HRDF cleared\n"); ! 315: #endif ! 316: dsp_core_hostport_update_trdy(dsp_core); ! 317: dsp_core_host2dsp(dsp_core); ! 318: } ! 319: ! 320: void dsp_core_hostport_dspwrite(dsp_core_t *dsp_core) ! 321: { ! 322: /* Clear HTDE bit to say that DSP has written */ ! 323: dsp_core->periph[DSP_SPACE_X][DSP_HOST_HSR] &= 0xff-(1<<DSP_HOST_HSR_HTDE); ! 324: #if DSP_DISASM_HOSTWRITE ! 325: fprintf(stderr, "Dsp: (D->H): Dsp HTDE cleared\n"); ! 326: #endif ! 327: ! 328: dsp_core_dsp2host(dsp_core); ! 329: } ! 330: ! 331: static void dsp_core_hostport_cpuread(dsp_core_t *dsp_core) ! 332: { ! 333: /* Clear RXDF bit to say that CPU has read */ ! 334: dsp_core->hostport[CPU_HOST_ISR] &= 0xff-(1<<CPU_HOST_ISR_RXDF); ! 335: #if DSP_DISASM_HOSTWRITE ! 336: fprintf(stderr, "Dsp: (D->H): Host RXDF cleared\n"); ! 337: #endif ! 338: dsp_core_dsp2host(dsp_core); ! 339: } ! 340: ! 341: static void dsp_core_hostport_cpuwrite(dsp_core_t *dsp_core) ! 342: { ! 343: /* Clear TXDE to say that CPU has written */ ! 344: dsp_core->hostport[CPU_HOST_ISR] &= 0xff-(1<<CPU_HOST_ISR_TXDE); ! 345: #if DSP_DISASM_HOSTREAD ! 346: fprintf(stderr, "Dsp: (H->D): Host TXDE cleared\n"); ! 347: #endif ! 348: ! 349: dsp_core_hostport_update_trdy(dsp_core); ! 350: dsp_core_host2dsp(dsp_core); ! 351: } ! 352: ! 353: /* Read/writes on host port */ ! 354: ! 355: Uint8 dsp_core_read_host(dsp_core_t *dsp_core, int addr) ! 356: { ! 357: #if 0 /* DSP_HOST_FORCEEXEC */ ! 358: switch(addr) { ! 359: case CPU_HOST_RXH: ! 360: case CPU_HOST_RXM: ! 361: case CPU_HOST_RXL: ! 362: dsp_core_force_exec(dsp_core); ! 363: break; ! 364: } ! 365: #endif ! 366: ! 367: SDL_LockMutex(dsp_core->mutex); ! 368: Uint8 value = dsp_core->hostport[addr]; ! 369: if (addr == CPU_HOST_RXL) { ! 370: dsp_core_hostport_cpuread(dsp_core); ! 371: ! 372: /* Wake up DSP if it was waiting our read */ ! 373: #if DSP_DISASM_STATE ! 374: fprintf(stderr, "Dsp: WAIT_HOSTREAD done\n"); ! 375: #endif ! 376: SDL_SemPost(dsp_core->semaphore); ! 377: } ! 378: SDL_UnlockMutex(dsp_core->mutex); ! 379: ! 380: return value; ! 381: } ! 382: ! 383: void dsp_core_write_host(dsp_core_t *dsp_core, int addr, Uint8 value) ! 384: { ! 385: #if DSP_HOST_FORCEEXEC ! 386: switch(addr) { ! 387: case CPU_HOST_TXH: ! 388: case CPU_HOST_TXM: ! 389: case CPU_HOST_TXL: ! 390: dsp_core_force_exec(dsp_core); ! 391: break; ! 392: } ! 393: #endif ! 394: ! 395: SDL_LockMutex(dsp_core->mutex); ! 396: switch(addr) { ! 397: case CPU_HOST_ICR: ! 398: dsp_core->hostport[CPU_HOST_ICR]=value & 0xfb; ! 399: /* Set HF1 and HF0 accordingly on the host side */ ! 400: dsp_core->periph[DSP_SPACE_X][DSP_HOST_HSR] &= ! 401: 0xff-((1<<DSP_HOST_HSR_HF1)|(1<<DSP_HOST_HSR_HF0)); ! 402: dsp_core->periph[DSP_SPACE_X][DSP_HOST_HSR] |= ! 403: dsp_core->hostport[CPU_HOST_ICR] & ((1<<DSP_HOST_HSR_HF1)|(1<<DSP_HOST_HSR_HF0)); ! 404: break; ! 405: case CPU_HOST_CVR: ! 406: dsp_core->hostport[CPU_HOST_CVR]=value & 0x9f; ! 407: /* if bit 7=1, host command */ ! 408: if (value & (1<<7)) { ! 409: dsp_core->periph[DSP_SPACE_X][DSP_HOST_HSR] |= 1<<DSP_HOST_HSR_HCP; ! 410: } ! 411: break; ! 412: case CPU_HOST_ISR: ! 413: case CPU_HOST_TX0: ! 414: /* Read only */ ! 415: break; ! 416: case CPU_HOST_IVR: ! 417: case CPU_HOST_TXH: ! 418: case CPU_HOST_TXM: ! 419: dsp_core->hostport[addr]=value; ! 420: break; ! 421: case CPU_HOST_TXL: ! 422: dsp_core->hostport[CPU_HOST_TXL]=value; ! 423: ! 424: if (!dsp_core->running) { ! 425: dsp_core->ramint[DSP_SPACE_P][dsp_core->bootstrap_pos] = ! 426: (dsp_core->hostport[CPU_HOST_TXH]<<16) | ! 427: (dsp_core->hostport[CPU_HOST_TXM]<<8) | ! 428: dsp_core->hostport[CPU_HOST_TXL]; ! 429: #if DEBUG ! 430: fprintf(stderr, "Dsp: bootstrap p:0x%04x = 0x%06x\n", ! 431: dsp_core->bootstrap_pos, ! 432: dsp_core->ramint[DSP_SPACE_P][dsp_core->bootstrap_pos]); ! 433: #endif ! 434: if (++dsp_core->bootstrap_pos == 0x200) { ! 435: #if DSP_DISASM_STATE ! 436: fprintf(stderr, "Dsp: WAIT_BOOTSTRAP done\n"); ! 437: #endif ! 438: dsp_core->running = 1; ! 439: SDL_SemPost(dsp_core->semaphore); ! 440: } ! 441: } else { ! 442: dsp_core_hostport_cpuwrite(dsp_core); ! 443: ! 444: /* Wake up DSP if it was waiting our write */ ! 445: #if DSP_DISASM_STATE ! 446: fprintf(stderr, "Dsp: WAIT_HOSTWRITE done\n"); ! 447: #endif ! 448: SDL_SemPost(dsp_core->semaphore); ! 449: } ! 450: break; ! 451: } ! 452: SDL_UnlockMutex(dsp_core->mutex); ! 453: } ! 454: ! 455: /* ! 456: vim:ts=4:sw=4: ! 457: */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.