parent
06c7ac92a2
commit
e961cf79ca
|
@ -1,12 +1,13 @@
|
||||||
#include "nes.h"
|
#include "nes.h"
|
||||||
#include "sound/nes/cpu_inline.h"
|
#include "sound/nes/cpu_inline.h"
|
||||||
#include "../engine.h"
|
#include "../engine.h"
|
||||||
|
#include <cstddef>
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
|
|
||||||
#define FREQ_BASE 3424.0f
|
#define FREQ_BASE 3424.0f
|
||||||
#define FREQ_BASE_PAL 3180.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) {
|
void DivPlatformNES::acquire(short* bufL, short* bufR, size_t start, size_t len) {
|
||||||
for (size_t i=start; i<start+len; i++) {
|
for (size_t i=start; i<start+len; i++) {
|
||||||
|
@ -28,12 +29,12 @@ void DivPlatformNES::acquire(short* bufL, short* bufR, size_t start, size_t len)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
apu_tick(NULL);
|
apu_tick(nes,NULL);
|
||||||
apu.odd_cycle=!apu.odd_cycle;
|
nes->apu.odd_cycle=!nes->apu.odd_cycle;
|
||||||
if (apu.clocked) {
|
if (nes->apu.clocked) {
|
||||||
apu.clocked=false;
|
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;
|
dacSample=-1;
|
||||||
sampleBank=0;
|
sampleBank=0;
|
||||||
|
|
||||||
apu_turn_on();
|
apu_turn_on(nes);
|
||||||
apu.cpu_cycles=0;
|
nes->apu.cpu_cycles=0;
|
||||||
apu.cpu_opcode_cycle=0;
|
nes->apu.cpu_opcode_cycle=0;
|
||||||
|
|
||||||
rWrite(0x4015,(!isMuted[0])|((!isMuted[1])<<1)|((!isMuted[2])<<2)|((!isMuted[3])<<3)|((!isMuted[4])<<4));
|
rWrite(0x4015,(!isMuted[0])|((!isMuted[1])<<1)|((!isMuted[2])<<2)|((!isMuted[3])<<3)|((!isMuted[4])<<4));
|
||||||
rWrite(0x4001,0x08);
|
rWrite(0x4001,0x08);
|
||||||
|
@ -330,6 +331,7 @@ int DivPlatformNES::init(DivEngine* p, int channels, int sugRate, bool pal) {
|
||||||
isMuted[i]=false;
|
isMuted[i]=false;
|
||||||
}
|
}
|
||||||
setPAL(pal);
|
setPAL(pal);
|
||||||
|
nes=new struct NESAPU;
|
||||||
|
|
||||||
init_nla_table(500,500);
|
init_nla_table(500,500);
|
||||||
reset();
|
reset();
|
||||||
|
@ -337,6 +339,7 @@ int DivPlatformNES::init(DivEngine* p, int channels, int sugRate, bool pal) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void DivPlatformNES::quit() {
|
void DivPlatformNES::quit() {
|
||||||
|
delete nes;
|
||||||
}
|
}
|
||||||
|
|
||||||
DivPlatformNES::~DivPlatformNES() {
|
DivPlatformNES::~DivPlatformNES() {
|
||||||
|
|
|
@ -37,6 +37,7 @@ class DivPlatformNES: public DivDispatch {
|
||||||
unsigned int dacPos;
|
unsigned int dacPos;
|
||||||
int dacSample;
|
int dacSample;
|
||||||
unsigned char sampleBank;
|
unsigned char sampleBank;
|
||||||
|
struct NESAPU* nes;
|
||||||
|
|
||||||
float freqBase;
|
float freqBase;
|
||||||
|
|
||||||
|
|
|
@ -21,14 +21,14 @@
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include "apu.h"
|
#include "apu.h"
|
||||||
|
|
||||||
void apu_tick(BYTE *hwtick) {
|
void apu_tick(struct NESAPU* a, BYTE *hwtick) {
|
||||||
/* sottraggo il numero di cicli eseguiti */
|
/* sottraggo il numero di cicli eseguiti */
|
||||||
apu.cycles--;
|
a->apu.cycles--;
|
||||||
/*
|
/*
|
||||||
* questo flag sara' a TRUE solo nel ciclo
|
* questo flag sara' a TRUE solo nel ciclo
|
||||||
* in cui viene eseguito il length counter.
|
* in cui viene eseguito il length counter.
|
||||||
*/
|
*/
|
||||||
apu.length_clocked = FALSE;
|
a->apu.length_clocked = FALSE;
|
||||||
/*
|
/*
|
||||||
* se e' settato il delay del $4017, essendo
|
* se e' settato il delay del $4017, essendo
|
||||||
* questo il ciclo successivo, valorizzo il
|
* questo il ciclo successivo, valorizzo il
|
||||||
|
@ -40,22 +40,22 @@ void apu_tick(BYTE *hwtick) {
|
||||||
r4017_jitter();
|
r4017_jitter();
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
if (r4017.jitter.delay) {
|
if (a->r4017.jitter.delay) {
|
||||||
r4017.jitter.delay = FALSE;
|
a->r4017.jitter.delay = FALSE;
|
||||||
r4017_jitter(0)
|
r4017_jitter(0)
|
||||||
}
|
}
|
||||||
r4017_reset_frame()
|
r4017_reset_frame()
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* quando apu.cycles e' a 0 devo eseguire uno step */
|
/* quando apu.cycles e' a 0 devo eseguire uno step */
|
||||||
if (!apu.cycles) {
|
if (!a->apu.cycles) {
|
||||||
switch (apu.step) {
|
switch (a->apu.step) {
|
||||||
case 0:
|
case 0:
|
||||||
/*
|
/*
|
||||||
* nel mode 1 devo eseguire il
|
* nel mode 1 devo eseguire il
|
||||||
* length counter e lo sweep.
|
* length counter e lo sweep.
|
||||||
*/
|
*/
|
||||||
if (apu.mode == APU_48HZ) {
|
if (a->apu.mode == APU_48HZ) {
|
||||||
length_clock()
|
length_clock()
|
||||||
sweep_clock()
|
sweep_clock()
|
||||||
}
|
}
|
||||||
|
@ -63,11 +63,11 @@ void apu_tick(BYTE *hwtick) {
|
||||||
/* triangle's linear counter */
|
/* triangle's linear counter */
|
||||||
linear_clock()
|
linear_clock()
|
||||||
/* passo al prossimo step */
|
/* passo al prossimo step */
|
||||||
apu_change_step(++apu.step);
|
apu_change_step(++a->apu.step);
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
/* nel mode 0 devo eseguire il length counter */
|
/* nel mode 0 devo eseguire il length counter */
|
||||||
if (apu.mode == APU_60HZ) {
|
if (a->apu.mode == APU_60HZ) {
|
||||||
length_clock()
|
length_clock()
|
||||||
sweep_clock()
|
sweep_clock()
|
||||||
}
|
}
|
||||||
|
@ -75,14 +75,14 @@ void apu_tick(BYTE *hwtick) {
|
||||||
/* triangle's linear counter */
|
/* triangle's linear counter */
|
||||||
linear_clock()
|
linear_clock()
|
||||||
/* passo al prossimo step */
|
/* passo al prossimo step */
|
||||||
apu_change_step(++apu.step);
|
apu_change_step(++a->apu.step);
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
/*
|
/*
|
||||||
* nel mode 1 devo eseguire il
|
* nel mode 1 devo eseguire il
|
||||||
* length counter e lo sweep.
|
* length counter e lo sweep.
|
||||||
*/
|
*/
|
||||||
if (apu.mode == APU_48HZ) {
|
if (a->apu.mode == APU_48HZ) {
|
||||||
length_clock()
|
length_clock()
|
||||||
sweep_clock()
|
sweep_clock()
|
||||||
}
|
}
|
||||||
|
@ -90,21 +90,21 @@ void apu_tick(BYTE *hwtick) {
|
||||||
/* triangle's linear counter */
|
/* triangle's linear counter */
|
||||||
linear_clock()
|
linear_clock()
|
||||||
/* passo al prossimo step */
|
/* passo al prossimo step */
|
||||||
apu_change_step(++apu.step);
|
apu_change_step(++a->apu.step);
|
||||||
break;
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
/*
|
/*
|
||||||
* gli step 3, 4 e 5 settano il bit 6 del $4015
|
* gli step 3, 4 e 5 settano il bit 6 del $4015
|
||||||
* ma solo nel 4 genero un IRQ.
|
* 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
|
* se e' a 0 il bit 6 del $4017 (interrupt
|
||||||
* inhibit flag) allora devo generare un IRQ.
|
* inhibit flag) allora devo generare un IRQ.
|
||||||
*/
|
*/
|
||||||
if (!(r4017.value & 0x40)) {
|
if (!(a->r4017.value & 0x40)) {
|
||||||
/* setto il bit 6 del $4015 */
|
/* setto il bit 6 del $4015 */
|
||||||
r4015.value |= 0x40;
|
a->r4015.value |= 0x40;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
/* nel mode 1 devo eseguire l'envelope */
|
/* nel mode 1 devo eseguire l'envelope */
|
||||||
|
@ -113,14 +113,14 @@ void apu_tick(BYTE *hwtick) {
|
||||||
linear_clock()
|
linear_clock()
|
||||||
}
|
}
|
||||||
/* passo al prossimo step */
|
/* passo al prossimo step */
|
||||||
apu_change_step(++apu.step);
|
apu_change_step(++a->apu.step);
|
||||||
break;
|
break;
|
||||||
case 4:
|
case 4:
|
||||||
/*
|
/*
|
||||||
* gli step 3, 4 e 5 settano il bit 6 del $4015
|
* gli step 3, 4 e 5 settano il bit 6 del $4015
|
||||||
* ma solo nel 4 genero un IRQ.
|
* ma solo nel 4 genero un IRQ.
|
||||||
*/
|
*/
|
||||||
if (apu.mode == APU_60HZ) {
|
if (a->apu.mode == APU_60HZ) {
|
||||||
length_clock()
|
length_clock()
|
||||||
sweep_clock()
|
sweep_clock()
|
||||||
envelope_clock()
|
envelope_clock()
|
||||||
|
@ -130,35 +130,35 @@ void apu_tick(BYTE *hwtick) {
|
||||||
* se e' a 0 il bit 6 del $4017 (interrupt
|
* se e' a 0 il bit 6 del $4017 (interrupt
|
||||||
* inhibit flag) allora devo generare un IRQ.
|
* inhibit flag) allora devo generare un IRQ.
|
||||||
*/
|
*/
|
||||||
if (!(r4017.value & 0x40)) {
|
if (!(a->r4017.value & 0x40)) {
|
||||||
/* setto il bit 6 del $4015 */
|
/* setto il bit 6 del $4015 */
|
||||||
r4015.value |= 0x40;
|
a->r4015.value |= 0x40;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* passo al prossimo step */
|
/* passo al prossimo step */
|
||||||
apu_change_step(++apu.step);
|
apu_change_step(++a->apu.step);
|
||||||
break;
|
break;
|
||||||
case 5:
|
case 5:
|
||||||
/*
|
/*
|
||||||
* gli step 3, 4 e 5 settano il bit 6 del $4015
|
* gli step 3, 4 e 5 settano il bit 6 del $4015
|
||||||
* ma solo nel 4 genero un IRQ.
|
* 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
|
* se e' a 0 il bit 6 del $4017 (interrupt
|
||||||
* inhibit flag) allora devo generare un IRQ.
|
* inhibit flag) allora devo generare un IRQ.
|
||||||
*/
|
*/
|
||||||
if (!(r4017.value & 0x40)) {
|
if (!(a->r4017.value & 0x40)) {
|
||||||
/* setto il bit 6 del $4015 */
|
/* setto il bit 6 del $4015 */
|
||||||
r4015.value |= 0x40;
|
a->r4015.value |= 0x40;
|
||||||
}
|
}
|
||||||
apu.step++;
|
a->apu.step++;
|
||||||
} else {
|
} else {
|
||||||
/* nel mode 1 devo ricominciare il ciclo */
|
/* nel mode 1 devo ricominciare il ciclo */
|
||||||
apu.step = 0;
|
a->apu.step = 0;
|
||||||
}
|
}
|
||||||
/* passo al prossimo step */
|
/* passo al prossimo step */
|
||||||
apu_change_step(apu.step);
|
apu_change_step(a->apu.step);
|
||||||
break;
|
break;
|
||||||
case 6:
|
case 6:
|
||||||
/* da qui ci passo solo nel mode 0 */
|
/* da qui ci passo solo nel mode 0 */
|
||||||
|
@ -166,9 +166,9 @@ void apu_tick(BYTE *hwtick) {
|
||||||
/* triangle's linear counter */
|
/* triangle's linear counter */
|
||||||
linear_clock()
|
linear_clock()
|
||||||
/* questo e' il passaggio finale del mode 0 */
|
/* questo e' il passaggio finale del mode 0 */
|
||||||
apu.step = 1;
|
a->apu.step = 1;
|
||||||
/* passo al prossimo step */
|
/* passo al prossimo step */
|
||||||
apu_change_step(apu.step);
|
apu_change_step(a->apu.step);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -177,8 +177,8 @@ void apu_tick(BYTE *hwtick) {
|
||||||
* eseguo un ticket per ogni canale
|
* eseguo un ticket per ogni canale
|
||||||
* valorizzandone l'output.
|
* valorizzandone l'output.
|
||||||
*/
|
*/
|
||||||
square_tick(S1, 0, apu)
|
square_tick(a->S1, 0, a->apu)
|
||||||
square_tick(S2, 0, apu)
|
square_tick(a->S2, 0, a->apu)
|
||||||
triangle_tick()
|
triangle_tick()
|
||||||
noise_tick()
|
noise_tick()
|
||||||
dmc_tick()
|
dmc_tick()
|
||||||
|
@ -188,41 +188,41 @@ void apu_tick(BYTE *hwtick) {
|
||||||
snd_apu_tick();
|
snd_apu_tick();
|
||||||
}*/
|
}*/
|
||||||
|
|
||||||
r4011.cycles++;
|
a->r4011.cycles++;
|
||||||
}
|
}
|
||||||
void apu_turn_on(void) {
|
void apu_turn_on(struct NESAPU* a) {
|
||||||
memset(&apu, 0x00, sizeof(apu));
|
memset(&a->apu, 0x00, sizeof(a->apu));
|
||||||
memset(&r4015, 0x00, sizeof(r4015));
|
memset(&a->r4015, 0x00, sizeof(a->r4015));
|
||||||
memset(&r4017, 0x00, sizeof(r4017));
|
memset(&a->r4017, 0x00, sizeof(a->r4017));
|
||||||
/* azzero tutte le variabili interne dei canali */
|
/* azzero tutte le variabili interne dei canali */
|
||||||
memset(&S1, 0x00, sizeof(S1));
|
memset(&a->S1, 0x00, sizeof(a->S1));
|
||||||
memset(&S2, 0x00, sizeof(S2));
|
memset(&a->S2, 0x00, sizeof(a->S2));
|
||||||
memset(&TR, 0x00, sizeof(TR));
|
memset(&a->TR, 0x00, sizeof(a->TR));
|
||||||
memset(&NS, 0x00, sizeof(NS));
|
memset(&a->NS, 0x00, sizeof(a->NS));
|
||||||
memset(&DMC, 0x00, sizeof(DMC));
|
memset(&a->DMC, 0x00, sizeof(a->DMC));
|
||||||
/* al reset e' sempre settato a 60Hz */
|
/* al reset e' sempre settato a 60Hz */
|
||||||
apu.mode = APU_60HZ;
|
a->apu.mode = APU_60HZ;
|
||||||
apu.type = 0;
|
a->apu.type = 0;
|
||||||
apu_change_step(apu.step);
|
apu_change_step(a->apu.step);
|
||||||
/* valori iniziali dei vari canali */
|
/* valori iniziali dei vari canali */
|
||||||
S1.frequency = 1;
|
a->S1.frequency = 1;
|
||||||
S1.sweep.delay = 1;
|
a->S1.sweep.delay = 1;
|
||||||
S1.sweep.divider = 1;
|
a->S1.sweep.divider = 1;
|
||||||
S2.frequency = 1;
|
a->S2.frequency = 1;
|
||||||
S2.sweep.delay = 1;
|
a->S2.sweep.delay = 1;
|
||||||
S2.sweep.divider = 1;
|
a->S2.sweep.divider = 1;
|
||||||
TR.frequency = 1;
|
a->TR.frequency = 1;
|
||||||
TR.sequencer = 0;
|
a->TR.sequencer = 0;
|
||||||
NS.frequency = 1;
|
a->NS.frequency = 1;
|
||||||
NS.shift = 1;
|
a->NS.shift = 1;
|
||||||
DMC.frequency = 1;
|
a->DMC.frequency = 1;
|
||||||
DMC.empty = TRUE;
|
a->DMC.empty = TRUE;
|
||||||
DMC.silence = TRUE;
|
a->DMC.silence = TRUE;
|
||||||
DMC.counter_out = 8;
|
a->DMC.counter_out = 8;
|
||||||
// sembra che l'address del DMC al power on dia valorizzato a 0xC000
|
// sembra che l'address del DMC al power on dia valorizzato a 0xC000
|
||||||
// e la lunghezza del sample sia settato a 1 byte.
|
// e la lunghezza del sample sia settato a 1 byte.
|
||||||
// http://forums.nesdev.com/viewtopic.php?f=3&t=18278
|
// http://forums.nesdev.com/viewtopic.php?f=3&t=18278
|
||||||
DMC.length = 1;
|
a->DMC.length = 1;
|
||||||
DMC.address_start = 0xC000;
|
a->DMC.address_start = 0xC000;
|
||||||
apu.odd_cycle = 0;
|
a->apu.odd_cycle = 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,11 +39,11 @@ enum apu_mode { APU_60HZ, APU_48HZ };
|
||||||
channel.length.value--;\
|
channel.length.value--;\
|
||||||
}
|
}
|
||||||
#define length_clock()\
|
#define length_clock()\
|
||||||
apu.length_clocked = TRUE;\
|
a->apu.length_clocked = TRUE;\
|
||||||
length_run(S1)\
|
length_run(a->S1)\
|
||||||
length_run(S2)\
|
length_run(a->S2)\
|
||||||
length_run(TR)\
|
length_run(a->TR)\
|
||||||
length_run(NS)
|
length_run(a->NS)
|
||||||
/* envelope */
|
/* envelope */
|
||||||
#define envelope_run(channel)\
|
#define envelope_run(channel)\
|
||||||
if (channel.envelope.enabled) {\
|
if (channel.envelope.enabled) {\
|
||||||
|
@ -66,9 +66,9 @@ enum apu_mode { APU_60HZ, APU_48HZ };
|
||||||
channel.volume = channel.envelope.counter;\
|
channel.volume = channel.envelope.counter;\
|
||||||
}
|
}
|
||||||
#define envelope_clock()\
|
#define envelope_clock()\
|
||||||
envelope_run(S1)\
|
envelope_run(a->S1)\
|
||||||
envelope_run(S2)\
|
envelope_run(a->S2)\
|
||||||
envelope_run(NS)
|
envelope_run(a->NS)
|
||||||
/* sweep */
|
/* sweep */
|
||||||
#define sweep_run(channel, negative_adjust)\
|
#define sweep_run(channel, negative_adjust)\
|
||||||
if (!(--channel.sweep.delay)) {\
|
if (!(--channel.sweep.delay)) {\
|
||||||
|
@ -96,17 +96,17 @@ enum apu_mode { APU_60HZ, APU_48HZ };
|
||||||
}\
|
}\
|
||||||
}
|
}
|
||||||
#define sweep_clock()\
|
#define sweep_clock()\
|
||||||
sweep_run(S1, -1)\
|
sweep_run(a->S1, -1)\
|
||||||
sweep_run(S2, 0)
|
sweep_run(a->S2, 0)
|
||||||
/* linear counter */
|
/* linear counter */
|
||||||
#define linear_clock()\
|
#define linear_clock()\
|
||||||
if (TR.linear.halt) {\
|
if (a->TR.linear.halt) {\
|
||||||
TR.linear.value = TR.linear.reload;\
|
a->TR.linear.value = a->TR.linear.reload;\
|
||||||
} else if (TR.linear.value) {\
|
} else if (a->TR.linear.value) {\
|
||||||
TR.linear.value--;\
|
a->TR.linear.value--;\
|
||||||
}\
|
}\
|
||||||
if (!TR.length.halt) {\
|
if (!a->TR.length.halt) {\
|
||||||
TR.linear.halt = FALSE;\
|
a->TR.linear.halt = FALSE;\
|
||||||
}
|
}
|
||||||
/* output */
|
/* output */
|
||||||
#define square_output(square, swap)\
|
#define square_output(square, swap)\
|
||||||
|
@ -124,18 +124,18 @@ enum apu_mode { APU_60HZ, APU_48HZ };
|
||||||
* risultante e' troppo alta (oltre i 20 kHz,\
|
* risultante e' troppo alta (oltre i 20 kHz,\
|
||||||
* quindi non udibile), percio' la taglio.\
|
* quindi non udibile), percio' la taglio.\
|
||||||
*/\
|
*/\
|
||||||
TR.output = triangle_duty[TR.sequencer];\
|
a->TR.output = triangle_duty[a->TR.sequencer];\
|
||||||
if (TR.timer < 2) {\
|
if (a->TR.timer < 2) {\
|
||||||
TR.output = triangle_duty[8];\
|
a->TR.output = triangle_duty[8];\
|
||||||
}
|
}
|
||||||
#define noise_output()\
|
#define noise_output()\
|
||||||
envelope_volume(NS)\
|
envelope_volume(a->NS)\
|
||||||
NS.output = 0;\
|
a->NS.output = 0;\
|
||||||
if (NS.length.value && !(NS.shift & 0x0001)) {\
|
if (a->NS.length.value && !(a->NS.shift & 0x0001)) {\
|
||||||
NS.output = NS.volume;\
|
a->NS.output = a->NS.volume;\
|
||||||
}
|
}
|
||||||
#define dmc_output()\
|
#define dmc_output()\
|
||||||
DMC.output = DMC.counter & 0x7F
|
a->DMC.output = a->DMC.counter & 0x7F
|
||||||
/* tick */
|
/* tick */
|
||||||
#define square_tick(square, swap, type)\
|
#define square_tick(square, swap, type)\
|
||||||
if (!(--square.frequency)) {\
|
if (!(--square.frequency)) {\
|
||||||
|
@ -145,57 +145,57 @@ enum apu_mode { APU_60HZ, APU_48HZ };
|
||||||
type.clocked = TRUE;\
|
type.clocked = TRUE;\
|
||||||
}
|
}
|
||||||
#define triangle_tick()\
|
#define triangle_tick()\
|
||||||
if (!(--TR.frequency)) {\
|
if (!(--a->TR.frequency)) {\
|
||||||
TR.frequency = TR.timer + 1;\
|
a->TR.frequency = a->TR.timer + 1;\
|
||||||
if (TR.length.value && TR.linear.value) {\
|
if (a->TR.length.value && a->TR.linear.value) {\
|
||||||
TR.sequencer = (TR.sequencer + 1) & 0x1F;\
|
a->TR.sequencer = (a->TR.sequencer + 1) & 0x1F;\
|
||||||
triangle_output()\
|
triangle_output()\
|
||||||
apu.clocked = TRUE;\
|
a->apu.clocked = TRUE;\
|
||||||
}\
|
}\
|
||||||
}
|
}
|
||||||
#define noise_tick()\
|
#define noise_tick()\
|
||||||
if (!(--NS.frequency)) {\
|
if (!(--a->NS.frequency)) {\
|
||||||
if (NS.mode) {\
|
if (a->NS.mode) {\
|
||||||
NS.shift = (NS.shift >> 1) | (((NS.shift ^ (NS.shift >> 6)) & 0x0001) << 14);\
|
a->NS.shift = (a->NS.shift >> 1) | (((a->NS.shift ^ (a->NS.shift >> 6)) & 0x0001) << 14);\
|
||||||
} else {\
|
} 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()\
|
noise_output()\
|
||||||
NS.frequency = noise_timer[apu.type][NS.timer];\
|
a->NS.frequency = noise_timer[a->apu.type][a->NS.timer];\
|
||||||
apu.clocked = TRUE;\
|
a->apu.clocked = TRUE;\
|
||||||
}
|
}
|
||||||
#define dmc_tick()\
|
#define dmc_tick()\
|
||||||
if (!(--DMC.frequency)) {\
|
if (!(--a->DMC.frequency)) {\
|
||||||
if (!DMC.silence) {\
|
if (!a->DMC.silence) {\
|
||||||
if (!(DMC.shift & 0x01)) {\
|
if (!(a->DMC.shift & 0x01)) {\
|
||||||
if (DMC.counter > 1) {\
|
if (a->DMC.counter > 1) {\
|
||||||
DMC.counter -= 2;\
|
a->DMC.counter -= 2;\
|
||||||
}\
|
}\
|
||||||
} else {\
|
} else {\
|
||||||
if (DMC.counter < 126) {\
|
if (a->DMC.counter < 126) {\
|
||||||
DMC.counter += 2;\
|
a->DMC.counter += 2;\
|
||||||
}\
|
}\
|
||||||
}\
|
}\
|
||||||
}\
|
}\
|
||||||
DMC.shift >>= 1;\
|
a->DMC.shift >>= 1;\
|
||||||
dmc_output();\
|
dmc_output();\
|
||||||
if (!(--DMC.counter_out)) {\
|
if (!(--a->DMC.counter_out)) {\
|
||||||
DMC.counter_out = 8;\
|
a->DMC.counter_out = 8;\
|
||||||
if (!DMC.empty) {\
|
if (!a->DMC.empty) {\
|
||||||
DMC.shift = DMC.buffer;\
|
a->DMC.shift = a->DMC.buffer;\
|
||||||
DMC.empty = TRUE;\
|
a->DMC.empty = TRUE;\
|
||||||
DMC.silence = FALSE;\
|
a->DMC.silence = FALSE;\
|
||||||
} else {\
|
} else {\
|
||||||
DMC.silence = TRUE;\
|
a->DMC.silence = TRUE;\
|
||||||
}\
|
}\
|
||||||
}\
|
}\
|
||||||
DMC.frequency = dmc_rate[apu.type][DMC.rate_index];\
|
a->DMC.frequency = dmc_rate[a->apu.type][a->DMC.rate_index];\
|
||||||
apu.clocked = TRUE;\
|
a->apu.clocked = TRUE;\
|
||||||
}\
|
}\
|
||||||
if (DMC.empty && DMC.remain) {\
|
if (a->DMC.empty && a->DMC.remain) {\
|
||||||
BYTE tick = 4;\
|
BYTE tick = 4;\
|
||||||
switch (DMC.tick_type) {\
|
switch (a->DMC.tick_type) {\
|
||||||
case DMC_CPU_WRITE:\
|
case DMC_CPU_WRITE:\
|
||||||
tick = 3;\
|
tick = 3;\
|
||||||
break;\
|
break;\
|
||||||
|
@ -207,81 +207,81 @@ enum apu_mode { APU_60HZ, APU_48HZ };
|
||||||
break;\
|
break;\
|
||||||
}\
|
}\
|
||||||
{\
|
{\
|
||||||
DMC.buffer = 0;\
|
a->DMC.buffer = 0;\
|
||||||
}\
|
}\
|
||||||
/* incremento gli hwtick da compiere */\
|
/* incremento gli hwtick da compiere */\
|
||||||
if (hwtick) { hwtick[0] += tick; }\
|
if (hwtick) { hwtick[0] += tick; }\
|
||||||
/* e naturalmente incremento anche quelli eseguiti dall'opcode */\
|
/* 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 */\
|
/* 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 */\
|
/* il DMC non e' vuoto */\
|
||||||
DMC.empty = FALSE;\
|
a->DMC.empty = FALSE;\
|
||||||
if (++DMC.address > 0xFFFF) {\
|
if (++a->DMC.address > 0xFFFF) {\
|
||||||
DMC.address = 0x8000;\
|
a->DMC.address = 0x8000;\
|
||||||
}\
|
}\
|
||||||
if (!(--DMC.remain)) {\
|
if (!(--a->DMC.remain)) {\
|
||||||
if (DMC.loop) {\
|
if (a->DMC.loop) {\
|
||||||
DMC.remain = DMC.length;\
|
a->DMC.remain = a->DMC.length;\
|
||||||
DMC.address = DMC.address_start;\
|
a->DMC.address = a->DMC.address_start;\
|
||||||
} else if (DMC.irq_enabled) {\
|
} else if (a->DMC.irq_enabled) {\
|
||||||
r4015.value |= 0x80;\
|
a->r4015.value |= 0x80;\
|
||||||
}\
|
}\
|
||||||
}\
|
}\
|
||||||
}
|
}
|
||||||
|
|
||||||
#define apu_change_step(index)\
|
#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)
|
#if defined (VECCHIA_GESTIONE_JITTER)
|
||||||
#define r4017_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\
|
* se il bit 7 e' a zero, devo attivare la\
|
||||||
* modalita' NTSC, se a uno quella PAL.\
|
* modalita' NTSC, se a uno quella PAL.\
|
||||||
*/\
|
*/\
|
||||||
if (r4017.value & 0x80) {\
|
if (a->r4017.value & 0x80) {\
|
||||||
apu.mode = APU_48HZ;\
|
a->apu.mode = APU_48HZ;\
|
||||||
} else {\
|
} 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 */\
|
/* azzero il bit 6 del $4015 */\
|
||||||
r4015.value &= 0xBF;\
|
a->r4015.value &= 0xBF;\
|
||||||
/* questo non e' affatto necessario sul forno */\
|
/* questo non e' affatto necessario sul forno */\
|
||||||
}\
|
}\
|
||||||
/* riavvio il frame audio */\
|
/* riavvio il frame audio */\
|
||||||
apu.step = apu.cycles = 0;\
|
a->apu.step = a->apu.cycles = 0;\
|
||||||
apu_change_step(apu.step)
|
apu_change_step(a->apu.step)
|
||||||
#else
|
#else
|
||||||
#define r4017_jitter(apc)\
|
#define r4017_jitter(apc)\
|
||||||
r4017.value = (r4017.jitter.value & 0xC0);\
|
a->r4017.value = (a->r4017.jitter.value & 0xC0);\
|
||||||
r4017.reset_frame_delay = 1;\
|
a->r4017.reset_frame_delay = 1;\
|
||||||
if (apu.cycles == apc) {\
|
if (a->apu.cycles == apc) {\
|
||||||
if (apu.mode == APU_48HZ) {\
|
if (a->apu.mode == APU_48HZ) {\
|
||||||
r4017.reset_frame_delay += 1;\
|
a->r4017.reset_frame_delay += 1;\
|
||||||
} else {\
|
} else {\
|
||||||
r4017.reset_frame_delay += 2;\
|
a->r4017.reset_frame_delay += 2;\
|
||||||
}\
|
}\
|
||||||
}\
|
}\
|
||||||
/*\
|
/*\
|
||||||
* se il bit 7 e' a zero, devo attivare la\
|
* se il bit 7 e' a zero, devo attivare la\
|
||||||
* modalita' NTSC, se a uno quella PAL.\
|
* modalita' NTSC, se a uno quella PAL.\
|
||||||
*/\
|
*/\
|
||||||
if (r4017.value & 0x80) {\
|
if (a->r4017.value & 0x80) {\
|
||||||
apu.mode = APU_48HZ;\
|
a->apu.mode = APU_48HZ;\
|
||||||
} else {\
|
} 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 */\
|
/* azzero il bit 6 del $4015 */\
|
||||||
r4015.value &= 0xBF;\
|
a->r4015.value &= 0xBF;\
|
||||||
/* questo non e' affatto necessario sul forno */\
|
/* questo non e' affatto necessario sul forno */\
|
||||||
}
|
}
|
||||||
#define r4017_reset_frame()\
|
#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 */\
|
/* riavvio il frame audio */\
|
||||||
apu.step = apu.cycles = 0;\
|
a->apu.step = a->apu.cycles = 0;\
|
||||||
apu_change_step(apu.step);\
|
apu_change_step(a->apu.step);\
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
#define square_reg0(square)\
|
#define square_reg0(square)\
|
||||||
|
@ -312,7 +312,7 @@ enum apu_mode { APU_60HZ, APU_48HZ };
|
||||||
* momento del clock di un length counter e\
|
* momento del clock di un length counter e\
|
||||||
* con il length diverso da zero.\
|
* 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];\
|
square.length.value = length_table[value >> 3];\
|
||||||
}\
|
}\
|
||||||
/* envelope */\
|
/* envelope */\
|
||||||
|
@ -337,22 +337,22 @@ enum apu_mode { APU_60HZ, APU_48HZ };
|
||||||
}
|
}
|
||||||
#define _apu_channel_volume_adjust(ch, index)\
|
#define _apu_channel_volume_adjust(ch, index)\
|
||||||
((ch))
|
((ch))
|
||||||
#define s1_out\
|
#define s1_out(a)\
|
||||||
_apu_channel_volume_adjust(S1.output, APU_S1)
|
_apu_channel_volume_adjust(a->S1.output, APU_S1)
|
||||||
#define s2_out\
|
#define s2_out(a)\
|
||||||
_apu_channel_volume_adjust(S2.output, APU_S2)
|
_apu_channel_volume_adjust(a->S2.output, APU_S2)
|
||||||
#define tr_out\
|
#define tr_out(a)\
|
||||||
_apu_channel_volume_adjust(TR.output, APU_TR)
|
_apu_channel_volume_adjust(a->TR.output, APU_TR)
|
||||||
#define ns_out\
|
#define ns_out(a)\
|
||||||
_apu_channel_volume_adjust(NS.output, APU_NS)
|
_apu_channel_volume_adjust(a->NS.output, APU_NS)
|
||||||
#define dmc_out\
|
#define dmc_out(a)\
|
||||||
_apu_channel_volume_adjust(DMC.output, APU_DMC)
|
_apu_channel_volume_adjust(a->DMC.output, APU_DMC)
|
||||||
#define extra_out(ch)\
|
#define extra_out(ch)\
|
||||||
(ch * cfg->apu.channel[APU_EXTRA])
|
(ch * cfg->apu.channel[APU_EXTRA])
|
||||||
#define pulse_output()\
|
#define pulse_output(a)\
|
||||||
nla_table.pulse[(int) (s1_out + s2_out)]
|
nla_table.pulse[(int) (s1_out(a) + s2_out(a))]
|
||||||
#define tnd_output()\
|
#define tnd_output(a)\
|
||||||
nla_table.tnd[(int) ((tr_out * 3) + (ns_out * 2) + dmc_out)]
|
nla_table.tnd[(int) ((tr_out(a) * 3) + (ns_out(a) * 2) + dmc_out(a))]
|
||||||
|
|
||||||
typedef struct _config_apu {
|
typedef struct _config_apu {
|
||||||
BYTE channel[APU_MASTER + 1];
|
BYTE channel[APU_MASTER + 1];
|
||||||
|
@ -514,14 +514,16 @@ EXTERNC struct _nla_table {
|
||||||
SWORD tnd[203];
|
SWORD tnd[203];
|
||||||
} nla_table;
|
} nla_table;
|
||||||
|
|
||||||
EXTERNC _apu apu;
|
EXTERNC struct NESAPU {
|
||||||
EXTERNC _r4011 r4011;
|
_apu apu;
|
||||||
EXTERNC _r4015 r4015;
|
_r4011 r4011;
|
||||||
EXTERNC _r4017 r4017;
|
_r4015 r4015;
|
||||||
EXTERNC _apuSquare S1, S2;
|
_r4017 r4017;
|
||||||
EXTERNC _apuTriangle TR;
|
_apuSquare S1, S2;
|
||||||
EXTERNC _apuNoise NS;
|
_apuTriangle TR;
|
||||||
EXTERNC _apuDMC DMC;
|
_apuNoise NS;
|
||||||
|
_apuDMC DMC;
|
||||||
|
};
|
||||||
|
|
||||||
/* apuPeriod[mode][type][cycles] */
|
/* apuPeriod[mode][type][cycles] */
|
||||||
static const WORD apuPeriod[2][3][7] = {
|
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_tick(struct NESAPU* a, BYTE *hwtick);
|
||||||
EXTERNC void apu_turn_on(void);
|
EXTERNC void apu_turn_on(struct NESAPU* a);
|
||||||
|
|
||||||
#undef EXTERNC
|
#undef EXTERNC
|
||||||
|
|
||||||
|
|
|
@ -38,27 +38,27 @@
|
||||||
r2006.value++;\
|
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)) {
|
if (!(address & 0x0010)) {
|
||||||
/* -------------------- square 1 --------------------*/
|
/* -------------------- square 1 --------------------*/
|
||||||
if (address <= 0x4003) {
|
if (address <= 0x4003) {
|
||||||
if (address == 0x4000) {
|
if (address == 0x4000) {
|
||||||
square_reg0(S1);
|
square_reg0(a->S1);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (address == 0x4001) {
|
if (address == 0x4001) {
|
||||||
square_reg1(S1);
|
square_reg1(a->S1);
|
||||||
sweep_silence(S1)
|
sweep_silence(a->S1)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (address == 0x4002) {
|
if (address == 0x4002) {
|
||||||
square_reg2(S1);
|
square_reg2(a->S1);
|
||||||
sweep_silence(S1)
|
sweep_silence(a->S1)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (address == 0x4003) {
|
if (address == 0x4003) {
|
||||||
square_reg3(S1);
|
square_reg3(a->S1);
|
||||||
sweep_silence(S1)
|
sweep_silence(a->S1)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
|
@ -66,22 +66,22 @@ INLINE static void apu_wr_reg(WORD address, BYTE value) {
|
||||||
/* -------------------- square 2 --------------------*/
|
/* -------------------- square 2 --------------------*/
|
||||||
if (address <= 0x4007) {
|
if (address <= 0x4007) {
|
||||||
if (address == 0x4004) {
|
if (address == 0x4004) {
|
||||||
square_reg0(S2);
|
square_reg0(a->S2);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (address == 0x4005) {
|
if (address == 0x4005) {
|
||||||
square_reg1(S2);
|
square_reg1(a->S2);
|
||||||
sweep_silence(S2)
|
sweep_silence(a->S2)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (address == 0x4006) {
|
if (address == 0x4006) {
|
||||||
square_reg2(S2);
|
square_reg2(a->S2);
|
||||||
sweep_silence(S2)
|
sweep_silence(a->S2)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (address == 0x4007) {
|
if (address == 0x4007) {
|
||||||
square_reg3(S2);
|
square_reg3(a->S2);
|
||||||
sweep_silence(S2)
|
sweep_silence(a->S2)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
|
@ -94,14 +94,14 @@ INLINE static void apu_wr_reg(WORD address, BYTE value) {
|
||||||
* il triangle ha una posizione diversa per il
|
* il triangle ha una posizione diversa per il
|
||||||
* flag LCHalt.
|
* flag LCHalt.
|
||||||
*/
|
*/
|
||||||
TR.length.halt = value & 0x80;
|
a->TR.length.halt = value & 0x80;
|
||||||
/* linear counter */
|
/* linear counter */
|
||||||
TR.linear.reload = value & 0x7F;
|
a->TR.linear.reload = value & 0x7F;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (address == 0x400A) {
|
if (address == 0x400A) {
|
||||||
/* timer (low 8 bits) */
|
/* timer (low 8 bits) */
|
||||||
TR.timer = (TR.timer & 0x0700) | value;
|
a->TR.timer = (a->TR.timer & 0x0700) | value;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (address == 0x400B) {
|
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
|
* momento del clock di un length counter e
|
||||||
* con il length diverso da zero.
|
* con il length diverso da zero.
|
||||||
*/
|
*/
|
||||||
if (TR.length.enabled && !(apu.length_clocked && TR.length.value)) {
|
if (a->TR.length.enabled && !(a->apu.length_clocked && a->TR.length.value)) {
|
||||||
TR.length.value = length_table[value >> 3];
|
a->TR.length.value = length_table[value >> 3];
|
||||||
}
|
}
|
||||||
/* timer (high 3 bits) */
|
/* 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
|
* scrivendo in questo registro si setta
|
||||||
* automaticamente l'halt flag del triangle.
|
* automaticamente l'halt flag del triangle.
|
||||||
*/
|
*/
|
||||||
TR.linear.halt = TRUE;
|
a->TR.linear.halt = TRUE;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
|
@ -131,15 +131,15 @@ INLINE static void apu_wr_reg(WORD address, BYTE value) {
|
||||||
/* --------------------- noise ----------------------*/
|
/* --------------------- noise ----------------------*/
|
||||||
if (address <= 0x400F) {
|
if (address <= 0x400F) {
|
||||||
if (address == 0x400C) {
|
if (address == 0x400C) {
|
||||||
NS.length.halt = value & 0x20;
|
a->NS.length.halt = value & 0x20;
|
||||||
/* envelope */
|
/* envelope */
|
||||||
NS.envelope.constant_volume = value & 0x10;
|
a->NS.envelope.constant_volume = value & 0x10;
|
||||||
NS.envelope.divider = value & 0x0F;
|
a->NS.envelope.divider = value & 0x0F;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (address == 0x400E) {
|
if (address == 0x400E) {
|
||||||
NS.mode = value & 0x80;
|
a->NS.mode = value & 0x80;
|
||||||
NS.timer = value & 0x0F;
|
a->NS.timer = value & 0x0F;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (address == 0x400F) {
|
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
|
* momento del clock di un length counter e
|
||||||
* con il length diverso da zero.
|
* con il length diverso da zero.
|
||||||
*/
|
*/
|
||||||
if (NS.length.enabled && !(apu.length_clocked && NS.length.value)) {
|
if (a->NS.length.enabled && !(a->apu.length_clocked && a->NS.length.value)) {
|
||||||
NS.length.value = length_table[value >> 3];
|
a->NS.length.value = length_table[value >> 3];
|
||||||
}
|
}
|
||||||
/* envelope */
|
/* envelope */
|
||||||
NS.envelope.enabled = TRUE;
|
a->NS.envelope.enabled = TRUE;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
|
@ -165,18 +165,18 @@ INLINE static void apu_wr_reg(WORD address, BYTE value) {
|
||||||
/* ---------------------- DMC -----------------------*/
|
/* ---------------------- DMC -----------------------*/
|
||||||
if (address <= 0x4013) {
|
if (address <= 0x4013) {
|
||||||
if (address == 0x4010) {
|
if (address == 0x4010) {
|
||||||
DMC.irq_enabled = value & 0x80;
|
a->DMC.irq_enabled = value & 0x80;
|
||||||
/* se l'irq viene disabilitato allora... */
|
/* se l'irq viene disabilitato allora... */
|
||||||
if (!DMC.irq_enabled) {
|
if (!a->DMC.irq_enabled) {
|
||||||
/* ...azzero l'interrupt flag del DMC */
|
/* ...azzero l'interrupt flag del DMC */
|
||||||
r4015.value &= 0x7F;
|
a->r4015.value &= 0x7F;
|
||||||
}
|
}
|
||||||
DMC.loop = value & 0x40;
|
a->DMC.loop = value & 0x40;
|
||||||
DMC.rate_index = value & 0x0F;
|
a->DMC.rate_index = value & 0x0F;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (address == 0x4011) {
|
if (address == 0x4011) {
|
||||||
BYTE save = DMC.counter;
|
BYTE save = a->DMC.counter;
|
||||||
|
|
||||||
value &= 0x7F;
|
value &= 0x7F;
|
||||||
|
|
||||||
|
@ -193,25 +193,25 @@ INLINE static void apu_wr_reg(WORD address, BYTE value) {
|
||||||
* emulated these filters.
|
* emulated these filters.
|
||||||
* (Xodnizel)
|
* (Xodnizel)
|
||||||
*/
|
*/
|
||||||
if (r4011.frames > 1) {
|
if (a->r4011.frames > 1) {
|
||||||
r4011.output = (value - save) >> 3;
|
a->r4011.output = (value - save) >> 3;
|
||||||
DMC.counter = DMC.output = save + r4011.output;
|
a->DMC.counter = a->DMC.output = save + a->r4011.output;
|
||||||
} else {
|
} 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;
|
a->r4011.cycles = a->r4011.frames = 0;
|
||||||
r4011.value = value;
|
a->r4011.value = value;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (address == 0x4012) {
|
if (address == 0x4012) {
|
||||||
DMC.address_start = (value << 6) | 0xC000;
|
a->DMC.address_start = (value << 6) | 0xC000;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (address == 0x4013) {
|
if (address == 0x4013) {
|
||||||
/* sample length */
|
/* sample length */
|
||||||
DMC.length = (value << 4) | 0x01;
|
a->DMC.length = (value << 4) | 0x01;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
|
@ -236,23 +236,23 @@ INLINE static void apu_wr_reg(WORD address, BYTE value) {
|
||||||
* essere azzerato mentre lascio inalterati
|
* essere azzerato mentre lascio inalterati
|
||||||
* i bit 5 e 6.
|
* 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
|
* quando il flag di abilitazione del length
|
||||||
* counter di ogni canale e' a 0, il counter
|
* counter di ogni canale e' a 0, il counter
|
||||||
* dello stesso canale e' immediatamente azzerato.
|
* dello stesso canale e' immediatamente azzerato.
|
||||||
*/
|
*/
|
||||||
if (!(S1.length.enabled = r4015.value & 0x01)) {
|
if (!(a->S1.length.enabled = a->r4015.value & 0x01)) {
|
||||||
S1.length.value = 0;
|
a->S1.length.value = 0;
|
||||||
}
|
}
|
||||||
if (!(S2.length.enabled = r4015.value & 0x02)) {
|
if (!(a->S2.length.enabled = a->r4015.value & 0x02)) {
|
||||||
S2.length.value = 0;
|
a->S2.length.value = 0;
|
||||||
}
|
}
|
||||||
if (!(TR.length.enabled = r4015.value & 0x04)) {
|
if (!(a->TR.length.enabled = a->r4015.value & 0x04)) {
|
||||||
TR.length.value = 0;
|
a->TR.length.value = 0;
|
||||||
}
|
}
|
||||||
if (!(NS.length.enabled = r4015.value & 0x08)) {
|
if (!(a->NS.length.enabled = a->r4015.value & 0x08)) {
|
||||||
NS.length.value = 0;
|
a->NS.length.value = 0;
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
* se il bit 4 e' 0 allora devo azzerare i bytes
|
* 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
|
* la lettura dei sample DMC solo nel caso che
|
||||||
* in cui i bytes rimanenti siano a 0.
|
* in cui i bytes rimanenti siano a 0.
|
||||||
*/
|
*/
|
||||||
if (!(r4015.value & 0x10)) {
|
if (!(a->r4015.value & 0x10)) {
|
||||||
DMC.remain = 0;
|
a->DMC.remain = 0;
|
||||||
DMC.empty = TRUE;
|
a->DMC.empty = TRUE;
|
||||||
} else if (!DMC.remain) {
|
} else if (!a->DMC.remain) {
|
||||||
DMC.remain = DMC.length;
|
a->DMC.remain = a->DMC.length;
|
||||||
DMC.address = DMC.address_start;
|
a->DMC.address = a->DMC.address_start;
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -290,16 +290,16 @@ INLINE static void apu_wr_reg(WORD address, BYTE value) {
|
||||||
#else
|
#else
|
||||||
if (address == 0x4017) {
|
if (address == 0x4017) {
|
||||||
/* APU frame counter */
|
/* APU frame counter */
|
||||||
r4017.jitter.value = value;
|
a->r4017.jitter.value = value;
|
||||||
/*
|
/*
|
||||||
* nell'2A03 se la scrittura del $4017 avviene
|
* nell'2A03 se la scrittura del $4017 avviene
|
||||||
* in un ciclo pari, allora l'effettiva modifica
|
* in un ciclo pari, allora l'effettiva modifica
|
||||||
* avverra' nel ciclo successivo.
|
* avverra' nel ciclo successivo.
|
||||||
*/
|
*/
|
||||||
if (apu.odd_cycle) {
|
if (a->apu.odd_cycle) {
|
||||||
r4017.jitter.delay = TRUE;
|
a->r4017.jitter.delay = TRUE;
|
||||||
} else {
|
} else {
|
||||||
r4017.jitter.delay = FALSE;
|
a->r4017.jitter.delay = FALSE;
|
||||||
r4017_jitter(1)
|
r4017_jitter(1)
|
||||||
r4017_reset_frame()
|
r4017_reset_frame()
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue