First commit

This commit is contained in:
mkwong98 2014-06-24 22:34:22 +08:00
commit e107b6cc78
61 changed files with 14451 additions and 0 deletions

22
.gitattributes vendored Normal file
View file

@ -0,0 +1,22 @@
# Auto detect text files and perform LF normalization
* text=auto
# Custom for Visual Studio
*.cs diff=csharp
*.sln merge=union
*.csproj merge=union
*.vbproj merge=union
*.fsproj merge=union
*.dbproj merge=union
# Standard to msysgit
*.doc diff=astextplain
*.DOC diff=astextplain
*.docx diff=astextplain
*.DOCX diff=astextplain
*.dot diff=astextplain
*.DOT diff=astextplain
*.pdf diff=astextplain
*.PDF diff=astextplain
*.rtf diff=astextplain
*.RTF diff=astextplain

215
.gitignore vendored Normal file
View file

@ -0,0 +1,215 @@
#################
## Eclipse
#################
*.pydevproject
.project
.metadata
bin/
tmp/
*.tmp
*.bak
*.swp
*~.nib
local.properties
.classpath
.settings/
.loadpath
# External tool builders
.externalToolBuilders/
# Locally stored "Eclipse launch configurations"
*.launch
# CDT-specific
.cproject
# PDT-specific
.buildpath
#################
## Visual Studio
#################
## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.
# User-specific files
*.suo
*.user
*.sln.docstates
# Build results
[Dd]ebug/
[Rr]elease/
x64/
build/
[Bb]in/
[Oo]bj/
# MSTest test Results
[Tt]est[Rr]esult*/
[Bb]uild[Ll]og.*
*_i.c
*_p.c
*.ilk
*.meta
*.obj
*.pch
*.pdb
*.pgc
*.pgd
*.rsp
*.sbr
*.tlb
*.tli
*.tlh
*.tmp
*.tmp_proj
*.log
*.vspscc
*.vssscc
.builds
*.pidb
*.log
*.scc
# Visual C++ cache files
ipch/
*.aps
*.ncb
*.opensdf
*.sdf
*.cachefile
# Visual Studio profiler
*.psess
*.vsp
*.vspx
# Guidance Automation Toolkit
*.gpState
# ReSharper is a .NET coding add-in
_ReSharper*/
*.[Rr]e[Ss]harper
# TeamCity is a build add-in
_TeamCity*
# DotCover is a Code Coverage Tool
*.dotCover
# NCrunch
*.ncrunch*
.*crunch*.local.xml
# Installshield output folder
[Ee]xpress/
# DocProject is a documentation generator add-in
DocProject/buildhelp/
DocProject/Help/*.HxT
DocProject/Help/*.HxC
DocProject/Help/*.hhc
DocProject/Help/*.hhk
DocProject/Help/*.hhp
DocProject/Help/Html2
DocProject/Help/html
# Click-Once directory
publish/
# Publish Web Output
*.Publish.xml
*.pubxml
# NuGet Packages Directory
## TODO: If you have NuGet Package Restore enabled, uncomment the next line
#packages/
# Windows Azure Build Output
csx
*.build.csdef
# Windows Store app package directory
AppPackages/
# Others
sql/
*.Cache
ClientBin/
[Ss]tyle[Cc]op.*
~$*
*~
*.dbmdl
*.[Pp]ublish.xml
*.pfx
*.publishsettings
# RIA/Silverlight projects
Generated_Code/
# Backup & report files from converting an old project file to a newer
# Visual Studio version. Backup files are not needed, because we have git ;-)
_UpgradeReport_Files/
Backup*/
UpgradeLog*.XML
UpgradeLog*.htm
# SQL Server files
App_Data/*.mdf
App_Data/*.ldf
#############
## Windows detritus
#############
# Windows image file caches
Thumbs.db
ehthumbs.db
# Folder config file
Desktop.ini
# Recycle Bin used on file shares
$RECYCLE.BIN/
# Mac crap
.DS_Store
#############
## Python
#############
*.py[co]
# Packages
*.egg
*.egg-info
dist/
build/
eggs/
parts/
var/
sdist/
develop-eggs/
.installed.cfg
# Installer logs
pip-log.txt
# Unit test / coverage reports
.coverage
.tox
#Translations
*.mo
#Mr Developer
.mr.developer.cfg

40
ReadMe.txt Normal file
View file

@ -0,0 +1,40 @@
========================================================================
CONSOLE APPLICATION : hdnes Project Overview
========================================================================
AppWizard has created this hdnes application for you.
This file contains a summary of what you will find in each of the files that
make up your hdnes application.
hdnes.vcxproj
This is the main project file for VC++ projects generated using an Application Wizard.
It contains information about the version of Visual C++ that generated the file, and
information about the platforms, configurations, and project features selected with the
Application Wizard.
hdnes.vcxproj.filters
This is the filters file for VC++ projects generated using an Application Wizard.
It contains information about the association between the files in your project
and the filters. This association is used in the IDE to show grouping of files with
similar extensions under a specific node (for e.g. ".cpp" files are associated with the
"Source Files" filter).
hdnes.cpp
This is the main application source file.
/////////////////////////////////////////////////////////////////////////////
Other standard files:
StdAfx.h, StdAfx.cpp
These files are used to build a precompiled header (PCH) file
named hdnes.pch and a precompiled types file named StdAfx.obj.
/////////////////////////////////////////////////////////////////////////////
Other notes:
AppWizard uses "TODO:" comments to indicate parts of the source code you
should add to or customize.
/////////////////////////////////////////////////////////////////////////////

797
apu.cpp Normal file
View file

@ -0,0 +1,797 @@
#include "StdAfx.h"
#include "apu.h"
#include "sysState.h"
apu::apu(void)
{
lcLoadValue[0x00] = 10;
lcLoadValue[0x01] = 254;
lcLoadValue[0x02] = 20;
lcLoadValue[0x03] = 2;
lcLoadValue[0x04] = 40;
lcLoadValue[0x05] = 4;
lcLoadValue[0x06] = 80;
lcLoadValue[0x07] = 6;
lcLoadValue[0x08] = 160;
lcLoadValue[0x09] = 8;
lcLoadValue[0x0A] = 60;
lcLoadValue[0x0B] = 10;
lcLoadValue[0x0C] = 14;
lcLoadValue[0x0D] = 12;
lcLoadValue[0x0E] = 26;
lcLoadValue[0x0F] = 14;
lcLoadValue[0x10] = 12;
lcLoadValue[0x11] = 16;
lcLoadValue[0x12] = 24;
lcLoadValue[0x13] = 18;
lcLoadValue[0x14] = 48;
lcLoadValue[0x15] = 20;
lcLoadValue[0x16] = 96;
lcLoadValue[0x17] = 22;
lcLoadValue[0x18] = 192;
lcLoadValue[0x19] = 24;
lcLoadValue[0x1A] = 72;
lcLoadValue[0x1B] = 26;
lcLoadValue[0x1C] = 16;
lcLoadValue[0x1D] = 28;
lcLoadValue[0x1E] = 32;
lcLoadValue[0x1F] = 30;
dutyCycle[0][0] = 0;
dutyCycle[0][1] = 1;
dutyCycle[0][2] = 0;
dutyCycle[0][3] = 0;
dutyCycle[0][4] = 0;
dutyCycle[0][5] = 0;
dutyCycle[0][6] = 0;
dutyCycle[0][7] = 0;
dutyCycle[1][0] = 0;
dutyCycle[1][1] = 1;
dutyCycle[1][2] = 1;
dutyCycle[1][3] = 0;
dutyCycle[1][4] = 0;
dutyCycle[1][5] = 0;
dutyCycle[1][6] = 0;
dutyCycle[1][7] = 0;
dutyCycle[2][0] = 0;
dutyCycle[2][1] = 1;
dutyCycle[2][2] = 1;
dutyCycle[2][3] = 1;
dutyCycle[2][4] = 1;
dutyCycle[2][5] = 0;
dutyCycle[2][6] = 0;
dutyCycle[2][7] = 0;
dutyCycle[3][0] = 1;
dutyCycle[3][1] = 0;
dutyCycle[3][2] = 0;
dutyCycle[3][3] = 1;
dutyCycle[3][4] = 1;
dutyCycle[3][5] = 1;
dutyCycle[3][6] = 1;
dutyCycle[3][7] = 1;
triCycle[0] = 15;
triCycle[1] = 14;
triCycle[2] = 13;
triCycle[3] = 12;
triCycle[4] = 11;
triCycle[5] = 10;
triCycle[6] = 9;
triCycle[7] = 8;
triCycle[8] = 7;
triCycle[9] = 6;
triCycle[10] = 5;
triCycle[11] = 4;
triCycle[12] = 3;
triCycle[13] = 2;
triCycle[14] = 1;
triCycle[15] = 0;
triCycle[16] = 0;
triCycle[17] = 1;
triCycle[18] = 2;
triCycle[19] = 3;
triCycle[20] = 4;
triCycle[21] = 5;
triCycle[22] = 6;
triCycle[23] = 7;
triCycle[24] = 8;
triCycle[25] = 9;
triCycle[26] = 10;
triCycle[27] = 11;
triCycle[28] = 12;
triCycle[29] = 13;
triCycle[30] = 14;
triCycle[31] = 15;
noiseLen[0] = 4;
noiseLen[1] = 8;
noiseLen[2] = 16;
noiseLen[3] = 32;
noiseLen[4] = 64;
noiseLen[5] = 96;
noiseLen[6] = 128;
noiseLen[7] = 160;
noiseLen[8] = 202;
noiseLen[9] = 254;
noiseLen[10] = 380;
noiseLen[11] = 508;
noiseLen[12] = 762;
noiseLen[13] = 1016;
noiseLen[14] = 2034;
noiseLen[15] = 4068;
dmcRate[0] = 428 / 2;
dmcRate[1] = 380 / 2;
dmcRate[2] = 340 / 2;
dmcRate[3] = 320 / 2;
dmcRate[4] = 286 / 2;
dmcRate[5] = 254 / 2;
dmcRate[6] = 226 / 2;
dmcRate[7] = 214 / 2;
dmcRate[8] = 190 / 2;
dmcRate[9] = 160 / 2;
dmcRate[10] = 142 / 2;
dmcRate[11] = 128 / 2;
dmcRate[12] = 106 / 2;
dmcRate[13] = 84 / 2;
dmcRate[14] = 72 / 2;
dmcRate[15] = 54 / 2;
dmcPeriodCounter = 0;
apuBufferCounter = 0;
apuBufferFilled = 0;
for(int i = 0; i < 5; ++i){
apuBuffer[i][0] = 0;
apuCounterAcc[i] = 0;
}
bufferFillClock = 0;
newDMCCycle = true;
}
apu::~apu(void)
{
}
void apu::init(){
reset();
}
void apu::reset(){
curCycle = 0;
fcCycleCounter = 0;
write4000(0);
write4001(0);
write4002(0);
write4003(0);
write4004(0);
write4005(0);
write4006(0);
write4007(0);
write4008(0);
write400A(0);
write400B(0);
write400C(0);
write400E(0);
write400F(0);
write4010(0);
write4011(0);
write4012(0);
write4013(0);
write4015(0);
write4017(0);
sq1Env.counter = 0;
sq2Env.counter = 0;
noiseEnv.counter = 0;
dmcCounter = 0;
dmcBytes = 0;
sampleBuffer = 0;
bitsRemaining = 0;
shiftReg = 1;
sq1Sweep.targetPeriod = 0;
sq2Sweep.targetPeriod = 0;
}
void apu::runCatchUp(unsigned int cycle){
while(curCycle < cycle){
if(fcMode5Step){
switch (fcCycleCounter){
case FC5STEP1:
clockFC1();
clockFC2();
break;
case FC5STEP2:
clockFC1();
break;
case FC5STEP3:
clockFC1();
clockFC2();
break;
case FC5STEP4:
clockFC1();
break;
case FC5STEP5:
fcCycleCounter = -1;
break;
}
}
else{
switch (fcCycleCounter){
case FC4STEP1:
clockFC1();
break;
case FC4STEP2:
clockFC1();
clockFC2();
break;
case FC4STEP3:
clockFC1();
break;
case FC4STEP4:
clockFC1();
clockFC2();
fcCycleCounter = -1;
if(!fcInterruptDisable) signalIRQ = true;
break;
}
}
if ((curCycle & 0x01) == 0x00) {
//run at even cpu cycles
//clockSq1Timer();
//clockSq2Timer();
clockDMC();
}
++bufferFillClock;
if(bufferFillClock >= mixer->clockPerSample){
fillAPUBuffer();
bufferFillClock -= mixer->clockPerSample;
}
if(fcCycleCounter == -1){
mixer->resumeLastMusic();
}
++curCycle;
++fcCycleCounter;
}
if(signalIRQ){
cpuCore->setIRQ();
}
}
Uint8 apu::readReg(Uint8 address){
return (address == 0x15? read4015(): 0);
}
void apu::writeReg(Uint8 address, Uint8 data){
//if(cpuCore->runLog){
// char tps[64];
// sprintf(tps, " address:%02X data:%02X \n", address, data );
// cpuCore->myfile << tps;
//}
switch(address){
case 0:
write4000(data);
break;
case 1:
write4001(data);
break;
case 2:
write4002(data);
break;
case 3:
write4003(data);
break;
case 4:
write4004(data);
break;
case 5:
write4005(data);
break;
case 6:
write4006(data);
break;
case 7:
write4007(data);
break;
case 8:
write4008(data);
break;
case 0x0A:
write400A(data);
break;
case 0x0B:
write400B(data);
break;
case 0x0C:
write400C(data);
break;
case 0x0E:
write400E(data);
break;
case 0x0F:
write400F(data);
break;
case 0x10:
write4010(data);
break;
case 0x11:
write4011(data);
break;
case 0x12:
write4012(data);
break;
case 0x13:
write4013(data);
break;
case 0x15:
write4015(data);
break;
case 0x17:
write4017(data);
break;
}
}
//sq1
void apu::write4000(Uint8 data){
reg[0] = data;
sq1Duty = (data >> 6);
lc[CHANNEL_SQUARE1].halted = ((data & 0x20) != 0);
sq1Env.loop = lc[CHANNEL_SQUARE1].halted;
sq1Env.disableDecay = ((data & 0x10) != 0);
if(sq1Env.disableDecay)
sq1Env.constVol = (data & 0x0F);
else
sq1Env.dividerPeriod = ((data & 0x0F) + 1);
vol[CHANNEL_SQUARE1] = envVol(sq1Env);
}
void apu::write4001(Uint8 data){
reg[1] = data;
sq1Sweep.enabled = ((data & 0x80) != 0);
sq1Sweep.dividerPeriod = ((data >> 4) & 0x07) + 1;
sq1Sweep.negate = ((data & 0x08) != 0);
sq1Sweep.shift = (data & 0x07);
sq1Sweep.reload = true;
}
void apu::write4002(Uint8 data){
reg[2] = data;
channelPeriod[CHANNEL_SQUARE1] &= 0x0700;
channelPeriod[CHANNEL_SQUARE1] |= data;
sq1Timer = channelPeriod[CHANNEL_SQUARE1];
}
void apu::write4003(Uint8 data){
reg[3] = data;
channelPeriod[CHANNEL_SQUARE1] &= 0x00FF;
channelPeriod[CHANNEL_SQUARE1] |= ((data & 0x07) << 8);
sq1Timer = channelPeriod[CHANNEL_SQUARE1];
lc[CHANNEL_SQUARE1].length = lcLoadValue[data >> 3];
if(lc[CHANNEL_SQUARE1].enabled){
lc[CHANNEL_SQUARE1].currentVal = lc[CHANNEL_SQUARE1].length;
sq1Env.startFlag = true;
}
else{
lc[CHANNEL_SQUARE1].currentVal = 0;
}
}
void apu::write4004(Uint8 data){
reg[4] = data;
sq2Duty = (data >> 6);
lc[CHANNEL_SQUARE2].halted = ((data & 0x20) != 0);
sq2Env.loop = lc[CHANNEL_SQUARE2].halted;
sq2Env.disableDecay = ((data & 0x10) != 0);
if(sq2Env.disableDecay)
sq2Env.constVol = (data & 0x0F);
else
sq2Env.dividerPeriod = ((data & 0x0F) + 1);
vol[CHANNEL_SQUARE2] = envVol(sq2Env);
}
void apu::write4005(Uint8 data){
reg[5] = data;
sq2Sweep.enabled = ((data & 0x80) != 0);
sq2Sweep.dividerPeriod = ((data >> 4) & 0x07) + 1;
sq2Sweep.negate = ((data & 0x08) != 0);
sq2Sweep.shift = (data & 0x07);
sq2Sweep.reload = true;
}
void apu::write4006(Uint8 data){
reg[6] = data;
channelPeriod[CHANNEL_SQUARE2] &= 0x0700;
channelPeriod[CHANNEL_SQUARE2] |= data;
sq2Timer = channelPeriod[CHANNEL_SQUARE2];
}
void apu::write4007(Uint8 data){
reg[7] = data;
channelPeriod[CHANNEL_SQUARE2] &= 0x00FF;
channelPeriod[CHANNEL_SQUARE2] |= ((data & 0x07) << 8);
sq2Timer = channelPeriod[CHANNEL_SQUARE2];
lc[CHANNEL_SQUARE2].length = lcLoadValue[data >> 3];
if(lc[CHANNEL_SQUARE2].enabled){
lc[CHANNEL_SQUARE2].currentVal = lc[CHANNEL_SQUARE2].length;
sq2Env.startFlag = true;
}
else{
lc[CHANNEL_SQUARE2].currentVal = 0;
}
}
void apu::write4008(Uint8 data){
reg[8] = data;
lc[CHANNEL_TRIANGLE].halted = ((data & 0x80) != 0);
linearCounter.enabled = ((data & 0x80) != 0);
linearCounter.length = (data & 0x7F);
if(linearCounter.enabled) linearCounter.currentVal = linearCounter.length;
}
void apu::write400A(Uint8 data){
reg[0x0A] = data;
channelPeriod[CHANNEL_TRIANGLE] &= 0xFF00;
channelPeriod[CHANNEL_TRIANGLE] |= data;
}
void apu::write400B(Uint8 data){
reg[0x0B] = data;
lc[CHANNEL_TRIANGLE].length = lcLoadValue[data >> 3];
if(lc[CHANNEL_TRIANGLE].enabled) lc[CHANNEL_TRIANGLE].currentVal = lc[CHANNEL_TRIANGLE].length;
linearCounter.halted = true;
channelPeriod[CHANNEL_TRIANGLE] &= 0x00FF;
channelPeriod[CHANNEL_TRIANGLE] |= ((data & 0x07) << 8);
}
void apu::write400C(Uint8 data){
reg[0x0C] = data;
lc[CHANNEL_NOISE].halted = ((data & 0x20) != 0);
noiseEnv.loop = lc[CHANNEL_NOISE].halted;
noiseEnv.disableDecay = ((data & 0x10) != 0);
if(noiseEnv.disableDecay)
noiseEnv.constVol = (data & 0x0F);
else
noiseEnv.dividerPeriod = ((data & 0x0F) + 1);
vol[CHANNEL_NOISE] = envVol(noiseEnv);
}
void apu::write400E(Uint8 data){
reg[0x0E] = data;
noiseModeFlag = ((data & 0x80) != 0);
channelPeriod[CHANNEL_NOISE] = noiseLen[data & 0x0F];
}
void apu::write400F(Uint8 data){
reg[0x0F] = data;
lc[CHANNEL_NOISE].length = lcLoadValue[data >> 3];
if(lc[CHANNEL_NOISE].enabled) lc[CHANNEL_NOISE].currentVal = lc[CHANNEL_NOISE].length;
noiseEnv.startFlag = true;
}
void apu::shiftNoiseReg(){
Uint16 feedBack;
if(noiseModeFlag)
feedBack = ((shiftReg & 0x0001) ^ ((shiftReg & 0x0040) >> 6));
else
feedBack = ((shiftReg & 0x0001) ^ ((shiftReg & 0x0002) >> 1));
shiftReg = ((shiftReg >> 1) | (feedBack << 14));
}
void apu::write4010(Uint8 data){
reg[10] = data;
irqEnabled = ((data & 0x80) != 0);
if(!irqEnabled){
signalIRQ = false;
}
dmcLoop = ((data & 0x40) != 0);
dmcOutPutRate = data & 0x0F;
channelPeriod[CHANNEL_DMC] = dmcRate[dmcOutPutRate];
dmcPeriodCounter = 0;
}
void apu::write4011(Uint8 data){
reg[11] = data;
dmcCounter = data & 0x7F;
}
void apu::write4012(Uint8 data){
reg[12] = data;
sampleAddress = (data << 6) | 0xC000;
newDMCCycle = true;
}
void apu::write4013(Uint8 data){
reg[13] = data;
sampleLength = (data << 4) | 0x01;
newDMCCycle = true;
}
void apu::write4015(Uint8 data){
reg[15] = data;
lc[CHANNEL_SQUARE1].enabled = ((data & 0x01) != 0);
lc[CHANNEL_SQUARE2].enabled = ((data & 0x02) != 0);
lc[CHANNEL_TRIANGLE].enabled = ((data & 0x04) != 0);
linearCounter.enabled = ((data & 0x04) != 0);
lc[CHANNEL_NOISE].enabled = ((data & 0x08) != 0);
dmcEnabled = ((data & 0x10) != 0);
if(!dmcEnabled){
dmcBytes = 0;
}
else if(dmcBytes == 0){
curAddress = sampleAddress;
dmcBytes = sampleLength;
newDMCCycle = true;
}
for(Uint8 i = 0; i < 4; ++i){
if(!lc[i].enabled) lc[i].currentVal = 0;
}
if(!linearCounter.enabled) linearCounter.currentVal = 0;
signalDMC = false;
}
Uint8 apu::read4015(){
reg[15] = 0x00;
if(signalDMC) reg[15] |= 0x80;
if(signalIRQ) reg[15] |= 0x40;
if(dmcBytes > 0) reg[15] |= 0x10;
if(lc[CHANNEL_NOISE].currentVal != 0) reg[15] |= 0x08;
if(lc[CHANNEL_TRIANGLE].currentVal != 0) reg[15] |= 0x04;
if(lc[CHANNEL_SQUARE2].currentVal != 0) reg[15] |= 0x02;
if(lc[CHANNEL_SQUARE1].currentVal != 0) reg[15] |= 0x01;
signalIRQ = false;
return reg[15];
}
void apu::clockFC1(){
clockEnv(sq1Env);
vol[CHANNEL_SQUARE1] = envVol(sq1Env);
clockEnv(sq2Env);
vol[CHANNEL_SQUARE2] = envVol(sq2Env);
clockEnv(noiseEnv);
vol[CHANNEL_NOISE] = envVol(noiseEnv);
clockLinear();
}
void apu::clockFC2(){
clockLC();
clockSweep1();
clockSweep2();
}
void apu::clockLC(){
for(Uint8 i = 0; i < 4; ++i){
if(lc[i].currentVal > 0 && !lc[i].halted) --(lc[i].currentVal);
}
}
Uint8 apu:: envVol(envelope e){
return (e.disableDecay? e.constVol:e.counter);
}
void apu::clockEnv(envelope &e){
if(e.startFlag){
e.startFlag = false;
e.counter = 15;
e.dividerCounter = e.dividerPeriod;
}
else{
--(e.dividerCounter);
if(e.dividerCounter == 0){
if(e.counter > 0)
--e.counter;
else if(e.loop)
e.counter = 15;
e.dividerCounter = e.dividerPeriod;
}
}
}
void apu::clockSweep1(){
Uint8 oldCounter;
Uint16 dif;
bool adjustPeriod;
adjustPeriod = false;
oldCounter = sq1Sweep.dividerCounter;
if(sq1Sweep.reload){
sq1Sweep.reload = false;
sq1Sweep.dividerCounter = sq1Sweep.dividerPeriod;
if(oldCounter == 0){
adjustPeriod = true;
}
}
else if(sq1Sweep.dividerCounter > 0){
--(sq1Sweep.dividerCounter);
}
else if(sq1Sweep.enabled){
sq1Sweep.dividerCounter = sq1Sweep.dividerPeriod;
adjustPeriod = true;
}
if(adjustPeriod){
dif = (channelPeriod[CHANNEL_SQUARE1] >> sq1Sweep.shift);
if(sq1Sweep.negate)
sq1Sweep.targetPeriod = channelPeriod[CHANNEL_SQUARE1] - (dif - 1);
else
sq1Sweep.targetPeriod = channelPeriod[CHANNEL_SQUARE1] + dif;
if(channelPeriod[CHANNEL_SQUARE1] >= 8 && sq1Sweep.targetPeriod <= 0x7FF && sq1Sweep.shift > 0){
channelPeriod[CHANNEL_SQUARE1] = sq1Sweep.targetPeriod;
}
}
}
void apu::clockSweep2(){
Uint8 oldCounter;
Uint16 dif;
bool adjustPeriod;
adjustPeriod = false;
oldCounter = sq2Sweep.dividerCounter;
if(sq2Sweep.reload){
sq2Sweep.reload = false;
sq2Sweep.dividerCounter = sq2Sweep.dividerPeriod;
if(oldCounter == 0){
adjustPeriod = true;
}
}
else if(sq2Sweep.dividerCounter > 0){
--(sq2Sweep.dividerCounter);
}
else if(sq2Sweep.enabled){
sq2Sweep.dividerCounter = sq2Sweep.dividerPeriod;
adjustPeriod = true;
}
if(adjustPeriod){
dif = (channelPeriod[CHANNEL_SQUARE2] >> sq2Sweep.shift);
if(sq2Sweep.negate)
sq2Sweep.targetPeriod = channelPeriod[CHANNEL_SQUARE2] - dif;
else
sq2Sweep.targetPeriod = channelPeriod[CHANNEL_SQUARE2] + dif;
if(channelPeriod[CHANNEL_SQUARE2] >= 8 && sq2Sweep.targetPeriod <= 0x7FF && sq2Sweep.shift > 0){
channelPeriod[CHANNEL_SQUARE2] = sq2Sweep.targetPeriod;
}
}
}
void apu::write4017(Uint8 data){
fcMode5Step = ((data & 0x80) != 0);
fcInterruptDisable = ((data & 0x40) != 0);
if(fcInterruptDisable) signalIRQ = false;
fcCycleCounter = -2;
if(fcMode5Step){
clockFC1();
clockFC2();
}
}
void apu::clockLinear(){
if(linearCounter.halted)
linearCounter.currentVal = linearCounter.length;
else if(linearCounter.currentVal != 0)
--(linearCounter.currentVal);
if(!linearCounter.enabled) linearCounter.halted = false;
}
void apu::clockDMC(){
if(dmcEnabled){
++dmcPeriodCounter;
if(dmcPeriodCounter >= channelPeriod[CHANNEL_DMC]){
if(!dmcSilence){
if(((sampleBuffer & 0x01) == 0) && dmcCounter > 1){
dmcCounter -= 2;
}
else if(((sampleBuffer & 0x01) != 0) && dmcCounter < 126){
dmcCounter += 2;
}
sampleBuffer >>= 1;
--bitsRemaining;
if(bitsRemaining == 0) newDMCCycle = true;
}
if(newDMCCycle){
newDMCCycle = false;
dmcSilence = true;
if(dmcEnabled){
if(dmcBytes > 0){
sampleBuffer = memDat->cpuBusRead(curAddress);
if(curAddress == 0xFFFF){
curAddress = 0x8000;
}
else{
++curAddress;
}
--dmcBytes;
if(dmcBytes == 0){
if(dmcLoop){
curAddress = sampleAddress;
dmcBytes = sampleLength;
}
else if(irqEnabled){
signalIRQ = true;
}
}
dmcSilence = false;
}
}
bitsRemaining = 8;
}
dmcPeriodCounter = 0;
}
}
apuCounterAcc[CHANNEL_DMC] += apuAccAR[dmcCounter];
}
void apu::clockSq1Timer(){
if(sq1Timer > 0){
--sq1Timer;
}
else{
sq1Timer = channelPeriod[CHANNEL_SQUARE1];
++sq1SeqCounter;
if(sq1SeqCounter >= 8) sq1SeqCounter = 0;
}
if(lc[CHANNEL_SQUARE1].enabled
&& (lc[CHANNEL_SQUARE1].currentVal > 0)
&& channelPeriod[CHANNEL_SQUARE1] >= 8
&& sq1Sweep.targetPeriod <= 0x07FF
&& dutyCycle[sq1Duty][sq1SeqCounter]){
apuCounterAcc[CHANNEL_SQUARE1] += apuAccAR[(sq1Env.disableDecay? sq1Env.constVol:sq1Env.counter)];
}
}
void apu::clockSq2Timer(){
if(sq2Timer > 0){
--sq2Timer;
}
else{
sq2Timer = channelPeriod[CHANNEL_SQUARE2];
++sq2SeqCounter;
if(sq2SeqCounter >= 8) sq2SeqCounter = 0;
}
if(lc[CHANNEL_SQUARE2].enabled
&& (lc[CHANNEL_SQUARE2].currentVal > 0)
&& channelPeriod[CHANNEL_SQUARE2] >= 8
&& sq2Sweep.targetPeriod <= 0x07FF
&& dutyCycle[sq2Duty][sq2SeqCounter]){
apuCounterAcc[CHANNEL_SQUARE2] += apuAccAR[(sq2Env.disableDecay? sq2Env.constVol:sq2Env.counter)];
}
}
void apu::fillAPUBuffer(){
for(int i = 0; i < 5; ++i){
apuBuffer[i][(apuBufferCounter + apuBufferFilled) % APU_BUFFER_SIZE] = apuCounterAcc[i];
apuCounterAcc[i] = 0;
}
++apuBufferFilled;
if (apuBufferFilled >= APU_BUFFER_SIZE) {
apuBufferCounter = ((apuBufferCounter + apuBufferFilled)) % APU_BUFFER_SIZE;
apuBufferFilled = APU_BUFFER_SIZE;
}
}
void apu::resetCycleCount(){
curCycle = curCycle % 341;
}
void apu::saveState(fstream* statefile){
statefile->write((char *)(this), sizeof(apu));
}
void apu::loadState(fstream* statefile){
statefile->read((char *)(this), sizeof(apu));
}

170
apu.h Normal file
View file

@ -0,0 +1,170 @@
#pragma once
#define FC4STEP1 7456 //3728 * 2 cpu cycles
#define FC4STEP2 14912 //7456 * 2
#define FC4STEP3 22370 //11185 * 2
#define FC4STEP4 29828 //14914 * 2
#define FC5STEP1 7456 //3728 * 2 cpu cycles
#define FC5STEP2 14912 //7456 * 2
#define FC5STEP3 22370 //11185 * 2
#define FC5STEP4 29828 //14914 * 2
#define FC5STEP5 37280 //18640 * 2
#define CHANNEL_SQUARE1 0
#define CHANNEL_SQUARE2 1
#define CHANNEL_TRIANGLE 2
#define CHANNEL_NOISE 3
#define CHANNEL_DMC 4
struct lenCounter{
bool enabled;
bool halted;
Uint16 currentVal;
Uint16 length;
};
struct envelope{
bool startFlag;
bool disableDecay;
bool loop;
Uint8 dividerPeriod;
Uint8 dividerCounter;
Uint8 counter;
Uint8 constVol;
};
struct sweep{
bool enabled;
bool reload;
Uint8 dividerPeriod;
Uint8 dividerCounter;
bool negate;
Uint8 shift;
Uint16 targetPeriod;
};
class apu
{
public:
Uint8 reg[0x16];
Uint32 curCycle;
lenCounter lc[5];
Uint16 channelPeriod[5];
Uint8 vol[5];
Uint8 lcLoadValue[0x20];
Uint8 dutyCycle[4][8];
Uint8 triCycle[32];
Uint16 noiseLen[16];
Uint16 dmcRate[16];
apu(void);
~apu(void);
void init();
void reset();
void runCatchUp(unsigned int cycle);
Uint8 readReg(Uint8 address);
void writeReg(Uint8 address, Uint8 data);
//sq1
envelope sq1Env;
sweep sq1Sweep;
Uint8 sq1Duty;
Uint8 sq1SeqCounter;
Uint16 sq1Timer;
void write4000(Uint8 data);
void write4001(Uint8 data);
void write4002(Uint8 data);
void write4003(Uint8 data);
//sq2
envelope sq2Env;
sweep sq2Sweep;
Uint8 sq2Duty;
Uint8 sq2SeqCounter;
Uint16 sq2Timer;
void write4004(Uint8 data);
void write4005(Uint8 data);
void write4006(Uint8 data);
void write4007(Uint8 data);
//triangle
lenCounter linearCounter;
void write4008(Uint8 data);
void write400A(Uint8 data);
void write400B(Uint8 data);
//noise
envelope noiseEnv;
bool noiseModeFlag;
Uint16 shiftReg;
void write400C(Uint8 data);
void write400E(Uint8 data);
void write400F(Uint8 data);
void shiftNoiseReg();
//DMC
bool irqEnabled;
bool dmcLoop;
Uint8 dmcCounter;
Uint8 dmcOutPutRate;
Uint16 sampleAddress;
Uint16 sampleLength;
Uint16 curAddress;
Uint8 sampleBuffer;
Uint8 bitsRemaining;
bool dmcSilence;
Uint16 dmcPeriodCounter;
bool newDMCCycle;
double dmcCounterAcc;
void write4010(Uint8 data);
void write4011(Uint8 data);
void write4012(Uint8 data);
void write4013(Uint8 data);
Uint8 apuBuffer[5][APU_BUFFER_SIZE];
Uint16 apuBufferCounter;
Uint16 apuBufferFilled;
double bufferFillClock;
double apuAccAR[256];
double apuCounterAcc[5];
//status
bool dmcEnabled;
bool signalDMC;
Uint16 dmcBytes;
void write4015(Uint8 data);
Uint8 read4015();
bool fcMode5Step;
bool signalIRQ;
bool fcInterruptDisable;
Sint16 fcCycleCounter;
void write4017(Uint8 data);
void clockFC1();
void clockFC2();
void clockLC();
void clockSweep1();
void clockSweep2();
void clockEnv(envelope &e);
void clockLinear();
void resetCycleCount();
void clockSq1Timer();
void clockSq2Timer();
void clockDMC();
void fillAPUBuffer();
Uint8 envVol(envelope e);
void saveState(fstream* statefile);
void loadState(fstream* statefile);
};

466
audio.cpp Normal file
View file

@ -0,0 +1,466 @@
#include "StdAfx.h"
#include "sysState.h"
void fill_audio(void *data,Uint8 *stream,int len)
{
Uint16 *buff;
int i;
int length;
buff = (Uint16*)stream;
double stepPerSample[5];
Uint8 vol[5];
Uint16 result[5];
////sq1
if(apuCore->lc[CHANNEL_SQUARE1].enabled && (apuCore->lc[CHANNEL_SQUARE1].currentVal > 0) && apuCore->channelPeriod[CHANNEL_SQUARE1] >= 8 && apuCore->sq1Sweep.targetPeriod <= 0x07FF){
vol[CHANNEL_SQUARE1] = (apuCore->sq1Env.disableDecay? apuCore->sq1Env.constVol:apuCore->sq1Env.counter);
//2 cpu clocks per apu clock, PERIOD + 1 apu clocks per sequence step
stepPerSample[CHANNEL_SQUARE1] = mixer->clockPerSample / (double)((apuCore->channelPeriod[CHANNEL_SQUARE1] + 1) * 2);
}
else{
vol[CHANNEL_SQUARE1] = 0;
}
//sq2
if(apuCore->lc[CHANNEL_SQUARE2].enabled && (apuCore->lc[CHANNEL_SQUARE2].currentVal > 0) && apuCore->channelPeriod[CHANNEL_SQUARE2] >= 8 && apuCore->sq2Sweep.targetPeriod <= 0x07FF){
vol[CHANNEL_SQUARE2] = (apuCore->sq2Env.disableDecay? apuCore->sq2Env.constVol:apuCore->sq2Env.counter);
stepPerSample[CHANNEL_SQUARE2] = mixer->clockPerSample / (double)((apuCore->channelPeriod[CHANNEL_SQUARE2] + 1) * 2);
}
else{
vol[CHANNEL_SQUARE2] = 0;
}
//tri
if(apuCore->lc[CHANNEL_TRIANGLE].enabled && (apuCore->lc[CHANNEL_TRIANGLE].currentVal > 0) && apuCore->linearCounter.currentVal > 0 && apuCore->channelPeriod[CHANNEL_TRIANGLE] > 1){
vol[CHANNEL_TRIANGLE] = 1;
stepPerSample[CHANNEL_TRIANGLE] = mixer->clockPerSample / ((double)(apuCore->channelPeriod[CHANNEL_TRIANGLE] + 1));
}
else{
vol[CHANNEL_TRIANGLE] = 0;
}
//noise
if(apuCore->lc[CHANNEL_NOISE].enabled && (apuCore->lc[CHANNEL_NOISE].currentVal > 0)){
vol[CHANNEL_NOISE] = (apuCore->noiseEnv.disableDecay? apuCore->noiseEnv.constVol:apuCore->noiseEnv.counter);
stepPerSample[CHANNEL_NOISE] = mixer->clockPerSample / (double)((apuCore->channelPeriod[CHANNEL_NOISE] + 1) * 2);
}
else{
vol[CHANNEL_NOISE] = 0;
}
for(i = 0; i < 4; ++i){
if(stepPerSample[i] != mixer->lastFreq[i]){
mixer->step[i] = 0.0;
mixer->lastFreq[i] = stepPerSample[i];
}
}
buff = (Uint16*)stream;
//2 bytes to 1 16 bits sample
length = len / 2;
for(i = 0; i < length; i += 2){
if(vol[CHANNEL_SQUARE1] > 0){
result[CHANNEL_SQUARE1] = (apuCore->dutyCycle[apuCore->sq1Duty][(short)(mixer->step[CHANNEL_SQUARE1])] ? vol[CHANNEL_SQUARE1] : 0);
mixer->step[CHANNEL_SQUARE1] += stepPerSample[CHANNEL_SQUARE1];
while(mixer->step[CHANNEL_SQUARE1] >= 8.0){
mixer->step[CHANNEL_SQUARE1] -= 8.0;
}
}
else{
result[CHANNEL_SQUARE1] = 0;
}
if(vol[CHANNEL_SQUARE2] > 0){
result[CHANNEL_SQUARE2] = (apuCore->dutyCycle[apuCore->sq2Duty][(short)(mixer->step[CHANNEL_SQUARE2])] ? vol[CHANNEL_SQUARE2] : 0);
mixer->step[CHANNEL_SQUARE2] += stepPerSample[CHANNEL_SQUARE2];
while(mixer->step[CHANNEL_SQUARE2] >= 8.0){
mixer->step[CHANNEL_SQUARE2] -= 8.0;
}
}
else{
result[CHANNEL_SQUARE2] = 0;
}
if(vol[CHANNEL_TRIANGLE] > 0){
result[CHANNEL_TRIANGLE] = apuCore->triCycle[(short)(mixer->step[CHANNEL_TRIANGLE])];
mixer->step[CHANNEL_TRIANGLE] += stepPerSample[CHANNEL_TRIANGLE];
while(mixer->step[CHANNEL_TRIANGLE] >= 32.0){
mixer->step[CHANNEL_TRIANGLE] -= 32.0;
}
}
else{
result[CHANNEL_TRIANGLE] = 0;
}
if(vol[CHANNEL_NOISE] > 0){
result[CHANNEL_NOISE] = ((apuCore->shiftReg & 0x0001) == 0x000? vol[CHANNEL_NOISE]:0);
mixer->step[CHANNEL_NOISE] += stepPerSample[CHANNEL_NOISE];
while(mixer->step[CHANNEL_NOISE] >= 1.0){
apuCore->shiftNoiseReg();
mixer->step[CHANNEL_NOISE] -= 1.0;
}
}
else{
result[CHANNEL_NOISE] = 0;
}
//always output counter value
//result[CHANNEL_SQUARE1] = apuCore->apuBuffer[CHANNEL_SQUARE1][apuCore->apuBufferCounter];
//result[CHANNEL_SQUARE2] = apuCore->apuBuffer[CHANNEL_SQUARE2][apuCore->apuBufferCounter];
result[CHANNEL_DMC] = apuCore->apuBuffer[CHANNEL_DMC][apuCore->apuBufferCounter];
if(apuCore->apuBufferFilled > 1){
++(apuCore->apuBufferCounter);
--(apuCore->apuBufferFilled);
if(apuCore->apuBufferCounter >= APU_BUFFER_SIZE){
apuCore->apuBufferCounter -= APU_BUFFER_SIZE;
}
}
buff[i] = 492 * (result[CHANNEL_SQUARE1] + result[CHANNEL_SQUARE2]) + 557 * result[CHANNEL_TRIANGLE] + 323 * result[CHANNEL_NOISE] + 219 * result[CHANNEL_DMC];
buff[i + 1] = buff[i];
}
}
void setReadyResumeLastMusic(int channel){
mixer->readyResumeLastMusic = true;
}
void audio::init(){
Mix_Init(MIX_INIT_OGG | MIX_INIT_MP3);
Mix_OpenAudio(SAMPLE_RATE, AUDIO_U16SYS, 2, AUDIO_BUFFER_SIZE);
clockPerSample = 1789773.0 / (double)SAMPLE_RATE;
for(int i = 0; i < 256; ++i){
apuCore->apuAccAR[i] = ((float)i) * 2.0 / clockPerSample;
}
for(int i = 0; i < 5; ++i){
step[i] = 0;
lastFreq[i] = 0;
}
Mix_HookMusic(fill_audio, NULL);
playingMP3 = -1;
playingChannel = -1;
readyResumeLastMusic = false;
ReadAudioPack();
string filename;
music.clear();
for(unsigned int i = 0; i < mp3List.size(); ++i){
filename = getHDPackPath() + string("\\") + mp3List[i];
music.push_back(Mix_LoadWAV(filename.c_str()));
}
}
audio::audio(void)
{
usePack = true;
playingMP3 = -1;
playingChannel = -1;
for(unsigned int i = 0; i < music.size(); ++i){
Mix_FreeChunk(music[i]);
}
music.clear();
}
audio::~audio(void)
{
if(playingMP3 >= 0){
Mix_HaltChannel(playingChannel);
}
for(unsigned int i = 0; i < music.size(); ++i){
Mix_FreeChunk(music[i]);
}
playingMP3 = -1;
Mix_HaltMusic();
Mix_CloseAudio();
Mix_Quit();
}
void audio::ReadAudioPack(){
string path = getHDPackPath();
DWORD ftyp = GetFileAttributesA(path.c_str());
if (ftyp & FILE_ATTRIBUTE_DIRECTORY){
//read the file
fstream inifile;
string line;
inifile.open(path + "\\audio.txt", ios::in);
if (inifile.is_open()){
mp3List.clear();
musicList.clear();
while ( inifile.good() ){
std::getline(inifile, line);
if(line.substr(0, 5) == "<mp3>"){
//read a mp3 file
string mp3Name = line.substr(5, string::npos);
mp3List.push_back(mp3Name);
}
else if(line.substr(0, 7) == "<music>"){
vector<string> lineTokens;
split(line.substr(7, string::npos), ',', lineTokens);
if (lineTokens.size() >= 8) {
musicPiece b;
b.priority = stoi(lineTokens[0]);
b.ramAddress = stoi(lineTokens[1], nullptr, 16);
b.hasCheck = (lineTokens[2] == "Y");
b.checkValue = stoi(lineTokens[3], nullptr, 16);
b.hasReplace = (lineTokens[4] == "Y");
b.replaceValue = stoi(lineTokens[5], nullptr, 16);
b.playType = stoi(lineTokens[6]);
b.mp3Idx = stoi(lineTokens[7]);
if(lineTokens.size() >= 9){
b.conditions = lineTokens[8];
}
if(lineTokens.size() >= 10){
b.gotoNext = (lineTokens[9] == "Y");
}
else{
b.gotoNext = false;
}
compileCondition(b);
musicList.push_back(b);
}
}
}
inifile.close();
}
}
}
void audio::SaveAudioPack(){
//get directory and check exists
string path = getHDPackPath();
_mkdir(path.c_str());
DWORD ftyp = GetFileAttributesA(path.c_str());
if (ftyp & FILE_ATTRIBUTE_DIRECTORY){
string filename;
fstream logfile;
char tmpStr[20];
filename = path + "\\audio.txt";
logfile.open(filename, ios::out | ios::trunc);
if (logfile.is_open()){
for(unsigned int i = 0; i < mp3List.size(); ++i){
logfile << "<mp3>" + mp3List[i] + "\n";
}
for(unsigned int i = 0; i < musicList.size(); ++i){
musicPiece b = musicList[i];
logfile << "<music>" + to_string((long double)b.priority) + "," ;
sprintf_s(tmpStr,"%x",b.ramAddress);
logfile << tmpStr;
logfile << (b.hasCheck? ",Y,": ",N,");
sprintf_s(tmpStr,"%x",b.checkValue);
logfile << tmpStr;
logfile << (b.hasReplace? ",Y,": ",N,");
sprintf_s(tmpStr,"%x",b.replaceValue);
logfile << tmpStr;
logfile << "," + to_string((long double)b.playType) + ","
+ to_string((long double)b.mp3Idx) + ",";
logfile << b.conditions;
logfile << (b.gotoNext ? ",Y,": ",N,");
logfile << "\n";
}
logfile.close();
}
}
}
void audio::CleanAudioPack(){
for(unsigned int i = 0; i < music.size(); ++i){
Mix_FreeChunk(music[i]);
}
music.clear();
mp3List.clear();
musicList.clear();
}
void audio::resumeLastMusic(){
if(readyResumeLastMusic && playingChannel != -1){
Mix_Resume(playingChannel);
}
}
Uint8 audio::handleRAMWrite(Uint16 address, Uint8 data){
musicPiece b;
if(!usePack) return data;
for(unsigned int i = 0; i < musicList.size(); ++i){
b = musicList[i];
if(b.ramAddress == address){
if((b.hasCheck && b.checkValue == data) || !b.hasCheck){
bool conSat = true;
Uint16 vleft;
Uint16 vright;
for(unsigned int j = 0; j < b.conlist.size(); ++j){
switch (b.conlist[j].opTypeL){
case OP_TYPE_ADDRESS:
vleft = memDat->cpuRAM[b.conlist[j].operandL & 0x07FF];
break;
case OP_TYPE_VALUE:
vleft = b.conlist[j].operandL;
break;
case OP_TYPE_WRITE:
vleft = data;
break;
default:
vleft = 0;
break;
}
switch (b.conlist[j].opTypeR){
case OP_TYPE_ADDRESS:
vright = memDat->cpuRAM[b.conlist[j].operandR & 0x07FF];
break;
case OP_TYPE_VALUE:
vright = b.conlist[j].operandR;
break;
case OP_TYPE_WRITE:
vright = data;
break;
default:
vright = 0;
break;
}
switch(b.conlist[j].operatorC){
case OP_EQUALS_TO:
conSat = (conSat && (vleft == vright));
break;
case OP_GREATER_THAN:
conSat = (conSat && (vleft >= vright));
break;
case OP_LESS_THAN:
conSat = (conSat && (vleft <= vright));
break;
case OP_NOT_EQUAL:
conSat = (conSat && (vleft != vright));
break;
}
}
if(conSat && (playingMP3 != b.mp3Idx)){
if(playingMP3 >= 0 && b.mp3Idx != -2){
if(b.playType == 0 || b.playType ==1){
Mix_HaltChannel(playingChannel);
playingChannel = -1;
playingMP3 = b.mp3Idx;
}
else if(b.playType == 2){
Mix_Pause(playingChannel);
}
}
if(b.mp3Idx >= 0){
string filename;
filename = getHDPackPath() + string("\\") + mp3List[b.mp3Idx];
if(b.playType == 0 || b.playType ==1){
playingChannel = Mix_PlayChannel(-1, music[b.mp3Idx], (b.playType == 0 ? -1 : 0));
playingMP3 = b.mp3Idx;
}
else {
//play on another channel
int difChannel = Mix_PlayChannel(-1, music[b.mp3Idx], 0);
if(b.playType == 2){
//resume when finish
Mix_ChannelFinished(setReadyResumeLastMusic);
}
}
}
}
if(!b.gotoNext){
return (b.hasReplace ? b.replaceValue : data);
}
}
}
}
return data;
}
void audio::readConfig(string value){
vector<string> lineTokens;
split(value, ',', lineTokens);
if (lineTokens[0].compare("usepack") == 0) {
usePack = (lineTokens[1].compare("Y") == 0);
}
}
void audio::saveConfig(fstream* inifile){
(*inifile) << "audio:usepack," + string(usePack ? "Y":"N") + "\n";
}
void audio::compileCondition(musicPiece& m){
vector<string> lineTokens;
size_t found;
string leftToken;
string rightToken;
string cOp;
string tmpStr;
musicCondition c;
m.conlist.clear();
split(removeSpace(m.conditions), ';', lineTokens);
for(unsigned int i = 0; i < lineTokens.size(); ++i){
found = lineTokens[i].find_last_of("=");
if(found != string::npos && found > 3){
rightToken = lineTokens[i].substr(found+1);
leftToken = lineTokens[i].substr(0, found - 1);
cOp = lineTokens[i].substr(found - 1, 1);
if(cOp.compare("=") == 0) c.operatorC = OP_EQUALS_TO;
if(cOp.compare(">") == 0) c.operatorC = OP_GREATER_THAN;
if(cOp.compare("<") == 0) c.operatorC = OP_LESS_THAN;
if(cOp.compare("!") == 0) c.operatorC = OP_NOT_EQUAL;
tmpStr = rightToken.substr(0, 1);
tmpStr = rightToken.substr(0, 1);
if ((tmpStr.compare("A") == 0)){
c.opTypeR = OP_TYPE_ADDRESS;
c.operandR = stoi(rightToken.substr(1), nullptr, 16);
}
else if ((tmpStr.compare("$") == 0)){
c.opTypeR = OP_TYPE_VALUE;
c.operandR = stoi(rightToken.substr(1), nullptr, 16);
}
else if ((tmpStr.compare("W") == 0)){
c.opTypeR = OP_TYPE_WRITE;
c.operandR = 0;
}
else{
c.opTypeR = OP_TYPE_UNDEFINE;
c.operandR = 0;
}
tmpStr = leftToken.substr(0, 1);
if ((tmpStr.compare("A") == 0)){
c.opTypeL = OP_TYPE_ADDRESS;
c.operandL = stoi(leftToken.substr(1), nullptr, 16);
}
else if ((tmpStr.compare("$") == 0)){
c.opTypeL = OP_TYPE_VALUE;
c.operandL = stoi(leftToken.substr(1), nullptr, 16);
}
else if ((tmpStr.compare("W") == 0)){
c.opTypeL = OP_TYPE_WRITE;
c.operandL = 0;
}
else{
c.opTypeL = OP_TYPE_UNDEFINE;
c.operandL = 0;
}
m.conlist.push_back(c);
}
}
}

63
audio.h Normal file
View file

@ -0,0 +1,63 @@
#pragma once
#include "stdafx.h"
extern void fill_audio(void *data,Uint8 *stream,int len);
extern void setReadyResumeLastMusic(int channel);
struct musicCondition{
Uint8 opTypeL;
Uint16 operandL;
Uint8 opTypeR;
Uint16 operandR;
Uint8 operatorC;
};
struct musicPiece{
Uint8 priority;
Uint16 ramAddress;
bool hasCheck;
Uint8 checkValue;
bool hasReplace;
Uint8 replaceValue;
Uint8 playType;
Sint16 mp3Idx;
Sint16 mp3Idx2;
string conditions;
vector<musicCondition> conlist;
bool gotoNext;
};
class audio
{
public:
double clockPerSample;
double step[5];
double lastFreq[5];
void init();
audio(void);
~audio(void);
vector<musicPiece> musicList;
vector<string> mp3List;
void ReadAudioPack();
void SaveAudioPack();
void CleanAudioPack();
bool usePack;
Sint16 playingMP3;
vector<Mix_Chunk *> music;
int playingChannel;
bool readyResumeLastMusic;
Uint8 handleRAMWrite(Uint16 address, Uint8 data);
void resumeLastMusic();
//config settings
void readConfig(string value);
void saveConfig(fstream* inifile);
void compileCondition(musicPiece& m);
};

513
batchMapImp.cpp Normal file
View file

@ -0,0 +1,513 @@
#include "StdAfx.h"
#include "batchMapImp.h"
#include "sysState.h"
#include <wx/rawbmp.h>
#include <Shlwapi.h>
batchMapImp::batchMapImp():batchMap(NULL){
cboImage->Clear();
for(unsigned int i = 0; i < vid->bmpInfos.size(); i++){
cboImage->Append(wxString(vid->bmpInfos[i].filename.c_str(), wxConvUTF8));
}
cboNewImage->Clear();
for(unsigned int i = 0; i < vid->bmpInfos.size(); i++){
cboNewImage->Append(wxString(vid->bmpInfos[i].filename.c_str(), wxConvUTF8));
}
firstTileCache = NULL;
paletteTileCache = NULL;
}
batchMapImp::~batchMapImp(){
if(firstTileCache){
free(firstTileCache);
}
if(paletteTileCache){
free(paletteTileCache);
}
}
void batchMapImp::loadImage( wxCommandEvent& event ) {
//load tiles
lstFirstTile->Clear();
lstLastTile->Clear();
lstNewPalette->Clear();
showSourceImg();
bitmapE b;
bitmapF c;
string tiledisplay;
vector<bitmapE> v;
if(firstTileCache){
free(firstTileCache);
}
for(unsigned int i = 0; i < vid->packSize; i++){
if(vid->packData[i] != BAD_ADDRESS){
for(unsigned int j = 0; j < vid->tdata[vid->packData[i]].bitmapP.size(); j++){
//for each tile in the pack
c = vid->tdata[vid->packData[i]].bitmapP[j];
if(c.bitmapID == cboImage->GetSelection()){
b.bitmapID = c.bitmapID;
b.colors = c.colors;
if(romDat->chrPageCount == 0){
b.rawDat = c.rawDat;
}
b.patternAddress = vid->tdata[vid->packData[i]].patternAddress;
b.x = c.x;
b.y = c.y;
b.brightness = c.brightness;
v.push_back(b);
}
}
}
}
if(v.size() > 0){
firstTileCache = (bitmapE*)malloc(v.size() * sizeof(bitmapE));
for(unsigned int i = 0; i < v.size(); i++){
firstTileCache[i] = v[i];
tiledisplay = to_string((long double)(firstTileCache[i].patternAddress)) + "," + vid->GetPaletteString(firstTileCache[i].colors) + "," + to_string((long double)(firstTileCache[i].brightness * 100)) + "%";
lstFirstTile->Append(wxString(tiledisplay.c_str(), wxConvUTF8), &firstTileCache[i]);
}
}
}
void batchMapImp::refreshImg(wxImage img, int poffsetx, int poffsety, int pdrawW, int pdrawH,
int poffsetx2, int poffsety2, int pdrawW2, int pdrawH2){
int neww, newh;
wxImage objimg;
int offsetx;
int offsety;
int drawW;
int drawH;
if(img.GetWidth() / img.GetHeight() > pnlOldImg->GetSize().GetWidth() / pnlOldImg->GetSize().GetHeight()){
neww = pnlOldImg->GetSize().GetWidth();
newh = img.GetHeight() * pnlOldImg->GetSize().GetWidth() / img.GetWidth();
}
else{
newh = pnlOldImg->GetSize().GetHeight();
neww = img.GetWidth() * pnlOldImg->GetSize().GetHeight() / img.GetHeight();
}
objimg = img.Scale(neww, newh);
if(!objimg.HasAlpha()) objimg.InitAlpha();
if(pdrawW > 0 && pdrawH > 0 ){
offsetx = poffsetx * neww / img.GetWidth();
offsety = poffsety * newh / img.GetHeight();
drawW = pdrawW * neww / img.GetWidth();
drawH = pdrawH * newh / img.GetHeight();
if(offsety + drawH < objimg.GetHeight() && offsetx + drawW < objimg.GetWidth()){
for(int i = offsetx; i < offsetx + drawW; i++){
objimg.SetRGB(i, offsety + 1, 0, 0, 0);
objimg.SetAlpha(i, offsety + 1, 255);
if(offsety + 1 + drawH < objimg.GetHeight()){
objimg.SetRGB(i, offsety + 1 + drawH, 0, 0, 0);
objimg.SetAlpha(i, offsety + 1 + drawH, 255);
}
}
for(int j = offsety; j < offsety + drawH; j++){
objimg.SetRGB(offsetx + 1, j, 0, 0, 0);
objimg.SetAlpha(offsetx + 1, j, 255);
if(offsetx + 1 + drawW < objimg.GetWidth()){
objimg.SetRGB(offsetx + 1 + drawW, j, 0, 0, 0);
objimg.SetAlpha(offsetx + 1 + drawW, j, 255);
}
}
for(int i = offsetx; i < offsetx + drawW; i++){
objimg.SetRGB(i, offsety, 255, 255, 255);
objimg.SetAlpha(i, offsety, 255);
if(offsety + drawH < objimg.GetHeight()){
objimg.SetRGB(i, offsety + drawH, 255, 255, 255);
objimg.SetAlpha(i, offsety + drawH, 255);
}
}
for(int j = offsety; j < offsety + drawH; j++){
objimg.SetRGB(offsetx, j, 255, 255, 255);
objimg.SetAlpha(offsetx, j, 255);
if(offsetx + drawW< objimg.GetWidth()){
objimg.SetRGB(offsetx + drawW, j, 255, 255, 255);
objimg.SetAlpha(offsetx + drawW, j, 255);
}
}
}
}
if(pdrawW2 > 0 && pdrawH2 > 0){
offsetx = poffsetx2 * neww / img.GetWidth();
offsety = poffsety2 * newh / img.GetHeight();
drawW = pdrawW2 * neww / img.GetWidth();
drawH = pdrawH2 * newh / img.GetHeight();
if(offsety + drawH < objimg.GetHeight() && offsetx + drawW < objimg.GetWidth()){
for(int i = offsetx; i < offsetx + drawW; i++){
objimg.SetRGB(i, offsety + 1, 0, 0, 0);
objimg.SetAlpha(i, offsety + 1, 255);
if(offsety + 1 + drawH < objimg.GetHeight()){
objimg.SetRGB(i, offsety + 1 + drawH, 0, 0, 0);
objimg.SetAlpha(i, offsety + 1 + drawH, 255);
}
}
for(int j = offsety; j < offsety + drawH; j++){
objimg.SetRGB(offsetx + 1, j, 0, 0, 0);
objimg.SetAlpha(offsetx + 1, j, 255);
if(offsetx + 1 + drawW < objimg.GetWidth()){
objimg.SetRGB(offsetx + 1 + drawW, j, 0, 0, 0);
objimg.SetAlpha(offsetx + 1 + drawW, j, 255);
}
}
for(int i = offsetx; i < offsetx + drawW; i++){
objimg.SetRGB(i, offsety, 255, 255, 255);
objimg.SetAlpha(i, offsety, 255);
if(offsety + drawH < objimg.GetHeight()){
objimg.SetRGB(i, offsety + drawH, 255, 255, 255);
objimg.SetAlpha(i, offsety + drawH, 255);
}
}
for(int j = offsety; j < offsety + drawH; j++){
objimg.SetRGB(offsetx, j, 255, 255, 255);
objimg.SetAlpha(offsetx, j, 255);
if(offsetx + drawW< objimg.GetWidth()){
objimg.SetRGB(offsetx + drawW, j, 255, 255, 255);
objimg.SetAlpha(offsetx + drawW, j, 255);
}
}
}
}
pnlOldImg->ClearBackground();
wxClientDC* objDC = new wxClientDC(pnlOldImg);
objDC->DrawBitmap(wxBitmap(objimg), 0, 0);
delete objDC;
}
void batchMapImp::showSourceImg(){
int ox1, oy1, ow1, oh1, ox2, oy2, ow2, oh2;
if(cboImage->GetSelection() == wxNOT_FOUND) return;
string filename = getHDPackPath() + "\\" + vid->bmpInfos[cboImage->GetSelection()].filename;
wxImage objImageImg = wxImage(wxString(filename.c_str(), wxConvUTF8));
bitmapE* b;
ox1 = 0; oy1 = 0; ow1 = 0; oh1 = 0;
ox2 = 0; oy2 = 0; ow2 = 0; oh2 = 0;
if(lstFirstTile->GetSelection() != wxNOT_FOUND){
b = (bitmapE*)lstFirstTile->GetClientData(lstFirstTile->GetSelection());
ox1 = b->x;
oy1 = b->y;
ow1 = 8 * vid->packScale;
oh1 = 8 * vid->packScale;
}
if(lstLastTile->GetSelection() != wxNOT_FOUND){
b = (bitmapE*)lstLastTile->GetClientData(lstLastTile->GetSelection());
ox2 = b->x;
oy2 = b->y;
ow2 = 8 * vid->packScale;
oh2 = 8 * vid->packScale;
}
refreshImg(objImageImg, ox1, oy1, ow1, oh1, ox2, oy2, ow2, oh2);
}
void batchMapImp::firstTileSelected( wxCommandEvent& event ) {
lstLastTile->Clear();
lstNewPalette->Clear();
showSourceImg();
bitmapE* b;
bitmapE* b2;
string tiledisplay;
if(lstFirstTile->GetSelection() == wxNOT_FOUND) return;
b = (bitmapE*)lstFirstTile->GetClientData(lstFirstTile->GetSelection());
//get list of tiles with matching palette and add to last tile list
for(int i = lstFirstTile->GetSelection(); i < lstFirstTile->GetCount(); i++){
b2 = (bitmapE*)lstFirstTile->GetClientData(i);
if(i > lstFirstTile->GetSelection() && b->colors.colorValues == b2->colors.colorValues){
tiledisplay = to_string((long double)(b2->patternAddress));
lstLastTile->Append(wxString(tiledisplay.c_str(), wxConvUTF8), b2);
}
}
//add list of other palette
bitmapE d;
bitmapF c;
vector<bitmapE> v;
if(paletteTileCache){
free(paletteTileCache);
}
if(vid->editData[b->patternAddress] != BAD_ADDRESS){
for(unsigned int j = 0; j < vid->etiledata[vid->editData[b->patternAddress]].bitmapP.size(); j++){
c = vid->etiledata[vid->editData[b->patternAddress]].bitmapP[j];
d.bitmapID = c.bitmapID;
d.colors = c.colors;
if(romDat->chrPageCount == 0){
d.rawDat = c.rawDat;
}
d.patternAddress = b->patternAddress;
d.x = c.x;
d.y = c.y;
d.brightness = c.brightness;
v.push_back(d);
}
}
if(v.size() > 0){
paletteTileCache = (bitmapE*)malloc(v.size() * sizeof(bitmapE));
for(unsigned int i = 0; i < v.size(); i++){
paletteTileCache[i] = v[i];
tiledisplay = vid->GetPaletteString(paletteTileCache[i].colors);
lstNewPalette->Append(wxString(tiledisplay.c_str(), wxConvUTF8), &paletteTileCache[i]);
}
}
}
void batchMapImp::lastTileSelected( wxCommandEvent& event ) {
if(cboImage->GetSelection() == wxNOT_FOUND) return;
showSourceImg();
}
void batchMapImp::showNewPalette( wxCommandEvent& event ) {
wxImage objimg;
int offsetx;
int offsety;
int drawW;
int drawH;
if(lstNewPalette->GetSelection() == wxNOT_FOUND) return;
bitmapE* b = (bitmapE*)lstNewPalette->GetClientData(lstNewPalette->GetSelection());
if(b == NULL) return;
string filename = getEditPackPath() + vid->screenFileNameList[b->bitmapID];
objimg = wxImage(wxString((filename + ".png").c_str(), wxConvUTF8));
//draw a box in the screenshot
offsetx = b->x * objimg.GetWidth() / DISPLAY_WIDTH;
offsety = b->y * objimg.GetHeight() / DISPLAY_HEIGHT;
drawW = 8 * objimg.GetWidth() / DISPLAY_WIDTH;
drawH = 8 * objimg.GetHeight() / DISPLAY_HEIGHT;
refreshImg(objimg, offsetx, offsety, drawW, drawW, 0, 0, 0, 0);
}
void batchMapImp::showNewImage( wxCommandEvent& event ) {
loadNewImg();
}
void batchMapImp::loadNewImg(){
wxClientDC* objDC;
int neww, newh;
wxImage img;
wxImage objimg;
int offsetx;
int offsety;
int drawW;
int drawH;
if(cboNewImage->GetSelection() == wxNOT_FOUND) return;
string filename = getHDPackPath() + "\\" + vid->bmpInfos[cboNewImage->GetSelection()].filename;
img = wxImage(wxString(filename.c_str(), wxConvUTF8));
newImgW = img.GetWidth();
newImgH = img.GetHeight();
if(newImgW / newImgH > pnlNewImage->GetSize().GetWidth() / pnlNewImage->GetSize().GetHeight()){
neww = pnlNewImage->GetSize().GetWidth();
newh = newImgH * pnlNewImage->GetSize().GetWidth() / newImgW;
}
else{
newh = pnlNewImage->GetSize().GetHeight();
neww = newImgW * pnlNewImage->GetSize().GetHeight() / newImgH;
}
objimg = img.Scale(neww, newh);
if(!objimg.HasAlpha()) objimg.InitAlpha();
if(string(txtMapX->GetValue().char_str()).compare("") != 0
&& string(txtMapY->GetValue().char_str()).compare("") != 0){
offsetx = stoi(string(txtMapX->GetValue().char_str())) * neww / newImgW;
offsety = stoi(string(txtMapY->GetValue().char_str())) * newh / newImgH;
drawW = 8 * vid->packScale * neww / newImgW;
drawH = 8 * vid->packScale * newh / newImgH;
if(offsety + drawH < objimg.GetHeight() && offsetx + drawW < objimg.GetWidth()){
for(int i = offsetx; i < offsetx + drawW; i++){
objimg.SetRGB(i, offsety + 1, 0, 0, 0);
objimg.SetAlpha(i, offsety + 1, 255);
if(offsety + 1 + drawH < objimg.GetHeight()){
objimg.SetRGB(i, offsety + 1 + drawH, 0, 0, 0);
objimg.SetAlpha(i, offsety + 1 + drawH, 255);
}
}
for(int j = offsety; j < offsety + drawH; j++){
objimg.SetRGB(offsetx + 1, j, 0, 0, 0);
objimg.SetAlpha(offsetx + 1, j, 255);
if(offsetx + 1 + drawW < objimg.GetWidth()){
objimg.SetRGB(offsetx + 1 + drawW, j, 0, 0, 0);
objimg.SetAlpha(offsetx + 1 + drawW, j, 255);
}
}
for(int i = offsetx; i < offsetx + drawW; i++){
objimg.SetRGB(i, offsety, 255, 255, 255);
objimg.SetAlpha(i, offsety, 255);
if(offsety + drawH < objimg.GetHeight()){
objimg.SetRGB(i, offsety + drawH, 255, 255, 255);
objimg.SetAlpha(i, offsety + drawH, 255);
}
}
for(int j = offsety; j < offsety + drawH; j++){
objimg.SetRGB(offsetx, j, 255, 255, 255);
objimg.SetAlpha(offsetx, j, 255);
if(offsetx + drawW< objimg.GetWidth()){
objimg.SetRGB(offsetx + drawW, j, 255, 255, 255);
objimg.SetAlpha(offsetx + drawW, j, 255);
}
}
}
}
pnlNewImage->ClearBackground();
objDC = new wxClientDC(pnlNewImage);
objDC->DrawBitmap(wxBitmap(objimg), 0, 0);
delete objDC;
}
void batchMapImp::addImageToPack( wxFileDirPickerEvent& event ) {
string filename = string(m_filePicker2->GetPath().char_str());
wxImage objImg;
//load image for image size
objImg = wxImage(wxString(filename.c_str(), wxConvUTF8));
//create hd pack dir
string packdir = getHDPackPath() + "\\";
_mkdir(packdir.c_str());
//get file name
CHAR szPath[MAX_PATH];
filename.copy(szPath, MAX_PATH, 0);
szPath[filename.length()] = NULL;
PathStripPathA(szPath);
objImg.SaveFile(wxString((packdir + string(szPath)).c_str(), wxConvUTF8));
vid->AddHiResImg(string(szPath));
cboNewImage->Append(wxString(szPath, wxConvUTF8));
cboNewImage->SetSelection(vid->bmpInfos.size() - 1);
loadNewImg();
}
void batchMapImp::addMappings( wxCommandEvent& event ) {
if(string(txtMapX->GetValue().char_str()).compare("") != 0
&& string(txtMapY->GetValue().char_str()).compare("") != 0
&& cboImage->GetSelection() != wxNOT_FOUND
&& cboNewImage->GetSelection() != wxNOT_FOUND
&& lstFirstTile->GetSelection() != wxNOT_FOUND
&& lstLastTile->GetSelection() != wxNOT_FOUND
&& lstNewPalette->GetSelection() != wxNOT_FOUND){
bitmapF c;
bitmapF f;
bitmapF newMap;
bitmapE* b = (bitmapE*)lstFirstTile->GetClientData(lstFirstTile->GetSelection());
bitmapE* d = (bitmapE*)lstNewPalette->GetClientData(lstNewPalette->GetSelection());
int newOffsetX = stoi(string(txtMapX->GetValue().char_str())) - b->x;
int newOffsetY = stoi(string(txtMapY->GetValue().char_str())) - b->y;
GLfloat newBrightness = stof(string(txtBrightness->GetValue().char_str())) / 100;
newMap.bitmapID = cboNewImage->GetSelection();
newMap.colors = d->colors;
newMap.brightness = newBrightness;
int tileIDFrom = b->patternAddress;
int tileIDTo = ((bitmapE*)lstLastTile->GetClientData(lstLastTile->GetSelection()))->patternAddress;
for(int i = tileIDFrom; i <= tileIDTo; i++){
//find current maping
if(vid->packData[i] != BAD_ADDRESS){
bool hasOldMapping = false;
bool hasMatchSource = false;
int oldMappingIdx;
for(unsigned int j = 0; j < vid->tdata[vid->packData[i]].bitmapP.size(); j++){
//for each tile within range
c = vid->tdata[vid->packData[i]].bitmapP[j];
if(romDat->chrPageCount == 0){
newMap.rawDat = c.rawDat;
}
//if palette matches the source
if(c.colors.colorValues == b->colors.colorValues){
hasMatchSource = true;
f = c;
}
//if palette matches the destination
if(c.colors.colorValues == d->colors.colorValues){
hasOldMapping = true;
oldMappingIdx = j;
}
}
if(hasMatchSource){
newMap.x = f.x + newOffsetX;
newMap.y = f.y + newOffsetY;
if (newMap.x >= 0 && newMap.y >= 0) {
if(hasOldMapping){
//replace old
vid->tdata[vid->packData[i]].bitmapP[oldMappingIdx] = newMap;
}
else{
//add new
vid->tdata[vid->packData[i]].bitmapP.push_back(newMap);
}
}
}
}
}
this->EndModal(1);
}
}
void batchMapImp::cancel( wxCommandEvent& event ) {
this->EndModal(0);
}
void batchMapImp::ImageTileSelected( wxMouseEvent& event ) {
int selectX;
int selectY;
float scale;
if(newImgW / newImgH > pnlNewImage->GetSize().GetWidth() / pnlNewImage->GetSize().GetHeight()){
scale = (float)newImgW / (float)pnlNewImage->GetSize().GetWidth();
}
else{
scale = (float)newImgH / (float)pnlNewImage->GetSize().GetHeight();
}
selectX = event.GetPosition().x * scale;
selectX = selectX - (selectX % (8 * vid->packScale));
selectY = event.GetPosition().y * scale;
selectY = selectY - (selectY % (8 * vid->packScale));
if(selectX < newImgW && selectY < newImgH){
txtMapX->SetValue(wxString(to_string((long double)(selectX)).c_str(), wxConvUTF8));
txtMapY->SetValue(wxString(to_string((long double)(selectY)).c_str(), wxConvUTF8));
loadNewImg();
}
}

31
batchMapImp.h Normal file
View file

@ -0,0 +1,31 @@
#pragma once
#include "..\wxwidget\formhdnes.h"
#include "video.h"
class batchMapImp :
public batchMap
{
protected:
bitmapE* firstTileCache;
bitmapE* paletteTileCache;
int newImgW;
int newImgH;
void loadImage( wxCommandEvent& event );
void firstTileSelected( wxCommandEvent& event );
void lastTileSelected( wxCommandEvent& event );
void showNewImage( wxCommandEvent& event );
void addImageToPack( wxFileDirPickerEvent& event );
void addMappings( wxCommandEvent& event );
void cancel( wxCommandEvent& event );
void ImageTileSelected( wxMouseEvent& event );
void showNewPalette( wxCommandEvent& event );
public:
batchMapImp();
~batchMapImp();
void showSourceImg();
void refreshImg(wxImage img, int poffsetx, int poffsety, int pdrawW, int pdrawH, int poffsetx2, int poffsety2, int pdrawW2, int pdrawH2);
void loadNewImg();
};

184
cart.cpp Normal file
View file

@ -0,0 +1,184 @@
#include "StdAfx.h"
#include "cart.h"
#include "sysState.h"
#include "mapperList.h"
#include <fstream>
#include <Shlwapi.h>
using namespace std;
cart::cart()
{
romLoaded = false;
}
cart::~cart(void)
{
clean();
}
void cart::clean(){
if(romLoaded){
saveBat();
if(prgPageCount > 0){
free(prgROM);
}
if(chrPageCount > 0){
free(chrROM);
}
else{
free(chrRAM);
free(chrRAMAddress);
}
free(batDat);
delete mmc;
}
}
void cart::loadRom(string name){
fstream romfile;
char fileType[4];
char header[12];
clean();
gameName = name;
setting->gamePath = name;
romfile.open(gameName, ios::in | ios::binary);
if (romfile.is_open()){
romfile.read(fileType, 4);
if(fileType[0] == 0x4E
&& fileType[1] == 0x45
&& fileType[2] == 0x53
&& fileType[3] == 0x1A){
//first 4 bytes are correct, read rest of the header
romfile.read(header, 12);
prgPageCount = header[0];
chrPageCount = header[1];
mapperID = header[3] + ((header[2] >> 4) & 0x0F);
mirrorV = ((header[2] & 0x01) == 0x01);
useBat = ((header[2] & 0x02) == 0x02);
useTrain = ((header[2] & 0x04) == 0x04);
scr4x = ((header[2] & 0x08) == 0x08);
//skip trainer
if(useTrain){
romfile.seekg(528);
}
//read prg pages
if(prgPageCount > 0){
prgROM = (Uint8*) malloc(PRG_PAGE_SIZE * prgPageCount);
romfile.read((char *)(prgROM), 0x4000 * prgPageCount);
}
//read chr pages
if(chrPageCount > 0){
chrROM = (Uint8*) malloc(CHR_PAGE_SIZE * chrPageCount);
romfile.read((char *)(chrROM), 0x2000 * chrPageCount);
}
else{
chrRAM = (Uint8*) malloc(0x4000);
chrRAMAddress = (Uint32*) malloc(0x400 * sizeof(Uint32));
for(int i = 0; i < 0x400; ++i){
chrRAMAddress[i] = BAD_ADDRESS;
}
lastPrgRead = BAD_ADDRESS;
}
batDat = (Uint8*) malloc(0x2000);
loadBat();
//if (useBat) {
// loadBat();
//}
batChanged = false;
scr4RAM = (Uint8*) malloc(0x1000);
romLoaded = true;
switch(mapperID){
case 0:
mmc = new mapper0();
break;
case 1:
mmc = new mapper1();
break;
case 2:
mmc = new mapper2();
break;
case 3:
mmc = new mapper3();
break;
case 4:
mmc = new mapper4();
break;
case 7:
mmc = new mapper7();
break;
case 9:
mmc = new mapper9();
break;
case 10:
mmc = new mapper10();
break;
case 16:
case 153:
case 159:
mmc = new mapper16();
break;
default:
writeLog("Unsupported mapper:" + to_string((long double)mapperID));
romLoaded = false;
}
}
romfile.close();
}
}
void cart::loadBat(){
fstream romfile;
string filename = getROMDirPath() + "\\" + getROMName() + ".sav";
romfile.open(filename, ios::in | ios::binary);
if (romfile.is_open()){
romfile.read((char *)(batDat), 0x2000);
romfile.close();
}
}
void cart::saveBat(){
if(batChanged){
fstream romfile;
string filename = getROMDirPath() + "\\" + getROMName() + ".sav";
romfile.open(filename, ios::out | ios::binary | ios::trunc);
if (romfile.is_open()){
romfile.write((char *)(batDat), 0x2000);
romfile.close();
}
}
}
bool cart::getLoadState(){
return romLoaded;
}
void cart::saveState(fstream* statefile){
if (chrPageCount == 0) {
statefile->write((char *)(chrRAM), 0x4000);
}
statefile->write((char *)(batDat), 0x2000);
statefile->write((char *)(scr4RAM), 0x1000);
}
void cart::loadState(fstream* statefile){
if (chrPageCount == 0) {
statefile->read((char *)(chrRAM), 0x4000);
}
statefile->read((char *)(batDat), 0x2000);
statefile->read((char *)(scr4RAM), 0x1000);
}

42
cart.h Normal file
View file

@ -0,0 +1,42 @@
#pragma once
class cart
{
private:
public:
string gameName;
bool romLoaded;
Uint8 mapperID;
Uint8 chrPageCount;
Uint8 prgPageCount;
bool mirrorV;
bool scr4x;
bool useBat;
bool useTrain;
bool batChanged;
Uint8* prgROM;
Uint8* chrROM;
Uint8* chrRAM;
Uint8* batDat;
Uint8* scr4RAM;
Uint32* chrRAMAddress;
Uint32 lastPrgRead;
cart();
~cart(void);
void loadRom(string name);
void loadBat();
void saveBat();
bool getLoadState();
void clean();
void saveState(fstream* statefile);
void loadState(fstream* statefile);
};

74
commonUtil.cpp Normal file
View file

@ -0,0 +1,74 @@
#pragma once
#include "stdafx.h"
#include <vector>
#include <sstream>
#include <Shlwapi.h>
#include "sysState.h"
using namespace std;
vector<string> split(const string &s, char delim, vector<string> &elems) {
stringstream ss(s);
string item;
while(getline(ss, item, delim)) {
elems.push_back(item);
}
return elems;
}
string removeSpace(const string &s){
stringstream ss(s);
string item;
string result = "";
while(getline(ss, item, ' ')) {
result += item;
}
return result;
}
string getROMDirPath(){
CHAR szPath[MAX_PATH];
romDat->gameName.copy(szPath, MAX_PATH, 0);
szPath[romDat->gameName.length()] = NULL;
PathRemoveFileSpecA(szPath);
return string(szPath);
}
string getROMName(){
CHAR szPath[MAX_PATH];
string romName = getHDPackPath();
romName.copy(szPath, MAX_PATH, 0);
szPath[romName.length()] = NULL;
PathStripPathA(szPath);
return string(szPath);
}
string getHDPackPath(){
CHAR szPath[MAX_PATH];
romDat->gameName.copy(szPath, MAX_PATH, 0);
szPath[romDat->gameName.length()] = NULL;
PathRemoveExtensionA(szPath);
return string(szPath);
}
string getEditPackPath(){
return setting->exeDir + "\\edit\\" + getROMName() + "\\";
}
void writeLog(string s){
fstream logfile;
_mkdir(setting->logDir.c_str());
logfile.open(setting->logName, ios::out | ios::app);
if (logfile.is_open()){
logfile << s + "\n";
logfile.close();
}
}
string int_to_hex(Uint16 i){
std::stringstream stream;
stream << std::hex << i;
return stream.str();
}

13
commonUtil.h Normal file
View file

@ -0,0 +1,13 @@
#pragma once
#include <vector>
using namespace std;
vector<string> split(const string &s, char delim, vector<string> &elems);
string removeSpace(const string &s);
string getROMDirPath();
string getROMName();
string getHDPackPath();
string getEditPackPath();
void writeLog(string s);
string int_to_hex(Uint16 i);

2063
cpu.cpp Normal file

File diff suppressed because it is too large Load diff

331
cpu.h Normal file
View file

@ -0,0 +1,331 @@
#pragma once
using namespace std;
class cpu
{
private:
//commited cpu state
Uint16 regPC;
Uint8 regSP;
Uint8 regA;
Uint8 regX;
Uint8 regY;
bool flagC;
bool flagZ;
bool flagI;
bool flagD;
bool flagV;
bool flagN;
Uint32 curCycle;
bool hasIRQ;
//temp cpu state
Uint32 _curCycle;
bool dmaSkip;
Uint8 oddEvenFlag;
Uint8 op;
//ADC
void opcode69();
void opcode65();
void opcode75();
void opcode6D();
void opcode7D();
void opcode79();
void opcode61();
void opcode71();
void opADC(Uint8 value);
//AND
void opcode29();
void opcode25();
void opcode35();
void opcode2D();
void opcode3D();
void opcode39();
void opcode21();
void opcode31();
void opAND(Uint8 value);
//ASL
void opcode0A();
void opcode06();
void opcode16();
void opcode0E();
void opcode1E();
void opASL(Uint16 address);
//BIT
void opcode24();
void opcode2C();
void opBIT(Uint8 value);
//Branch
void opcode10();
void opcode30();
void opcode50();
void opcode70();
void opcode90();
void opcodeB0();
void opcodeD0();
void opcodeF0();
void opBranch(bool doBranch);
//BRK
void opcode00();
//CMP
void opcodeC9();
void opcodeC5();
void opcodeD5();
void opcodeCD();
void opcodeDD();
void opcodeD9();
void opcodeC1();
void opcodeD1();
void opCMP(Uint8 value);
//CPX
void opcodeE0();
void opcodeE4();
void opcodeEC();
void opCPX(Uint8 value);
//CPY
void opcodeC0();
void opcodeC4();
void opcodeCC();
void opCPY(Uint8 value);
//DEC
void opcodeC6();
void opcodeD6();
void opcodeCE();
void opcodeDE();
void opDEC(Uint16 address);
//DOP
void opcode04();
void opcode14();
void opcode34();
void opcode44();
void opcode54();
void opcode64();
void opcode74();
void opcode80();
void opcode82();
void opcode89();
void opcodeC2();
void opcodeD4();
void opcodeE2();
void opcodeF4();
//EOR
void opcode49();
void opcode45();
void opcode55();
void opcode4D();
void opcode5D();
void opcode59();
void opcode41();
void opcode51();
void opEOR(Uint8 value);
//Flag
void opcode18();
void opcode38();
void opcode58();
void opcode78();
void opcodeB8();
void opcodeD8();
void opcodeF8();
//INC
void opcodeE6();
void opcodeF6();
void opcodeEE();
void opcodeFE();
void opINC(Uint16 address);
//JMP
void opcode4C();
void opcode6C();
void opJMP(Uint16 address);
//JSR
void opcode20();
//LDA
void opcodeA9();
void opcodeA5();
void opcodeB5();
void opcodeAD();
void opcodeBD();
void opcodeB9();
void opcodeA1();
void opcodeB1();
void opLDA(Uint8 value);
//LDX
void opcodeA2();
void opcodeA6();
void opcodeB6();
void opcodeAE();
void opcodeBE();
void opLDX(Uint8 value);
//LDY
void opcodeA0();
void opcodeA4();
void opcodeB4();
void opcodeAC();
void opcodeBC();
void opLDY(Uint8 value);
//LSR
void opcode4A();
void opcode46();
void opcode56();
void opcode4E();
void opcode5E();
void opLSR(Uint16 address);
//NOP
void opcode1A();
void opcode3A();
void opcode5A();
void opcode7A();
void opcodeDA();
void opcodeEA();
void opcodeFA();
//ORA
void opcode09();
void opcode05();
void opcode15();
void opcode0D();
void opcode1D();
void opcode19();
void opcode01();
void opcode11();
void opORA(Uint8 value);
//Register
void opcodeAA();
void opcode8A();
void opcodeCA();
void opcodeE8();
void opcodeA8();
void opcode98();
void opcode88();
void opcodeC8();
//ROL
void opcode2A();
void opcode26();
void opcode36();
void opcode2E();
void opcode3E();
void opROL(Uint16 address);
//ROR
void opcode6A();
void opcode66();
void opcode76();
void opcode6E();
void opcode7E();
void opROR(Uint16 address);
//RTI
void opcode40();
//RTS
void opcode60();
//SBC
void opcodeE9();
void opcodeE5();
void opcodeF5();
void opcodeED();
void opcodeFD();
void opcodeF9();
void opcodeE1();
void opcodeF1();
void opSBC(Uint8 value);
//STA
void opcode85();
void opcode95();
void opcode8D();
void opcode9D();
void opcode99();
void opcode81();
void opcode91();
void opSTA(Uint16 address);
//Stack
void opcode9A();
void opcodeBA();
void opcode48();
void opcode68();
void opcode08();
void opcode28();
//STX
void opcode86();
void opcode96();
void opcode8E();
void opSTX(Uint16 address);
//STY
void opcode84();
void opcode94();
void opcode8C();
void opSTY(Uint16 address);
//TOP triple NOP
void opcode0C();
void opcode1C();
void opcode3C();
void opcode5C();
void opcode7C();
void opcodeDC();
void opcodeFC();
void opcodeTOP();
//unknown opcode
void opcodeXX();
Uint8 getStatusWord();
void pushStack(Uint8 data);
Uint8 popStack();
public:
cpu(void);
~cpu(void);
void init();
void reset();
void runClock();
void runCode();
void runNMI();
void runIRQ();
void setIRQ();
void runDMA();
unsigned int getCodeRunCycle();
void resetCycleCount();
bool runLog;
ofstream myfile;
void DecodeInstruction (Uint16 Addr, char *str1);
void saveState(fstream* statefile);
void loadState(fstream* statefile);
};

1465
fraHDNesImp.cpp Normal file

File diff suppressed because it is too large Load diff

110
fraHDNesImp.h Normal file
View file

@ -0,0 +1,110 @@
#pragma once
#include "..\wxwidget\formhdnes.h"
#include "video.h"
#include "audio.h"
class fraHDNesImp :
public fraHDNes
{
protected:
wxImage objScreenImg;
wxBitmap objScreenBmp;
bitmapE* screenTileCache;
wxImage objImageImg;
wxBitmap objImageBmp;
batchMap* bmDialog;
void powerButtonClicked( wxCommandEvent& event );
void input1UP( wxCommandEvent& event );
void input1DOWN( wxCommandEvent& event );
void input1LEFT( wxCommandEvent& event );
void input1RIGHT( wxCommandEvent& event );
void input1A( wxCommandEvent& event );
void input1B( wxCommandEvent& event );
void input1SELECT( wxCommandEvent& event );
void input1START( wxCommandEvent& event );
void input2UP( wxCommandEvent& event );
void input2DOWN( wxCommandEvent& event );
void input2LEFT( wxCommandEvent& event );
void input2RIGHT( wxCommandEvent& event );
void input2A( wxCommandEvent& event );
void input2B( wxCommandEvent& event );
void input2SELECT( wxCommandEvent& event );
void input2START( wxCommandEvent& event );
void screen1x( wxCommandEvent& event );
void screen2x( wxCommandEvent& event );
void screen4x( wxCommandEvent& event );
void screenxx( wxCommandEvent& event );
void screenWidth( wxKeyEvent& event );
void screenHeight( wxKeyEvent& event );
void toggleGraphicsPack( wxCommandEvent& event );
void toggleEditPack( wxCommandEvent& event );
void toggleEdgeData( wxCommandEvent& event );
void toggleCHRRamEdit( wxCommandEvent& event );
void loadPackData( wxCommandEvent& event );
void savePackData( wxCommandEvent& event );
void setPackScale( wxCommandEvent& event );
void showScreenShot( wxCommandEvent& event );
void screenTileSelected( wxCommandEvent& event );
void showCustomImage( wxCommandEvent& event );
void addImageToPack( wxFileDirPickerEvent& event );
void ImageTileSelected( wxMouseEvent& event );
void confirmImgSelection( wxCommandEvent& event );
void cancelSelection( wxCommandEvent& event );
void genHDPack( wxCommandEvent& event );
void inputEndGame( wxCommandEvent& event );
void inputSaveState( wxCommandEvent& event );
void inputLoadState( wxCommandEvent& event );
void inputScreenCap( wxCommandEvent& event );
void inputDataCap( wxCommandEvent& event );
void inputPause( wxCommandEvent& event );
void inputRunFrame( wxCommandEvent& event );
void inputContCap( wxCommandEvent& event );
void addBatchMapping( wxCommandEvent& event );
void optimizeScreenEdit( wxCommandEvent& event );
Sint16 editingMusic;
void loadAudioPack( wxCommandEvent& event );
void saveAudioPack( wxCommandEvent& event );
void addMP3ToPick( wxFileDirPickerEvent& event );
void addMP3( wxCommandEvent& event );
void changeMP3( wxCommandEvent& event );
void deleteMP3( wxCommandEvent& event );
void musicSelected( wxListEvent& event );
void toggleAudioPack( wxCommandEvent& event );
void removeImageFromPack( wxCommandEvent& event );
void AddDarkMapping( wxCommandEvent& event );
public:
fraHDNesImp();
~fraHDNesImp();
int keycodes[SDLK_LAST];
void addKeyCode(wxChoice* cbobox);
void showKeyCode(wxChoice* cbobox, SDLKey key);
void refreshGUI();
void refreshInputGUI();
void refreshVideoGUI();
void refreshAudioGUI();
void refreshGraphicsPackGUI();
void loadScreen();
void loadScreenTiles();
void refreshScreenBitmap();
void displayScreenBitmap();
void loadImage();
void refreshImageBitmap();
void displayImageBitmap();
void refreshAudioPackGUI();
void refreshMP3GUI();
void addMP3Field();
void refreshRAMGUI();
static string GetTileDisplayString(bitmapE* b);
static wxString GetCellContentsString(wxListCtrl* wxc, long row_number, int column);
};

140
gameManager.cpp Normal file
View file

@ -0,0 +1,140 @@
#include "stdafx.h"
#include "sysState.h"
using namespace std;
gameManager::gameManager()
{
if(initialize()){
cpuCore = new cpu();
ppuCore = new ppu();
apuCore = new apu();
clockRatio = 3;
}
loadStateFlag = false;
saveStateFlag = false;
}
gameManager::~gameManager(void)
{
delete apuCore;
delete ppuCore;
delete cpuCore;
cleanup();
}
void gameManager::start(){
SDL_Event event;
if (romDat->romLoaded) {
vid->init();
cpuCore->init();
ppuCore->init();
apuCore->init();
mixer->init();
inputCore->Init();
continuePlay = true;
pauseFrame = 0;
waitPauseCommand = -1;
while(continuePlay){
if(pauseFrame != 1 && !vid->waitFrame){
cpuCore->runClock();
ppuCore->runCatchUp(cpuCore->getCodeRunCycle() * clockRatio);
apuCore->runCatchUp(cpuCore->getCodeRunCycle());
mmc->runCatchUp(cpuCore->getCodeRunCycle());
cpuCore->runCode();
if(ppuCore->signalNMI){
cpuCore->runNMI();
ppuCore->signalNMI = false;
}
}
if(ppuCore->signalFrameReady){
vid->displayFrame();
if(pauseFrame > 1)
--pauseFrame;
if(waitPauseCommand != -1){
pauseFrame = waitPauseCommand;
if(waitPauseCommand > 0){
guiForm->refreshRAMGUI();
}
waitPauseCommand = -1;
}
if(pauseFrame != 1 && !vid->waitFrame){
vid->clearScreenData();
ppuCore->signalFrameReady = false;
cpuCore->resetCycleCount();
ppuCore->resetCycleCount();
apuCore->resetCycleCount();
mmc->resetCycleCount();
}
}
if(pauseFrame != 1 && !vid->waitFrame){
cpuCore->runIRQ();
if (loadStateFlag) {
loadState();
}
if (saveStateFlag) {
saveState();
}
}
while( SDL_PollEvent( &event ) ){
inputCore->handleEvent(event);
}
}
vid->cleanUp();
romDat->saveBat();
}
delete gm;
gm = NULL;
}
bool gameManager::initialize(){
if(SDL_Init(SDL_INIT_TIMER|SDL_INIT_VIDEO|SDL_INIT_AUDIO|SDL_INIT_JOYSTICK) < 0){
return false;
}
return true;
}
void gameManager::cleanup(){
SDL_Quit();
}
void gameManager::saveState(){
fstream statefile;
string filename = getROMDirPath() + "\\" + getROMName() + ".sta";
statefile.open(filename, ios::out | ios::binary | ios::trunc);
if (statefile.is_open()){
romDat->saveState(&statefile);
memDat->saveState(&statefile);
mmc->saveState(&statefile);
cpuCore->saveState(&statefile);
ppuCore->saveState(&statefile);
apuCore->saveState(&statefile);
statefile.close();
}
saveStateFlag = false;
}
void gameManager::loadState(){
fstream statefile;
string filename = getROMDirPath() + "\\" + getROMName() + ".sta";
statefile.open(filename, ios::in | ios::binary);
if (statefile.is_open()){
romDat->loadState(&statefile);
memDat->loadState(&statefile);
mmc->loadState(&statefile);
cpuCore->loadState(&statefile);
ppuCore->loadState(&statefile);
apuCore->loadState(&statefile);
statefile.close();
}
loadStateFlag = false;
}

26
gameManager.h Normal file
View file

@ -0,0 +1,26 @@
#pragma once
using namespace std;
class gameManager
{
private:
bool initialize();
void cleanup();
float clockRatio;
public:
gameManager();
~gameManager(void);
void start();
void saveState();
void loadState();
bool continuePlay;
bool saveStateFlag;
bool loadStateFlag;
Sint8 pauseFrame;
Sint8 waitPauseCommand;
};

31
globalConst.h Normal file
View file

@ -0,0 +1,31 @@
#define LINE_CYCLE 341
#define SCANLINES 262
#define DISPLAY_WIDTH 256
#define DISPLAY_HEIGHT 240
#define PPU_VBLANK 0 //line 201 - 260
#define PPU_PRERENDER 1 //line 261
#define PPU_RENDERING 2 //line 0 - 239
#define PPU_IDLE 3 //line 240
#define SAMPLE_RATE 44100
#define AUDIO_BUFFER_SIZE 1024
#define APU_BUFFER_SIZE 2048
#define BAD_ADDRESS 0xFFFFFFFF
#define GEN_HD_WIDTH 128
#define GEN_HD_HEIGHT 128
#define CHR_PAGE_SIZE 0x2000
#define PRG_PAGE_SIZE 0x4000
#define OP_TYPE_ADDRESS 0
#define OP_TYPE_VALUE 1
#define OP_TYPE_WRITE 2
#define OP_TYPE_UNDEFINE 3
#define OP_EQUALS_TO 0
#define OP_GREATER_THAN 1
#define OP_LESS_THAN 2
#define OP_NOT_EQUAL 3

8
hdnes.h Normal file
View file

@ -0,0 +1,8 @@
#include "stdafx.h"
#include "sysSetting.h"
bool initialize();
void cleanup();
SDL_Surface* Surf_Display;
sysSetting* Setting;

173
hdnes.vcxproj Normal file
View file

@ -0,0 +1,173 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{CB764762-DEBC-4773-8E5A-B7A30155B70A}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>hdnes</RootNamespace>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LinkIncremental>true</LinkIncremental>
<IncludePath>C:\Users\mkwong98\Documents\Visual Studio 2010\common include;$(IncludePath)</IncludePath>
<LibraryPath>C:\Users\mkwong98\Documents\Visual Studio 2010\SDL_mixer\lib\x86;C:\Users\mkwong98\Documents\Visual Studio 2010\glew-1.6.0\lib;C:\SourceCode\Libraries\wxWidgets2.8\lib\vc_lib;C:\Users\mkwong98\Documents\Visual Studio 2010\SDL_image-1.2.12\lib\x86;C:\Users\mkwong98\Documents\Visual Studio 2010\SDL-1.2.14\lib;$(LibraryPath)</LibraryPath>
<SourcePath>C:\Users\mkwong98\Documents\Visual Studio 2010\Projects\hdnes\wxwidget;$(SourcePath)</SourcePath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>true</LinkIncremental>
<IncludePath>C:\Users\mkwong98\Documents\Visual Studio 2010\common include;$(IncludePath)</IncludePath>
<LibraryPath>C:\Users\mkwong98\Documents\Visual Studio 2010\SDL_image-1.2.12\lib\x86;C:\Users\mkwong98\Documents\Visual Studio 2010\glew-1.6.0\lib;C:\SourceCode\Libraries\wxWidgets2.8\lib\vc_lib;C:\Users\mkwong98\Documents\Visual Studio 2010\SDL_mixer\lib\x86;C:\Users\mkwong98\Documents\Visual Studio 2010\SDL-1.2.14\lib;$(LibraryPath)</LibraryPath>
<SourcePath>C:\Users\mkwong98\Documents\Visual Studio 2010\Projects\hdnes\wxwidget;$(SourcePath)</SourcePath>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;__WINDOWS__;__WXMSW__;__WXDEBUG__;WXDEBUG=1;__WIN95__;__WIN32__;WINVER=0x0400;STRICT;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<InlineFunctionExpansion>Default</InlineFunctionExpansion>
<IntrinsicFunctions>false</IntrinsicFunctions>
<FavorSizeOrSpeed>Neither</FavorSizeOrSpeed>
<EnableFiberSafeOptimizations>false</EnableFiberSafeOptimizations>
<WholeProgramOptimization>false</WholeProgramOptimization>
<AdditionalIncludeDirectories>C:\SourceCode\Libraries\wxWidgets2.8\lib\vc_lib\mswud;C:\SourceCode\Libraries\wxWidgets2.8\contrib\include;C:\SourceCode\Libraries\wxWidgets2.8\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
<RuntimeTypeInfo>true</RuntimeTypeInfo>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>sdl.lib;sdlmain.lib;opengl32.lib;glew32.lib;glu32.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;comctl32.lib;rpcrt4.lib;wsock32.lib;winmm.lib;wxmsw28ud_core.lib;wxbase28ud.lib;Shlwapi.lib;SDL_image.lib;wxpngd.lib;wxtiffd.lib;wxzlibd.lib;wxjpegd.lib;SDL_mixer.lib</AdditionalDependencies>
<AdditionalLibraryDirectories>C:\SourceCode\Libraries\wxWidgets2.8\contrib\lib;C:\SourceCode\Libraries\wxWidgets2.8\lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>
<LinkTimeCodeGeneration>PGOptimization</LinkTimeCodeGeneration>
<IgnoreSpecificDefaultLibraries>libcd.lib;libcid.lib;msvcrt.lib</IgnoreSpecificDefaultLibraries>
<Profile>true</Profile>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>NDEBUG;WIN32;_WINDOWS;__WINDOWS__;__WXMSW__;__WIN95__;__WIN32__;WINVER=0x0400;STRICT;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>
<AdditionalIncludeDirectories>C:\SourceCode\Libraries\wxWidgets2.8\lib\vc_lib\mswu;C:\SourceCode\Libraries\wxWidgets2.8\contrib\include;C:\SourceCode\Libraries\wxWidgets2.8\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<InlineFunctionExpansion>AnySuitable</InlineFunctionExpansion>
<EnableEnhancedInstructionSet>StreamingSIMDExtensions</EnableEnhancedInstructionSet>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>false</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<AdditionalDependencies>sdl.lib;sdlmain.lib;opengl32.lib;glew32.lib;glu32.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;comctl32.lib;rpcrt4.lib;wsock32.lib;winmm.lib;wxmsw28u_core.lib;wxbase28u.lib;Shlwapi.lib;SDL_image.lib;wxpngd.lib;wxtiffd.lib;wxzlibd.lib;wxjpegd.lib;SDL_mixer.lib</AdditionalDependencies>
<IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>
<IgnoreSpecificDefaultLibraries>libcd.lib;libcid.lib;msvcrt.lib;LIBCMTD.lib</IgnoreSpecificDefaultLibraries>
<AdditionalLibraryDirectories>C:\SourceCode\Libraries\wxWidgets2.8\contrib\lib;C:\SourceCode\Libraries\wxWidgets2.8\lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<None Include="ReadMe.txt" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\wxwidget\formHDNes.h" />
<ClInclude Include="apu.h" />
<ClInclude Include="audio.h" />
<ClInclude Include="batchMapImp.h" />
<ClInclude Include="cart.h" />
<ClInclude Include="commonUtil.h" />
<ClInclude Include="cpu.h" />
<ClInclude Include="fraHDNesImp.h" />
<ClInclude Include="gameManager.h" />
<ClInclude Include="globalConst.h" />
<ClInclude Include="input.h" />
<ClInclude Include="mainApp.h" />
<ClInclude Include="mapper.h" />
<ClInclude Include="mapper0.h" />
<ClInclude Include="mapper1.h" />
<ClInclude Include="mapper10.h" />
<ClInclude Include="mapper16.h" />
<ClInclude Include="mapper2.h" />
<ClInclude Include="mapper3.h" />
<ClInclude Include="mapper4.h" />
<ClInclude Include="mapper7.h" />
<ClInclude Include="mapper9.h" />
<ClInclude Include="mapperList.h" />
<ClInclude Include="memory.h" />
<ClInclude Include="ppu.h" />
<ClInclude Include="stdafx.h" />
<ClInclude Include="sysSetting.h" />
<ClInclude Include="sysState.h" />
<ClInclude Include="targetver.h" />
<ClInclude Include="video.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\wxwidget\formHDNes.cpp" />
<ClCompile Include="apu.cpp" />
<ClCompile Include="audio.cpp" />
<ClCompile Include="batchMapImp.cpp" />
<ClCompile Include="cart.cpp" />
<ClCompile Include="commonUtil.cpp" />
<ClCompile Include="cpu.cpp" />
<ClCompile Include="fraHDNesImp.cpp" />
<ClCompile Include="gameManager.cpp" />
<ClCompile Include="input.cpp" />
<ClCompile Include="mainApp.cpp" />
<ClCompile Include="mapper.cpp" />
<ClCompile Include="mapper0.cpp" />
<ClCompile Include="mapper1.cpp" />
<ClCompile Include="mapper10.cpp" />
<ClCompile Include="mapper16.cpp" />
<ClCompile Include="mapper2.cpp" />
<ClCompile Include="mapper3.cpp" />
<ClCompile Include="mapper4.cpp" />
<ClCompile Include="mapper7.cpp" />
<ClCompile Include="mapper9.cpp" />
<ClCompile Include="memory.cpp" />
<ClCompile Include="ppu.cpp" />
<ClCompile Include="stdafx.cpp">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Create</PrecompiledHeader>
</ClCompile>
<ClCompile Include="sysSetting.cpp" />
<ClCompile Include="sysState.cpp" />
<ClCompile Include="video.cpp" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

198
hdnes.vcxproj.filters Normal file
View file

@ -0,0 +1,198 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Source Files">
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter>
<Filter Include="Header Files">
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
<Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
</Filter>
<Filter Include="Resource Files">
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
</Filter>
<Filter Include="GUI">
<UniqueIdentifier>{c3ad955a-f09c-4047-837e-22f88d8d1aa9}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<None Include="ReadMe.txt" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="stdafx.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="targetver.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="sysSetting.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\wxwidget\formHDNes.h">
<Filter>GUI</Filter>
</ClInclude>
<ClInclude Include="mainApp.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="sysState.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="fraHDNesImp.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="gameManager.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="video.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="memory.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="cpu.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="cart.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="mapper.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="mapper0.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="mapperList.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="ppu.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="globalConst.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="apu.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="input.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="audio.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="mapper1.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="mapper2.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="mapper3.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="mapper4.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="commonUtil.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="mapper16.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="batchMapImp.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="mapper7.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="mapper9.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="mapper10.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="stdafx.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="sysSetting.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\wxwidget\formHDNes.cpp">
<Filter>GUI</Filter>
</ClCompile>
<ClCompile Include="mainApp.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="fraHDNesImp.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="gameManager.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="video.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="sysState.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="memory.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="cpu.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="cart.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="mapper.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="mapper0.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="ppu.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="apu.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="input.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="audio.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="mapper1.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="mapper2.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="mapper3.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="mapper4.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="commonUtil.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="mapper16.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="batchMapImp.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="mapper7.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="mapper9.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="mapper10.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
</Project>

187
input.cpp Normal file
View file

@ -0,0 +1,187 @@
#include "StdAfx.h"
#include "sysState.h"
input::input(void)
{
controller[0][BUTTON_A].assignedKey = SDLK_z;
controller[0][BUTTON_B].assignedKey = SDLK_x;
controller[0][BUTTON_SELECT].assignedKey = SDLK_a;
controller[0][BUTTON_START].assignedKey = SDLK_s;
controller[0][BUTTON_UP].assignedKey = SDLK_UP;
controller[0][BUTTON_DOWN].assignedKey = SDLK_DOWN;
controller[0][BUTTON_LEFT].assignedKey = SDLK_LEFT;
controller[0][BUTTON_RIGHT].assignedKey = SDLK_RIGHT;
controller[1][BUTTON_A].assignedKey = SDLK_UNKNOWN;
controller[1][BUTTON_B].assignedKey = SDLK_UNKNOWN;
controller[1][BUTTON_SELECT].assignedKey = SDLK_UNKNOWN;
controller[1][BUTTON_START].assignedKey = SDLK_UNKNOWN;
controller[1][BUTTON_UP].assignedKey = SDLK_UNKNOWN;
controller[1][BUTTON_DOWN].assignedKey = SDLK_UNKNOWN;
controller[1][BUTTON_LEFT].assignedKey = SDLK_UNKNOWN;
controller[1][BUTTON_RIGHT].assignedKey = SDLK_UNKNOWN;
setting[SETTING_SCREENCAP].assignedKey = SDLK_PRINT;
setting[SETTING_END_EMU].assignedKey = SDLK_ESCAPE;
setting[SETTING_SAVE_STATE].assignedKey = SDLK_F1;
setting[SETTING_LOAD_STATE].assignedKey = SDLK_F2;
setting[SETTING_PAUSE].assignedKey = SDLK_F3;
setting[SETTING_RUN_FRAME].assignedKey = SDLK_F4;
setting[SETTING_CAP_DATA].assignedKey = SDLK_F5;
setting[SETTING_CONT_CAP].assignedKey = SDLK_F6;
}
input::~input(void)
{
}
void input::Init(){
for(Uint8 i = 0; i < BUTTON_COUNT; ++i){
controller[0][i].currentState = false;
controller[0][i].recordedState = false;
controller[1][i].currentState = false;
controller[1][i].recordedState = false;
}
currentRead1P = 0;
currentRead2P = 0;
readReady = false;
}
void input::handleEvent(SDL_Event event){
button* eventButton;
int settingKey;
switch( event.type ){
case SDL_KEYDOWN:
//find if controller key pressed
eventButton = findKeyButton(event.key.keysym.sym);
if(eventButton != NULL) {
eventButton->currentState = true;
}
//find setting key pressed
settingKey = findSettingButton(event.key.keysym.sym);
if(settingKey != -1) {
switch (settingKey) {
case SETTING_SCREENCAP:
vid->capScreenFlag = true;
break;
case SETTING_END_EMU:
gm->continuePlay = false;
break;
case SETTING_SAVE_STATE:
gm->saveStateFlag = true;
break;
case SETTING_LOAD_STATE:
gm->loadStateFlag = true;
break;
case SETTING_PAUSE:
gm->waitPauseCommand = (gm->pauseFrame == 1 ? 0 : 1);
break;
case SETTING_RUN_FRAME:
gm->waitPauseCommand = 2;
break;
case SETTING_CAP_DATA:
vid->capDataFlag = true;
break;
case SETTING_CONT_CAP:
vid->contCapFlag = !vid->contCapFlag;
vid->contCapCounter = 0;
break;
default:
break;
}
}
break;
case SDL_KEYUP:
eventButton = findKeyButton(event.key.keysym.sym);
if(eventButton != NULL) eventButton->currentState = false;
break;
default:
break;
}
}
button* input::findKeyButton(SDLKey key){
for(Uint8 i = 0; i < BUTTON_COUNT; ++i){
for(Uint8 j = 0; j < 2; ++j){
if(controller[j][i].assignedKey == key)
return &controller[j][i];
}
}
return NULL;
}
int input::findSettingButton(SDLKey key){
for(int i = 0; i < SETTING_COUNT; ++i){
if(setting[i].assignedKey == key) return i;
}
return -1;
}
Uint8 input::readReg(Uint8 address){
Uint8 value = 0x00;
if(address == 0x16){
value = (controller[0][currentRead1P].recordedState? 0x01: 0x00);
if(readReady) ++currentRead1P;
}
if(address == 0x17){
value = (controller[1][currentRead2P].recordedState? 0x01: 0x00);
if(readReady) ++currentRead2P;
}
return value;
}
void input::writeReg(Uint8 address, Uint8 data){
if(address == 0x16){
if((data & 0x01) != 0){
for(Uint8 i = 0; i < BUTTON_COUNT; ++i){
for(Uint8 j = 0; j < 2; ++j){
controller[j][i].recordedState = controller[j][i].currentState;
}
}
currentRead1P = 0;
currentRead2P = 0;
readReady = false;
}
else{
readReady = true;
}
}
}
void input::readConfig(string value){
vector<string> lineTokens;
split(value, ',', lineTokens);
if (lineTokens[0].compare("controller") == 0) {
controller[stoi(lineTokens[1])][stoi(lineTokens[2])].assignedKey = (SDLKey)stoi(lineTokens[3]);
}
if (lineTokens[0].compare("setting") == 0) {
setting[stoi(lineTokens[1])].assignedKey = (SDLKey)stoi(lineTokens[2]);
}
}
void input::saveConfig(fstream* inifile){
for(Uint8 i = 0; i < BUTTON_COUNT; ++i){
for(Uint8 j = 0; j < 2; ++j){
(*inifile) << "input:controller," + to_string((long double)j) + "," + to_string((long double)i) + "," + to_string((long double)(controller[j][i].assignedKey)) + "\n";
}
}
for(Uint8 i = 0; i < SETTING_COUNT; ++i){
(*inifile) << "input:setting," + to_string((long double)i) + "," + to_string((long double)(setting[i].assignedKey)) + "\n";
}
}

55
input.h Normal file
View file

@ -0,0 +1,55 @@
#pragma once
#define BUTTON_A 0
#define BUTTON_B 1
#define BUTTON_SELECT 2
#define BUTTON_START 3
#define BUTTON_UP 4
#define BUTTON_DOWN 5
#define BUTTON_LEFT 6
#define BUTTON_RIGHT 7
#define BUTTON_COUNT 8
#define SETTING_SCREENCAP 0
#define SETTING_END_EMU 1
#define SETTING_SAVE_STATE 2
#define SETTING_LOAD_STATE 3
#define SETTING_PAUSE 4
#define SETTING_RUN_FRAME 5
#define SETTING_CAP_DATA 6
#define SETTING_CONT_CAP 7
#define SETTING_COUNT 8
struct button{
bool recordedState;
bool currentState;
SDLKey assignedKey;
};
class input
{
public:
button controller[2][BUTTON_COUNT];
button setting[SETTING_COUNT];
Uint8 currentRead1P;
Uint8 currentRead2P;
bool readReady;
input(void);
~input(void);
void Init();
void handleEvent(SDL_Event event);
button* findKeyButton(SDLKey key);
int findSettingButton(SDLKey key);
Uint8 readReg(Uint8 address);
void writeReg(Uint8 address, Uint8 data);
//config settings
void readConfig(string value);
void saveConfig(fstream* inifile);
};

52
mainApp.cpp Normal file
View file

@ -0,0 +1,52 @@
#include "mainApp.h"
#include "sysState.h"
IMPLEMENT_APP(mainApp)
opcode opArr[256];
mainApp::mainApp(void)
{
if(SDL_Init(SDL_INIT_TIMER|SDL_INIT_VIDEO|SDL_INIT_AUDIO|SDL_INIT_JOYSTICK) < 0){
initOK = false;
}
else{
inputCore = new input();
vid = new video();
mixer = new audio();
romDat = new cart();
memDat = new memory();
//must wait others
setting = new sysSetting();
SDL_Quit();
initOK = true;
}
}
mainApp::~mainApp(void)
{
delete setting;
delete inputCore;
delete mixer;
delete vid;
delete romDat;
delete memDat;
}
bool mainApp::OnInit()
{
// start doing stuff
if(initOK){
mainForm = new fraHDNesImp();
mainForm->Show(true);
guiForm = mainForm;
return true;
}
else{
return false;
}
}

15
mainApp.h Normal file
View file

@ -0,0 +1,15 @@
#pragma once
#include "stdafx.h"
#include "sysSetting.h"
#include "fraHDNesImp.h"
class mainApp : public wxApp
{
public:
fraHDNesImp* mainForm;
bool initOK;
mainApp(void);
~mainApp(void);
virtual bool OnInit();
};

37
mapper.cpp Normal file
View file

@ -0,0 +1,37 @@
#include "StdAfx.h"
#include "sysState.h"
mapper::mapper(void)
{
}
mapper::~mapper(void)
{
}
Uint8 mapper::getTilePalette(Uint8 tableX, Uint8 tableY, Uint8 tileX, Uint8 tileY){
Uint8 tableID;
Uint8 paletteDat;
tableID = memDat->nameTableMirroring[tableX][tableY];
//combine the top 3 bits
paletteDat = memDat->attributeTable[tableID][((tileY & 0x1C) << 1) | (tileX >> 2)];
if((tileX & 0x02) != 0){
if((tileY & 0x02) != 0){
return ((paletteDat >> 6) & 0x03);
}
else{
return ((paletteDat >> 2) & 0x03);
}
}
else{
if((tileY & 0x02) != 0){
return ((paletteDat >> 4) & 0x03);
}
else{
return (paletteDat & 0x03);
}
}
}

20
mapper.h Normal file
View file

@ -0,0 +1,20 @@
#include "stdafx.h"
#pragma once
class mapper
{
public:
mapper(void);
~mapper(void);
virtual void runCatchUp(unsigned int cycle) = 0;
virtual void resetCycleCount() = 0;
virtual void writeCPUData(Uint16 address, Uint8 data) = 0;
virtual Uint8 readCPUData(Uint16 address, bool opRead) = 0;
virtual void writePPUData(Uint16 address, Uint8 data) = 0;
virtual Uint8 readPPUData(Uint16 address) = 0;
virtual Uint8 getTilePalette(Uint8 tableX, Uint8 tableY, Uint8 tileX, Uint8 tileY);
virtual void getPattern(Uint16 address, Uint8 row, bool isFirst, Uint8& data, Uint32& patternAddress, Uint32& ramAddress) = 0;
virtual void saveState(fstream* statefile) = 0;
virtual void loadState(fstream* statefile) = 0;
};

120
mapper0.cpp Normal file
View file

@ -0,0 +1,120 @@
#include "StdAfx.h"
#include "mapper0.h"
#include "sysState.h"
mapper0::mapper0(void)
{
if(romDat->mirrorV){
memDat->nameTableMirroring[0][0] = 0;
memDat->nameTableMirroring[0][1] = 0;
memDat->nameTableMirroring[1][0] = 1;
memDat->nameTableMirroring[1][1] = 1;
}
else{
memDat->nameTableMirroring[0][0] = 0;
memDat->nameTableMirroring[0][1] = 1;
memDat->nameTableMirroring[1][0] = 0;
memDat->nameTableMirroring[1][1] = 1;
}
prgPtr[0] = &(romDat->prgROM[0]);
prgPtr[1] = &(romDat->prgROM[0x4000]);
}
mapper0::~mapper0(void)
{
}
void mapper0::writeCPUData(Uint16 address, Uint8 data){
if((address < 0x8000) && (address >= 0x6000)){
romDat->batDat[address & 0x1FFF] = data;
if(romDat->useBat)romDat->batChanged = true;
}
}
Uint8 mapper0::readCPUData(Uint16 address, bool opRead){
Uint16 bank;
bank = (address & 0xC000);
if(bank == 0x8000){
lastPrgRead = &(prgPtr[0][address & 0x3FFF]) - romDat->prgROM;
return prgPtr[0][address & 0x3FFF];
}
else if(bank == 0xC000){
if(romDat->prgPageCount == 1){
if(opRead) lastPrgRead = &(prgPtr[0][address & 0x3FFF]) - romDat->prgROM;
return prgPtr[0][address & 0x3FFF];
}
else{
if(opRead) lastPrgRead = &(prgPtr[1][address & 0x3FFF]) - romDat->prgROM;
return prgPtr[1][address & 0x3FFF];
}
}
else if(address >= 0x6000){
return romDat->batDat[address & 0x1FFF];
}
else{
return 0;
}
}
void mapper0::writePPUData(Uint16 address, Uint8 data){
if(address < 0x2000){
if(romDat->chrPageCount == 0){
romDat->chrRAM[address] = data;
if(lastPrgRead != BAD_ADDRESS)
romDat->chrRAMAddress[address >> 4] = lastPrgRead >> 4;
}
}
}
Uint8 mapper0::readPPUData(Uint16 address){
if(address < 0x2000){
if(romDat->chrPageCount > 0){
return romDat->chrROM[address];
}
else{
return romDat->chrRAM[address];
}
}
else{
return 0;
}
}
void mapper0::getPattern(Uint16 address, Uint8 row, bool isFirst, Uint8& data, Uint32& patternAddress, Uint32& ramAddress){
Uint16 tmpAddress;
tmpAddress = address;
if(row >= 8){
tmpAddress += 16;
row -= 8;
}
if(!isFirst) tmpAddress += 8;
if(romDat->chrPageCount > 0){
data = romDat->chrROM[tmpAddress + row];
patternAddress = tmpAddress >> 4;
}
else{
data = romDat->chrRAM[tmpAddress + row];
ramAddress = tmpAddress & 0xFFF0;
if(vid->chrRamMatch){
patternAddress = romDat->chrRAMAddress[tmpAddress >> 4];
}
else{
patternAddress = tmpAddress >> 4;
}
}
}
void mapper0::saveState(fstream* statefile){
}
void mapper0::loadState(fstream* statefile){
}
void mapper0::runCatchUp(unsigned int cycle){
}
void mapper0::resetCycleCount(){
}

28
mapper0.h Normal file
View file

@ -0,0 +1,28 @@
#pragma once
#include "mapper.h"
//NROM
class mapper0: public mapper{
private:
Uint8* prgPtr[2];
Uint32 lastPrgRead;
public:
mapper0(void);
~mapper0(void);
void runCatchUp(unsigned int cycle);
void resetCycleCount();
void writeCPUData(Uint16 address, Uint8 data);
Uint8 readCPUData(Uint16 address, bool opRead);
void writePPUData(Uint16 address, Uint8 data);
Uint8 readPPUData(Uint16 address);
void getPattern(Uint16 address, Uint8 row, bool isFirst, Uint8& data, Uint32& patternAddress, Uint32& ramAddress);
void saveState(fstream* statefile);
void loadState(fstream* statefile);
};

297
mapper1.cpp Normal file
View file

@ -0,0 +1,297 @@
#include "StdAfx.h"
#include "mapper1.h"
#include "sysState.h"
mapper1::mapper1(void)
{
if(romDat->mirrorV){
reg[0] = 0x02;
}
else{
reg[0] = 0x03;
}
setMirroring();
writeNum = 0;
writeRegBuffer = 0;
chr8KMode = false;
prg32KMode = false;
slotCSwap = false;
chrReg0 = 0;
chrReg1 = 0;
prgReg = 0;
wramDisable = false;
setBankSwitching();
}
mapper1::~mapper1(void)
{
}
void mapper1::setMirroring(){
switch(reg[0] & 0x03){
case 0x00:
memDat->nameTableMirroring[0][0] = 0;
memDat->nameTableMirroring[0][1] = 0;
memDat->nameTableMirroring[1][0] = 0;
memDat->nameTableMirroring[1][1] = 0;
break;
case 0x01:
memDat->nameTableMirroring[0][0] = 1;
memDat->nameTableMirroring[0][1] = 1;
memDat->nameTableMirroring[1][0] = 1;
memDat->nameTableMirroring[1][1] = 1;
break;
case 0x02:
memDat->nameTableMirroring[0][0] = 0;
memDat->nameTableMirroring[0][1] = 0;
memDat->nameTableMirroring[1][0] = 1;
memDat->nameTableMirroring[1][1] = 1;
break;
case 0x03:
memDat->nameTableMirroring[0][0] = 0;
memDat->nameTableMirroring[0][1] = 1;
memDat->nameTableMirroring[1][0] = 0;
memDat->nameTableMirroring[1][1] = 1;
break;
}
}
void mapper1::setBankSwitching(){
Uint8 tmpReg;
if(romDat->chrPageCount > 0){
if(chr8KMode){
tmpReg = chrReg0 & 0xFE;
chrPtr[0] = &(romDat->chrROM[tmpReg << 12]);
chrPtr[1] = &(romDat->chrROM[(tmpReg + 1) << 12]);
}
else{
chrPtr[0] = &(romDat->chrROM[chrReg0 << 12]);
chrPtr[1] = &(romDat->chrROM[chrReg1 << 12]);
}
}
else{
chrPtr[0] = &(romDat->chrRAM[0]);
chrPtr[1] = &(romDat->chrRAM[0x1000]);
}
if(prg32KMode){
prgPtr[0] = &(romDat->prgROM[(prgReg & 0xFE) << 14]);
prgPtr[1] = &(romDat->prgROM[((prgReg & 0xFE) + 1) << 14]);
}
else{
if(slotCSwap){
prgPtr[0] = &(romDat->prgROM[0]);
prgPtr[1] = &(romDat->prgROM[prgReg << 14]);
}
else{
prgPtr[0] = &(romDat->prgROM[prgReg << 14]);
if(romDat->prgPageCount <= 15){
prgPtr[1] = &(romDat->prgROM[(romDat->prgPageCount - 1) << 14]);
}
else{
prgPtr[1] = &(romDat->prgROM[0x3C000]);
}
}
}
}
void mapper1::writeCPUData(Uint16 address, Uint8 data){
Uint8 regID;
if(address >= 0x6000){
if(address < 0x8000){
if(!wramDisable){
romDat->batDat[address & 0x1FFF] = data;
if(romDat->useBat)romDat->batChanged = true;
}
}
else{
if(data & 0x80){
writeNum = 0;
writeRegBuffer = 0;
reg[0] = reg[0] | 0x0c;
writeReg0(reg[0]);
setBankSwitching();
}
else{
if(writeNum < 5){
writeRegBuffer = writeRegBuffer | ((data & 0x01) << writeNum);
++writeNum;
if(writeNum == 5){
regID = (address >> 13) & 0x03;
reg[regID] = writeRegBuffer;
switch(regID){
case 0:
writeReg0(writeRegBuffer);
break;
case 1:
writeReg1(writeRegBuffer);
break;
case 2:
writeReg2(writeRegBuffer);
break;
case 3:
writeReg3(writeRegBuffer);
break;
}
setBankSwitching();
writeNum = 0;
writeRegBuffer = 0;
}
}
}
}
}
}
void mapper1::writeReg0(Uint8 data){
setMirroring();
chr8KMode = ((data & 0x10) == 0);
prg32KMode = ((data & 0x08) == 0);
slotCSwap = ((data & 0x04) == 0);
}
void mapper1::writeReg1(Uint8 data){
chrReg0 = data & 0x1F;
}
void mapper1::writeReg2(Uint8 data){
chrReg1 = data & 0x1F;
}
void mapper1::writeReg3(Uint8 data){
wramDisable = ((data & 0x10) != 0);
prgReg = data & 0x0F;
}
Uint8 mapper1::readCPUData(Uint16 address, bool opRead){
Uint8 bank;
if(address >= 0x6000){
if(address < 0x8000){
if(!wramDisable) return romDat->batDat[address & 0x1FFF];
}
else{
bank = ((address & 0x7FFF) >> 14);
if(opRead) lastPrgRead = &(prgPtr[bank][address & 0x3FFF]) - romDat->prgROM;
return prgPtr[bank][address & 0x3FFF];
}
}
return 0;
}
void mapper1::writePPUData(Uint16 address, Uint8 data){
if(address < 0x2000){
if(romDat->chrPageCount == 0){
romDat->chrRAM[address] = data;
if(lastPrgRead != BAD_ADDRESS)
romDat->chrRAMAddress[address >> 4] = lastPrgRead >> 4;
}
}
}
Uint8 mapper1::readPPUData(Uint16 address){
Uint8 bank;
if(address < 0x2000){
bank = (address >> 12);
if(romDat->chrPageCount > 0){
return chrPtr[bank][address & 0x0FFF];
}
else{
return romDat->chrRAM[address];
}
}
return 0;
}
void mapper1::getPattern(Uint16 address, Uint8 row, bool isFirst, Uint8& data, Uint32& patternAddress, Uint32& ramAddress){
Uint16 tmpAddress;
Uint32 realAddress;
Uint8 bank;
tmpAddress = address;
if(row >= 8){
tmpAddress += 16;
row -= 8;
}
if(!isFirst) tmpAddress += 8;
if(romDat->chrPageCount > 0){
bank = (tmpAddress >> 12);
data = chrPtr[bank][(tmpAddress + row) & 0x0FFF];
realAddress = &(chrPtr[bank][(tmpAddress + row) & 0x0FFF]) - romDat->chrROM;
patternAddress = realAddress >> 4;
}
else{
data = romDat->chrRAM[tmpAddress + row];
ramAddress = tmpAddress & 0xFFF0;
//patternAddress = BAD_ADDRESS;
if(vid->chrRamMatch){
patternAddress = romDat->chrRAMAddress[tmpAddress >> 4];
}
else{
patternAddress = tmpAddress >> 4;
}
}
}
void mapper1::saveState(fstream* statefile){
Uint32 offset;
statefile->write((char *)(&writeRegBuffer), sizeof(Uint8));
statefile->write((char *)(&writeNum), sizeof(Uint8));
statefile->write((char *)(reg), sizeof(Uint8) * 4);
statefile->write((char *)(&chr8KMode), sizeof(boolean));
statefile->write((char *)(&prg32KMode), sizeof(boolean));
statefile->write((char *)(&slotCSwap), sizeof(boolean));
statefile->write((char *)(&chrReg0), sizeof(Uint8));
statefile->write((char *)(&chrReg1), sizeof(Uint8));
statefile->write((char *)(&wramDisable), sizeof(boolean));
statefile->write((char *)(&prgReg), sizeof(Uint8));
statefile->write((char *)(&lastPrgRead), sizeof(Uint32));
offset = chrPtr[0] - romDat->chrROM;
statefile->write((char *)(&offset), sizeof(Uint32));
offset = chrPtr[1] - romDat->chrROM;
statefile->write((char *)(&offset), sizeof(Uint32));
offset = prgPtr[0] - romDat->prgROM;
statefile->write((char *)(&offset), sizeof(Uint32));
offset = prgPtr[1] - romDat->prgROM;
statefile->write((char *)(&offset), sizeof(Uint32));
}
void mapper1::loadState(fstream* statefile){
Uint32 offset;
statefile->read((char *)(&writeRegBuffer), sizeof(Uint8));
statefile->read((char *)(&writeNum), sizeof(Uint8));
statefile->read((char *)(reg), sizeof(Uint8) * 4);
statefile->read((char *)(&chr8KMode), sizeof(boolean));
statefile->read((char *)(&prg32KMode), sizeof(boolean));
statefile->read((char *)(&slotCSwap), sizeof(boolean));
statefile->read((char *)(&chrReg0), sizeof(Uint8));
statefile->read((char *)(&chrReg1), sizeof(Uint8));
statefile->read((char *)(&wramDisable), sizeof(boolean));
statefile->read((char *)(&prgReg), sizeof(Uint8));
statefile->read((char *)(&lastPrgRead), sizeof(Uint32));
statefile->read((char *)(&offset), sizeof(Uint32));
chrPtr[0] = &(romDat->chrROM[offset]);
statefile->read((char *)(&offset), sizeof(Uint32));
chrPtr[1] = &(romDat->chrROM[offset]);
statefile->read((char *)(&offset), sizeof(Uint32));
prgPtr[0] = &(romDat->prgROM[offset]);
statefile->read((char *)(&offset), sizeof(Uint32));
prgPtr[1] = &(romDat->prgROM[offset]);
setMirroring();
setBankSwitching();
}
void mapper1::runCatchUp(unsigned int cycle){
}
void mapper1::resetCycleCount(){
}

50
mapper1.h Normal file
View file

@ -0,0 +1,50 @@
#pragma once
#include "mapper.h"
//mmc1
class mapper1 :
public mapper
{
private:
Uint8 writeRegBuffer;
Uint8 writeNum;
Uint8 reg[4];
boolean chr8KMode;
boolean prg32KMode;
boolean slotCSwap;
Uint8 chrReg0;
Uint8 chrReg1;
boolean wramDisable;
Uint8 prgReg;
Uint32 lastPrgRead;
Uint8* chrPtr[2];
Uint8* prgPtr[2];
void setMirroring();
void setBankSwitching();
void writeReg0(Uint8 data);
void writeReg1(Uint8 data);
void writeReg2(Uint8 data);
void writeReg3(Uint8 data);
public:
mapper1(void);
~mapper1(void);
void runCatchUp(unsigned int cycle);
void resetCycleCount();
void writeCPUData(Uint16 address, Uint8 data);
Uint8 readCPUData(Uint16 address, bool opRead);
void writePPUData(Uint16 address, Uint8 data);
Uint8 readPPUData(Uint16 address);
void getPattern(Uint16 address, Uint8 row, bool isFirst, Uint8& data, Uint32& patternAddress, Uint32& ramAddress);
void saveState(fstream* statefile);
void loadState(fstream* statefile);
};

254
mapper10.cpp Normal file
View file

@ -0,0 +1,254 @@
#include "StdAfx.h"
#include "mapper10.h"
#include "sysState.h"
mapper10::mapper10(void)
{
chrMask = 0xF000;
chrSwitchMask = ((CHR_PAGE_SIZE * romDat->chrPageCount) >> 10) - 1;
prgSwitchMask = ((PRG_PAGE_SIZE * romDat->prgPageCount) >> 14) - 1;
chrMode[0] = 0;
chrMode[1] = 0;
mapReg[0] = 0;
mapReg[1] = 0;
mapReg[2] = 0;
mapReg[3] = 0;
mapReg[4] = 0;
mapReg[5] = 0;
setMirroring();
setBankSwitching();
setChrBankSwitching();
}
mapper10::~mapper10(void)
{
}
void mapper10::setMirroring(){
if((mapReg[5] & 0x01) == 0){
memDat->nameTableMirroring[0][0] = 0;
memDat->nameTableMirroring[0][1] = 0;
memDat->nameTableMirroring[1][0] = 1;
memDat->nameTableMirroring[1][1] = 1;
}
else{
memDat->nameTableMirroring[0][0] = 0;
memDat->nameTableMirroring[0][1] = 1;
memDat->nameTableMirroring[1][0] = 0;
memDat->nameTableMirroring[1][1] = 1;
}
}
void mapper10::setBankSwitching(){
prgPtr[0] = &(romDat->prgROM[(mapReg[0] & prgSwitchMask) << 14]);
prgPtr[1] = &(romDat->prgROM[(((mapReg[0] & prgSwitchMask) << 1) + 1) << 13]);
prgPtr[2] = &(romDat->prgROM[(romDat->prgPageCount * 2 - 2) << 13]);
prgPtr[3] = &(romDat->prgROM[(romDat->prgPageCount * 2 - 1) << 13]);
}
void mapper10::setChrBankSwitching(){
if (chrMode[0] == 0) {
chrPtr[0] = &(romDat->chrROM[(mapReg[1] & chrSwitchMask) << 12]);
}
else{
chrPtr[0] = &(romDat->chrROM[(mapReg[2] & chrSwitchMask) << 12]);
}
if (chrMode[1] == 0) {
chrPtr[1] = &(romDat->chrROM[(mapReg[3] & chrSwitchMask) << 12]);
}
else{
chrPtr[1] = &(romDat->chrROM[(mapReg[4] & chrSwitchMask) << 12]);
}
}
void mapper10::writeCPUData(Uint16 address, Uint8 data){
Uint16 writeAddress;
if(address >= 0x6000){
if(address < 0x8000){
romDat->batDat[address & 0x1FFF] = data;
if(romDat->useBat) romDat->batChanged = true;
}
else{
writeAddress = (address & chrMask);
switch(writeAddress){
case 0xA000:
mapReg[0] = data;
setBankSwitching();
break;
case 0xB000:
mapReg[1] = data;
setChrBankSwitching();
break;
case 0xC000:
mapReg[2] = data;
setChrBankSwitching();
break;
case 0xD000:
mapReg[3] = data;
setChrBankSwitching();
break;
case 0xE000:
mapReg[4] = data;
setChrBankSwitching();
break;
case 0xF000:
mapReg[5] = data;
setMirroring();
break;
}
}
}
}
Uint8 mapper10::readCPUData(Uint16 address, bool opRead){
Uint16 bank;
bank = (address >> 13) & 0x03;
if(address >= 0x8000){
if(opRead) lastPrgRead = &(prgPtr[bank][address & 0x1FFF]) - romDat->prgROM;
return prgPtr[bank][address & 0x1FFF];
}
else if(address >= 0x6000 && !romDat->scr4x){
return romDat->batDat[address & 0x1FFF];
}
else{
return 0;
}
}
void mapper10::writePPUData(Uint16 address, Uint8 data){
if(address < 0x2000){
if(romDat->chrPageCount == 0){
romDat->chrRAM[address] = data;
if(lastPrgRead != BAD_ADDRESS)
romDat->chrRAMAddress[address >> 4] = lastPrgRead >> 4;
}
}
}
void mapper10::setChrMode(Uint16 address){
Uint16 modeCheck;
modeCheck = address & 0x1FF0;
switch(modeCheck){
case 0x0FD0:
chrMode[0] = 0;
break;
case 0x0FE0:
chrMode[0] = 1;
break;
case 0x1FD0:
chrMode[1] = 0;
break;
case 0x1FE0:
chrMode[1] = 1;
break;
}
switch(modeCheck){
case 0x0FD0:
case 0x0FE0:
case 0x1FD0:
case 0x1FE0:
setChrBankSwitching();
break;
}
}
Uint8 mapper10::readPPUData(Uint16 address){
Uint16 bank;
Uint8 data;
bank = (address >> 12) & 0x03;
if(romDat->chrPageCount > 0){
data = chrPtr[bank][address & 0xFFF];
setChrMode(address);
return data;
}
else{
return romDat->chrRAM[address];
}
}
void mapper10::getPattern(Uint16 address, Uint8 row, bool isFirst, Uint8& data, Uint32& patternAddress, Uint32& ramAddress){
Uint16 tmpAddress;
Uint16 bank;
Uint32 realAddress;
tmpAddress = address;
if(row >= 8){
tmpAddress += 16;
row -= 8;
}
if(!isFirst) tmpAddress += 8;
bank = ((tmpAddress>> 12) & 0x03);
if(romDat->chrPageCount > 0){
data = chrPtr[bank][(tmpAddress + row) & 0xFFF];
realAddress = (&(chrPtr[bank][(tmpAddress + row) & 0xFFF])) - romDat->chrROM;
patternAddress = realAddress >> 4;
}
else{
data = romDat->chrRAM[tmpAddress + row];
ramAddress = tmpAddress & 0xFFF0;
if(vid->chrRamMatch){
patternAddress = romDat->chrRAMAddress[tmpAddress >> 4];
}
else{
patternAddress = tmpAddress >> 4;
}
}
setChrMode(tmpAddress);
}
void mapper10::saveState(fstream* statefile){
Uint32 offset;
statefile->write((char *)(&chrMask), sizeof(Uint16));
statefile->write((char *)(&chrSwitchMask), sizeof(Uint16));
statefile->write((char *)(&prgSwitchMask), sizeof(Uint16));
statefile->write((char *)(chrMode), sizeof(Uint8) * 2);
statefile->write((char *)(mapReg), sizeof(Uint8) * 6);
statefile->write((char *)(&lastPrgRead), sizeof(Uint32));
for (int i = 0; i < 2; ++i) {
offset = chrPtr[i] - romDat->chrROM;
statefile->write((char *)(&offset), sizeof(Uint32));
}
for (int i = 0; i < 4; ++i) {
offset = prgPtr[i] - romDat->prgROM;
statefile->write((char *)(&offset), sizeof(Uint32));
}
}
void mapper10::loadState(fstream* statefile){
Uint32 offset;
statefile->read((char *)(&chrMask), sizeof(Uint16));
statefile->read((char *)(&chrSwitchMask), sizeof(Uint16));
statefile->read((char *)(&prgSwitchMask), sizeof(Uint16));
statefile->read((char *)(chrMode), sizeof(Uint8) * 2);
statefile->read((char *)(mapReg), sizeof(Uint8) * 8);
statefile->read((char *)(&lastPrgRead), sizeof(Uint32));
for (int i = 0; i < 2; ++i) {
statefile->read((char *)(&offset), sizeof(Uint32));
chrPtr[i] = &(romDat->chrROM[offset]);
}
for (int i = 0; i < 4; ++i) {
statefile->read((char *)(&offset), sizeof(Uint32));
prgPtr[i] = &(romDat->prgROM[offset]);
}
setMirroring();
setBankSwitching();
setChrBankSwitching();
}
void mapper10::runCatchUp(unsigned int cycle){
}
void mapper10::resetCycleCount(){
}

37
mapper10.h Normal file
View file

@ -0,0 +1,37 @@
#pragma once
#include "mapper.h"
class mapper10 :public mapper{
private:
Uint16 chrMask;
Uint16 chrSwitchMask;
Uint16 prgSwitchMask;
Uint8 chrMode[2];
Uint8 mapReg[6];
Uint8* prgPtr[4];
Uint8* chrPtr[2];
Uint32 lastPrgRead;
void setMirroring();
void setBankSwitching();
void setChrBankSwitching();
void setChrMode(Uint16 address);
public:
mapper10(void);
~mapper10(void);
void runCatchUp(unsigned int cycle);
void resetCycleCount();
void writeCPUData(Uint16 address, Uint8 data);
Uint8 readCPUData(Uint16 address, bool opRead);
void writePPUData(Uint16 address, Uint8 data);
Uint8 readPPUData(Uint16 address);
void getPattern(Uint16 address, Uint8 row, bool isFirst, Uint8& data, Uint32& patternAddress, Uint32& ramAddress);
void saveState(fstream* statefile);
void loadState(fstream* statefile);
};

372
mapper16.cpp Normal file
View file

@ -0,0 +1,372 @@
#include "StdAfx.h"
#include "mapper16.h"
#include "sysState.h"
mapper16::mapper16(void)
{
for (int i = 0; i < 8; ++i) {
reg[i] = 0;
}
reg[0x8] = 0;
reg[0x9] = 0;
reg[0xA] = 0;
reg[0xB] = 0;
reg[0xC] = 0;
reg[0xD] = 0;
reg[0xE] = 0;
reg[0xF] = 0;
curCycle = 0;
irqEnabled = false;
irqFlag = false;
eepromLines = 0;
eepromMode = EEPROM_STANDBY;
eepromType = EEPROM_TYPE_UNKNOWN;
setMirroring();
setBankSwitching();
}
mapper16::~mapper16(void)
{
}
void mapper16::setMirroring(){
switch (reg[9] & 0x03) {
case 0:
memDat->nameTableMirroring[0][0] = 0;
memDat->nameTableMirroring[0][1] = 0;
memDat->nameTableMirroring[1][0] = 1;
memDat->nameTableMirroring[1][1] = 1;
break;
case 1:
memDat->nameTableMirroring[0][0] = 0;
memDat->nameTableMirroring[0][1] = 1;
memDat->nameTableMirroring[1][0] = 0;
memDat->nameTableMirroring[1][1] = 1;
break;
case 2:
memDat->nameTableMirroring[0][0] = 0;
memDat->nameTableMirroring[0][1] = 0;
memDat->nameTableMirroring[1][0] = 0;
memDat->nameTableMirroring[1][1] = 0;
break;
case 3:
memDat->nameTableMirroring[0][0] = 1;
memDat->nameTableMirroring[0][1] = 1;
memDat->nameTableMirroring[1][0] = 1;
memDat->nameTableMirroring[1][1] = 1;
break;
default:
break;
}
}
void mapper16::setBankSwitching(){
for (int i = 0; i < 8; ++i) {
chrPtr[i] = &(romDat->chrROM[reg[i] << 10]);
}
prgPtr[0] = &(romDat->prgROM[reg[8] << 14]);
prgPtr[1] = &(romDat->prgROM[(romDat->prgPageCount - 1) << 14]);
}
void mapper16::writeCPUData(Uint16 address, Uint8 data){
Uint16 writeAddress;
if(address >= 0x6000){
writeAddress = address & 0x000F;
reg[writeAddress] = data;
switch(writeAddress){
case 0:
case 1:
case 2:
case 3:
case 4:
case 5:
case 6:
case 7:
case 8:
setBankSwitching();
break;
case 9:
setMirroring();
break;
case 0x0A:
irqFlag = false;
if (data & 0x01) {
irqEnabled = true;
}
else{
irqEnabled = false;
}
break;
case 0x0B:
irqCounter = (irqCounter & 0xFF00) | data;
break;
case 0x0C:
irqCounter = (irqCounter & 0x00FF) | (data << 8);
break;
case 0x0D:
handleEEPROMWrite();
break;
}
}
}
Uint8 mapper16::readCPUData(Uint16 address, bool opRead){
Uint16 bank;
bank = (address >> 14) & 0x01;
if(address >= 0x8000){
if(opRead) lastPrgRead = &(prgPtr[bank][address & 0x3FFF]) - romDat->prgROM;
return prgPtr[bank][address & 0x3FFF];
}
else if(address >= 0x6000){
if (eepromMode == EEPROM_OUTPUT && bitCounter <= 8 && (reg[0xD] & 0xE0)) {
if(eepromType == EEPROM_TYPE_256)
return (eepromRead & (0x80 >> bitCounter) ? 0x10 : 0x00);
else
return (eepromRead & (0x01 << bitCounter) ? 0x10 : 0x00);
}
else{
return 0;
}
}
else{
return 0;
}
}
void mapper16::writePPUData(Uint16 address, Uint8 data){
if(address < 0x2000){
if(romDat->chrPageCount == 0){
romDat->chrRAM[address] = data;
if(lastPrgRead != BAD_ADDRESS)
romDat->chrRAMAddress[address >> 4] = lastPrgRead >> 4;
}
}
}
Uint8 mapper16::readPPUData(Uint16 address){
Uint16 bank;
bank = (address >> 10) & 0x07;
if(romDat->chrPageCount > 0){
return chrPtr[bank][address & 0x3FF];
}
else{
return romDat->chrRAM[address];
}
}
void mapper16::getPattern(Uint16 address, Uint8 row, bool isFirst, Uint8& data, Uint32& patternAddress, Uint32& ramAddress){
Uint16 tmpAddress;
Uint16 bank;
Uint32 realAddress;
tmpAddress = address;
if(row >= 8){
tmpAddress += 16;
row -= 8;
}
if(!isFirst) tmpAddress += 8;
bank = ((tmpAddress>> 10) & 0x07);
if(romDat->chrPageCount > 0){
data = chrPtr[bank][(tmpAddress + row) & 0x3FF];
realAddress = (&(chrPtr[bank][(tmpAddress + row) & 0x3FF])) - romDat->chrROM;
patternAddress = realAddress >> 4;
}
else{
data = romDat->chrRAM[tmpAddress + row];
ramAddress = tmpAddress & 0xFFF0;
if(vid->chrRamMatch){
patternAddress = romDat->chrRAMAddress[tmpAddress >> 4];
}
else{
patternAddress = tmpAddress >> 4;
}
}
}
void mapper16::saveState(fstream* statefile){
Uint32 offset;
//statefile->write((char *)(this), sizeof(mapper16));
statefile->write((char *)(reg), sizeof(Uint8)*16);
statefile->write((char *)(&lastPrgRead), sizeof(Uint32));
statefile->write((char *)(&curCycle), sizeof(Uint32));
statefile->write((char *)(&irqCounter), sizeof(Uint16));
statefile->write((char *)(&irqEnabled), sizeof(bool));
statefile->write((char *)(&irqFlag), sizeof(bool));
statefile->write((char *)(&eepromMode), sizeof(Uint8));
statefile->write((char *)(&eepromLines), sizeof(Uint8));
statefile->write((char *)(&eepromAddress), sizeof(Uint8));
statefile->write((char *)(&bitCounter), sizeof(Uint8));
statefile->write((char *)(&eepromTemp), sizeof(Uint8));
statefile->write((char *)(&eepromIsReading), sizeof(bool));
statefile->write((char *)(&eepromRead), sizeof(Uint8));
statefile->write((char *)(&eepromType), sizeof(Uint8));
for (int i = 0; i < 8; ++i) {
offset = chrPtr[i] - romDat->chrROM;
statefile->write((char *)(&offset), sizeof(Uint32));
}
for (int i = 0; i < 2; ++i) {
offset = prgPtr[i] - romDat->prgROM;
statefile->write((char *)(&offset), sizeof(Uint32));
}
}
void mapper16::loadState(fstream* statefile){
Uint32 offset;
statefile->read((char *)(reg), sizeof(Uint8)*16);
statefile->read((char *)(&lastPrgRead), sizeof(Uint32));
statefile->read((char *)(&curCycle), sizeof(Uint32));
statefile->read((char *)(&irqCounter), sizeof(Uint16));
statefile->read((char *)(&irqEnabled), sizeof(bool));
statefile->read((char *)(&irqFlag), sizeof(bool));
statefile->read((char *)(&eepromMode), sizeof(Uint8));
statefile->read((char *)(&eepromLines), sizeof(Uint8));
statefile->read((char *)(&eepromAddress), sizeof(Uint8));
statefile->read((char *)(&bitCounter), sizeof(Uint8));
statefile->read((char *)(&eepromTemp), sizeof(Uint8));
statefile->read((char *)(&eepromIsReading), sizeof(bool));
statefile->read((char *)(&eepromRead), sizeof(Uint8));
statefile->read((char *)(&eepromType), sizeof(Uint8));
for (int i = 0; i < 8; ++i) {
statefile->read((char *)(&offset), sizeof(Uint32));
chrPtr[i] = &(romDat->chrROM[offset]);
}
for (int i = 0; i < 2; ++i) {
statefile->read((char *)(&offset), sizeof(Uint32));
prgPtr[i] = &(romDat->prgROM[offset]);
}
setMirroring();
setBankSwitching();
}
void mapper16::runCatchUp(unsigned int cycle){
if (irqEnabled) {
for (unsigned int i = 0; i < cycle - curCycle; ++i) {
if (irqCounter > 0) {
--irqCounter;
if (irqCounter == 0) {
irqFlag = true;
}
}
else{
irqCounter = 0xFFFF;
}
}
}
if(irqFlag){
cpuCore->setIRQ();
}
curCycle = cycle;
}
void mapper16::resetCycleCount(){
curCycle = 0;
}
void mapper16::handleEEPROMWrite(){
/*
Data out = bit 4
SCL = bit 5
SDA = bit 6
R/W = bit 7 (1 = read, 0 = write)
*/
if ((eepromLines & reg[0xD] & 0x20) && (eepromLines & 0x40) && (!(reg[0xD] & 0x40))) {
//11 -> 01
eepromMode = EEPROM_STANDBY_END;
bitCounter = 0;
eepromTemp = 0;
}
if (eepromMode != EEPROM_STANDBY) {
if ((eepromLines & reg[0xD] & 0x20) && (!(eepromLines & 0x40)) && (reg[0xD] & 0x40)) {
//10 -> 11
eepromMode = EEPROM_STANDBY;
}
else{
if ((eepromLines & 0x20) && !(reg[0xD] & 0x20)){
//?1 -> ?0
if (eepromMode == EEPROM_STANDBY_END){
eepromMode = EEPROM_RW_SELECT;
}
else if(bitCounter < 8){
if(eepromMode != EEPROM_OUTPUT){
if(eepromType == EEPROM_TYPE_UNKNOWN || eepromType == EEPROM_TYPE_256)
eepromTemp = eepromTemp | (reg[0xD] & 0x40 ? 0x80 >> bitCounter : 0);
else
eepromTemp = eepromTemp | (reg[0xD] & 0x40 ? 0x01 << bitCounter : 0);
++bitCounter;
}
else
if(reg[0xD] & 0x40)
++bitCounter;
}
else{
++bitCounter;
}
if(bitCounter == 9){
if(eepromType == EEPROM_TYPE_UNKNOWN){
if((eepromTemp & 0xF0) == 0xA0){
eepromType = EEPROM_TYPE_256;
}
else{
eepromType = EEPROM_TYPE_128;
Uint8 reverseTemp = 0;
for(int i = 0; i < 8; ++i){
//reverse the byte
reverseTemp = reverseTemp |(((eepromTemp >> i) & 0x01) << (7 - i));
}
eepromTemp = reverseTemp;
}
}
switch (eepromMode){
case EEPROM_RW_SELECT:
if(eepromType == EEPROM_TYPE_256){
eepromIsReading = ((eepromTemp & 0x01) != 0);
eepromMode = (eepromIsReading ? EEPROM_OUTPUT : EEPROM_WAIT_ADDRESS);
}
else{
eepromIsReading = ((eepromTemp & 0x80) != 0);
eepromAddress = eepromTemp & 0x7F;
eepromMode = (eepromIsReading ? EEPROM_OUTPUT : EEPROM_WAIT_DATA);
}
if(eepromIsReading)
eepromRead = romDat->batDat[eepromAddress & 0xFF];
break;
case EEPROM_WAIT_ADDRESS:
eepromAddress = eepromTemp;
eepromMode = EEPROM_WAIT_DATA;
break;
case EEPROM_WAIT_DATA:
romDat->batDat[eepromAddress & 0xFF] = eepromTemp;
romDat->batChanged = true;
//can only move the last 3 bits, can't change page
eepromAddress = (eepromAddress & 0xF8) | ((eepromAddress + 1) & 0x7);
break;
case EEPROM_OUTPUT:
++eepromAddress;
eepromRead = romDat->batDat[eepromAddress & 0xFF];
}
bitCounter = 0;
eepromTemp = 0;
}
}
}
}
eepromLines = reg[0xD];
}

