/************************************************************ * * DRQ callback * *************************************************************/ /*static TIMER_CALLBACK( upd7759_slave_update ) * { * upd7759_state *chip = (upd7759_state *)ptr; * UINT8 olddrq = chip.drq; * * // update the stream * //stream_update(chip.channel); * * // advance the state * advance_state(chip); * * // if the DRQ changed, update it * logerror("slave_update: DRQ %d->%d\n", olddrq, chip.drq); * if (olddrq != chip.drq && chip.drqcallback) * //(*chip.drqcallback)(chip.device, chip.drq); * (*chip.drqcallback)(chip.drq); * * // set a timer to go off when that is done * //if (chip.state != STATE_IDLE) * // timer_adjust_oneshot(chip.timer, attotime_mul(chip.clock_period, chip.clocks_left), 0); * }*/ /************************************************************ * * Sound startup * *************************************************************/ private void upd7759_reset(_upd7759_state chip) { chip.pos = 0; chip.fifo_in = 0; chip.drq = 0; chip.state = (sbyte)STATE.IDLE; chip.clocks_left = 0; chip.nibbles_left = 0; chip.repeat_count = 0; chip.post_drq_state = (sbyte)STATE.IDLE; chip.post_drq_clocks = 0; chip.req_sample = 0; chip.last_sample = 0; chip.block_header = 0; chip.sample_rate = 0; chip.first_valid_header = 0; chip.offset = 0; chip.repeat_offset = 0; chip.adpcm_state = 0; chip.adpcm_data = 0; chip.sample = 0; // Valley Bell: reset buffer chip.data_buf[0] = chip.data_buf[1] = 0x00; chip.dbuf_pos_read = 0x00; chip.dbuf_pos_write = 0x00; /* turn off any timer */ //if (chip.timer) // timer_adjust_oneshot(chip.timer, attotime_never, 0); if (chip.ChipMode != 0) { chip.clocks_left = -1; } }
//static DEVICE_RESET( upd7759 ) private void device_reset_upd7759(byte ChipID) { _upd7759_state chip = UPD7759Data[ChipID]; //upd7759_reset(get_safe_token(device)); upd7759_reset(chip); }
public void uPD7759_write_rom2(byte ChipID, int ROMSize, int DataStart, int DataLength, byte[] ROMData, int SrcStartAdr) { _upd7759_state chip = UPD7759Data[ChipID]; if (chip.romsize != ROMSize) { chip.rombase = new byte[ROMSize]; // (UINT8*) realloc(chip.rombase, ROMSize); chip.romsize = (uint)ROMSize; for (int i = 0; i < ROMSize; i++) { chip.rombase[i] = 0xff; } chip.rom = chip.rombase; chip.romPtr = (int)chip.romoffset; } if (DataStart > ROMSize) { return; } if (DataStart + DataLength > ROMSize) { DataLength = ROMSize - DataStart; } for (int i = 0; i < DataLength; i++) { chip.rombase[i + DataStart] = ROMData[i + SrcStartAdr]; } return; }
//void upd7759_start_w(running_device *device, UINT8 data) private void upd7759_start_w(byte ChipID, byte data) { /* update the start value */ //upd7759_state *chip = get_safe_token(device); _upd7759_state chip = UPD7759Data[ChipID]; byte oldstart = chip.start; chip.start = (byte)((data != 0) ? 1 : 0); #if DEBUG if (DEBUG_STATES != 0) { logerror(string.Format("upd7759_start_w: {0}->{1}\n", oldstart, chip.start)); } #endif /* update the stream first */ //stream_update(chip.channel); /* on the rising edge, if we're idle, start going, but not if we're held in reset */ if (chip.state == STATE.IDLE && oldstart == 0 && chip.start != 0 && chip.reset != 0) { chip.state = STATE.START; /* for slave mode, start the timer going */ //if (chip.timer) // timer_adjust_oneshot(chip.timer, attotime_zero, 0); chip.clocks_left = 0; } }
//int upd7759_busy_r(running_device *device) private int upd7759_busy_r(byte ChipID) { /* return /BUSY */ //upd7759_state *chip = get_safe_token(device); _upd7759_state chip = UPD7759Data[ChipID]; return((chip.state == (sbyte)STATE.IDLE) ? 1 : 0); }
//void upd7759_set_bank_base(running_device *device, UINT32 base) private void upd7759_set_bank_base(byte ChipID, UInt32 base_) { //upd7759_state *chip = get_safe_token(device); _upd7759_state chip = UPD7759Data[ChipID]; chip.rom = chip.rombase; chip.romPtr = (int)base_; chip.romoffset = base_; }
private void device_stop_upd7759(byte ChipID) { _upd7759_state chip = UPD7759Data[ChipID]; //free(chip.rombase); chip.rombase = NULL; chip.rom = null; chip.romPtr = 0; chip.rombase = null; return; }
/************************************************************ * * Master chip state machine * *************************************************************/ private void get_fifo_data(_upd7759_state chip) { if (chip.dbuf_pos_read == chip.dbuf_pos_write) { logerror("Warning: UPD7759 reading empty FIFO!\n"); return; } chip.fifo_in = chip.data_buf[chip.dbuf_pos_read]; chip.dbuf_pos_read++; chip.dbuf_pos_read &= 0x3F; return; }
/************************************************************ * * ADPCM sample updater * *************************************************************/ private void update_adpcm(_upd7759_state chip, int data) { /* update the sample and the state */ chip.sample += (Int16)upd7759_step[chip.adpcm_state][data]; chip.adpcm_state += (sbyte)upd7759_state_table[data]; /* clamp the state to 0..15 */ if (chip.adpcm_state < 0) { chip.adpcm_state = 0; } else if (chip.adpcm_state > 15) { chip.adpcm_state = 15; } }
/************************************************************ * * I/O handlers * *************************************************************/ //void upd7759_reset_w(running_device *device, UINT8 data) private void upd7759_reset_w(byte ChipID, byte data) { /* update the reset value */ //upd7759_state *chip = get_safe_token(device); _upd7759_state chip = UPD7759Data[ChipID]; byte oldreset = chip.reset; chip.reset = (byte)((data != 0) ? 1 : 0); /* update the stream first */ //stream_update(chip.channel); /* on the falling edge, reset everything */ if (oldreset != 0 && chip.reset == 0) { upd7759_reset(chip); } }
//WRITE8_DEVICE_HANDLER( upd7759_port_w ) private void upd7759_port_w(byte ChipID, int offset, byte data) { /* update the FIFO value */ //upd7759_state *chip = get_safe_token(device); _upd7759_state chip = UPD7759Data[ChipID]; if (chip.ChipMode == 0) { chip.fifo_in = data; } else { // Valley Bell: added FIFO buffer for Slave mode chip.data_buf[chip.dbuf_pos_write] = data; chip.dbuf_pos_write++; chip.dbuf_pos_write &= 0x3F; } }
/************************************************************ * * Stream callback * *************************************************************/ //static STREAM_UPDATE( upd7759_update ) private void upd7759_update(byte ChipID, int[][] outputs, int samples) { //upd7759_state *chip = (upd7759_state *)param; _upd7759_state chip = UPD7759Data[ChipID]; Int32 clocks_left = chip.clocks_left; Int16 sample = chip.sample; UInt32 step = chip.step; UInt32 pos = chip.pos; int[] buffer = outputs[0]; int[] buffer2 = outputs[1]; int bufferPtr = 0; int bufferPtr2 = 0; /* loop until done */ if (chip.state != (sbyte)STATE.IDLE) { while (samples != 0) { /* store the current sample */ buffer[bufferPtr++] = sample << 7; buffer2[bufferPtr2++] = sample << 7; samples--; /* advance by the number of clocks/output sample */ pos += step; /* handle clocks, but only in standalone mode */ if (chip.ChipMode == 0) { while (chip.rom != null && pos >= FRAC_ONE) { int clocks_this_time = (int)(pos >> FRAC_BITS); if (clocks_this_time > clocks_left) { clocks_this_time = clocks_left; } /* clock once */ pos -= (uint)(clocks_this_time * FRAC_ONE); clocks_left -= clocks_this_time; /* if we're out of clocks, time to handle the next state */ if (clocks_left == 0) { /* advance one state; if we hit idle, bail */ advance_state(chip); if (chip.state == (sbyte)STATE.IDLE) { break; } /* reimport the variables that we cached */ clocks_left = chip.clocks_left; sample = chip.sample; } } } else { byte CntFour; if (clocks_left == 0) { advance_state(chip); clocks_left = chip.clocks_left; } // advance the state (4x because of Clock Divider /4) for (CntFour = 0; CntFour < 4; CntFour++) { clocks_left--; if (clocks_left == 0) { advance_state(chip); clocks_left = chip.clocks_left; } } } } } /* if we got out early, just zap the rest of the buffer */ if (samples != 0) { for (int i = 0; i < buffer.Length; i++) { buffer[i] = 0; } for (int i = 0; i < buffer2.Length; i++) { buffer2[i] = 0; } } /* flush the state back */ chip.clocks_left = clocks_left; chip.pos = pos; }
private void advance_state(_upd7759_state chip) { switch (chip.state) { /* Idle state: we stick around here while there's nothing to do */ case STATE.IDLE: chip.clocks_left = 4; break; /* drop DRQ state: update to the intended state */ case STATE.DROP_DRQ: chip.drq = 0; if (chip.ChipMode != 0) { get_fifo_data(chip); // Slave Mode only } chip.clocks_left = chip.post_drq_clocks; chip.state = chip.post_drq_state; break; /* Start state: we begin here as soon as a sample is triggered */ case STATE.START: chip.req_sample = (byte)(chip.rom != null ? chip.fifo_in : 0x10); #if DEBUG if (DEBUG_STATES != 0) { DEBUG_METHOD(string.Format("UPD7759: req_sample = {0:02X}\n", chip.req_sample)); } #endif /* 35+ cycles after we get here, the /DRQ goes low * (first byte (number of samples in ROM) should be sent in response) * * (35 is the minimum number of cycles I found during heavy tests. * Depending on the state the chip was in just before the /MD was set to 0 (reset, standby * or just-finished-playing-previous-sample) this number can range from 35 up to ~24000). * It also varies slightly from test to test, but not much - a few cycles at most.) */ chip.clocks_left = 70; /* 35 - breaks cotton */ chip.state = STATE.FIRST_REQ; break; /* First request state: issue a request for the first byte */ /* The expected response will be the index of the last sample */ case STATE.FIRST_REQ: #if DEBUG if (DEBUG_STATES != 0) { DEBUG_METHOD("UPD7759: first data request\n"); } #endif chip.drq = 1; /* 44 cycles later, we will latch this value and request another byte */ chip.clocks_left = 44; chip.state = STATE.LAST_SAMPLE; break; /* Last sample state: latch the last sample value and issue a request for the second byte */ /* The second byte read will be just a dummy */ case STATE.LAST_SAMPLE: chip.last_sample = chip.rom != null ? chip.rom[chip.romPtr + 0] : chip.fifo_in; #if DEBUG if (DEBUG_STATES != 0) { DEBUG_METHOD(string.Format("UPD7759: last_sample = {0:02X}, requesting dummy 1\n", chip.last_sample)); } #endif chip.drq = 1; /* 28 cycles later, we will latch this value and request another byte */ chip.clocks_left = 28; /* 28 - breaks cotton */ chip.state = ((chip.req_sample > chip.last_sample) ? STATE.IDLE : STATE.DUMMY1); break; /* First dummy state: ignore any data here and issue a request for the third byte */ /* The expected response will be the MSB of the sample address */ case STATE.DUMMY1: #if DEBUG if (DEBUG_STATES != 0) { DEBUG_METHOD("UPD7759: dummy1, requesting offset_hi\n"); } #endif chip.drq = 1; /* 32 cycles later, we will latch this value and request another byte */ chip.clocks_left = 32; chip.state = STATE.ADDR_MSB; break; /* Address MSB state: latch the MSB of the sample address and issue a request for the fourth byte */ /* The expected response will be the LSB of the sample address */ case STATE.ADDR_MSB: chip.offset = (uint)((chip.rom != null ? chip.rom[chip.romPtr + (chip.req_sample * 2 + 5)] : chip.fifo_in) << 9); #if DEBUG if (DEBUG_STATES != 0) { DEBUG_METHOD(string.Format("UPD7759: offset_hi = {0:02X}, requesting offset_lo\n", chip.offset >> 9)); } #endif chip.drq = 1; /* 44 cycles later, we will latch this value and request another byte */ chip.clocks_left = 44; chip.state = STATE.ADDR_LSB; break; /* Address LSB state: latch the LSB of the sample address and issue a request for the fifth byte */ /* The expected response will be just a dummy */ case STATE.ADDR_LSB: chip.offset |= (uint)((chip.rom != null ? chip.rom[chip.romPtr + (chip.req_sample * 2 + 6)] : chip.fifo_in) << 1); #if DEBUG if (DEBUG_STATES != 0) { DEBUG_METHOD(string.Format("UPD7759: offset_lo = {0:02X}, requesting dummy 2\n", (chip.offset >> 1) & 0xff)); } #endif chip.drq = 1; /* 36 cycles later, we will latch this value and request another byte */ chip.clocks_left = 36; chip.state = STATE.DUMMY2; break; /* Second dummy state: ignore any data here and issue a request for the the sixth byte */ /* The expected response will be the first block header */ case STATE.DUMMY2: chip.offset++; chip.first_valid_header = 0; #if DEBUG if (DEBUG_STATES != 0) { DEBUG_METHOD("UPD7759: dummy2, requesting block header\n"); } #endif chip.drq = 1; /* 36?? cycles later, we will latch this value and request another byte */ chip.clocks_left = 36; chip.state = STATE.BLOCK_HEADER; break; /* Block header state: latch the header and issue a request for the first byte afterwards */ case STATE.BLOCK_HEADER: /* if we're in a repeat loop, reset the offset to the repeat point and decrement the count */ if (chip.repeat_count != 0) { chip.repeat_count--; chip.offset = chip.repeat_offset; } chip.block_header = chip.rom != null ? chip.rom[chip.romPtr + (chip.offset++ & 0x1ffff)] : chip.fifo_in; #if DEBUG if (DEBUG_STATES != 0) { DEBUG_METHOD(string.Format("UPD7759: header (@{0:05X}) = {1:02X}, requesting next byte\n", chip.offset, chip.block_header)); } #endif chip.drq = 1; /* our next step depends on the top two bits */ switch (chip.block_header & 0xc0) { case 0x00: /* silence */ chip.clocks_left = 1024 * ((chip.block_header & 0x3f) + 1); chip.state = (chip.block_header == 0 && chip.first_valid_header != 0) ? STATE.IDLE : STATE.BLOCK_HEADER; chip.sample = 0; chip.adpcm_state = 0; break; case 0x40: /* 256 nibbles */ chip.sample_rate = (byte)((chip.block_header & 0x3f) + 1); chip.nibbles_left = 256; chip.clocks_left = 36; /* just a guess */ chip.state = STATE.NIBBLE_MSN; break; case 0x80: /* n nibbles */ chip.sample_rate = (byte)((chip.block_header & 0x3f) + 1); chip.clocks_left = 36; /* just a guess */ chip.state = STATE.NIBBLE_COUNT; break; case 0xc0: /* repeat loop */ chip.repeat_count = (byte)((chip.block_header & 7) + 1); chip.repeat_offset = chip.offset; chip.clocks_left = 36; /* just a guess */ chip.state = STATE.BLOCK_HEADER; break; } /* set a flag when we get the first non-zero header */ if (chip.block_header != 0) { chip.first_valid_header = 1; } break; /* Nibble count state: latch the number of nibbles to play and request another byte */ /* The expected response will be the first data byte */ case STATE.NIBBLE_COUNT: chip.nibbles_left = (UInt16)((chip.rom != null ? chip.rom[chip.romPtr + (chip.offset++ & 0x1ffff)] : chip.fifo_in) + 1); #if DEBUG if (DEBUG_STATES != 0) { DEBUG_METHOD(string.Format("UPD7759: nibble_count = {0}, requesting next byte\n", chip.nibbles_left)); } #endif chip.drq = 1; /* 36?? cycles later, we will latch this value and request another byte */ chip.clocks_left = 36; /* just a guess */ chip.state = STATE.NIBBLE_MSN; break; /* MSN state: latch the data for this pair of samples and request another byte */ /* The expected response will be the next sample data or another header */ case STATE.NIBBLE_MSN: chip.adpcm_data = chip.rom != null ? chip.rom[chip.romPtr + (chip.offset++ & 0x1ffff)] : chip.fifo_in; update_adpcm(chip, chip.adpcm_data >> 4); chip.drq = 1; /* we stay in this state until the time for this sample is complete */ chip.clocks_left = chip.sample_rate * 4; if (--chip.nibbles_left == 0) { chip.state = STATE.BLOCK_HEADER; } else { chip.state = STATE.NIBBLE_LSN; } break; /* LSN state: process the lower nibble */ case STATE.NIBBLE_LSN: update_adpcm(chip, chip.adpcm_data & 15); /* we stay in this state until the time for this sample is complete */ chip.clocks_left = chip.sample_rate * 4; if (--chip.nibbles_left == 0) { chip.state = STATE.BLOCK_HEADER; } else { chip.state = STATE.NIBBLE_MSN; } break; } /* if there's a DRQ, fudge the state */ if (chip.drq != 0) { chip.post_drq_state = chip.state; chip.post_drq_clocks = chip.clocks_left - 21; chip.state = STATE.DROP_DRQ; chip.clocks_left = 21; } }