//#if 0 //void YM_DELTAT_BRDY_callback(YM_DELTAT *DELTAT) //{ // logerror("BRDY_callback reached (flag set) !\n"); // /* set BRDY bit in status register */ // if(DELTAT->status_set_handler) // if(DELTAT->status_change_BRDY_bit) // (DELTAT->status_set_handler)(DELTAT->status_change_which_chip, DELTAT->status_change_BRDY_bit); //} //#endif public byte YM_DELTAT_ADPCM_Read(YM_DELTAT DELTAT) { byte v = 0; /* external memory read */ if ((DELTAT.portstate & 0xe0) == 0x20) { /* two dummy reads */ if (DELTAT.memread != 0) { DELTAT.now_addr = DELTAT.start << 1; DELTAT.memread--; return(0); } if (DELTAT.now_addr != (DELTAT.end << 1)) { v = DELTAT.memory[DELTAT.now_addr >> 1]; /*logerror("YM Delta-T memory read $%08x, v=$%02x\n", DELTAT.now_addr >> 1, v);*/ DELTAT.now_addr += 2; /* two nibbles at a time */ /* reset BRDY bit in status register, which means we are reading the memory now */ if (DELTAT.status_reset_handler != null) { if (DELTAT.status_change_BRDY_bit != 0) { DELTAT.status_reset_handler(DELTAT.status_change_which_chip, DELTAT.status_change_BRDY_bit); } } /* setup a timer that will callback us in 10 master clock cycles for Y8950 * in the callback set the BRDY flag to 1 , which means we have another data ready. * For now, we don't really do this; we simply reset and set the flag in zero time, so that the IRQ will work. */ /* set BRDY bit in status register */ if (DELTAT.status_set_handler != null) { if (DELTAT.status_change_BRDY_bit != 0) { DELTAT.status_set_handler(DELTAT.status_change_which_chip, DELTAT.status_change_BRDY_bit); } } } else { /* set EOS bit in status register */ if (DELTAT.status_set_handler != null) { if (DELTAT.status_change_EOS_bit != 0) { DELTAT.status_set_handler(DELTAT.status_change_which_chip, DELTAT.status_change_EOS_bit); } } } } return(v); }
/* DELTA-T ADPCM write register */ public void YM_DELTAT_ADPCM_Write(YM_DELTAT DELTAT, int r, int v) { if (r >= 0x10) { return; } DELTAT.reg[DELTAT.regPtr + r] = (byte)v; /* stock data */ switch (r) { case 0x00: /* * START: * Accessing *external* memory is started when START bit (D7) is set to "1", so * you must set all conditions needed for recording/playback before starting. * If you access *CPU-managed* memory, recording/playback starts after * read/write of ADPCM data register $08. * * REC: * 0 = ADPCM synthesis (playback) * 1 = ADPCM analysis (record) * * MEMDATA: * 0 = processor (*CPU-managed*) memory (means: using register $08) * 1 = external memory (using start/end/limit registers to access memory: RAM or ROM) * * * SPOFF: * controls output pin that should disable the speaker while ADPCM analysis * * RESET and REPEAT only work with external memory. * * * some examples: * value: START, REC, MEMDAT, REPEAT, SPOFF, x,x,RESET meaning: * C8 1 1 0 0 1 0 0 0 Analysis (recording) from AUDIO to CPU (to reg $08), sample rate in PRESCALER register * E8 1 1 1 0 1 0 0 0 Analysis (recording) from AUDIO to EXT.MEMORY, sample rate in PRESCALER register * 80 1 0 0 0 0 0 0 0 Synthesis (playing) from CPU (from reg $08) to AUDIO,sample rate in DELTA-N register * a0 1 0 1 0 0 0 0 0 Synthesis (playing) from EXT.MEMORY to AUDIO, sample rate in DELTA-N register * * 60 0 1 1 0 0 0 0 0 External memory write via ADPCM data register $08 * 20 0 0 1 0 0 0 0 0 External memory read via ADPCM data register $08 * */ /* handle emulation mode */ if (DELTAT.emulation_mode == YM_DELTAT_EMULATION_MODE_YM2610) { v |= 0x20; /* YM2610 always uses external memory and doesn't even have memory flag bit. */ } DELTAT.portstate = (byte)(v & (0x80 | 0x40 | 0x20 | 0x10 | 0x01)); /* start, rec, memory mode, repeat flag copy, reset(bit0) */ if ((DELTAT.portstate & 0x80) != 0) /* START,REC,MEMDATA,REPEAT,SPOFF,--,--,RESET */ { /* set PCM BUSY bit */ DELTAT.PCM_BSY = 1; /* start ADPCM */ DELTAT.now_step = 0; DELTAT.acc = 0; DELTAT.prev_acc = 0; DELTAT.adpcml = 0; DELTAT.adpcmd = YM_DELTAT_DELTA_DEF; DELTAT.now_data = 0; if (DELTAT.start > DELTAT.end) { logerror("DeltaT-Warning: Start: %06X, End: %06X\n", DELTAT.start, DELTAT.end); } } if ((DELTAT.portstate & 0x20) != 0) /* do we access external memory? */ { DELTAT.now_addr = DELTAT.start << 1; DELTAT.memread = 2; /* two dummy reads needed before accesing external memory via register $08*/ /* if yes, then let's check if ADPCM memory is mapped and big enough */ if (DELTAT.memory == null) { #if DEBUG logerror("YM Delta-T ADPCM rom not mapped\n"); #endif DELTAT.portstate = 0x00; DELTAT.PCM_BSY = 0; } else { if (DELTAT.end >= DELTAT.memory_size) /* Check End in Range */ { #if DEBUG logerror("YM Delta-T ADPCM end out of range: $%08x\n", DELTAT.end); #endif DELTAT.end = DELTAT.memory_size - 1; } if (DELTAT.start >= DELTAT.memory_size) /* Check Start in Range */ { #if DEBUG logerror("YM Delta-T ADPCM start out of range: $%08x\n", DELTAT.start); #endif DELTAT.portstate = 0x00; DELTAT.PCM_BSY = 0; } } } else /* we access CPU memory (ADPCM data register $08) so we only reset now_addr here */ { DELTAT.now_addr = 0; } if ((DELTAT.portstate & 0x01) != 0) { DELTAT.portstate = 0x00; /* clear PCM BUSY bit (in status register) */ DELTAT.PCM_BSY = 0; /* set BRDY flag */ if (DELTAT.status_set_handler != null) { if (DELTAT.status_change_BRDY_bit != 0) { DELTAT.status_set_handler(DELTAT.status_change_which_chip, DELTAT.status_change_BRDY_bit); } } } break; case 0x01: /* L,R,-,-,SAMPLE,DA/AD,RAMTYPE,ROM */ /* handle emulation mode */ if (DELTAT.emulation_mode == YM_DELTAT_EMULATION_MODE_YM2610) { v |= 0x01; /* YM2610 always uses ROM as an external memory and doesn't have ROM/RAM memory flag bit. */ } DELTAT.pan = DELTAT.output_pointer; DELTAT.panPtr = (v >> 6) & 0x03; if ((DELTAT.control2 & 3) != (v & 3)) { /*0-DRAM x1, 1-ROM, 2-DRAM x8, 3-ROM (3 is bad setting - not allowed by the manual) */ if (DELTAT.DRAMportshift != dram_rightshift[v & 3]) { DELTAT.DRAMportshift = dram_rightshift[v & 3]; /* final shift value depends on chip type and memory type selected: * 8 for YM2610 (ROM only), * 5 for ROM for Y8950 and YM2608, * 5 for x8bit DRAMs for Y8950 and YM2608, * 2 for x1bit DRAMs for Y8950 and YM2608. */ /* refresh addresses */ DELTAT.start = (uint)((DELTAT.reg[DELTAT.regPtr + 0x3] * 0x0100 | DELTAT.reg[DELTAT.regPtr + 0x2]) << (DELTAT.portshift - DELTAT.DRAMportshift)); DELTAT.end = (uint)((DELTAT.reg[DELTAT.regPtr + 0x5] * 0x0100 | DELTAT.reg[DELTAT.regPtr + 0x4]) << (DELTAT.portshift - DELTAT.DRAMportshift)); DELTAT.end += (uint)((1 << (DELTAT.portshift - DELTAT.DRAMportshift)) - 1); DELTAT.limit = (uint)((DELTAT.reg[DELTAT.regPtr + 0xd] * 0x0100 | DELTAT.reg[DELTAT.regPtr + 0xc]) << (DELTAT.portshift - DELTAT.DRAMportshift)); } } DELTAT.control2 = (byte)v; break; case 0x02: /* Start Address L */ case 0x03: /* Start Address H */ DELTAT.start = (uint)((DELTAT.reg[DELTAT.regPtr + 0x3] * 0x0100 | DELTAT.reg[DELTAT.regPtr + 0x2]) << (DELTAT.portshift - DELTAT.DRAMportshift)); /*logerror("DELTAT start: 02=%2x 03=%2x addr=%8x\n",DELTAT.reg[0x2], DELTAT.reg[0x3],DELTAT.start );*/ break; case 0x04: /* Stop Address L */ case 0x05: /* Stop Address H */ DELTAT.end = (uint)((DELTAT.reg[DELTAT.regPtr + 0x5] * 0x0100 | DELTAT.reg[DELTAT.regPtr + 0x4]) << (DELTAT.portshift - DELTAT.DRAMportshift)); DELTAT.end += (uint)((1 << (DELTAT.portshift - DELTAT.DRAMportshift)) - 1); /*logerror("DELTAT end : 04=%2x 05=%2x addr=%8x\n",DELTAT.reg[0x4], DELTAT.reg[0x5],DELTAT.end );*/ break; case 0x06: /* Prescale L (ADPCM and Record frq) */ case 0x07: /* Prescale H */ break; case 0x08: /* ADPCM data */ /* * some examples: * value: START, REC, MEMDAT, REPEAT, SPOFF, x,x,RESET meaning: * C8 1 1 0 0 1 0 0 0 Analysis (recording) from AUDIO to CPU (to reg $08), sample rate in PRESCALER register * E8 1 1 1 0 1 0 0 0 Analysis (recording) from AUDIO to EXT.MEMORY, sample rate in PRESCALER register * 80 1 0 0 0 0 0 0 0 Synthesis (playing) from CPU (from reg $08) to AUDIO,sample rate in DELTA-N register * a0 1 0 1 0 0 0 0 0 Synthesis (playing) from EXT.MEMORY to AUDIO, sample rate in DELTA-N register * * 60 0 1 1 0 0 0 0 0 External memory write via ADPCM data register $08 * 20 0 0 1 0 0 0 0 0 External memory read via ADPCM data register $08 * */ /* external memory write */ if ((DELTAT.portstate & 0xe0) == 0x60) { if (DELTAT.memread != 0) { DELTAT.now_addr = DELTAT.start << 1; DELTAT.memread = 0; } /*logerror("YM Delta-T memory write $%08x, v=$%02x\n", DELTAT.now_addr >> 1, v);*/ if (DELTAT.now_addr != (DELTAT.end << 1)) { DELTAT.memory[DELTAT.now_addr >> 1] = (byte)v; DELTAT.now_addr += 2; /* two nibbles at a time */ /* reset BRDY bit in status register, which means we are processing the write */ if (DELTAT.status_reset_handler != null) { if (DELTAT.status_change_BRDY_bit != 0) { DELTAT.status_reset_handler(DELTAT.status_change_which_chip, DELTAT.status_change_BRDY_bit); } } /* setup a timer that will callback us in 10 master clock cycles for Y8950 * in the callback set the BRDY flag to 1 , which means we have written the data. * For now, we don't really do this; we simply reset and set the flag in zero time, so that the IRQ will work. */ /* set BRDY bit in status register */ if (DELTAT.status_set_handler != null) { if (DELTAT.status_change_BRDY_bit != 0) { DELTAT.status_set_handler(DELTAT.status_change_which_chip, DELTAT.status_change_BRDY_bit); } } } else { /* set EOS bit in status register */ if (DELTAT.status_set_handler != null) { if (DELTAT.status_change_EOS_bit != 0) { DELTAT.status_set_handler(DELTAT.status_change_which_chip, DELTAT.status_change_EOS_bit); } } } return; } /* ADPCM synthesis from CPU */ if ((DELTAT.portstate & 0xe0) == 0x80) { DELTAT.CPU_data = (byte)v; /* Reset BRDY bit in status register, which means we are full of data */ if (DELTAT.status_reset_handler != null) { if (DELTAT.status_change_BRDY_bit != 0) { DELTAT.status_reset_handler(DELTAT.status_change_which_chip, DELTAT.status_change_BRDY_bit); } } return; } break; case 0x09: /* DELTA-N L (ADPCM Playback Prescaler) */ case 0x0a: /* DELTA-N H */ DELTAT.delta = (uint)(DELTAT.reg[DELTAT.regPtr + 0xa] * 0x0100 | DELTAT.reg[DELTAT.regPtr + 0x9]); DELTAT.step = (uint)((double)(DELTAT.delta /* *(1<<(YM_DELTAT_SHIFT-16)) */) * (DELTAT.freqbase)); /*logerror("DELTAT deltan:09=%2x 0a=%2x\n",DELTAT.reg[0x9], DELTAT.reg[0xa]);*/ break; case 0x0b: /* Output level control (volume, linear) */ { int oldvol = DELTAT.volume; DELTAT.volume = (v & 0xff) * (DELTAT.output_range / 256) / YM_DELTAT_DECODE_RANGE; /* v * ((1<<16)>>8) >> 15; * thus: v * (1<<8) >> 15; * thus: output_range must be (1 << (15+8)) at least * v * ((1<<23)>>8) >> 15; * v * (1<<15) >> 15; */ /*logerror("DELTAT vol = %2x\n",v&0xff);*/ if (oldvol != 0) { DELTAT.adpcml = (int)((double)DELTAT.adpcml / (double)oldvol * (double)DELTAT.volume); } } break; case 0x0c: /* Limit Address L */ case 0x0d: /* Limit Address H */ DELTAT.limit = (uint)((DELTAT.reg[DELTAT.regPtr + 0xd] * 0x0100 | DELTAT.reg[DELTAT.regPtr + 0xc]) << (DELTAT.portshift - DELTAT.DRAMportshift)); /*logerror("DELTAT limit: 0c=%2x 0d=%2x addr=%8x\n",DELTAT.reg[0xc], DELTAT.reg[0xd],DELTAT.limit );*/ break; } }
public static void YM_DELTAT_ADPCM_Write(int r, byte v) { if (r >= 0x10) { return; } DELTAT.reg[r] = v; switch (r) { case 0x00: if (DELTAT.emulation_mode == 1) { v |= 0x20; } DELTAT.portstate = (byte)(v & (0x80 | 0x40 | 0x20 | 0x10 | 0x01)); if ((DELTAT.portstate & 0x80) != 0) { DELTAT.PCM_BSY = 1; DELTAT.now_step = 0; DELTAT.acc = 0; DELTAT.prev_acc = 0; DELTAT.adpcml = 0; DELTAT.adpcmd = YM_DELTAT_DELTA_DEF; DELTAT.now_data = 0; } if ((DELTAT.portstate & 0x20) != 0) { DELTAT.now_addr = DELTAT.start << 1; DELTAT.memread = 2; if (ymsnddeltatrom == null) { DELTAT.portstate = 0x00; DELTAT.PCM_BSY = 0; } else { if (DELTAT.end >= DELTAT.memory_size) { DELTAT.end = DELTAT.memory_size - 1; } if (DELTAT.start >= DELTAT.memory_size) { DELTAT.portstate = 0x00; DELTAT.PCM_BSY = 0; } } } else { DELTAT.now_addr = 0; } if ((DELTAT.portstate & 0x01) != 0) { DELTAT.portstate = 0x00; DELTAT.PCM_BSY = 0; if (DELTAT.status_set_handler != null) { if (DELTAT.status_change_BRDY_bit != 0) { DELTAT.status_set_handler(DELTAT.status_change_BRDY_bit); } } } break; case 0x01: /* handle emulation mode */ if (DELTAT.emulation_mode == 1) { v |= 0x01; } DELTAT.pan_offset = (v >> 6) & 0x03; if ((DELTAT.control2 & 3) != (v & 3)) { if (DELTAT.DRAMportshift != dram_rightshift[v & 3]) { DELTAT.DRAMportshift = dram_rightshift[v & 3]; DELTAT.start = (DELTAT.reg[0x3] * 0x0100 | DELTAT.reg[0x2]) << (DELTAT.portshift - DELTAT.DRAMportshift); DELTAT.end = (DELTAT.reg[0x5] * 0x0100 | DELTAT.reg[0x4]) << (DELTAT.portshift - DELTAT.DRAMportshift); DELTAT.end += (1 << (DELTAT.portshift - DELTAT.DRAMportshift)) - 1; DELTAT.limit = (DELTAT.reg[0xd] * 0x0100 | DELTAT.reg[0xc]) << (DELTAT.portshift - DELTAT.DRAMportshift); } } DELTAT.control2 = v; break; case 0x02: case 0x03: DELTAT.start = (DELTAT.reg[0x3] * 0x0100 | DELTAT.reg[0x2]) << (DELTAT.portshift - DELTAT.DRAMportshift); break; case 0x04: case 0x05: DELTAT.end = (DELTAT.reg[0x5] * 0x0100 | DELTAT.reg[0x4]) << (DELTAT.portshift - DELTAT.DRAMportshift); DELTAT.end += (1 << (DELTAT.portshift - DELTAT.DRAMportshift)) - 1; break; case 0x06: case 0x07: break; case 0x08: if ((DELTAT.portstate & 0xe0) == 0x60) { if (DELTAT.memread != 0) { DELTAT.now_addr = DELTAT.start << 1; DELTAT.memread = 0; } if (DELTAT.now_addr != (DELTAT.end << 1)) { ymsnddeltatrom[DELTAT.now_addr >> 1] = v; DELTAT.now_addr += 2; if (DELTAT.status_reset_handler != null) { if (DELTAT.status_change_BRDY_bit != 0) { DELTAT.status_reset_handler(DELTAT.status_change_BRDY_bit); } } if (DELTAT.status_set_handler != null) { if (DELTAT.status_change_BRDY_bit != 0) { DELTAT.status_set_handler(DELTAT.status_change_BRDY_bit); } } } else { if (DELTAT.status_set_handler != null) { if (DELTAT.status_change_EOS_bit != 0) { DELTAT.status_set_handler(DELTAT.status_change_EOS_bit); } } } return; } if ((DELTAT.portstate & 0xe0) == 0x80) { DELTAT.CPU_data = v; if (DELTAT.status_reset_handler != null) { if (DELTAT.status_change_BRDY_bit != 0) { DELTAT.status_reset_handler(DELTAT.status_change_BRDY_bit); } } return; } break; case 0x09: case 0x0a: DELTAT.delta = (DELTAT.reg[0xa] * 0x0100 | DELTAT.reg[0x9]); DELTAT.step = (int)(DELTAT.delta * DELTAT.freqbase); break; case 0x0b: { int oldvol = DELTAT.volume; DELTAT.volume = (v & 0xff) * (DELTAT.output_range / 256) / YM_DELTAT_DECODE_RANGE; if (oldvol != 0) { DELTAT.adpcml = (int)((double)DELTAT.adpcml / (double)oldvol * (double)DELTAT.volume); } } break; case 0x0c: case 0x0d: DELTAT.limit = (DELTAT.reg[0xd] * 0x0100 | DELTAT.reg[0xc]) << (DELTAT.portshift - DELTAT.DRAMportshift); break; } }