59
mapper16.h Normal file
View file

@ -0,0 +1,59 @@
#pragma once
#include "mapper.h"
#define EEPROM_STANDBY 0
#define EEPROM_STANDBY_END 1
#define EEPROM_RW_SELECT 2
#define EEPROM_WAIT_ADDRESS 3
#define EEPROM_WAIT_DATA 4
#define EEPROM_OUTPUT 5
#define EEPROM_TYPE_UNKNOWN 0
#define EEPROM_TYPE_256 1
#define EEPROM_TYPE_128 2
class mapper16 :public mapper{
private:
Uint8 reg[16];
Uint8* chrPtr[8];
Uint8* prgPtr[2];
Uint32 lastPrgRead;
Uint32 curCycle;
Uint16 irqCounter;
bool irqEnabled;
bool irqFlag;
Uint8 eepromMode;
Uint8 eepromLines;
Uint8 eepromAddress;
Uint8 bitCounter;
Uint8 eepromTemp;
bool eepromIsReading;
Uint8 eepromRead;
Uint8 eepromType;
void setBankSwitching();
void handleEEPROMWrite();
public:
mapper16(void);
~mapper16(void);
void runCatchUp(unsigned int cycle);
void resetCycleCount();
void writeCPUData(Uint16 address, Uint8 data);
Uint8 readCPUData(Uint16 address, bool opRead);
void writePPUData(Uint16 address, Uint8 data);
Uint8 readPPUData(Uint16 address);
void getPattern(Uint16 address, Uint8 row, bool isFirst, Uint8& data, Uint32& patternAddress, Uint32& ramAddress);
void setMirroring();
void saveState(fstream* statefile);
void loadState(fstream* statefile);
};

