Skip to content

Commit

Permalink
-various small changes to further increase overall performance
Browse files Browse the repository at this point in the history
-corrected small inaccuracy in one of the unofficial cpu instructions
-changed the logic of the apu sweep to produce a better output
  • Loading branch information
FIX94 committed Jul 21, 2018
1 parent b6e6204 commit 6ae44f3
Show file tree
Hide file tree
Showing 14 changed files with 201 additions and 182 deletions.
6 changes: 5 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,12 +34,16 @@ For the standalone you will at least need freeglut as well as openal-soft, it sh
Also you can use this as a core for retroarch by using the Makefile in the libretro folder.

There are several defines you can add/remove for different options for both the standalone version and the retroarch core:
AUDIO_LOWERFREQ
Reduces the output frequency of the emulator for more performance
COL_32BIT
Changes the output texture to be 32bit per pixel (RGBA8) instead of 16bit (RGB565)
COL_BGRA
Used in combination with COL_32BIT, this will change the output texture to BGRA8 instead of RGBA8
COL_TEX_BSWAP
In 32bit per pixel mode, this will change the byte order of the output texture, in 16bit mode this will output in BGR565
In 32bit per pixel mode, this will change the byte order of the output texture, in 16bit mode this will output in BGR565
DO_INLINE_ATTRIBS
Will use optimized function inline attributes for more overall performance

These defines are specific to the standalone version:
AUDIO_FLOAT
Expand Down
104 changes: 47 additions & 57 deletions apu.c
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,11 @@ void apuInitBufs()
//apu.Frequency = nesPAL ? 831187 : 893415;
//effective frequencies for Original PPU Video out
//apu.Frequency = nesPAL ? 831303 : 894886;
#if AUDIO_LOWERFREQ
apu.Frequency = nesPAL ? 51956 : 55930;
#else
apu.Frequency = nesPAL ? 207825 : 223721;
#endif
audioExpansion = 0;
double dt = 1.0/((double)apu.Frequency);
//LP at 22kHz
Expand All @@ -213,11 +217,11 @@ void apuInitBufs()
#if AUDIO_FLOAT
apu.BufSizeBytes = apu.BufSize*sizeof(float);
apu.OutBuf = (float*)malloc(apu.BufSizeBytes);
printf("Audio: 32-bit Float Output\n");
printf("Audio: 32-bit Float Output at %iHz\n", apu.Frequency);
#else
apu.BufSizeBytes = apu.BufSize*sizeof(int16_t);
apu.OutBuf = (int16_t*)malloc(apu.BufSizeBytes);
printf("Audio: 16-bit Short Output\n");
printf("Audio: 16-bit Short Output at %iHz\n", apu.Frequency);
#endif
/* https://wiki.nesdev.com/w/index.php/APU_Mixer#Lookup_Table */
uint8_t i;
Expand Down Expand Up @@ -314,7 +318,7 @@ void apuWriteDMCBuf(uint8_t val)

extern bool cpu_odd_cycle;

static void apuChangeMode()
FIXNES_NOINLINE static void apuChangeMode()
{
if(!cpu_odd_cycle)
return;
Expand Down Expand Up @@ -356,57 +360,49 @@ void doEnvelopeLogic(envelope_t *env)
//env->envelope = (env->constant ? env->vol : env->decay);
}

void sweepUpdateFreq(sweep_t *sw, uint16_t *freq)
static void sweepUpdateFreq(sweep_t *sw, uint16_t *freq)
{
uint16_t inFreq = *freq;
if(sw->shift > 0)
//any freq update causes target freq update
sw->targetFreq = *freq;
if(sw->targetFreq >= 8)
{
if(sw->negative)
{
inFreq -= (inFreq >> sw->shift);
if(sw->chan1 == true) inFreq--;
sw->targetFreq -= (sw->targetFreq >> sw->shift);
if(sw->chan1 == true) sw->targetFreq--;
}
else
inFreq += (inFreq >> sw->shift);
}
if(inFreq > 8 && (inFreq < 0x7FF))
{
sw->mute = false;
if(sw->enabled && sw->shift)
*freq = inFreq;
sw->targetFreq += (sw->targetFreq >> sw->shift);
if(sw->targetFreq <= 0x7FF)
sw->mute = false;
else //larger than freq register
sw->mute = true;
}
else
else //any input < 8 gets muted
sw->mute = true;
}

