mirror of
https://github.com/libretro/fixNES.git
synced 2025-03-01 06:45:47 +00:00
-made a couple changes to the sound code
-added support for mappers 21,22,23,24,25 and 26
This commit is contained in:
parent
0df3532ebe
commit
96705272f8
@ -3,7 +3,7 @@ This is yet another NES Emulator which was written so I can learn about the NES,
|
||||
If you want to check it out for some reason I do include a windows binary in the "Releases" tab, if you want to compile it go check out the "build" files.
|
||||
You will need freeglut as well as openal-soft to compile the project, it should run on most systems since it is fairly generic C code.
|
||||
NTSC and PAL .nes ROMs are supported right now, it also creates .sav files if the chosen game supports saving.
|
||||
Supported Mappers: 0,1,2,3,4,7,9,10,11,13,15,36,37,38,44,46,47,66,71,79,87,99,101,113,133,140,144,145,146,147,148,149,185,240 and 242.
|
||||
Supported Mappers: 0,1,2,3,4,7,9,10,11,13,15,21,22,23,24,25,26,36,37,38,44,46,47,66,71,79,87,99,101,113,133,140,144,145,146,147,148,149,185,240 and 242.
|
||||
To start a game, simply drag and drop its .nes file into it or call it via command line with the .nes file as argument.
|
||||
If you are starting a PAL NES title then make sure it has (E) in the name to be started in PAL mode.
|
||||
You can also play FDS titles if you have the FDS BIOS named disksys.rom in the same folder as your .fds files.
|
||||
|
216
apu.c
216
apu.c
@ -53,9 +53,10 @@ static uint8_t triLengthCtr, triLinearCtr, triCurLinearCtr;
|
||||
static uint8_t dmcVol, dmcCurVol;
|
||||
static uint8_t dmcSampleRemain;
|
||||
static bool mode5 = false;
|
||||
static int modePos = 0;
|
||||
static uint8_t modePos = 0;
|
||||
static uint16_t modeCurCtr = 0;
|
||||
static uint16_t p1freqCtr, p2freqCtr, triFreqCtr, noiseFreqCtr, dmcFreqCtr;
|
||||
static uint8_t p1Cycle, p2Cycle, triCycle;//, dmcCycle;
|
||||
static uint8_t p1Cycle, p2Cycle, triCycle;
|
||||
static bool p1haltloop, p2haltloop, trihaltloop, noisehaltloop, dmchaltloop;
|
||||
static bool dmcstart;
|
||||
static bool dmcirqenable;
|
||||
@ -116,8 +117,25 @@ static const uint16_t dmcPeriodPal[16] = {
|
||||
398, 354, 316, 298, 276, 236, 210, 198, 176, 148, 132, 118, 98, 78, 66, 50,
|
||||
};
|
||||
|
||||
static const uint16_t mode4CtrNtsc[4] = {
|
||||
7456, 7458, 7458, 7458
|
||||
};
|
||||
|
||||
static const uint16_t mode4CtrPal[4] = {
|
||||
8314, 8312, 8314, 8314
|
||||
};
|
||||
|
||||
static const uint16_t mode5CtrNtsc[5] = {
|
||||
7458, 7456, 7458, 7458, 7452
|
||||
};
|
||||
|
||||
static const uint16_t mode5CtrPal[5] = {
|
||||
8314, 8314, 8312, 8314, 8312
|
||||
};
|
||||
|
||||
//used externally
|
||||
const uint16_t *dmcPeriod, *noisePeriod;
|
||||
const uint16_t *mode4Ctr, *mode5Ctr;
|
||||
|
||||
static const uint8_t *p1seq = pulseSeqs[0],
|
||||
*p2seq = pulseSeqs[1];
|
||||
@ -130,6 +148,8 @@ void apuInitBufs()
|
||||
{
|
||||
noisePeriod = nesPAL ? noisePeriodPal : noisePeriodNtsc;
|
||||
dmcPeriod = nesPAL ? dmcPeriodPal : dmcPeriodNtsc;
|
||||
mode4Ctr = nesPAL ? mode4CtrPal : mode4CtrNtsc;
|
||||
mode5Ctr = nesPAL ? mode5CtrPal : mode5CtrNtsc;
|
||||
//effective frequencies for 50.000Hz and 60.000Hz Video out
|
||||
apuFrequency = nesPAL ? 831187 : 893415;
|
||||
double dt = 1.0/((double)apuFrequency);
|
||||
@ -175,7 +195,7 @@ void apuInit()
|
||||
dmcCurAddr = 0, dmcCurLen = 0; dmcCurVol = 0;
|
||||
dmcSampleRemain = 0;
|
||||
p1freqCtr = 0; p2freqCtr = 0; triFreqCtr = 0, noiseFreqCtr = 0, dmcFreqCtr = 0;
|
||||
p1Cycle = 0; p2Cycle = 0; triCycle = 0;// dmcCycle = 0;
|
||||
p1Cycle = 0; p2Cycle = 0; triCycle = 0;
|
||||
|
||||
memset(&p1Env,0,sizeof(envelope_t));
|
||||
memset(&p2Env,0,sizeof(envelope_t));
|
||||
@ -199,104 +219,91 @@ void apuInit()
|
||||
extern uint32_t cpu_oam_dma;
|
||||
void apuClockTimers()
|
||||
{
|
||||
if(p1LengthCtr && (APU_IO_Reg[0x15] & P1_ENABLE))
|
||||
if(p1freqCtr)
|
||||
p1freqCtr--;
|
||||
if(p1freqCtr == 0)
|
||||
{
|
||||
if(p1freqCtr)
|
||||
p1freqCtr--;
|
||||
if(p1freqCtr == 0)
|
||||
{
|
||||
p1freqCtr = (freq1+1)*2;
|
||||
p1Cycle++;
|
||||
}
|
||||
p1freqCtr = (freq1+1)*2;
|
||||
p1Cycle++;
|
||||
if(p1Cycle >= 8)
|
||||
p1Cycle = 0;
|
||||
}
|
||||
if(p2LengthCtr && (APU_IO_Reg[0x15] & P2_ENABLE))
|
||||
|
||||
if(p2freqCtr)
|
||||
p2freqCtr--;
|
||||
if(p2freqCtr == 0)
|
||||
{
|
||||
if(p2freqCtr)
|
||||
p2freqCtr--;
|
||||
if(p2freqCtr == 0)
|
||||
{
|
||||
p2freqCtr = (freq2+1)*2;
|
||||
p2Cycle++;
|
||||
}
|
||||
p2freqCtr = (freq2+1)*2;
|
||||
p2Cycle++;
|
||||
if(p2Cycle >= 8)
|
||||
p2Cycle = 0;
|
||||
}
|
||||
if(triLengthCtr && triCurLinearCtr && (APU_IO_Reg[0x15] & TRI_ENABLE))
|
||||
|
||||
if(triFreqCtr)
|
||||
triFreqCtr--;
|
||||
if(triFreqCtr == 0)
|
||||
{
|
||||
if(triFreqCtr)
|
||||
triFreqCtr--;
|
||||
if(triFreqCtr == 0)
|
||||
{
|
||||
triFreqCtr = triFreq+1;
|
||||
triCycle++;
|
||||
}
|
||||
triFreqCtr = triFreq+1;
|
||||
triCycle++;
|
||||
if(triCycle >= 32)
|
||||
triCycle = 0;
|
||||
}
|
||||
if(noiseLengthCtr && (APU_IO_Reg[0x15] & NOISE_ENABLE))
|
||||
|
||||
if(noiseFreqCtr)
|
||||
noiseFreqCtr--;
|
||||
if(noiseFreqCtr == 0)
|
||||
{
|
||||
if(noiseFreqCtr)
|
||||
noiseFreqCtr--;
|
||||
if(noiseFreqCtr == 0)
|
||||
{
|
||||
noiseFreqCtr = noiseFreq;
|
||||
uint8_t cmpBit = noiseMode1 ? (noiseShiftReg>>6)&1 : (noiseShiftReg>>1)&1;
|
||||
uint8_t cmpRes = (noiseShiftReg&1)^cmpBit;
|
||||
noiseShiftReg>>=1;
|
||||
noiseShiftReg|=cmpRes<<14;
|
||||
}
|
||||
noiseFreqCtr = noiseFreq;
|
||||
uint8_t cmpBit = noiseMode1 ? (noiseShiftReg>>6)&1 : (noiseShiftReg>>1)&1;
|
||||
uint8_t cmpRes = (noiseShiftReg&1)^cmpBit;
|
||||
noiseShiftReg >>= 1;
|
||||
noiseShiftReg |= cmpRes<<14;
|
||||
}
|
||||
if(dmcLen && (APU_IO_Reg[0x15] & DMC_ENABLE))
|
||||
|
||||
if(dmcFreqCtr)
|
||||
dmcFreqCtr--;
|
||||
if(dmcFreqCtr == 0)
|
||||
{
|
||||
if(dmcFreqCtr)
|
||||
dmcFreqCtr--;
|
||||
if(dmcFreqCtr == 0)
|
||||
dmcFreqCtr = dmcFreq;
|
||||
if(dmcSampleRemain)
|
||||
{
|
||||
dmcFreqCtr = dmcFreq;
|
||||
//dmcCycle++;
|
||||
if(dmcSampleRemain)
|
||||
if(dmcSampleBuf&1)
|
||||
{
|
||||
if(dmcSampleBuf&1)
|
||||
{
|
||||
if(dmcVol <= 125)
|
||||
dmcVol += 2;
|
||||
}
|
||||
else if(dmcVol >= 2)
|
||||
dmcVol -= 2;
|
||||
dmcSampleBuf>>=1;
|
||||
dmcSampleRemain--;
|
||||
if(dmcVol <= 125)
|
||||
dmcVol += 2;
|
||||
}
|
||||
if(!dmcSampleRemain)
|
||||
else if(dmcVol >= 2)
|
||||
dmcVol -= 2;
|
||||
dmcSampleBuf>>=1;
|
||||
dmcSampleRemain--;
|
||||
}
|
||||
if(!dmcSampleRemain)
|
||||
{
|
||||
if(dmcCurLen)
|
||||
{
|
||||
if(dmcCurLen)
|
||||
dmcSampleBuf = memGet8(dmcCurAddr);
|
||||
if(cpu_oam_dma > 0)
|
||||
cpuIncWaitCycles(2);
|
||||
else
|
||||
cpuIncWaitCycles(4);
|
||||
dmcCurAddr++;
|
||||
if(dmcCurAddr < 0x8000)
|
||||
dmcCurAddr |= 0x8000;
|
||||
dmcCurLen--;
|
||||
if(!dmcCurLen)
|
||||
{
|
||||
dmcSampleBuf = memGet8(dmcCurAddr);
|
||||
if(cpu_oam_dma > 0)
|
||||
cpuIncWaitCycles(2);
|
||||
else
|
||||
cpuIncWaitCycles(4);
|
||||
dmcCurAddr++;
|
||||
if(dmcCurAddr < 0x8000)
|
||||
dmcCurAddr |= 0x8000;
|
||||
dmcCurLen--;
|
||||
if(!dmcCurLen)
|
||||
if(dmchaltloop)
|
||||
{
|
||||
if(dmchaltloop)
|
||||
{
|
||||
dmcCurAddr = dmcAddr;
|
||||
dmcCurLen = dmcLen;
|
||||
}
|
||||
else if(dmcirqenable)
|
||||
{
|
||||
//printf("DMC IRQ\n");
|
||||
dmc_interrupt = true;
|
||||
}
|
||||
dmcCurAddr = dmcAddr;
|
||||
dmcCurLen = dmcLen;
|
||||
}
|
||||
else if(dmcirqenable)
|
||||
{
|
||||
//printf("DMC IRQ\n");
|
||||
dmc_interrupt = true;
|
||||
}
|
||||
dmcSampleRemain = 8;
|
||||
}
|
||||
//dmcCycle = 0;
|
||||
dmcSampleRemain = 8;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -357,7 +364,7 @@ int apuCycle()
|
||||
//very rough still
|
||||
if(vrc6enabled)
|
||||
{
|
||||
vrc6Cycle();
|
||||
vrc6AudioCycle();
|
||||
curIn += ((float)vrc6Out)*0.008f;
|
||||
curIn *= 0.665f;
|
||||
}
|
||||
@ -493,7 +500,6 @@ void apuClockB()
|
||||
}
|
||||
|
||||
extern bool apu_interrupt;
|
||||
extern void nesEmuResetApuClock(void);
|
||||
|
||||
void apuLenCycle()
|
||||
{
|
||||
@ -502,28 +508,41 @@ void apuLenCycle()
|
||||
|
||||
if(mode5 == false)
|
||||
{
|
||||
if(modePos >= 4)
|
||||
modePos = 0;
|
||||
if(modePos == 1)
|
||||
apuClockA();
|
||||
if(modePos == 3)
|
||||
if(modeCurCtr)
|
||||
modeCurCtr--;
|
||||
if(modeCurCtr == 0)
|
||||
{
|
||||
apuClockA();
|
||||
if(apu_enable_irq)
|
||||
apu_interrupt = true;
|
||||
if(modePos == 1)
|
||||
apuClockA();
|
||||
if(modePos == 3)
|
||||
{
|
||||
apuClockA();
|
||||
if(apu_enable_irq)
|
||||
apu_interrupt = true;
|
||||
}
|
||||
apuClockB();
|
||||
modePos++;
|
||||
if(modePos >= 4)
|
||||
modePos = 0;
|
||||
modeCurCtr = mode4Ctr[modePos];
|
||||
}
|
||||
apuClockB();
|
||||
}
|
||||
else
|
||||
{
|
||||
if(modePos >= 5)
|
||||
modePos = 0;
|
||||
if(modePos == 0 || modePos == 2)
|
||||
apuClockA();
|
||||
if(modePos != 4)
|
||||
apuClockB();
|
||||
if(modeCurCtr)
|
||||
modeCurCtr--;
|
||||
if(modeCurCtr == 0)
|
||||
{
|
||||
if(modePos == 0 || modePos == 2)
|
||||
apuClockA();
|
||||
if(modePos != 4)
|
||||
apuClockB();
|
||||
modePos++;
|
||||
if(modePos >= 5)
|
||||
modePos = 0;
|
||||
modeCurCtr = mode5Ctr[modePos];
|
||||
}
|
||||
}
|
||||
modePos++;
|
||||
}
|
||||
|
||||
void apuSet8(uint8_t reg, uint8_t val)
|
||||
@ -677,9 +696,10 @@ void apuSet8(uint8_t reg, uint8_t val)
|
||||
mode5 = ((val&(1<<7)) != 0);
|
||||
//printf("Set 0x17 %d %d\n", apu_enable_irq, mode5);
|
||||
modePos = 0;
|
||||
nesEmuResetApuClock();
|
||||
if(mode5)
|
||||
apuLenCycle();
|
||||
modeCurCtr = 1;
|
||||
else
|
||||
modeCurCtr = nesPAL ? 7459 : 8315;
|
||||
}
|
||||
}
|
||||
|
||||
|
60
audio_mmc5.c
60
audio_mmc5.c
@ -39,6 +39,8 @@ static uint16_t mmc5_dmcCurAddr, mmc5_dmcCurLen;*/
|
||||
static uint8_t mmc5_p1LengthCtr, mmc5_p2LengthCtr;
|
||||
//static uint8_t mmc5_dmcVol, mmc5_dmcCurVol;
|
||||
//static uint8_t dmcSampleRemain;
|
||||
static uint8_t mmc5_modePos = 0;
|
||||
static uint16_t mmc5_modeCurCtr = 0;
|
||||
static uint16_t mmc5_p1freqCtr, mmc5_p2freqCtr;//, mmc5_dmcFreqCtr;
|
||||
static uint8_t mmc5_p1Cycle, mmc5_p2Cycle;//, dmcCycle;
|
||||
static bool mmc5_p1haltloop, mmc5_p2haltloop;//, mmc5_dmchaltloop;
|
||||
@ -51,6 +53,7 @@ static envelope_t mmc5_p1Env, mmc5_p2Env;
|
||||
extern const uint8_t lengthLookupTbl[0x20];
|
||||
extern const uint8_t pulseSeqs[4][8];
|
||||
extern const uint16_t *dmcPeriod;
|
||||
extern const uint16_t *mode4Ctr;
|
||||
|
||||
static const uint8_t *mmc5_p1seq = pulseSeqs[0],
|
||||
*mmc5_p2seq = pulseSeqs[1];
|
||||
@ -80,30 +83,26 @@ void mmc5AudioInit()
|
||||
extern uint32_t cpu_oam_dma;
|
||||
void mmc5AudioClockTimers()
|
||||
{
|
||||
if(mmc5_p1LengthCtr && (MMC5_IO_Reg[0x15] & P1_ENABLE))
|
||||
if(mmc5_p1freqCtr)
|
||||
mmc5_p1freqCtr--;
|
||||
if(mmc5_p1freqCtr == 0)
|
||||
{
|
||||
if(mmc5_p1freqCtr)
|
||||
mmc5_p1freqCtr--;
|
||||
if(mmc5_p1freqCtr == 0)
|
||||
{
|
||||
mmc5_p1freqCtr = (mmc5_freq1+1)*2;
|
||||
mmc5_p1Cycle++;
|
||||
}
|
||||
mmc5_p1freqCtr = (mmc5_freq1+1)*2;
|
||||
mmc5_p1Cycle++;
|
||||
if(mmc5_p1Cycle >= 8)
|
||||
mmc5_p1Cycle = 0;
|
||||
}
|
||||
if(mmc5_p2LengthCtr && (MMC5_IO_Reg[0x15] & P2_ENABLE))
|
||||
|
||||
if(mmc5_p2freqCtr)
|
||||
mmc5_p2freqCtr--;
|
||||
if(mmc5_p2freqCtr == 0)
|
||||
{
|
||||
if(mmc5_p2freqCtr)
|
||||
mmc5_p2freqCtr--;
|
||||
if(mmc5_p2freqCtr == 0)
|
||||
{
|
||||
mmc5_p2freqCtr = (mmc5_freq2+1)*2;
|
||||
mmc5_p2Cycle++;
|
||||
}
|
||||
mmc5_p2freqCtr = (mmc5_freq2+1)*2;
|
||||
mmc5_p2Cycle++;
|
||||
if(mmc5_p2Cycle >= 8)
|
||||
mmc5_p2Cycle = 0;
|
||||
}
|
||||
|
||||
/*if(mmc5_dmcLen && (MMC5_IO_Reg[0x15] & DMC_ENABLE))
|
||||
{
|
||||
if(mmc5_dmcFreqCtr)
|
||||
@ -184,17 +183,26 @@ int mmc5AudioCycle()
|
||||
|
||||
void mmc5AudioLenCycle()
|
||||
{
|
||||
if(mmc5_p1LengthCtr)
|
||||
if(mmc5_modeCurCtr)
|
||||
mmc5_modeCurCtr--;
|
||||
if(mmc5_modeCurCtr == 0)
|
||||
{
|
||||
doEnvelopeLogic(&mmc5_p1Env);
|
||||
if(!mmc5_p1haltloop)
|
||||
mmc5_p1LengthCtr--;
|
||||
}
|
||||
if(mmc5_p2LengthCtr)
|
||||
{
|
||||
doEnvelopeLogic(&mmc5_p2Env);
|
||||
if(!mmc5_p2haltloop)
|
||||
mmc5_p2LengthCtr--;
|
||||
if(mmc5_p1LengthCtr)
|
||||
{
|
||||
doEnvelopeLogic(&mmc5_p1Env);
|
||||
if(!mmc5_p1haltloop)
|
||||
mmc5_p1LengthCtr--;
|
||||
}
|
||||
if(mmc5_p2LengthCtr)
|
||||
{
|
||||
doEnvelopeLogic(&mmc5_p2Env);
|
||||
if(!mmc5_p2haltloop)
|
||||
mmc5_p2LengthCtr--;
|
||||
}
|
||||
mmc5_modePos++;
|
||||
if(mmc5_modePos >= 4)
|
||||
mmc5_modePos = 0;
|
||||
mmc5_modeCurCtr = mode4Ctr[mmc5_modePos];
|
||||
}
|
||||
}
|
||||
|
||||
|
82
audio_vrc6.c
82
audio_vrc6.c
@ -28,7 +28,7 @@ static bool vrc6_p1const, vrc6_p2const;
|
||||
static bool vrc6_p1enable, vrc6_p2enable, vrc6_sawenable;
|
||||
static bool vrc6_halt;
|
||||
|
||||
void vrc6Init()
|
||||
void vrc6AudioInit()
|
||||
{
|
||||
vrc6enabled = true;
|
||||
vrc6_freq1 = 0, vrc6_freq2 = 0, vrc6_sawFreq = 0;
|
||||
@ -45,7 +45,7 @@ void vrc6Init()
|
||||
|
||||
static uint8_t vrc6_lastP1Out = 0, vrc6_lastP2Out = 0, vrc6_lastSawOut = 0;
|
||||
|
||||
void vrc6Cycle()
|
||||
void vrc6AudioCycle()
|
||||
{
|
||||
uint8_t p1Out = vrc6_lastP1Out, p2Out = vrc6_lastP2Out, sawOut = vrc6_lastSawOut;
|
||||
if(vrc6_p1enable)
|
||||
@ -68,58 +68,52 @@ void vrc6Cycle()
|
||||
vrc6Out = p1Out+p2Out+sawOut;
|
||||
}
|
||||
|
||||
void vrc6ClockTimers()
|
||||
void vrc6AudioClockTimers()
|
||||
{
|
||||
if(vrc6_halt) return;
|
||||
if(vrc6_p1enable)
|
||||
|
||||
if(vrc6_p1freqCtr)
|
||||
vrc6_p1freqCtr--;
|
||||
if(vrc6_p1freqCtr == 0)
|
||||
{
|
||||
if(vrc6_p1freqCtr)
|
||||
vrc6_p1freqCtr--;
|
||||
if(vrc6_p1freqCtr == 0)
|
||||
{
|
||||
if(vrc6_speed == 0)
|
||||
vrc6_p1freqCtr = (vrc6_freq1+1);
|
||||
else if(vrc6_speed == 1)
|
||||
vrc6_p1freqCtr = (vrc6_freq1+1)>>4;
|
||||
else
|
||||
vrc6_p1freqCtr = (vrc6_freq1+1)>>8;
|
||||
vrc6_p1Cycle++;
|
||||
}
|
||||
if(vrc6_speed == 0)
|
||||
vrc6_p1freqCtr = (vrc6_freq1+1);
|
||||
else if(vrc6_speed == 1)
|
||||
vrc6_p1freqCtr = (vrc6_freq1+1)>>4;
|
||||
else
|
||||
vrc6_p1freqCtr = (vrc6_freq1+1)>>8;
|
||||
vrc6_p1Cycle++;
|
||||
if(vrc6_p1Cycle >= 16)
|
||||
vrc6_p1Cycle = 0;
|
||||
}
|
||||
if(vrc6_p2enable)
|
||||
|
||||
if(vrc6_p2freqCtr)
|
||||
vrc6_p2freqCtr--;
|
||||
if(vrc6_p2freqCtr == 0)
|
||||
{
|
||||
if(vrc6_p2freqCtr)
|
||||
vrc6_p2freqCtr--;
|
||||
if(vrc6_p2freqCtr == 0)
|
||||
{
|
||||
if(vrc6_speed == 0)
|
||||
vrc6_p2freqCtr = (vrc6_freq2+1);
|
||||
else if(vrc6_speed == 1)
|
||||
vrc6_p2freqCtr = (vrc6_freq2+1)>>4;
|
||||
else
|
||||
vrc6_p2freqCtr = (vrc6_freq2+1)>>8;
|
||||
vrc6_p2Cycle++;
|
||||
}
|
||||
if(vrc6_speed == 0)
|
||||
vrc6_p2freqCtr = (vrc6_freq2+1);
|
||||
else if(vrc6_speed == 1)
|
||||
vrc6_p2freqCtr = (vrc6_freq2+1)>>4;
|
||||
else
|
||||
vrc6_p2freqCtr = (vrc6_freq2+1)>>8;
|
||||
vrc6_p2Cycle++;
|
||||
if(vrc6_p2Cycle >= 16)
|
||||
vrc6_p2Cycle = 0;
|
||||
}
|
||||
if(vrc6_sawenable)
|
||||
|
||||
if(vrc6_sawFreqCtr)
|
||||
vrc6_sawFreqCtr--;
|
||||
if(vrc6_sawFreqCtr == 0)
|
||||
{
|
||||
if(vrc6_sawFreqCtr)
|
||||
vrc6_sawFreqCtr--;
|
||||
if(vrc6_sawFreqCtr == 0)
|
||||
{
|
||||
if(vrc6_speed == 0)
|
||||
vrc6_sawFreqCtr = (vrc6_sawFreq+1)*2;
|
||||
else if(vrc6_speed == 1)
|
||||
vrc6_sawFreqCtr = (vrc6_sawFreq+1)*2>>4;
|
||||
else
|
||||
vrc6_sawFreqCtr = (vrc6_sawFreq+1)*2>>8;
|
||||
vrc6_sawCycle++;
|
||||
vrc6_sawVol += vrc6_sawAdd;
|
||||
}
|
||||
if(vrc6_speed == 0)
|
||||
vrc6_sawFreqCtr = (vrc6_sawFreq+1)*2;
|
||||
else if(vrc6_speed == 1)
|
||||
vrc6_sawFreqCtr = (vrc6_sawFreq+1)*2>>4;
|
||||
else
|
||||
vrc6_sawFreqCtr = (vrc6_sawFreq+1)*2>>8;
|
||||
vrc6_sawCycle++;
|
||||
vrc6_sawVol += vrc6_sawAdd;
|
||||
if(vrc6_sawCycle >= 7)
|
||||
{
|
||||
vrc6_sawCycle = 0;
|
||||
@ -128,7 +122,7 @@ void vrc6ClockTimers()
|
||||
}
|
||||
}
|
||||
|
||||
void vrc6Set8(uint16_t addr, uint8_t val)
|
||||
void vrc6AudioSet8(uint16_t addr, uint8_t val)
|
||||
{
|
||||
if(addr == 0x9000)
|
||||
{
|
||||
|
@ -8,10 +8,10 @@
|
||||
#ifndef _AUDIO_VRC6_H_
|
||||
#define _AUDIO_VRC6_H_
|
||||
|
||||
void vrc6Init();
|
||||
void vrc6Cycle();
|
||||
void vrc6ClockTimers();
|
||||
void vrc6Set8(uint16_t addr, uint8_t val);
|
||||
void vrc6AudioInit();
|
||||
void vrc6AudioCycle();
|
||||
void vrc6AudioClockTimers();
|
||||
void vrc6AudioSet8(uint16_t addr, uint8_t val);
|
||||
|
||||
extern bool vrc6enabled;
|
||||
extern uint8_t vrc6Out;
|
||||
|
20
main.c
20
main.c
@ -29,7 +29,7 @@
|
||||
#define DEBUG_KEY 0
|
||||
#define DEBUG_LOAD_INFO 1
|
||||
|
||||
static const char *VERSION_STRING = "fixNES Alpha v0.5.7";
|
||||
static const char *VERSION_STRING = "fixNES Alpha v0.6";
|
||||
|
||||
static void nesEmuDisplayFrame(void);
|
||||
static void nesEmuMainLoop(void);
|
||||
@ -84,8 +84,6 @@ static const int visibleImg = VISIBLE_DOTS*VISIBLE_LINES*4;
|
||||
static int scaleFactor = 2;
|
||||
static bool emuSaveEnabled = false;
|
||||
static bool emuFdsHasSideB = false;
|
||||
static int emuApuClockCycles;
|
||||
static int emuApuClock;
|
||||
static int mainLoopRuns;
|
||||
static int mainLoopPos;
|
||||
static int ppuCycleTimer;
|
||||
@ -300,8 +298,6 @@ int main(int argc, char** argv)
|
||||
int i;
|
||||
for(i = 0; i < visibleImg; i+=4)
|
||||
textureImage[i+3] = 0xFF;
|
||||
emuApuClockCycles = nesPAL ? 8313 : 7457;
|
||||
emuApuClock = emuApuClockCycles - (nesPAL ? 1066 : 1137);
|
||||
cpuCycleTimer = nesPAL ? 16 : 12;
|
||||
//do one scanline per idle loop
|
||||
ppuCycleTimer = nesPAL ? 5 : 4;
|
||||
@ -348,7 +344,7 @@ static void nesEmuDeinit(void)
|
||||
apuDeinitBufs();
|
||||
if(emuNesROM != NULL)
|
||||
{
|
||||
if(fdsEnabled)
|
||||
if(!nesEmuNSFPlayback && fdsEnabled)
|
||||
{
|
||||
FILE *save = fopen(emuSaveName, "wb");
|
||||
if(save)
|
||||
@ -426,13 +422,7 @@ static void nesEmuMainLoop(void)
|
||||
mapperCycle();
|
||||
//mCycles++;
|
||||
//channel timer updates
|
||||
if(emuApuClock == emuApuClockCycles)
|
||||
{
|
||||
apuLenCycle();
|
||||
emuApuClock = 0;
|
||||
}
|
||||
else
|
||||
emuApuClock++;
|
||||
apuLenCycle();
|
||||
mainClock = 1;
|
||||
}
|
||||
else
|
||||
@ -488,10 +478,6 @@ static void nesEmuMainLoop(void)
|
||||
#endif
|
||||
}
|
||||
|
||||
void nesEmuResetApuClock(void)
|
||||
{
|
||||
emuApuClock = 0;
|
||||
}
|
||||
extern bool fdsSwitch;
|
||||
static void nesEmuHandleKeyDown(unsigned char key, int x, int y)
|
||||
{
|
||||
|
@ -47,7 +47,7 @@ static void nsfInitPlayback()
|
||||
memset(nsf_FillRAM, 0, 0x8000);
|
||||
cpuInitNSF(nsf_initAddr, nsf_curTrack-1, nesPAL ? 1 : 0);
|
||||
if(vrc6enabled)
|
||||
vrc6Init();
|
||||
vrc6AudioInit();
|
||||
if(mmc5enabled)
|
||||
mmc5AudioInit();
|
||||
if(fdsEnabled)
|
||||
@ -69,7 +69,7 @@ void nsfinit(uint8_t *nsfBIN, uint32_t nsfBINsize, uint8_t *prgRAMin, uint32_t p
|
||||
nesPAL = ((nsfBIN[0x7A]&1) != 0);
|
||||
apuInitBufs();
|
||||
if((nsfBIN[0x7B]&1) != 0)
|
||||
vrc6Init();
|
||||
vrc6AudioInit();
|
||||
if((nsfBIN[0x7B]&4) != 0)
|
||||
fdsAudioInit();
|
||||
if((nsfBIN[0x7B]&8) != 0)
|
||||
@ -271,7 +271,7 @@ void nsfset8(uint16_t addr, uint8_t val)
|
||||
else if(vrc6enabled && ((addr >= 0x9000 && addr <= 0x9003) ||
|
||||
(addr >= 0xA000 && addr <= 0xA002) ||
|
||||
(addr >= 0xB000 && addr <= 0xB002)))
|
||||
vrc6Set8(addr, val);
|
||||
vrc6AudioSet8(addr, val);
|
||||
}
|
||||
}
|
||||
|
||||
@ -290,7 +290,7 @@ extern uint8_t inValReads[8];
|
||||
void nsfcycle()
|
||||
{
|
||||
if(vrc6enabled)
|
||||
vrc6ClockTimers();
|
||||
vrc6AudioClockTimers();
|
||||
if(fdsEnabled)
|
||||
fdsAudioClockTimers();
|
||||
if(mmc5enabled)
|
||||
|
334
mapper/vrc.c
Normal file
334
mapper/vrc.c
Normal file
@ -0,0 +1,334 @@
|
||||
/*
|
||||
* Copyright (C) 2017 FIX94
|
||||
*
|
||||
* This software may be modified and distributed under the terms
|
||||
* of the MIT license. See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
#include <inttypes.h>
|
||||
#include "../ppu.h"
|
||||
|
||||
static uint8_t *vrc_prgROM;
|
||||
static uint8_t *vrc_prgRAM;
|
||||
static uint8_t *vrc_chrROM;
|
||||
static uint32_t vrc_prgROMsize;
|
||||
static uint32_t vrc_prgRAMsize;
|
||||
static uint32_t vrc_chrROMsize;
|
||||
static uint32_t vrc_curPRGBank0;
|
||||
static uint32_t vrc_curPRGBank1;
|
||||
static uint32_t vrc_lastM1PRGBank;
|
||||
static uint32_t vrc_lastPRGBank;
|
||||
static uint32_t vrc_CHRBank[8];
|
||||
static uint32_t vrc_prgROMand;
|
||||
static uint32_t vrc_chrROMand;
|
||||
static uint8_t vrc_irqCtr;
|
||||
static uint8_t vrc_irqCurCtr;
|
||||
static uint8_t vrc_irqCurCycleCtr;
|
||||
static uint8_t vrc_scanTblPos;
|
||||
static bool vrc_irq_enabled;
|
||||
static bool vrc_irq_enable_after_ack;
|
||||
static bool vrc_irq_cyclemode;
|
||||
static bool vrc_prg_bank_flip;
|
||||
extern bool mapper_interrupt;
|
||||
|
||||
static uint8_t vrc_scanTbl[3] = { 113, 113, 112 };
|
||||
|
||||
void vrcinit(uint8_t *prgROMin, uint32_t prgROMsizeIn,
|
||||
uint8_t *prgRAMin, uint32_t prgRAMsizeIn,
|
||||
uint8_t *chrROMin, uint32_t chrROMsizeIn)
|
||||
{
|
||||
vrc_prgROM = prgROMin;
|
||||
vrc_prgROMsize = prgROMsizeIn;
|
||||
vrc_prgRAM = prgRAMin;
|
||||
vrc_prgRAMsize = prgRAMsizeIn;
|
||||
vrc_curPRGBank0 = 0;
|
||||
vrc_curPRGBank1 = 0x2000;
|
||||
vrc_lastPRGBank = (prgROMsizeIn - 0x2000);
|
||||
vrc_lastM1PRGBank = vrc_lastPRGBank - 0x2000;
|
||||
vrc_prgROMand = prgROMsizeIn-1;
|
||||
vrc_chrROM = chrROMin;
|
||||
vrc_chrROMsize = chrROMsizeIn;
|
||||
vrc_chrROMand = chrROMsizeIn-1;
|
||||
memset(vrc_CHRBank, 0, 8*sizeof(uint32_t));
|
||||
vrc_prg_bank_flip = false;
|
||||
vrc_irqCtr = 0;
|
||||
vrc_irqCurCtr = 0;
|
||||
vrc_irqCurCycleCtr = 0;
|
||||
vrc_irq_enabled = false;
|
||||
vrc_irq_enable_after_ack = false;
|
||||
vrc_irq_cyclemode = false;
|
||||
vrc_scanTblPos = 0;
|
||||
printf("VRC Mapper inited\n");
|
||||
}
|
||||
|
||||
uint8_t vrcget8(uint16_t addr)
|
||||
{
|
||||
if(addr >= 0x6000 && addr < 0x8000)
|
||||
return vrc_prgRAM[addr&0x1FFF];
|
||||
else if(addr >= 0x8000)
|
||||
{
|
||||
if(addr < 0xA000)
|
||||
{
|
||||
if(vrc_prg_bank_flip)
|
||||
return vrc_prgROM[(((vrc_lastM1PRGBank+(addr&0x1FFF)))&vrc_prgROMand)];
|
||||
else
|
||||
return vrc_prgROM[(((vrc_curPRGBank0<<13)+(addr&0x1FFF))&vrc_prgROMand)];
|
||||
}
|
||||
else if(addr < 0xC000)
|
||||
return vrc_prgROM[(((vrc_curPRGBank1<<13)+(addr&0x1FFF))&vrc_prgROMand)];
|
||||
else if(addr < 0xE000)
|
||||
{
|
||||
if(vrc_prg_bank_flip)
|
||||
return vrc_prgROM[(((vrc_curPRGBank0<<13)+(addr&0x1FFF))&vrc_prgROMand)];
|
||||
else
|
||||
return vrc_prgROM[((vrc_lastM1PRGBank+(addr&0x1FFF))&vrc_prgROMand)];
|
||||
}
|
||||
return vrc_prgROM[((vrc_lastPRGBank+(addr&0x1FFF))&vrc_prgROMand)];
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void vrcset8(uint16_t addr, uint8_t val)
|
||||
{
|
||||
//select all possible addresses
|
||||
addr &= 0xF003;
|
||||
if(addr == 0x8000 || addr == 0x8001 || addr == 0x8002 || addr == 0x8003)
|
||||
vrc_curPRGBank0 = (val&0x1F);
|
||||
else if(addr == 0x9000 || addr == 0x9001)
|
||||
{
|
||||
if(!ppu4Screen)
|
||||
{
|
||||
val &= 3;
|
||||
switch(val)
|
||||
{
|
||||
case 0:
|
||||
ppuSetNameTblVertical();
|
||||
break;
|
||||
case 1:
|
||||
ppuSetNameTblHorizontal();
|
||||
break;
|
||||
case 2:
|
||||
ppuSetNameTblSingleLower();
|
||||
break;
|
||||
default: //case 3
|
||||
ppuSetNameTblSingleUpper();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(addr == 0x9002 || addr == 0x9003)
|
||||
vrc_prg_bank_flip = ((val&2) != 0);
|
||||
else if(addr == 0xA000 || addr == 0xA001 || addr == 0xA002 || addr == 0xA003)
|
||||
vrc_curPRGBank1 = (val&0x1F);
|
||||
else if(addr == 0xB000)
|
||||
vrc_CHRBank[0] = (vrc_CHRBank[0]&~0xF) | (val&0xF);
|
||||
else if(addr == 0xB001)
|
||||
vrc_CHRBank[0] = (vrc_CHRBank[0]&0xF) | ((val&0x1F)<<4);
|
||||
else if(addr == 0xB002)
|
||||
vrc_CHRBank[1] = (vrc_CHRBank[1]&~0xF) | (val&0xF);
|
||||
else if(addr == 0xB003)
|
||||
vrc_CHRBank[1] = (vrc_CHRBank[1]&0xF) | ((val&0x1F)<<4);
|
||||
else if(addr == 0xC000)
|
||||
vrc_CHRBank[2] = (vrc_CHRBank[2]&~0xF) | (val&0xF);
|
||||
else if(addr == 0xC001)
|
||||
vrc_CHRBank[2] = (vrc_CHRBank[2]&0xF) | ((val&0x1F)<<4);
|
||||
else if(addr == 0xC002)
|
||||
vrc_CHRBank[3] = (vrc_CHRBank[3]&~0xF) | (val&0xF);
|
||||
else if(addr == 0xC003)
|
||||
vrc_CHRBank[3] = (vrc_CHRBank[3]&0xF) | ((val&0x1F)<<4);
|
||||
else if(addr == 0xD000)
|
||||
vrc_CHRBank[4] = (vrc_CHRBank[4]&~0xF) | (val&0xF);
|
||||
else if(addr == 0xD001)
|
||||
vrc_CHRBank[4] = (vrc_CHRBank[4]&0xF) | ((val&0x1F)<<4);
|
||||
else if(addr == 0xD002)
|
||||
vrc_CHRBank[5] = (vrc_CHRBank[5]&~0xF) | (val&0xF);
|
||||
else if(addr == 0xD003)
|
||||
vrc_CHRBank[5] = (vrc_CHRBank[5]&0xF) | ((val&0x1F)<<4);
|
||||
else if(addr == 0xE000)
|
||||
vrc_CHRBank[6] = (vrc_CHRBank[6]&~0xF) | (val&0xF);
|
||||
else if(addr == 0xE001)
|
||||
vrc_CHRBank[6] = (vrc_CHRBank[6]&0xF) | ((val&0x1F)<<4);
|
||||
else if(addr == 0xE002)
|
||||
vrc_CHRBank[7] = (vrc_CHRBank[7]&~0xF) | (val&0xF);
|
||||
else if(addr == 0xE003)
|
||||
vrc_CHRBank[7] = (vrc_CHRBank[7]&0xF) | ((val&0x1F)<<4);
|
||||
else if(addr == 0xF000)
|
||||
vrc_irqCtr = (vrc_irqCtr&~0xF) | (val&0xF);
|
||||
else if(addr == 0xF001)
|
||||
vrc_irqCtr = (vrc_irqCtr&0xF) | ((val&0xF)<<4);
|
||||
else if(addr == 0xF002)
|
||||
{
|
||||
mapper_interrupt = false;
|
||||
vrc_irq_enable_after_ack = ((val&1) != 0);
|
||||
vrc_irq_cyclemode = ((val&4) != 0);
|
||||
if((val&2) != 0)
|
||||
{
|
||||
vrc_irq_enabled = true;
|
||||
vrc_irqCurCtr = vrc_irqCtr;
|
||||
vrc_irqCurCycleCtr = 0;
|
||||
vrc_scanTblPos = 0;
|
||||
//printf("VRC IRQ Reload with in %02x ctr %i\n", val, vrc_irqCtr);
|
||||
}
|
||||
}
|
||||
else if(addr == 0xF003)
|
||||
{
|
||||
mapper_interrupt = false;
|
||||
if(vrc_irq_enable_after_ack)
|
||||
{
|
||||
vrc_irq_enabled = true;
|
||||
//printf("VRC ACK IRQ Reload\n");
|
||||
}
|
||||
//else
|
||||
// printf("VRC ACK No Reload\n");
|
||||
}
|
||||
}
|
||||
|
||||
void m21_set8(uint16_t addr, uint8_t val)
|
||||
{
|
||||
if(addr < 0x6000)
|
||||
return;
|
||||
if(addr < 0x8000)
|
||||
{
|
||||
vrc_prgRAM[addr&0x1FFF] = val;
|
||||
return;
|
||||
}
|
||||
//printf("m21_set8 %04x %02x\n", addr, val);
|
||||
//VRC4 M21 Address Setup
|
||||
uint8_t tmp1 = (addr>>1)&3;
|
||||
uint8_t tmp2 = (addr>>6)&3;
|
||||
addr &= 0xF000; addr |= (tmp1 | tmp2);
|
||||
vrcset8(addr, val);
|
||||
}
|
||||
|
||||
void m22_set8(uint16_t addr, uint8_t val)
|
||||
{
|
||||
if(addr < 0x8000)
|
||||
return;
|
||||
//printf("m22_set8 %04x %02x\n", addr, val);
|
||||
//VRC2 only supports vertical/horizonal
|
||||
if(addr == 0x9000 || addr == 0x9002)
|
||||
val &= 1;
|
||||
//VRC2 M22 Address Setup
|
||||
uint8_t tmp = addr&3;
|
||||
addr &= ~0x3; addr |= (((tmp&1)<<1) | ((tmp&2)>>1));
|
||||
vrcset8(addr, val);
|
||||
}
|
||||
|
||||
void m23_set8(uint16_t addr, uint8_t val)
|
||||
{
|
||||
if(addr < 0x6000)
|
||||
return;
|
||||
if(addr < 0x8000)
|
||||
{
|
||||
vrc_prgRAM[addr&0x1FFF] = val;
|
||||
return;
|
||||
}
|
||||
//printf("m23_set8 %04x %02x\n", addr, val);
|
||||
//VRC2 Wai Wai World, avoid wrong mirroring
|
||||
if(addr == 0x9000 && val == 0xFF)
|
||||
val &= 1; //only supports vertical/horizonal
|
||||
//VRC4 M23 Address Setup
|
||||
uint8_t tmp = (addr>>2)&3;
|
||||
addr &= ~0xC; addr |= tmp;
|
||||
vrcset8(addr, val);
|
||||
}
|
||||
|
||||
void m25_set8(uint16_t addr, uint8_t val)
|
||||
{
|
||||
if(addr < 0x6000)
|
||||
return;
|
||||
if(addr < 0x8000)
|
||||
{
|
||||
vrc_prgRAM[addr&0x1FFF] = val;
|
||||
return;
|
||||
}
|
||||
//printf("m25_set8 %04x %02x\n", addr, val);
|
||||
//VRC4 M25 Address Setup
|
||||
uint8_t tmp1 = (((addr&1)<<1) | ((addr&2)>>1));
|
||||
uint8_t tmp2 = ((((addr>>2)&1)<<1) | (((addr>>2)&2)>>1));
|
||||
addr &= 0xF000; addr |= (tmp1 | tmp2);
|
||||
vrcset8(addr, val);
|
||||
}
|
||||
|
||||
uint8_t vrcchrGet8(uint16_t addr)
|
||||
{
|
||||
if(addr < 0x400)
|
||||
return vrc_chrROM[(((vrc_CHRBank[0]<<10)+(addr&0x3FF))&vrc_chrROMand)];
|
||||
else if(addr < 0x800)
|
||||
return vrc_chrROM[(((vrc_CHRBank[1]<<10)+(addr&0x3FF))&vrc_chrROMand)];
|
||||
else if(addr < 0xC00)
|
||||
return vrc_chrROM[(((vrc_CHRBank[2]<<10)+(addr&0x3FF))&vrc_chrROMand)];
|
||||
else if(addr < 0x1000)
|
||||
return vrc_chrROM[(((vrc_CHRBank[3]<<10)+(addr&0x3FF))&vrc_chrROMand)];
|
||||
else if(addr < 0x1400)
|
||||
return vrc_chrROM[(((vrc_CHRBank[4]<<10)+(addr&0x3FF))&vrc_chrROMand)];
|
||||
else if(addr < 0x1800)
|
||||
return vrc_chrROM[(((vrc_CHRBank[5]<<10)+(addr&0x3FF))&vrc_chrROMand)];
|
||||
else if(addr < 0x1C00)
|
||||
return vrc_chrROM[(((vrc_CHRBank[6]<<10)+(addr&0x3FF))&vrc_chrROMand)];
|
||||
else // < 0x2000
|
||||
return vrc_chrROM[(((vrc_CHRBank[7]<<10)+(addr&0x3FF))&vrc_chrROMand)];
|
||||
}
|
||||
|
||||
uint8_t m22_chrGet8(uint16_t addr)
|
||||
{
|
||||
if(addr < 0x400)
|
||||
return vrc_chrROM[((((vrc_CHRBank[0]>>1)<<10)+(addr&0x3FF))&vrc_chrROMand)];
|
||||
else if(addr < 0x800)
|
||||
return vrc_chrROM[((((vrc_CHRBank[1]>>1)<<10)+(addr&0x3FF))&vrc_chrROMand)];
|
||||
else if(addr < 0xC00)
|
||||
return vrc_chrROM[((((vrc_CHRBank[2]>>1)<<10)+(addr&0x3FF))&vrc_chrROMand)];
|
||||
else if(addr < 0x1000)
|
||||
return vrc_chrROM[((((vrc_CHRBank[3]>>1)<<10)+(addr&0x3FF))&vrc_chrROMand)];
|
||||
else if(addr < 0x1400)
|
||||
return vrc_chrROM[((((vrc_CHRBank[4]>>1)<<10)+(addr&0x3FF))&vrc_chrROMand)];
|
||||
else if(addr < 0x1800)
|
||||
return vrc_chrROM[((((vrc_CHRBank[5]>>1)<<10)+(addr&0x3FF))&vrc_chrROMand)];
|
||||
else if(addr < 0x1C00)
|
||||
return vrc_chrROM[((((vrc_CHRBank[6]>>1)<<10)+(addr&0x3FF))&vrc_chrROMand)];
|
||||
else // < 0x2000
|
||||
return vrc_chrROM[((((vrc_CHRBank[7]>>1)<<10)+(addr&0x3FF))&vrc_chrROMand)];
|
||||
}
|
||||
|
||||
void vrcchrSet8(uint16_t addr, uint8_t val)
|
||||
{
|
||||
(void)addr;
|
||||
(void)val;
|
||||
}
|
||||
|
||||
void vrcctrcycle()
|
||||
{
|
||||
if(vrc_irqCurCtr == 0xFF)
|
||||
{
|
||||
if(vrc_irq_enabled)
|
||||
{
|
||||
//printf("VRC Cycle Interrupt\n");
|
||||
mapper_interrupt = true;
|
||||
vrc_irq_enabled = false;
|
||||
}
|
||||
vrc_irqCurCtr = vrc_irqCtr;
|
||||
}
|
||||
else
|
||||
vrc_irqCurCtr++;
|
||||
}
|
||||
|
||||
void vrccycle()
|
||||
{
|
||||
if(vrc_irq_cyclemode)
|
||||
vrcctrcycle();
|
||||
else
|
||||
{
|
||||
if(vrc_irqCurCycleCtr >= vrc_scanTbl[vrc_scanTblPos])
|
||||
{
|
||||
vrcctrcycle();
|
||||
vrc_scanTblPos++;
|
||||
if(vrc_scanTblPos >= 3)
|
||||
vrc_scanTblPos = 0;
|
||||
vrc_irqCurCycleCtr = 0;
|
||||
}
|
||||
else
|
||||
vrc_irqCurCycleCtr++;
|
||||
}
|
||||
}
|
274
mapper/vrc6.c
Normal file
274
mapper/vrc6.c
Normal file
@ -0,0 +1,274 @@
|
||||
/*
|
||||
* Copyright (C) 2017 FIX94
|
||||
*
|
||||
* This software may be modified and distributed under the terms
|
||||
* of the MIT license. See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
#include <inttypes.h>
|
||||
#include "../ppu.h"
|
||||
#include "../audio_vrc6.h"
|
||||
|
||||
static uint8_t *vrc6_prgROM;
|
||||
static uint8_t *vrc6_prgRAM;
|
||||
static uint8_t *vrc6_chrROM;
|
||||
static uint32_t vrc6_prgROMsize;
|
||||
static uint32_t vrc6_prgRAMsize;
|
||||
static uint32_t vrc6_chrROMsize;
|
||||
static uint32_t vrc6_curPRGBank0;
|
||||
static uint32_t vrc6_curPRGBank1;
|
||||
static uint32_t vrc6_lastPRGBank;
|
||||
static uint32_t vrc6_CHRBank[8];
|
||||
static uint8_t vrc6_CHRMode;
|
||||
static uint32_t vrc6_prgROMand;
|
||||
static uint32_t vrc6_chrROMand;
|
||||
static uint8_t vrc6_irqCtr;
|
||||
static uint8_t vrc6_irqCurCtr;
|
||||
static uint8_t vrc6_irqCurCycleCtr;
|
||||
static uint8_t vrc6_scanTblPos;
|
||||
static bool vrc6_irq_enabled;
|
||||
static bool vrc6_irq_enable_after_ack;
|
||||
static bool vrc6_irq_cyclemode;
|
||||
extern bool mapper_interrupt;
|
||||
|
||||
static uint8_t vrc6_scanTbl[3] = { 113, 113, 112 };
|
||||
|
||||
void vrc6init(uint8_t *prgROMin, uint32_t prgROMsizeIn,
|
||||
uint8_t *prgRAMin, uint32_t prgRAMsizeIn,
|
||||
uint8_t *chrROMin, uint32_t chrROMsizeIn)
|
||||
{
|
||||
vrc6_prgROM = prgROMin;
|
||||
vrc6_prgROMsize = prgROMsizeIn;
|
||||
vrc6_prgRAM = prgRAMin;
|
||||
vrc6_prgRAMsize = prgRAMsizeIn;
|
||||
vrc6_curPRGBank0 = 0;
|
||||
vrc6_curPRGBank1 = 0x2000;
|
||||
vrc6_lastPRGBank = (prgROMsizeIn - 0x2000);
|
||||
vrc6_prgROMand = prgROMsizeIn-1;
|
||||
vrc6_chrROM = chrROMin;
|
||||
vrc6_chrROMsize = chrROMsizeIn;
|
||||
vrc6_chrROMand = chrROMsizeIn-1;
|
||||
memset(vrc6_CHRBank, 0, 8*sizeof(uint32_t));
|
||||
vrc6_CHRMode = 0;
|
||||
vrc6_irqCtr = 0;
|
||||
vrc6_irqCurCtr = 0;
|
||||
vrc6_irqCurCycleCtr = 0;
|
||||
vrc6_irq_enabled = false;
|
||||
vrc6_irq_enable_after_ack = false;
|
||||
vrc6_irq_cyclemode = false;
|
||||
vrc6_scanTblPos = 0;
|
||||
vrc6AudioInit();
|
||||
printf("VRC6 Mapper inited\n");
|
||||
}
|
||||
|
||||
uint8_t vrc6get8(uint16_t addr)
|
||||
{
|
||||
if(addr >= 0x6000 && addr < 0x8000)
|
||||
return vrc6_prgRAM[addr&0x1FFF];
|
||||
else if(addr >= 0x8000)
|
||||
{
|
||||
if(addr < 0xC000)
|
||||
return vrc6_prgROM[(((vrc6_curPRGBank0<<14)+(addr&0x3FFF))&vrc6_prgROMand)];
|
||||
else if(addr < 0xE000)
|
||||
return vrc6_prgROM[(((vrc6_curPRGBank1<<13)+(addr&0x1FFF))&vrc6_prgROMand)];
|
||||
return vrc6_prgROM[((vrc6_lastPRGBank+(addr&0x1FFF))&vrc6_prgROMand)];
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void vrc6set8(uint16_t addr, uint8_t val)
|
||||
{
|
||||
//select all possible addresses
|
||||
addr &= 0xF003;
|
||||
if(addr == 0x8000 || addr == 0x8001 || addr == 0x8002 || addr == 0x8003)
|
||||
vrc6_curPRGBank0 = (val&0xF);
|
||||
else if(addr == 0xB003)
|
||||
{
|
||||
if((val & 0x3) == 0)
|
||||
vrc6_CHRMode = 0;
|
||||
else if((val & 0x3) == 1)
|
||||
vrc6_CHRMode = 1;
|
||||
else
|
||||
vrc6_CHRMode = 2;
|
||||
if(!ppu4Screen)
|
||||
{
|
||||
if((val & 0xF) == 0 || (val & 0xF) == 7)
|
||||
ppuSetNameTblVertical();
|
||||
else if((val & 0xF) == 4 || (val & 0xF) == 3)
|
||||
ppuSetNameTblHorizontal();
|
||||
if((val & 0xF) == 8 || (val & 0xF) == 0xF)
|
||||
ppuSetNameTblSingleLower();
|
||||
if((val & 0xF) == 0xC || (val & 0xF) == 0xB)
|
||||
ppuSetNameTblSingleUpper();
|
||||
}
|
||||
}
|
||||
else if(addr == 0xC000 || addr == 0xC001 || addr == 0xC002 || addr == 0xC003)
|
||||
vrc6_curPRGBank1 = (val&0x1F);
|
||||
else if(addr == 0xD000)
|
||||
vrc6_CHRBank[0] = val;
|
||||
else if(addr == 0xD001)
|
||||
vrc6_CHRBank[1] = val;
|
||||
else if(addr == 0xD002)
|
||||
vrc6_CHRBank[2] = val;
|
||||
else if(addr == 0xD003)
|
||||
vrc6_CHRBank[3] = val;
|
||||
else if(addr == 0xE000)
|
||||
vrc6_CHRBank[4] = val;
|
||||
else if(addr == 0xE001)
|
||||
vrc6_CHRBank[5] = val;
|
||||
else if(addr == 0xE002)
|
||||
vrc6_CHRBank[6] = val;
|
||||
else if(addr == 0xE003)
|
||||
vrc6_CHRBank[7] = val;
|
||||
else if(addr == 0xF000)
|
||||
vrc6_irqCtr = val;
|
||||
else if(addr == 0xF001)
|
||||
{
|
||||
mapper_interrupt = false;
|
||||
vrc6_irq_enable_after_ack = ((val&1) != 0);
|
||||
vrc6_irq_cyclemode = ((val&4) != 0);
|
||||
if((val&2) != 0)
|
||||
{
|
||||
vrc6_irq_enabled = true;
|
||||
vrc6_irqCurCtr = vrc6_irqCtr;
|
||||
vrc6_irqCurCycleCtr = 0;
|
||||
vrc6_scanTblPos = 0;
|
||||
//printf("vrc6 IRQ Reload with in %02x ctr %i\n", val, vrc6_irqCtr);
|
||||
}
|
||||
}
|
||||
else if(addr == 0xF002)
|
||||
{
|
||||
mapper_interrupt = false;
|
||||
if(vrc6_irq_enable_after_ack)
|
||||
{
|
||||
vrc6_irq_enabled = true;
|
||||
//printf("vrc6 ACK IRQ Reload\n");
|
||||
}
|
||||
//else
|
||||
// printf("vrc6 ACK No Reload\n");
|
||||
}
|
||||
else
|
||||
vrc6AudioSet8(addr, val);
|
||||
}
|
||||
|
||||
void m24_set8(uint16_t addr, uint8_t val)
|
||||
{
|
||||
if(addr < 0x6000)
|
||||
return;
|
||||
if(addr < 0x8000)
|
||||
{
|
||||
vrc6_prgRAM[addr&0x1FFF] = val;
|
||||
return;
|
||||
}
|
||||
//printf("m24_set8 %04x %02x\n", addr, val);
|
||||
vrc6set8(addr, val);
|
||||
}
|
||||
|
||||
void m26_set8(uint16_t addr, uint8_t val)
|
||||
{
|
||||
if(addr < 0x6000)
|
||||
return;
|
||||
if(addr < 0x8000)
|
||||
{
|
||||
vrc6_prgRAM[addr&0x1FFF] = val;
|
||||
return;
|
||||
}
|
||||
//printf("m26_set8 %04x %02x\n", addr, val);
|
||||
//vrc6 M26 Address Setup
|
||||
uint8_t tmp = addr&3;
|
||||
addr &= ~0x3; addr |= (((tmp&1)<<1) | ((tmp&2)>>1));
|
||||
vrc6set8(addr, val);
|
||||
}
|
||||
|
||||
uint8_t vrc6chrGet8(uint16_t addr)
|
||||
{
|
||||
if(vrc6_CHRMode == 0)
|
||||
{
|
||||
if(addr < 0x400)
|
||||
return vrc6_chrROM[(((vrc6_CHRBank[0]<<10)+(addr&0x3FF))&vrc6_chrROMand)];
|
||||
else if(addr < 0x800)
|
||||
return vrc6_chrROM[(((vrc6_CHRBank[1]<<10)+(addr&0x3FF))&vrc6_chrROMand)];
|
||||
else if(addr < 0xC00)
|
||||
return vrc6_chrROM[(((vrc6_CHRBank[2]<<10)+(addr&0x3FF))&vrc6_chrROMand)];
|
||||
else if(addr < 0x1000)
|
||||
return vrc6_chrROM[(((vrc6_CHRBank[3]<<10)+(addr&0x3FF))&vrc6_chrROMand)];
|
||||
else if(addr < 0x1400)
|
||||
return vrc6_chrROM[(((vrc6_CHRBank[4]<<10)+(addr&0x3FF))&vrc6_chrROMand)];
|
||||
else if(addr < 0x1800)
|
||||
return vrc6_chrROM[(((vrc6_CHRBank[5]<<10)+(addr&0x3FF))&vrc6_chrROMand)];
|
||||
else if(addr < 0x1C00)
|
||||
return vrc6_chrROM[(((vrc6_CHRBank[6]<<10)+(addr&0x3FF))&vrc6_chrROMand)];
|
||||
else // < 0x2000
|
||||
return vrc6_chrROM[(((vrc6_CHRBank[7]<<10)+(addr&0x3FF))&vrc6_chrROMand)];
|
||||
}
|
||||
else if(vrc6_CHRMode == 1)
|
||||
{
|
||||
if(addr < 0x800)
|
||||
return vrc6_chrROM[(((vrc6_CHRBank[0]<<11)+(addr&0x7FF))&vrc6_chrROMand)];
|
||||
else if(addr < 0x1000)
|
||||
return vrc6_chrROM[(((vrc6_CHRBank[1]<<11)+(addr&0x7FF))&vrc6_chrROMand)];
|
||||
else if(addr < 0x1800)
|
||||
return vrc6_chrROM[(((vrc6_CHRBank[2]<<11)+(addr&0x7FF))&vrc6_chrROMand)];
|
||||
else // < 0x200
|
||||
return vrc6_chrROM[(((vrc6_CHRBank[3]<<11)+(addr&0x7FF))&vrc6_chrROMand)];
|
||||
}
|
||||
else
|
||||
{
|
||||
if(addr < 0x400)
|
||||
return vrc6_chrROM[(((vrc6_CHRBank[0]<<10)+(addr&0x3FF))&vrc6_chrROMand)];
|
||||
else if(addr < 0x800)
|
||||
return vrc6_chrROM[(((vrc6_CHRBank[1]<<10)+(addr&0x3FF))&vrc6_chrROMand)];
|
||||
else if(addr < 0xC00)
|
||||
return vrc6_chrROM[(((vrc6_CHRBank[2]<<10)+(addr&0x3FF))&vrc6_chrROMand)];
|
||||
else if(addr < 0x1000)
|
||||
return vrc6_chrROM[(((vrc6_CHRBank[3]<<10)+(addr&0x3FF))&vrc6_chrROMand)];
|
||||
else if(addr < 0x1800)
|
||||
return vrc6_chrROM[(((vrc6_CHRBank[4]<<11)+(addr&0x7FF))&vrc6_chrROMand)];
|
||||
else // < 0x2000
|
||||
return vrc6_chrROM[(((vrc6_CHRBank[5]<<11)+(addr&0x7FF))&vrc6_chrROMand)];
|
||||
}
|
||||
}
|
||||
|
||||
void vrc6chrSet8(uint16_t addr, uint8_t val)
|
||||
{
|
||||
(void)addr;
|
||||
(void)val;
|
||||
}
|
||||
|
||||
void vrc6ctrcycle()
|
||||
{
|
||||
if(vrc6_irqCurCtr == 0xFF)
|
||||
{
|
||||
if(vrc6_irq_enabled)
|
||||
{
|
||||
//printf("vrc6 Cycle Interrupt\n");
|
||||
mapper_interrupt = true;
|
||||
vrc6_irq_enabled = false;
|
||||
}
|
||||
vrc6_irqCurCtr = vrc6_irqCtr;
|
||||
}
|
||||
else
|
||||
vrc6_irqCurCtr++;
|
||||
}
|
||||
|
||||
void vrc6cycle()
|
||||
{
|
||||
vrc6AudioClockTimers();
|
||||
if(vrc6_irq_cyclemode)
|
||||
vrc6ctrcycle();
|
||||
else
|
||||
{
|
||||
if(vrc6_irqCurCycleCtr >= vrc6_scanTbl[vrc6_scanTblPos])
|
||||
{
|
||||
vrc6ctrcycle();
|
||||
vrc6_scanTblPos++;
|
||||
if(vrc6_scanTblPos >= 3)
|
||||
vrc6_scanTblPos = 0;
|
||||
vrc6_irqCurCycleCtr = 0;
|
||||
}
|
||||
else
|
||||
vrc6_irqCurCycleCtr++;
|
||||
}
|
||||
}
|
14
mapperList.c
14
mapperList.c
@ -19,6 +19,8 @@
|
||||
#include "mapper_h/p8c8.h"
|
||||
#include "mapper_h/p16.h"
|
||||
#include "mapper_h/p32c8.h"
|
||||
#include "mapper_h/vrc.h"
|
||||
#include "mapper_h/vrc6.h"
|
||||
#include "mapper.h"
|
||||
#include "mapperList.h"
|
||||
|
||||
@ -44,12 +46,12 @@ mapperList_t mapperList[256] = {
|
||||
{ NULL, NULL, NULL, NULL, NULL, NULL },
|
||||
{ NULL, NULL, NULL, NULL, NULL, NULL },
|
||||
{ NULL, NULL, NULL, NULL, NULL, NULL },
|
||||
{ NULL, NULL, NULL, NULL, NULL, NULL },
|
||||
{ NULL, NULL, NULL, NULL, NULL, NULL },
|
||||
{ NULL, NULL, NULL, NULL, NULL, NULL },
|
||||
{ NULL, NULL, NULL, NULL, NULL, NULL },
|
||||
{ NULL, NULL, NULL, NULL, NULL, NULL },
|
||||
{ NULL, NULL, NULL, NULL, NULL, NULL },
|
||||
{ vrcinit, vrcget8, m21_set8, vrcchrGet8, vrcchrSet8, vrccycle },
|
||||
{ vrcinit, vrcget8, m22_set8, m22_chrGet8, vrcchrSet8, vrccycle },
|
||||
{ vrcinit, vrcget8, m23_set8, vrcchrGet8, vrcchrSet8, vrccycle },
|
||||
{ vrc6init, vrc6get8, m24_set8, vrc6chrGet8, vrc6chrSet8, vrc6cycle },
|
||||
{ vrcinit, vrcget8, m25_set8, vrcchrGet8, vrcchrSet8, vrccycle },
|
||||
{ vrc6init, vrc6get8, m26_set8, vrc6chrGet8, vrc6chrSet8, vrc6cycle },
|
||||
{ NULL, NULL, NULL, NULL, NULL, NULL },
|
||||
{ NULL, NULL, NULL, NULL, NULL, NULL },
|
||||
{ NULL, NULL, NULL, NULL, NULL, NULL },
|
||||
|
24
mapper_h/vrc.h
Normal file
24
mapper_h/vrc.h
Normal file
@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Copyright (C) 2017 FIX94
|
||||
*
|
||||
* This software may be modified and distributed under the terms
|
||||
* of the MIT license. See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
#ifndef vrc_h_
|
||||
#define vrc_h_
|
||||
|
||||
void vrcinit(uint8_t *prgROM, uint32_t prgROMsize,
|
||||
uint8_t *prgRAM, uint32_t prgRAMsize,
|
||||
uint8_t *chrROM, uint32_t chrROMsize);
|
||||
uint8_t vrcget8(uint16_t addr);
|
||||
void m21_set8(uint16_t addr, uint8_t val);
|
||||
void m22_set8(uint16_t addr, uint8_t val);
|
||||
void m23_set8(uint16_t addr, uint8_t val);
|
||||
void m25_set8(uint16_t addr, uint8_t val);
|
||||
uint8_t vrcchrGet8(uint16_t addr);
|
||||
uint8_t m22_chrGet8(uint16_t addr);
|
||||
void vrcchrSet8(uint16_t addr, uint8_t val);
|
||||
void vrccycle();
|
||||
|
||||
#endif
|
21
mapper_h/vrc6.h
Normal file
21
mapper_h/vrc6.h
Normal file
@ -0,0 +1,21 @@
|
||||
/*
|
||||
* Copyright (C) 2017 FIX94
|
||||
*
|
||||
* This software may be modified and distributed under the terms
|
||||
* of the MIT license. See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
#ifndef vrc6_h_
|
||||
#define vrc6_h_
|
||||
|
||||
void vrc6init(uint8_t *prgROM, uint32_t prgROMsize,
|
||||
uint8_t *prgRAM, uint32_t prgRAMsize,
|
||||
uint8_t *chrROM, uint32_t chrROMsize);
|
||||
uint8_t vrc6get8(uint16_t addr);
|
||||
void m24_set8(uint16_t addr, uint8_t val);
|
||||
void m26_set8(uint16_t addr, uint8_t val);
|
||||
uint8_t vrc6chrGet8(uint16_t addr);
|
||||
void vrc6chrSet8(uint16_t addr, uint8_t val);
|
||||
void vrc6cycle();
|
||||
|
||||
#endif
|
4
ppu.c
4
ppu.c
@ -453,7 +453,7 @@ ppuIncreasePos:
|
||||
ppuSprite0hit--;
|
||||
/* VBlank start at first dot after post-render line */
|
||||
/* Though results are better when starting it a bit later */
|
||||
if(curDot == 11 && curLine == 241)
|
||||
if(curDot == 8 && curLine == 241)
|
||||
{
|
||||
ppuNMITriggered = false;
|
||||
if(!ppuReadReg2)
|
||||
@ -465,7 +465,7 @@ ppuIncreasePos:
|
||||
ppuReadReg2 = false;
|
||||
/* VBlank ends at first dot of the pre-render line */
|
||||
/* Though results are better when clearing it a bit later */
|
||||
if(curDot == 4 && curLine == ppuPreRenderLine)
|
||||
if(curDot == 1 && curLine == ppuPreRenderLine)
|
||||
{
|
||||
#if PPU_DEBUG_VSYNC
|
||||
printf("PPU End VBlank\n");
|
||||
|
Loading…
x
Reference in New Issue
Block a user