148
mapper2.cpp Normal file
View file

@ -0,0 +1,148 @@
#include "StdAfx.h"
#include "mapper2.h"
#include "sysState.h"
mapper2::mapper2(void)
{
if(romDat->mirrorV){
memDat->nameTableMirroring[0][0] = 0;
memDat->nameTableMirroring[0][1] = 0;
memDat->nameTableMirroring[1][0] = 1;
memDat->nameTableMirroring[1][1] = 1;
}
else{
memDat->nameTableMirroring[0][0] = 0;
memDat->nameTableMirroring[0][1] = 1;
memDat->nameTableMirroring[1][0] = 0;
memDat->nameTableMirroring[1][1] = 1;
}
prgReg = 0;
setBankSwitching();
}
mapper2::~mapper2(void)
{
}
void mapper2::setBankSwitching(){
prgPtr[0] = &(romDat->prgROM[prgReg << 14]);
prgPtr[1] = &(romDat->prgROM[(romDat->prgPageCount - 1) << 14]);
}
void mapper2::writeCPUData(Uint16 address, Uint8 data){
if(address >= 0x6000){
if(address < 0x8000){
romDat->batDat[address & 0x3FFF] = data;
if(romDat->useBat)romDat->batChanged = true;
}
else{
prgReg = data;
setBankSwitching();
}
}
}
Uint8 mapper2::readCPUData(Uint16 address, bool opRead){
Uint16 bank;
bank = (address & 0xC000);
if(bank == 0x8000){
if(opRead)
lastPrgRead = &(prgPtr[0][address & 0x3FFF]) - romDat->prgROM;
return prgPtr[0][address & 0x3FFF];
}
else if(bank == 0xC000){
if(opRead)
lastPrgRead = &(prgPtr[1][address & 0x3FFF]) - romDat->prgROM;
return prgPtr[1][address & 0x3FFF];
}
else if(address >= 0x6000){
return romDat->batDat[address & 0x1FFF];
}
else{
return 0;
}
}
void mapper2::writePPUData(Uint16 address, Uint8 data){
if(address < 0x2000){
if(romDat->chrPageCount == 0){
romDat->chrRAM[address] = data;
if(lastPrgRead != BAD_ADDRESS)
romDat->chrRAMAddress[address >> 4] = lastPrgRead >> 4;
}
}
}
Uint8 mapper2::readPPUData(Uint16 address){
if(address < 0x2000){
if(romDat->chrPageCount > 0){
return romDat->chrROM[address];
}
else{
return romDat->chrRAM[address];
}
}
else{
return 0;
}
}
void mapper2::getPattern(Uint16 address, Uint8 row, bool isFirst, Uint8& data, Uint32& patternAddress, Uint32& ramAddress){
Uint16 tmpAddress;
tmpAddress = address;
if(row >= 8){
tmpAddress += 16;
row -= 8;
}
if(!isFirst) tmpAddress += 8;
if(romDat->chrPageCount > 0){
data = romDat->chrROM[tmpAddress + row];
patternAddress = tmpAddress >> 4;
}
else{
data = romDat->chrRAM[tmpAddress + row];
ramAddress = tmpAddress & 0xFFF0;
//patternAddress = BAD_ADDRESS;
if(vid->chrRamMatch){
patternAddress = romDat->chrRAMAddress[tmpAddress >> 4];
}
else{
patternAddress = tmpAddress >> 4;
}
}
}
void mapper2::saveState(fstream* statefile){
Uint32 offset;
statefile->write((char *)(&prgReg), sizeof(Uint8));
statefile->write((char *)(&lastPrgRead), sizeof(Uint32));
offset = prgPtr[0] - romDat->prgROM;
statefile->write((char *)(&offset), sizeof(Uint32));
offset = prgPtr[1] - romDat->prgROM;
statefile->write((char *)(&offset), sizeof(Uint32));
}
void mapper2::loadState(fstream* statefile){
Uint32 offset;
statefile->read((char *)(&prgReg), sizeof(Uint8));
statefile->read((char *)(&lastPrgRead), sizeof(Uint32));
statefile->read((char *)(&offset), sizeof(Uint32));
prgPtr[0] = &(romDat->prgROM[offset]);
statefile->read((char *)(&offset), sizeof(Uint32));
prgPtr[1] = &(romDat->prgROM[offset]);
setBankSwitching();
}
void mapper2::runCatchUp(unsigned int cycle){
}
void mapper2::resetCycleCount(){
}

