From e961cf79caf88e2e4212213d67e3557923d73eda Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sat, 8 Jan 2022 17:44:17 -0500 Subject: [PATCH] NES: add NESAPU struct to allow multi-chip support --- src/engine/platform/nes.cpp | 21 +- src/engine/platform/nes.h | 1 + src/engine/platform/sound/nes/apu.c | 122 +++++------ src/engine/platform/sound/nes/apu.h | 232 +++++++++++---------- src/engine/platform/sound/nes/cpu_inline.h | 128 ++++++------ 5 files changed, 255 insertions(+), 249 deletions(-) diff --git a/src/engine/platform/nes.cpp b/src/engine/platform/nes.cpp index cc22024f..d26326db 100644 --- a/src/engine/platform/nes.cpp +++ b/src/engine/platform/nes.cpp @@ -1,12 +1,13 @@ #include "nes.h" #include "sound/nes/cpu_inline.h" #include "../engine.h" +#include #include #define FREQ_BASE 3424.0f #define FREQ_BASE_PAL 3180.0f -#define rWrite(a,v) if (!skipRegisterWrites) {apu_wr_reg(a,v);} +#define rWrite(a,v) if (!skipRegisterWrites) {apu_wr_reg(nes,a,v);} void DivPlatformNES::acquire(short* bufL, short* bufR, size_t start, size_t len) { for (size_t i=start; iapu.odd_cycle=!nes->apu.odd_cycle; + if (nes->apu.clocked) { + nes->apu.clocked=false; } - bufL[i]=(pulse_output()+tnd_output())*30; + bufL[i]=(pulse_output(nes)+tnd_output(nes))*30; } } @@ -300,9 +301,9 @@ void DivPlatformNES::reset() { dacSample=-1; sampleBank=0; - apu_turn_on(); - apu.cpu_cycles=0; - apu.cpu_opcode_cycle=0; + apu_turn_on(nes); + nes->apu.cpu_cycles=0; + nes->apu.cpu_opcode_cycle=0; rWrite(0x4015,(!isMuted[0])|((!isMuted[1])<<1)|((!isMuted[2])<<2)|((!isMuted[3])<<3)|((!isMuted[4])<<4)); rWrite(0x4001,0x08); @@ -330,6 +331,7 @@ int DivPlatformNES::init(DivEngine* p, int channels, int sugRate, bool pal) { isMuted[i]=false; } setPAL(pal); + nes=new struct NESAPU; init_nla_table(500,500); reset(); @@ -337,6 +339,7 @@ int DivPlatformNES::init(DivEngine* p, int channels, int sugRate, bool pal) { } void DivPlatformNES::quit() { + delete nes; } DivPlatformNES::~DivPlatformNES() { diff --git a/src/engine/platform/nes.h b/src/engine/platform/nes.h index 8809e1d9..13321820 100644 --- a/src/engine/platform/nes.h +++ b/src/engine/platform/nes.h @@ -37,6 +37,7 @@ class DivPlatformNES: public DivDispatch { unsigned int dacPos; int dacSample; unsigned char sampleBank; + struct NESAPU* nes; float freqBase; diff --git a/src/engine/platform/sound/nes/apu.c b/src/engine/platform/sound/nes/apu.c index bcfe4577..981a72ec 100644 --- a/src/engine/platform/sound/nes/apu.c +++ b/src/engine/platform/sound/nes/apu.c @@ -21,14 +21,14 @@ #include #include "apu.h" -void apu_tick(BYTE *hwtick) { +void apu_tick(struct NESAPU* a, BYTE *hwtick) { /* sottraggo il numero di cicli eseguiti */ - apu.cycles--; + a->apu.cycles--; /* * questo flag sara' a TRUE solo nel ciclo * in cui viene eseguito il length counter. */ - apu.length_clocked = FALSE; + a->apu.length_clocked = FALSE; /* * se e' settato il delay del $4017, essendo * questo il ciclo successivo, valorizzo il @@ -40,22 +40,22 @@ void apu_tick(BYTE *hwtick) { r4017_jitter(); } #else - if (r4017.jitter.delay) { - r4017.jitter.delay = FALSE; + 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 (!apu.cycles) { - switch (apu.step) { + if (!a->apu.cycles) { + switch (a->apu.step) { case 0: /* * nel mode 1 devo eseguire il * length counter e lo sweep. */ - if (apu.mode == APU_48HZ) { + if (a->apu.mode == APU_48HZ) { length_clock() sweep_clock() } @@ -63,11 +63,11 @@ void apu_tick(BYTE *hwtick) { /* triangle's linear counter */ linear_clock() /* passo al prossimo step */ - apu_change_step(++apu.step); + apu_change_step(++a->apu.step); break; case 1: /* nel mode 0 devo eseguire il length counter */ - if (apu.mode == APU_60HZ) { + if (a->apu.mode == APU_60HZ) { length_clock() sweep_clock() } @@ -75,14 +75,14 @@ void apu_tick(BYTE *hwtick) { /* triangle's linear counter */ linear_clock() /* passo al prossimo step */ - apu_change_step(++apu.step); + apu_change_step(++a->apu.step); break; case 2: /* * nel mode 1 devo eseguire il * length counter e lo sweep. */ - if (apu.mode == APU_48HZ) { + if (a->apu.mode == APU_48HZ) { length_clock() sweep_clock() } @@ -90,21 +90,21 @@ void apu_tick(BYTE *hwtick) { /* triangle's linear counter */ linear_clock() /* passo al prossimo step */ - apu_change_step(++apu.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 (apu.mode == APU_60HZ) { + if (a->apu.mode == APU_60HZ) { /* * se e' a 0 il bit 6 del $4017 (interrupt * inhibit flag) allora devo generare un IRQ. */ - if (!(r4017.value & 0x40)) { + if (!(a->r4017.value & 0x40)) { /* setto il bit 6 del $4015 */ - r4015.value |= 0x40; + a->r4015.value |= 0x40; } } else { /* nel mode 1 devo eseguire l'envelope */ @@ -113,14 +113,14 @@ void apu_tick(BYTE *hwtick) { linear_clock() } /* passo al prossimo step */ - apu_change_step(++apu.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 (apu.mode == APU_60HZ) { + if (a->apu.mode == APU_60HZ) { length_clock() sweep_clock() envelope_clock() @@ -130,35 +130,35 @@ void apu_tick(BYTE *hwtick) { * se e' a 0 il bit 6 del $4017 (interrupt * inhibit flag) allora devo generare un IRQ. */ - if (!(r4017.value & 0x40)) { + if (!(a->r4017.value & 0x40)) { /* setto il bit 6 del $4015 */ - r4015.value |= 0x40; + a->r4015.value |= 0x40; } } /* passo al prossimo step */ - apu_change_step(++apu.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 (apu.mode == APU_60HZ) { + if (a->apu.mode == APU_60HZ) { /* * se e' a 0 il bit 6 del $4017 (interrupt * inhibit flag) allora devo generare un IRQ. */ - if (!(r4017.value & 0x40)) { + if (!(a->r4017.value & 0x40)) { /* setto il bit 6 del $4015 */ - r4015.value |= 0x40; + a->r4015.value |= 0x40; } - apu.step++; + a->apu.step++; } else { /* nel mode 1 devo ricominciare il ciclo */ - apu.step = 0; + a->apu.step = 0; } /* passo al prossimo step */ - apu_change_step(apu.step); + apu_change_step(a->apu.step); break; case 6: /* da qui ci passo solo nel mode 0 */ @@ -166,9 +166,9 @@ void apu_tick(BYTE *hwtick) { /* triangle's linear counter */ linear_clock() /* questo e' il passaggio finale del mode 0 */ - apu.step = 1; + a->apu.step = 1; /* passo al prossimo step */ - apu_change_step(apu.step); + apu_change_step(a->apu.step); break; } } @@ -177,8 +177,8 @@ void apu_tick(BYTE *hwtick) { * eseguo un ticket per ogni canale * valorizzandone l'output. */ - square_tick(S1, 0, apu) - square_tick(S2, 0, apu) + square_tick(a->S1, 0, a->apu) + square_tick(a->S2, 0, a->apu) triangle_tick() noise_tick() dmc_tick() @@ -188,41 +188,41 @@ void apu_tick(BYTE *hwtick) { snd_apu_tick(); }*/ - r4011.cycles++; + a->r4011.cycles++; } -void apu_turn_on(void) { - memset(&apu, 0x00, sizeof(apu)); - memset(&r4015, 0x00, sizeof(r4015)); - memset(&r4017, 0x00, sizeof(r4017)); +void apu_turn_on(struct NESAPU* a) { + 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(&S1, 0x00, sizeof(S1)); - memset(&S2, 0x00, sizeof(S2)); - memset(&TR, 0x00, sizeof(TR)); - memset(&NS, 0x00, sizeof(NS)); - memset(&DMC, 0x00, sizeof(DMC)); + 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 */ - apu.mode = APU_60HZ; - apu.type = 0; - apu_change_step(apu.step); + a->apu.mode = APU_60HZ; + a->apu.type = 0; + apu_change_step(a->apu.step); /* valori iniziali dei vari canali */ - S1.frequency = 1; - S1.sweep.delay = 1; - S1.sweep.divider = 1; - S2.frequency = 1; - S2.sweep.delay = 1; - S2.sweep.divider = 1; - TR.frequency = 1; - TR.sequencer = 0; - NS.frequency = 1; - NS.shift = 1; - DMC.frequency = 1; - DMC.empty = TRUE; - DMC.silence = TRUE; - DMC.counter_out = 8; + 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->TR.sequencer = 0; + 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 - DMC.length = 1; - DMC.address_start = 0xC000; - apu.odd_cycle = 0; + a->DMC.length = 1; + a->DMC.address_start = 0xC000; + a->apu.odd_cycle = 0; } diff --git a/src/engine/platform/sound/nes/apu.h b/src/engine/platform/sound/nes/apu.h index 0c132759..b8c7dd95 100644 --- a/src/engine/platform/sound/nes/apu.h +++ b/src/engine/platform/sound/nes/apu.h @@ -39,11 +39,11 @@ enum apu_mode { APU_60HZ, APU_48HZ }; channel.length.value--;\ } #define length_clock()\ - apu.length_clocked = TRUE;\ - length_run(S1)\ - length_run(S2)\ - length_run(TR)\ - length_run(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) {\ @@ -66,9 +66,9 @@ enum apu_mode { APU_60HZ, APU_48HZ }; channel.volume = channel.envelope.counter;\ } #define envelope_clock()\ - envelope_run(S1)\ - envelope_run(S2)\ - envelope_run(NS) + envelope_run(a->S1)\ + envelope_run(a->S2)\ + envelope_run(a->NS) /* sweep */ #define sweep_run(channel, negative_adjust)\ if (!(--channel.sweep.delay)) {\ @@ -96,17 +96,17 @@ enum apu_mode { APU_60HZ, APU_48HZ }; }\ } #define sweep_clock()\ - sweep_run(S1, -1)\ - sweep_run(S2, 0) + sweep_run(a->S1, -1)\ + sweep_run(a->S2, 0) /* linear counter */ #define linear_clock()\ - if (TR.linear.halt) {\ - TR.linear.value = TR.linear.reload;\ - } else if (TR.linear.value) {\ - TR.linear.value--;\ + if (a->TR.linear.halt) {\ + a->TR.linear.value = a->TR.linear.reload;\ + } else if (a->TR.linear.value) {\ + a->TR.linear.value--;\ }\ - if (!TR.length.halt) {\ - TR.linear.halt = FALSE;\ + if (!a->TR.length.halt) {\ + a->TR.linear.halt = FALSE;\ } /* output */ #define square_output(square, swap)\ @@ -124,18 +124,18 @@ enum apu_mode { APU_60HZ, APU_48HZ }; * risultante e' troppo alta (oltre i 20 kHz,\ * quindi non udibile), percio' la taglio.\ */\ - TR.output = triangle_duty[TR.sequencer];\ - if (TR.timer < 2) {\ - TR.output = triangle_duty[8];\ + a->TR.output = triangle_duty[a->TR.sequencer];\ + if (a->TR.timer < 2) {\ + a->TR.output = triangle_duty[8];\ } #define noise_output()\ - envelope_volume(NS)\ - NS.output = 0;\ - if (NS.length.value && !(NS.shift & 0x0001)) {\ - NS.output = 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()\ - DMC.output = DMC.counter & 0x7F + a->DMC.output = a->DMC.counter & 0x7F /* tick */ #define square_tick(square, swap, type)\ if (!(--square.frequency)) {\ @@ -145,57 +145,57 @@ enum apu_mode { APU_60HZ, APU_48HZ }; type.clocked = TRUE;\ } #define triangle_tick()\ - if (!(--TR.frequency)) {\ - TR.frequency = TR.timer + 1;\ - if (TR.length.value && TR.linear.value) {\ - TR.sequencer = (TR.sequencer + 1) & 0x1F;\ + 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()\ - apu.clocked = TRUE;\ + a->apu.clocked = TRUE;\ }\ } #define noise_tick()\ - if (!(--NS.frequency)) {\ - if (NS.mode) {\ - NS.shift = (NS.shift >> 1) | (((NS.shift ^ (NS.shift >> 6)) & 0x0001) << 14);\ + 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 {\ - NS.shift = (NS.shift >> 1) | (((NS.shift ^ (NS.shift >> 1)) & 0x0001) << 14);\ + a->NS.shift = (a->NS.shift >> 1) | (((a->NS.shift ^ (a->NS.shift >> 1)) & 0x0001) << 14);\ }\ - NS.shift &= 0x7FFF;\ + a->NS.shift &= 0x7FFF;\ noise_output()\ - NS.frequency = noise_timer[apu.type][NS.timer];\ - apu.clocked = TRUE;\ + a->NS.frequency = noise_timer[a->apu.type][a->NS.timer];\ + a->apu.clocked = TRUE;\ } #define dmc_tick()\ - if (!(--DMC.frequency)) {\ - if (!DMC.silence) {\ - if (!(DMC.shift & 0x01)) {\ - if (DMC.counter > 1) {\ - DMC.counter -= 2;\ + if (!(--a->DMC.frequency)) {\ + if (!a->DMC.silence) {\ + if (!(a->DMC.shift & 0x01)) {\ + if (a->DMC.counter > 1) {\ + a->DMC.counter -= 2;\ }\ } else {\ - if (DMC.counter < 126) {\ - DMC.counter += 2;\ + if (a->DMC.counter < 126) {\ + a->DMC.counter += 2;\ }\ }\ }\ - DMC.shift >>= 1;\ + a->DMC.shift >>= 1;\ dmc_output();\ - if (!(--DMC.counter_out)) {\ - DMC.counter_out = 8;\ - if (!DMC.empty) {\ - DMC.shift = DMC.buffer;\ - DMC.empty = TRUE;\ - DMC.silence = FALSE;\ + 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 {\ - DMC.silence = TRUE;\ + a->DMC.silence = TRUE;\ }\ }\ - DMC.frequency = dmc_rate[apu.type][DMC.rate_index];\ - apu.clocked = TRUE;\ + a->DMC.frequency = dmc_rate[a->apu.type][a->DMC.rate_index];\ + a->apu.clocked = TRUE;\ }\ - if (DMC.empty && DMC.remain) {\ + if (a->DMC.empty && a->DMC.remain) {\ BYTE tick = 4;\ - switch (DMC.tick_type) {\ + switch (a->DMC.tick_type) {\ case DMC_CPU_WRITE:\ tick = 3;\ break;\ @@ -207,81 +207,81 @@ enum apu_mode { APU_60HZ, APU_48HZ }; break;\ }\ {\ - DMC.buffer = 0;\ + a->DMC.buffer = 0;\ }\ /* incremento gli hwtick da compiere */\ if (hwtick) { hwtick[0] += tick; }\ /* e naturalmente incremento anche quelli eseguiti dall'opcode */\ - apu.cpu_cycles += tick;\ + a->apu.cpu_cycles += tick;\ /* salvo a che ciclo dell'istruzione avviene il dma */\ - DMC.dma_cycle = apu.cpu_opcode_cycle;\ + a->DMC.dma_cycle = a->apu.cpu_opcode_cycle;\ /* il DMC non e' vuoto */\ - DMC.empty = FALSE;\ - if (++DMC.address > 0xFFFF) {\ - DMC.address = 0x8000;\ + a->DMC.empty = FALSE;\ + if (++a->DMC.address > 0xFFFF) {\ + a->DMC.address = 0x8000;\ }\ - if (!(--DMC.remain)) {\ - if (DMC.loop) {\ - DMC.remain = DMC.length;\ - DMC.address = DMC.address_start;\ - } else if (DMC.irq_enabled) {\ - r4015.value |= 0x80;\ + 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;\ }\ }\ } #define apu_change_step(index)\ - apu.cycles += apuPeriod[apu.mode][apu.type][index] + a->apu.cycles += apuPeriod[a->apu.mode][a->apu.type][index] #if defined (VECCHIA_GESTIONE_JITTER) #define r4017_jitter()\ - r4017.value = (r4017.jitter.value & 0xC0);\ + 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 (r4017.value & 0x80) {\ - apu.mode = APU_48HZ;\ + if (a->r4017.value & 0x80) {\ + a->apu.mode = APU_48HZ;\ } else {\ - apu.mode = APU_60HZ;\ + a->apu.mode = APU_60HZ;\ }\ - if (r4017.value & 0x40) {\ + if (a->r4017.value & 0x40) {\ /* azzero il bit 6 del $4015 */\ - r4015.value &= 0xBF;\ + a->r4015.value &= 0xBF;\ /* questo non e' affatto necessario sul forno */\ }\ /* riavvio il frame audio */\ - apu.step = apu.cycles = 0;\ - apu_change_step(apu.step) + a->apu.step = a->apu.cycles = 0;\ + apu_change_step(a->apu.step) #else #define r4017_jitter(apc)\ - r4017.value = (r4017.jitter.value & 0xC0);\ - r4017.reset_frame_delay = 1;\ - if (apu.cycles == apc) {\ - if (apu.mode == APU_48HZ) {\ - r4017.reset_frame_delay += 1;\ + 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 {\ - r4017.reset_frame_delay += 2;\ + a->r4017.reset_frame_delay += 2;\ }\ }\ /*\ * se il bit 7 e' a zero, devo attivare la\ * modalita' NTSC, se a uno quella PAL.\ */\ - if (r4017.value & 0x80) {\ - apu.mode = APU_48HZ;\ + if (a->r4017.value & 0x80) {\ + a->apu.mode = APU_48HZ;\ } else {\ - apu.mode = APU_60HZ;\ + a->apu.mode = APU_60HZ;\ }\ - if (r4017.value & 0x40) {\ + if (a->r4017.value & 0x40) {\ /* azzero il bit 6 del $4015 */\ - r4015.value &= 0xBF;\ + a->r4015.value &= 0xBF;\ /* questo non e' affatto necessario sul forno */\ } #define r4017_reset_frame()\ - if (r4017.reset_frame_delay && (--r4017.reset_frame_delay == 0)) {\ + if (a->r4017.reset_frame_delay && (--a->r4017.reset_frame_delay == 0)) {\ /* riavvio il frame audio */\ - apu.step = apu.cycles = 0;\ - apu_change_step(apu.step);\ + a->apu.step = a->apu.cycles = 0;\ + apu_change_step(a->apu.step);\ } #endif #define square_reg0(square)\ @@ -312,7 +312,7 @@ enum apu_mode { APU_60HZ, APU_48HZ }; * momento del clock di un length counter e\ * con il length diverso da zero.\ */\ - if (square.length.enabled && !(apu.length_clocked && square.length.value)) {\ + if (square.length.enabled && !(a->apu.length_clocked && square.length.value)) {\ square.length.value = length_table[value >> 3];\ }\ /* envelope */\ @@ -337,22 +337,22 @@ enum apu_mode { APU_60HZ, APU_48HZ }; } #define _apu_channel_volume_adjust(ch, index)\ ((ch)) -#define s1_out\ - _apu_channel_volume_adjust(S1.output, APU_S1) -#define s2_out\ - _apu_channel_volume_adjust(S2.output, APU_S2) -#define tr_out\ - _apu_channel_volume_adjust(TR.output, APU_TR) -#define ns_out\ - _apu_channel_volume_adjust(NS.output, APU_NS) -#define dmc_out\ - _apu_channel_volume_adjust(DMC.output, APU_DMC) +#define s1_out(a)\ + _apu_channel_volume_adjust(a->S1.output, APU_S1) +#define s2_out(a)\ + _apu_channel_volume_adjust(a->S2.output, APU_S2) +#define tr_out(a)\ + _apu_channel_volume_adjust(a->TR.output, APU_TR) +#define ns_out(a)\ + _apu_channel_volume_adjust(a->NS.output, APU_NS) +#define dmc_out(a)\ + _apu_channel_volume_adjust(a->DMC.output, APU_DMC) #define extra_out(ch)\ (ch * cfg->apu.channel[APU_EXTRA]) -#define pulse_output()\ - nla_table.pulse[(int) (s1_out + s2_out)] -#define tnd_output()\ - nla_table.tnd[(int) ((tr_out * 3) + (ns_out * 2) + dmc_out)] +#define pulse_output(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))] typedef struct _config_apu { BYTE channel[APU_MASTER + 1]; @@ -514,14 +514,16 @@ EXTERNC struct _nla_table { SWORD tnd[203]; } nla_table; -EXTERNC _apu apu; -EXTERNC _r4011 r4011; -EXTERNC _r4015 r4015; -EXTERNC _r4017 r4017; -EXTERNC _apuSquare S1, S2; -EXTERNC _apuTriangle TR; -EXTERNC _apuNoise NS; -EXTERNC _apuDMC DMC; +EXTERNC struct NESAPU { + _apu apu; + _r4011 r4011; + _r4015 r4015; + _r4017 r4017; + _apuSquare S1, S2; + _apuTriangle TR; + _apuNoise NS; + _apuDMC DMC; +}; /* apuPeriod[mode][type][cycles] */ static const WORD apuPeriod[2][3][7] = { @@ -625,8 +627,8 @@ static const WORD dmc_rate[3][16] = { } }; -EXTERNC void apu_tick(BYTE *hwtick); -EXTERNC void apu_turn_on(void); +EXTERNC void apu_tick(struct NESAPU* a, BYTE *hwtick); +EXTERNC void apu_turn_on(struct NESAPU* a); #undef EXTERNC diff --git a/src/engine/platform/sound/nes/cpu_inline.h b/src/engine/platform/sound/nes/cpu_inline.h index 3cb85e82..665fa01e 100644 --- a/src/engine/platform/sound/nes/cpu_inline.h +++ b/src/engine/platform/sound/nes/cpu_inline.h @@ -38,27 +38,27 @@ r2006.value++;\ } -INLINE static void apu_wr_reg(WORD address, BYTE 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(S1); + square_reg0(a->S1); return; } if (address == 0x4001) { - square_reg1(S1); - sweep_silence(S1) + square_reg1(a->S1); + sweep_silence(a->S1) return; } if (address == 0x4002) { - square_reg2(S1); - sweep_silence(S1) + square_reg2(a->S1); + sweep_silence(a->S1) return; } if (address == 0x4003) { - square_reg3(S1); - sweep_silence(S1) + square_reg3(a->S1); + sweep_silence(a->S1) return; } return; @@ -66,22 +66,22 @@ INLINE static void apu_wr_reg(WORD address, BYTE value) { /* -------------------- square 2 --------------------*/ if (address <= 0x4007) { if (address == 0x4004) { - square_reg0(S2); + square_reg0(a->S2); return; } if (address == 0x4005) { - square_reg1(S2); - sweep_silence(S2) + square_reg1(a->S2); + sweep_silence(a->S2) return; } if (address == 0x4006) { - square_reg2(S2); - sweep_silence(S2) + square_reg2(a->S2); + sweep_silence(a->S2) return; } if (address == 0x4007) { - square_reg3(S2); - sweep_silence(S2) + square_reg3(a->S2); + sweep_silence(a->S2) return; } return; @@ -94,14 +94,14 @@ INLINE static void apu_wr_reg(WORD address, BYTE value) { * il triangle ha una posizione diversa per il * flag LCHalt. */ - TR.length.halt = value & 0x80; + a->TR.length.halt = value & 0x80; /* linear counter */ - TR.linear.reload = value & 0x7F; + a->TR.linear.reload = value & 0x7F; return; } if (address == 0x400A) { /* timer (low 8 bits) */ - TR.timer = (TR.timer & 0x0700) | value; + a->TR.timer = (a->TR.timer & 0x0700) | value; return; } if (address == 0x400B) { @@ -114,16 +114,16 @@ INLINE static void apu_wr_reg(WORD address, BYTE value) { * momento del clock di un length counter e * con il length diverso da zero. */ - if (TR.length.enabled && !(apu.length_clocked && TR.length.value)) { - TR.length.value = length_table[value >> 3]; + 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) */ - TR.timer = (TR.timer & 0x00FF) | ((value & 0x07) << 8); + a->TR.timer = (a->TR.timer & 0x00FF) | ((value & 0x07) << 8); /* * scrivendo in questo registro si setta * automaticamente l'halt flag del triangle. */ - TR.linear.halt = TRUE; + a->TR.linear.halt = TRUE; return; } return; @@ -131,15 +131,15 @@ INLINE static void apu_wr_reg(WORD address, BYTE value) { /* --------------------- noise ----------------------*/ if (address <= 0x400F) { if (address == 0x400C) { - NS.length.halt = value & 0x20; + a->NS.length.halt = value & 0x20; /* envelope */ - NS.envelope.constant_volume = value & 0x10; - NS.envelope.divider = value & 0x0F; + a->NS.envelope.constant_volume = value & 0x10; + a->NS.envelope.divider = value & 0x0F; return; } if (address == 0x400E) { - NS.mode = value & 0x80; - NS.timer = value & 0x0F; + a->NS.mode = value & 0x80; + a->NS.timer = value & 0x0F; return; } if (address == 0x400F) { @@ -151,11 +151,11 @@ INLINE static void apu_wr_reg(WORD address, BYTE value) { * momento del clock di un length counter e * con il length diverso da zero. */ - if (NS.length.enabled && !(apu.length_clocked && NS.length.value)) { - NS.length.value = length_table[value >> 3]; + if (a->NS.length.enabled && !(a->apu.length_clocked && a->NS.length.value)) { + a->NS.length.value = length_table[value >> 3]; } /* envelope */ - NS.envelope.enabled = TRUE; + a->NS.envelope.enabled = TRUE; return; } return; @@ -165,18 +165,18 @@ INLINE static void apu_wr_reg(WORD address, BYTE value) { /* ---------------------- DMC -----------------------*/ if (address <= 0x4013) { if (address == 0x4010) { - DMC.irq_enabled = value & 0x80; + a->DMC.irq_enabled = value & 0x80; /* se l'irq viene disabilitato allora... */ - if (!DMC.irq_enabled) { + if (!a->DMC.irq_enabled) { /* ...azzero l'interrupt flag del DMC */ - r4015.value &= 0x7F; + a->r4015.value &= 0x7F; } - DMC.loop = value & 0x40; - DMC.rate_index = value & 0x0F; + a->DMC.loop = value & 0x40; + a->DMC.rate_index = value & 0x0F; return; } if (address == 0x4011) { - BYTE save = DMC.counter; + BYTE save = a->DMC.counter; value &= 0x7F; @@ -193,25 +193,25 @@ INLINE static void apu_wr_reg(WORD address, BYTE value) { * emulated these filters. * (Xodnizel) */ - if (r4011.frames > 1) { - r4011.output = (value - save) >> 3; - DMC.counter = DMC.output = save + r4011.output; + if (a->r4011.frames > 1) { + a->r4011.output = (value - save) >> 3; + a->DMC.counter = a->DMC.output = save + a->r4011.output; } else { - DMC.counter = DMC.output = value; + a->DMC.counter = a->DMC.output = value; } - apu.clocked = TRUE; + a->apu.clocked = TRUE; - r4011.cycles = r4011.frames = 0; - r4011.value = value; + a->r4011.cycles = a->r4011.frames = 0; + a->r4011.value = value; return; } if (address == 0x4012) { - DMC.address_start = (value << 6) | 0xC000; + a->DMC.address_start = (value << 6) | 0xC000; return; } if (address == 0x4013) { /* sample length */ - DMC.length = (value << 4) | 0x01; + a->DMC.length = (value << 4) | 0x01; return; } return; @@ -236,23 +236,23 @@ INLINE static void apu_wr_reg(WORD address, BYTE value) { * essere azzerato mentre lascio inalterati * i bit 5 e 6. */ - r4015.value = (r4015.value & 0x60) | (value & 0x1F); + 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 (!(S1.length.enabled = r4015.value & 0x01)) { - S1.length.value = 0; + if (!(a->S1.length.enabled = a->r4015.value & 0x01)) { + a->S1.length.value = 0; } - if (!(S2.length.enabled = r4015.value & 0x02)) { - S2.length.value = 0; + if (!(a->S2.length.enabled = a->r4015.value & 0x02)) { + a->S2.length.value = 0; } - if (!(TR.length.enabled = r4015.value & 0x04)) { - TR.length.value = 0; + if (!(a->TR.length.enabled = a->r4015.value & 0x04)) { + a->TR.length.value = 0; } - if (!(NS.length.enabled = r4015.value & 0x08)) { - NS.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 @@ -260,12 +260,12 @@ INLINE static void apu_wr_reg(WORD address, BYTE value) { * la lettura dei sample DMC solo nel caso che * in cui i bytes rimanenti siano a 0. */ - if (!(r4015.value & 0x10)) { - DMC.remain = 0; - DMC.empty = TRUE; - } else if (!DMC.remain) { - DMC.remain = DMC.length; - DMC.address = DMC.address_start; + 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; } @@ -290,16 +290,16 @@ INLINE static void apu_wr_reg(WORD address, BYTE value) { #else if (address == 0x4017) { /* APU frame counter */ - r4017.jitter.value = value; + 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 (apu.odd_cycle) { - r4017.jitter.delay = TRUE; + if (a->apu.odd_cycle) { + a->r4017.jitter.delay = TRUE; } else { - r4017.jitter.delay = FALSE; + a->r4017.jitter.delay = FALSE; r4017_jitter(1) r4017_reset_frame() }