mirror of
https://github.com/mkwong98/HDNes.git
synced 2024-05-10 16:45:24 -04:00
First commit
This commit is contained in:
commit
e107b6cc78
22
.gitattributes
vendored
Normal file
22
.gitattributes
vendored
Normal 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
215
.gitignore
vendored
Normal 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
40
ReadMe.txt
Normal 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
797
apu.cpp
Normal 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
170
apu.h
Normal 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
466
audio.cpp
Normal 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
63
audio.h
Normal 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
513
batchMapImp.cpp
Normal 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
31
batchMapImp.h
Normal 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
184
cart.cpp
Normal 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
42
cart.h
Normal 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
74
commonUtil.cpp
Normal 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
13
commonUtil.h
Normal 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);
|
331
cpu.h
Normal file
331
cpu.h
Normal 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
1465
fraHDNesImp.cpp
Normal file
File diff suppressed because it is too large
Load diff
110
fraHDNesImp.h
Normal file
110
fraHDNesImp.h
Normal 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
140
gameManager.cpp
Normal 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
26
gameManager.h
Normal 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
31
globalConst.h
Normal 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
8
hdnes.h
Normal 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
173
hdnes.vcxproj
Normal 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
198
hdnes.vcxproj.filters
Normal 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
187
input.cpp
Normal 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
55
input.h
Normal 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
52
mainApp.cpp
Normal 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
15
mainApp.h
Normal 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
37
mapper.cpp
Normal 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
20
mapper.h
Normal 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
120
mapper0.cpp
Normal 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
28
mapper0.h
Normal 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
297
mapper1.cpp
Normal 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
50
mapper1.h
Normal 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
254
mapper10.cpp
Normal 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
37
mapper10.h
Normal 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
372
mapper16.cpp
Normal 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
59
mapper16.h
Normal 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
148
mapper2.cpp
Normal 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
28
mapper2.h
Normal 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
165
mapper3.cpp
Normal 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
30
mapper3.h
Normal 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
293
mapper4.cpp
Normal 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 *)(®Address), 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 *)(®Address), 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
46
mapper4.h
Normal 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
152
mapper7.cpp
Normal 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
30
mapper7.h
Normal 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
254
mapper9.cpp
Normal 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
37
mapper9.h
Normal 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
9
mapperList.h
Normal 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
149
memory.cpp
Normal 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
32
memory.h
Normal 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
863
ppu.cpp
Normal 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 *)(¤tBgTile), sizeof(Uint8));
|
||||
statefile->write((char *)(¤tBgX), 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 *)(¤tBgTile), sizeof(Uint8));
|
||||
statefile->read((char *)(¤tBgX), 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
148
ppu.h
Normal 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
8
stdafx.cpp
Normal 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
27
stdafx.h
Normal 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
95
sysSetting.cpp
Normal 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
24
sysSetting.h
Normal 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
14
sysState.cpp
Normal 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
34
sysState.h
Normal 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
8
targetver.h
Normal 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>
|
357
video.h
Normal file
357
video.h
Normal 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);
|
||||
};
|
||||
|
Loading…
Reference in a new issue