28
mapper2.h Normal file
View file

@ -0,0 +1,28 @@
#pragma once
#include "mapper.h"
class mapper2 :public mapper{
private:
Uint8 prgReg;
Uint8* prgPtr[2];
Uint32 lastPrgRead;
void setBankSwitching();
public:
mapper2(void);
~mapper2(void);
void runCatchUp(unsigned int cycle);
void resetCycleCount();
void writeCPUData(Uint16 address, Uint8 data);
Uint8 readCPUData(Uint16 address, bool opRead);
void writePPUData(Uint16 address, Uint8 data);
Uint8 readPPUData(Uint16 address);
void getPattern(Uint16 address, Uint8 row, bool isFirst, Uint8& data, Uint32& patternAddress, Uint32& ramAddress);
void saveState(fstream* statefile);
void loadState(fstream* statefile);
};

165
mapper3.cpp Normal file
View file

@ -0,0 +1,165 @@
#include "StdAfx.h"
#include "mapper3.h"
#include "sysState.h"
mapper3::mapper3(void)
{
if(romDat->mirrorV){
memDat->nameTableMirroring[0][0] = 0;
memDat->nameTableMirroring[0][1] = 0;
memDat->nameTableMirroring[1][0] = 1;
memDat->nameTableMirroring[1][1] = 1;
}
else{
memDat->nameTableMirroring[0][0] = 0;
memDat->nameTableMirroring[0][1] = 1;
memDat->nameTableMirroring[1][0] = 0;
memDat->nameTableMirroring[1][1] = 1;
}
prgPtr[0] = &(romDat->prgROM[0]);
prgPtr[1] = &(romDat->prgROM[0x4000]);
chrReg = 0;
chrMask = 0xFF;
while(chrMask > romDat->chrPageCount){
chrMask = chrMask >> 1;
}
setBankSwitching();
}
mapper3::~mapper3(void)
{
}
void mapper3::setBankSwitching(){
chrPtr = &(romDat->chrROM[chrReg << 13]);
}
void mapper3::writeCPUData(Uint16 address, Uint8 data){
if(address >= 0x6000){
if(address < 0x8000){
romDat->batDat[address & 0x1FFF] = data;
if(romDat->useBat)romDat->batChanged = true;
}
else{
chrReg = (data & chrMask);
setBankSwitching();
}
}
}
Uint8 mapper3::readCPUData(Uint16 address, bool opRead){
Uint16 bank;
bank = (address & 0xC000);
if(bank == 0x8000){
if(opRead) lastPrgRead = (&(prgPtr[0][address & 0x3FFF])) - romDat->prgROM;
return prgPtr[0][address & 0x3FFF];
}
else if(bank == 0xC000){
if(romDat->prgPageCount == 1){
if(opRead) lastPrgRead = (&(prgPtr[0][address & 0x3FFF])) - romDat->prgROM;
return prgPtr[0][address & 0x3FFF];
}
else{
if(opRead) lastPrgRead = (&(prgPtr[1][address & 0x3FFF])) - romDat->prgROM;
return prgPtr[1][address & 0x3FFF];
}
}
else if(address >= 0x6000){
return romDat->batDat[address & 0x1FFF];
}
else{
return 0;
}
}
void mapper3::writePPUData(Uint16 address, Uint8 data){
if(address < 0x2000){
if(romDat->chrPageCount == 0){
romDat->chrRAM[address] = data;
if(lastPrgRead != BAD_ADDRESS)
romDat->chrRAMAddress[address >> 4] = lastPrgRead >> 4;
}
}
}
Uint8 mapper3::readPPUData(Uint16 address){
if(address < 0x2000){
if(romDat->chrPageCount > 0){
return chrPtr[address];
}
else{
return romDat->chrRAM[address];
}
}
else{
return 0;
}
}
void mapper3::getPattern(Uint16 address, Uint8 row, bool isFirst, Uint8& data, Uint32& patternAddress, Uint32& ramAddress){
Uint16 tmpAddress;
Uint32 realAddress;
tmpAddress = address;
if(row >= 8){
tmpAddress += 16;
row -= 8;
}
if(!isFirst) tmpAddress += 8;
if(romDat->chrPageCount > 0){
data = chrPtr[tmpAddress + row];
realAddress = (&(chrPtr[tmpAddress + row])) - romDat->chrROM;
patternAddress = realAddress >> 4;
}
else{
data = romDat->chrRAM[tmpAddress + row];
ramAddress = tmpAddress & 0xFFF0;
//patternAddress = BAD_ADDRESS;
if(vid->chrRamMatch){
patternAddress = romDat->chrRAMAddress[tmpAddress >> 4];
}
else{
patternAddress = tmpAddress >> 4;
}
}
}
void mapper3::saveState(fstream* statefile){
Uint32 offset;
statefile->write((char *)(&chrReg), sizeof(Uint8));
statefile->write((char *)(&chrMask), sizeof(Uint8));
statefile->write((char *)(&lastPrgRead), sizeof(Uint32));
offset = chrPtr - romDat->chrROM;
statefile->write((char *)(&offset), sizeof(Uint32));
offset = prgPtr[0] - romDat->prgROM;
statefile->write((char *)(&offset), sizeof(Uint32));
offset = prgPtr[1] - romDat->prgROM;
statefile->write((char *)(&offset), sizeof(Uint32));
}
void mapper3::loadState(fstream* statefile){
Uint32 offset;
statefile->read((char *)(&chrReg), sizeof(Uint8));
statefile->read((char *)(&chrMask), sizeof(Uint8));
statefile->read((char *)(&lastPrgRead), sizeof(Uint32));
statefile->read((char *)(&offset), sizeof(Uint32));
chrPtr = &(romDat->chrROM[offset]);
statefile->read((char *)(&offset), sizeof(Uint32));
prgPtr[0] = &(romDat->prgROM[offset]);
statefile->read((char *)(&offset), sizeof(Uint32));
prgPtr[1] = &(romDat->prgROM[offset]);
setBankSwitching();
}
void mapper3::runCatchUp(unsigned int cycle){
}
void mapper3::resetCycleCount(){
}

