public void YM_DELTAT_ADPCM_Reset(YM_DELTAT DELTAT, int pan, int emulation_mode) { DELTAT.now_addr = 0; DELTAT.now_step = 0; DELTAT.step = 0; DELTAT.start = 0; DELTAT.end = 0; DELTAT.limit = unchecked ((uint)~0); /* this way YM2610 and Y8950 (both of which don't have limit address reg) will still work */ DELTAT.volume = 0; DELTAT.pan = DELTAT.output_pointer; DELTAT.panPtr = pan; DELTAT.acc = 0; DELTAT.prev_acc = 0; DELTAT.adpcmd = 127; DELTAT.adpcml = 0; DELTAT.emulation_mode = (byte)emulation_mode; DELTAT.portstate = (byte)((emulation_mode == YM_DELTAT_EMULATION_MODE_YM2610) ? 0x20 : 0); DELTAT.control2 = (byte)((emulation_mode == YM_DELTAT_EMULATION_MODE_YM2610) ? 0x01 : 0); /* default setting depends on the emulation mode. MSX demo called "facdemo_4" doesn't setup control2 register at all and still works */ DELTAT.DRAMportshift = dram_rightshift[DELTAT.control2 & 3]; /* The flag mask register disables the BRDY after the reset, however ** as soon as the mask is enabled the flag needs to be set. */ /* 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); } } }
/* ADPCM B (Delta-T control type) */ public void YM_DELTAT_ADPCM_CALC(YM_DELTAT DELTAT) { /* * some examples: * value: START, REC, MEMDAT, REPEAT, SPOFF, x,x,RESET meaning: * 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 * 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 * * 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 * */ if ((DELTAT.portstate & 0xe0) == 0xa0) { YM_DELTAT_synthesis_from_external_memory(DELTAT); return; } if ((DELTAT.portstate & 0xe0) == 0x80) { /* ADPCM synthesis from CPU-managed memory (from reg $08) */ YM_DELTAT_synthesis_from_CPU_memory(DELTAT); /* change output based on data in ADPCM data reg ($08) */ return; } //todo: ADPCM analysis // if ( (DELTAT.portstate & 0xe0)==0xc0 ) // if ( (DELTAT.portstate & 0xe0)==0xe0 ) return; }
//INLINE private void YM_DELTAT_synthesis_from_CPU_memory(YM_DELTAT DELTAT) { uint step; int data; DELTAT.now_step += DELTAT.step; if (DELTAT.now_step >= (1 << YM_DELTAT_SHIFT)) { step = DELTAT.now_step >> YM_DELTAT_SHIFT; DELTAT.now_step &= (1 << YM_DELTAT_SHIFT) - 1; do { if ((DELTAT.now_addr & 1) != 0) { data = DELTAT.now_data & 0x0f; DELTAT.now_data = DELTAT.CPU_data; /* after we used CPU_data, we set BRDY bit in status register, * which means we are ready to accept another byte of data */ 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 { data = DELTAT.now_data >> 4; } DELTAT.now_addr++; /* store accumulator value */ DELTAT.prev_acc = DELTAT.acc; /* Forecast to next Forecast */ DELTAT.acc += (ym_deltat_decode_tableB1[data] * DELTAT.adpcmd / 8); YM_DELTAT_Limit(ref DELTAT.acc, YM_DELTAT_DECODE_MAX, YM_DELTAT_DECODE_MIN); /* delta to next delta */ DELTAT.adpcmd = (DELTAT.adpcmd * ym_deltat_decode_tableB2[data]) / 64; YM_DELTAT_Limit(ref DELTAT.adpcmd, YM_DELTAT_DELTA_MAX, YM_DELTAT_DELTA_MIN); } while ((--step) != 0); } /* ElSemi: Fix interpolator. */ DELTAT.adpcml = DELTAT.prev_acc * (int)((1 << YM_DELTAT_SHIFT) - DELTAT.now_step); DELTAT.adpcml += (DELTAT.acc * (int)DELTAT.now_step); DELTAT.adpcml = (DELTAT.adpcml >> YM_DELTAT_SHIFT) * (int)DELTAT.volume; /* output for work of output channels (outd[OPNxxxx])*/ DELTAT.pan[DELTAT.panPtr] += DELTAT.adpcml; }
public void YM_DELTAT_savestate(YM_DELTAT DELTAT) { //#ifdef __STATE_H__ // state_save_register_device_item(device, 0, DELTAT.portstate); // state_save_register_device_item(device, 0, DELTAT.now_addr); // state_save_register_device_item(device, 0, DELTAT.now_step); // state_save_register_device_item(device, 0, DELTAT.acc); // state_save_register_device_item(device, 0, DELTAT.prev_acc); // state_save_register_device_item(device, 0, DELTAT.adpcmd); // state_save_register_device_item(device, 0, DELTAT.adpcml); //#endif }
public void YM_DELTAT_calc_mem_mask(YM_DELTAT DELTAT) { uint MaskSize; MaskSize = 0x01; while (MaskSize < DELTAT.memory_size) { MaskSize <<= 1; } DELTAT.memory_mask = (MaskSize << 1) - 1; // it's Mask<<1 because of the nibbles return; }
public void YM_DELTAT_postload(YM_DELTAT DELTAT, byte[] regs, int regPtr) { int r; // to keep adpcml DELTAT.volume = 0; // update for (r = 1; r < 16; r++) { YM_DELTAT_ADPCM_Write(DELTAT, r, regs[regPtr + r]); } DELTAT.reg = regs; DELTAT.regPtr = regPtr; // current rom data if (DELTAT.memory != null) { DELTAT.now_data = DELTAT.memory[(DELTAT.now_addr >> 1)]; } }
//INLINE private void YM_DELTAT_synthesis_from_external_memory(YM_DELTAT DELTAT) { uint step; int data; DELTAT.now_step += DELTAT.step; if (DELTAT.now_step >= (1 << YM_DELTAT_SHIFT)) { step = DELTAT.now_step >> YM_DELTAT_SHIFT; DELTAT.now_step &= (1 << YM_DELTAT_SHIFT) - 1; do { if (DELTAT.now_addr == (DELTAT.limit << 1)) { DELTAT.now_addr = 0; } if (DELTAT.now_addr == (DELTAT.end << 1)) { /* 12-06-2001 JB: corrected comparison. Was > instead of == */ if ((DELTAT.portstate & 0x10) != 0) { /* repeat start */ DELTAT.now_addr = DELTAT.start << 1; DELTAT.acc = 0; DELTAT.adpcmd = YM_DELTAT_DELTA_DEF; DELTAT.prev_acc = 0; } 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); } } /* clear PCM BUSY bit (reflected in status register) */ DELTAT.PCM_BSY = 0; DELTAT.portstate = 0; DELTAT.adpcml = 0; DELTAT.prev_acc = 0; return; } } if ((DELTAT.now_addr & 1) != 0) { data = DELTAT.now_data & 0x0f; } else { DELTAT.now_data = DELTAT.memory[(DELTAT.now_addr >> 1)]; data = DELTAT.now_data >> 4; } DELTAT.now_addr++; /* 12-06-2001 JB: */ /* YM2610 address register is 24 bits wide.*/ /* The "+1" is there because we use 1 bit more for nibble calculations.*/ /* WARNING: */ /* Side effect: we should take the size of the mapped ROM into account */ //DELTAT.now_addr &= ( (1<<(24+1))-1); DELTAT.now_addr &= DELTAT.memory_mask; /* store accumulator value */ DELTAT.prev_acc = DELTAT.acc; /* Forecast to next Forecast */ DELTAT.acc += (ym_deltat_decode_tableB1[data] * DELTAT.adpcmd / 8); YM_DELTAT_Limit(ref DELTAT.acc, YM_DELTAT_DECODE_MAX, YM_DELTAT_DECODE_MIN); /* delta to next delta */ DELTAT.adpcmd = (DELTAT.adpcmd * ym_deltat_decode_tableB2[data]) / 64; YM_DELTAT_Limit(ref DELTAT.adpcmd, YM_DELTAT_DELTA_MAX, YM_DELTAT_DELTA_MIN); /* ElSemi: Fix interpolator. */ /*DELTAT.prev_acc = prev_acc + ((DELTAT.acc - prev_acc) / 2 );*/ } while ((--step) != 0); } /* ElSemi: Fix interpolator. */ DELTAT.adpcml = DELTAT.prev_acc * (int)((1 << YM_DELTAT_SHIFT) - DELTAT.now_step); DELTAT.adpcml += (DELTAT.acc * (int)DELTAT.now_step); DELTAT.adpcml = (DELTAT.adpcml >> YM_DELTAT_SHIFT) * (int)DELTAT.volume; /* output for work of output channels (outd[OPNxxxx])*/ DELTAT.pan[DELTAT.panPtr] += DELTAT.adpcml; }
public void YM_DELTAT_savestate(fm.device_config device, YM_DELTAT DELTAT) { }
/* 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; } }
//#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); }