diff --git a/src/engine/platform/sound/nes/apu.c b/src/engine/platform/sound/nes/apu.c index f1793f558..7930c57e7 100644 --- a/src/engine/platform/sound/nes/apu.c +++ b/src/engine/platform/sound/nes/apu.c @@ -22,303 +22,303 @@ #include "apu.h" void apu_tick(struct NESAPU* a, BYTE *hwtick) { - /* sottraggo il numero di cicli eseguiti */ - a->apu.cycles--; - /* - * questo flag sara' a TRUE solo nel ciclo - * in cui viene eseguito il length counter. - */ - a->apu.length_clocked = FALSE; - /* - * se e' settato il delay del $4017, essendo - * questo il ciclo successivo, valorizzo il - * registro. - */ + /* sottraggo il numero di cicli eseguiti */ + a->apu.cycles--; + /* + * questo flag sara' a TRUE solo nel ciclo + * in cui viene eseguito il length counter. + */ + a->apu.length_clocked = FALSE; + /* + * se e' settato il delay del $4017, essendo + * questo il ciclo successivo, valorizzo il + * registro. + */ #if defined (VECCHIA_GESTIONE_JITTER) - if (r4017.jitter.delay) { - r4017.jitter.delay = FALSE; - r4017_jitter(); - } + if (r4017.jitter.delay) { + r4017.jitter.delay = FALSE; + r4017_jitter(); + } #else - if (a->r4017.jitter.delay) { - a->r4017.jitter.delay = FALSE; - r4017_jitter(0) - } - r4017_reset_frame() + if (a->r4017.jitter.delay) { + a->r4017.jitter.delay = FALSE; + r4017_jitter(0) + } + r4017_reset_frame() #endif - /* quando apu.cycles e' a 0 devo eseguire uno step */ - if (!a->apu.cycles) { - switch (a->apu.step) { - case 0: - /* - * nel mode 1 devo eseguire il - * length counter e lo sweep. - */ - if (a->apu.mode == APU_48HZ) { - length_clock() - sweep_clock() - } - envelope_clock() - /* triangle's linear counter */ - linear_clock() - /* passo al prossimo step */ - apu_change_step(++a->apu.step); - break; - case 1: - /* nel mode 0 devo eseguire il length counter */ - if (a->apu.mode == APU_60HZ) { - length_clock() - sweep_clock() - } - envelope_clock() - /* triangle's linear counter */ - linear_clock() - /* passo al prossimo step */ - apu_change_step(++a->apu.step); - break; - case 2: - /* - * nel mode 1 devo eseguire il - * length counter e lo sweep. - */ - if (a->apu.mode == APU_48HZ) { - length_clock() - sweep_clock() - } - envelope_clock() - /* triangle's linear counter */ - linear_clock() - /* passo al prossimo step */ - apu_change_step(++a->apu.step); - break; - case 3: - /* - * gli step 3, 4 e 5 settano il bit 6 del $4015 - * ma solo nel 4 genero un IRQ. - */ - if (a->apu.mode == APU_60HZ) { - /* - * se e' a 0 il bit 6 del $4017 (interrupt - * inhibit flag) allora devo generare un IRQ. - */ - if (!(a->r4017.value & 0x40)) { - /* setto il bit 6 del $4015 */ - a->r4015.value |= 0x40; - } - } else { - /* nel mode 1 devo eseguire l'envelope */ - envelope_clock() - /* triangle's linear counter */ - linear_clock() - } - /* passo al prossimo step */ - apu_change_step(++a->apu.step); - break; - case 4: - /* - * gli step 3, 4 e 5 settano il bit 6 del $4015 - * ma solo nel 4 genero un IRQ. - */ - if (a->apu.mode == APU_60HZ) { - length_clock() - sweep_clock() - envelope_clock() - /* triangle's linear counter */ - linear_clock() - /* - * se e' a 0 il bit 6 del $4017 (interrupt - * inhibit flag) allora devo generare un IRQ. - */ - if (!(a->r4017.value & 0x40)) { - /* setto il bit 6 del $4015 */ - a->r4015.value |= 0x40; - } - } - /* passo al prossimo step */ - apu_change_step(++a->apu.step); - break; - case 5: - /* - * gli step 3, 4 e 5 settano il bit 6 del $4015 - * ma solo nel 4 genero un IRQ. - */ - if (a->apu.mode == APU_60HZ) { - /* - * se e' a 0 il bit 6 del $4017 (interrupt - * inhibit flag) allora devo generare un IRQ. - */ - if (!(a->r4017.value & 0x40)) { - /* setto il bit 6 del $4015 */ - a->r4015.value |= 0x40; - } - a->apu.step++; - } else { - /* nel mode 1 devo ricominciare il ciclo */ - a->apu.step = 0; - } - /* passo al prossimo step */ - apu_change_step(a->apu.step); - break; - case 6: - /* da qui ci passo solo nel mode 0 */ - envelope_clock() - /* triangle's linear counter */ - linear_clock() - /* questo e' il passaggio finale del mode 0 */ - a->apu.step = 1; - /* passo al prossimo step */ - apu_change_step(a->apu.step); - break; - } - } + /* quando apu.cycles e' a 0 devo eseguire uno step */ + if (!a->apu.cycles) { + switch (a->apu.step) { + case 0: + /* + * nel mode 1 devo eseguire il + * length counter e lo sweep. + */ + if (a->apu.mode == APU_48HZ) { + length_clock() + sweep_clock() + } + envelope_clock() + /* triangle's linear counter */ + linear_clock() + /* passo al prossimo step */ + apu_change_step(++a->apu.step); + break; + case 1: + /* nel mode 0 devo eseguire il length counter */ + if (a->apu.mode == APU_60HZ) { + length_clock() + sweep_clock() + } + envelope_clock() + /* triangle's linear counter */ + linear_clock() + /* passo al prossimo step */ + apu_change_step(++a->apu.step); + break; + case 2: + /* + * nel mode 1 devo eseguire il + * length counter e lo sweep. + */ + if (a->apu.mode == APU_48HZ) { + length_clock() + sweep_clock() + } + envelope_clock() + /* triangle's linear counter */ + linear_clock() + /* passo al prossimo step */ + apu_change_step(++a->apu.step); + break; + case 3: + /* + * gli step 3, 4 e 5 settano il bit 6 del $4015 + * ma solo nel 4 genero un IRQ. + */ + if (a->apu.mode == APU_60HZ) { + /* + * se e' a 0 il bit 6 del $4017 (interrupt + * inhibit flag) allora devo generare un IRQ. + */ + if (!(a->r4017.value & 0x40)) { + /* setto il bit 6 del $4015 */ + a->r4015.value |= 0x40; + } + } else { + /* nel mode 1 devo eseguire l'envelope */ + envelope_clock() + /* triangle's linear counter */ + linear_clock() + } + /* passo al prossimo step */ + apu_change_step(++a->apu.step); + break; + case 4: + /* + * gli step 3, 4 e 5 settano il bit 6 del $4015 + * ma solo nel 4 genero un IRQ. + */ + if (a->apu.mode == APU_60HZ) { + length_clock() + sweep_clock() + envelope_clock() + /* triangle's linear counter */ + linear_clock() + /* + * se e' a 0 il bit 6 del $4017 (interrupt + * inhibit flag) allora devo generare un IRQ. + */ + if (!(a->r4017.value & 0x40)) { + /* setto il bit 6 del $4015 */ + a->r4015.value |= 0x40; + } + } + /* passo al prossimo step */ + apu_change_step(++a->apu.step); + break; + case 5: + /* + * gli step 3, 4 e 5 settano il bit 6 del $4015 + * ma solo nel 4 genero un IRQ. + */ + if (a->apu.mode == APU_60HZ) { + /* + * se e' a 0 il bit 6 del $4017 (interrupt + * inhibit flag) allora devo generare un IRQ. + */ + if (!(a->r4017.value & 0x40)) { + /* setto il bit 6 del $4015 */ + a->r4015.value |= 0x40; + } + a->apu.step++; + } else { + /* nel mode 1 devo ricominciare il ciclo */ + a->apu.step = 0; + } + /* passo al prossimo step */ + apu_change_step(a->apu.step); + break; + case 6: + /* da qui ci passo solo nel mode 0 */ + envelope_clock() + /* triangle's linear counter */ + linear_clock() + /* questo e' il passaggio finale del mode 0 */ + a->apu.step = 1; + /* passo al prossimo step */ + apu_change_step(a->apu.step); + break; + } + } - /* - * eseguo un ticket per ogni canale - * valorizzandone l'output. - */ - // SQUARE 1 TICK - if (!(--a->S1.frequency)) { - square_output(a->S1, 0) - a->S1.frequency = (a->S1.timer + 1) << 1; - a->S1.sequencer = (a->S1.sequencer + 1) & 0x07; - a->apu.clocked = TRUE; - } + /* + * eseguo un ticket per ogni canale + * valorizzandone l'output. + */ + // SQUARE 1 TICK + if (!(--a->S1.frequency)) { + square_output(a->S1, 0) + a->S1.frequency = (a->S1.timer + 1) << 1; + a->S1.sequencer = (a->S1.sequencer + 1) & 0x07; + a->apu.clocked = TRUE; + } - // SQUARE 2 TICK - if (!(--a->S2.frequency)) { - square_output(a->S2, 0) - a->S2.frequency = (a->S2.timer + 1) << 1; - a->S2.sequencer = (a->S2.sequencer + 1) & 0x07; - a->apu.clocked = TRUE; - } + // SQUARE 2 TICK + if (!(--a->S2.frequency)) { + square_output(a->S2, 0) + a->S2.frequency = (a->S2.timer + 1) << 1; + a->S2.sequencer = (a->S2.sequencer + 1) & 0x07; + a->apu.clocked = TRUE; + } - // TRIANGLE TICK - if (!(--a->TR.frequency)) { - a->TR.frequency = a->TR.timer + 1; - if (a->TR.length.value && a->TR.linear.value) { - a->TR.sequencer = (a->TR.sequencer + 1) & 0x1F; - triangle_output() - a->apu.clocked = TRUE; - } - } + // TRIANGLE TICK + if (!(--a->TR.frequency)) { + a->TR.frequency = a->TR.timer + 1; + if (a->TR.length.value && a->TR.linear.value) { + a->TR.sequencer = (a->TR.sequencer + 1) & 0x1F; + triangle_output() + a->apu.clocked = TRUE; + } + } - // NOISE TICK - if (!(--a->NS.frequency)) { - if (a->NS.mode) { - a->NS.shift = (a->NS.shift >> 1) | (((a->NS.shift ^ (a->NS.shift >> 6)) & 0x0001) << 14); - } else { - a->NS.shift = (a->NS.shift >> 1) | (((a->NS.shift ^ (a->NS.shift >> 1)) & 0x0001) << 14); - } - a->NS.shift &= 0x7FFF; - noise_output() - a->NS.frequency = noise_timer[a->apu.type][a->NS.timer]; - a->apu.clocked = TRUE; - } + // NOISE TICK + if (!(--a->NS.frequency)) { + if (a->NS.mode) { + a->NS.shift = (a->NS.shift >> 1) | (((a->NS.shift ^ (a->NS.shift >> 6)) & 0x0001) << 14); + } else { + a->NS.shift = (a->NS.shift >> 1) | (((a->NS.shift ^ (a->NS.shift >> 1)) & 0x0001) << 14); + } + a->NS.shift &= 0x7FFF; + noise_output() + a->NS.frequency = noise_timer[a->apu.type][a->NS.timer]; + a->apu.clocked = TRUE; + } - // DMC TICK - if (!(--a->DMC.frequency)) { - if (!a->DMC.silence) { - if (!(a->DMC.shift & 0x01)) { - if (a->DMC.counter > 1) { - a->DMC.counter -= 2; - } - } else { - if (a->DMC.counter < 126) { - a->DMC.counter += 2; - } - } - } - a->DMC.shift >>= 1; - dmc_output(); - if (!(--a->DMC.counter_out)) { - a->DMC.counter_out = 8; - if (!a->DMC.empty) { - a->DMC.shift = a->DMC.buffer; - a->DMC.empty = TRUE; - a->DMC.silence = FALSE; - } else { - a->DMC.silence = TRUE; - } - } - a->DMC.frequency = dmc_rate[a->apu.type][a->DMC.rate_index]; - a->apu.clocked = TRUE; - } - if (a->DMC.empty && a->DMC.remain) { - BYTE tick = 4; - switch (a->DMC.tick_type) { - case DMC_CPU_WRITE: - tick = 3; - break; - case DMC_R4014: - tick = 2; - break; - case DMC_NNL_DMA: - tick = 1; - break; - } - { - a->DMC.buffer = a->readDMC(a->readDMCUser,a->DMC.address); - } - /* incremento gli hwtick da compiere */ - if (hwtick) { hwtick[0] += tick; } - /* e naturalmente incremento anche quelli eseguiti dall'opcode */ - a->apu.cpu_cycles += tick; - /* salvo a che ciclo dell'istruzione avviene il dma */ - a->DMC.dma_cycle = a->apu.cpu_opcode_cycle; - /* il DMC non e' vuoto */ - a->DMC.empty = FALSE; - if (++a->DMC.address > 0xFFFF) { - a->DMC.address = 0x8000; - } - if (!(--a->DMC.remain)) { - if (a->DMC.loop) { - a->DMC.remain = a->DMC.length; - a->DMC.address = a->DMC.address_start; - } else if (a->DMC.irq_enabled) { - a->r4015.value |= 0x80; - } - } - } + // DMC TICK + if (!(--a->DMC.frequency)) { + if (!a->DMC.silence) { + if (!(a->DMC.shift & 0x01)) { + if (a->DMC.counter > 1) { + a->DMC.counter -= 2; + } + } else { + if (a->DMC.counter < 126) { + a->DMC.counter += 2; + } + } + } + a->DMC.shift >>= 1; + dmc_output(); + if (!(--a->DMC.counter_out)) { + a->DMC.counter_out = 8; + if (!a->DMC.empty) { + a->DMC.shift = a->DMC.buffer; + a->DMC.empty = TRUE; + a->DMC.silence = FALSE; + } else { + a->DMC.silence = TRUE; + } + } + a->DMC.frequency = dmc_rate[a->apu.type][a->DMC.rate_index]; + a->apu.clocked = TRUE; + } + if (a->DMC.empty && a->DMC.remain) { + BYTE tick = 4; + switch (a->DMC.tick_type) { + case DMC_CPU_WRITE: + tick = 3; + break; + case DMC_R4014: + tick = 2; + break; + case DMC_NNL_DMA: + tick = 1; + break; + } + { + a->DMC.buffer = a->readDMC(a->readDMCUser,a->DMC.address); + } + /* incremento gli hwtick da compiere */ + if (hwtick) { hwtick[0] += tick; } + /* e naturalmente incremento anche quelli eseguiti dall'opcode */ + a->apu.cpu_cycles += tick; + /* salvo a che ciclo dell'istruzione avviene il dma */ + a->DMC.dma_cycle = a->apu.cpu_opcode_cycle; + /* il DMC non e' vuoto */ + a->DMC.empty = FALSE; + if (++a->DMC.address > 0xFFFF) { + a->DMC.address = 0x8000; + } + if (!(--a->DMC.remain)) { + if (a->DMC.loop) { + a->DMC.remain = a->DMC.length; + a->DMC.address = a->DMC.address_start; + } else if (a->DMC.irq_enabled) { + a->r4015.value |= 0x80; + } + } + } - a->r4011.cycles++; + a->r4011.cycles++; } void apu_turn_on(struct NESAPU* a, BYTE apu_type) { - memset(&a->apu, 0x00, sizeof(a->apu)); - memset(&a->r4015, 0x00, sizeof(a->r4015)); - memset(&a->r4017, 0x00, sizeof(a->r4017)); - /* azzero tutte le variabili interne dei canali */ - memset(&a->S1, 0x00, sizeof(a->S1)); - memset(&a->S2, 0x00, sizeof(a->S2)); - memset(&a->TR, 0x00, sizeof(a->TR)); - memset(&a->NS, 0x00, sizeof(a->NS)); - memset(&a->DMC, 0x00, sizeof(a->DMC)); - /* al reset e' sempre settato a 60Hz */ - a->apu.mode = APU_60HZ; + memset(&a->apu, 0x00, sizeof(a->apu)); + memset(&a->r4015, 0x00, sizeof(a->r4015)); + memset(&a->r4017, 0x00, sizeof(a->r4017)); + /* azzero tutte le variabili interne dei canali */ + memset(&a->S1, 0x00, sizeof(a->S1)); + memset(&a->S2, 0x00, sizeof(a->S2)); + memset(&a->TR, 0x00, sizeof(a->TR)); + memset(&a->NS, 0x00, sizeof(a->NS)); + memset(&a->DMC, 0x00, sizeof(a->DMC)); + /* al reset e' sempre settato a 60Hz */ + a->apu.mode = APU_60HZ; /* per favore non fatemi questo... e' terribile */ - a->apu.type = apu_type; - apu_change_step(a->apu.step); - /* valori iniziali dei vari canali */ - a->S1.frequency = 1; - a->S1.sweep.delay = 1; - a->S1.sweep.divider = 1; - a->S2.frequency = 1; - a->S2.sweep.delay = 1; - a->S2.sweep.divider = 1; - a->TR.frequency = 1; + a->apu.type = apu_type; + apu_change_step(a->apu.step); + /* valori iniziali dei vari canali */ + a->S1.frequency = 1; + a->S1.sweep.delay = 1; + a->S1.sweep.divider = 1; + a->S2.frequency = 1; + a->S2.sweep.delay = 1; + a->S2.sweep.divider = 1; + a->TR.frequency = 1; /* questo era 0 ma produce click nell'audio */ - a->TR.sequencer = 7; - a->NS.frequency = 1; - a->NS.shift = 1; - a->DMC.frequency = 1; - a->DMC.empty = TRUE; - a->DMC.silence = TRUE; - a->DMC.counter_out = 8; - // sembra che l'address del DMC al power on dia valorizzato a 0xC000 - // e la lunghezza del sample sia settato a 1 byte. - // http://forums.nesdev.com/viewtopic.php?f=3&t=18278 - a->DMC.length = 1; - a->DMC.address_start = 0xC000; + a->TR.sequencer = 7; + a->NS.frequency = 1; + a->NS.shift = 1; + a->DMC.frequency = 1; + a->DMC.empty = TRUE; + a->DMC.silence = TRUE; + a->DMC.counter_out = 8; + // sembra che l'address del DMC al power on dia valorizzato a 0xC000 + // e la lunghezza del sample sia settato a 1 byte. + // http://forums.nesdev.com/viewtopic.php?f=3&t=18278 + a->DMC.length = 1; + a->DMC.address_start = 0xC000; a->apu.odd_cycle = 0; // come non viene inizializzato? Vorrei qualche spiegazione... a->r4011.frames = 0; diff --git a/src/engine/platform/sound/nes/apu.h b/src/engine/platform/sound/nes/apu.h index cd10e070f..1e1afffae 100644 --- a/src/engine/platform/sound/nes/apu.h +++ b/src/engine/platform/sound/nes/apu.h @@ -31,384 +31,384 @@ enum apu_mode { APU_60HZ, APU_48HZ }; /* length counter */ #define length_run(channel)\ - /*\ - * se non e' settato il flag halt e il length\ - * counter non e' 0 allora devo decrementarlo.\ - */\ - if (!channel.length.halt && channel.length.value) {\ - channel.length.value--;\ - } + /*\ + * se non e' settato il flag halt e il length\ + * counter non e' 0 allora devo decrementarlo.\ + */\ + if (!channel.length.halt && channel.length.value) {\ + channel.length.value--;\ + } #define length_clock()\ - a->apu.length_clocked = TRUE;\ - length_run(a->S1)\ - length_run(a->S2)\ - length_run(a->TR)\ - length_run(a->NS) + a->apu.length_clocked = TRUE;\ + length_run(a->S1)\ + length_run(a->S2)\ + length_run(a->TR)\ + length_run(a->NS) /* envelope */ #define envelope_run(channel)\ - if (channel.envelope.enabled) {\ - channel.envelope.enabled = FALSE;\ - channel.envelope.counter = 15;\ - channel.envelope.delay = (channel.envelope.divider + 1);\ - } else if (!(--channel.envelope.delay)) {\ - channel.envelope.delay = (channel.envelope.divider + 1);\ - if (channel.envelope.counter | channel.length.halt) {\ - channel.envelope.counter = (channel.envelope.counter - 1) & 0x0F;\ - }\ - } + if (channel.envelope.enabled) {\ + channel.envelope.enabled = FALSE;\ + channel.envelope.counter = 15;\ + channel.envelope.delay = (channel.envelope.divider + 1);\ + } else if (!(--channel.envelope.delay)) {\ + channel.envelope.delay = (channel.envelope.divider + 1);\ + if (channel.envelope.counter | channel.length.halt) {\ + channel.envelope.counter = (channel.envelope.counter - 1) & 0x0F;\ + }\ + } #define envelope_volume(channel)\ - /* setto il volume */\ - if (!channel.length.value) {\ - channel.volume = 0;\ - } else if (channel.envelope.constant_volume) {\ - channel.volume = channel.envelope.divider;\ - } else {\ - channel.volume = channel.envelope.counter;\ - } + /* setto il volume */\ + if (!channel.length.value) {\ + channel.volume = 0;\ + } else if (channel.envelope.constant_volume) {\ + channel.volume = channel.envelope.divider;\ + } else {\ + channel.volume = channel.envelope.counter;\ + } #define envelope_clock()\ - envelope_run(a->S1)\ - envelope_run(a->S2)\ - envelope_run(a->NS) + envelope_run(a->S1)\ + envelope_run(a->S2)\ + envelope_run(a->NS) /* sweep */ #define sweep_run(channel, negative_adjust)\ - if (!(--channel.sweep.delay)) {\ - channel.sweep.delay = (channel.sweep.divider + 1);\ - if (channel.sweep.enabled && channel.sweep.shift && (channel.timer >= 8)) {\ - SWORD offset = channel.timer >> channel.sweep.shift;\ - if (channel.sweep.negate) {\ - channel.timer += ((SWORD) negative_adjust - offset);\ - } else if ((channel.timer + offset) <= 0x800) {\ - channel.timer += offset;\ - }\ - }\ - sweep_silence(channel)\ - }\ - if (channel.sweep.reload) {\ - channel.sweep.reload = FALSE;\ - channel.sweep.delay = (channel.sweep.divider + 1);\ - } + if (!(--channel.sweep.delay)) {\ + channel.sweep.delay = (channel.sweep.divider + 1);\ + if (channel.sweep.enabled && channel.sweep.shift && (channel.timer >= 8)) {\ + SWORD offset = channel.timer >> channel.sweep.shift;\ + if (channel.sweep.negate) {\ + channel.timer += ((SWORD) negative_adjust - offset);\ + } else if ((channel.timer + offset) <= 0x800) {\ + channel.timer += offset;\ + }\ + }\ + sweep_silence(channel)\ + }\ + if (channel.sweep.reload) {\ + channel.sweep.reload = FALSE;\ + channel.sweep.delay = (channel.sweep.divider + 1);\ + } #define sweep_silence(channel)\ {\ - WORD offset = channel.timer >> channel.sweep.shift;\ - channel.sweep.silence = FALSE;\ - if ((channel.timer <= 8) || (!channel.sweep.negate && ((channel.timer + offset) >= 0x800))) {\ - channel.sweep.silence = TRUE;\ - }\ + WORD offset = channel.timer >> channel.sweep.shift;\ + channel.sweep.silence = FALSE;\ + if ((channel.timer <= 8) || (!channel.sweep.negate && ((channel.timer + offset) >= 0x800))) {\ + channel.sweep.silence = TRUE;\ + }\ } #define sweep_clock()\ - sweep_run(a->S1, -1)\ - sweep_run(a->S2, 0) + sweep_run(a->S1, -1)\ + sweep_run(a->S2, 0) /* linear counter */ #define linear_clock()\ - if (a->TR.linear.halt) {\ - a->TR.linear.value = a->TR.linear.reload;\ - } else if (a->TR.linear.value) {\ - a->TR.linear.value--;\ - }\ - if (!a->TR.length.halt) {\ - a->TR.linear.halt = FALSE;\ - } + if (a->TR.linear.halt) {\ + a->TR.linear.value = a->TR.linear.reload;\ + } else if (a->TR.linear.value) {\ + a->TR.linear.value--;\ + }\ + if (!a->TR.length.halt) {\ + a->TR.linear.halt = FALSE;\ + } /* output */ #define square_output(square, swap)\ {\ - envelope_volume(square)\ - if (square.sweep.silence) {\ - square.output = 0;\ - } else {\ - square.output = square_duty[swap][square.duty][square.sequencer] * square.volume;\ - }\ + envelope_volume(square)\ + if (square.sweep.silence) {\ + square.output = 0;\ + } else {\ + square.output = square_duty[swap][square.duty][square.sequencer] * square.volume;\ + }\ } #define triangle_output()\ - /*\ - * ai 2 cicli piu' bassi del timer, la frequenza\ - * risultante e' troppo alta (oltre i 20 kHz,\ - * quindi non udibile), percio' la taglio.\ - */\ - a->TR.output = triangle_duty[a->TR.sequencer];\ - if (a->TR.timer < 2) {\ - a->TR.output = triangle_duty[8];\ - } + /*\ + * ai 2 cicli piu' bassi del timer, la frequenza\ + * risultante e' troppo alta (oltre i 20 kHz,\ + * quindi non udibile), percio' la taglio.\ + */\ + a->TR.output = triangle_duty[a->TR.sequencer];\ + if (a->TR.timer < 2) {\ + a->TR.output = triangle_duty[8];\ + } #define noise_output()\ - envelope_volume(a->NS)\ - a->NS.output = 0;\ - if (a->NS.length.value && !(a->NS.shift & 0x0001)) {\ - a->NS.output = a->NS.volume;\ - } + envelope_volume(a->NS)\ + a->NS.output = 0;\ + if (a->NS.length.value && !(a->NS.shift & 0x0001)) {\ + a->NS.output = a->NS.volume;\ + } #define dmc_output()\ - a->DMC.output = a->DMC.counter & 0x7F + a->DMC.output = a->DMC.counter & 0x7F /* tick */ #define apu_change_step(index)\ - a->apu.cycles += apuPeriod[a->apu.mode][a->apu.type][index] + a->apu.cycles += apuPeriod[a->apu.mode][a->apu.type][index] #if defined (VECCHIA_GESTIONE_JITTER) #define r4017_jitter()\ - a->r4017.value = (a->r4017.jitter.value & 0xC0);\ - /*\ - * se il bit 7 e' a zero, devo attivare la\ - * modalita' NTSC, se a uno quella PAL.\ - */\ - if (a->r4017.value & 0x80) {\ - a->apu.mode = APU_48HZ;\ - } else {\ - a->apu.mode = APU_60HZ;\ - }\ - if (a->r4017.value & 0x40) {\ - /* azzero il bit 6 del $4015 */\ - a->r4015.value &= 0xBF;\ - /* questo non e' affatto necessario sul forno */\ - }\ - /* riavvio il frame audio */\ - a->apu.step = a->apu.cycles = 0;\ - apu_change_step(a->apu.step) + a->r4017.value = (a->r4017.jitter.value & 0xC0);\ + /*\ + * se il bit 7 e' a zero, devo attivare la\ + * modalita' NTSC, se a uno quella PAL.\ + */\ + if (a->r4017.value & 0x80) {\ + a->apu.mode = APU_48HZ;\ + } else {\ + a->apu.mode = APU_60HZ;\ + }\ + if (a->r4017.value & 0x40) {\ + /* azzero il bit 6 del $4015 */\ + a->r4015.value &= 0xBF;\ + /* questo non e' affatto necessario sul forno */\ + }\ + /* riavvio il frame audio */\ + a->apu.step = a->apu.cycles = 0;\ + apu_change_step(a->apu.step) #else #define r4017_jitter(apc)\ - a->r4017.value = (a->r4017.jitter.value & 0xC0);\ - a->r4017.reset_frame_delay = 1;\ - if (a->apu.cycles == apc) {\ - if (a->apu.mode == APU_48HZ) {\ - a->r4017.reset_frame_delay += 1;\ - } else {\ - a->r4017.reset_frame_delay += 2;\ - }\ - }\ - /*\ - * se il bit 7 e' a zero, devo attivare la\ - * modalita' NTSC, se a uno quella PAL.\ - */\ - if (a->r4017.value & 0x80) {\ - a->apu.mode = APU_48HZ;\ - } else {\ - a->apu.mode = APU_60HZ;\ - }\ - if (a->r4017.value & 0x40) {\ - /* azzero il bit 6 del $4015 */\ - a->r4015.value &= 0xBF;\ - /* questo non e' affatto necessario sul forno */\ - } + a->r4017.value = (a->r4017.jitter.value & 0xC0);\ + a->r4017.reset_frame_delay = 1;\ + if (a->apu.cycles == apc) {\ + if (a->apu.mode == APU_48HZ) {\ + a->r4017.reset_frame_delay += 1;\ + } else {\ + a->r4017.reset_frame_delay += 2;\ + }\ + }\ + /*\ + * se il bit 7 e' a zero, devo attivare la\ + * modalita' NTSC, se a uno quella PAL.\ + */\ + if (a->r4017.value & 0x80) {\ + a->apu.mode = APU_48HZ;\ + } else {\ + a->apu.mode = APU_60HZ;\ + }\ + if (a->r4017.value & 0x40) {\ + /* azzero il bit 6 del $4015 */\ + a->r4015.value &= 0xBF;\ + /* questo non e' affatto necessario sul forno */\ + } #define r4017_reset_frame()\ - if (a->r4017.reset_frame_delay && (--a->r4017.reset_frame_delay == 0)) {\ - /* riavvio il frame audio */\ - a->apu.step = a->apu.cycles = 0;\ - apu_change_step(a->apu.step);\ - } + if (a->r4017.reset_frame_delay && (--a->r4017.reset_frame_delay == 0)) {\ + /* riavvio il frame audio */\ + a->apu.step = a->apu.cycles = 0;\ + apu_change_step(a->apu.step);\ + } #endif #define square_reg0(square)\ - /* duty */\ - square.duty = value >> 6;\ - /* length counter */\ - square.length.halt = value & 0x20;\ - /* envelope */\ - square.envelope.constant_volume = value & 0x10;\ - square.envelope.divider = value & 0x0F + /* duty */\ + square.duty = value >> 6;\ + /* length counter */\ + square.length.halt = value & 0x20;\ + /* envelope */\ + square.envelope.constant_volume = value & 0x10;\ + square.envelope.divider = value & 0x0F #define square_reg1(square)\ - /* sweep */\ - square.sweep.reload = TRUE;\ - square.sweep.divider = (value >> 4) & 0x07;\ - square.sweep.shift = value & 0x07;\ - square.sweep.enabled = value & 0x80;\ - square.sweep.negate = value & 0x08 + /* sweep */\ + square.sweep.reload = TRUE;\ + square.sweep.divider = (value >> 4) & 0x07;\ + square.sweep.shift = value & 0x07;\ + square.sweep.enabled = value & 0x80;\ + square.sweep.negate = value & 0x08 #define square_reg2(square)\ - /* timer (low 8 bits) */\ - square.timer = (square.timer & 0x0700) | value + /* timer (low 8 bits) */\ + square.timer = (square.timer & 0x0700) | value #define square_reg3(square,length_clocked)\ - /* length counter */\ - /*\ - * se non disabilitato, una scrittura in\ - * questo registro, carica immediatamente il\ - * length counter del canale, tranne nel caso\ - * in cui la scrittura avvenga nello stesso\ - * momento del clock di un length counter e\ - * con il length diverso da zero.\ - */\ - if (square.length.enabled && !(length_clocked && square.length.value)) {\ - square.length.value = length_table[value >> 3];\ - }\ - /* envelope */\ - square.envelope.enabled = TRUE;\ - /* timer (high 3 bits) */\ - square.timer = (square.timer & 0x00FF) | ((value & 0x07) << 8);\ - /*The correct behaviour is to reset the duty cycle sequencers but not the clock dividers*/\ - /*square.frequency = 1;*/\ - /* sequencer */\ - square.sequencer = 0 + /* length counter */\ + /*\ + * se non disabilitato, una scrittura in\ + * questo registro, carica immediatamente il\ + * length counter del canale, tranne nel caso\ + * in cui la scrittura avvenga nello stesso\ + * momento del clock di un length counter e\ + * con il length diverso da zero.\ + */\ + if (square.length.enabled && !(length_clocked && square.length.value)) {\ + square.length.value = length_table[value >> 3];\ + }\ + /* envelope */\ + square.envelope.enabled = TRUE;\ + /* timer (high 3 bits) */\ + square.timer = (square.timer & 0x00FF) | ((value & 0x07) << 8);\ + /*The correct behaviour is to reset the duty cycle sequencers but not the clock dividers*/\ + /*square.frequency = 1;*/\ + /* sequencer */\ + square.sequencer = 0 #define init_nla_table(p, t)\ {\ - WORD i;\ - for (i = 0; i < LENGTH(nla_table.pulse); i++) {\ - double vl = 95.52 / (8128.0 / (double) i + 100.0);\ - nla_table.pulse[i] = (vl * p);\ - }\ - for (i = 0; i < LENGTH(nla_table.tnd); i++) {\ - double vl = 163.67 / (24329.0 / (double) i + 100.0);\ - nla_table.tnd[i] = (vl * t);\ - }\ + WORD i;\ + for (i = 0; i < LENGTH(nla_table.pulse); i++) {\ + double vl = 95.52 / (8128.0 / (double) i + 100.0);\ + nla_table.pulse[i] = (vl * p);\ + }\ + for (i = 0; i < LENGTH(nla_table.tnd); i++) {\ + double vl = 163.67 / (24329.0 / (double) i + 100.0);\ + nla_table.tnd[i] = (vl * t);\ + }\ } #define _apu_channel_volume_adjust(ch, index)\ - ((ch)) + ((ch)) #define s1_out(a)\ - (a->muted[0] ? 0 : _apu_channel_volume_adjust(a->S1.output, APU_S1)) + (a->muted[0] ? 0 : _apu_channel_volume_adjust(a->S1.output, APU_S1)) #define s2_out(a)\ - (a->muted[1] ? 0 : _apu_channel_volume_adjust(a->S2.output, APU_S2)) + (a->muted[1] ? 0 : _apu_channel_volume_adjust(a->S2.output, APU_S2)) #define tr_out(a)\ - (a->muted[2] ? 0 : _apu_channel_volume_adjust(a->TR.output, APU_TR)) + (a->muted[2] ? 0 : _apu_channel_volume_adjust(a->TR.output, APU_TR)) #define ns_out(a)\ - (a->muted[3] ? 0 : _apu_channel_volume_adjust(a->NS.output, APU_NS)) + (a->muted[3] ? 0 : _apu_channel_volume_adjust(a->NS.output, APU_NS)) #define dmc_out(a)\ - (a->muted[4] ? 0 : _apu_channel_volume_adjust(a->DMC.output, APU_DMC)) + (a->muted[4] ? 0 : _apu_channel_volume_adjust(a->DMC.output, APU_DMC)) #define extra_out(ch)\ - (ch * cfg->apu.channel[APU_EXTRA]) + (ch * cfg->apu.channel[APU_EXTRA]) #define pulse_output(a)\ - nla_table.pulse[(int) (s1_out(a) + s2_out(a))] + nla_table.pulse[(int) (s1_out(a) + s2_out(a))] #define tnd_output(a)\ - nla_table.tnd[(int) ((tr_out(a) * 3) + (ns_out(a) * 2) + dmc_out(a))] + nla_table.tnd[(int) ((tr_out(a) * 3) + (ns_out(a) * 2) + dmc_out(a))] typedef struct _config_apu { - BYTE channel[APU_MASTER + 1]; - double volume[APU_MASTER + 1]; + BYTE channel[APU_MASTER + 1]; + double volume[APU_MASTER + 1]; } _config_apu; typedef struct _apu { - BYTE mode; - BYTE type; - BYTE step; - BYTE length_clocked; - BYTE DMC; - SWORD cycles; + BYTE mode; + BYTE type; + BYTE step; + BYTE length_clocked; + BYTE DMC; + SWORD cycles; int cpu_cycles; int cpu_opcode_cycle; BYTE odd_cycle; - /* ------------------------------------------------------- */ - /* questi valori non e' necessario salvarli nei savestates */ - /* ------------------------------------------------------- */ - /* */ BYTE clocked; /* */ - /* ------------------------------------------------------- */ + /* ------------------------------------------------------- */ + /* questi valori non e' necessario salvarli nei savestates */ + /* ------------------------------------------------------- */ + /* */ BYTE clocked; /* */ + /* ------------------------------------------------------- */ } _apu; typedef struct _r4011 { - BYTE value; - DBWORD frames; - DBWORD cycles; - SWORD output; + BYTE value; + DBWORD frames; + DBWORD cycles; + SWORD output; } _r4011; typedef struct _r4015 { - BYTE value; + BYTE value; } _r4015; typedef struct _r4017 { - BYTE value; - struct _r4017_litter { - BYTE value; - BYTE delay; - } jitter; - BYTE reset_frame_delay; + BYTE value; + struct _r4017_litter { + BYTE value; + BYTE delay; + } jitter; + BYTE reset_frame_delay; } _r4017; typedef struct _envelope { - BYTE enabled; - BYTE divider; - BYTE counter; - BYTE constant_volume; - SBYTE delay; + BYTE enabled; + BYTE divider; + BYTE counter; + BYTE constant_volume; + SBYTE delay; } _envelope; typedef struct _sweep { - BYTE enabled; - BYTE negate; - BYTE divider; - BYTE shift; - BYTE reload; - BYTE silence; - SBYTE delay; + BYTE enabled; + BYTE negate; + BYTE divider; + BYTE shift; + BYTE reload; + BYTE silence; + SBYTE delay; } _sweep; typedef struct _length_counter { - BYTE value; - BYTE enabled; - BYTE halt; + BYTE value; + BYTE enabled; + BYTE halt; } _length_counter; typedef struct _linear_counter { - BYTE value; - BYTE reload; - BYTE halt; + BYTE value; + BYTE reload; + BYTE halt; } _linear_counter; typedef struct _apuSquare { - /* timer */ - DBWORD timer; - /* ogni quanti cicli devo generare un output */ - WORD frequency; - /* duty */ - BYTE duty; - /* envelope */ - _envelope envelope; - /* volume */ - BYTE volume; - /* sequencer */ - BYTE sequencer; - /* sweep */ - _sweep sweep; - /* length counter */ - _length_counter length; - /* output */ - SWORD output; + /* timer */ + DBWORD timer; + /* ogni quanti cicli devo generare un output */ + WORD frequency; + /* duty */ + BYTE duty; + /* envelope */ + _envelope envelope; + /* volume */ + BYTE volume; + /* sequencer */ + BYTE sequencer; + /* sweep */ + _sweep sweep; + /* length counter */ + _length_counter length; + /* output */ + SWORD output; } _apuSquare; typedef struct _apuTriangle { - /* timer */ - DBWORD timer; - /* ogni quanti cicli devo generare un output */ - WORD frequency; - /* linear counter */ - _linear_counter linear; - /* length counter */ - _length_counter length; - /* sequencer */ - BYTE sequencer; - /* output */ - SWORD output; + /* timer */ + DBWORD timer; + /* ogni quanti cicli devo generare un output */ + WORD frequency; + /* linear counter */ + _linear_counter linear; + /* length counter */ + _length_counter length; + /* sequencer */ + BYTE sequencer; + /* output */ + SWORD output; } _apuTriangle; typedef struct _apuNoise { - /* timer */ - DBWORD timer; - /* ogni quanti cicli devo generare un output */ - WORD frequency; - /* envelope */ - _envelope envelope; - /* specifico del noise */ - BYTE mode; - /* volume */ - BYTE volume; - /* shift register */ - WORD shift; - /* length counter */ - _length_counter length; - /* sequencer */ - BYTE sequencer; - /* output */ - SWORD output; + /* timer */ + DBWORD timer; + /* ogni quanti cicli devo generare un output */ + WORD frequency; + /* envelope */ + _envelope envelope; + /* specifico del noise */ + BYTE mode; + /* volume */ + BYTE volume; + /* shift register */ + WORD shift; + /* length counter */ + _length_counter length; + /* sequencer */ + BYTE sequencer; + /* output */ + SWORD output; } _apuNoise; typedef struct _apuDMC { - /* ogni quanti cicli devo generare un output */ - WORD frequency; + /* ogni quanti cicli devo generare un output */ + WORD frequency; - WORD remain; - BYTE irq_enabled; - BYTE loop; - BYTE rate_index; - WORD address_start; - DBWORD address; - WORD length; - BYTE counter; - BYTE empty; - BYTE buffer; + WORD remain; + BYTE irq_enabled; + BYTE loop; + BYTE rate_index; + WORD address_start; + DBWORD address; + WORD length; + BYTE counter; + BYTE empty; + BYTE buffer; - /* DMA */ - BYTE dma_cycle; + /* DMA */ + BYTE dma_cycle; - /* output unit */ - BYTE silence; - BYTE shift; - BYTE counter_out; + /* output unit */ + BYTE silence; + BYTE shift; + BYTE counter_out; - /* output */ - SWORD output; + /* output */ + SWORD output; - /* misc */ - BYTE tick_type; + /* misc */ + BYTE tick_type; } _apuDMC; #if defined (__cplusplus) @@ -418,8 +418,8 @@ typedef struct _apuDMC { #endif EXTERNC struct _nla_table { - SWORD pulse[32]; - SWORD tnd[203]; + SWORD pulse[32]; + SWORD tnd[203]; }; extern struct _nla_table nla_table; @@ -440,104 +440,104 @@ EXTERNC struct NESAPU { /* apuPeriod[mode][type][cycles] */ static const WORD apuPeriod[2][3][7] = { - /* - * Mode 0: 4-step sequence - * Action Envelopes & Length Counter& Interrupt Delay to next - * Linear Counter Sweep Units Flag NTSC PAL Dendy - * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - * $4017=$00 - - - 7459 8315 7459 - * Step 1 Clock - - 7456 8314 7456 - * Step 2 Clock Clock - 7458 8312 7458 - * Step 3 Clock - - 7458 8314 7458 - * Step 4 Clock Clock Set if enabled 7458 8314 7458 - */ - { - {7459, 7456, 7458, 7457, 1, 1, 7457}, - {8315, 8314, 8312, 8313, 1, 1, 8313}, - {7459, 7456, 7458, 7457, 1, 1, 7457} - }, - /* - * Mode 1: 5-step sequence - * Action Envelopes & Length Counter& Interrupt Delay to next - * Linear Counter Sweep Units Flag NTSC PAL Dendy - * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - * $4017=$80 - - - 1 1 1 - * Step 1 Clock Clock - 7458 8314 7458 - * Step 2 Clock - - 7456 8314 7456 - * Step 3 Clock Clock - 7458 8312 7458 - * Step 4 Clock - - 7458 8314 7458 - * Step 5 - - - 7452 8312 7452 - * - * Note: - * il 7452 e il 8312 dello step 5 diventano 7451 e 8311 - * nella mia tabella perche' il ciclo mancante lo eseguo - * all'inizio del ciclo successivo. - */ - { - {1, 7458, 7456, 7458, 7458, 7451, 0}, - {1, 8314, 8314, 8312, 8314, 8311, 0}, - {1, 7458, 7456, 7458, 7458, 7451, 0} - } + /* + * Mode 0: 4-step sequence + * Action Envelopes & Length Counter& Interrupt Delay to next + * Linear Counter Sweep Units Flag NTSC PAL Dendy + * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + * $4017=$00 - - - 7459 8315 7459 + * Step 1 Clock - - 7456 8314 7456 + * Step 2 Clock Clock - 7458 8312 7458 + * Step 3 Clock - - 7458 8314 7458 + * Step 4 Clock Clock Set if enabled 7458 8314 7458 + */ + { + {7459, 7456, 7458, 7457, 1, 1, 7457}, + {8315, 8314, 8312, 8313, 1, 1, 8313}, + {7459, 7456, 7458, 7457, 1, 1, 7457} + }, + /* + * Mode 1: 5-step sequence + * Action Envelopes & Length Counter& Interrupt Delay to next + * Linear Counter Sweep Units Flag NTSC PAL Dendy + * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + * $4017=$80 - - - 1 1 1 + * Step 1 Clock Clock - 7458 8314 7458 + * Step 2 Clock - - 7456 8314 7456 + * Step 3 Clock Clock - 7458 8312 7458 + * Step 4 Clock - - 7458 8314 7458 + * Step 5 - - - 7452 8312 7452 + * + * Note: + * il 7452 e il 8312 dello step 5 diventano 7451 e 8311 + * nella mia tabella perche' il ciclo mancante lo eseguo + * all'inizio del ciclo successivo. + */ + { + {1, 7458, 7456, 7458, 7458, 7451, 0}, + {1, 8314, 8314, 8312, 8314, 8311, 0}, + {1, 7458, 7456, 7458, 7458, 7451, 0} + } }; /* la tabella con i valori da caricare nel length counter del canale */ static const BYTE length_table[32] = { - 0x0A, 0xFE, 0x14, 0x02, 0x28, 0x04, 0x50, 0x06, - 0xA0, 0x08, 0x3C, 0x0A, 0x0E, 0x0C, 0x1A, 0x0E, - 0x0C, 0x10, 0x18, 0x12, 0x30, 0x14, 0x60, 0x16, - 0xC0, 0x18, 0x48, 0x1A, 0x10, 0x1C, 0x20, 0x1E + 0x0A, 0xFE, 0x14, 0x02, 0x28, 0x04, 0x50, 0x06, + 0xA0, 0x08, 0x3C, 0x0A, 0x0E, 0x0C, 0x1A, 0x0E, + 0x0C, 0x10, 0x18, 0x12, 0x30, 0x14, 0x60, 0x16, + 0xC0, 0x18, 0x48, 0x1A, 0x10, 0x1C, 0x20, 0x1E }; static const BYTE square_duty[2][4][8] = { - { - { 1, 0, 0, 0, 0, 0, 0, 0}, - { 1, 1, 0, 0, 0, 0, 0, 0}, - { 1, 1, 1, 1, 0, 0, 0, 0}, - { 0, 0, 1, 1, 1, 1, 1, 1} - }, - { - { 1, 0, 0, 0, 0, 0, 0, 0}, - { 1, 1, 1, 1, 0, 0, 0, 0}, - { 1, 1, 0, 0, 0, 0, 0, 0}, - { 0, 0, 1, 1, 1, 1, 1, 1} - }, + { + { 1, 0, 0, 0, 0, 0, 0, 0}, + { 1, 1, 0, 0, 0, 0, 0, 0}, + { 1, 1, 1, 1, 0, 0, 0, 0}, + { 0, 0, 1, 1, 1, 1, 1, 1} + }, + { + { 1, 0, 0, 0, 0, 0, 0, 0}, + { 1, 1, 1, 1, 0, 0, 0, 0}, + { 1, 1, 0, 0, 0, 0, 0, 0}, + { 0, 0, 1, 1, 1, 1, 1, 1} + }, }; static const BYTE triangle_duty[32] = { - 0x0F, 0x0E, 0x0D, 0x0C, 0x0B, 0x0A, 0x09, 0x08, - 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00, - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + 0x0F, 0x0E, 0x0D, 0x0C, 0x0B, 0x0A, 0x09, 0x08, + 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, }; static const WORD noise_timer[3][16] = { - { - 0x0004, 0x0008, 0x0010, 0x0020, 0x0040, 0x0060, 0x0080, 0x00A0, - 0x00CA, 0x00FE, 0x017C, 0x01FC, 0x02FA, 0x03F8, 0x07F2, 0x0FE4 - }, - { - 0x0004, 0x0007, 0x000E, 0x001E, 0x003C, 0x0058, 0x0076, 0x0094, - 0x00BC, 0x00EC, 0x0162, 0x01D8, 0x02C4, 0x03B0, 0x0762, 0x0EC2 - }, - { - 0x0004, 0x0008, 0x0010, 0x0020, 0x0040, 0x0060, 0x0080, 0x00A0, - 0x00CA, 0x00FE, 0x017C, 0x01FC, 0x02FA, 0x03F8, 0x07F2, 0x0FE4 - } + { + 0x0004, 0x0008, 0x0010, 0x0020, 0x0040, 0x0060, 0x0080, 0x00A0, + 0x00CA, 0x00FE, 0x017C, 0x01FC, 0x02FA, 0x03F8, 0x07F2, 0x0FE4 + }, + { + 0x0004, 0x0007, 0x000E, 0x001E, 0x003C, 0x0058, 0x0076, 0x0094, + 0x00BC, 0x00EC, 0x0162, 0x01D8, 0x02C4, 0x03B0, 0x0762, 0x0EC2 + }, + { + 0x0004, 0x0008, 0x0010, 0x0020, 0x0040, 0x0060, 0x0080, 0x00A0, + 0x00CA, 0x00FE, 0x017C, 0x01FC, 0x02FA, 0x03F8, 0x07F2, 0x0FE4 + } }; static const WORD dmc_rate[3][16] = { - { - 0x01AC, 0x017C, 0x0154, 0x0140, 0x011E, 0x00FE, 0x00E2, 0x00D6, - 0x00BE, 0x00A0, 0x008E, 0x0080, 0x006A, 0x0054, 0x0048, 0x0036 - }, - { - 0x018E, 0x0162, 0x013C, 0x012A, 0x0114, 0x00EC, 0x00D2, 0x00C6, - 0x00B0, 0x0094, 0x0084, 0x0076, 0x0062, 0x004E, 0x0042, 0x0032 - }, - { - 0x01AC, 0x017C, 0x0154, 0x0140, 0x011E, 0x00FE, 0x00E2, 0x00D6, - 0x00BE, 0x00A0, 0x008E, 0x0080, 0x006A, 0x0054, 0x0048, 0x0036 - } + { + 0x01AC, 0x017C, 0x0154, 0x0140, 0x011E, 0x00FE, 0x00E2, 0x00D6, + 0x00BE, 0x00A0, 0x008E, 0x0080, 0x006A, 0x0054, 0x0048, 0x0036 + }, + { + 0x018E, 0x0162, 0x013C, 0x012A, 0x0114, 0x00EC, 0x00D2, 0x00C6, + 0x00B0, 0x0094, 0x0084, 0x0076, 0x0062, 0x004E, 0x0042, 0x0032 + }, + { + 0x01AC, 0x017C, 0x0154, 0x0140, 0x011E, 0x00FE, 0x00E2, 0x00D6, + 0x00BE, 0x00A0, 0x008E, 0x0080, 0x006A, 0x0054, 0x0048, 0x0036 + } }; EXTERNC void apu_tick(struct NESAPU* a, BYTE *hwtick); diff --git a/src/engine/platform/sound/nes/common.h b/src/engine/platform/sound/nes/common.h index c8ab4b6bc..8baa438c0 100644 --- a/src/engine/platform/sound/nes/common.h +++ b/src/engine/platform/sound/nes/common.h @@ -37,31 +37,31 @@ enum exit_type { EXIT_OK, EXIT_ERROR }; enum lower_value { LOWER, UPPER }; enum machine_mode { AUTO, NTSC, PAL, DENDY, DEFAULT = 255 }; enum reset_type { - RESET = 0x10, - HARD = 0x20, - CHANGE_ROM = 0x30, - CHANGE_MODE = 0x40, - POWER_UP = 0x50 + RESET = 0x10, + HARD = 0x20, + CHANGE_ROM = 0x30, + CHANGE_MODE = 0x40, + POWER_UP = 0x50 }; /* le dimesioni dello screen da renderizzare */ enum screen_dimension { SCR_LINES = 240, SCR_ROWS = 256 }; enum type_of_system_info { HEADER, DATABASE }; enum header_type { iNES_1_0, NES_2_0, UNIF_FORMAT, FDS_FORMAT, NSF_FORMAT, NSFE_FORMAT }; enum length_file_name_type { - LENGTH_FILE_NAME = 512, - LENGTH_FILE_NAME_MID = 1024, - LENGTH_FILE_NAME_LONG = 2048, - LENGTH_FILE_NAME_MAX = 4096 + LENGTH_FILE_NAME = 512, + LENGTH_FILE_NAME_MID = 1024, + LENGTH_FILE_NAME_LONG = 2048, + LENGTH_FILE_NAME_MAX = 4096 }; enum forced_mirroring { UNK_HORIZONTAL, UNK_VERTICAL }; enum max_chips_rom { MAX_CHIPS = 8 }; enum languages { LNG_ENGLISH, LNG_ITALIAN, LNG_RUSSIAN }; enum database_mode { - NODIPSWITCH = 0xFF00, - NOEXTRA = 0x0000, - VSZAPPER = 0x0001, - CHRRAM32K = 0x0002, - CHRRAM256K = 0x0004 + NODIPSWITCH = 0xFF00, + NOEXTRA = 0x0000, + VSZAPPER = 0x0001, + CHRRAM32K = 0x0002, + CHRRAM256K = 0x0004 }; #define LENGTH(x) (sizeof(x)/sizeof(*(x))) diff --git a/src/engine/platform/sound/nes/cpu_inline.h b/src/engine/platform/sound/nes/cpu_inline.h index c9af64e9e..87ea3c9ee 100644 --- a/src/engine/platform/sound/nes/cpu_inline.h +++ b/src/engine/platform/sound/nes/cpu_inline.h @@ -25,373 +25,373 @@ #define mod_cycles_op(op, vl) cpu.cycles op vl #define r2006_during_rendering()\ - if (!ppu.vblank && r2001.visible && (ppu.frame_y > ppu_sclines.vint) &&\ - (ppu.screen_y < SCR_LINES)) {\ - _r2006_during_rendering()\ - } else {\ - r2006.value += r2000.r2006_inc;\ - } + if (!ppu.vblank && r2001.visible && (ppu.frame_y > ppu_sclines.vint) &&\ + (ppu.screen_y < SCR_LINES)) {\ + _r2006_during_rendering()\ + } else {\ + r2006.value += r2000.r2006_inc;\ + } #define _r2006_during_rendering()\ - r2006_inc()\ - if ((r2006.value & 0x1F) == 0x1F) {\ - r2006.value ^= 0x41F;\ - } else {\ - r2006.value++;\ - } + r2006_inc()\ + if ((r2006.value & 0x1F) == 0x1F) {\ + r2006.value ^= 0x41F;\ + } else {\ + r2006.value++;\ + } INLINE static void apu_wr_reg(struct NESAPU* a, WORD address, BYTE value) { - if (!(address & 0x0010)) { - /* -------------------- square 1 --------------------*/ - if (address <= 0x4003) { - if (address == 0x4000) { - square_reg0(a->S1); - return; - } - if (address == 0x4001) { - square_reg1(a->S1); - sweep_silence(a->S1) - return; - } - if (address == 0x4002) { - square_reg2(a->S1); - sweep_silence(a->S1) - return; - } - if (address == 0x4003) { - square_reg3(a->S1,a->apu.length_clocked); - sweep_silence(a->S1) - return; - } - return; - } - /* -------------------- square 2 --------------------*/ - if (address <= 0x4007) { - if (address == 0x4004) { - square_reg0(a->S2); - return; - } - if (address == 0x4005) { - square_reg1(a->S2); - sweep_silence(a->S2) - return; - } - if (address == 0x4006) { - square_reg2(a->S2); - sweep_silence(a->S2) - return; - } - if (address == 0x4007) { - square_reg3(a->S2,a->apu.length_clocked); - sweep_silence(a->S2) - return; - } - return; - } - /* -------------------- triangle --------------------*/ - if (address <= 0x400B) { - if (address == 0x4008) { - /* length counter */ - /* - * il triangle ha una posizione diversa per il - * flag LCHalt. - */ - a->TR.length.halt = value & 0x80; - /* linear counter */ - a->TR.linear.reload = value & 0x7F; - return; - } - if (address == 0x400A) { - /* timer (low 8 bits) */ - a->TR.timer = (a->TR.timer & 0x0700) | value; - return; - } - if (address == 0x400B) { - /* length counter */ - /* - * se non disabilitato, una scrittura in - * questo registro, carica immediatamente il - * length counter del canale, tranne nel caso - * in cui la scrittura avvenga nello stesso - * momento del clock di un length counter e - * con il length diverso da zero. - */ - if (a->TR.length.enabled && !(a->apu.length_clocked && a->TR.length.value)) { - a->TR.length.value = length_table[value >> 3]; - } - /* timer (high 3 bits) */ - a->TR.timer = (a->TR.timer & 0x00FF) | ((value & 0x07) << 8); - /* - * scrivendo in questo registro si setta - * automaticamente l'halt flag del triangle. - */ - a->TR.linear.halt = TRUE; - return; - } - return; - } - /* --------------------- noise ----------------------*/ - if (address <= 0x400F) { - if (address == 0x400C) { - a->NS.length.halt = value & 0x20; - /* envelope */ - a->NS.envelope.constant_volume = value & 0x10; - a->NS.envelope.divider = value & 0x0F; - return; - } - if (address == 0x400E) { - a->NS.mode = value & 0x80; - a->NS.timer = value & 0x0F; - return; - } - if (address == 0x400F) { - /* - * se non disabilitato, una scrittura in - * questo registro, carica immediatamente il - * length counter del canale, tranne nel caso - * in cui la scrittura avvenga nello stesso - * momento del clock di un length counter e - * con il length diverso da zero. - */ - if (a->NS.length.enabled && !(a->apu.length_clocked && a->NS.length.value)) { - a->NS.length.value = length_table[value >> 3]; - } - /* envelope */ - a->NS.envelope.enabled = TRUE; - return; - } - return; - } - return; - } else { - /* ---------------------- DMC -----------------------*/ - if (address <= 0x4013) { - if (address == 0x4010) { - a->DMC.irq_enabled = value & 0x80; - /* se l'irq viene disabilitato allora... */ - if (!a->DMC.irq_enabled) { - /* ...azzero l'interrupt flag del DMC */ - a->r4015.value &= 0x7F; - } - a->DMC.loop = value & 0x40; - a->DMC.rate_index = value & 0x0F; - return; - } - if (address == 0x4011) { - BYTE save = a->DMC.counter; + if (!(address & 0x0010)) { + /* -------------------- square 1 --------------------*/ + if (address <= 0x4003) { + if (address == 0x4000) { + square_reg0(a->S1); + return; + } + if (address == 0x4001) { + square_reg1(a->S1); + sweep_silence(a->S1) + return; + } + if (address == 0x4002) { + square_reg2(a->S1); + sweep_silence(a->S1) + return; + } + if (address == 0x4003) { + square_reg3(a->S1,a->apu.length_clocked); + sweep_silence(a->S1) + return; + } + return; + } + /* -------------------- square 2 --------------------*/ + if (address <= 0x4007) { + if (address == 0x4004) { + square_reg0(a->S2); + return; + } + if (address == 0x4005) { + square_reg1(a->S2); + sweep_silence(a->S2) + return; + } + if (address == 0x4006) { + square_reg2(a->S2); + sweep_silence(a->S2) + return; + } + if (address == 0x4007) { + square_reg3(a->S2,a->apu.length_clocked); + sweep_silence(a->S2) + return; + } + return; + } + /* -------------------- triangle --------------------*/ + if (address <= 0x400B) { + if (address == 0x4008) { + /* length counter */ + /* + * il triangle ha una posizione diversa per il + * flag LCHalt. + */ + a->TR.length.halt = value & 0x80; + /* linear counter */ + a->TR.linear.reload = value & 0x7F; + return; + } + if (address == 0x400A) { + /* timer (low 8 bits) */ + a->TR.timer = (a->TR.timer & 0x0700) | value; + return; + } + if (address == 0x400B) { + /* length counter */ + /* + * se non disabilitato, una scrittura in + * questo registro, carica immediatamente il + * length counter del canale, tranne nel caso + * in cui la scrittura avvenga nello stesso + * momento del clock di un length counter e + * con il length diverso da zero. + */ + if (a->TR.length.enabled && !(a->apu.length_clocked && a->TR.length.value)) { + a->TR.length.value = length_table[value >> 3]; + } + /* timer (high 3 bits) */ + a->TR.timer = (a->TR.timer & 0x00FF) | ((value & 0x07) << 8); + /* + * scrivendo in questo registro si setta + * automaticamente l'halt flag del triangle. + */ + a->TR.linear.halt = TRUE; + return; + } + return; + } + /* --------------------- noise ----------------------*/ + if (address <= 0x400F) { + if (address == 0x400C) { + a->NS.length.halt = value & 0x20; + /* envelope */ + a->NS.envelope.constant_volume = value & 0x10; + a->NS.envelope.divider = value & 0x0F; + return; + } + if (address == 0x400E) { + a->NS.mode = value & 0x80; + a->NS.timer = value & 0x0F; + return; + } + if (address == 0x400F) { + /* + * se non disabilitato, una scrittura in + * questo registro, carica immediatamente il + * length counter del canale, tranne nel caso + * in cui la scrittura avvenga nello stesso + * momento del clock di un length counter e + * con il length diverso da zero. + */ + if (a->NS.length.enabled && !(a->apu.length_clocked && a->NS.length.value)) { + a->NS.length.value = length_table[value >> 3]; + } + /* envelope */ + a->NS.envelope.enabled = TRUE; + return; + } + return; + } + return; + } else { + /* ---------------------- DMC -----------------------*/ + if (address <= 0x4013) { + if (address == 0x4010) { + a->DMC.irq_enabled = value & 0x80; + /* se l'irq viene disabilitato allora... */ + if (!a->DMC.irq_enabled) { + /* ...azzero l'interrupt flag del DMC */ + a->r4015.value &= 0x7F; + } + a->DMC.loop = value & 0x40; + a->DMC.rate_index = value & 0x0F; + return; + } + if (address == 0x4011) { + BYTE save = a->DMC.counter; - value &= 0x7F; + value &= 0x7F; - /* - * questa lo faccio perche' in alcuni giochi come Batman, - * Ninja Gaiden 3, Castlevania II ed altri, producono - * un popping del suono fastidioso; - * from Fceu doc: - * Why do some games make a popping sound (Batman, Ninja Gaiden 3, - * Castlevania II etc.)? These games do a very crude drum imitation - * by causing a large jump in the output level for a short period of - * time via the register at $4011. The analog filters on a real - * Famicom make it sound decent(better). I have not completely - * emulated these filters. - * (Xodnizel) - */ - if (a->r4011.frames > 1) { - a->r4011.output = (value - save) >> 3; - a->DMC.counter = a->DMC.output = save + a->r4011.output; - } else { - a->DMC.counter = a->DMC.output = value; - } - a->apu.clocked = TRUE; + /* + * questa lo faccio perche' in alcuni giochi come Batman, + * Ninja Gaiden 3, Castlevania II ed altri, producono + * un popping del suono fastidioso; + * from Fceu doc: + * Why do some games make a popping sound (Batman, Ninja Gaiden 3, + * Castlevania II etc.)? These games do a very crude drum imitation + * by causing a large jump in the output level for a short period of + * time via the register at $4011. The analog filters on a real + * Famicom make it sound decent(better). I have not completely + * emulated these filters. + * (Xodnizel) + */ + if (a->r4011.frames > 1) { + a->r4011.output = (value - save) >> 3; + a->DMC.counter = a->DMC.output = save + a->r4011.output; + } else { + a->DMC.counter = a->DMC.output = value; + } + a->apu.clocked = TRUE; - a->r4011.cycles = a->r4011.frames = 0; - a->r4011.value = value; - return; - } - if (address == 0x4012) { - a->DMC.address_start = (value << 6) | 0xC000; - return; - } - if (address == 0x4013) { - /* sample length */ - a->DMC.length = (value << 4) | 0x01; - return; - } - return; - } - /* --------------------------------------------------*/ - if (address == 0x4015) { - /* - * 76543210 - * || ||||| - * || ||||+- Pulse channel 1's length counter enabled flag - * || |||+-- Pulse channel 2's length counter enabled flag - * || ||+--- Triangle channel's length counter enabled flag - * || |+---- Noise channel's length counter enabled flag - * || +----- If clear, the DMC's bytes remaining is set to 0, - * || otherwise the DMC sample is restarted only if the - * || DMC's bytes remaining is 0 - * |+------- Frame interrupt flag - * +-------- DMC interrupt flag - */ - /* - * dopo la write il bit 7 (dmc flag) deve - * essere azzerato mentre lascio inalterati - * i bit 5 e 6. - */ - a->r4015.value = (a->r4015.value & 0x60) | (value & 0x1F); - /* - * quando il flag di abilitazione del length - * counter di ogni canale e' a 0, il counter - * dello stesso canale e' immediatamente azzerato. - */ - if (!(a->S1.length.enabled = a->r4015.value & 0x01)) { - a->S1.length.value = 0; - } - if (!(a->S2.length.enabled = a->r4015.value & 0x02)) { - a->S2.length.value = 0; - } - if (!(a->TR.length.enabled = a->r4015.value & 0x04)) { - a->TR.length.value = 0; - } - if (!(a->NS.length.enabled = a->r4015.value & 0x08)) { - a->NS.length.value = 0; - } - /* - * se il bit 4 e' 0 allora devo azzerare i bytes - * rimanenti del DMC, alrimenti devo riavviare - * la lettura dei sample DMC solo nel caso che - * in cui i bytes rimanenti siano a 0. - */ - if (!(a->r4015.value & 0x10)) { - a->DMC.remain = 0; - a->DMC.empty = TRUE; - } else if (!a->DMC.remain) { - a->DMC.remain = a->DMC.length; - a->DMC.address = a->DMC.address_start; - } - return; - } + a->r4011.cycles = a->r4011.frames = 0; + a->r4011.value = value; + return; + } + if (address == 0x4012) { + a->DMC.address_start = (value << 6) | 0xC000; + return; + } + if (address == 0x4013) { + /* sample length */ + a->DMC.length = (value << 4) | 0x01; + return; + } + return; + } + /* --------------------------------------------------*/ + if (address == 0x4015) { + /* + * 76543210 + * || ||||| + * || ||||+- Pulse channel 1's length counter enabled flag + * || |||+-- Pulse channel 2's length counter enabled flag + * || ||+--- Triangle channel's length counter enabled flag + * || |+---- Noise channel's length counter enabled flag + * || +----- If clear, the DMC's bytes remaining is set to 0, + * || otherwise the DMC sample is restarted only if the + * || DMC's bytes remaining is 0 + * |+------- Frame interrupt flag + * +-------- DMC interrupt flag + */ + /* + * dopo la write il bit 7 (dmc flag) deve + * essere azzerato mentre lascio inalterati + * i bit 5 e 6. + */ + a->r4015.value = (a->r4015.value & 0x60) | (value & 0x1F); + /* + * quando il flag di abilitazione del length + * counter di ogni canale e' a 0, il counter + * dello stesso canale e' immediatamente azzerato. + */ + if (!(a->S1.length.enabled = a->r4015.value & 0x01)) { + a->S1.length.value = 0; + } + if (!(a->S2.length.enabled = a->r4015.value & 0x02)) { + a->S2.length.value = 0; + } + if (!(a->TR.length.enabled = a->r4015.value & 0x04)) { + a->TR.length.value = 0; + } + if (!(a->NS.length.enabled = a->r4015.value & 0x08)) { + a->NS.length.value = 0; + } + /* + * se il bit 4 e' 0 allora devo azzerare i bytes + * rimanenti del DMC, alrimenti devo riavviare + * la lettura dei sample DMC solo nel caso che + * in cui i bytes rimanenti siano a 0. + */ + if (!(a->r4015.value & 0x10)) { + a->DMC.remain = 0; + a->DMC.empty = TRUE; + } else if (!a->DMC.remain) { + a->DMC.remain = a->DMC.length; + a->DMC.address = a->DMC.address_start; + } + return; + } #if defined (VECCHIA_GESTIONE_JITTER) - if (address == 0x4017) { - /* APU frame counter */ - r4017.jitter.value = value; - /* - * nell'2A03 se la scrittura del $4017 avviene - * in un ciclo pari, allora l'effettiva modifica - * avverra' nel ciclo successivo. - */ - if (cpu.odd_cycle) { - r4017.jitter.delay = TRUE; - } else { - r4017.jitter.delay = FALSE; - r4017_jitter(); - } - return; - } + if (address == 0x4017) { + /* APU frame counter */ + r4017.jitter.value = value; + /* + * nell'2A03 se la scrittura del $4017 avviene + * in un ciclo pari, allora l'effettiva modifica + * avverra' nel ciclo successivo. + */ + if (cpu.odd_cycle) { + r4017.jitter.delay = TRUE; + } else { + r4017.jitter.delay = FALSE; + r4017_jitter(); + } + return; + } #else - if (address == 0x4017) { - /* APU frame counter */ - a->r4017.jitter.value = value; - /* - * nell'2A03 se la scrittura del $4017 avviene - * in un ciclo pari, allora l'effettiva modifica - * avverra' nel ciclo successivo. - */ - if (a->apu.odd_cycle) { - a->r4017.jitter.delay = TRUE; - } else { - a->r4017.jitter.delay = FALSE; - r4017_jitter(1) - r4017_reset_frame() - } - return; - } + if (address == 0x4017) { + /* APU frame counter */ + a->r4017.jitter.value = value; + /* + * nell'2A03 se la scrittura del $4017 avviene + * in un ciclo pari, allora l'effettiva modifica + * avverra' nel ciclo successivo. + */ + if (a->apu.odd_cycle) { + a->r4017.jitter.delay = TRUE; + } else { + a->r4017.jitter.delay = FALSE; + r4017_jitter(1) + r4017_reset_frame() + } + return; + } #endif - } + } #if defined (DEBUG) - //fprintf(stderr, "Alert: Attempt to write APU port %04X\n", address); + //fprintf(stderr, "Alert: Attempt to write APU port %04X\n", address); #endif - return; + return; } INLINE static BYTE fds_wr_mem(struct _fds* fds, WORD address, BYTE value) { if (address == 0x4023) { fds->enabled_snd_reg=value&0x02; } - if ((address >= 0x4040) && (address <= 0x408A)) { - if (fds->enabled_snd_reg) { - if ((address >= 0x4040) && (address <= 0x407F)) { - fds->snd.wave.data[address & 0x003F] = value & 0x3F; - return (TRUE); - } - if (address == 0x4080) { - fds->snd.volume.speed = value & 0x3F; - fds->snd.volume.increase = value & 0x40; - fds->snd.volume.mode = value & 0x80; - return (TRUE); - } - if (address == 0x4082) { - fds->snd.main.frequency = (fds->snd.main.frequency & 0xFF00) | value; - return (TRUE); - } - if (address == 0x4083) { - fds->snd.main.frequency = ((value & 0x0F) << 8) | (fds->snd.main.frequency & 0x00FF); - fds->snd.envelope.disabled = value & 0x40; - fds->snd.main.silence = value & 0x80; - return (TRUE); - } - if (address == 0x4084) { - fds->snd.sweep.speed = value & 0x3F; - fds->snd.sweep.increase = value & 0x40; - fds->snd.sweep.mode = value & 0x80; - return (TRUE); - } - if (address == 0x4085) { - fds->snd.sweep.bias = ((SBYTE) (value << 1)) / 2; - fds->snd.modulation.index = 0; - return (TRUE); - } - if (address == 0x4086) { - fds->snd.modulation.frequency = (fds->snd.modulation.frequency & 0xFF00) | value; - return (TRUE); - } - if (address == 0x4087) { - fds->snd.modulation.frequency = ((value & 0x0F) << 8) - | (fds->snd.modulation.frequency & 0x00FF); - fds->snd.modulation.disabled = value & 0x80; - return (TRUE); - } - if (address == 0x4088) { - BYTE i; + if ((address >= 0x4040) && (address <= 0x408A)) { + if (fds->enabled_snd_reg) { + if ((address >= 0x4040) && (address <= 0x407F)) { + fds->snd.wave.data[address & 0x003F] = value & 0x3F; + return (TRUE); + } + if (address == 0x4080) { + fds->snd.volume.speed = value & 0x3F; + fds->snd.volume.increase = value & 0x40; + fds->snd.volume.mode = value & 0x80; + return (TRUE); + } + if (address == 0x4082) { + fds->snd.main.frequency = (fds->snd.main.frequency & 0xFF00) | value; + return (TRUE); + } + if (address == 0x4083) { + fds->snd.main.frequency = ((value & 0x0F) << 8) | (fds->snd.main.frequency & 0x00FF); + fds->snd.envelope.disabled = value & 0x40; + fds->snd.main.silence = value & 0x80; + return (TRUE); + } + if (address == 0x4084) { + fds->snd.sweep.speed = value & 0x3F; + fds->snd.sweep.increase = value & 0x40; + fds->snd.sweep.mode = value & 0x80; + return (TRUE); + } + if (address == 0x4085) { + fds->snd.sweep.bias = ((SBYTE) (value << 1)) / 2; + fds->snd.modulation.index = 0; + return (TRUE); + } + if (address == 0x4086) { + fds->snd.modulation.frequency = (fds->snd.modulation.frequency & 0xFF00) | value; + return (TRUE); + } + if (address == 0x4087) { + fds->snd.modulation.frequency = ((value & 0x0F) << 8) + | (fds->snd.modulation.frequency & 0x00FF); + fds->snd.modulation.disabled = value & 0x80; + return (TRUE); + } + if (address == 0x4088) { + BYTE i; - // 0,2,4,6,-8,-6,-4,-2 - for (i = 0; i < 32; i++) { - BYTE a = i << 1; + // 0,2,4,6,-8,-6,-4,-2 + for (i = 0; i < 32; i++) { + BYTE a = i << 1; - if (i < 31) { - fds->snd.modulation.data[a] = fds->snd.modulation.data[a + 2]; - } else { - BYTE tmp = ((value & 0x03) | (0x3F * (value & 0x04))); - fds->snd.modulation.data[a] = (SBYTE) tmp; - } - fds->snd.modulation.data[a + 1] = fds->snd.modulation.data[a]; - } - return (TRUE); - } - if (address == 0x4089) { - fds->snd.wave.writable = value & 0x80; - fds->snd.wave.volume = value & 0x03; - return (TRUE); - } - if (address == 0x408A) { - fds->snd.envelope.speed = value; - return (TRUE); - } - } - } + if (i < 31) { + fds->snd.modulation.data[a] = fds->snd.modulation.data[a + 2]; + } else { + BYTE tmp = ((value & 0x03) | (0x3F * (value & 0x04))); + fds->snd.modulation.data[a] = (SBYTE) tmp; + } + fds->snd.modulation.data[a + 1] = fds->snd.modulation.data[a]; + } + return (TRUE); + } + if (address == 0x4089) { + fds->snd.wave.writable = value & 0x80; + fds->snd.wave.volume = value & 0x03; + return (TRUE); + } + if (address == 0x408A) { + fds->snd.envelope.speed = value; + return (TRUE); + } + } + } - return (FALSE); + return (FALSE); } #endif /* CPU_INLINE_H_ */ diff --git a/src/engine/platform/sound/nes/fds.c b/src/engine/platform/sound/nes/fds.c index e72e90389..3ac14d0c7 100644 --- a/src/engine/platform/sound/nes/fds.c +++ b/src/engine/platform/sound/nes/fds.c @@ -29,110 +29,110 @@ void fds_reset(struct _fds* fds) { } void extcl_apu_tick_FDS(struct _fds* fds) { - SWORD freq; + SWORD freq; - /* volume unit */ - if (fds->snd.volume.mode) { - fds->snd.volume.gain = fds->snd.volume.speed; - } else if (!fds->snd.envelope.disabled && fds->snd.envelope.speed) { - if (fds->snd.volume.counter) { - fds->snd.volume.counter--; - } else { - fds->snd.volume.counter = (fds->snd.envelope.speed << 3) * (fds->snd.volume.speed + 1); - if (fds->snd.volume.increase) { - if (fds->snd.volume.gain < 32) { - fds->snd.volume.gain++; - } - } else if (fds->snd.volume.gain) { - fds->snd.volume.gain--; - } - } - } + /* volume unit */ + if (fds->snd.volume.mode) { + fds->snd.volume.gain = fds->snd.volume.speed; + } else if (!fds->snd.envelope.disabled && fds->snd.envelope.speed) { + if (fds->snd.volume.counter) { + fds->snd.volume.counter--; + } else { + fds->snd.volume.counter = (fds->snd.envelope.speed << 3) * (fds->snd.volume.speed + 1); + if (fds->snd.volume.increase) { + if (fds->snd.volume.gain < 32) { + fds->snd.volume.gain++; + } + } else if (fds->snd.volume.gain) { + fds->snd.volume.gain--; + } + } + } - /* sweep unit */ - if (fds->snd.sweep.mode) { - fds->snd.sweep.gain = fds->snd.sweep.speed; - } else if (!fds->snd.envelope.disabled && fds->snd.envelope.speed) { - if (fds->snd.sweep.counter) { - fds->snd.sweep.counter--; - } else { - fds->snd.sweep.counter = (fds->snd.envelope.speed << 3) * (fds->snd.sweep.speed + 1); - if (fds->snd.sweep.increase) { - if (fds->snd.sweep.gain < 32) { - fds->snd.sweep.gain++; - } - } else if (fds->snd.sweep.gain) { - fds->snd.sweep.gain--; - } - } - } + /* sweep unit */ + if (fds->snd.sweep.mode) { + fds->snd.sweep.gain = fds->snd.sweep.speed; + } else if (!fds->snd.envelope.disabled && fds->snd.envelope.speed) { + if (fds->snd.sweep.counter) { + fds->snd.sweep.counter--; + } else { + fds->snd.sweep.counter = (fds->snd.envelope.speed << 3) * (fds->snd.sweep.speed + 1); + if (fds->snd.sweep.increase) { + if (fds->snd.sweep.gain < 32) { + fds->snd.sweep.gain++; + } + } else if (fds->snd.sweep.gain) { + fds->snd.sweep.gain--; + } + } + } - /* modulation unit */ - freq = fds->snd.main.frequency; + /* modulation unit */ + freq = fds->snd.main.frequency; - if (!fds->snd.modulation.disabled && fds->snd.modulation.frequency) { - if ((fds->snd.modulation.counter -= fds->snd.modulation.frequency) < 0) { - SWORD temp, temp2, a, d; - SBYTE adj = fds->snd.modulation.data[fds->snd.modulation.index]; + if (!fds->snd.modulation.disabled && fds->snd.modulation.frequency) { + if ((fds->snd.modulation.counter -= fds->snd.modulation.frequency) < 0) { + SWORD temp, temp2, a, d; + SBYTE adj = fds->snd.modulation.data[fds->snd.modulation.index]; - fds->snd.modulation.counter += 65536; + fds->snd.modulation.counter += 65536; - if (++fds->snd.modulation.index == 64) { - fds->snd.modulation.index = 0; - } + if (++fds->snd.modulation.index == 64) { + fds->snd.modulation.index = 0; + } - if (adj == -4) { - fds->snd.sweep.bias = 0; - } else { - fds->snd.sweep.bias += adj; - } + if (adj == -4) { + fds->snd.sweep.bias = 0; + } else { + fds->snd.sweep.bias += adj; + } - temp = fds->snd.sweep.bias * ((fds->snd.sweep.gain < 32) ? fds->snd.sweep.gain : 32); + temp = fds->snd.sweep.bias * ((fds->snd.sweep.gain < 32) ? fds->snd.sweep.gain : 32); - a = 64; - d = 0; + a = 64; + d = 0; - if (temp <= 0) { - d = 15; - } else if (temp < 3040) { //95 * 32 - a = 66; - d = -31; - } + if (temp <= 0) { + d = 15; + } else if (temp < 3040) { //95 * 32 + a = 66; + d = -31; + } - temp2 = a + (SBYTE) ((temp - d) / 16 - a); + temp2 = a + (SBYTE) ((temp - d) / 16 - a); - fds->snd.modulation.mod = freq * temp2 / 64; - } + fds->snd.modulation.mod = freq * temp2 / 64; + } - if (freq) { - freq += fds->snd.modulation.mod; - } - } + if (freq) { + freq += fds->snd.modulation.mod; + } + } - /* main unit */ - if (fds->snd.main.silence) { - fds->snd.main.output = 0; - return; - } + /* main unit */ + if (fds->snd.main.silence) { + fds->snd.main.output = 0; + return; + } - if (freq && !fds->snd.wave.writable) { - if ((fds->snd.wave.counter -= freq) < 0) { - WORD level; + if (freq && !fds->snd.wave.writable) { + if ((fds->snd.wave.counter -= freq) < 0) { + WORD level; - fds->snd.wave.counter += 65536; + fds->snd.wave.counter += 65536; - level = (fds->snd.volume.gain < 32 ? fds->snd.volume.gain : 32) - * volume_wave[fds->snd.wave.volume]; + level = (fds->snd.volume.gain < 32 ? fds->snd.volume.gain : 32) + * volume_wave[fds->snd.wave.volume]; - /* valore massimo dell'output (63 * (39 * 32)) = 78624 */ - /*fds->snd.main.output = (fds->snd.wave.data[fds->snd.wave.index] * level) >> 4;*/ - fds->snd.main.output = (fds->snd.wave.data[fds->snd.wave.index] * level) >> 3; + /* valore massimo dell'output (63 * (39 * 32)) = 78624 */ + /*fds->snd.main.output = (fds->snd.wave.data[fds->snd.wave.index] * level) >> 4;*/ + fds->snd.main.output = (fds->snd.wave.data[fds->snd.wave.index] * level) >> 3; - if (++fds->snd.wave.index == 64) { - fds->snd.wave.index = 0; - } + if (++fds->snd.wave.index == 64) { + fds->snd.wave.index = 0; + } - fds->snd.wave.clocked = TRUE; - } - } + fds->snd.wave.clocked = TRUE; + } + } } diff --git a/src/engine/platform/sound/nes/fds.h b/src/engine/platform/sound/nes/fds.h index f1ef45e72..df22bc53d 100644 --- a/src/engine/platform/sound/nes/fds.h +++ b/src/engine/platform/sound/nes/fds.h @@ -30,60 +30,60 @@ enum fds_operations { FDS_OP_NONE, FDS_OP_READ, FDS_OP_WRITE }; #endif EXTERNC struct _fds { - // snd + // snd BYTE enabled_snd_reg; - struct _fds_snd { - struct _fds_snd_wave { - BYTE data[64]; - BYTE writable; - BYTE volume; + struct _fds_snd { + struct _fds_snd_wave { + BYTE data[64]; + BYTE writable; + BYTE volume; - BYTE index; - int32_t counter; + BYTE index; + int32_t counter; - /* ------------------------------------------------------- */ - /* questi valori non e' necessario salvarli nei savestates */ - /* ------------------------------------------------------- */ - /* */ BYTE clocked; /* */ - /* ------------------------------------------------------- */ - } wave; - struct _fds_snd_envelope { - BYTE speed; - BYTE disabled; - } envelope; - struct _fds_snd_main { - BYTE silence; - WORD frequency; + /* ------------------------------------------------------- */ + /* questi valori non e' necessario salvarli nei savestates */ + /* ------------------------------------------------------- */ + /* */ BYTE clocked; /* */ + /* ------------------------------------------------------- */ + } wave; + struct _fds_snd_envelope { + BYTE speed; + BYTE disabled; + } envelope; + struct _fds_snd_main { + BYTE silence; + WORD frequency; - SWORD output; - } main; - struct _fds_snd_volume { - BYTE speed; - BYTE mode; - BYTE increase; + SWORD output; + } main; + struct _fds_snd_volume { + BYTE speed; + BYTE mode; + BYTE increase; - BYTE gain; - uint32_t counter; - } volume; - struct _fds_snd_sweep { - SBYTE bias; - BYTE mode; - BYTE increase; - BYTE speed; + BYTE gain; + uint32_t counter; + } volume; + struct _fds_snd_sweep { + SBYTE bias; + BYTE mode; + BYTE increase; + BYTE speed; - BYTE gain; - uint32_t counter; - } sweep; - struct _fds_snd_modulation { - SBYTE data[64]; - WORD frequency; - BYTE disabled; + BYTE gain; + uint32_t counter; + } sweep; + struct _fds_snd_modulation { + SBYTE data[64]; + WORD frequency; + BYTE disabled; - BYTE index; - int32_t counter; - SWORD mod; - } modulation; - } snd; + BYTE index; + int32_t counter; + SWORD mod; + } modulation; + } snd; }; EXTERNC void extcl_apu_tick_FDS(struct _fds* fds); diff --git a/src/engine/platform/sound/nes/mmc5.c b/src/engine/platform/sound/nes/mmc5.c index 961ac975b..54217e7a5 100644 --- a/src/engine/platform/sound/nes/mmc5.c +++ b/src/engine/platform/sound/nes/mmc5.c @@ -28,93 +28,93 @@ const BYTE filler_attrib[4] = {0x00, 0x55, 0xAA, 0xFF}; BYTE prg_ram_mode; void map_init_MMC5(struct _mmc5* mmc5) { - memset(mmc5,0,sizeof(struct _mmc5)); + memset(mmc5,0,sizeof(struct _mmc5)); - mmc5->S3.frequency = 1; - mmc5->S4.frequency = 1; - mmc5->S3.length.enabled = 0; - mmc5->S3.length.value = 0; - mmc5->S4.length.enabled = 0; - mmc5->S4.length.value = 0; + mmc5->S3.frequency = 1; + mmc5->S4.frequency = 1; + mmc5->S3.length.enabled = 0; + mmc5->S3.length.value = 0; + mmc5->S4.length.enabled = 0; + mmc5->S4.length.value = 0; } void extcl_cpu_wr_mem_MMC5(struct _mmc5* mmc5, WORD address, BYTE value) { - if (address < 0x5000) { - return; - } + if (address < 0x5000) { + return; + } - switch (address) { - case 0x5000: - square_reg0(mmc5->S3); - return; - case 0x5001: - /* lo sweep non e' utilizzato */ - return; - case 0x5002: - square_reg2(mmc5->S3); - return; - case 0x5003: - square_reg3(mmc5->S3,0); - return; - case 0x5004: - square_reg0(mmc5->S4); - return; - case 0x5005: - /* lo sweep non e' utilizzato */ - return; - case 0x5006: - square_reg2(mmc5->S4); - return; - case 0x5007: - square_reg3(mmc5->S4,0); - return; - case 0x5010: - mmc5->pcm.enabled = ~value & 0x01; - mmc5->pcm.output = 0; - if (mmc5->pcm.enabled) { - mmc5->pcm.output = mmc5->pcm.amp; - } - mmc5->clocked = TRUE; - return; - case 0x5011: - mmc5->pcm.amp = value; - mmc5->pcm.output = 0; - if (mmc5->pcm.enabled) { - mmc5->pcm.output = mmc5->pcm.amp; - } - mmc5->clocked = TRUE; - return; - case 0x5015: - if (!(mmc5->S3.length.enabled = value & 0x01)) { - mmc5->S3.length.value = 0; - } - if (!(mmc5->S4.length.enabled = value & 0x02)) { - mmc5->S4.length.value = 0; - } - return; - } + switch (address) { + case 0x5000: + square_reg0(mmc5->S3); + return; + case 0x5001: + /* lo sweep non e' utilizzato */ + return; + case 0x5002: + square_reg2(mmc5->S3); + return; + case 0x5003: + square_reg3(mmc5->S3,0); + return; + case 0x5004: + square_reg0(mmc5->S4); + return; + case 0x5005: + /* lo sweep non e' utilizzato */ + return; + case 0x5006: + square_reg2(mmc5->S4); + return; + case 0x5007: + square_reg3(mmc5->S4,0); + return; + case 0x5010: + mmc5->pcm.enabled = ~value & 0x01; + mmc5->pcm.output = 0; + if (mmc5->pcm.enabled) { + mmc5->pcm.output = mmc5->pcm.amp; + } + mmc5->clocked = TRUE; + return; + case 0x5011: + mmc5->pcm.amp = value; + mmc5->pcm.output = 0; + if (mmc5->pcm.enabled) { + mmc5->pcm.output = mmc5->pcm.amp; + } + mmc5->clocked = TRUE; + return; + case 0x5015: + if (!(mmc5->S3.length.enabled = value & 0x01)) { + mmc5->S3.length.value = 0; + } + if (!(mmc5->S4.length.enabled = value & 0x02)) { + mmc5->S4.length.value = 0; + } + return; + } } void extcl_length_clock_MMC5(struct _mmc5* mmc5) { - length_run(mmc5->S3) - length_run(mmc5->S4) + length_run(mmc5->S3) + length_run(mmc5->S4) } void extcl_envelope_clock_MMC5(struct _mmc5* mmc5) { - envelope_run(mmc5->S3) - envelope_run(mmc5->S4) + envelope_run(mmc5->S3) + envelope_run(mmc5->S4) } void extcl_apu_tick_MMC5(struct _mmc5* mmc5) { // SQUARE 3 TICK - if (!(--mmc5->S3.frequency)) { - square_output(mmc5->S3, 0) - mmc5->S3.frequency = (mmc5->S3.timer + 1) << 1; - mmc5->S3.sequencer = (mmc5->S3.sequencer + 1) & 0x07; - mmc5->clocked = TRUE; - } + if (!(--mmc5->S3.frequency)) { + square_output(mmc5->S3, 0) + mmc5->S3.frequency = (mmc5->S3.timer + 1) << 1; + mmc5->S3.sequencer = (mmc5->S3.sequencer + 1) & 0x07; + mmc5->clocked = TRUE; + } // SQUARE 4 TICK - if (!(--mmc5->S4.frequency)) { - square_output(mmc5->S4, 0) - mmc5->S4.frequency = (mmc5->S4.timer + 1) << 1; - mmc5->S4.sequencer = (mmc5->S4.sequencer + 1) & 0x07; - mmc5->clocked = TRUE; - } + if (!(--mmc5->S4.frequency)) { + square_output(mmc5->S4, 0) + mmc5->S4.frequency = (mmc5->S4.timer + 1) << 1; + mmc5->S4.sequencer = (mmc5->S4.sequencer + 1) & 0x07; + mmc5->clocked = TRUE; + } } diff --git a/src/engine/platform/sound/nes/mmc5.h b/src/engine/platform/sound/nes/mmc5.h index 3d1fbff93..f82595c79 100644 --- a/src/engine/platform/sound/nes/mmc5.h +++ b/src/engine/platform/sound/nes/mmc5.h @@ -28,45 +28,45 @@ #endif EXTERNC struct _mmc5 { - BYTE prg_mode; - BYTE chr_mode; - BYTE ext_mode; - BYTE nmt_mode[4]; - BYTE prg_ram_write[2]; - BYTE prg_bank[4]; - uint32_t prg_ram_bank[4][2]; - BYTE chr_last; - WORD chr_high; - WORD chr_s[8]; - WORD chr_b[4]; - BYTE ext_ram[0x400]; - BYTE fill_table[0x400]; - BYTE fill_tile; - BYTE fill_attr; - BYTE split; - BYTE split_st_tile; - BYTE split_side; - BYTE split_scrl; - BYTE split_in_reg; - BYTE split_x; - BYTE split_y; - WORD split_tile; - uint32_t split_bank; - BYTE factor[2]; - WORD product; - _apuSquare S3, S4; - struct _mmc5_pcm { - BYTE enabled; - BYTE output; - BYTE amp; - } pcm; - BYTE filler[50]; + BYTE prg_mode; + BYTE chr_mode; + BYTE ext_mode; + BYTE nmt_mode[4]; + BYTE prg_ram_write[2]; + BYTE prg_bank[4]; + uint32_t prg_ram_bank[4][2]; + BYTE chr_last; + WORD chr_high; + WORD chr_s[8]; + WORD chr_b[4]; + BYTE ext_ram[0x400]; + BYTE fill_table[0x400]; + BYTE fill_tile; + BYTE fill_attr; + BYTE split; + BYTE split_st_tile; + BYTE split_side; + BYTE split_scrl; + BYTE split_in_reg; + BYTE split_x; + BYTE split_y; + WORD split_tile; + uint32_t split_bank; + BYTE factor[2]; + WORD product; + _apuSquare S3, S4; + struct _mmc5_pcm { + BYTE enabled; + BYTE output; + BYTE amp; + } pcm; + BYTE filler[50]; - /* ------------------------------------------------------- */ - /* questi valori non e' necessario salvarli nei savestates */ - /* ------------------------------------------------------- */ - /* */ BYTE clocked; /* */ - /* ------------------------------------------------------- */ + /* ------------------------------------------------------- */ + /* questi valori non e' necessario salvarli nei savestates */ + /* ------------------------------------------------------- */ + /* */ BYTE clocked; /* */ + /* ------------------------------------------------------- */ }; EXTERNC void map_init_MMC5(struct _mmc5* mmc5);