30
mapper3.h Normal file
View file

@ -0,0 +1,30 @@
#pragma once
#include "mapper.h"
class mapper3: public mapper{
private:
Uint8 chrReg;
Uint8* chrPtr;
Uint8 chrMask;
void setBankSwitching();
Uint8* prgPtr[2];
Uint32 lastPrgRead;
public:
mapper3(void);
~mapper3(void);
void runCatchUp(unsigned int cycle);
void resetCycleCount();
void writeCPUData(Uint16 address, Uint8 data);
Uint8 readCPUData(Uint16 address, bool opRead);
void writePPUData(Uint16 address, Uint8 data);
Uint8 readPPUData(Uint16 address);
void getPattern(Uint16 address, Uint8 row, bool isFirst, Uint8& data, Uint32& patternAddress, Uint32& ramAddress);
void saveState(fstream* statefile);
void loadState(fstream* statefile);
};

293
mapper4.cpp Normal file
View file

@ -0,0 +1,293 @@
#include "StdAfx.h"
#include "mapper4.h"
#include "sysState.h"
mapper4::mapper4(void)
{
setMirroring();
chrMask = 0xE001;
chrSwitchMask = ((CHR_PAGE_SIZE * romDat->chrPageCount) >> 10) - 1;
prgSwitchMask = ((PRG_PAGE_SIZE * romDat->prgPageCount) >> 13) - 1;
chrMode = 0;
prgMode = 0;
regAddress = 0;
irqEnabled = false;
irqFlag = false;
mapReg[0] = 0;
mapReg[1] = 2;
mapReg[2] = 4;
mapReg[3] = 5;
mapReg[4] = 6;
mapReg[5] = 7;
mapReg[6] = 0;
mapReg[7] = 1;
setBankSwitching();
}
mapper4::~mapper4(void)
{
}
void mapper4::setMirroring(){
if(!romDat->scr4x){
if(romDat->mirrorV){
memDat->nameTableMirroring[0][0] = 0;
memDat->nameTableMirroring[0][1] = 0;
memDat->nameTableMirroring[1][0] = 1;
memDat->nameTableMirroring[1][1] = 1;
}
else{
memDat->nameTableMirroring[0][0] = 0;
memDat->nameTableMirroring[0][1] = 1;
memDat->nameTableMirroring[1][0] = 0;
memDat->nameTableMirroring[1][1] = 1;
}
}
else{
memDat->nameTableMirroring[0][0] = 0;
memDat->nameTableMirroring[0][1] = 1;
memDat->nameTableMirroring[1][0] = 2;
memDat->nameTableMirroring[1][1] = 3;
}
}
void mapper4::setBankSwitching(){
if (chrMode == 0) {
chrPtr[0] = &(romDat->chrROM[((mapReg[0] & 0xFE) & chrSwitchMask) << 10]);
chrPtr[1] = &(romDat->chrROM[(((mapReg[0] & 0xFE) + 1) & chrSwitchMask) << 10]);
chrPtr[2] = &(romDat->chrROM[((mapReg[1] & 0xFE) & chrSwitchMask) << 10]);
chrPtr[3] = &(romDat->chrROM[(((mapReg[1] & 0xFE) + 1) & chrSwitchMask) << 10]);
chrPtr[4] = &(romDat->chrROM[(mapReg[2] & chrSwitchMask) << 10]);
chrPtr[5] = &(romDat->chrROM[(mapReg[3] & chrSwitchMask) << 10]);
chrPtr[6] = &(romDat->chrROM[(mapReg[4] & chrSwitchMask) << 10]);
chrPtr[7] = &(romDat->chrROM[(mapReg[5] & chrSwitchMask) << 10]);
}
else{
chrPtr[0] = &(romDat->chrROM[(mapReg[2] & chrSwitchMask) << 10]);
chrPtr[1] = &(romDat->chrROM[(mapReg[3] & chrSwitchMask) << 10]);
chrPtr[2] = &(romDat->chrROM[(mapReg[4] & chrSwitchMask) << 10]);
chrPtr[3] = &(romDat->chrROM[(mapReg[5] & chrSwitchMask) << 10]);
chrPtr[4] = &(romDat->chrROM[((mapReg[0] & 0xFE) & chrSwitchMask) << 10]);
chrPtr[5] = &(romDat->chrROM[(((mapReg[0] & 0xFE) + 1) & chrSwitchMask) << 10]);
chrPtr[6] = &(romDat->chrROM[((mapReg[1] & 0xFE) & chrSwitchMask) << 10]);
chrPtr[7] = &(romDat->chrROM[(((mapReg[1] & 0xFE) + 1) & chrSwitchMask) << 10]);
}
if (prgMode == 0) {
prgPtr[0] = &(romDat->prgROM[(mapReg[6] & prgSwitchMask) << 13]);
prgPtr[2] = &(romDat->prgROM[(romDat->prgPageCount * 2 - 2) << 13]);
}
else{
prgPtr[2] = &(romDat->prgROM[(mapReg[6] & prgSwitchMask) << 13]);
prgPtr[0] = &(romDat->prgROM[(romDat->prgPageCount * 2 - 2) << 13]);
}
prgPtr[1] = &(romDat->prgROM[(mapReg[7] & prgSwitchMask) << 13]);
prgPtr[3] = &(romDat->prgROM[(romDat->prgPageCount * 2 - 1) << 13]);
}
void mapper4::writeCPUData(Uint16 address, Uint8 data){
Uint16 writeAddress;
if(address >= 0x6000){
if(address < 0x8000){
if(!romDat->scr4x){
romDat->batDat[address & 0x1FFF] = data;
if(romDat->useBat)
romDat->batChanged = true;
}
}
else{
writeAddress = (address & chrMask);
switch(writeAddress){
case 0x8000:
chrMode = data >> 7;
prgMode = (data >> 6) & 0x01;
regAddress = data & 0x07;
setBankSwitching();
break;
case 0x8001:
mapReg[regAddress] = data;
setBankSwitching();
break;
case 0xA000:
//disable writes to mirroring when 4 screen
if(!romDat->scr4x){
romDat->mirrorV = ((data & 0x01) == 0);
setMirroring();
}
break;
case 0xA001:
break;
case 0xC000:
irqValue = data;
break;
case 0xC001:
irqCounter = 0;
break;
case 0xE000:
irqFlag = false;
irqEnabled = false;
break;
case 0xE001:
irqEnabled = true;
scanlineNo = -1;
break;
}
}
}
}
Uint8 mapper4::readCPUData(Uint16 address, bool opRead){
Uint16 bank;
bank = (address >> 13) & 0x03;
if(address >= 0x8000){
if(opRead) lastPrgRead = &(prgPtr[bank][address & 0x1FFF]) - romDat->prgROM;
return prgPtr[bank][address & 0x1FFF];
}
else if(address >= 0x6000 && !romDat->scr4x){
return romDat->batDat[address & 0x1FFF];
}
else{
return 0;
}
}
void mapper4::writePPUData(Uint16 address, Uint8 data){
if(address < 0x2000){
if(romDat->chrPageCount == 0){
romDat->chrRAM[address] = data;
if(lastPrgRead != BAD_ADDRESS)
romDat->chrRAMAddress[address >> 4] = lastPrgRead >> 4;
}
}
}
Uint8 mapper4::readPPUData(Uint16 address){
Uint16 bank;
bank = (address >> 10) & 0x07;
if(romDat->chrPageCount > 0){
return chrPtr[bank][address & 0x3FF];
}
else{
return romDat->chrRAM[address];
}
}
void mapper4::getPattern(Uint16 address, Uint8 row, bool isFirst, Uint8& data, Uint32& patternAddress, Uint32& ramAddress){
Uint16 tmpAddress;
Uint16 bank;
Uint32 realAddress;
tmpAddress = address;
if(row >= 8){
tmpAddress += 16;
row -= 8;
}
if(!isFirst) tmpAddress += 8;
bank = ((tmpAddress>> 10) & 0x07);
if(romDat->chrPageCount > 0){
data = chrPtr[bank][(tmpAddress + row) & 0x3FF];
realAddress = (&(chrPtr[bank][(tmpAddress + row) & 0x3FF])) - romDat->chrROM;
patternAddress = realAddress >> 4;
}
else{
data = romDat->chrRAM[tmpAddress + row];
ramAddress = tmpAddress & 0xFFF0;
if(vid->chrRamMatch){
patternAddress = romDat->chrRAMAddress[tmpAddress >> 4];
}
else{
patternAddress = tmpAddress >> 4;
}
}
if(address & 0x1000){
if(scanlineNo != ppuCore->screenY){
scanlineNo = ppuCore->screenY;
if(irqCounter == 0){
irqCounter = irqValue;
}
else{
--irqCounter;
if(irqCounter == 0 && irqEnabled && !irqFlag){
irqFlag = true;
}
}
}
}
if(irqFlag){
cpuCore->setIRQ();
}
}
void mapper4::saveState(fstream* statefile){
Uint32 offset;
statefile->write((char *)(&chrMask), sizeof(Uint16));
statefile->write((char *)(&chrSwitchMask), sizeof(Uint16));
statefile->write((char *)(&prgSwitchMask), sizeof(Uint16));
statefile->write((char *)(&chrMode), sizeof(Uint8));
statefile->write((char *)(&prgMode), sizeof(Uint8));
statefile->write((char *)(&regAddress), sizeof(Uint8));
statefile->write((char *)(mapReg), sizeof(Uint8) * 8);
statefile->write((char *)(&lastPrgRead), sizeof(Uint32));
statefile->write((char *)(&irqEnabled), sizeof(bool));
statefile->write((char *)(&irqValue), sizeof(Uint8));
statefile->write((char *)(&irqCounter), sizeof(Uint8));
statefile->write((char *)(&irqFlag), sizeof(bool));
statefile->write((char *)(&scanlineNo), sizeof(int));
for (int i = 0; i < 8; ++i) {
offset = chrPtr[i] - romDat->chrROM;
statefile->write((char *)(&offset), sizeof(Uint32));
}
for (int i = 0; i < 4; ++i) {
offset = prgPtr[i] - romDat->prgROM;
statefile->write((char *)(&offset), sizeof(Uint32));
}
}
void mapper4::loadState(fstream* statefile){
Uint32 offset;
statefile->read((char *)(&chrMask), sizeof(Uint16));
statefile->read((char *)(&chrSwitchMask), sizeof(Uint16));
statefile->read((char *)(&prgSwitchMask), sizeof(Uint16));
statefile->read((char *)(&chrMode), sizeof(Uint8));
statefile->read((char *)(&prgMode), sizeof(Uint8));
statefile->read((char *)(&regAddress), sizeof(Uint8));
statefile->read((char *)(mapReg), sizeof(Uint8) * 8);
statefile->read((char *)(&lastPrgRead), sizeof(Uint32));
statefile->read((char *)(&irqEnabled), sizeof(bool));
statefile->read((char *)(&irqValue), sizeof(Uint8));
statefile->read((char *)(&irqCounter), sizeof(Uint8));
statefile->read((char *)(&irqFlag), sizeof(bool));
statefile->read((char *)(&scanlineNo), sizeof(int));
for (int i = 0; i < 8; ++i) {
statefile->read((char *)(&offset), sizeof(Uint32));
chrPtr[i] = &(romDat->chrROM[offset]);
}
for (int i = 0; i < 4; ++i) {
statefile->read((char *)(&offset), sizeof(Uint32));
prgPtr[i] = &(romDat->prgROM[offset]);
}
setMirroring();
setBankSwitching();
}
void mapper4::runCatchUp(unsigned int cycle){
}
void mapper4::resetCycleCount(){
}

