From 80f73ab3769b26298c3c2351cd2686377128b154 Mon Sep 17 00:00:00 2001 From: Fabio Priuli Date: Thu, 6 Aug 2009 10:58:38 +0000 Subject: [PATCH] More NES work: [Robert Bohms] * Fixes bug in nes_apu that caused errors reading $4015 * Adds length counter status bits to $4015 * Fixes 4-screen mirroring (PPU regression) * Fixed cham24 Also, I fixed the tab lengths in nes_apu.c --- src/emu/sound/nes_apu.c | 852 +++++++++++++++++++------------------- src/emu/sound/nes_defs.h | 107 ++--- src/mame/drivers/cham24.c | 21 +- src/mame/video/ppu2c0x.c | 37 +- 4 files changed, 506 insertions(+), 511 deletions(-) diff --git a/src/emu/sound/nes_apu.c b/src/emu/sound/nes_apu.c index 0f217c50f77..bfe7ea448bf 100644 --- a/src/emu/sound/nes_apu.c +++ b/src/emu/sound/nes_apu.c @@ -88,48 +88,48 @@ INLINE nesapu_state *get_safe_token(const device_config *device) /* INITIALIZE WAVE TIMES RELATIVE TO SAMPLE RATE */ static void create_vbltimes(uint32 * table,const uint8 *vbl,unsigned int rate) { - int i; + int i; - for (i=0;i<0x20;i++) - table[i]=vbl[i]*rate; + for (i = 0; i < 0x20; i++) + table[i] = vbl[i] * rate; } /* INITIALIZE SAMPLE TIMES IN TERMS OF VSYNCS */ static void create_syncs(nesapu_state *info, unsigned long sps) { - int i; - unsigned long val=sps; + int i; + unsigned long val = sps; - for (i=0;isync_times1[i]=val; - val+=sps; - } + for (i = 0; i < SYNCS_MAX1; i++) + { + info->sync_times1[i] = val; + val += sps; + } - val=0; - for (i=0;isync_times2[i]=val; - info->sync_times2[i]>>=2; - val+=sps; - } + val = 0; + for (i = 0; i < SYNCS_MAX2; i++) + { + info->sync_times2[i] = val; + info->sync_times2[i] >>= 2; + val += sps; + } } /* INITIALIZE NOISE LOOKUP TABLE */ static void create_noise(uint8 *buf, const int bits, int size) { - static int m = 0x0011; - int xor_val, i; + static int m = 0x0011; + int xor_val, i; - for (i = 0; i < size; i++) - { - xor_val = m & 1; - m >>= 1; - xor_val ^= (m & 1); - m |= xor_val << (bits - 1); + for (i = 0; i < size; i++) + { + xor_val = m & 1; + m >>= 1; + xor_val ^= (m & 1); + m |= xor_val << (bits - 1); - buf[i] = m; - } + buf[i] = m; + } } /* TODO: sound channels should *ALL* have DC volume decay */ @@ -137,526 +137,539 @@ static void create_noise(uint8 *buf, const int bits, int size) /* OUTPUT SQUARE WAVE SAMPLE (VALUES FROM -16 to +15) */ static int8 apu_square(nesapu_state *info, square_t *chan) { - int env_delay; - int sweep_delay; - int8 output; + int env_delay; + int sweep_delay; + int8 output; - /* reg0: 0-3=volume, 4=envelope, 5=hold, 6-7=duty cycle - ** reg1: 0-2=sweep shifts, 3=sweep inc/dec, 4-6=sweep length, 7=sweep on - ** reg2: 8 bits of freq - ** reg3: 0-2=high freq, 7-4=vbl length counter - */ + /* reg0: 0-3=volume, 4=envelope, 5=hold, 6-7=duty cycle + ** reg1: 0-2=sweep shifts, 3=sweep inc/dec, 4-6=sweep length, 7=sweep on + ** reg2: 8 bits of freq + ** reg3: 0-2=high freq, 7-4=vbl length counter + */ - if (FALSE == chan->enabled) - return 0; + if (FALSE == chan->enabled) + return 0; - /* enveloping */ - env_delay = info->sync_times1[chan->regs[0] & 0x0F]; + /* enveloping */ + env_delay = info->sync_times1[chan->regs[0] & 0x0F]; - /* decay is at a rate of (env_regs + 1) / 240 secs */ - chan->env_phase -= 4; - while (chan->env_phase < 0) - { - chan->env_phase += env_delay; - if (chan->regs[0] & 0x20) - chan->env_vol = (chan->env_vol + 1) & 15; - else if (chan->env_vol < 15) - chan->env_vol++; - } + /* decay is at a rate of (env_regs + 1) / 240 secs */ + chan->env_phase -= 4; + while (chan->env_phase < 0) + { + chan->env_phase += env_delay; + if (chan->regs[0] & 0x20) + chan->env_vol = (chan->env_vol + 1) & 15; + else if (chan->env_vol < 15) + chan->env_vol++; + } - /* vbl length counter */ - if (chan->vbl_length > 0 && 0 == (chan->regs [0] & 0x20)) - chan->vbl_length--; + /* vbl length counter */ + if (chan->vbl_length > 0 && 0 == (chan->regs [0] & 0x20)) + chan->vbl_length--; - if (0 == chan->vbl_length) - return 0; + if (0 == chan->vbl_length) + return 0; - /* freqsweeps */ - if ((chan->regs[1] & 0x80) && (chan->regs[1] & 7)) - { - sweep_delay = info->sync_times1[(chan->regs[1] >> 4) & 7]; - chan->sweep_phase -= 2; - while (chan->sweep_phase < 0) - { - chan->sweep_phase += sweep_delay; - if (chan->regs[1] & 8) - chan->freq -= chan->freq >> (chan->regs[1] & 7); - else - chan->freq += chan->freq >> (chan->regs[1] & 7); - } - } + /* freqsweeps */ + if ((chan->regs[1] & 0x80) && (chan->regs[1] & 7)) + { + sweep_delay = info->sync_times1[(chan->regs[1] >> 4) & 7]; + chan->sweep_phase -= 2; + while (chan->sweep_phase < 0) + { + chan->sweep_phase += sweep_delay; + if (chan->regs[1] & 8) + chan->freq -= chan->freq >> (chan->regs[1] & 7); + else + chan->freq += chan->freq >> (chan->regs[1] & 7); + } + } - if ((0 == (chan->regs[1] & 8) && (chan->freq >> 16) > freq_limit[chan->regs[1] & 7]) - || (chan->freq >> 16) < 4) - return 0; + if ((0 == (chan->regs[1] & 8) && (chan->freq >> 16) > freq_limit[chan->regs[1] & 7]) + || (chan->freq >> 16) < 4) + return 0; - chan->phaseacc -= (float) info->apu_incsize; /* # of cycles per sample */ + chan->phaseacc -= (float) info->apu_incsize; /* # of cycles per sample */ - while (chan->phaseacc < 0) - { - chan->phaseacc += (chan->freq >> 16); - chan->adder = (chan->adder + 1) & 0x0F; - } + while (chan->phaseacc < 0) + { + chan->phaseacc += (chan->freq >> 16); + chan->adder = (chan->adder + 1) & 0x0F; + } - if (chan->regs[0] & 0x10) /* fixed volume */ - output = chan->regs[0] & 0x0F; - else - output = 0x0F - chan->env_vol; + if (chan->regs[0] & 0x10) /* fixed volume */ + output = chan->regs[0] & 0x0F; + else + output = 0x0F - chan->env_vol; - if (chan->adder < (duty_lut[chan->regs[0] >> 6])) - output = -output; + if (chan->adder < (duty_lut[chan->regs[0] >> 6])) + output = -output; - return (int8) output; + return (int8) output; } /* OUTPUT TRIANGLE WAVE SAMPLE (VALUES FROM -16 to +15) */ static int8 apu_triangle(nesapu_state *info, triangle_t *chan) { - int freq; - int8 output; - /* reg0: 7=holdnote, 6-0=linear length counter - ** reg2: low 8 bits of frequency - ** reg3: 7-3=length counter, 2-0=high 3 bits of frequency - */ + int freq; + int8 output; + /* reg0: 7=holdnote, 6-0=linear length counter + ** reg2: low 8 bits of frequency + ** reg3: 7-3=length counter, 2-0=high 3 bits of frequency + */ - if (FALSE == chan->enabled) - return 0; + if (FALSE == chan->enabled) + return 0; - if (FALSE == chan->counter_started && 0 == (chan->regs[0] & 0x80)) - { - if (chan->write_latency) - chan->write_latency--; - if (0 == chan->write_latency) - chan->counter_started = TRUE; - } + if (FALSE == chan->counter_started && 0 == (chan->regs[0] & 0x80)) + { + if (chan->write_latency) + chan->write_latency--; + if (0 == chan->write_latency) + chan->counter_started = TRUE; + } - if (chan->counter_started) - { - if (chan->linear_length > 0) - chan->linear_length--; - if (chan->vbl_length && 0 == (chan->regs[0] & 0x80)) - chan->vbl_length--; + if (chan->counter_started) + { + if (chan->linear_length > 0) + chan->linear_length--; + if (chan->vbl_length && 0 == (chan->regs[0] & 0x80)) + chan->vbl_length--; - if (0 == chan->vbl_length) - return 0; - } + if (0 == chan->vbl_length) + return 0; + } - if (0 == chan->linear_length) - return 0; + if (0 == chan->linear_length) + return 0; - freq = (((chan->regs[3] & 7) << 8) + chan->regs[2]) + 1; + freq = (((chan->regs[3] & 7) << 8) + chan->regs[2]) + 1; - if (freq < 4) /* inaudible */ - return 0; + if (freq < 4) /* inaudible */ + return 0; - chan->phaseacc -= (float) info->apu_incsize; /* # of cycles per sample */ - while (chan->phaseacc < 0) - { - chan->phaseacc += freq; - chan->adder = (chan->adder + 1) & 0x1F; + chan->phaseacc -= (float) info->apu_incsize; /* # of cycles per sample */ + while (chan->phaseacc < 0) + { + chan->phaseacc += freq; + chan->adder = (chan->adder + 1) & 0x1F; - output = (chan->adder & 7) << 1; - if (chan->adder & 8) - output = 0x10 - output; - if (chan->adder & 0x10) - output = -output; + output = (chan->adder & 7) << 1; + if (chan->adder & 8) + output = 0x10 - output; + if (chan->adder & 0x10) + output = -output; - chan->output_vol = output; - } + chan->output_vol = output; + } - return (int8) chan->output_vol; + return (int8) chan->output_vol; } /* OUTPUT NOISE WAVE SAMPLE (VALUES FROM -16 to +15) */ static int8 apu_noise(nesapu_state *info, noise_t *chan) { - int freq, env_delay; - uint8 outvol; - uint8 output; + int freq, env_delay; + uint8 outvol; + uint8 output; - /* reg0: 0-3=volume, 4=envelope, 5=hold - ** reg2: 7=small(93 byte) sample,3-0=freq lookup - ** reg3: 7-4=vbl length counter - */ + /* reg0: 0-3=volume, 4=envelope, 5=hold + ** reg2: 7=small(93 byte) sample,3-0=freq lookup + ** reg3: 7-4=vbl length counter + */ - if (FALSE == chan->enabled) - return 0; + if (FALSE == chan->enabled) + return 0; - /* enveloping */ - env_delay = info->sync_times1[chan->regs[0] & 0x0F]; + /* enveloping */ + env_delay = info->sync_times1[chan->regs[0] & 0x0F]; - /* decay is at a rate of (env_regs + 1) / 240 secs */ - chan->env_phase -= 4; - while (chan->env_phase < 0) - { - chan->env_phase += env_delay; - if (chan->regs[0] & 0x20) - chan->env_vol = (chan->env_vol + 1) & 15; - else if (chan->env_vol < 15) - chan->env_vol++; - } + /* decay is at a rate of (env_regs + 1) / 240 secs */ + chan->env_phase -= 4; + while (chan->env_phase < 0) + { + chan->env_phase += env_delay; + if (chan->regs[0] & 0x20) + chan->env_vol = (chan->env_vol + 1) & 15; + else if (chan->env_vol < 15) + chan->env_vol++; + } - /* length counter */ - if (0 == (chan->regs[0] & 0x20)) - { - if (chan->vbl_length > 0) - chan->vbl_length--; - } + /* length counter */ + if (0 == (chan->regs[0] & 0x20)) + { + if (chan->vbl_length > 0) + chan->vbl_length--; + } - if (0 == chan->vbl_length) - return 0; + if (0 == chan->vbl_length) + return 0; - freq = noise_freq[chan->regs[2] & 0x0F]; - chan->phaseacc -= (float) info->apu_incsize; /* # of cycles per sample */ - while (chan->phaseacc < 0) - { - chan->phaseacc += freq; + freq = noise_freq[chan->regs[2] & 0x0F]; + chan->phaseacc -= (float) info->apu_incsize; /* # of cycles per sample */ + while (chan->phaseacc < 0) + { + chan->phaseacc += freq; - chan->cur_pos++; - if (NOISE_SHORT == chan->cur_pos && (chan->regs[2] & 0x80)) - chan->cur_pos = 0; - else if (NOISE_LONG == chan->cur_pos) - chan->cur_pos = 0; - } + chan->cur_pos++; + if (NOISE_SHORT == chan->cur_pos && (chan->regs[2] & 0x80)) + chan->cur_pos = 0; + else if (NOISE_LONG == chan->cur_pos) + chan->cur_pos = 0; + } - if (chan->regs[0] & 0x10) /* fixed volume */ - outvol = chan->regs[0] & 0x0F; - else - outvol = 0x0F - chan->env_vol; + if (chan->regs[0] & 0x10) /* fixed volume */ + outvol = chan->regs[0] & 0x0F; + else + outvol = 0x0F - chan->env_vol; - output = info->noise_lut[chan->cur_pos]; - if (output > outvol) - output = outvol; + output = info->noise_lut[chan->cur_pos]; + if (output > outvol) + output = outvol; - if (info->noise_lut[chan->cur_pos] & 0x80) /* make it negative */ - output = -output; + if (info->noise_lut[chan->cur_pos] & 0x80) /* make it negative */ + output = -output; - return (int8) output; + return (int8) output; } /* RESET DPCM PARAMETERS */ INLINE void apu_dpcmreset(dpcm_t *chan) { - chan->address = 0xC000 + (uint16) (chan->regs[2] << 6); - chan->length = (uint16) (chan->regs[3] << 4) + 1; - chan->bits_left = chan->length << 3; - chan->irq_occurred = FALSE; - chan->enabled = TRUE; /* Fixed * Proper DPCM channel ENABLE/DISABLE flag behaviour*/ - chan->vol = 0; /* Fixed * DPCM DAC resets itself when restarted */ + chan->address = 0xC000 + (uint16) (chan->regs[2] << 6); + chan->length = (uint16) (chan->regs[3] << 4) + 1; + chan->bits_left = chan->length << 3; + chan->irq_occurred = FALSE; + chan->enabled = TRUE; /* Fixed * Proper DPCM channel ENABLE/DISABLE flag behaviour*/ + chan->vol = 0; /* Fixed * DPCM DAC resets itself when restarted */ } /* OUTPUT DPCM WAVE SAMPLE (VALUES FROM -64 to +63) */ /* TODO: centerline naughtiness */ static int8 apu_dpcm(nesapu_state *info, dpcm_t *chan) { - int freq, bit_pos; + int freq, bit_pos; - /* reg0: 7=irq gen, 6=looping, 3-0=pointer to clock table - ** reg1: output dc level, 7 bits unsigned - ** reg2: 8 bits of 64-byte aligned address offset : $C000 + (value * 64) - ** reg3: length, (value * 16) + 1 - */ + /* reg0: 7=irq gen, 6=looping, 3-0=pointer to clock table + ** reg1: output dc level, 7 bits unsigned + ** reg2: 8 bits of 64-byte aligned address offset : $C000 + (value * 64) + ** reg3: length, (value * 16) + 1 + */ - if (chan->enabled) - { - freq = dpcm_clocks[chan->regs[0] & 0x0F]; - chan->phaseacc -= (float) info->apu_incsize; /* # of cycles per sample */ + if (chan->enabled) + { + freq = dpcm_clocks[chan->regs[0] & 0x0F]; + chan->phaseacc -= (float) info->apu_incsize; /* # of cycles per sample */ - while (chan->phaseacc < 0) - { - chan->phaseacc += freq; + while (chan->phaseacc < 0) + { + chan->phaseacc += freq; - if (0 == chan->length) - { - chan->enabled = FALSE; /* Fixed * Proper DPCM channel ENABLE/DISABLE flag behaviour*/ - chan->vol=0; /* Fixed * DPCM DAC resets itself when restarted */ - if (chan->regs[0] & 0x40) - apu_dpcmreset(chan); - else - { - if (chan->regs[0] & 0x80) /* IRQ Generator */ - { - chan->irq_occurred = TRUE; - n2a03_irq(info->APU.dpcm.memory->cpu); - } - break; - } - } + if (0 == chan->length) + { + chan->enabled = FALSE; /* Fixed * Proper DPCM channel ENABLE/DISABLE flag behaviour*/ + chan->vol=0; /* Fixed * DPCM DAC resets itself when restarted */ + if (chan->regs[0] & 0x40) + apu_dpcmreset(chan); + else + { + if (chan->regs[0] & 0x80) /* IRQ Generator */ + { + chan->irq_occurred = TRUE; + n2a03_irq(info->APU.dpcm.memory->cpu); + } + break; + } + } - chan->bits_left--; - bit_pos = 7 - (chan->bits_left & 7); - if (7 == bit_pos) - { - chan->cur_byte = memory_read_byte(info->APU.dpcm.memory, chan->address); - chan->address++; - chan->length--; - } + chan->bits_left--; + bit_pos = 7 - (chan->bits_left & 7); + if (7 == bit_pos) + { + chan->cur_byte = memory_read_byte(info->APU.dpcm.memory, chan->address); + chan->address++; + chan->length--; + } - if (chan->cur_byte & (1 << bit_pos)) -// chan->regs[1]++; - chan->vol+=2; /* FIXED * DPCM channel only uses the upper 6 bits of the DAC */ - else -// chan->regs[1]--; - chan->vol-=2; - } - } + if (chan->cur_byte & (1 << bit_pos)) +// chan->regs[1]++; + chan->vol+=2; /* FIXED * DPCM channel only uses the upper 6 bits of the DAC */ + else +// chan->regs[1]--; + chan->vol-=2; + } + } - if (chan->vol > 63) - chan->vol = 63; - else if (chan->vol < -64) - chan->vol = -64; + if (chan->vol > 63) + chan->vol = 63; + else if (chan->vol < -64) + chan->vol = -64; - return (int8) (chan->vol); + return (int8) (chan->vol); } /* WRITE REGISTER VALUE */ INLINE void apu_regwrite(nesapu_state *info,int address, uint8 value) { - int chan = (address & 4) ? 1 : 0; + int chan = (address & 4) ? 1 : 0; - switch (address) - { - /* squares */ - case APU_WRA0: - case APU_WRB0: - info->APU.squ[chan].regs[0] = value; - break; + switch (address) + { + /* squares */ + case APU_WRA0: + case APU_WRB0: + info->APU.squ[chan].regs[0] = value; + break; - case APU_WRA1: - case APU_WRB1: - info->APU.squ[chan].regs[1] = value; - break; + case APU_WRA1: + case APU_WRB1: + info->APU.squ[chan].regs[1] = value; + break; - case APU_WRA2: - case APU_WRB2: - info->APU.squ[chan].regs[2] = value; - if (info->APU.squ[chan].enabled) - info->APU.squ[chan].freq = ((((info->APU.squ[chan].regs[3] & 7) << 8) + value) + 1) << 16; - break; + case APU_WRA2: + case APU_WRB2: + info->APU.squ[chan].regs[2] = value; + if (info->APU.squ[chan].enabled) + info->APU.squ[chan].freq = ((((info->APU.squ[chan].regs[3] & 7) << 8) + value) + 1) << 16; + break; - case APU_WRA3: - case APU_WRB3: - info->APU.squ[chan].regs[3] = value; + case APU_WRA3: + case APU_WRB3: + info->APU.squ[chan].regs[3] = value; - if (info->APU.squ[chan].enabled) - { - info->APU.squ[chan].vbl_length = info->vbl_times[value >> 3]; - info->APU.squ[chan].env_vol = 0; - info->APU.squ[chan].freq = ((((value & 7) << 8) + info->APU.squ[chan].regs[2]) + 1) << 16; - } + if (info->APU.squ[chan].enabled) + { + info->APU.squ[chan].vbl_length = info->vbl_times[value >> 3]; + info->APU.squ[chan].env_vol = 0; + info->APU.squ[chan].freq = ((((value & 7) << 8) + info->APU.squ[chan].regs[2]) + 1) << 16; + } - break; + break; - /* triangle */ - case APU_WRC0: - info->APU.tri.regs[0] = value; + /* triangle */ + case APU_WRC0: + info->APU.tri.regs[0] = value; - if (info->APU.tri.enabled) - { /* ??? */ - if (FALSE == info->APU.tri.counter_started) - info->APU.tri.linear_length = info->sync_times2[value & 0x7F]; - } + if (info->APU.tri.enabled) + { /* ??? */ + if (FALSE == info->APU.tri.counter_started) + info->APU.tri.linear_length = info->sync_times2[value & 0x7F]; + } - break; + break; - case 0x4009: - /* unused */ - info->APU.tri.regs[1] = value; - break; + case 0x4009: + /* unused */ + info->APU.tri.regs[1] = value; + break; - case APU_WRC2: - info->APU.tri.regs[2] = value; - break; + case APU_WRC2: + info->APU.tri.regs[2] = value; + break; - case APU_WRC3: - info->APU.tri.regs[3] = value; + case APU_WRC3: + info->APU.tri.regs[3] = value; - /* this is somewhat of a hack. there is some latency on the Real - ** Thing between when trireg0 is written to and when the linear - ** length counter actually begins its countdown. we want to prevent - ** the case where the program writes to the freq regs first, then - ** to reg 0, and the counter accidentally starts running because of - ** the sound queue's timestamp processing. - ** - ** set to a few NES sample -- should be sufficient - ** - ** 3 * (1789772.727 / 44100) = ~122 cycles, just around one scanline - ** - ** should be plenty of time for the 6502 code to do a couple of table - ** dereferences and load up the other triregs - */ + /* this is somewhat of a hack. there is some latency on the Real + ** Thing between when trireg0 is written to and when the linear + ** length counter actually begins its countdown. we want to prevent + ** the case where the program writes to the freq regs first, then + ** to reg 0, and the counter accidentally starts running because of + ** the sound queue's timestamp processing. + ** + ** set to a few NES sample -- should be sufficient + ** + ** 3 * (1789772.727 / 44100) = ~122 cycles, just around one scanline + ** + ** should be plenty of time for the 6502 code to do a couple of table + ** dereferences and load up the other triregs + */ /* used to be 3, but now we run the clock faster, so base it on samples/sync */ - info->APU.tri.write_latency = (info->samps_per_sync + 239) / 240; + info->APU.tri.write_latency = (info->samps_per_sync + 239) / 240; - if (info->APU.tri.enabled) - { - info->APU.tri.counter_started = FALSE; - info->APU.tri.vbl_length = info->vbl_times[value >> 3]; - info->APU.tri.linear_length = info->sync_times2[info->APU.tri.regs[0] & 0x7F]; - } + if (info->APU.tri.enabled) + { + info->APU.tri.counter_started = FALSE; + info->APU.tri.vbl_length = info->vbl_times[value >> 3]; + info->APU.tri.linear_length = info->sync_times2[info->APU.tri.regs[0] & 0x7F]; + } - break; + break; - /* noise */ - case APU_WRD0: - info->APU.noi.regs[0] = value; - break; + /* noise */ + case APU_WRD0: + info->APU.noi.regs[0] = value; + break; - case 0x400D: - /* unused */ - info->APU.noi.regs[1] = value; - break; + case 0x400D: + /* unused */ + info->APU.noi.regs[1] = value; + break; - case APU_WRD2: - info->APU.noi.regs[2] = value; - break; + case APU_WRD2: + info->APU.noi.regs[2] = value; + break; - case APU_WRD3: - info->APU.noi.regs[3] = value; + case APU_WRD3: + info->APU.noi.regs[3] = value; - if (info->APU.noi.enabled) - { - info->APU.noi.vbl_length = info->vbl_times[value >> 3]; - info->APU.noi.env_vol = 0; /* reset envelope */ - } - break; + if (info->APU.noi.enabled) + { + info->APU.noi.vbl_length = info->vbl_times[value >> 3]; + info->APU.noi.env_vol = 0; /* reset envelope */ + } + break; - /* DMC */ - case APU_WRE0: - info->APU.dpcm.regs[0] = value; - if (0 == (value & 0x80)) - info->APU.dpcm.irq_occurred = FALSE; - break; + /* DMC */ + case APU_WRE0: + info->APU.dpcm.regs[0] = value; + if (0 == (value & 0x80)) + info->APU.dpcm.irq_occurred = FALSE; + break; - case APU_WRE1: /* 7-bit DAC */ - //info->APU.dpcm.regs[1] = value - 0x40; - info->APU.dpcm.regs[1] = value & 0x7F; - info->APU.dpcm.vol = (info->APU.dpcm.regs[1]-64); - break; + case APU_WRE1: /* 7-bit DAC */ + //info->APU.dpcm.regs[1] = value - 0x40; + info->APU.dpcm.regs[1] = value & 0x7F; + info->APU.dpcm.vol = (info->APU.dpcm.regs[1]-64); + break; - case APU_WRE2: - info->APU.dpcm.regs[2] = value; - //apu_dpcmreset(info->APU.dpcm); - break; + case APU_WRE2: + info->APU.dpcm.regs[2] = value; + //apu_dpcmreset(info->APU.dpcm); + break; - case APU_WRE3: - info->APU.dpcm.regs[3] = value; - break; + case APU_WRE3: + info->APU.dpcm.regs[3] = value; + break; - case APU_IRQCTRL: - break; + case APU_IRQCTRL: + if(value & 0x80) + info->APU.step_mode = 5; + else + info->APU.step_mode = 4; + break; - case APU_SMASK: - if (value & 0x01) - info->APU.squ[0].enabled = TRUE; - else - { - info->APU.squ[0].enabled = FALSE; - info->APU.squ[0].vbl_length = 0; - } + case APU_SMASK: + if (value & 0x01) + info->APU.squ[0].enabled = TRUE; + else + { + info->APU.squ[0].enabled = FALSE; + info->APU.squ[0].vbl_length = 0; + } - if (value & 0x02) - info->APU.squ[1].enabled = TRUE; - else - { - info->APU.squ[1].enabled = FALSE; - info->APU.squ[1].vbl_length = 0; - } + if (value & 0x02) + info->APU.squ[1].enabled = TRUE; + else + { + info->APU.squ[1].enabled = FALSE; + info->APU.squ[1].vbl_length = 0; + } - if (value & 0x04) - info->APU.tri.enabled = TRUE; - else - { - info->APU.tri.enabled = FALSE; - info->APU.tri.vbl_length = 0; - info->APU.tri.linear_length = 0; - info->APU.tri.counter_started = FALSE; - info->APU.tri.write_latency = 0; - } + if (value & 0x04) + info->APU.tri.enabled = TRUE; + else + { + info->APU.tri.enabled = FALSE; + info->APU.tri.vbl_length = 0; + info->APU.tri.linear_length = 0; + info->APU.tri.counter_started = FALSE; + info->APU.tri.write_latency = 0; + } - if (value & 0x08) - info->APU.noi.enabled = TRUE; - else - { - info->APU.noi.enabled = FALSE; - info->APU.noi.vbl_length = 0; - } + if (value & 0x08) + info->APU.noi.enabled = TRUE; + else + { + info->APU.noi.enabled = FALSE; + info->APU.noi.vbl_length = 0; + } - if (value & 0x10) - { - /* only reset dpcm values if DMA is finished */ - if (FALSE == info->APU.dpcm.enabled) - { - info->APU.dpcm.enabled = TRUE; - apu_dpcmreset(&info->APU.dpcm); - } - } - else - info->APU.dpcm.enabled = FALSE; + if (value & 0x10) + { + /* only reset dpcm values if DMA is finished */ + if (FALSE == info->APU.dpcm.enabled) + { + info->APU.dpcm.enabled = TRUE; + apu_dpcmreset(&info->APU.dpcm); + } + } + else + info->APU.dpcm.enabled = FALSE; - info->APU.dpcm.irq_occurred = FALSE; + info->APU.dpcm.irq_occurred = FALSE; - break; - default: + break; + default: #ifdef MAME_DEBUG logerror("invalid apu write: $%02X at $%04X\n", value, address); #endif - break; - } + break; + } } /* UPDATE SOUND BUFFER USING CURRENT DATA */ INLINE void apu_update(nesapu_state *info, stream_sample_t *buffer16, int samples) { - int accum; + int accum; - while (samples--) - { - accum = apu_square(info, &info->APU.squ[0]); - accum += apu_square(info, &info->APU.squ[1]); - accum += apu_triangle(info, &info->APU.tri); - accum += apu_noise(info, &info->APU.noi); - accum += apu_dpcm(info, &info->APU.dpcm); + while (samples--) + { + accum = apu_square(info, &info->APU.squ[0]); + accum += apu_square(info, &info->APU.squ[1]); + accum += apu_triangle(info, &info->APU.tri); + accum += apu_noise(info, &info->APU.noi); + accum += apu_dpcm(info, &info->APU.dpcm); - /* 8-bit clamps */ - if (accum > 127) - accum = 127; - else if (accum < -128) - accum = -128; + /* 8-bit clamps */ + if (accum > 127) + accum = 127; + else if (accum < -128) + accum = -128; - *(buffer16++)=accum<<8; - } + *(buffer16++)=accum<<8; + } } /* READ VALUES FROM REGISTERS */ INLINE uint8 apu_read(nesapu_state *info,int address) { - if (address == 0x0f) /*FIXED* Address $4015 has different behaviour*/ + if (address == 0x15) /*FIXED* Address $4015 has different behaviour*/ { - int readval = 0; - if ( info->APU.dpcm.enabled == TRUE ) - { - readval |= 0x10; - } + int readval = 0; + if (info->APU.squ[0].vbl_length > 0) + readval |= 0x01; - if ( info->APU.dpcm.irq_occurred == TRUE ) - { - readval |= 0x80; - } - return readval; - } - else - return info->APU.regs[address]; + if (info->APU.squ[1].vbl_length > 0) + readval |= 0x02; + + if (info->APU.tri.vbl_length > 0) + readval |= 0x04; + + if (info->APU.noi.vbl_length > 0) + readval |= 0x08; + + if (info->APU.dpcm.enabled == TRUE) + readval |= 0x10; + + if (info->APU.dpcm.irq_occurred == TRUE) + readval |= 0x80; + + return readval; + } + else + return info->APU.regs[address]; } /* WRITE VALUE TO TEMP REGISTRY AND QUEUE EVENT */ INLINE void apu_write(nesapu_state *info,int address, uint8 value) { - info->APU.regs[address]=value; - stream_update(info->stream); - apu_regwrite(info,address,value); + info->APU.regs[address]=value; + stream_update(info->stream); + apu_regwrite(info,address,value); } /* EXTERNAL INTERFACE FUNCTIONS */ @@ -753,6 +766,7 @@ static DEVICE_START( nesapu ) state_save_register_device_item(device, 0, info->APU.tail); #else state_save_register_device_item(device, 0, info->APU.buf_pos); + state_save_register_device_item(device, 0, info->APU.step_mode); #endif } diff --git a/src/emu/sound/nes_defs.h b/src/emu/sound/nes_defs.h index af708394558..0cbd8431404 100644 --- a/src/emu/sound/nes_defs.h +++ b/src/emu/sound/nes_defs.h @@ -50,8 +50,8 @@ typedef UINT8 boolean; typedef struct queue_s { - int pos; - unsigned char reg,val; + int pos; + unsigned char reg,val; } queue_t; #endif @@ -86,88 +86,89 @@ typedef struct queue_s /* Square Wave */ typedef struct square_s { - uint8 regs[4]; - int vbl_length; - int freq; - float phaseacc; - float output_vol; - float env_phase; - float sweep_phase; - uint8 adder; - uint8 env_vol; - boolean enabled; + uint8 regs[4]; + int vbl_length; + int freq; + float phaseacc; + float output_vol; + float env_phase; + float sweep_phase; + uint8 adder; + uint8 env_vol; + boolean enabled; } square_t; /* Triangle Wave */ typedef struct triangle_s { - uint8 regs[4]; /* regs[1] unused */ - int linear_length; - int vbl_length; - int write_latency; - float phaseacc; - float output_vol; - uint8 adder; - boolean counter_started; - boolean enabled; + uint8 regs[4]; /* regs[1] unused */ + int linear_length; + int vbl_length; + int write_latency; + float phaseacc; + float output_vol; + uint8 adder; + boolean counter_started; + boolean enabled; } triangle_t; /* Noise Wave */ typedef struct noise_s { - uint8 regs[4]; /* regs[1] unused */ - int cur_pos; - int vbl_length; - float phaseacc; - float output_vol; - float env_phase; - uint8 env_vol; - boolean enabled; + uint8 regs[4]; /* regs[1] unused */ + int cur_pos; + int vbl_length; + float phaseacc; + float output_vol; + float env_phase; + uint8 env_vol; + boolean enabled; } noise_t; /* DPCM Wave */ typedef struct dpcm_s { - uint8 regs[4]; - uint32 address; - uint32 length; - int bits_left; - float phaseacc; - float output_vol; - uint8 cur_byte; - boolean enabled; - boolean irq_occurred; - const address_space *memory; - signed char vol; + uint8 regs[4]; + uint32 address; + uint32 length; + int bits_left; + float phaseacc; + float output_vol; + uint8 cur_byte; + boolean enabled; + boolean irq_occurred; + const address_space *memory; + signed char vol; } dpcm_t; /* APU type */ typedef struct apu { - /* Sound channels */ - square_t squ[2]; - triangle_t tri; - noise_t noi; - dpcm_t dpcm; + /* Sound channels */ + square_t squ[2]; + triangle_t tri; + noise_t noi; + dpcm_t dpcm; - /* APU registers */ - unsigned char regs[0x17]; + /* APU registers */ + unsigned char regs[0x17]; - /* Sound pointers */ - void *buffer; + /* Sound pointers */ + void *buffer; #ifdef USE_QUEUE - /* Event queue */ - queue_t queue[QUEUE_SIZE]; - int head,tail; + /* Event queue */ + queue_t queue[QUEUE_SIZE]; + int head, tail; #else - int buf_pos; + int buf_pos; #endif + int step_mode; } apu_t; /* CONSTANTS */ diff --git a/src/mame/drivers/cham24.c b/src/mame/drivers/cham24.c index 5a2766164d6..d0709f414af 100644 --- a/src/mame/drivers/cham24.c +++ b/src/mame/drivers/cham24.c @@ -244,12 +244,6 @@ static const nes_interface cham24_interface_1 = static MACHINE_RESET( cham24 ) { - /* switch PRG rom */ - UINT8* dst = memory_region(machine, "maincpu"); - UINT8* src = memory_region(machine, "user1"); - - memcpy(&dst[0x8000], &src[0x0f8000], 0x4000); - memcpy(&dst[0xc000], &src[0x0f8000], 0x4000); } static PALETTE_INIT( cham24 ) @@ -282,8 +276,16 @@ static VIDEO_UPDATE( cham24 ) return 0; } -static DRIVER_INIT( cham24 ) + +static MACHINE_START( cham24 ) { + /* switch PRG rom */ + UINT8* dst = memory_region(machine, "maincpu"); + UINT8* src = memory_region(machine, "user1"); + + memcpy(&dst[0x8000], &src[0x0f8000], 0x4000); + memcpy(&dst[0xc000], &src[0x0f8000], 0x4000); + /* uses 8K swapping, all ROM!*/ memory_install_readwrite8_handler(cpu_get_address_space(cputag_get_cpu(machine, "ppu"), ADDRESS_SPACE_PROGRAM), 0x0000, 0x1fff, 0, 0, SMH_BANK(1), 0); memory_set_bankptr(machine, 1, memory_region(machine, "gfx1")); @@ -299,6 +301,10 @@ static DRIVER_INIT( cham24 ) memory_install_readwrite8_handler(cpu_get_address_space(cputag_get_cpu(machine, "ppu"), ADDRESS_SPACE_PROGRAM), 0x2000, 0x3eff, 0, 0, nt_r, nt_w); } +static DRIVER_INIT( cham24 ) +{ +} + static GFXDECODE_START( cham24 ) /* none, the ppu generates one */ GFXDECODE_END @@ -309,6 +315,7 @@ static MACHINE_DRIVER_START( cham24 ) MDRV_CPU_PROGRAM_MAP(cham24_map) MDRV_MACHINE_RESET( cham24 ) + MDRV_MACHINE_START( cham24 ) /* video hardware */ MDRV_SCREEN_ADD("screen", RASTER) diff --git a/src/mame/video/ppu2c0x.c b/src/mame/video/ppu2c0x.c index 6c993ad5b88..36a6aedc56b 100644 --- a/src/mame/video/ppu2c0x.c +++ b/src/mame/video/ppu2c0x.c @@ -19,6 +19,7 @@ * Micro Machines has minor rendering glitches (needs better timing). * Mach Rider has minor road rendering glitches (needs better timing). + * Rad Racer demonstrates road glitches: it changes horizontal scrolling mid-line. ******************************************************************************/ @@ -380,7 +381,6 @@ static void draw_background( const device_config *device, UINT8 *line_priority ) const pen_t *color_table; const pen_t *paldata; - // const UINT8 *sd; int tilecount = 0; @@ -447,19 +447,16 @@ static void draw_background( const device_config *device, UINT8 *line_priority ) if (start_x < VISIBLE_SCREEN_WIDTH) { - UINT8 plane1, plane2; // use extended size so I can shift! + UINT8 plane1, plane2; paldata = &color_table[4 * (((color_byte >> color_bits) & 0x03))]; - // start = scroll_y_fine * line_modulo; // need to read 0x0000 or 0x1000 + 16*nametable data address = ((this_ppu->tile_page) ? 0x1000 : 0) + (page2 * 16); // plus something that accounts for y - // address -= (scanline % 8); address += scroll_y_fine; plane1 = memory_read_byte(device->space[0], (address & 0x1fff)); plane2 = memory_read_byte(device->space[0], (address + 8) & 0x1fff); - // plane2 = plane2 << 1; /* render the pixel */ for (i = 0; i < 8; i++) @@ -618,30 +615,23 @@ static void draw_sprites( const device_config *device, UINT8 *line_priority ) plane1 = memory_read_byte(device->space[0], (index1 + sprite_line) & 0x1fff); plane2 = memory_read_byte(device->space[0], (index1 + sprite_line + 8) & 0x1fff); -// sd = gfx_element_get_data(device->machine->gfx[gfx_bank], index1 % total_elements) + start; -// if (size > 8) -// gfx_element_get_data(device->machine->gfx[gfx_bank], (index1 + 1) % total_elements); - if (pri) { /* draw the low-priority sprites */ for (pixel = 0; pixel < 8; pixel++) { -// UINT8 pixelData = flipx ? sd[7-pixel] : sd[pixel]; UINT8 pixelData; if (flipx) { pixelData = (plane1 & 1) + ((plane2 & 1) << 1); plane1 = plane1 >> 1; plane2 = plane2 >> 1; - // sd[7 - pixel] } else { pixelData = ((plane1 >> 7) & 1) | (((plane2 >> 7) & 1) << 1); plane1 = plane1 << 1; plane2 = plane2 << 1; - // sd[pixel]; } /* is this pixel non-transparent? */ @@ -1037,11 +1027,11 @@ READ8_HANDLER( ppu2c0x_palette_read ) { ppu2c0x_chip *this_ppu = get_token(space->cpu); { - // it's a palette - // ERROR: doesn't currently handle monochrome! if (this_ppu->regs[PPU_CONTROL1] & PPU_CONTROL1_DISPLAY_MONO) return (this_ppu->palette_ram[offset & 0x1f] & 0x30); - else return (this_ppu->palette_ram[offset & 0x1f] & 0x3f); + + else + return (this_ppu->palette_ram[offset & 0x1f] & 0x3f); } } @@ -1242,9 +1232,6 @@ WRITE8_DEVICE_HANDLER( ppu2c0x_w ) { /* store the data */ memory_write_byte(device->space[0], tempAddr, data); - - /* mark the char dirty */ - // gfx_element_mark_dirty(device->machine->gfx[intf->gfx_layout_number], tempAddr >> 4); } else @@ -1273,28 +1260,14 @@ void ppu2c0x_spriteram_dma( const address_space *space, const device_config *dev int i; int address = page << 8; -// logerror("sprite DMA: %d (scanline: %d)\n", page, this_ppu->scanline); for (i = 0; i < SPRITERAM_SIZE; i++) { UINT8 spriteData = memory_read_byte(space, address + i); memory_write_byte(space, 0x2004, spriteData); -// ppu2c0x_w(device, PPU_SPRITE_DATA, spriteData); } // should last 513 CPU cycles. cpu_adjust_icount(space->cpu, -513); - - // ????TODO : need to account for PPU rendering - this is roughly 4.5 scanlines eaten up. - // Because the DMA is only useful during vblank, this may not be strictly necessary since - // the scanline timers should catch us up before drawing actually happens. -#if 0 -{ - scanline_callback(device); - scanline_callback(device); - scanline_callback(device); - scanline_callback(device); -} -#endif } /*************************************