-made a couple changes to the sound code

-added support for mappers 21,22,23,24,25 and 26
This commit is contained in:
FIX94 2017-02-21 06:16:57 +01:00
parent 0df3532ebe
commit 96705272f8
No known key found for this signature in database
GPG Key ID: CE39016A19D8EADA
13 changed files with 865 additions and 202 deletions

View File

@ -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
View File

@ -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;
}
}

View File

@ -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];
}
}

View File

@ -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)
{

View File

@ -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
View File

@ -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)
{

View File

@ -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
View 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
View 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++;
}
}

View File

@ -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
View 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
View 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
View File

@ -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");