46
mapper4.h Normal file
View file

@ -0,0 +1,46 @@
#pragma once
#include "mapper.h"
class mapper4 :public mapper{
private:
Uint16 chrMask;
Uint16 chrSwitchMask;
Uint16 prgSwitchMask;
Uint8 chrMode;
Uint8 prgMode;
Uint8 regAddress;
Uint8 mapReg[8];
Uint8* chrPtr[8];
Uint8* prgPtr[4];
Uint32 lastPrgRead;
bool irqEnabled;
Uint8 irqValue;
Uint8 irqCounter;
bool irqFlag;
int scanlineNo;
void setBankSwitching();
void setMirroring();
public:
mapper4(void);
~mapper4(void);
void runCatchUp(unsigned int cycle);
void resetCycleCount();
void writeCPUData(Uint16 address, Uint8 data);
Uint8 readCPUData(Uint16 address, bool opRead);
void writePPUData(Uint16 address, Uint8 data);
Uint8 readPPUData(Uint16 address);
void getPattern(Uint16 address, Uint8 row, bool isFirst, Uint8& data, Uint32& patternAddress, Uint32& ramAddress);
void saveState(fstream* statefile);
void loadState(fstream* statefile);
};

152
mapper7.cpp Normal file
View file

@ -0,0 +1,152 @@
#include "StdAfx.h"
#include "mapper7.h"
#include "sysState.h"
mapper7::mapper7(void)
{
prgReg = 0;
setMirroring();
setBankSwitching();
}
mapper7::~mapper7(void)
{
}
void mapper7::setMirroring(){
if((prgReg & 0x10) == 0){
memDat->nameTableMirroring[0][0] = 0;
memDat->nameTableMirroring[0][1] = 0;
memDat->nameTableMirroring[1][0] = 0;
memDat->nameTableMirroring[1][1] = 0;
}
else{
memDat->nameTableMirroring[0][0] = 1;
memDat->nameTableMirroring[0][1] = 1;
memDat->nameTableMirroring[1][0] = 1;
memDat->nameTableMirroring[1][1] = 1;
}
}
void mapper7::setBankSwitching(){
Uint8 pID = ((prgReg & 0x07) << 1) & (romDat->prgPageCount - 1);
prgPtr[0] = &(romDat->prgROM[pID << 14]);
prgPtr[1] = &(romDat->prgROM[(pID + 1) << 14]);
}
void mapper7::writeCPUData(Uint16 address, Uint8 data){
if(address >= 0x6000){
if(address < 0x8000){
romDat->batDat[address & 0x1FFF] = data;
if(romDat->useBat)romDat->batChanged = true;
}
else{
prgReg = data;
setMirroring();
setBankSwitching();
}
}
}
Uint8 mapper7::readCPUData(Uint16 address, bool opRead){
Uint16 bank;
bank = (address & 0xC000);
if(bank == 0x8000){
if(opRead)
lastPrgRead = &(prgPtr[0][address & 0x3FFF]) - romDat->prgROM;
return prgPtr[0][address & 0x3FFF];
}
else if(bank == 0xC000){
if(opRead)
lastPrgRead = &(prgPtr[1][address & 0x3FFF]) - romDat->prgROM;
return prgPtr[1][address & 0x3FFF];
}
else if(address >= 0x6000){
return romDat->batDat[address & 0x1FFF];
}
else{
return 0;
}
}
void mapper7::writePPUData(Uint16 address, Uint8 data){
if(address < 0x2000){
romDat->chrRAM[address] = data;
if(lastPrgRead != BAD_ADDRESS)
romDat->chrRAMAddress[address >> 4] = lastPrgRead >> 4;
}
}
Uint8 mapper7::readPPUData(Uint16 address){
if(address < 0x2000){
if(romDat->chrPageCount > 0){
return romDat->chrROM[address];
}
else{
return romDat->chrRAM[address];
}
}
else{
return 0;
}
}
void mapper7::getPattern(Uint16 address, Uint8 row, bool isFirst, Uint8& data, Uint32& patternAddress, Uint32& ramAddress){
Uint16 tmpAddress;
tmpAddress = address;
if(row >= 8){
tmpAddress += 16;
row -= 8;
}
if(!isFirst) tmpAddress += 8;
if(romDat->chrPageCount > 0){
data = romDat->chrROM[tmpAddress + row];
patternAddress = tmpAddress >> 4;
}
else{
data = romDat->chrRAM[tmpAddress + row];
ramAddress = tmpAddress & 0xFFF0;
//patternAddress = BAD_ADDRESS;
if(vid->chrRamMatch){
patternAddress = romDat->chrRAMAddress[tmpAddress >> 4];
}
else{
patternAddress = tmpAddress >> 4;
}
}
}
void mapper7::saveState(fstream* statefile){
Uint32 offset;
statefile->write((char *)(&prgReg), sizeof(Uint8));
statefile->write((char *)(&lastPrgRead), sizeof(Uint32));
offset = prgPtr[0] - romDat->prgROM;
statefile->write((char *)(&offset), sizeof(Uint32));
offset = prgPtr[1] - romDat->prgROM;
statefile->write((char *)(&offset), sizeof(Uint32));
}
void mapper7::loadState(fstream* statefile){
Uint32 offset;
statefile->read((char *)(&prgReg), sizeof(Uint8));
statefile->read((char *)(&lastPrgRead), sizeof(Uint32));
statefile->read((char *)(&offset), sizeof(Uint32));
prgPtr[0] = &(romDat->prgROM[offset]);
statefile->read((char *)(&offset), sizeof(Uint32));
prgPtr[1] = &(romDat->prgROM[offset]);
setMirroring();
setBankSwitching();
}
void mapper7::runCatchUp(unsigned int cycle){
}
void mapper7::resetCycleCount(){
}

30
mapper7.h Normal file
View file

@ -0,0 +1,30 @@
#pragma once
#include "mapper.h"
class mapper7 :public mapper{
private:
Uint8 prgReg;
Uint8* prgPtr[2];
Uint32 lastPrgRead;
void setMirroring();
void setBankSwitching();
public:
mapper7(void);
~mapper7(void);
void runCatchUp(unsigned int cycle);
void resetCycleCount();
void writeCPUData(Uint16 address, Uint8 data);
Uint8 readCPUData(Uint16 address, bool opRead);
void writePPUData(Uint16 address, Uint8 data);
Uint8 readPPUData(Uint16 address);
void getPattern(Uint16 address, Uint8 row, bool isFirst, Uint8& data, Uint32& patternAddress, Uint32& ramAddress);
void saveState(fstream* statefile);
void loadState(fstream* statefile);
};

254
mapper9.cpp Normal file
View file