void doSweepLogic(sweep_t *sw, uint16_t *freq)
static void doSweepLogic(sweep_t *sw, uint16_t *freq)
{
if(sw->start)
{
uint8_t prevDiv = sw->divider;
sw->divider = sw->period;
sw->start = false;
if(prevDiv == 0)
sweepUpdateFreq(sw, freq);
}
else
if(sw->divider == 0)
{
if(sw->divider == 0)
if(sw->enabled && sw->shift && !sw->mute)
{
*freq = sw->targetFreq;
sweepUpdateFreq(sw, freq);
sw->divider = sw->period;
}
else
sw->divider--;
sw->divider = sw->period;
}
//gets clocked too little on its own?
/*if(inFreq < 8 || (inFreq >= 0x7FF))
sw->mute = true;
else
sw->mute = false;*/
sw->divider--;
if(sw->start)
{
sw->divider = sw->period;
sw->start = false;
}
}

void apuClockA()
FIXNES_NOINLINE static void apuClockA()
{
if(apu.p1LengthCtr)
{
Expand All @@ -426,7 +422,7 @@ void apuClockA()
apu.noiseLengthCtr--;
}

void apuClockB()
FIXNES_NOINLINE static void apuClockB()
{
if(apu.p1LengthCtr)
doEnvelopeLogic(&apu.p1Env);
Expand All @@ -442,19 +438,23 @@ void apuClockB()
apu.trireload = false;
}

void apuCycle()
FIXNES_ALWAYSINLINE void apuCycle()
{
uint8_t aExp = audioExpansion;
#if AUDIO_LOWERFREQ
if(!(apu.apuClock&31))
#else
if(!(apu.apuClock&7))
#endif
{
if(apu.p1LengthCtr && (apu.reg[0x15] & P1_ENABLE))
{
if(!apu.p1Sweep.mute && apu.freq1 >= 8 && apu.freq1 < 0x7FF)
if(!apu.p1Sweep.mute)
apu.p1Out = apu.p1seq[apu.p1Cycle] ? (apu.p1Env.constant ? apu.p1Env.vol : apu.p1Env.decay) : 0;
}
if(apu.p2LengthCtr && (apu.reg[0x15] & P2_ENABLE))
{
if(!apu.p2Sweep.mute && apu.freq2 >= 8 && apu.freq2 < 0x7FF)
if(!apu.p2Sweep.mute)
apu.p2Out = apu.p2seq[apu.p2Cycle] ? (apu.p2Env.constant ? apu.p2Env.vol : apu.p2Env.decay) : 0;
}
if(apu.triLengthCtr && apu.triCurLinearCtr && (apu.reg[0x15] & TRI_ENABLE))
Expand Down Expand Up @@ -713,8 +713,6 @@ void apuSetReg00(uint16_t addr, uint8_t val)
apu.p1seq = pulseSeqs[val>>6];
apu.p1Env.constant = ((val&PULSE_CONST_V) != 0);
apu.p1Env.loop = apu.p1haltloop = ((val&PULSE_HALT_LOOP) != 0);
if(apu.freq1 > 8 && (apu.freq1 < 0x7FF))
apu.p1Sweep.mute = false; //to be safe
}
void apuSetReg01(uint16_t addr, uint8_t val)
{
Expand All @@ -726,18 +724,16 @@ void apuSetReg01(uint16_t addr, uint8_t val)
apu.p1Sweep.period = (val>>4)&7;
apu.p1Sweep.negative = ((val&0x8) != 0);
apu.p1Sweep.start = true;
if(apu.freq1 > 8 && (apu.freq1 < 0x7FF))
apu.p1Sweep.mute = false; //to be safe
doSweepLogic(&apu.p1Sweep, &apu.freq1);
//adjust for new sweep regs
sweepUpdateFreq(&apu.p1Sweep, &apu.freq1);
}
void apuSetReg02(uint16_t addr, uint8_t val)
{
(void)addr;
apu.reg[2] = val;
//printf("P1 time low %02x\n", val);
apu.freq1 = ((apu.freq1&~0xFF) | val);
if(apu.freq1 > 8 && (apu.freq1 < 0x7FF))
apu.p1Sweep.mute = false; //to be safe
sweepUpdateFreq(&apu.p1Sweep, &apu.freq1);
}
void apuSetReg03(uint16_t addr, uint8_t val)
{
Expand All @@ -747,8 +743,7 @@ void apuSetReg03(uint16_t addr, uint8_t val)
if(apu.reg[0x15] & P1_ENABLE)
apu.p1LengthCtr = apu.lengthLookupTbl[val>>3];
apu.freq1 = (apu.freq1&0xFF) | ((val&7)<<8);
if(apu.freq1 > 8 && (apu.freq1 < 0x7FF))
apu.p1Sweep.mute = false; //to be safe
sweepUpdateFreq(&apu.p1Sweep, &apu.freq1);
//printf("P1 new freq %04x\n", apu.freq1);
apu.p1Env.start = true;
}
Expand All @@ -760,8 +755,6 @@ void apuSetReg04(uint16_t addr, uint8_t val)
apu.p2seq = pulseSeqs[val>>6];
apu.p2Env.constant = ((val&PULSE_CONST_V) != 0);
apu.p2Env.loop = apu.p2haltloop = ((val&PULSE_HALT_LOOP) != 0);
if(apu.freq2 > 8 && (apu.freq2 < 0x7FF))
apu.p2Sweep.mute = false; //to be safe
}
void apuSetReg05(uint16_t addr, uint8_t val)
{
Expand All @@ -773,18 +766,16 @@ void apuSetReg05(uint16_t addr, uint8_t val)
apu.p2Sweep.period = (val>>4)&7;
apu.p2Sweep.negative = ((val&0x8) != 0);
apu.p2Sweep.start = true;
if(apu.freq2 > 8 && (apu.freq2 < 0x7FF))
apu.p2Sweep.mute = false; //to be safe
doSweepLogic(&apu.p2Sweep, &apu.freq2);
//adjust for new sweep regs
sweepUpdateFreq(&apu.p2Sweep, &apu.freq2);
}
void apuSetReg06(uint16_t addr, uint8_t val)
{
(void)addr;
apu.reg[6] = val;
//printf("P2 time low %02x\n", val);
apu.freq2 = ((apu.freq2&~0xFF) | val);
if(apu.freq2 > 8 && (apu.freq2 < 0x7FF))
apu.p2Sweep.mute = false; //to be safe
sweepUpdateFreq(&apu.p2Sweep, &apu.freq2);
}
void apuSetReg07(uint16_t addr, uint8_t val)
{
Expand All @@ -794,8 +785,7 @@ void apuSetReg07(uint16_t addr, uint8_t val)
if(apu.reg[0x15] & P2_ENABLE)
apu.p2LengthCtr = apu.lengthLookupTbl[val>>3];
apu.freq2 = (apu.freq2&0xFF) | ((val&7)<<8);
if(apu.freq2 > 8 && (apu.freq2 < 0x7FF))
apu.p2Sweep.mute = false; //to be safe
sweepUpdateFreq(&apu.p2Sweep, &apu.freq2);
//printf("P2 new freq %04x\n", apu.freq2);
apu.p2Env.start = true;
}
Expand Down
7 changes: 6 additions & 1 deletion apu.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
#ifndef _apu_h_
#define _apu_h_

#include "common.h"

#define NUM_BUFFERS 4

#define EXP_VRC6 (1<<0)
Expand All @@ -20,7 +22,7 @@
void apuInitBufs();
void apuDeinitBufs();
void apuInit();
void apuCycle();
FIXNES_ALWAYSINLINE void apuCycle();
void apuWriteDMCBuf(uint8_t val);
uint8_t *apuGetBuf();
uint32_t apuGetBufSize();
Expand Down Expand Up @@ -69,6 +71,9 @@ typedef struct _sweep_t {
uint8_t period;
uint8_t divider;
uint8_t shift;
//specifically signed for pulse 1 as a shift value of 0 and negative
//flag enabled would cause an overflow and a mute otherwise
int16_t targetFreq;
} sweep_t;

void doEnvelopeLogic(envelope_t *env);
Expand Down
2 changes: 1 addition & 1 deletion build_linux.sh
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@

#Need to replace this with a makefile

gcc -DZIPSUPPORT main.c apu.c audio.c audio_fds.c audio_mmc5.c audio_vrc6.c audio_vrc7.c audio_n163.c audio_s5b.c alhelpers.c cpu.c ppu.c mem.c input.c mapper.c mapperList.c fm2play.c vrc_irq.c mapper/*.c unzip/*.c -DFREEGLUT_STATIC -lglut -lopenal -lGL -lGLU -lm -Wall -lz -Wextra -O3 -flto -s -o fixNES
gcc -DZIPSUPPORT main.c apu.c audio.c audio_fds.c audio_mmc5.c audio_vrc6.c audio_vrc7.c audio_n163.c audio_s5b.c alhelpers.c cpu.c ppu.c mem.c input.c mapper.c mapperList.c fm2play.c vrc_irq.c mapper/*.c unzip/*.c -DFREEGLUT_STATIC -lglut -lopenal -lGL -lGLU -lm -Wall -lz -Wextra -DDO_INLINE_ATTRIBS=1 -Wno-attributes -O3 -flto -s -o fixNES
echo "Succesfully built fixNES"

2 changes: 1 addition & 1 deletion build_msys32.sh
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
#!/bin/sh
gcc -DWINDOWS_BUILD -DZIPSUPPORT main.c apu.c audio.c audio_fds.c audio_mmc5.c audio_vrc6.c audio_vrc7.c audio_n163.c audio_s5b.c alhelpers.c cpu.c ppu.c mem.c input.c mapper.c mapperList.c fm2play.c vrc_irq.c mapper/*.c unzip/*.c -DFREEGLUT_STATIC -lfreeglut_static -lopenal32 -lopengl32 -lglu32 -lgdi32 -lwinmm -lz -Wall -Wextra -O3 -flto -s -o fixNES
gcc -DWINDOWS_BUILD -DZIPSUPPORT main.c apu.c audio.c audio_fds.c audio_mmc5.c audio_vrc6.c audio_vrc7.c audio_n163.c audio_s5b.c alhelpers.c cpu.c ppu.c mem.c input.c mapper.c mapperList.c fm2play.c vrc_irq.c mapper/*.c unzip/*.c -DFREEGLUT_STATIC -lfreeglut_static -lopenal32 -lopengl32 -lglu32 -lgdi32 -lwinmm -lz -Wall -Wextra -DDO_INLINE_ATTRIBS=1 -Wno-attributes -O3 -flto -s -o fixNES
2 changes: 0 additions & 2 deletions build_windows_console.bat

This file was deleted.

2 changes: 0 additions & 2 deletions build_windows_noconsole.bat

This file was deleted.

7 changes: 7 additions & 0 deletions common.h
Original file line number Diff line number Diff line change
@@ -1,10 +1,17 @@
#ifndef _common_h_
#define _common_h_

#if DO_INLINE_ATTRIBS
#ifdef _MSC_VER
#define FIXNES_NOINLINE __declspec(noinline)
#define FIXNES_ALWAYSINLINE __forceinline
#else
#define FIXNES_NOINLINE __attribute__((noinline))
#define FIXNES_ALWAYSINLINE __attribute__((always_inline))
#endif
#else
#define FIXNES_NOINLINE
#define FIXNES_ALWAYSINLINE
#endif

#endif
Loading

0 comments on commit 6ae44f3

Please sign in to comment.