@ -0,0 +1,254 @@
#include "StdAfx.h"
#include "mapper9.h"
#include "sysState.h"
mapper9::mapper9(void)
{
chrMask = 0xF000;
chrSwitchMask = ((CHR_PAGE_SIZE * romDat->chrPageCount) >> 12) - 1;
prgSwitchMask = ((PRG_PAGE_SIZE * romDat->prgPageCount) >> 13) - 1;
chrMode[0] = 0;
chrMode[1] = 0;
mapReg[0] = 0;
mapReg[1] = 0;
mapReg[2] = 0;
mapReg[3] = 0;
mapReg[4] = 0;
mapReg[5] = 0;
setMirroring();
setBankSwitching();
setChrBankSwitching();
}
mapper9::~mapper9(void)
{
}
void mapper9::setMirroring(){
if((mapReg[5] & 0x01) == 0){
memDat->nameTableMirroring[0][0] = 0;
memDat->nameTableMirroring[0][1] = 0;
memDat->nameTableMirroring[1][0] = 1;
memDat->nameTableMirroring[1][1] = 1;
}
else{
memDat->nameTableMirroring[0][0] = 0;
memDat->nameTableMirroring[0][1] = 1;
memDat->nameTableMirroring[1][0] = 0;
memDat->nameTableMirroring[1][1] = 1;
}
}
void mapper9::setBankSwitching(){
prgPtr[0] = &(romDat->prgROM[(mapReg[0] & prgSwitchMask) << 13]);
prgPtr[1] = &(romDat->prgROM[(romDat->prgPageCount * 2 - 3) << 13]);
prgPtr[2] = &(romDat->prgROM[(romDat->prgPageCount * 2 - 2) << 13]);
prgPtr[3] = &(romDat->prgROM[(romDat->prgPageCount * 2 - 1) << 13]);
}
void mapper9::setChrBankSwitching(){
if (chrMode[0] == 0) {
chrPtr[0] = &(romDat->chrROM[(mapReg[1] & chrSwitchMask) << 12]);
}
else{
chrPtr[0] = &(romDat->chrROM[(mapReg[2] & chrSwitchMask) << 12]);
}
if (chrMode[1] == 0) {
chrPtr[1] = &(romDat->chrROM[(mapReg[3] & chrSwitchMask) << 12]);
}
else{
chrPtr[1] = &(romDat->chrROM[(mapReg[4] & chrSwitchMask) << 12]);
}
}
void mapper9::writeCPUData(Uint16 address, Uint8 data){
Uint16 writeAddress;
if(address >= 0x6000){
if(address < 0x8000){
romDat->batDat[address & 0x1FFF] = data;
if(romDat->useBat) romDat->batChanged = true;
}
else{
writeAddress = (address & chrMask);
switch(writeAddress){
case 0xA000:
mapReg[0] = data;
setBankSwitching();
break;
case 0xB000:
mapReg[1] = data;
setChrBankSwitching();
break;
case 0xC000:
mapReg[2] = data;
setChrBankSwitching();
break;
case 0xD000:
mapReg[3] = data;
setChrBankSwitching();
break;
case 0xE000:
mapReg[4] = data;
setChrBankSwitching();
break;
case 0xF000:
mapReg[5] = data;
setMirroring();
break;
}
}
}
}
Uint8 mapper9::readCPUData(Uint16 address, bool opRead){
Uint16 bank;
bank = (address >> 13) & 0x03;
if(address >= 0x8000){
if(opRead) lastPrgRead = &(prgPtr[bank][address & 0x1FFF]) - romDat->prgROM;
return prgPtr[bank][address & 0x1FFF];
}
else if(address >= 0x6000 && !romDat->scr4x){
return romDat->batDat[address & 0x1FFF];
}
else{
return 0;
}
}
void mapper9::writePPUData(Uint16 address, Uint8 data){
if(address < 0x2000){
if(romDat->chrPageCount == 0){
romDat->chrRAM[address] = data;
if(lastPrgRead != BAD_ADDRESS)
romDat->chrRAMAddress[address >> 4] = lastPrgRead >> 4;
}
}
}
void mapper9::setChrMode(Uint16 address){
Uint16 modeCheck;
modeCheck = address & 0x1FF0;
switch(modeCheck){
case 0x0FD0:
chrMode[0] = 0;
break;
case 0x0FE0:
chrMode[0] = 1;
break;
case 0x1FD0:
chrMode[1] = 0;
break;
case 0x1FE0:
chrMode[1] = 1;
break;
}
switch(modeCheck){
case 0x0FD0:
case 0x0FE0:
case 0x1FD0:
case 0x1FE0:
setChrBankSwitching();
break;
}
}
Uint8 mapper9::readPPUData(Uint16 address){
Uint16 bank;
Uint8 data;
bank = (address >> 12) & 0x03;
if(romDat->chrPageCount > 0){
data = chrPtr[bank][address & 0xFFF];
setChrMode(address);
return data;
}
else{
return romDat->chrRAM[address];
}
}
void mapper9::getPattern(Uint16 address, Uint8 row, bool isFirst, Uint8& data, Uint32& patternAddress, Uint32& ramAddress){
Uint16 tmpAddress;
Uint16 bank;
Uint32 realAddress;
tmpAddress = address;
if(row >= 8){
tmpAddress += 16;
row -= 8;
}
if(!isFirst) tmpAddress += 8;
bank = ((tmpAddress>> 12) & 0x03);
if(romDat->chrPageCount > 0){
data = chrPtr[bank][(tmpAddress + row) & 0xFFF];
realAddress = (&(chrPtr[bank][(tmpAddress + row) & 0xFFF])) - romDat->chrROM;
patternAddress = realAddress >> 4;
}
else{
data = romDat->chrRAM[tmpAddress + row];
ramAddress = tmpAddress & 0xFFF0;
if(vid->chrRamMatch){
patternAddress = romDat->chrRAMAddress[tmpAddress >> 4];
}
else{
patternAddress = tmpAddress >> 4;
}
}
setChrMode(tmpAddress);
}
void mapper9::saveState(fstream* statefile){
Uint32 offset;
statefile->write((char *)(&chrMask), sizeof(Uint16));
statefile->write((char *)(&chrSwitchMask), sizeof(Uint16));
statefile->write((char *)(&prgSwitchMask), sizeof(Uint16));
statefile->write((char *)(chrMode), sizeof(Uint8) * 2);
statefile->write((char *)(mapReg), sizeof(Uint8) * 6);
statefile->write((char *)(&lastPrgRead), sizeof(Uint32));
for (int i = 0; i < 2; ++i) {
offset = chrPtr[i] - romDat->chrROM;
statefile->write((char *)(&offset), sizeof(Uint32));
}
for (int i = 0; i < 4; ++i) {
offset = prgPtr[i] - romDat->prgROM;
statefile->write((char *)(&offset), sizeof(Uint32));
}
}
void mapper9::loadState(fstream* statefile){
Uint32 offset;
statefile->read((char *)(&chrMask), sizeof(Uint16));
statefile->read((char *)(&chrSwitchMask), sizeof(Uint16));
statefile->read((char *)(&prgSwitchMask), sizeof(Uint16));
statefile->read((char *)(chrMode), sizeof(Uint8) * 2);
statefile->read((char *)(mapReg), sizeof(Uint8) * 8);
statefile->read((char *)(&lastPrgRead), sizeof(Uint32));
for (int i = 0; i < 2; ++i) {
statefile->read((char *)(&offset), sizeof(Uint32));
chrPtr[i] = &(romDat->chrROM[offset]);
}
for (int i = 0; i < 4; ++i) {
statefile->read((char *)(&offset), sizeof(Uint32));
prgPtr[i] = &(romDat->prgROM[offset]);
}
setMirroring();
setBankSwitching();
setChrBankSwitching();
}
void mapper9::runCatchUp(unsigned int cycle){
}
void mapper9::resetCycleCount(){
}

37
mapper9.h Normal file
View file

@ -0,0 +1,37 @@
#pragma once
#include "mapper.h"
class mapper9 :public mapper{
private:
Uint16 chrMask;
Uint16 chrSwitchMask;
Uint16 prgSwitchMask;
Uint8 chrMode[2];
Uint8 mapReg[6];
Uint8* prgPtr[4];
Uint8* chrPtr[2];
Uint32 lastPrgRead;
void setMirroring();
void setBankSwitching();
void setChrBankSwitching();
void setChrMode(Uint16 address);
public:
mapper9(void);
~mapper9(void);
void runCatchUp(unsigned int cycle);
void resetCycleCount();
void writeCPUData(Uint16 address, Uint8 data);
Uint8 readCPUData(Uint16 address, bool opRead);
void writePPUData(Uint16 address, Uint8 data);
Uint8 readPPUData(Uint16 address);
void getPattern(Uint16 address, Uint8 row, bool isFirst, Uint8& data, Uint32& patternAddress, Uint32& ramAddress);
void saveState(fstream* statefile);
void loadState(fstream* statefile);
};

9
mapperList.h Normal file
View file

@ -0,0 +1,9 @@
#include "mapper0.h"
#include "mapper1.h"
#include "mapper2.h"
#include "mapper3.h"
#include "mapper4.h"
#include "mapper7.h"
#include "mapper9.h"
#include "mapper10.h"
#include "mapper16.h"

149
memory.cpp Normal file
View file

@ -0,0 +1,149 @@
#include "StdAfx.h"
#include "memory.h"
#include "sysState.h"
memory::memory(void)
{
}
memory::~memory(void)
{
}
Uint8 memory::cpuBusRead(Uint16 address){
return cpuBusRead(address, false);
}
Uint8 memory::cpuBusRead(Uint16 address, bool opRead){
if(address < 0x2000){
return cpuRAM[address & 0x07FF];
}
else if(address < 0x4000){
return ppuCore->readReg(address & 0x0007);
}
else if(address < 0x4016){
if(address != 0x4014){
return apuCore->readReg(address & 0x001F);
}
else{
return 0;
}
}
else if(address < 0x4018){
return inputCore->readReg(address & 0x001F);
}
else if(address < 0x4020){
return ppuCore->readReg(address - 0x17);
}
else{
return mmc->readCPUData(address, opRead);
}
}
void memory::cpuBusWrite(Uint16 address, Uint8 data){
if(address < 0x2000){
cpuRAM[address & 0x07FF] = mixer->handleRAMWrite(address, data);
}
else if(address < 0x4000){
ppuCore->writeReg(address & 0x0007, data);
}
else if(address < 0x4016){
if(address != 0x4014){
apuCore->writeReg(address & 0x001F, data);
}
else{
ppuCore->transferDMA(data);
}
}
else if(address < 0x4017){
inputCore->writeReg(address & 0x001F, data);
}
else if(address < 0x4018){
apuCore->writeReg(address & 0x001F, data);
}
else if(address < 0x4020){
ppuCore->writeReg(address - 0x17, data);
}
else{
mmc->writeCPUData(address, data);
}
}
void memory::cpuBusInit(){
memset(cpuRAM, 0x00, 0x800);
cpuRAM[0x008] = 0xF7;
cpuRAM[0x009] = 0xEF;
cpuRAM[0x00A] = 0xDF;
cpuRAM[0x00F] = 0xBF;
bgColourID = 0;
}
Uint8 memory::ppuBusRead(Uint16 address){
Uint8 tableID;
Uint16 tmpAddress;
if(address < 0x2000){
return mmc->readPPUData(address);
}
else if(address < 0x3F00){
//0x2?00 => 10YX0000000000 => [X][Y]
//0x3?00 => 11YX0000000000 => [X][Y]
tableID = nameTableMirroring[(address & 0x0400) >> 10][(address & 0x0800) >> 11];
tmpAddress = address & 0x03FF;
if(tmpAddress < 0x03C0){
return nameTable[tableID][tmpAddress];
}
else{
return attributeTable[tableID][tmpAddress & 0x003F];
}
}
else if(address < 0x4000){
return paletteTable[(address & 0x001C) >> 2][address & 0x0003];
}
else{
return 0;
}
}
void memory::ppuBusWrite(Uint16 address, Uint8 data){
Uint8 tableID;
Uint16 tmpAddress;
if(address < 0x2000){
mmc->writePPUData(address, data);
}
else if(address < 0x3F00){
//0x2?00 => 10YX0000000000 => [X][Y]
//0x3?00 => 11YX0000000000 => [X][Y]
tableID = nameTableMirroring[(address & 0x0400) >> 10][(address & 0x0800) >> 11];
tmpAddress = address & 0x03FF;
if(tmpAddress < 0x03C0){
nameTable[tableID][tmpAddress] = data;
}
else{
attributeTable[tableID][tmpAddress & 0x003F] = data;
}
}
else if(address < 0x4000){
if((address & 0x000F) == 0) bgColourID = data;
if((address & 0x0003) == 0){
//mirroring
paletteTable[(address & 0x000C) >> 2][0] = data;
paletteTable[((address & 0x000C) | 0x0010) >> 2][0] = data;
}
else{
paletteTable[(address & 0x001C) >> 2][address & 0x0003] = data;
}
}
}
void memory::saveState(fstream* statefile){
statefile->write((char *)(this), sizeof(memory));
}
void memory::loadState(fstream* statefile){
statefile->read((char *)(this), sizeof(memory));
}

32
memory.h Normal file
View file

@ -0,0 +1,32 @@
#pragma once
using namespace std;
//control read or write to all internal memory
class memory
{
public:
Uint8 cpuRAM[0x800];
Uint8 sprRAM[0x100];
Uint8 sprRAM2[32];
Uint8 nameTable[4][0x3C0];
Uint8 nameTableMirroring[2][2];
Uint8 attributeTable[4][64];
Uint8 paletteTable[8][4];
Uint8 bgColourID;
memory(void);
~memory(void);
Uint8 cpuBusRead(Uint16 address);
Uint8 cpuBusRead(Uint16 address, bool opRead);
void cpuBusWrite(Uint16 address, Uint8 data);
void cpuBusInit();
Uint8 ppuBusRead(Uint16 address);
void ppuBusWrite(Uint16 address, Uint8 data);
void saveState(fstream* statefile);
void loadState(fstream* statefile);
};

863
ppu.cpp Normal file
View file

@ -0,0 +1,863 @@
#include "StdAfx.h"
#include "sysState.h"
#include <time.h>
#include <Shlwapi.h>
ppu::ppu(void)
{
for(int i = 0; i < 34; ++i){
bgPatternIDFretched[i] = 0;
bgPaletteFretched[i] = 0;
bgPatternDataFretched[i][0] = 0;
bgPatternDataFretched[i][1] = 0;
bgAddressFretched[i] = BAD_ADDRESS;
}
for(int i = 0; i < 8; ++i){
spRowFretched[i] = 0;
spPatternDataFretched[i][0] = 0;
spPatternDataFretched[i][1] = 0;
spAddressFretched[i] = BAD_ADDRESS;
}
}
ppu::~ppu(void)
{
}
void ppu::init(){
initState();
sprOverflow = false;
spr0hit = false;
write2003(0);
}
void ppu::reset(){
initState();
writeDisabledPeriod = 29658;
}
void ppu::initState(){
writeDisabledPeriod = 0;
for(int i = 0; i < 8; ++i){
reg[i] = 0;
}
newWrite = true;
write2000(0);
write2001(0);
lastRegWrite = 0;
offsetX = 0;
tmpVRAMAddress = 0;
vRAMAddress = 0;
screenX = 0;
screenY = 241;
curCycle = 0;
vBlankFlag = false;
oldVBlankFlag = false;
signalNMI = false;
signalFrameReady = false;
oddFrame = false;
frameCount = 0;
bgLoadingY = 0;
//init fretch and eval
ZeroMemory(bgPatternIDFretched, 34);
ZeroMemory(bgPaletteFretched, 34);
bgTileToLoad = 0;
bgFretchNameTableAddress = 0;
spTileToLoad = 0;
ZeroMemory(spPatternDataFretched, 16);
oam2AddressToWrite = 0;
spBytesToCopy = 0;
}
Uint16 ppu::getSprPatternAddress(Uint8 patternID){
if(useLargeSpr)
return ((patternID & 0x01) << 12) | ((patternID & 0xFE) << 4);
else
return sprPatternTable | (patternID << 4);
}
void ppu::runStep(){
Uint8 bgPix;
Uint8 spPix;
Uint8 colourID;
//a new frame
if(screenX == 0 && screenY == 0){
vid->startFrame();
spr0hitDone = false;
++frameCount;
}
if(screenX == 0 && screenY < 240){
vid->initScanlineData(screenY);
}
if(screenY < 240 && (screenX % 8 == 0) && screenX <= 256 && enabled){
vid->setBGStripData(screenY, screenX >> 3);
}
//if(screenY < 240 && screenX == 256 && enabled){
// vid->setScanlineData();
//}
if(screenY < 240 && screenX < 256 && enabled){
if(screenX == 0){
currentBgTile = 0;
currentBgX = offsetX;
for(int i = 0; i < 8; ++i){
currentSpX[i] = 0;
}
for(int i = 0; i < 32; ++i){
tmpSprRAM2[i] = memDat->sprRAM2[i];
}
}
//render pixel
//get bg pix
bgPix = ((bgPatternDataFretched[currentBgTile][0] >> (7 - currentBgX)) & 0x01) | (((bgPatternDataFretched[currentBgTile][1] >> (7 - currentBgX)) & 0x01) << 1);
for (int i = 0; i < 8; ++i){
if(tmpSprRAM2[i * 4 + 3] == 0 && currentSpX[i] == 0){
vid->setSPStripData(screenY, screenX, i);
}
}
//check spr
for (int i = 0; i < 8; ++i){
spPix = 0;
if(tmpSprRAM2[i * 4] != 0xFF){
if(tmpSprRAM2[i * 4 + 3] == 0 && currentSpX[i] < 8){
if(spPatternDataFretched[i][0] != 0 || spPatternDataFretched[i][1] != 0){
//check hflip
if(((tmpSprRAM2[i * 4 + 2] >> 6) & 0x01) != 0){
spPix = ((spPatternDataFretched[i][0] >> currentSpX[i]) & 0x01) | (((spPatternDataFretched[i][1] >> currentSpX[i]) & 0x01) << 1);
}
else{
spPix = ((spPatternDataFretched[i][0] >> (7 - currentSpX[i])) & 0x01) | (((spPatternDataFretched[i][1] >> (7 - currentSpX[i])) & 0x01) << 1);
}
if(spPix != 0){
if(lastIsSp0 && bgPix != 0 && !spr0hit && !spr0hitDone && i == 0 && showBG && showSpr && ((showBGOnLeft && showSprOnLeft) || screenX >= 8) && screenX < 255){
spr0hit = true;
spr0hitDone = true;
}
if(((tmpSprRAM2[i * 4 + 2] >> 5) & 0x01) != 0){
//sp is back
if(bgPix == 0){
//render sp
colourID = memDat->paletteTable[(tmpSprRAM2[i * 4 + 2] & 0x03) | 0x04][spPix];
}
else{
//render bg
colourID = memDat->paletteTable[bgPaletteFretched[currentBgTile]][bgPix];
}
}
else{
//render sp
colourID = memDat->paletteTable[(tmpSprRAM2[i * 4 + 2] & 0x03) | 0x04][spPix];
}
break;
}
}
}
}
}
++currentBgX;
if(currentBgX == 8){
++currentBgTile;
currentBgX = 0;
}
//shift all sprite pixel
for (int i = 0; i < 8; ++i){
if(tmpSprRAM2[i * 4] != 0xFF){
if(tmpSprRAM2[i * 4 + 3] == 0){
++currentSpX[i];
}
else{
--tmpSprRAM2[i * 4 + 3];
}
}
}
}
//prerender line
if(screenY == 261){
if(screenX == 0){
vBlankFlag = false;
spr0hit = false;
sprOverflow = false;
}
if(screenX == 304 && enabled){
//vertical scroll bits are reloaded if rendering is enabled
//v:111101111100000=t:111101111100000
vRAMAddress = (vRAMAddress & 0x041F) | (tmpVRAMAddress & 0xFBE0);
bgLoadingY = (vRAMAddress >> 12) & 0x07;
}
if(screenX == 328 && showBG && oddFrame){
//skip one cycle on odd frame
++screenX;
}
}
//sprite evaluation
if(screenY < 240 && enabled){
if(screenX == 0){
enableWriteOAM2 = true;
spAddressToEval = 0;
oam2AddressToWrite = 0;
spFound = 0;
spEvalStateCheckY = true;
spYInRange = false;
isSp0 = false;
}
if(screenX < 256){
if((screenX & 0x01) == 0){
//even cycles
if(screenX < 64){
if(screenX == 0){
spBytesToCopy = 32;
}
//init OAM2 to $FF
dataToWriteOAM2 = 0xFF;
}
else{
if(spAddressToEval < 256){
if(screenX == 64){
oam2AddressToWrite = 0;
}
//read OAM
dataToWriteOAM2 = memDat->sprRAM[spAddressToEval];
if(spEvalStateCheckY){
//check Y in range
spYInRange = (dataToWriteOAM2 <= screenY && (dataToWriteOAM2 + sprHeight) > screenY);
if(spYInRange){
if(spFound < 8){
if(spFound == 0 && spAddressToEval == 0){
isSp0 = true;
}
++spFound;
}
else{
sprOverflow = true;
}
spEvalStateCheckY = false;
spBytesToCopy = 4;
++spAddressToEval;
}
else{
spAddressToEval += 4;
if(spFound == 8){
++spAddressToEval;
}
}
}
else{
++spAddressToEval;
}
}
else{
//all sprite passed
}
}
}
else{
//On odd cycles, data is written to secondary OAM
if(enableWriteOAM2){
if(spBytesToCopy > 0){
memDat->sprRAM2[oam2AddressToWrite] = dataToWriteOAM2;
++oam2AddressToWrite;
}
}
else{
//(unless writes are inhibited, in which case it will read the value in secondary OAM instead)
dataToWriteOAM2 = memDat->sprRAM2[oam2AddressToWrite];
}
if(spBytesToCopy > 0){
--spBytesToCopy;
if(spBytesToCopy == 0){
spEvalStateCheckY = true;
if(spFound == 8){
enableWriteOAM2 = false;
}
}
}
}
}
else if(screenX == 256){
lastIsSp0 = isSp0;
}
else if(screenX < 320){
//fretch tiles see below
}
else{
//read first byte in OAM2
}
}
//reset bg fretch
if(screenX == 320){
bgFretchNameTableAddress = 0x2000 | (vRAMAddress & 0x0FFF);
bgTileToLoad = 0;
}
if(1 == 0){
saveVRam(setting->exeDir + "\\screen\\");
}
//fretch tile data
if((screenY < 240 || screenY == 261) && enabled){
if(screenX < 256 || (screenX >= 320 && screenX < 336)){
//bg fretch
switch(screenX % 8){
case 0:
//start read name table byte
break;
case 1:
//finish read name table byte
bgPatternIDFretched[bgTileToLoad] = memDat->ppuBusRead(bgFretchNameTableAddress);
break;
case 2:
//start read attribute table byte
break;
case 3:
//finish read attribute table byte
bgPaletteFretched[bgTileToLoad] = mmc->getTilePalette((bgFretchNameTableAddress >> 10) & 0x0001, (bgFretchNameTableAddress >> 11) & 0x0001, bgFretchNameTableAddress & 0x001F, (bgFretchNameTableAddress >> 5) & 0x001F);
break;
case 4:
//start read tile bitmap A
break;
case 5:
//finish read tile bitmap A
mmc->getPattern(bgTilePatternTable | (bgPatternIDFretched[bgTileToLoad] << 4), bgLoadingY, true, bgPatternDataFretched[bgTileToLoad][0], bgAddressFretched[bgTileToLoad], bgRAMAddress[bgTileToLoad]);
break;
case 6:
//start read tile bitmap B
break;
case 7:
//finish read tile bitmap B
mmc->getPattern(bgTilePatternTable | (bgPatternIDFretched[bgTileToLoad] << 4), bgLoadingY, false, bgPatternDataFretched[bgTileToLoad][1], bgAddressFretched[bgTileToLoad], bgRAMAddress[bgTileToLoad]);
++bgTileToLoad;
if((bgFretchNameTableAddress & 0x001F) == 0x001F){
//end of name table, flip bit 10 to switch table
if((bgFretchNameTableAddress & 0x0400) == 0){
bgFretchNameTableAddress = (bgFretchNameTableAddress | 0x0400) & 0xFFE0;
}
else{
bgFretchNameTableAddress = bgFretchNameTableAddress & 0xFBE0;
}
}
else{
++bgFretchNameTableAddress;
}
break;
}
}
else if(screenX < 320){
if(screenX == 256){
spTileToLoad = 0;
bgLoadingY = (vRAMAddress >> 12) & 0x07;
++bgLoadingY;
if(bgLoadingY == 8){
bgLoadingY = 0;
if((vRAMAddress & 0x03E0) == 0x03E0){
//reached max coarse y, flip back to 0
vRAMAddress = vRAMAddress & 0xFC1F;
}
else if((vRAMAddress & 0x03A0) == 0x03A0){
//end of name table, flip bit 11 to switch table
if((vRAMAddress & 0x0800) == 0){
vRAMAddress = (vRAMAddress | 0x0800) & 0xFC1F;
}
else{
vRAMAddress = vRAMAddress & 0xF41F;
}
}
else{
vRAMAddress += 0x0020;
}
}
vRAMAddress = (vRAMAddress & 0x0FFF) | (bgLoadingY << 12);
}
if(screenX == 257){
//v:0000010000011111=t:0000010000011111
vRAMAddress = (vRAMAddress & 0xFBE0) | (tmpVRAMAddress & 0x041F);
}
//sprite fretch
if(spTileToLoad < 8){
switch(screenX % 8){
case 0:
//start read garbage name table byte
break;
case 1:
//finish read garbage name table byte
break;
case 2:
//start read garbage name table byte
break;
case 3:
//finish read garbage name table byte
break;
case 4:
//start read tile bitmap A
break;
case 5:
//finish read tile bitmap A
//check vertical flip
spRowFretched[spTileToLoad] = ((memDat->sprRAM2[spTileToLoad * 4 + 2] >> 7) != 0 ? sprHeight - 1 - (screenY - memDat->sprRAM2[spTileToLoad * 4]): screenY - memDat->sprRAM2[spTileToLoad * 4]);
mmc->getPattern(getSprPatternAddress(memDat->sprRAM2[spTileToLoad * 4 + 1]), spRowFretched[spTileToLoad], true, spPatternDataFretched[spTileToLoad][0], spAddressFretched[spTileToLoad], spRAMAddress[spTileToLoad]);
break;
case 6:
//start read tile bitmap B
break;
case 7:
//finish read tile bitmap B
mmc->getPattern(getSprPatternAddress(memDat->sprRAM2[spTileToLoad * 4 + 1]), spRowFretched[spTileToLoad], false, spPatternDataFretched[spTileToLoad][1], spAddressFretched[spTileToLoad], spRAMAddress[spTileToLoad]);
//if spTileToLoad > sprite count then load dummy
break;
}
}
if(screenX % 8 == 7) ++spTileToLoad;
}
else if(screenX < 340){
//two dummy read
switch(screenX){
case 336:
//start read name table byte
break;
case 337:
//finish read name table byte
break;
case 338:
//start read name table byte
break;
case 339:
//finish read name table byte
break;
}
}
else{
//idle
}
}
else if(screenY == 240){
//idle
if(screenX == 340){
vBlankFlag = true;
}
}
else if(screenY == 241){
}
else{
//idle
}
++screenX;
if(screenX == 341){
screenX = 0;
++screenY;
if(screenY == 240){
signalFrameReady = true;
}
if(screenY == 262){
screenY = 0;
}
}
if(enableVBlank && vBlankFlag && !oldVBlankFlag){
signalNMI = true;
}
oldVBlankFlag = vBlankFlag;
if(writeDisabledPeriod > 0) --writeDisabledPeriod;
++curCycle;
}
void ppu::runCatchUp(unsigned int cycle){
while(curCycle < cycle) runStep();
}
Uint8 ppu::readReg(Uint8 address){
switch(address){
case 2:
return read2002();
break;
case 4:
return read2004();
break;
case 7:
return read2007();
break;
}
return 0;
}
void ppu::writeReg(Uint8 address, Uint8 data){
lastRegWrite = data;
switch(address){
case 0:
write2000(data);
break;
case 1:
write2001(data);
break;
case 3:
write2003(data);
break;
case 4:
write2004(data);
break;
case 5:
write2005(data);
break;
case 6:
write2006(data);
break;
case 7:
write2007(data);
break;
}
}
void ppu::write2000(Uint8 data){
if(writeDisabledPeriod == 0){
tmpVRAMAddress &= 0xF3FF;
tmpVRAMAddress |= ((data & 0x03) << 10);
baseNameTableAddress = (data & 0x03);
aIncSize = ((data & 0x04) != 0? 32: 1);
sprPatternTable = ((data & 0x08) != 0? 0x1000: 0x0000);
bgTilePatternTable = ((data & 0x10) != 0? 0x1000: 0x0000);
useLargeSpr = ((data & 0x20) != 0);
sprHeight = (useLargeSpr?16:8);
enableVBlank = ((data & 0x80) != 0);
reg[0] = data;
}
}
void ppu::write2001(Uint8 data){
if(writeDisabledPeriod == 0){
useGrayscale = ((data & 0x01) != 0);
showBGOnLeft = ((data & 0x02) != 0);
showSprOnLeft = ((data & 0x04) != 0);
showBG = ((data & 0x08) != 0);
showSpr = ((data & 0x10) != 0);
intensifyR = ((data & 0x20) != 0);
intensifyG = ((data & 0x40) != 0);
intensifyB = ((data & 0x80) != 0);
enabled = ((data & 0x18) != 0);
reg[1] = data;
}
}
Uint8 ppu::read2002(){
reg[2] = lastRegWrite & 0x1F;
if(sprOverflow) reg[2] |= 0x20;
if(spr0hit) reg[2] |= 0x40;
if(oldVBlankFlag) reg[2] |= 0x80;
vBlankFlag = false;
newWrite = true;
return reg[2];
}
void ppu::write2003(Uint8 data){
reg[3] = data;
}
Uint8 ppu::read2004(){
if(screenY >= 240){
return memDat->sprRAM[reg[3]];
}
else{
return dataToWriteOAM2;
}
}
void ppu::write2004(Uint8 data){
memDat->sprRAM[reg[3]] = data;
++reg[3];
}
void ppu::write2005(Uint8 data){
//change scrolling by pixels so 3 LS bits are taken as offset
//and the remaining is the tile data index
//activeAddress = 0yyyABYYYYYXXXXX
//offsetX = xxx
//AB = bit 0 and 1 of reg2000
if(writeDisabledPeriod == 0){
if(newWrite){
offsetX = (data & 0x07);
tmpVRAMAddress &= 0xFFE0;
tmpVRAMAddress |= (data >> 3);
}
else{
tmpVRAMAddress &= 0x0C1F;
tmpVRAMAddress |= ((data & 0xF8) << 2);
tmpVRAMAddress |= ((data & 0x07) << 12);
}
newWrite = !newWrite;
}
}
void ppu::write2006(Uint8 data){
if(writeDisabledPeriod == 0){
if(newWrite){
tmpVRAMAddress &= 0x00FF;
tmpVRAMAddress |= ((data & 0x3F) << 8);
}
else{
tmpVRAMAddress &= 0xFF00;
tmpVRAMAddress |= data;
vRAMAddress = tmpVRAMAddress;
bgLoadingY = (vRAMAddress >> 12) & 0x07;
}
newWrite = !newWrite;
}
}
Uint8 ppu::read2007(){
Uint8 buffer;
if(screenY < 240 && screenX < 256 && enabled){
buffer = 0;
}
else{
if(vRAMAddress < 0x3F00){
buffer = reg[7];
reg[7] = memDat->ppuBusRead(vRAMAddress);
}
else{
buffer = memDat->ppuBusRead(vRAMAddress);
//read the mirrored value into buffer
reg[7] = memDat->ppuBusRead(vRAMAddress & 0xEFFF);
}
}
vRAMAddress += aIncSize;
if(vRAMAddress > 0x3FFF){
vRAMAddress -= 0x4000;
}
bgLoadingY = (vRAMAddress >> 12) & 0x07;
return buffer;
}
void ppu::write2007(Uint8 data){
if(!(screenY < 240 && screenX < 256 && enabled)){
memDat->ppuBusWrite(vRAMAddress, data);
vRAMAddress += aIncSize;
if(vRAMAddress > 0x3FFF){
vRAMAddress -= 0x4000;
}
bgLoadingY = (vRAMAddress >> 12) & 0x07;
}
}
void ppu::transferDMA(Uint8 data){
Uint16 address;
address = (data << 8);
for(Uint16 i = 0; i < 256; ++i){
memDat->sprRAM[reg[3]] = memDat->cpuBusRead(address);
++reg[3];
++address;
}
cpuCore->runDMA();
}
void ppu::resetCycleCount(){
curCycle = curCycle % 1023;
}
void ppu::saveState(fstream* statefile){
statefile->write((char *)(&lastRegWrite), sizeof(Uint8));
statefile->write((char *)(&enabled), sizeof(bool));
statefile->write((char *)(&signalNMI), sizeof(bool));
statefile->write((char *)(&signalFrameReady), sizeof(bool));
statefile->write((char *)(&oddFrame), sizeof(bool));
statefile->write((char *)(&screenX), sizeof(Uint16));
statefile->write((char *)(&screenY), sizeof(Uint16));
statefile->write((char *)(&curCycle), sizeof(Uint32));
statefile->write((char *)(&frameCount), sizeof(Uint32));
statefile->write((char *)(&writeDisabledPeriod), sizeof(unsigned int));
statefile->write((char *)(reg), sizeof(Uint8) * 8);
statefile->write((char *)(spriteList), sizeof(sprite) * 64);
statefile->write((char *)(&baseNameTableAddress), sizeof(Uint8));
statefile->write((char *)(&aIncSize), sizeof(Uint8));
statefile->write((char *)(&sprPatternTable), sizeof(Uint16));
statefile->write((char *)(&bgTilePatternTable), sizeof(Uint16));
statefile->write((char *)(&useLargeSpr), sizeof(bool));
statefile->write((char *)(&sprHeight), sizeof(Uint8));
statefile->write((char *)(&enableVBlank), sizeof(bool));
statefile->write((char *)(&useGrayscale), sizeof(bool));
statefile->write((char *)(&showBGOnLeft), sizeof(bool));
statefile->write((char *)(&showSprOnLeft), sizeof(bool));
statefile->write((char *)(&showBG), sizeof(bool));
statefile->write((char *)(&showSpr), sizeof(bool));
statefile->write((char *)(&intensifyR), sizeof(bool));
statefile->write((char *)(&intensifyG), sizeof(bool));
statefile->write((char *)(&intensifyB), sizeof(bool));
statefile->write((char *)(&sprOverflow), sizeof(bool));
statefile->write((char *)(&spr0hit), sizeof(bool));
statefile->write((char *)(&spr0hitDone), sizeof(bool));
statefile->write((char *)(spr0PatternData), sizeof(Uint8) * 16);
statefile->write((char *)(spr0PatternData2), sizeof(Uint8) * 16);
statefile->write((char *)(&vBlankFlag), sizeof(bool));
statefile->write((char *)(&oldVBlankFlag), sizeof(bool));
statefile->write((char *)(&oamAddress), sizeof(Uint8));
statefile->write((char *)(&newWrite), sizeof(bool));
statefile->write((char *)(&offsetX), sizeof(Uint8));
statefile->write((char *)(&tmpVRAMAddress), sizeof(Uint16));
statefile->write((char *)(&vRAMAddress), sizeof(Uint16));
statefile->write((char *)(&dataToWriteOAM2), sizeof(Uint8));
statefile->write((char *)(&enableWriteOAM2), sizeof(bool));
statefile->write((char *)(&spAddressToEval), sizeof(Uint16));
statefile->write((char *)(&oam2AddressToWrite), sizeof(Uint16));
statefile->write((char *)(&spFound), sizeof(Uint8));
statefile->write((char *)(&spEvalStateCheckY), sizeof(bool));
statefile->write((char *)(&spYInRange), sizeof(bool));
statefile->write((char *)(&spBytesToCopy), sizeof(Uint8));
statefile->write((char *)(&bgLoadingY), sizeof(Uint8));
statefile->write((char *)(&bgTileToLoad), sizeof(Uint8));
statefile->write((char *)(&bgFretchNameTableAddress), sizeof(Uint16));
statefile->write((char *)(bgPatternIDFretched), sizeof(Uint8) * 34);
statefile->write((char *)(bgPaletteFretched), sizeof(Uint8) * 34);
statefile->write((char *)(bgPatternDataFretched), sizeof(Uint8) * 34 * 2);
statefile->write((char *)(bgAddressFretched), sizeof(Uint32) * 34);
statefile->write((char *)(bgRAMAddress), sizeof(Uint32) * 34);
statefile->write((char *)(&spTileToLoad), sizeof(Uint8));
statefile->write((char *)(&spPatternDataFretched), sizeof(Uint8) * 16);
statefile->write((char *)(spRowFretched), sizeof(Uint8) * 8);
statefile->write((char *)(spAddressFretched), sizeof(Uint32) * 8);
statefile->write((char *)(spRAMAddress), sizeof(Uint32) * 8);
statefile->write((char *)(&isSp0), sizeof(bool));
statefile->write((char *)(&lastIsSp0), sizeof(bool));
statefile->write((char *)(&currentBgTile), sizeof(Uint8));
statefile->write((char *)(&currentBgX), sizeof(Uint8));
statefile->write((char *)(currentSpX), sizeof(Uint16) * 8);
statefile->write((char *)(tmpSprRAM2), sizeof(Uint8) * 32);
}
void ppu::loadState(fstream* statefile){
statefile->read((char *)(&lastRegWrite), sizeof(Uint8));
statefile->read((char *)(&enabled), sizeof(bool));
statefile->read((char *)(&signalNMI), sizeof(bool));
statefile->read((char *)(&signalFrameReady), sizeof(bool));
statefile->read((char *)(&oddFrame), sizeof(bool));
statefile->read((char *)(&screenX), sizeof(Uint16));
statefile->read((char *)(&screenY), sizeof(Uint16));
statefile->read((char *)(&curCycle), sizeof(Uint32));
statefile->read((char *)(&frameCount), sizeof(Uint32));
statefile->read((char *)(&writeDisabledPeriod), sizeof(unsigned int));
statefile->read((char *)(reg), sizeof(Uint8) * 8);
statefile->read((char *)(spriteList), sizeof(sprite) * 64);
statefile->read((char *)(&baseNameTableAddress), sizeof(Uint8));
statefile->read((char *)(&aIncSize), sizeof(Uint8));
statefile->read((char *)(&sprPatternTable), sizeof(Uint16));
statefile->read((char *)(&bgTilePatternTable), sizeof(Uint16));
statefile->read((char *)(&useLargeSpr), sizeof(bool));
statefile->read((char *)(&sprHeight), sizeof(Uint8));
statefile->read((char *)(&enableVBlank), sizeof(bool));
statefile->read((char *)(&useGrayscale), sizeof(bool));
statefile->read((char *)(&showBGOnLeft), sizeof(bool));
statefile->read((char *)(&showSprOnLeft), sizeof(bool));
statefile->read((char *)(&showBG), sizeof(bool));
statefile->read((char *)(&showSpr), sizeof(bool));
statefile->read((char *)(&intensifyR), sizeof(bool));
statefile->read((char *)(&intensifyG), sizeof(bool));
statefile->read((char *)(&intensifyB), sizeof(bool));
statefile->read((char *)(&sprOverflow), sizeof(bool));
statefile->read((char *)(&spr0hit), sizeof(bool));
statefile->read((char *)(&spr0hitDone), sizeof(bool));
statefile->read((char *)(spr0PatternData), sizeof(Uint8) * 16);
statefile->read((char *)(spr0PatternData2), sizeof(Uint8) * 16);
statefile->read((char *)(&vBlankFlag), sizeof(bool));
statefile->read((char *)(&oldVBlankFlag), sizeof(bool));
statefile->read((char *)(&oamAddress), sizeof(Uint8));
statefile->read((char *)(&newWrite), sizeof(bool));
statefile->read((char *)(&offsetX), sizeof(Uint8));
statefile->read((char *)(&tmpVRAMAddress), sizeof(Uint16));
statefile->read((char *)(&vRAMAddress), sizeof(Uint16));
statefile->read((char *)(&dataToWriteOAM2), sizeof(Uint8));
statefile->read((char *)(&enableWriteOAM2), sizeof(bool));
statefile->read((char *)(&spAddressToEval), sizeof(Uint16));
statefile->read((char *)(&oam2AddressToWrite), sizeof(Uint16));
statefile->read((char *)(&spFound), sizeof(Uint8));
statefile->read((char *)(&spEvalStateCheckY), sizeof(bool));
statefile->read((char *)(&spYInRange), sizeof(bool));
statefile->read((char *)(&spBytesToCopy), sizeof(Uint8));
statefile->read((char *)(&bgLoadingY), sizeof(Uint8));
statefile->read((char *)(&bgTileToLoad), sizeof(Uint8));
statefile->read((char *)(&bgFretchNameTableAddress), sizeof(Uint16));
statefile->read((char *)(bgPatternIDFretched), sizeof(Uint8) * 34);
statefile->read((char *)(bgPaletteFretched), sizeof(Uint8) * 34);
statefile->read((char *)(bgPatternDataFretched), sizeof(Uint8) * 34 * 2);
statefile->read((char *)(bgAddressFretched), sizeof(Uint32) * 34);
statefile->read((char *)(bgRAMAddress), sizeof(Uint32) * 34);
statefile->read((char *)(&spTileToLoad), sizeof(Uint8));
statefile->read((char *)(&spPatternDataFretched), sizeof(Uint8) * 16);
statefile->read((char *)(spRowFretched), sizeof(Uint8) * 8);
statefile->read((char *)(spAddressFretched), sizeof(Uint32) * 8);
statefile->read((char *)(spRAMAddress), sizeof(Uint32) * 8);
statefile->read((char *)(&isSp0), sizeof(bool));
statefile->read((char *)(&lastIsSp0), sizeof(bool));
statefile->read((char *)(&currentBgTile), sizeof(Uint8));
statefile->read((char *)(&currentBgX), sizeof(Uint8));
statefile->read((char *)(currentSpX), sizeof(Uint16) * 8);
statefile->read((char *)(tmpSprRAM2), sizeof(Uint8) * 32);
}
void ppu::saveSprObjects(string path){
fstream logfile;
logfile.open(path + "Spr.dat", ios::out | ios::trunc);
if (logfile.is_open()){
for(unsigned int i = 0; i < 64; ++i){
logfile << to_string((long double)memDat->sprRAM[i * 4])
+ ", " + to_string((long double)memDat->sprRAM[i * 4 + 1])
+ ", " + to_string((long double)memDat->sprRAM[i * 4 + 2])
+ "; " + to_string((long double)memDat->sprRAM[i * 4 + 3]) + "\n";
}
logfile.close();
}
}
void ppu::saveVRam(string path){
fstream logfile;
Uint16 ad = 0x2000;
char tps[64];
logfile.open(path + "Vram.dat", ios::out | ios::trunc);
if (logfile.is_open()){
for(Uint16 k = 0; k < 8; ++k){
sprintf(tps, "%02X;", ad);
logfile << tps;
logfile << "\n";
for(Uint16 i = 0; i < 32; ++i){
for(Uint16 j = 0; j < 32; ++j){
sprintf(tps, "%02X;", memDat->ppuBusRead(ad));
logfile << tps;
++ad;
}
logfile << "\n";
}
logfile << "\n";
}
logfile.close();
}
}

148
ppu.h Normal file
View file

@ -0,0 +1,148 @@
#pragma once
struct sprite{
Uint8 y;
Uint8 x;
Uint8 patternID;
Uint8 paletteID;
bool isBack;
bool hFlip;
bool vFlip;
};
class ppu
{
public:
Uint8 lastRegWrite;
bool enabled;
bool signalNMI;
bool signalFrameReady;
bool oddFrame;
Uint16 screenX;
Uint16 screenY;
Uint32 curCycle;
Uint32 frameCount;
unsigned int writeDisabledPeriod;
Uint8 reg[8];
sprite spriteList[64];
//reg 2000
Uint8 baseNameTableAddress;
Uint8 aIncSize;
Uint16 sprPatternTable;
Uint16 bgTilePatternTable;
bool useLargeSpr;
Uint8 sprHeight;
bool enableVBlank;
void write2000(Uint8 data);
//reg 2001
bool useGrayscale;
bool showBGOnLeft;
bool showSprOnLeft;
bool showBG;
bool showSpr;
bool intensifyR;
bool intensifyG;
bool intensifyB;
void write2001(Uint8 data);
//reg 2002
bool sprOverflow;
bool spr0hit;
bool spr0hitDone;
Uint8 spr0PatternData[8][2];
Uint8 spr0PatternData2[8][2];
bool vBlankFlag;
bool oldVBlankFlag;
Uint8 read2002();
//reg 2003
Uint8 oamAddress;
void write2003(Uint8 data);
//reg 2004
void write2004(Uint8 data);
Uint8 read2004();
//shared by 2005, 2006
bool newWrite;
Uint8 offsetX;
Uint16 tmpVRAMAddress;
Uint16 vRAMAddress;
//reg 2005
void write2005(Uint8 data);
//reg 2006
void write2006(Uint8 data);
//reg 2007
void write2007(Uint8 data);
Uint8 read2007();
//sprite evaluation
Uint8 dataToWriteOAM2;
bool enableWriteOAM2;
Uint16 spAddressToEval;
Uint16 oam2AddressToWrite;
Uint8 spFound;
bool spEvalStateCheckY;
bool spYInRange;
Uint8 spBytesToCopy;
//tile fretch
Uint8 bgLoadingY;
Uint8 bgTileToLoad;
Uint16 bgFretchNameTableAddress;
Uint8 bgPatternIDFretched[34];
Uint8 bgPaletteFretched[34];
Uint8 bgPatternDataFretched[34][2];
Uint32 bgAddressFretched[34];
Uint32 bgRAMAddress[34];
Uint8 spTileToLoad;
Uint8 spPatternDataFretched[8][2];
Uint8 spRowFretched[8];
Uint32 spAddressFretched[8];
Uint32 spRAMAddress[8];
bool isSp0;
bool lastIsSp0;
//rendering
Uint8 currentBgTile;
Uint8 currentBgX;
Uint16 currentSpX[8];
Uint8 tmpSprRAM2[32];
void runCatchUp(unsigned int cycle);
void runStep();
void readSprList();
Uint16 getSprPatternAddress(Uint8 patternID);
ppu(void);
~ppu(void);
void init();
void reset();
void initState();
void resetCycleCount();
Uint8 readReg(Uint8 address);
void writeReg(Uint8 address, Uint8 data);
//4014
void transferDMA(Uint8 data);
void saveState(fstream* statefile);
void loadState(fstream* statefile);
void saveSprObjects(string path);
void saveVRam(string path);
};

8
stdafx.cpp Normal file
View file

@ -0,0 +1,8 @@
// stdafx.cpp : source file that includes just the standard includes
// hdnes.pch will be the pre-compiled header
// stdafx.obj will contain the pre-compiled type information
#include "stdafx.h"
// TODO: reference any additional headers you need in STDAFX.H
// and not in this file

27
stdafx.h Normal file
View file

@ -0,0 +1,27 @@
// stdafx.h : include file for standard system include files,
// or project specific include files that are used frequently, but
// are changed infrequently
//
#pragma once
#include "targetver.h"
#include <stdio.h>
#include <tchar.h>
#include <time.h>
#include "SDL/SDL.h"
#include "SDL/SDL_mixer.h"
#include <GL\glew.h>
#include <gl/gl.h>
#include <gl/glu.h>
#include <GL\glext.h>
#include <wx\wx.h>
#include <vector>
#include <iostream>
#include <fstream>
#include <sstream>
#include "globalConst.h"
#include "commonUtil.h"

95
sysSetting.cpp Normal file
View file

@ -0,0 +1,95 @@
#include "StdAfx.h"
#include <fstream>
#include <Shlwapi.h>
#include "sysState.h"
sysSetting::sysSetting(void)
{
CHAR szPath[MAX_PATH];
GetModuleFileNameA( NULL, szPath, MAX_PATH );
PathRemoveFileSpecA(szPath);
exeDir = string(szPath);
if(!loadSetting()){
loadDefaultSetting();
}
progDir = exeDir + "\\shader\\";
logDir = exeDir + "\\log\\";
//create log file name
char buffer [80];
time_t timer;
struct tm * timeinfo;
time(&timer);
timeinfo = localtime (&timer);
strftime (buffer,80,"%Y%m%d%H%M%S",timeinfo);
logName = logDir + buffer + ".log";
}
sysSetting::~sysSetting(void)
{
saveSetting();
}
bool sysSetting::loadSetting(void){
fstream inifile;
string line;
inifile.open(exeDir + "\\hdnes.ini", ios::in);
if (inifile.is_open()){
while ( inifile.good() ){
std::getline(inifile, line);
loadLine(line);
}
inifile.close();
return true;
}
return false;
}
void sysSetting::loadLine(string pline){
unsigned found = pline.find(":");
string token;
string value;
if (found!=std::string::npos){
token = pline.substr (0,found);
value = pline.substr (found + 1, std::string::npos);
if (token.compare("gamePath") == 0){
gamePath = value;
}
if (token.compare("input") == 0){
inputCore->readConfig(value);
}
if (token.compare("video") == 0){
vid->readConfig(value);
}
if (token.compare("audio") == 0){
mixer->readConfig(value);
}
}
}
void sysSetting::loadDefaultSetting(){
gamePath = exeDir + "\\";
}
void sysSetting::saveSetting(){
fstream inifile;
inifile.open(exeDir + "\\hdnes.ini", ios::out);
inifile << "gamePath:" + gamePath + "\n";
inputCore->saveConfig(&inifile);
vid->saveConfig(&inifile);
mixer->saveConfig(&inifile);
inifile.close();
}

24
sysSetting.h Normal file
View file

@ -0,0 +1,24 @@
#pragma once
#include "StdAfx.h"
using namespace std;
class sysSetting
{
private:
bool loadSetting(void);
void loadDefaultSetting();
void loadLine(string pline);
void saveSetting();
public:
sysSetting(void);
~sysSetting(void);
string exeDir;
string gamePath;
string progDir;
string logDir;
string logName;
Uint32 debugVal;
};

14
sysState.cpp Normal file
View file

@ -0,0 +1,14 @@
#include "sysState.h"
sysSetting* setting;
gameManager* gm;
video* vid;
audio* mixer;
memory* memDat;
cart* romDat;
cpu* cpuCore;
mapper* mmc;
ppu* ppuCore;
apu* apuCore;
input* inputCore;
fraHDNesImp* guiForm;

34
sysState.h Normal file
View file

@ -0,0 +1,34 @@
#pragma once
#include "sysSetting.h"
#include "gameManager.h"
#include "video.h"
#include "audio.h"
#include "memory.h"
#include "cart.h"
#include "cpu.h"
#include "mapper.h"
#include "ppu.h"
#include "apu.h"
#include "input.h"
#include "fraHDNesImp.h"
//Global vars
extern sysSetting* setting;
extern gameManager* gm;
extern video* vid;
extern audio* mixer;
extern memory* memDat;
extern cart* romDat;
extern cpu* cpuCore;
extern mapper* mmc;
extern ppu* ppuCore;
extern apu* apuCore;
extern input* inputCore;
extern fraHDNesImp* guiForm;
typedef void(cpu::*opcode)();
typedef Uint8(cpu::*opcodeTicks)();
extern opcode opArr[256];
extern opcodeTicks opTicksArr[256];

8
targetver.h Normal file
View file

@ -0,0 +1,8 @@
#pragma once
// Including SDKDDKVer.h defines the highest available Windows platform.
// If you wish to build your application for a previous Windows platform, include WinSDKVer.h and
// set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h.
#include <SDKDDKVer.h>

2742
video.cpp Normal file

File diff suppressed because it is too large Load diff

357
video.h Normal file
View file

@ -0,0 +1,357 @@
#pragma once
#include "stdafx.h"
#include <vector>
#define SCREEN_SIZE_1X 0
#define SCREEN_SIZE_2X 1
#define SCREEN_SIZE_4X 2
#define SCREEN_SIZE_XX 3
#define RECORDING_TYPE_AUTO 0
#define RECORDING_TYPE_MANU 1
#define RECORDING_TYPE_NONE 2
#define CONT_CAP_RATE 5
#define BG_PATTERN_SIZE 8192
#define SP_PATTERN_SIZE 1024
struct rawPattern{
Uint32 pixStrip1;
Uint32 pixStrip2;
Uint32 pixStrip3;
Uint32 pixStrip4;
};
struct scale1Pattern{
Uint32 pixel0;
Uint32 pixel1;
Uint32 pixel2;
Uint32 pixel3;
Uint32 pixel4;
Uint32 pixel5;
Uint32 pixel6;
Uint32 pixel7;
};
struct scale2Pattern{
Uint32 pixel0;
Uint32 pixel1;
Uint32 pixel2;
Uint32 pixel3;
Uint32 pixel4;
Uint32 pixel5;
Uint32 pixel6;
Uint32 pixel7;
Uint32 pixel8;
Uint32 pixel9;
Uint32 pixel10;
Uint32 pixel11;
Uint32 pixel12;
Uint32 pixel13;
Uint32 pixel14;
Uint32 pixel15;
};
struct scale4Pattern{
Uint32 pixel0;
Uint32 pixel1;
Uint32 pixel2;
Uint32 pixel3;
Uint32 pixel4;
Uint32 pixel5;
Uint32 pixel6;
Uint32 pixel7;
Uint32 pixel8;
Uint32 pixel9;
Uint32 pixel10;
Uint32 pixel11;
Uint32 pixel12;
Uint32 pixel13;
Uint32 pixel14;
Uint32 pixel15;
Uint32 pixel16;
Uint32 pixel17;
Uint32 pixel18;
Uint32 pixel19;
Uint32 pixel20;
Uint32 pixel21;
Uint32 pixel22;
Uint32 pixel23;
Uint32 pixel24;
Uint32 pixel25;
Uint32 pixel26;
Uint32 pixel27;
Uint32 pixel28;
Uint32 pixel29;
Uint32 pixel30;
Uint32 pixel31;
};
union colorCombo{
Uint32 colorValues;
struct{
Uint16 color1;
Uint8 color2;
Uint8 color3;
};
};
struct patternDat{
Uint8 scale;
Uint32 patternAddress;
Uint8 row;
colorCombo colors;
rawPattern rawDat;
Uint8 lookupIdx;
Uint16 index;
Uint16 displayID;
GLfloat brightness;
};
struct bitmapE{//GUI use
Uint32 patternAddress;
Uint32 bitmapID;
colorCombo colors;
rawPattern rawDat;
int x;
int y;
GLfloat brightness;
};
struct bitmapF{
Uint32 bitmapID;
colorCombo colors;
rawPattern rawDat;
int x;
int y;
GLfloat brightness;
bool isBg;
};
struct TileData{
vector<bitmapF> bitmapP;
int defaultID;
Uint32 patternAddress;
};
struct bmpInfo{
int width;
int height;
string filename;
};
//editing struct
struct screenTile{
bool isBg;
Uint32 patternAddress;
colorCombo colors;
rawPattern rawDat;
int x;
int y;
string tileName;
};
class video
{
public:
SDL_Surface* Surf_Display;
bool initState;
int screenSizeOption;
int screenSizeWidth;
int screenSizeHeight;
clock_t lastClock;
clock_t clockPerFrame;
bool waitFrame;
//colour values
Uint32 colourList[64];
//opengl section
GLuint glProgID;
GLuint glProgIDSp1;
GLuint glProgIDSp2;
GLuint glVShader;
GLuint glVShaderSp1;
GLuint glVShaderSp2;
GLuint glPShader;
GLuint glPShaderSp1;
GLuint glPShaderSp2;
GLuint uniTexture;
GLuint uniXOffset;
GLuint uniFlagBG;
GLuint uniTextureSp1;
GLuint uniTextureSp2;
GLuint uniFlagSp1;
GLuint uniFlagSp2;
GLuint atrVectCoord;
GLuint atrTextCoord;
GLuint atrVectCoordSp1;
GLuint atrTextCoordSp1;
GLuint atrVectCoordSp2;
GLuint atrTextCoordSp2;
GLuint sampler;
GLuint xOffsetSampler;
GLuint flagSampler;
Uint8 bgColourID;
//textures
GLuint xOffsetTexture;
Uint8 bgXTexture[256];
GLuint flagsTextureT;
Uint8 flagsTexture[256];
Uint32 bgFill;
//data buffers
GLuint bgVBufferRef;
GLuint bgCBufferRef;
GLfloat* bgCBuffer;
GLfloat spTileDataBuffer[5760]; //240*8*3
GLuint spTileDataBufferRef;
Uint16 spPatCount;
GLuint spVBufferRef;
GLshort* spVBuffer;
GLuint spCBufferRef;
GLfloat* spCBuffer;
//graphics
Uint32 bgGraphics[2048 * 512];
Uint32 spGraphics[2048 * 128];
std::vector<Uint32> bgList[256];
std::vector<Uint32> spList[256];
Uint16 bgCounter;
patternDat bgPatternData[BG_PATTERN_SIZE]; //33 * 240 * 4
patternDat spPatternData[SP_PATTERN_SIZE]; //64 * 16 * 4
Uint8 bgPatternInUse[BG_PATTERN_SIZE];
Uint8 spPatternInUse[SP_PATTERN_SIZE];
Uint16 minBgIdx;
Uint16 minSpIdx;
Uint16 maxBgIdx;
Uint16 maxSpIdx;
Uint16 blankBgIdx;
Uint16 blankSpIdx;
Uint8 useScaleIdx[5];
Uint16 lastPatID;
bool lastIsBg;
GLuint bgTextureRef;
GLuint spTextureRef;
bool capScreenFlag;
bool capDataFlag;
bool contCapFlag;
Uint8 contCapCounter;
Uint32 packSize;
//graphics pack data
vector<Uint8*> rawBits; //raw picture data
vector<bmpInfo> bmpInfos;
vector<TileData> tdata;
Uint32* packData;
Uint8 packScale;
bool usePack;
//pack edit data
Uint8 editRecordingType;
bool cutEdgeTiles;
bool chrRamMatch;
vector<TileData> etiledata;
Uint32* editData;
vector<TileData> allEtiledata;
Uint32* allEditData;
//screen values;
vector<string> screenNameList;
vector<string> screenFileNameList;
vector<screenTile> screenTiles; //new tiles in the current screen
vector<screenTile> allScreenTiles; //all tiles in the current screen
vector<string> capScreenQueue;
void initColour();
void initBuffer();
void initPatternArea();
GLuint make_sampler();
GLuint make_texture(GLuint width, GLuint height,void *buffer_data, GLuint type, GLint internalFormat, GLenum format, GLenum datatype);
GLuint make_buffer(GLenum target, const void *buffer_data, GLsizei buffer_size);
GLuint make_shader(GLenum type, const char *filename);
GLuint make_program(GLuint vertex_shader, GLuint fragment_shader);
void BuildPerspProjMat(float *m, float fov, float aspect, float znear, float zfar);
void update_texture(GLuint uniformID, GLuint textureRef, GLuint samplerRef, GLuint width, GLuint oy, GLuint ny, GLuint maxy, void *buffer_data, GLuint type, GLenum format, GLenum datatype, int textureUnitIndex);
video(void);
~video(void);
void init();
void cleanUp();
bool getInitState();
void clearFrame();
void startFrame();
void displayFrame();
void clearScreenData();
//void setScanlineData();
void initScanlineData(Uint16 row);
void setBGStripData(Uint16 row, Uint8 bgID);
void setSPStripData(Uint16 row, Uint16 col, Uint8 spID);
void prepareTileData(bool isBg, Uint32 patternAddress, Uint8 row,
colorCombo colors, Uint8 patternByte0, Uint8 patternByte1, Uint32 ramAddress,
GLuint& decodedX, GLuint& decodedY, GLuint& patternScale, GLfloat& brightness);
void capScreen(bool useNative);
void saveScreenToPath(string path, bool useNative);
static int convertScreenCapToPNG(void* data);
void RefreshPackSize();
void ReadHiResPack();
void CleanHiResPack();
void SaveHiResPack();
void AddHiResImg(string filename);
void RemoveHiResImg(unsigned int pID);
void AddDarkMapping();
bool IsDarkerPalette(colorCombo color, colorCombo refColor);
bool IsDarkerColor(Uint16 color, Uint16 refColor);
GLfloat CalBrightnessValue(colorCombo color, colorCombo refColor);
string GetPaletteString(colorCombo color);
void ReadPackEdit();
void CleanPackEdit();
void SavePackEditScreen();
void OptimizePackEdit();
void RewritePackEdit();
void SavePackEditScreenList();
void SaveGraphics(string path);
void SaveBuffers(string path);
void SavePatterns(string path);
//config settings
void readConfig(string value);
void saveConfig(fstream* inifile);
Uint32 BgRender[30][35];
void saveBG(string path);
};